diff options
49 files changed, 634 insertions, 372 deletions
diff --git a/README-SERIOUSLY.bestpractices.md b/README-SERIOUSLY.bestpractices.md index 7e18c4aa8..ec36fac98 100644 --- a/README-SERIOUSLY.bestpractices.md +++ b/README-SERIOUSLY.bestpractices.md @@ -17,7 +17,8 @@ change over time as best practices are defined. Recognizing potential issues with certain classes of authorization * [Avoid Privilege Escalations]: Disable the ability to execute functions that may escalate privileges - +* [Important Security Considerations]: + More information on the Asterisk Wiki ## Additional Links @@ -386,3 +387,4 @@ In Asterisk 12 and later, live_dangerously defaults to no. [Reducing Pattern Match Typos]: #reducing-pattern-match-typos [Manager Class Authorizations]: #manager-class-authorizations [Avoid Privilege Escalations]: #avoid-privilege-escalations +[Important Security Considerations]: https://wiki.asterisk.org/wiki/display/AST/Important+Security+Considerations @@ -9,10 +9,7 @@ the security information document before you attempt to configure and run an Asterisk server. - If you downloaded Asterisk as a tarball, see the security section in the PDF -version of the documentation in doc/tex/asterisk.pdf. Alternatively, pull up -the HTML version of the documentation in doc/tex/asterisk/index.html. The -source for the security document is available in doc/tex/security.tex. +See [Important Security Considerations] for more information. ## WHAT IS ASTERISK ? @@ -269,4 +266,4 @@ Asterisk is a trademark of Digium, Inc. [CHANGES]: CHANGES [configs]: configs [doc]: doc - +[Important Security Considerations]: https://wiki.asterisk.org/wiki/display/AST/Important+Security+Considerations diff --git a/apps/app_ices.c b/apps/app_ices.c index 4ca4b67c5..1194384d4 100644 --- a/apps/app_ices.c +++ b/apps/app_ices.c @@ -113,7 +113,6 @@ static int ices_exec(struct ast_channel *chan, const char *data) int fds[2]; int ms = -1; int pid = -1; - int flags; struct ast_format *oreadformat; struct ast_frame *f; char filename[256]=""; @@ -128,8 +127,7 @@ static int ices_exec(struct ast_channel *chan, const char *data) ast_log(LOG_WARNING, "Unable to create pipe\n"); return -1; } - flags = fcntl(fds[1], F_GETFL); - fcntl(fds[1], F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(fds[1], O_NONBLOCK); ast_stopstream(chan); diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 76891ac98..832f28b49 100644 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -1191,7 +1191,6 @@ static struct phone_pvt *mkif(const char *iface, int mode, int txgain, int rxgai { /* Make a phone_pvt structure for this interface */ struct phone_pvt *tmp; - int flags; tmp = ast_calloc(1, sizeof(*tmp)); if (tmp) { @@ -1224,8 +1223,7 @@ static struct phone_pvt *mkif(const char *iface, int mode, int txgain, int rxgai ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression); #endif tmp->mode = mode; - flags = fcntl(tmp->fd, F_GETFL); - fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(tmp->fd, O_NONBLOCK); tmp->owner = NULL; ao2_cleanup(tmp->lastformat); tmp->lastformat = NULL; diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index e4e8fa586..69bcc187f 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -605,6 +605,11 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s ast_party_id_copy(&ast_channel_caller(chan)->id, &session->id); ast_party_id_copy(&ast_channel_caller(chan)->ani, &session->id); + if (!ast_strlen_zero(exten)) { + /* Set provided DNID on the new channel. */ + ast_channel_dialed(chan)->number.str = ast_strdup(exten); + } + ast_channel_priority_set(chan, 1); ast_channel_callgroup_set(chan, session->endpoint->pickup.callgroup); diff --git a/channels/chan_sip.c b/channels/chan_sip.c index a6e5493c2..4bae39da0 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -30125,6 +30125,7 @@ static int sip_send_keepalive(const void *data) struct sip_peer *peer = (struct sip_peer*) data; int res = 0; const char keepalive[] = "\r\n"; + size_t count = sizeof(keepalive) - 1; peer->keepalivesend = -1; @@ -30135,12 +30136,12 @@ static int sip_send_keepalive(const void *data) /* Send the packet out using the proper method for this peer */ if ((peer->socket.fd != -1) && (peer->socket.type == AST_TRANSPORT_UDP)) { - res = ast_sendto(peer->socket.fd, keepalive, sizeof(keepalive), 0, &peer->addr); + res = ast_sendto(peer->socket.fd, keepalive, count, 0, &peer->addr); } else if ((peer->socket.type & (AST_TRANSPORT_TCP | AST_TRANSPORT_TLS)) && peer->socket.tcptls_session) { - res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, sizeof(keepalive)); + res = sip_tcptls_write(peer->socket.tcptls_session, keepalive, count); } else if (peer->socket.type == AST_TRANSPORT_UDP) { - res = ast_sendto(sipsock, keepalive, sizeof(keepalive), 0, &peer->addr); + res = ast_sendto(sipsock, keepalive, count, 0, &peer->addr); } if (res == -1) { @@ -30154,7 +30155,7 @@ static int sip_send_keepalive(const void *data) } } - if (res != sizeof(keepalive)) { + if (res != count) { ast_log(LOG_WARNING, "sip_send_keepalive to %s returned %d: %s\n", ast_sockaddr_stringify(&peer->addr), res, strerror(errno)); } @@ -30554,6 +30555,14 @@ static struct ast_channel *sip_request_call(const char *type, struct ast_format_ } } + /* If stripping the DNID left us with nothing, bail out */ + if (ast_strlen_zero(tmp)) { + dialog_unlink_all(p); + dialog_unref(p, "unref dialog p from bad destination"); + *cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER; + return NULL; + } + /* Divvy up the items separated by slashes */ AST_NONSTANDARD_APP_ARGS(args, tmp, '/'); diff --git a/channels/pjsip/dialplan_functions.c b/channels/pjsip/dialplan_functions.c index 861edf72d..aa376f892 100644 --- a/channels/pjsip/dialplan_functions.c +++ b/channels/pjsip/dialplan_functions.c @@ -388,7 +388,7 @@ </enumlist> </enum> <enum name="target_uri"> - <para>The request URI of the <literal>INVITE</literal> request associated with the creation of this channel.</para> + <para>The contact URI where requests are sent.</para> </enum> <enum name="local_uri"> <para>The local URI.</para> @@ -402,6 +402,10 @@ <enum name="remote_tag"> <para>Tag in To header</para> </enum> + <enum name="request_uri"> + <para>The request URI of the incoming <literal>INVITE</literal> + associated with the creation of this channel.</para> + </enum> <enum name="t38state"> <para>The current state of any T.38 fax on this channel.</para> <enumlist> @@ -656,6 +660,27 @@ static int channel_read_rtcp(struct ast_channel *chan, const char *type, const c return 0; } +static int print_escaped_uri(struct ast_channel *chan, const char *type, + pjsip_uri_context_e context, const void *uri, char *buf, size_t size) +{ + int res; + char *buf_copy; + + res = pjsip_uri_print(context, uri, buf, size); + if (res < 0) { + ast_log(LOG_ERROR, "Channel %s: Unescaped %s too long for %d byte buffer\n", + ast_channel_name(chan), type, (int) size); + + /* Empty buffer that likely is not terminated. */ + buf[0] = '\0'; + return -1; + } + + buf_copy = ast_strdupa(buf); + ast_escape_quoted(buf_copy, buf, size); + return 0; +} + /*! * \internal \brief Handle reading signalling information */ @@ -664,6 +689,7 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan); char *buf_copy; pjsip_dialog *dlg; + int res = 0; if (!channel) { ast_log(AST_LOG_WARNING, "Channel %s has no pvt!\n", ast_channel_name(chan)); @@ -689,25 +715,27 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const return -1; #endif } else if (!strcmp(type, "target_uri")) { - pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->target, buf, buflen); - buf_copy = ast_strdupa(buf); - ast_escape_quoted(buf_copy, buf, buflen); + res = print_escaped_uri(chan, type, PJSIP_URI_IN_REQ_URI, dlg->target, buf, + buflen); } else if (!strcmp(type, "local_uri")) { - 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); + res = print_escaped_uri(chan, type, PJSIP_URI_IN_FROMTO_HDR, dlg->local.info->uri, + 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); + res = print_escaped_uri(chan, type, PJSIP_URI_IN_FROMTO_HDR, + dlg->remote.info->uri, 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, "request_uri")) { + if (channel->session->request_uri) { + res = print_escaped_uri(chan, type, PJSIP_URI_IN_REQ_URI, + channel->session->request_uri, buf, buflen); + } } else if (!strcmp(type, "t38state")) { ast_copy_string(buf, t38state_to_string[channel->session->t38state], buflen); } else if (!strcmp(type, "local_addr")) { @@ -743,7 +771,7 @@ static int channel_read_pjsip(struct ast_channel *chan, const char *type, const return -1; } - return 0; + return res; } /*! \brief Struct used to push function arguments to task processor */ diff --git a/channels/vgrabbers.c b/channels/vgrabbers.c index 25817407e..169e59c5d 100644 --- a/channels/vgrabbers.c +++ b/channels/vgrabbers.c @@ -226,12 +226,8 @@ static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps) v->b = *geom; b = &v->b; /* shorthand */ - i = fcntl(fd, F_GETFL); - if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) { - /* non fatal, just emit a warning */ - ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n", - dev, strerror(errno)); - } + ast_fd_set_flags(fd, O_NONBLOCK); + /* set format for the camera. * In principle we could retry with a different format if the * one we are asking for is not supported. diff --git a/codecs/codec_dahdi.c b/codecs/codec_dahdi.c index efb016853..941bb1fb2 100644 --- a/codecs/codec_dahdi.c +++ b/codecs/codec_dahdi.c @@ -613,7 +613,6 @@ static int dahdi_translate(struct ast_trans_pvt *pvt, uint32_t dst_dahdi_fmt, ui /* Request translation through zap if possible */ int fd; struct codec_dahdi_pvt *dahdip = pvt->pvt; - int flags; int tried_once = 0; const char *dev_filename = "/dev/dahdi/transcode"; @@ -659,11 +658,7 @@ retry: return -1; } - flags = fcntl(fd, F_GETFL); - if (flags > - 1) { - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) - ast_log(LOG_WARNING, "Could not set non-block mode!\n"); - } + ast_fd_set_flags(fd, O_NONBLOCK); dahdip->fd = fd; diff --git a/codecs/codecs.xml b/codecs/codecs.xml index 0b4e2a474..c3ccf00f1 100644 --- a/codecs/codecs.xml +++ b/codecs/codecs.xml @@ -3,6 +3,7 @@ <depend>xmlstarlet</depend> <depend>bash</depend> <depend>res_format_attr_opus</depend> + <depend>curl</depend> <defaultenabled>no</defaultenabled> </member> <member name="codec_silk" displayname="Download the SILK codec from Digium. See http://downloads.digium.com/pub/telephony/codec_silk/README."> diff --git a/configs/samples/iax.conf.sample b/configs/samples/iax.conf.sample index ebe4d7fdc..c6da46179 100644 --- a/configs/samples/iax.conf.sample +++ b/configs/samples/iax.conf.sample @@ -576,12 +576,12 @@ inkeys=freeworlddialup ; ; Peers may also be specified, with a secret and a remote hostname. ; -[demo] -type=peer -username=asterisk -secret=supersecret -host=216.207.245.47 -description=Demo System At Digium ; Description of this peer, as listed by +;[demo] +;type=peer +;username=asterisk +;secret=supersecret +;host=192.168.10.10 +;description=My IAX2 Peer ; Description of this peer, as listed by ; 'iax2 show peers' ;sendani=no ;host=asterisk.linux-support.net diff --git a/funcs/func_cdr.c b/funcs/func_cdr.c index 573431237..2dd9f1578 100644 --- a/funcs/func_cdr.c +++ b/funcs/func_cdr.c @@ -356,7 +356,7 @@ static void cdr_read_callback(void *data, struct stasis_subscription *sub, struc static void cdr_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - struct cdr_func_payload *payload = stasis_message_data(message); + struct cdr_func_payload *payload; struct ast_flags flags = { 0 }; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(variable); @@ -367,21 +367,17 @@ static void cdr_write_callback(void *data, struct stasis_subscription *sub, stru if (cdr_write_message_type() != stasis_message_type(message)) { return; } - + payload = stasis_message_data(message); if (!payload) { return; } - - if (ast_strlen_zero(payload->arguments)) { - ast_log(AST_LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)", - payload->cmd, payload->cmd); - return; - } - if (!payload->value) { - ast_log(AST_LOG_WARNING, "%s requires a value (%s(variable)=value)\n)", - payload->cmd, payload->cmd); + if (ast_strlen_zero(payload->arguments) + || !payload->value) { + /* Sanity check. cdr_write() could never send these bad messages */ + ast_assert(0); return; } + parse = ast_strdupa(payload->arguments); AST_STANDARD_APP_ARGS(args, parse); @@ -389,32 +385,16 @@ static void cdr_write_callback(void *data, struct stasis_subscription *sub, stru ast_app_parse_options(cdr_func_options, &flags, NULL, args.options); } - if (!strcasecmp(args.variable, "accountcode")) { - ast_log(AST_LOG_WARNING, "Using the CDR function to set 'accountcode' is deprecated. Please use the CHANNEL function instead.\n"); - ast_channel_lock(payload->chan); - ast_channel_accountcode_set(payload->chan, payload->value); - ast_channel_unlock(payload->chan); - } else if (!strcasecmp(args.variable, "peeraccount")) { - ast_log(AST_LOG_WARNING, "The 'peeraccount' setting is not supported. Please set the 'accountcode' on the appropriate channel using the CHANNEL function.\n"); - } else if (!strcasecmp(args.variable, "userfield")) { + /* These are already handled by cdr_write() */ + ast_assert(strcasecmp(args.variable, "accountcode") + && strcasecmp(args.variable, "peeraccount") + && strcasecmp(args.variable, "amaflags")); + + if (!strcasecmp(args.variable, "userfield")) { ast_cdr_setuserfield(ast_channel_name(payload->chan), payload->value); - } else if (!strcasecmp(args.variable, "amaflags")) { - ast_log(AST_LOG_WARNING, "Using the CDR function to set 'amaflags' is deprecated. Please use the CHANNEL function instead.\n"); - if (isdigit(*payload->value)) { - int amaflags; - sscanf(payload->value, "%30d", &amaflags); - ast_channel_lock(payload->chan); - ast_channel_amaflags_set(payload->chan, amaflags); - ast_channel_unlock(payload->chan); - } else { - ast_channel_lock(payload->chan); - ast_channel_amaflags_set(payload->chan, ast_channel_string2amaflag(payload->value)); - ast_channel_unlock(payload->chan); - } } else { ast_cdr_setvar(ast_channel_name(payload->chan), args.variable, payload->value); } - return; } static void cdr_prop_write_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message) @@ -523,27 +503,70 @@ static int cdr_read(struct ast_channel *chan, const char *cmd, char *parse, return 0; } -static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse, - const char *value) +static int cdr_write(struct ast_channel *chan, const char *cmd, char *arguments, + const char *value) { - RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); - RAII_VAR(struct cdr_func_payload *, payload, NULL, ao2_cleanup); - RAII_VAR(struct stasis_message_router *, router, - ast_cdr_message_router(), ao2_cleanup); + struct stasis_message *message; + struct cdr_func_payload *payload; + struct stasis_message_router *router; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(variable); + AST_APP_ARG(options); + ); + char *parse; if (!chan) { ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd); return -1; } - - if (!router) { - ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n", - ast_channel_name(chan)); + if (ast_strlen_zero(arguments)) { + ast_log(LOG_WARNING, "%s requires a variable (%s(variable)=value)\n)", + cmd, cmd); + return -1; + } + if (!value) { + ast_log(LOG_WARNING, "%s requires a value (%s(variable)=value)\n)", + cmd, cmd); return -1; } + parse = ast_strdupa(arguments); + AST_STANDARD_APP_ARGS(args, parse); + + /* These CDR variables are no longer supported or set directly on the channel */ + if (!strcasecmp(args.variable, "accountcode")) { + ast_log(LOG_WARNING, "Using the %s function to set 'accountcode' is deprecated. Please use the CHANNEL function instead.\n", + cmd); + ast_channel_lock(chan); + ast_channel_accountcode_set(chan, value); + ast_channel_unlock(chan); + return 0; + } + if (!strcasecmp(args.variable, "amaflags")) { + int amaflags; + + ast_log(LOG_WARNING, "Using the %s function to set 'amaflags' is deprecated. Please use the CHANNEL function instead.\n", + cmd); + if (isdigit(*value)) { + if (sscanf(value, "%30d", &amaflags) != 1) { + amaflags = AST_AMA_NONE; + } + } else { + amaflags = ast_channel_string2amaflag(value); + } + ast_channel_lock(chan); + ast_channel_amaflags_set(chan, amaflags); + ast_channel_unlock(chan); + return 0; + } + if (!strcasecmp(args.variable, "peeraccount")) { + ast_log(LOG_WARNING, "The 'peeraccount' setting is not supported. Please set the 'accountcode' on the appropriate channel using the CHANNEL function.\n"); + return 0; + } + + /* The remaining CDR variables are handled by CDR processing code */ if (!cdr_write_message_type()) { - ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n", + ast_log(LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n", ast_channel_name(chan)); return -1; } @@ -554,16 +577,26 @@ static int cdr_write(struct ast_channel *chan, const char *cmd, char *parse, } payload->chan = chan; payload->cmd = cmd; - payload->arguments = parse; + payload->arguments = arguments; payload->value = value; message = stasis_message_create(cdr_write_message_type(), payload); + ao2_ref(payload, -1); if (!message) { - ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n", + ast_log(LOG_WARNING, "Failed to manipulate CDR for channel %s: unable to create message\n", ast_channel_name(chan)); return -1; } + router = ast_cdr_message_router(); + if (!router) { + ast_log(LOG_WARNING, "Failed to manipulate CDR for channel %s: no message router\n", + ast_channel_name(chan)); + ao2_ref(message, -1); + return -1; + } stasis_message_router_publish_sync(router, message); + ao2_ref(router, -1); + ao2_ref(message, -1); return 0; } @@ -586,7 +619,7 @@ static int cdr_prop_write(struct ast_channel *chan, const char *cmd, char *parse return -1; } - if (!cdr_write_message_type()) { + if (!cdr_prop_write_message_type()) { ast_log(AST_LOG_WARNING, "Failed to manipulate CDR for channel %s: message type not available\n", ast_channel_name(chan)); return -1; diff --git a/funcs/func_channel.c b/funcs/func_channel.c index eb3ceddb4..b72cb141e 100644 --- a/funcs/func_channel.c +++ b/funcs/func_channel.c @@ -495,18 +495,17 @@ static int func_channel_write_real(struct ast_channel *chan, const char *functio ast_bridge_set_after_go_on(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), value); } } else if (!strcasecmp(data, "amaflags")) { - ast_channel_lock(chan); + int amaflags; + if (isdigit(*value)) { - int amaflags; - sscanf(value, "%30d", &amaflags); - ast_channel_amaflags_set(chan, amaflags); - } else if (!strcasecmp(value,"OMIT")){ - ast_channel_amaflags_set(chan, 1); - } else if (!strcasecmp(value,"BILLING")){ - ast_channel_amaflags_set(chan, 2); - } else if (!strcasecmp(value,"DOCUMENTATION")){ - ast_channel_amaflags_set(chan, 3); + if (sscanf(value, "%30d", &amaflags) != 1) { + amaflags = AST_AMA_NONE; + } + } else { + amaflags = ast_channel_string2amaflag(value); } + ast_channel_lock(chan); + ast_channel_amaflags_set(chan, amaflags); ast_channel_unlock(chan); } else if (!strcasecmp(data, "peeraccount")) locked_string_field_set(chan, peeraccount, value); diff --git a/include/asterisk/astdb.h b/include/asterisk/astdb.h index 8a870ae83..383864baf 100644 --- a/include/asterisk/astdb.h +++ b/include/asterisk/astdb.h @@ -83,6 +83,16 @@ int ast_db_deltree(const char *family, const char *keytree); */ struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree); +/*! + * \brief Get a list of values with the given key prefix + * + * \param family The family to search under + * \param key_prefix The key prefix to search under + * + * \retval NULL An error occurred + */ +struct ast_db_entry *ast_db_gettree_by_prefix(const char *family, const char *key_prefix); + /*! \brief Free structure created by ast_db_gettree() */ void ast_db_freetree(struct ast_db_entry *entry); diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index de6589abd..6d506a35b 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -211,6 +211,8 @@ struct ast_sip_session { unsigned int ended_while_deferred:1; /*! DTMF mode to use with this session, from endpoint but can change */ enum ast_sip_dtmf_mode dtmf; + /*! Initial incoming INVITE Request-URI. NULL otherwise. */ + pjsip_uri *request_uri; }; typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *session, pjsip_tx_data *tdata); diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 0a12b1d8a..c6c34074e 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -1141,4 +1141,44 @@ int ast_compare_versions(const char *version1, const char *version2); */ int ast_check_ipv6(void); +enum ast_fd_flag_operation { + AST_FD_FLAG_SET, + AST_FD_FLAG_CLEAR, +}; + +/* + * \brief Set flags on the given file descriptor + * \since 13.19 + * + * If getting or setting flags of the given file descriptor fails, logs an + * error message. + * + * \param fd File descriptor to set flags on + * \param flags The flag(s) to set + * + * \return -1 on error + * \return 0 if successful + */ +#define ast_fd_set_flags(fd, flags) \ + __ast_fd_set_flags((fd), (flags), AST_FD_FLAG_SET, __FILE__, __LINE__, __PRETTY_FUNCTION__) + +/* + * \brief Clear flags on the given file descriptor + * \since 13.19 + * + * If getting or setting flags of the given file descriptor fails, logs an + * error message. + * + * \param fd File descriptor to clear flags on + * \param flags The flag(s) to clear + * + * \return -1 on error + * \return 0 if successful + */ +#define ast_fd_clear_flags(fd, flags) \ + __ast_fd_set_flags((fd), (flags), AST_FD_FLAG_CLEAR, __FILE__, __LINE__, __PRETTY_FUNCTION__) + +int __ast_fd_set_flags(int fd, int flags, enum ast_fd_flag_operation op, + const char *file, int lineno, const char *function); + #endif /* _ASTERISK_UTILS_H */ diff --git a/main/alertpipe.c b/main/alertpipe.c index fa6ec7bcc..7932a7346 100644 --- a/main/alertpipe.c +++ b/main/alertpipe.c @@ -55,17 +55,8 @@ int ast_alertpipe_init(int alert_pipe[2]) 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)); + if (ast_fd_set_flags(alert_pipe[0], O_NONBLOCK) + || ast_fd_set_flags(alert_pipe[1], O_NONBLOCK)) { ast_alertpipe_close(alert_pipe); return -1; } diff --git a/main/asterisk.c b/main/asterisk.c index 2c86d1ebc..006a1b03a 100644 --- a/main/asterisk.c +++ b/main/asterisk.c @@ -733,6 +733,27 @@ static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cl int totalswap = 0; #if defined(HAVE_SYSINFO) struct sysinfo sys_info; +#elif defined(HAVE_SYSCTL) + static int pageshift; + struct vmtotal vmtotal; + struct timeval boottime; + time_t now; + int mib[2], pagesize, usedswap = 0; + size_t len; +#endif + + switch (cmd) { + case CLI_INIT: + e->command = "core show sysinfo"; + e->usage = + "Usage: core show sysinfo\n" + " List current system information.\n"; + return NULL; + case CLI_GENERATE: + return NULL; + } + +#if defined(HAVE_SYSINFO) sysinfo(&sys_info); uptime = sys_info.uptime / 3600; physmem = sys_info.totalram * sys_info.mem_unit; @@ -741,12 +762,6 @@ static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cl freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024; nprocs = sys_info.procs; #elif defined(HAVE_SYSCTL) - static int pageshift; - struct vmtotal vmtotal; - struct timeval boottime; - time_t now; - int mib[2], pagesize, usedswap = 0; - size_t len; /* calculate the uptime by looking at boottime */ time(&now); mib[0] = CTL_KERN; @@ -794,17 +809,6 @@ static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cl #endif #endif - switch (cmd) { - case CLI_INIT: - e->command = "core show sysinfo"; - e->usage = - "Usage: core show sysinfo\n" - " List current system information.\n"; - return NULL; - case CLI_GENERATE: - return NULL; - } - ast_cli(a->fd, "\nSystem Statistics\n"); ast_cli(a->fd, "-----------------\n"); ast_cli(a->fd, " System Uptime: %ld hours\n", uptime); @@ -1569,7 +1573,6 @@ static void *listener(void *unused) int s; socklen_t len; int x; - int flags; struct pollfd fds[1]; for (;;) { if (ast_socket < 0) @@ -1607,8 +1610,7 @@ static void *listener(void *unused) close(s); break; } - flags = fcntl(consoles[x].p[1], F_GETFL); - fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(consoles[x].p[1], O_NONBLOCK); consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */ /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able to know if the user didn't send the credentials. */ @@ -3012,19 +3014,26 @@ static char *cli_prompt(EditLine *editline) static struct ast_vector_string *ast_el_strtoarr(char *buf) { char *retstr; + char *bestmatch; struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec)); if (!vec) { return NULL; } + /* bestmatch must not be deduplicated */ + bestmatch = strsep(&buf, " "); + if (!bestmatch || !strcmp(bestmatch, AST_CLI_COMPLETE_EOF)) { + goto vector_cleanup; + } + while ((retstr = strsep(&buf, " "))) { if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) { break; } /* Older daemons sent duplicates. */ - if (AST_VECTOR_GET_CMP(vec, retstr, strcasecmp)) { + if (AST_VECTOR_GET_CMP(vec, retstr, !strcasecmp)) { continue; } @@ -3036,7 +3045,9 @@ static struct ast_vector_string *ast_el_strtoarr(char *buf) } } - if (!AST_VECTOR_SIZE(vec)) { + bestmatch = ast_strdup(bestmatch); + if (!bestmatch || AST_VECTOR_INSERT_AT(vec, 0, bestmatch)) { + ast_free(bestmatch); goto vector_cleanup; } @@ -4632,10 +4643,15 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou 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 is initialized after the dynamic modules load to avoid repeatedly + * reindexing sounds for every format module load. + */ + check_init(ast_sounds_index_init(), "Sounds Indexer"); + + /* * 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. diff --git a/main/bridge_basic.c b/main/bridge_basic.c index fd6bac0c9..68138bdcc 100644 --- a/main/bridge_basic.c +++ b/main/bridge_basic.c @@ -3170,7 +3170,8 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len ast_channel_lock(chan); xfer_cfg = ast_get_chan_features_xfer_config(chan); if (!xfer_cfg) { - ast_log(LOG_ERROR, "Unable to get transfer configuration\n"); + ast_log(LOG_ERROR, "Channel %s: Unable to get transfer configuration\n", + ast_channel_name(chan)); ast_channel_unlock(chan); return -1; } @@ -3214,9 +3215,9 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len } else if (!res) { /* 0 for invalid extension dialed. */ if (ast_strlen_zero(exten)) { - ast_debug(1, "%s dialed no digits.\n", ast_channel_name(chan)); + ast_verb(3, "Channel %s: Dialed no digits.\n", ast_channel_name(chan)); } else { - ast_debug(1, "%s dialed '%s@%s' does not exist.\n", + ast_verb(3, "Channel %s: Dialed '%s@%s' does not exist.\n", ast_channel_name(chan), exten, context); } if (attempts < max_attempts) { @@ -3303,9 +3304,12 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, /* Inhibit the bridge before we do anything else. */ bridge = ast_bridge_channel_merge_inhibit(bridge_channel, +1); + ast_verb(3, "Channel %s: Started DTMF attended transfer.\n", + ast_channel_name(bridge_channel->chan)); + if (strcmp(bridge->v_table->name, "basic")) { - ast_log(LOG_ERROR, "Attended transfer attempted on unsupported bridge type '%s'.\n", - bridge->v_table->name); + ast_log(LOG_ERROR, "Channel %s: Attended transfer attempted on unsupported bridge type '%s'.\n", + ast_channel_name(bridge_channel->chan), bridge->v_table->name); ast_bridge_merge_inhibit(bridge, -1); ao2_ref(bridge, -1); return 0; @@ -3327,7 +3331,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, props = attended_transfer_properties_alloc(bridge_channel->chan, attended_transfer ? attended_transfer->context : NULL); if (!props) { - ast_log(LOG_ERROR, "Unable to allocate control structure for performing attended transfer.\n"); + ast_log(LOG_ERROR, "Channel %s: Unable to allocate control structure for performing attended transfer.\n", + ast_channel_name(bridge_channel->chan)); ast_bridge_merge_inhibit(bridge, -1); ao2_ref(bridge, -1); return 0; @@ -3336,7 +3341,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, props->transferee_bridge = bridge; if (add_transferer_role(props->transferer, attended_transfer)) { - ast_log(LOG_ERROR, "Unable to set transferrer bridge role.\n"); + ast_log(LOG_ERROR, "Channel %s: Unable to set transferrer bridge role.\n", + ast_channel_name(bridge_channel->chan)); attended_transfer_properties_shutdown(props); return 0; } @@ -3345,7 +3351,15 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, /* Grab the extension to transfer to */ if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context)) { - ast_log(LOG_WARNING, "Unable to acquire target extension for attended transfer.\n"); + /* + * XXX The warning here really should be removed. While the + * message is accurate, this is a normal exit for when the user + * fails to specify a valid transfer target. e.g., The user + * hungup, didn't dial any digits, or dialed an invalid + * extension. + */ + ast_log(LOG_WARNING, "Channel %s: Unable to acquire target extension for attended transfer.\n", + ast_channel_name(bridge_channel->chan)); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); return 0; @@ -3356,12 +3370,14 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, /* Fill the variable with the extension and context we want to call */ snprintf(destination, sizeof(destination), "%s@%s", props->exten, props->context); - ast_debug(1, "Attended transfer to '%s'\n", destination); + ast_debug(1, "Channel %s: Attended transfer target '%s'\n", + ast_channel_name(bridge_channel->chan), destination); /* Get a channel that is the destination we wish to call */ 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_log(LOG_ERROR, "Channel %s: Unable to request outbound channel for attended transfer target.\n", + ast_channel_name(bridge_channel->chan)); stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); @@ -3372,7 +3388,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, /* Create a bridge to use to talk to the person we are calling */ 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_log(LOG_ERROR, "Channel %s: Unable to create bridge for attended transfer target.\n", + ast_channel_name(bridge_channel->chan)); stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); @@ -3383,7 +3400,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, ast_bridge_merge_inhibit(props->target_bridge, +1); if (attach_framehook(props, props->transfer_target)) { - ast_log(LOG_ERROR, "Unable to attach framehook to transfer target.\n"); + ast_log(LOG_ERROR, "Channel %s: Unable to attach framehook to transfer target.\n", + ast_channel_name(bridge_channel->chan)); stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); @@ -3398,7 +3416,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, BRIDGE_BASIC_PERSONALITY_ATXFER, props); if (ast_call(props->transfer_target, destination, 0)) { - ast_log(LOG_ERROR, "Unable to place outbound call to transfer target.\n"); + ast_log(LOG_ERROR, "Channel %s: Unable to place outbound call to transfer target.\n", + ast_channel_name(bridge_channel->chan)); stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); @@ -3414,7 +3433,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel, ast_channel_ref(props->transfer_target); 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_log(LOG_ERROR, "Channel %s: Unable to place transfer target into bridge.\n", + ast_channel_name(bridge_channel->chan)); stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); ast_hangup(props->transfer_target); @@ -3424,7 +3444,8 @@ 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_log(LOG_ERROR, "Channel %s: Unable to create monitoring thread for attended transfer.\n", + ast_channel_name(bridge_channel->chan)); stream_failsound(props->transferer); ast_bridge_channel_write_unhold(bridge_channel); attended_transfer_properties_shutdown(props); @@ -3455,6 +3476,9 @@ static int feature_blind_transfer(struct ast_bridge_channel *bridge_channel, voi const char *xfer_context; char *goto_on_blindxfr; + ast_verb(3, "Channel %s: Started DTMF blind transfer.\n", + ast_channel_name(bridge_channel->chan)); + ast_bridge_channel_write_hold(bridge_channel, NULL); ast_channel_lock(bridge_channel->chan); @@ -3470,13 +3494,16 @@ static int feature_blind_transfer(struct ast_bridge_channel *bridge_channel, voi return 0; } + ast_debug(1, "Channel %s: Blind transfer target '%s@%s'\n", + ast_channel_name(bridge_channel->chan), xfer_exten, xfer_context); + 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_debug(1, "Channel %s: After transfer, transferrer goes to %s\n", + ast_channel_name(bridge_channel->chan), goto_on_blindxfr); ast_channel_lock(bridge_channel->chan); chan_context = ast_strdupa(ast_channel_context(bridge_channel->chan)); @@ -127,6 +127,20 @@ DEFINE_SQL_STATEMENT(gettree_all_stmt, "SELECT key, value FROM astdb ORDER BY ke DEFINE_SQL_STATEMENT(showkey_stmt, "SELECT key, value FROM astdb WHERE key LIKE '%' || '/' || ? ORDER BY key") DEFINE_SQL_STATEMENT(create_astdb_stmt, "CREATE TABLE IF NOT EXISTS astdb(key VARCHAR(256), value VARCHAR(256), PRIMARY KEY(key))") +/* This query begs an explanation: + * + * First, the parameter binding syntax used here is slightly different then the other + * queries in that we use a numbered parameter so that we can bind once and get the same + * value substituted multiple times within the executed query. + * + * Second, the key comparison is being used to find all keys that are lexicographically + * greater than the provided key, but less than the provided key with a high (but + * invalid) Unicode codepoint appended to it. This will give us all keys in the database + * that have 'key' as a prefix and performs much better than the equivalent "LIKE key || + * '%'" operation. + */ +DEFINE_SQL_STATEMENT(gettree_prefix_stmt, "SELECT key, value FROM astdb WHERE key > ?1 AND key <= ?1 || X'ffff'") + static int init_stmt(sqlite3_stmt **stmt, const char *sql, size_t len) { ast_mutex_lock(&dblock); @@ -167,6 +181,7 @@ static void clean_statements(void) clean_stmt(&deltree_all_stmt, deltree_all_stmt_sql); clean_stmt(&gettree_stmt, gettree_stmt_sql); clean_stmt(&gettree_all_stmt, gettree_all_stmt_sql); + clean_stmt(&gettree_prefix_stmt, gettree_prefix_stmt_sql); clean_stmt(&showkey_stmt, showkey_stmt_sql); clean_stmt(&put_stmt, put_stmt_sql); clean_stmt(&create_astdb_stmt, create_astdb_stmt_sql); @@ -182,6 +197,7 @@ static int init_statements(void) || init_stmt(&deltree_all_stmt, deltree_all_stmt_sql, sizeof(deltree_all_stmt_sql)) || init_stmt(&gettree_stmt, gettree_stmt_sql, sizeof(gettree_stmt_sql)) || init_stmt(&gettree_all_stmt, gettree_all_stmt_sql, sizeof(gettree_all_stmt_sql)) + || init_stmt(&gettree_prefix_stmt, gettree_prefix_stmt_sql, sizeof(gettree_prefix_stmt_sql)) || init_stmt(&showkey_stmt, showkey_stmt_sql, sizeof(showkey_stmt_sql)) || init_stmt(&put_stmt, put_stmt_sql, sizeof(put_stmt_sql)); } @@ -473,19 +489,64 @@ int ast_db_deltree(const char *family, const char *keytree) return res; } +static struct ast_db_entry *db_gettree_common(sqlite3_stmt *stmt) +{ + struct ast_db_entry *head = NULL, *prev = NULL, *cur; + + while (sqlite3_step(stmt) == SQLITE_ROW) { + const char *key, *value; + size_t key_len, value_len; + + key = (const char *) sqlite3_column_text(stmt, 0); + value = (const char *) sqlite3_column_text(stmt, 1); + + if (!key || !value) { + break; + } + + key_len = strlen(key); + value_len = strlen(value); + + cur = ast_malloc(sizeof(*cur) + key_len + value_len + 2); + if (!cur) { + break; + } + + cur->next = NULL; + cur->key = cur->data + value_len + 1; + memcpy(cur->data, value, value_len + 1); + memcpy(cur->key, key, key_len + 1); + + if (prev) { + prev->next = cur; + } else { + head = cur; + } + prev = cur; + } + + return head; +} + struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree) { char prefix[MAX_DB_FIELD]; sqlite3_stmt *stmt = gettree_stmt; - struct ast_db_entry *cur, *last = NULL, *ret = NULL; + size_t res = 0; + struct ast_db_entry *ret; if (!ast_strlen_zero(family)) { if (!ast_strlen_zero(keytree)) { /* Family and key tree */ - snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree); + res = snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree); } else { /* Family only */ - snprintf(prefix, sizeof(prefix), "/%s", family); + res = snprintf(prefix, sizeof(prefix), "/%s", family); + } + + if (res >= sizeof(prefix)) { + ast_log(LOG_WARNING, "Requested prefix is too long: %s\n", keytree); + return NULL; } } else { prefix[0] = '\0'; @@ -493,41 +554,47 @@ struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree) } ast_mutex_lock(&dblock); - if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) { - ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb)); + if (res && (sqlite3_bind_text(stmt, 1, prefix, res, SQLITE_STATIC) != SQLITE_OK)) { + ast_log(LOG_WARNING, "Could not bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb)); sqlite3_reset(stmt); ast_mutex_unlock(&dblock); return NULL; } - while (sqlite3_step(stmt) == SQLITE_ROW) { - const char *key_s, *value_s; - if (!(key_s = (const char *) sqlite3_column_text(stmt, 0))) { - break; - } - if (!(value_s = (const char *) sqlite3_column_text(stmt, 1))) { - break; - } - if (!(cur = ast_malloc(sizeof(*cur) + strlen(key_s) + strlen(value_s) + 2))) { - break; - } - cur->next = NULL; - cur->key = cur->data + strlen(value_s) + 1; - strcpy(cur->data, value_s); - strcpy(cur->key, key_s); - if (last) { - last->next = cur; - } else { - ret = cur; - } - last = cur; - } + ret = db_gettree_common(stmt); sqlite3_reset(stmt); ast_mutex_unlock(&dblock); return ret; } +struct ast_db_entry *ast_db_gettree_by_prefix(const char *family, const char *key_prefix) +{ + char prefix[MAX_DB_FIELD]; + size_t res; + struct ast_db_entry *ret; + + res = snprintf(prefix, sizeof(prefix), "/%s/%s", family, key_prefix); + if (res >= sizeof(prefix)) { + ast_log(LOG_WARNING, "Requested key prefix is too long: %s\n", key_prefix); + return NULL; + } + + ast_mutex_lock(&dblock); + if (sqlite3_bind_text(gettree_prefix_stmt, 1, prefix, res, SQLITE_STATIC) != SQLITE_OK) { + ast_log(LOG_WARNING, "Could not bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb)); + sqlite3_reset(gettree_prefix_stmt); + ast_mutex_unlock(&dblock); + return NULL; + } + + ret = db_gettree_common(gettree_prefix_stmt); + sqlite3_reset(gettree_prefix_stmt); + ast_mutex_unlock(&dblock); + + return ret; +} + void ast_db_freetree(struct ast_db_entry *dbe) { struct ast_db_entry *last; diff --git a/main/iostream.c b/main/iostream.c index d91863319..aaa74fae1 100644 --- a/main/iostream.c +++ b/main/iostream.c @@ -77,7 +77,7 @@ int ast_iostream_get_fd(struct ast_iostream *stream) void ast_iostream_nonblock(struct ast_iostream *stream) { - fcntl(stream->fd, F_SETFL, fcntl(stream->fd, F_GETFL) | O_NONBLOCK); + ast_fd_set_flags(stream->fd, O_NONBLOCK); } SSL *ast_iostream_get_ssl(struct ast_iostream *stream) diff --git a/main/loader.c b/main/loader.c index 19e30f835..23a29d994 100644 --- a/main/loader.c +++ b/main/loader.c @@ -376,35 +376,39 @@ static int verify_key(const unsigned char *key) return -1; } -static int resource_name_match(const char *name1_in, const char *name2_in) +static size_t resource_name_baselen(const char *name) { - char *name1 = (char *) name1_in; - char *name2 = (char *) name2_in; + size_t len = strlen(name); - /* trim off any .so extensions */ - if (!strcasecmp(name1 + strlen(name1) - 3, ".so")) { - name1 = ast_strdupa(name1); - name1[strlen(name1) - 3] = '\0'; + if (len > 3 && !strcasecmp(name + len - 3, ".so")) { + return len - 3; } - if (!strcasecmp(name2 + strlen(name2) - 3, ".so")) { - name2 = ast_strdupa(name2); - name2[strlen(name2) - 3] = '\0'; + + return len; +} + +static int resource_name_match(const char *name1, size_t baselen1, const char *name2) +{ + if (baselen1 != resource_name_baselen(name2)) { + return -1; } - return strcasecmp(name1, name2); + return strncasecmp(name1, name2, baselen1); } static struct ast_module *find_resource(const char *resource, int do_lock) { struct ast_module *cur; + size_t resource_baselen = resource_name_baselen(resource); if (do_lock) { AST_DLLIST_LOCK(&module_list); } AST_DLLIST_TRAVERSE(&module_list, cur, entry) { - if (!resource_name_match(resource, cur->resource)) + if (!resource_name_match(resource, resource_baselen, cur->resource)) { break; + } } if (do_lock) { @@ -939,6 +943,7 @@ enum ast_module_reload_result ast_module_reload(const char *name) struct ast_module *cur; enum ast_module_reload_result res = AST_MODULE_RELOAD_NOT_FOUND; int i; + size_t name_baselen = name ? resource_name_baselen(name) : 0; /* If we aren't fully booted, we just pretend we reloaded but we queue this up to run once we are booted up. */ @@ -992,8 +997,9 @@ enum ast_module_reload_result ast_module_reload(const char *name) AST_DLLIST_TRAVERSE(&module_list, cur, entry) { const struct ast_module_info *info = cur->info; - if (name && resource_name_match(name, cur->resource)) + if (name && resource_name_match(name, name_baselen, cur->resource)) { continue; + } if (!cur->flags.running || cur->flags.declined) { if (res == AST_MODULE_RELOAD_NOT_FOUND) { @@ -1187,9 +1193,10 @@ AST_LIST_HEAD_NOLOCK(load_order, load_order_entry); static struct load_order_entry *add_to_load_order(const char *resource, struct load_order *load_order, int required) { struct load_order_entry *order; + size_t resource_baselen = resource_name_baselen(resource); AST_LIST_TRAVERSE(load_order, order, entry) { - if (!resource_name_match(order->resource, resource)) { + if (!resource_name_match(resource, resource_baselen, order->resource)) { /* Make sure we have the proper setting for the required field (we might have both load= and required= lines in modules.conf) */ order->required |= required; @@ -1436,11 +1443,15 @@ int load_modules(unsigned int preload_only) /* now scan the config for any modules we are prohibited from loading and remove them from the load order */ for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) { - if (strcasecmp(v->name, "noload")) + size_t baselen; + + if (strcasecmp(v->name, "noload")) { continue; + } + baselen = resource_name_baselen(v->value); AST_LIST_TRAVERSE_SAFE_BEGIN(&load_order, order, entry) { - if (!resource_name_match(order->resource, v->value)) { + if (!resource_name_match(v->value, baselen, order->resource)) { AST_LIST_REMOVE_CURRENT(entry); ast_free(order->resource); ast_free(order); diff --git a/main/media_index.c b/main/media_index.c index 3e3824580..60bdfe3fd 100644 --- a/main/media_index.c +++ b/main/media_index.c @@ -45,10 +45,10 @@ /*! \brief Structure to hold a list of the format variations for a media file for a specific variant */ struct media_variant { AST_DECLARE_STRING_FIELDS( - AST_STRING_FIELD(variant); /*!< The variant this media is available in */ AST_STRING_FIELD(description); /*!< The description of the media */ ); struct ast_format_cap *formats; /*!< The formats this media is available in for this variant */ + char variant[0]; /*!< The variant this media is available in */ }; static void media_variant_destroy(void *obj) @@ -61,20 +61,23 @@ static void media_variant_destroy(void *obj) static struct media_variant *media_variant_alloc(const char *variant_str) { - RAII_VAR(struct media_variant *, variant, ao2_alloc(sizeof(*variant), media_variant_destroy), ao2_cleanup); + size_t str_sz = strlen(variant_str) + 1; + struct media_variant *variant; - if (!variant || ast_string_field_init(variant, 8)) { + variant = ao2_alloc(sizeof(*variant) + str_sz, media_variant_destroy); + if (!variant) { return NULL; } + memcpy(variant->variant, variant_str, str_sz); + variant->formats = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT); - if (!variant->formats) { + if (!variant->formats || ast_string_field_init(variant, 8)) { + ao2_ref(variant, -1); + return NULL; } - ast_string_field_set(variant, variant, variant_str); - - ao2_ref(variant, 1); return variant; } @@ -93,37 +96,35 @@ static int media_variant_cmp(void *obj, void *arg, int flags) /*! \brief Structure to hold information about a media file */ struct media_info { - AST_DECLARE_STRING_FIELDS( - AST_STRING_FIELD(name); /*!< The file name of the media */ - ); - struct ao2_container *variants; /*!< The variants for which this media is available */ + struct ao2_container *variants; /*!< The variants for which this media is available */ + char name[0]; /*!< The file name of the media */ }; static void media_info_destroy(void *obj) { struct media_info *info = obj; - ast_string_field_free_memory(info); ao2_cleanup(info->variants); - info->variants = NULL; } static struct media_info *media_info_alloc(const char *name) { - RAII_VAR(struct media_info *, info, ao2_alloc(sizeof(*info), media_info_destroy), ao2_cleanup); + size_t name_sz = strlen(name) + 1; + struct media_info *info = ao2_alloc(sizeof(*info) + name_sz, media_info_destroy); - if (!info || ast_string_field_init(info, 128)) { + if (!info) { return NULL; } + memcpy(info->name, name, name_sz); + info->variants = ao2_container_alloc(VARIANT_BUCKETS, media_variant_hash, media_variant_cmp); if (!info->variants) { + ao2_ref(info, -1); + return NULL; } - ast_string_field_set(info, name, name); - - ao2_ref(info, 1); return info; } @@ -141,38 +142,37 @@ static int media_info_cmp(void *obj, void *arg, int flags) } struct ast_media_index { - AST_DECLARE_STRING_FIELDS( - AST_STRING_FIELD(base_dir); /*!< Base directory for indexing */ - ); struct ao2_container *index; /*!< The index of media that has requested */ struct ao2_container *media_list_cache; /*!< Cache of filenames to prevent them from being regenerated so often */ + char base_dir[0]; /*!< Base directory for indexing */ }; static void media_index_dtor(void *obj) { struct ast_media_index *index = obj; + ao2_cleanup(index->index); - index->index = NULL; ao2_cleanup(index->media_list_cache); - index->media_list_cache = NULL; - ast_string_field_free_memory(index); } struct ast_media_index *ast_media_index_create(const char *base_dir) { - RAII_VAR(struct ast_media_index *, index, ao2_alloc(sizeof(*index), media_index_dtor), ao2_cleanup); - if (!index || ast_string_field_init(index, 64)) { + size_t base_dir_sz = strlen(base_dir) + 1; + struct ast_media_index *index = ao2_alloc(sizeof(*index) + base_dir_sz, media_index_dtor); + + if (!index) { return NULL; } - ast_string_field_set(index, base_dir, base_dir); + memcpy(index->base_dir, base_dir, base_dir_sz); index->index = ao2_container_alloc(INDEX_BUCKETS, media_info_hash, media_info_cmp); if (!index->index) { + ao2_ref(index, -1); + return NULL; } - ao2_ref(index, +1); return index; } @@ -191,8 +191,8 @@ static struct media_variant *find_variant(struct ast_media_index *index, const c /*! \brief create the appropriate media_variant and any necessary structures */ static struct media_variant *alloc_variant(struct ast_media_index *index, const char *filename, const char *variant_str) { - RAII_VAR(struct media_info *, info, NULL, ao2_cleanup); - RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup); + struct media_info *info; + struct media_variant *variant = NULL; info = ao2_find(index->index, filename, OBJ_KEY); if (!info) { @@ -204,21 +204,21 @@ static struct media_variant *alloc_variant(struct ast_media_index *index, const } ao2_link(index->index, info); + } else { + variant = ao2_find(info->variants, variant_str, OBJ_KEY); } - variant = ao2_find(info->variants, variant_str, OBJ_KEY); if (!variant) { /* This is the first time the index has seen this variant for * this filename, allocate and link */ variant = media_variant_alloc(variant_str); - if (!variant) { - return NULL; + if (variant) { + ao2_link(info->variants, variant); } - - ao2_link(info->variants, variant); } - ao2_ref(variant, +1); + ao2_ref(info, -1); + return variant; } @@ -324,15 +324,16 @@ struct ao2_container *ast_media_get_media(struct ast_media_index *index) /*! \brief Update an index with new format/variant information */ static int update_file_format_info(struct ast_media_index *index, const char *filename, const char *variant_str, struct ast_format *file_format) { - RAII_VAR(struct media_variant *, variant, find_variant(index, filename, variant_str), ao2_cleanup); + struct media_variant *variant; + + variant = alloc_variant(index, filename, variant_str); if (!variant) { - variant = alloc_variant(index, filename, variant_str); - if (!variant) { - return -1; - } + return -1; } ast_format_cap_append(variant->formats, file_format, 0); + ao2_ref(variant, -1); + return 0; } @@ -341,7 +342,8 @@ static int process_media_file(struct ast_media_index *index, const char *variant { struct ast_format *file_format; const char *file_identifier = filename_stripped; - RAII_VAR(struct ast_str *, file_id_str, NULL, ast_free); + char *file_id_str = NULL; + int res; file_format = ast_get_format_for_file_ext(ext); if (!file_format) { @@ -351,19 +353,17 @@ static int process_media_file(struct ast_media_index *index, const char *variant /* handle updating the file information */ if (subdir) { - file_id_str = ast_str_create(64); - if (!file_id_str) { + if (ast_asprintf(&file_id_str, "%s/%s", subdir, filename_stripped) == -1) { return -1; } - ast_str_set(&file_id_str, 0, "%s/%s", subdir, filename_stripped); - file_identifier = ast_str_buffer(file_id_str); + file_identifier = file_id_str; } - if (update_file_format_info(index, file_identifier, variant, file_format)) { - return -1; - } - return 0; + res = update_file_format_info(index, file_identifier, variant, file_format); + ast_free(file_id_str); + + return res; } /*! @@ -443,20 +443,18 @@ static int process_description_file(struct ast_media_index *index, } else { /* if there's text in cumulative_description, archive it and start anew */ if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) { - RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup); + struct media_variant *variant; - variant = find_variant(index, file_id_persist, variant_str); + variant = alloc_variant(index, file_id_persist, variant_str); if (!variant) { - variant = alloc_variant(index, file_id_persist, variant_str); - if (!variant) { - res = -1; - break; - } + res = -1; + break; } ast_string_field_set(variant, description, ast_str_buffer(cumulative_description)); ast_str_reset(cumulative_description); + ao2_ref(variant, -1); } ast_free(file_id_persist); @@ -468,15 +466,12 @@ static int process_description_file(struct ast_media_index *index, /* handle the last one */ if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) { - RAII_VAR(struct media_variant *, variant, NULL, ao2_cleanup); - - variant = find_variant(index, file_id_persist, variant_str); - if (!variant) { - variant = alloc_variant(index, file_id_persist, variant_str); - } + struct media_variant *variant; + variant = alloc_variant(index, file_id_persist, variant_str); if (variant) { ast_string_field_set(variant, description, ast_str_buffer(cumulative_description)); + ao2_ref(variant, -1); } else { res = -1; } diff --git a/main/sounds_index.c b/main/sounds_index.c index c7f9f4dd9..c792c1bbd 100644 --- a/main/sounds_index.c +++ b/main/sounds_index.c @@ -285,13 +285,15 @@ static void sounds_cleanup(void) static void format_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message) { - ast_sounds_reindex(); + /* Reindexing during shutdown is pointless. */ + if (!ast_shutting_down()) { + ast_sounds_reindex(); + } } int ast_sounds_index_init(void) { int res = 0; - sounds_index = NULL; if (ast_sounds_reindex()) { return -1; } @@ -328,6 +330,5 @@ int ast_sounds_index_init(void) struct ast_media_index *ast_sounds_get_index(void) { - ao2_ref(sounds_index, +1); - return sounds_index; + return ao2_bump(sounds_index); } diff --git a/main/stasis_channels.c b/main/stasis_channels.c index b81dbe599..293db06d3 100644 --- a/main/stasis_channels.c +++ b/main/stasis_channels.c @@ -236,22 +236,24 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "")); ast_string_field_set(snapshot, caller_number, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "")); - ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, "")); ast_string_field_set(snapshot, caller_subaddr, S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, "")); - ast_string_field_set(snapshot, dialed_subaddr, - S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, "")); ast_string_field_set(snapshot, caller_ani, S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "")); + ast_string_field_set(snapshot, caller_rdnis, S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "")); + ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, "")); + ast_string_field_set(snapshot, dialed_subaddr, + S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, "")); ast_string_field_set(snapshot, connected_name, S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "")); ast_string_field_set(snapshot, connected_number, S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "")); + ast_string_field_set(snapshot, language, ast_channel_language(chan)); if ((bridge = ast_channel_get_bridge(chan))) { diff --git a/main/tcptls.c b/main/tcptls.c index a6d0538af..02a2af5c6 100644 --- a/main/tcptls.c +++ b/main/tcptls.c @@ -223,7 +223,7 @@ void *ast_tcptls_server_root(void *data) pthread_t launched; for (;;) { - int i, flags; + int i; if (desc->periodic_fn) { desc->periodic_fn(desc); @@ -261,8 +261,7 @@ void *ast_tcptls_server_root(void *data) close(fd); continue; } - flags = fcntl(fd, F_GETFL); - fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + ast_fd_clear_flags(fd, O_NONBLOCK); tcptls_session->stream = ast_iostream_from_fd(&fd); if (!tcptls_session->stream) { @@ -514,7 +513,6 @@ void ast_ssl_teardown(struct ast_tls_config *cfg) struct ast_tcptls_session_instance *ast_tcptls_client_start(struct ast_tcptls_session_instance *tcptls_session) { struct ast_tcptls_session_args *desc; - int flags; if (!(desc = tcptls_session->parent)) { goto client_start_error; @@ -528,8 +526,7 @@ struct ast_tcptls_session_instance *ast_tcptls_client_start(struct ast_tcptls_se goto client_start_error; } - flags = fcntl(desc->accept_fd, F_GETFL); - fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK); + ast_fd_clear_flags(desc->accept_fd, O_NONBLOCK); if (desc->tls_cfg) { desc->tls_cfg->enabled = 1; @@ -621,7 +618,6 @@ error: void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) { - int flags; int x = 1; int tls_changed = 0; int sd_socket; @@ -740,8 +736,7 @@ void ast_tcptls_server_start(struct ast_tcptls_session_args *desc) } systemd_socket_activation: - flags = fcntl(desc->accept_fd, F_GETFL); - fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(desc->accept_fd, O_NONBLOCK); if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", desc->name, diff --git a/main/translate.c b/main/translate.c index 70e97f955..ce4745ce0 100644 --- a/main/translate.c +++ b/main/translate.c @@ -1307,7 +1307,7 @@ int ast_unregister_translator(struct ast_translator *t) } AST_RWLIST_TRAVERSE_SAFE_END; - if (found) { + if (found && !ast_shutting_down()) { matrix_rebuild(0); } diff --git a/main/udptl.c b/main/udptl.c index 853e43c44..d982f6bcb 100644 --- a/main/udptl.c +++ b/main/udptl.c @@ -1012,7 +1012,6 @@ struct ast_udptl *ast_udptl_new_with_bindaddr(struct ast_sched_context *sched, s int x; int startplace; int i; - long int flags; RAII_VAR(struct udptl_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup); if (!cfg || !cfg->general) { @@ -1043,8 +1042,7 @@ struct ast_udptl *ast_udptl_new_with_bindaddr(struct ast_sched_context *sched, s ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno)); return NULL; } - flags = fcntl(udptl->fd, F_GETFL); - fcntl(udptl->fd, F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(udptl->fd, O_NONBLOCK); #ifdef SO_NO_CHECK if (cfg->general->nochecksums) diff --git a/main/utils.c b/main/utils.c index dd7176295..a070da49f 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2758,3 +2758,37 @@ int ast_compare_versions(const char *version1, const char *version2) } return extra[0] - extra[1]; } + +int __ast_fd_set_flags(int fd, int flags, enum ast_fd_flag_operation op, + const char *file, int lineno, const char *function) +{ + int f; + + f = fcntl(fd, F_GETFL); + if (f == -1) { + ast_log(__LOG_ERROR, file, lineno, function, + "Failed to get fcntl() flags for file descriptor: %s\n", strerror(errno)); + return -1; + } + + switch (op) { + case AST_FD_FLAG_SET: + f |= flags; + break; + case AST_FD_FLAG_CLEAR: + f &= ~flags; + break; + default: + ast_assert(0); + break; + } + + f = fcntl(fd, F_SETFL, f); + if (f == -1) { + ast_log(__LOG_ERROR, file, lineno, function, + "Failed to set fcntl() flags for file descriptor: %s\n", strerror(errno)); + return -1; + } + + return 0; +} diff --git a/menuselect/Makefile b/menuselect/Makefile index 96c574eb8..c6a6facb6 100644 --- a/menuselect/Makefile +++ b/menuselect/Makefile @@ -64,7 +64,10 @@ all: $(ALL_TGTS) $(OBJS) $(C_OBJS) $(N_OBJS) $(G_OBJS) $(M_OBJS): autoconfig.h menuselect.h -makeopts autoconfig.h: autoconfig.h.in makeopts.in +makeopts: makeopts.in +autoconfig.h: autoconfig.h.in + +makeopts autoconfig.h: @./configure $(CONFIGURE_SILENT) @echo "****" @echo "**** The configure script was just executed, so 'make' needs to be" diff --git a/res/res_agi.c b/res/res_agi.c index 13af48f49..85914c018 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -2046,7 +2046,7 @@ static int handle_connection(const char *agiurl, const struct ast_sockaddr addr, FastAGI defaults to port 4573 */ static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds) { - int s = 0, flags; + int s = 0; char *host, *script; int num_addrs = 0, i = 0; struct ast_sockaddr *addrs; @@ -2076,14 +2076,7 @@ static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds) continue; } - if ((flags = fcntl(s, F_GETFL)) < 0) { - ast_log(LOG_WARNING, "fcntl(F_GETFL) failed: %s\n", strerror(errno)); - close(s); - continue; - } - - if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { - ast_log(LOG_WARNING, "fnctl(F_SETFL) failed: %s\n", strerror(errno)); + if (ast_fd_set_flags(s, O_NONBLOCK)) { close(s); continue; } @@ -2249,9 +2242,8 @@ static enum agi_result launch_script(struct ast_channel *chan, char *script, int close(toast[1]); return AGI_RESULT_FAILURE; } - res = fcntl(audio[1], F_GETFL); - if (res > -1) - res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK); + + res = ast_fd_set_flags(audio[1], O_NONBLOCK); if (res < 0) { ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno)); close(fromast[0]); diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index c1f9a29d6..baaa40fd9 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -951,17 +951,11 @@ static struct ast_http_uri websocketuri = { /*! \brief Simple echo implementation which echoes received text and binary frames */ static void websocket_echo_callback(struct ast_websocket *session, struct ast_variable *parameters, struct ast_variable *headers) { - int flags, res; + int res; ast_debug(1, "Entering WebSocket echo loop\n"); - if ((flags = fcntl(ast_websocket_fd(session), F_GETFL)) == -1) { - goto end; - } - - flags |= O_NONBLOCK; - - if (fcntl(ast_websocket_fd(session), F_SETFL, flags) == -1) { + if (ast_fd_set_flags(ast_websocket_fd(session), O_NONBLOCK)) { goto end; } diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c index e4bb7a2d9..ef1b81c2a 100644 --- a/res/res_musiconhold.c +++ b/res/res_musiconhold.c @@ -922,7 +922,6 @@ static struct mohclass *_get_mohbyname(const char *name, int warn, int flags, co static struct mohdata *mohalloc(struct mohclass *cl) { struct mohdata *moh; - long flags; if (!(moh = ast_calloc(1, sizeof(*moh)))) return NULL; @@ -934,10 +933,8 @@ static struct mohdata *mohalloc(struct mohclass *cl) } /* Make entirely non-blocking */ - flags = fcntl(moh->pipe[0], F_GETFL); - fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); - flags = fcntl(moh->pipe[1], F_GETFL); - fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(moh->pipe[0], O_NONBLOCK); + ast_fd_set_flags(moh->pipe[1], O_NONBLOCK); moh->f.frametype = AST_FRAME_VOICE; moh->f.subclass.format = cl->format; diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 2f29456ab..a9a90ac92 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -917,6 +917,12 @@ static int transport_tls_method_handler(const struct aco_option *opt, struct ast state->tls.method = PJSIP_SSL_UNSPECIFIED_METHOD; } else if (!strcasecmp(var->value, "tlsv1")) { state->tls.method = PJSIP_TLSV1_METHOD; +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO + } else if (!strcasecmp(var->value, "tlsv1_1")) { + state->tls.method = PJSIP_TLSV1_1_METHOD; + } else if (!strcasecmp(var->value, "tlsv1_2")) { + state->tls.method = PJSIP_TLSV1_2_METHOD; +#endif } else if (!strcasecmp(var->value, "sslv2")) { state->tls.method = PJSIP_SSLV2_METHOD; } else if (!strcasecmp(var->value, "sslv3")) { @@ -933,6 +939,10 @@ static int transport_tls_method_handler(const struct aco_option *opt, struct ast static const char *tls_method_map[] = { [PJSIP_SSL_UNSPECIFIED_METHOD] = "unspecified", [PJSIP_TLSV1_METHOD] = "tlsv1", +#ifdef HAVE_PJSIP_TLS_TRANSPORT_PROTO + [PJSIP_TLSV1_1_METHOD] = "tlsv1_1", + [PJSIP_TLSV1_2_METHOD] = "tlsv1_2", +#endif [PJSIP_SSLV2_METHOD] = "sslv2", [PJSIP_SSLV3_METHOD] = "sslv3", [PJSIP_SSLV23_METHOD] = "sslv23", diff --git a/res/res_pjsip/pjsip_cli.c b/res/res_pjsip/pjsip_cli.c index 56ec191ed..4544a1717 100644 --- a/res/res_pjsip/pjsip_cli.c +++ b/res/res_pjsip/pjsip_cli.c @@ -82,31 +82,22 @@ int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags) return 0; } -static char *complete_show_sorcery_object(struct ao2_container *container, +static void complete_show_sorcery_object(struct ao2_container *container, struct ast_sip_cli_formatter_entry *formatter_entry, - const char *word, int state) + const char *word) { - char *result = NULL; - int wordlen = strlen(word); - int which = 0; - - struct ao2_iterator i = ao2_iterator_init(container, 0); + size_t wordlen = strlen(word); void *object; + struct ao2_iterator i = ao2_iterator_init(container, 0); while ((object = ao2_t_iterator_next(&i, "iterate thru endpoints table"))) { const char *id = formatter_entry->get_id(object); - if (!strncasecmp(word, id, wordlen) - && ++which > state) { - result = ast_strdup(id); + if (!strncasecmp(word, id, wordlen)) { + ast_cli_completion_add(ast_strdup(id)); } ao2_t_ref(object, -1, "toss iterator endpoint ptr before break"); - if (result) { - break; - } } ao2_iterator_destroy(&i); - - return result; } static void dump_str_and_free(int fd, struct ast_str *buf) @@ -211,7 +202,8 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_ if (cmd == CLI_GENERATE) { ast_free(context.output_buffer); - return complete_show_sorcery_object(container, formatter_entry, a->word, a->n); + complete_show_sorcery_object(container, formatter_entry, a->word); + return NULL; } if (is_container) { diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index e63e158c4..76cf528eb 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1,8 +1,19 @@ /* - * sip_cli_commands.c + * Asterisk -- An open source telephony toolkit. * - * Created on: Jan 25, 2013 - * Author: mjordan + * Copyright (C) 2013, Digium, Inc. + * + * Matt Jordan <mjordan@digium.com> + * + * 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" diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 662166c89..fbe07d53d 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1147,7 +1147,24 @@ static int qualify_and_schedule_cb_with_aor(void *obj, void *arg, int flags) static int qualify_and_schedule_cb_without_aor(void *obj, void *arg, int flags) { - qualify_and_schedule_contact((struct ast_sip_contact *) obj); + /* + * These are really dynamic contacts. We need to retrieve the aor associated + * with the contact since it's possible some of the aor's fields were updated + * since last load. + */ + struct ast_sip_contact *contact = obj; + struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(contact->aor); + + if (aor) { + qualify_and_schedule_cb_with_aor(obj, aor, flags); + ao2_ref(aor, -1); + } else { + ast_log(LOG_WARNING, "Unable to locate AOR for contact '%s'. Keeping old " + "associated settings: frequency=%d, timeout=%f, authenticate=%s\n", + contact->uri, contact->qualify_frequency, contact->qualify_timeout, + contact->authenticate_qualify ? "yes" : "no"); + qualify_and_schedule_contact(contact); + } return 0; } @@ -1175,32 +1192,21 @@ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) return 0; } -/*! - * \internal - * \brief Unschedule all existing contacts - */ -static int unschedule_all_cb(void *obj, void *arg, int flags) -{ - struct sched_data *data = obj; - - AST_SCHED_DEL_UNREF(sched, data->id, ao2_ref(data, -1)); - - return CMP_MATCH; -} - 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; - } - aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), - "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); + /* + * It's possible that the AOR had some of it's fields updated prior to a + * reload. For instance qualifying could have been turned on or off by + * setting the qualify_frequency. Due to this we have to iterate through + * all contacts (static and dynamic), and not just ones where the frequency + * is greater than zero, updating any contact fields with the AOR's values. + */ - ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); + aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "aor", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); if (aors) { ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); @@ -1208,14 +1214,11 @@ static void qualify_and_schedule_all(void) } contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), - "contact", AST_RETRIEVE_FLAG_MULTIPLE, var); + "contact", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); if (contacts) { ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL); ao2_ref(contacts, -1); } - - ast_variables_destroy(var); - } int ast_sip_format_contact_ami(void *obj, void *arg, int flags) diff --git a/res/res_pjsip_dlg_options.c b/res/res_pjsip_dlg_options.c index e2ed29a2c..de1ac97ef 100644 --- a/res/res_pjsip_dlg_options.c +++ b/res/res_pjsip_dlg_options.c @@ -99,6 +99,7 @@ static int unload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "SIP OPTIONS in dialog handler", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index f1f49d510..e5f12951f 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -1697,6 +1697,7 @@ static int reload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "PJSIP Outbound Publish Support", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, .unload = unload_module, diff --git a/res/res_pjsip_phoneprov_provider.c b/res/res_pjsip_phoneprov_provider.c index eef3a082f..7e082c4b5 100644 --- a/res/res_pjsip_phoneprov_provider.c +++ b/res/res_pjsip_phoneprov_provider.c @@ -413,6 +413,7 @@ static int reload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Phoneprov Provider", + .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .reload = reload_module, .unload = unload_module, diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index 72e1e4d7e..53ee60fe4 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -929,6 +929,7 @@ static int unload_module(void) } AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Asterisk Event PUBLISH Support", + .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .reload = reload_module, .unload = unload_module, diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index a87758267..854ed1459 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -1253,7 +1253,8 @@ static int add_crypto_to_stream(struct ast_sip_session *session, /* 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) { + if (session->inv_session->neg + && 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; diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 781d3e4eb..958f2254b 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2818,6 +2818,12 @@ static enum sip_get_destination_result get_destination(struct ast_sip_session *s ast_copy_pj_str(domain, &sip_ruri->host, size); pbx_builtin_setvar_helper(session->channel, "SIPDOMAIN", domain); + /* + * Save off the INVITE Request-URI in case it is + * needed: CHANNEL(pjsip,request_uri) + */ + session->request_uri = pjsip_uri_clone(session->inv_session->pool, ruri); + return SIP_GET_DEST_EXTEN_FOUND; } @@ -3872,10 +3878,15 @@ static struct pjmedia_sdp_session *create_local_sdp(pjsip_inv_session *inv, stru 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. + * of what kind of stream topology they would like. We try to not alter the current state of the SDP negotiation + * by using what is currently negotiated. If this is unavailable we fall back to what is configured on the 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->active_media_state->topology) { + session->pending_media_state->topology = ast_stream_topology_clone(session->active_media_state->topology); + } else { + session->pending_media_state->topology = ast_stream_topology_clone(session->endpoint->media.topology); + } if (!session->pending_media_state->topology) { return NULL; } diff --git a/res/res_pktccops.c b/res/res_pktccops.c index e8d266cda..156c49dc7 100644 --- a/res/res_pktccops.c +++ b/res/res_pktccops.c @@ -648,7 +648,7 @@ static struct cops_gate *cops_gate_cmd(int cmd, struct cops_cmts *cmts, static int cops_connect(char *host, char *port) { - int s, sfd = -1, flags; + int s, sfd = -1; struct addrinfo hints; struct addrinfo *rp; struct addrinfo *result; @@ -674,8 +674,7 @@ static int cops_connect(char *host, char *port) if (sfd == -1) { ast_log(LOG_WARNING, "Failed socket\n"); } - flags = fcntl(sfd, F_GETFL); - fcntl(sfd, F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(sfd, O_NONBLOCK); #ifdef HAVE_SO_NOSIGPIPE setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, &trueval, sizeof(trueval)); #endif diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 5aeb791d3..bdc83301e 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -3048,8 +3048,7 @@ static int create_new_socket(const char *type, int af) } ast_log(LOG_WARNING, "Unable to allocate %s socket: %s\n", type, strerror(errno)); } else { - long flags = fcntl(sock, F_GETFL); - fcntl(sock, F_SETFL, flags | O_NONBLOCK); + ast_fd_set_flags(sock, O_NONBLOCK); #ifdef SO_NO_CHECK if (nochecksums) { setsockopt(sock, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums)); @@ -5170,7 +5169,6 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c 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; @@ -5414,7 +5412,7 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c } return &ast_null_frame; } - rtcp_report->report_block[report_counter] = report_block; + rtcp_report->report_block[0] = report_block; report_block->source_ssrc = ntohl(rtcpheader[i]); report_block->lost_count.packets = ntohl(rtcpheader[i + 1]) & 0x00ffffff; report_block->lost_count.fraction = ((ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24); @@ -5451,7 +5449,6 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c ast_verbose(" DLSR: %4.4f (sec)\n",(double)report_block->dlsr / 65536.0); ast_verbose(" RTT: %4.4f(sec)\n", rtp->rtcp->rtt); } - report_counter++; } /* If and when we handle more than one report block, this should occur outside * this loop. @@ -5476,9 +5473,9 @@ static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, c /* There's always a single report block stored, here */ struct ast_rtp_rtcp_report *rtcp_report2; 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)); + memcpy(report_block, rtcp_report->report_block[0], sizeof(struct ast_rtp_rtcp_report_block)); rtcp_report2 = (struct ast_rtp_rtcp_report *)transport_rtp->f.data.ptr; - rtcp_report2->report_block[report_counter-1] = report_block; + rtcp_report2->report_block[0] = report_block; transport_rtp->f.datalen += sizeof(struct ast_rtp_rtcp_report_block); } transport_rtp->f.offset = AST_FRIENDLY_OFFSET; diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index 8b93b57ba..87823be0d 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -334,14 +334,14 @@ static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, voi const char *family_prefix = data; size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */ char family[family_len + 1]; - char tree[prefix_len + sizeof("%")]; + char tree[prefix_len + 1]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); struct ast_db_entry *entry; - snprintf(tree, sizeof(tree), "%.*s%%", (int) prefix_len, prefix); + snprintf(tree, sizeof(tree), "%.*s", (int) prefix_len, prefix); snprintf(family, sizeof(family), "%s/%s", family_prefix, type); - if (!(entries = ast_db_gettree(family, tree))) { + if (!(entries = ast_db_gettree_by_prefix(family, tree))) { return; } diff --git a/res/res_speech.c b/res/res_speech.c index d6c532971..31ad61acb 100644 --- a/res/res_speech.c +++ b/res/res_speech.c @@ -363,5 +363,5 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, - .load_pri = AST_MODPRI_APP_DEPEND, + .load_pri = AST_MODPRI_APP_DEPEND - 1, ); diff --git a/res/res_stasis.c b/res/res_stasis.c index f99dcee37..42a19bf56 100644 --- a/res/res_stasis.c +++ b/res/res_stasis.c @@ -2155,8 +2155,8 @@ static int load_module(void) return AST_MODULE_LOAD_SUCCESS; } -AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application support", - .load_pri = AST_MODPRI_APP_DEPEND, +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Stasis application support", + .load_pri = AST_MODPRI_APP_DEPEND - 1, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, diff --git a/res/res_timing_pthread.c b/res/res_timing_pthread.c index 09952f929..f52079643 100644 --- a/res/res_timing_pthread.c +++ b/res/res_timing_pthread.c @@ -130,9 +130,7 @@ static void *pthread_timer_open(void) } for (i = 0; i < ARRAY_LEN(timer->pipe); ++i) { - int flags = fcntl(timer->pipe[i], F_GETFL); - flags |= O_NONBLOCK; - fcntl(timer->pipe[i], F_SETFL, flags); + ast_fd_set_flags(timer->pipe[i], O_NONBLOCK); } ao2_lock(pthread_timers); |