diff options
-rw-r--r-- | apps/app_queue.c | 21 | ||||
-rw-r--r-- | cdr/cdr_adaptive_odbc.c | 22 | ||||
-rw-r--r-- | cel/cel_odbc.c | 23 | ||||
-rw-r--r-- | cel/cel_pgsql.c | 20 | ||||
-rw-r--r-- | channels/chan_pjsip.c | 4 | ||||
-rw-r--r-- | channels/chan_sip.c | 54 | ||||
-rw-r--r-- | main/sched.c | 141 | ||||
-rw-r--r-- | res/res_config_sqlite.c | 8 | ||||
-rw-r--r-- | res/res_pjsip_diversion.c | 4 | ||||
-rw-r--r-- | res/res_pjsip_pubsub.c | 33 |
10 files changed, 231 insertions, 99 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c index bb3ec1790..23f69853d 100644 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -5582,6 +5582,10 @@ struct queue_stasis_data { struct local_optimization caller_optimize; /*! Local channel optimization details for the member */ struct local_optimization member_optimize; + /*! Member channel */ + struct ast_channel *member_channel; + /*! Caller channel */ + struct ast_channel *caller_channel; }; /*! @@ -5599,6 +5603,9 @@ static void queue_stasis_data_destructor(void *obj) ao2_cleanup(queue_data->member); queue_unref(queue_data->queue); ast_string_field_free_memory(queue_data); + + ao2_ref(queue_data->member_channel, -1); + ao2_ref(queue_data->caller_channel, -1); } /*! @@ -5645,6 +5652,16 @@ static struct queue_stasis_data *queue_stasis_data_alloc(struct queue_ent *qe, queue_data->caller_pos = qe->opos; ao2_ref(mem, +1); queue_data->member = mem; + + /* + * During transfers it's possible for both the member and/or caller + * channel(s) to not be available. Adding a reference here ensures + * that the channels remain until app_queue is completely done with + * them. + */ + queue_data->member_channel = ao2_bump(peer); + queue_data->caller_channel = ao2_bump(qe->chan); + return queue_data; } @@ -6016,7 +6033,9 @@ static void handle_hangup(void *userdata, struct stasis_subscription *sub, } chan = ast_channel_get_by_name(channel_blob->snapshot->name); - if (chan && ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME)) { + if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) || + !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) || + !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) { /* Channel that is hanging up is doing it as part of a transfer. * We'll get a transfer event later */ diff --git a/cdr/cdr_adaptive_odbc.c b/cdr/cdr_adaptive_odbc.c index 8bd9d0da6..0da8c0142 100644 --- a/cdr/cdr_adaptive_odbc.c +++ b/cdr/cdr_adaptive_odbc.c @@ -358,11 +358,11 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data) return stmt; } -#define LENGTHEN_BUF1(size) \ +#define LENGTHEN_BUF(size, var_sql) \ do { \ /* Lengthen buffer, if necessary */ \ - if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) { \ - if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 1) / 512 + 1) * 512) != 0) { \ + if (ast_str_strlen(var_sql) + size + 1 > ast_str_size(var_sql)) { \ + if (ast_str_make_space(&var_sql, ((ast_str_size(var_sql) + size + 1) / 512 + 1) * 512) != 0) { \ ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \ ast_free(sql); \ ast_free(sql2); \ @@ -372,18 +372,10 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data) } \ } while (0) -#define LENGTHEN_BUF2(size) \ - do { \ - if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) { \ - if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \ - ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CDR '%s:%s' failed.\n", tableptr->connection, tableptr->table); \ - ast_free(sql); \ - ast_free(sql2); \ - AST_RWLIST_UNLOCK(&odbc_tables); \ - return -1; \ - } \ - } \ - } while (0) +#define LENGTHEN_BUF1(size) \ + LENGTHEN_BUF(size, sql); +#define LENGTHEN_BUF2(size) \ + LENGTHEN_BUF(size, sql2); static int odbc_log(struct ast_cdr *cdr) { diff --git a/cel/cel_odbc.c b/cel/cel_odbc.c index 2d8408baa..3c0be04e8 100644 --- a/cel/cel_odbc.c +++ b/cel/cel_odbc.c @@ -341,11 +341,11 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data) return stmt; } -#define LENGTHEN_BUF1(size) \ +#define LENGTHEN_BUF(size, var_sql) \ do { \ /* Lengthen buffer, if necessary */ \ - if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) { \ - if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 1) / 512 + 1) * 512) != 0) { \ + if (ast_str_strlen(var_sql) + size + 1 > ast_str_size(var_sql)) { \ + if (ast_str_make_space(&var_sql, ((ast_str_size(var_sql) + size + 1) / 512 + 1) * 512) != 0) { \ ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CEL '%s:%s' failed.\n", tableptr->connection, tableptr->table); \ ast_free(sql); \ ast_free(sql2); \ @@ -355,18 +355,11 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data) } \ } while (0) -#define LENGTHEN_BUF2(size) \ - do { \ - if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) { \ - if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \ - ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CEL '%s:%s' failed.\n", tableptr->connection, tableptr->table); \ - ast_free(sql); \ - ast_free(sql2); \ - AST_RWLIST_UNLOCK(&odbc_tables); \ - return; \ - } \ - } \ - } while (0) +#define LENGTHEN_BUF1(size) \ + LENGTHEN_BUF(size, sql); + +#define LENGTHEN_BUF2(size) \ + LENGTHEN_BUF(size, sql2); static void odbc_log(struct ast_event *event) { diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c index f4959474a..e4e280e41 100644 --- a/cel/cel_pgsql.c +++ b/cel/cel_pgsql.c @@ -100,11 +100,11 @@ struct columns { static AST_RWLIST_HEAD_STATIC(psql_columns, columns); -#define LENGTHEN_BUF1(size) \ +#define LENGTHEN_BUF(size, var_sql) \ do { \ /* Lengthen buffer, if necessary */ \ - if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) { \ - if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 3) / 512 + 1) * 512) != 0) { \ + if (ast_str_strlen(var_sql) + size + 1 > ast_str_size(var_sql)) { \ + if (ast_str_make_space(&var_sql, ((ast_str_size(var_sql) + size + 3) / 512 + 1) * 512) != 0) { \ ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CEL '%s:%s' failed.\n", pghostname, table); \ ast_free(sql); \ ast_free(sql2); \ @@ -114,18 +114,10 @@ static AST_RWLIST_HEAD_STATIC(psql_columns, columns); } \ } while (0) +#define LENGTHEN_BUF1(size) \ + LENGTHEN_BUF(size, sql); #define LENGTHEN_BUF2(size) \ - do { \ - if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) { \ - if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \ - ast_log(LOG_ERROR, "Unable to allocate sufficient memory. Insert CEL '%s:%s' failed.\n", pghostname, table); \ - ast_free(sql); \ - ast_free(sql2); \ - AST_RWLIST_UNLOCK(&psql_columns); \ - return; \ - } \ - } \ - } while (0) + LENGTHEN_BUF(size, sql2); static void pgsql_reconnect(void) { diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 9603f0514..153b2a33b 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -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; } diff --git a/channels/chan_sip.c b/channels/chan_sip.c index f96a80f3b..8d5af2f09 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -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 */ diff --git a/main/sched.c b/main/sched.c index 062b2fd96..8f9e84bff 100644 --- a/main/sched.c +++ b/main/sched.c @@ -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, diff --git a/res/res_config_sqlite.c b/res/res_config_sqlite.c index 5659b4e41..4375c3960 100644 --- a/res/res_config_sqlite.c +++ b/res/res_config_sqlite.c @@ -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; } diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c index 3dfae455b..ea2c7cd13 100644 --- a/res/res_pjsip_diversion.c +++ b/res/res_pjsip_diversion.c @@ -117,7 +117,9 @@ static void set_redirecting_value(char **dst, const pj_str_t *src) { ast_free(*dst); *dst = ast_malloc(pj_strlen(src) + 1); - ast_copy_pj_str(*dst, src, pj_strlen(src) + 1); + if (*dst) { + ast_copy_pj_str(*dst, src, pj_strlen(src) + 1); + } } static void set_redirecting_id(pjsip_name_addr *name_addr, struct ast_party_id *data, diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index e3b1024c0..7d84b4675 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -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); } } |