Merge "dr_adaptive_odbc.c, cel_odbc.c, cel_pgsql.c: REFACTOR Macro LENGTHEN_BUF"
authorMatt Jordan <mjordan@digium.com>
Sat, 19 Sep 2015 14:15:02 +0000 (09:15 -0500)
committerGerrit Code Review <gerrit2@gerrit.digium.api>
Sat, 19 Sep 2015 14:15:03 +0000 (09:15 -0500)
channels/chan_pjsip.c
channels/chan_sip.c
main/sched.c
res/res_config_sqlite.c
res/res_pjsip_nat.c
res/res_pjsip_pubsub.c

index 9603f05..153b2a3 100644 (file)
@@ -160,10 +160,10 @@ 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 = channel->pvt;
+       struct chan_pjsip_pvt *pvt;
        struct ast_sip_endpoint *endpoint;
 
-       if (!pvt || !channel->session || !pvt->media[SIP_MEDIA_AUDIO]->rtp) {
+       if (!channel || !channel->session || !(pvt = channel->pvt) || !pvt->media[SIP_MEDIA_AUDIO]->rtp) {
                return AST_RTP_GLUE_RESULT_FORBID;
        }
 
index e385ddb..8d5af2f 100644 (file)
@@ -13940,6 +13940,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
        int cid_has_name = 1;
        int cid_has_num = 1;
        struct ast_party_id connected_id;
+       int ret;
 
        if (ast_test_flag(&p->flags[0], SIP_USEREQPHONE)) {
                const char *s = p->username;    /* being a string field, cannot be NULL */
@@ -14024,26 +14025,41 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho
 
        ast_copy_string(tmp_l, l, sizeof(tmp_l));
        if (sip_cfg.pedanticsipchecking) {
-               ast_escape_quoted(n, tmp_n, sizeof(tmp_n));
-               n = tmp_n;
                ast_uri_encode(l, tmp_l, sizeof(tmp_l), ast_uri_sip_user);
        }
 
        ourport = (p->fromdomainport && (p->fromdomainport != STANDARD_SIP_PORT)) ? p->fromdomainport : ast_sockaddr_port(&p->ourip);
 
-       /* If a caller id name was specified, add a display name. */
-       if (cid_has_name || !cid_has_num) {
-               snprintf(from, sizeof(from), "\"%s\" ", n);
+       if (!sip_standard_port(p->socket.type, ourport)) {
+               ret = snprintf(from, sizeof(from), "<sip:%s@%s:%d>;tag=%s", tmp_l, d, ourport, p->tag);
        } else {
-               from[0] = '\0';
+               ret = snprintf(from, sizeof(from), "<sip:%s@%s>;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 */
+               /* 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);
        }
 
-       if (!sip_standard_port(p->socket.type, ourport)) {
-               size_t offset = strlen(from);
-               snprintf(&from[offset], sizeof(from) - offset, "<sip:%s@%s:%d>;tag=%s", tmp_l, d, ourport, p->tag);
-       } else {
-               size_t offset = strlen(from);
-               snprintf(&from[offset], sizeof(from) - offset, "<sip:%s@%s>;tag=%s", tmp_l, d, p->tag);
+       /* 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] = ' ';
+               }
        }
 
        if (!ast_strlen_zero(explicit_uri)) {
@@ -14085,21 +14101,25 @@ 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 */
-                       snprintf(to, sizeof(to), "<sip:%s@%s>%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
+                       ret = snprintf(to, sizeof(to), "<sip:%s@%s>%s%s", p->todnid, p->tohost, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
                } else {
-                       snprintf(to, sizeof(to), "<sip:%s>%s%s", p->todnid, ast_strlen_zero(p->theirtag) ? "" : ";tag=", p->theirtag);
+                       ret = snprintf(to, sizeof(to), "<sip:%s>%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) */
-                       snprintf(to, sizeof(to), "<%s%s>;tag=%s", (strncasecmp(p->uri, "sip:", 4) ? "sip:" : ""), p->uri, p->theirtag);
+                       ret = snprintf(to, sizeof(to), "<%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 */
-                       snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
+                       ret = snprintf(to, sizeof(to), "<%s>;%s", p->uri, p->options->vxml_url);
                } else {
-                       snprintf(to, sizeof(to), "<%s>", p->uri);
+                       ret = snprintf(to, sizeof(to), "<%s>", p->uri);
                }
        }
+       if (ret < 0 || ret >= sizeof(to)) { /* a return value of size or more means that the output was truncated */
+               /* 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);
+       }
 
        init_req(req, sipmethod, p->uri);
        /* now tmp_n is available so reuse it to build the CSeq */
@@ -33152,10 +33172,8 @@ static char *sip_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a
 /*! \brief  Part of Asterisk module interface */
 static int reload(void)
 {
-       if (sip_reload(0, 0, NULL)) {
-               return 0;
-       }
-       return 1;
+       sip_reload(0, 0, NULL);
+       return AST_MODULE_LOAD_SUCCESS;
 }
 
 /*! \brief  Return the first entry from ast_sockaddr_resolve filtered by address family
index 062b2fd..8f9e84b 100644 (file)
@@ -62,9 +62,26 @@ ASTERISK_REGISTER_FILE()
 
 AST_THREADSTORAGE(last_del_id);
 
+/*!
+ * \brief Scheduler ID holder
+ *
+ * These form a queue on a scheduler context. When a new
+ * scheduled item is created, a sched_id is popped off the
+ * queue and its id is assigned to the new scheduled item.
+ * When the scheduled task is complete, the sched_id on that
+ * task is then pushed to the back of the queue to be re-used
+ * on some future scheduled item.
+ */
+struct sched_id {
+       /*! Immutable ID number that is copied onto the scheduled task */
+       int id;
+       AST_LIST_ENTRY(sched_id) list;
+};
+
 struct sched {
        AST_LIST_ENTRY(sched) list;
-       int id;                       /*!< ID number of event */
+       /*! 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 */
        int resched;                  /*!< When to reschedule */
        int variable;                 /*!< Use return value from callback to reschedule */
@@ -99,6 +116,10 @@ struct ast_sched_context {
        AST_LIST_HEAD_NOLOCK(, sched) schedc;   /*!< Cache of unused schedule structures and how many */
        unsigned int schedccnt;
 #endif
+       /*! Queue of scheduler task IDs to assign */
+       AST_LIST_HEAD_NOLOCK(, sched_id) id_queue;
+       /*! The number of IDs in the id_queue */
+       int id_queue_size;
 };
 
 static void *sched_run(void *data)
@@ -208,6 +229,8 @@ struct ast_sched_context *ast_sched_context_create(void)
        ast_mutex_init(&tmp->lock);
        tmp->eventcnt = 1;
 
+       AST_LIST_HEAD_INIT_NOLOCK(&tmp->id_queue);
+
        if (!(tmp->sched_heap = ast_heap_create(8, sched_time_cmp,
                        offsetof(struct sched, __heap_index)))) {
                ast_sched_context_destroy(tmp);
@@ -219,6 +242,11 @@ struct ast_sched_context *ast_sched_context_create(void)
 
 static void sched_free(struct sched *task)
 {
+       /* task->sched_id will be NULL most of the time, but when the
+        * scheduler context shuts down, it will free all scheduled
+        * tasks, and in that case, the task->sched_id will be non-NULL
+        */
+       ast_free(task->sched_id);
        ast_cond_destroy(&task->cond);
        ast_free(task);
 }
@@ -226,6 +254,7 @@ static void sched_free(struct sched *task)
 void ast_sched_context_destroy(struct ast_sched_context *con)
 {
        struct sched *s;
+       struct sched_id *sid;
 
        sched_thread_destroy(con);
        con->sched_thread = NULL;
@@ -246,40 +275,75 @@ void ast_sched_context_destroy(struct ast_sched_context *con)
                con->sched_heap = NULL;
        }
 
+       while ((sid = AST_LIST_REMOVE_HEAD(&con->id_queue, list))) {
+               ast_free(sid);
+       }
+
        ast_mutex_unlock(&con->lock);
        ast_mutex_destroy(&con->lock);
 
        ast_free(con);
 }
 
-static struct sched *sched_alloc(struct ast_sched_context *con)
-{
-       struct sched *tmp;
+#define ID_QUEUE_INCREMENT 16
 
-       /*
-        * We keep a small cache of schedule entries
-        * to minimize the number of necessary malloc()'s
+/*!
+ * \brief Add new scheduler IDs to the queue.
+ *
+ * \retval The number of IDs added to the queue
+ */
+static int add_ids(struct ast_sched_context *con)
+{
+       int new_size;
+       int original_size;
+       int i;
+
+       original_size = con->id_queue_size;
+       /* So we don't go overboard with the mallocs here, we'll just up
+        * the size of the list by a fixed amount each time instead of
+        * multiplying the size by any particular factor
         */
-#ifdef SCHED_MAX_CACHE
-       if ((tmp = AST_LIST_REMOVE_HEAD(&con->schedc, list))) {
-               con->schedccnt--;
-       } else 
-#endif
-       {
-               tmp = ast_calloc(1, sizeof(*tmp));
-               ast_cond_init(&tmp->cond, NULL);
+       new_size = original_size + ID_QUEUE_INCREMENT;
+       if (new_size < 0) {
+               /* Overflow. Cap it at INT_MAX. */
+               new_size = INT_MAX;
        }
+       for (i = original_size; i < new_size; ++i) {
+               struct sched_id *new_id;
 
-       return tmp;
+               new_id = ast_calloc(1, sizeof(*new_id));
+               if (!new_id) {
+                       break;
+               }
+               new_id->id = i;
+               AST_LIST_INSERT_TAIL(&con->id_queue, new_id, list);
+               ++con->id_queue_size;
+       }
+
+       return con->id_queue_size - original_size;
+}
+
+static int set_sched_id(struct ast_sched_context *con, struct sched *new_sched)
+{
+       if (AST_LIST_EMPTY(&con->id_queue) && (add_ids(con) == 0)) {
+               return -1;
+       }
+
+       new_sched->sched_id = AST_LIST_REMOVE_HEAD(&con->id_queue, list);
+       return 0;
 }
 
 static void sched_release(struct ast_sched_context *con, struct sched *tmp)
 {
+       if (tmp->sched_id) {
+               AST_LIST_INSERT_TAIL(&con->id_queue, tmp->sched_id, list);
+               tmp->sched_id = NULL;
+       }
+
        /*
         * Add to the cache, or just free() if we
         * already have too many cache entries
         */
-
 #ifdef SCHED_MAX_CACHE
        if (con->schedccnt < SCHED_MAX_CACHE) {
                AST_LIST_INSERT_HEAD(&con->schedc, tmp, list);
@@ -289,6 +353,35 @@ static void sched_release(struct ast_sched_context *con, struct sched *tmp)
                sched_free(tmp);
 }
 
+static struct sched *sched_alloc(struct ast_sched_context *con)
+{
+       struct sched *tmp;
+
+       /*
+        * We keep a small cache of schedule entries
+        * to minimize the number of necessary malloc()'s
+        */
+#ifdef SCHED_MAX_CACHE
+       if ((tmp = AST_LIST_REMOVE_HEAD(&con->schedc, list))) {
+               con->schedccnt--;
+       } else
+#endif
+       {
+               tmp = ast_calloc(1, sizeof(*tmp));
+               if (!tmp) {
+                       return NULL;
+               }
+               ast_cond_init(&tmp->cond, NULL);
+       }
+
+       if (set_sched_id(con, tmp)) {
+               sched_release(con, tmp);
+               return NULL;
+       }
+
+       return tmp;
+}
+
 void ast_sched_clean_by_callback(struct ast_sched_context *con, ast_sched_cb match, ast_sched_cb cleanup_cb)
 {
        int i = 1;
@@ -388,7 +481,7 @@ int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb
 
        ast_mutex_lock(&con->lock);
        if ((tmp = sched_alloc(con))) {
-               tmp->id = con->eventcnt++;
+               con->eventcnt++;
                tmp->callback = callback;
                tmp->data = data;
                tmp->resched = when;
@@ -399,7 +492,7 @@ int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb
                        sched_release(con, tmp);
                } else {
                        schedule(con, tmp);
-                       res = tmp->id;
+                       res = tmp->sched_id->id;
                }
        }
 #ifdef DUMP_SCHEDULER
@@ -437,7 +530,7 @@ static struct sched *sched_find(struct ast_sched_context *con, int id)
        for (x = 1; x <= heap_size; x++) {
                struct sched *cur = ast_heap_peek(con->sched_heap, x);
 
-               if (cur->id == id) {
+               if (cur->sched_id->id == id) {
                        return cur;
                }
        }
@@ -488,16 +581,16 @@ int _ast_sched_del(struct ast_sched_context *con, int id, const char *file, int
        s = sched_find(con, id);
        if (s) {
                if (!ast_heap_remove(con->sched_heap, s)) {
-                       ast_log(LOG_WARNING,"sched entry %d not in the sched heap?\n", s->id);
+                       ast_log(LOG_WARNING,"sched entry %d not in the sched heap?\n", s->sched_id->id);
                }
                sched_release(con, s);
-       } else if (con->currently_executing && (id == con->currently_executing->id)) {
+       } else if (con->currently_executing && (id == con->currently_executing->sched_id->id)) {
                s = con->currently_executing;
                s->deleted = 1;
                /* Wait for executing task to complete so that caller of ast_sched_del() does not
                 * free memory out from under the task.
                 */
-               while (con->currently_executing && (id == con->currently_executing->id)) {
+               while (con->currently_executing && (id == con->currently_executing->sched_id->id)) {
                        ast_cond_wait(&s->cond, &con->lock);
                }
                /* Do not sched_release() here because ast_sched_runq() will do it */
@@ -586,7 +679,7 @@ void ast_sched_dump(struct ast_sched_context *con)
                q = ast_heap_peek(con->sched_heap, x);
                delta = ast_tvsub(q->when, when);
                ast_debug(1, "|%.4d | %-15p | %-15p | %.6ld : %.6ld |\n",
-                       q->id,
+                       q->sched_id->id,
                        q->callback,
                        q->data,
                        (long)delta.tv_sec,
index 5659b4e..4375c39 100644 (file)
@@ -781,8 +781,16 @@ static int cdr_handler(struct ast_cdr *cdr)
        struct ast_str *sql1 = ast_str_create(160), *sql2 = ast_str_create(16);
        int first = 1;
 
+       if (!sql1 || !sql2) {
+               ast_free(sql1);
+               ast_free(sql2);
+               return -1;
+       }
+
        if (!tbl) {
                ast_log(LOG_WARNING, "No such table: %s\n", cdr_table);
+               ast_free(sql1);
+               ast_free(sql2);
                return -1;
        }
 
index 483caa2..683ae61 100644 (file)
@@ -56,7 +56,7 @@ static int rewrite_route_set(pjsip_rx_data *rdata, pjsip_dialog *dlg)
                                break;
                        }
                }
-       } else {
+       } else if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method)) {
                rr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE, NULL);
        }
 
index e3b1024..7d84b46 100644 (file)
@@ -1306,7 +1306,7 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s
        return sub_tree;
 }
 
-static int generate_initial_notify(struct ast_sip_subscription *sub);
+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 */
@@ -1404,10 +1404,9 @@ static int subscription_persistence_recreate(void *obj, void *arg, int flags)
                }
                sub_tree->persistence = ao2_bump(persistence);
                subscription_persistence_update(sub_tree, &rdata);
-               if (generate_initial_notify(sub_tree->root)) {
+               if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ao2_bump(sub_tree))) {
                        pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
-               } else {
-                       send_notify(sub_tree, 1);
+                       ao2_ref(sub_tree, -1);
                }
        } else {
                ast_sorcery_delete(ast_sip_get_sorcery(), persistence);
@@ -2545,6 +2544,24 @@ static int generate_initial_notify(struct ast_sip_subscription *sub)
        return res;
 }
 
+static int initial_notify_task(void * obj)
+{
+       struct sip_subscription_tree *sub_tree;
+
+       sub_tree = obj;
+       if (generate_initial_notify(sub_tree->root)) {
+               pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
+       } else {
+               send_notify(sub_tree, 1);
+               ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
+                       "Resource: %s",
+                       sub_tree->root->resource);
+       }
+
+       ao2_ref(sub_tree, -1);
+       return 0;
+}
+
 static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
 {
        pjsip_expires_hdr *expires_header;
@@ -2632,13 +2649,9 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
                sub_tree->persistence = subscription_persistence_create(sub_tree);
                subscription_persistence_update(sub_tree, rdata);
                sip_subscription_accept(sub_tree, rdata, resp);
-               if (generate_initial_notify(sub_tree->root)) {
+               if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ao2_bump(sub_tree))) {
                        pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
-               } else {
-                       send_notify(sub_tree, 1);
-                       ast_test_suite_event_notify("SUBSCRIPTION_ESTABLISHED",
-                                       "Resource: %s",
-                                       sub_tree->root->resource);
+                       ao2_ref(sub_tree, -1);
                }
        }