From 692d360e0cf0f0e476261d9402a358c8fe3f81da Mon Sep 17 00:00:00 2001 From: Philip Prindeville Date: Sun, 6 Feb 2022 11:42:04 -0700 Subject: [PATCH 1/5] asterisk: don't send stdout to syslog by default Signed-off-by: Philip Prindeville (cherry picked from commit fb0c2cf2b8d5775e46cd8c2e71f9a20414feeb4a) --- net/asterisk/files/asterisk.conf | 2 +- net/asterisk/files/asterisk.init | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/asterisk/files/asterisk.conf b/net/asterisk/files/asterisk.conf index f175df8..d6d461c 100644 --- a/net/asterisk/files/asterisk.conf +++ b/net/asterisk/files/asterisk.conf @@ -12,5 +12,5 @@ config asterisk 'general' option enabled '0' option log_stderr '1' - option log_stdout '1' + option log_stdout '0' option options '' diff --git a/net/asterisk/files/asterisk.init b/net/asterisk/files/asterisk.init index 97dfe83..2e02f06 100644 --- a/net/asterisk/files/asterisk.init +++ b/net/asterisk/files/asterisk.init @@ -30,7 +30,7 @@ start_service() { fi config_get_bool log_stderr general log_stderr 1 - config_get_bool log_stdout general log_stdout 1 + config_get_bool log_stdout general log_stdout 0 config_get options general options From 7117f7971dde040a941c53e6a81736f69a01136f Mon Sep 17 00:00:00 2001 From: Sebastian Kemper Date: Fri, 15 Apr 2022 16:21:22 +0200 Subject: [PATCH 2/5] pjproject: sync patches with asterisk 18.11.2 Signed-off-by: Sebastian Kemper (cherry picked from commit 0c67ab5831bb1509af035ce8f142eabbf14bd82a) --- ...ditional-multipart-support-2919-2920.patch | 653 ++++++++++++++++++ ...escaping-of-tokens-during-parsing-29.patch | 116 ++++ ...ate-generic-pjsip_hdr_find-functions.patch | 169 +++++ ...60-Additional-multipart-improvements.patch | 635 +++++++++++++++++ 4 files changed, 1573 insertions(+) create mode 100644 libs/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch create mode 100644 libs/pjproject/patches/0140-Fix-incorrect-unescaping-of-tokens-during-parsing-29.patch create mode 100644 libs/pjproject/patches/0150-Create-generic-pjsip_hdr_find-functions.patch create mode 100644 libs/pjproject/patches/0160-Additional-multipart-improvements.patch diff --git a/libs/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch b/libs/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch new file mode 100644 index 0000000..8db8aab --- /dev/null +++ b/libs/pjproject/patches/0130-sip_inv-Additional-multipart-support-2919-2920.patch @@ -0,0 +1,653 @@ +From 0ed41eb5fd0e4192e1b7dc374f819d17aef3e805 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Tue, 21 Dec 2021 19:32:22 -0700 +Subject: [PATCH] sip_inv: Additional multipart support (#2919) (#2920) + +--- + pjsip/include/pjsip-ua/sip_inv.h | 108 ++++++++++- + pjsip/src/pjsip-ua/sip_inv.c | 240 ++++++++++++++++++++----- + pjsip/src/test/inv_offer_answer_test.c | 103 ++++++++++- + 3 files changed, 394 insertions(+), 57 deletions(-) + +--- a/pjsip/include/pjsip-ua/sip_inv.h ++++ b/pjsip/include/pjsip-ua/sip_inv.h +@@ -451,11 +451,11 @@ struct pjsip_inv_session + + + /** +- * This structure represents SDP information in a pjsip_rx_data. Application +- * retrieve this information by calling #pjsip_rdata_get_sdp_info(). This ++ * This structure represents SDP information in a pjsip_(rx|tx)_data. Application ++ * retrieve this information by calling #pjsip_get_sdp_info(). This + * mechanism supports multipart message body. + */ +-typedef struct pjsip_rdata_sdp_info ++typedef struct pjsip_sdp_info + { + /** + * Pointer and length of the text body in the incoming message. If +@@ -475,7 +475,15 @@ typedef struct pjsip_rdata_sdp_info + */ + pjmedia_sdp_session *sdp; + +-} pjsip_rdata_sdp_info; ++} pjsip_sdp_info; ++ ++/** ++ * For backwards compatibility and completeness, ++ * pjsip_rdata_sdp_info and pjsip_tdata_sdp_info ++ * are typedef'd to pjsip_sdp_info. ++ */ ++typedef pjsip_sdp_info pjsip_rdata_sdp_info; ++typedef pjsip_sdp_info pjsip_tdata_sdp_info; + + + /** +@@ -1046,6 +1054,44 @@ PJ_DECL(pj_status_t) pjsip_create_sdp_bo + pjsip_msg_body **p_body); + + /** ++ * This is a utility function to create a multipart body with the ++ * SIP body as the first part. ++ * ++ * @param pool Pool to allocate memory. ++ * @param sdp SDP session to be put in the SIP message body. ++ * @param p_body Pointer to receive SIP message body containing ++ * the SDP session. ++ * ++ * @return PJ_SUCCESS on success. ++ */ ++PJ_DECL(pj_status_t) pjsip_create_multipart_sdp_body( pj_pool_t *pool, ++ pjmedia_sdp_session *sdp, ++ pjsip_msg_body **p_body); ++ ++/** ++ * Retrieve SDP information from a message body. Application should ++ * prefer to use this function rather than parsing the SDP manually since ++ * this function supports multipart message body. ++ * ++ * This function will only parse the SDP once, the first time it is called ++ * on the same message. Subsequent call on the same message will just pick ++ * up the already parsed SDP from the message. ++ * ++ * @param pool Pool to allocate memory. ++ * @param body The message body. ++ * @param msg_media_type From the rdata or tdata Content-Type header, if available. ++ * If NULL, the content_type from the body will be used. ++ * @param search_media_type The media type to search for. ++ * If NULL, "application/sdp" will be used. ++ * ++ * @return The SDP info. ++ */ ++PJ_DECL(pjsip_sdp_info*) pjsip_get_sdp_info(pj_pool_t *pool, ++ pjsip_msg_body *body, ++ pjsip_media_type *msg_media_type, ++ const pjsip_media_type *search_media_type); ++ ++/** + * Retrieve SDP information from an incoming message. Application should + * prefer to use this function rather than parsing the SDP manually since + * this function supports multipart message body. +@@ -1061,6 +1107,60 @@ PJ_DECL(pj_status_t) pjsip_create_sdp_bo + PJ_DECL(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata); + + ++/** ++ * Retrieve SDP information from an incoming message. Application should ++ * prefer to use this function rather than parsing the SDP manually since ++ * this function supports multipart message body. ++ * ++ * This function will only parse the SDP once, the first time it is called ++ * on the same message. Subsequent call on the same message will just pick ++ * up the already parsed SDP from the message. ++ * ++ * @param rdata The incoming message. ++ * @param search_media_type The SDP media type to search for. ++ * If NULL, "application/sdp" will be used. ++ * ++ * @return The SDP info. ++ */ ++PJ_DECL(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info2( ++ pjsip_rx_data *rdata, ++ const pjsip_media_type *search_media_type); ++ ++/** ++ * Retrieve SDP information from an outgoing message. Application should ++ * prefer to use this function rather than parsing the SDP manually since ++ * this function supports multipart message body. ++ * ++ * This function will only parse the SDP once, the first time it is called ++ * on the same message. Subsequent call on the same message will just pick ++ * up the already parsed SDP from the message. ++ * ++ * @param tdata The outgoing message. ++ * ++ * @return The SDP info. ++ */ ++PJ_DECL(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info(pjsip_tx_data *tdata); ++ ++/** ++ * Retrieve SDP information from an outgoing message. Application should ++ * prefer to use this function rather than parsing the SDP manually since ++ * this function supports multipart message body. ++ * ++ * This function will only parse the SDP once, the first time it is called ++ * on the same message. Subsequent call on the same message will just pick ++ * up the already parsed SDP from the message. ++ * ++ * @param tdata The outgoing message. ++ * @param search_media_type The SDP media type to search for. ++ * If NULL, "application/sdp" will be used. ++ * ++ * @return The SDP info. ++ */ ++PJ_DECL(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info2( ++ pjsip_tx_data *tdata, ++ const pjsip_media_type *search_media_type); ++ ++ + PJ_END_DECL + + /** +--- a/pjsip/src/pjsip-ua/sip_inv.c ++++ b/pjsip/src/pjsip-ua/sip_inv.c +@@ -118,6 +118,8 @@ static pj_status_t handle_timer_response + static pj_bool_t inv_check_secure_dlg(pjsip_inv_session *inv, + pjsip_event *e); + ++static int print_sdp(pjsip_msg_body *body, char *buf, pj_size_t len); ++ + static void (*inv_state_handler[])( pjsip_inv_session *inv, pjsip_event *e) = + { + &inv_on_state_null, +@@ -956,66 +958,170 @@ PJ_DEF(pj_status_t) pjsip_inv_create_uac + return PJ_SUCCESS; + } + +-PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata) +-{ +- pjsip_rdata_sdp_info *sdp_info; +- pjsip_msg_body *body = rdata->msg_info.msg->body; +- pjsip_ctype_hdr *ctype_hdr = rdata->msg_info.ctype; +- pjsip_media_type app_sdp; ++PJ_DEF(pjsip_sdp_info*) pjsip_get_sdp_info(pj_pool_t *pool, ++ pjsip_msg_body *body, ++ pjsip_media_type *msg_media_type, ++ const pjsip_media_type *search_media_type) ++{ ++ pjsip_sdp_info *sdp_info; ++ pjsip_media_type search_type; ++ pjsip_media_type multipart_mixed; ++ pjsip_media_type multipart_alternative; ++ pjsip_media_type *msg_type; ++ pj_status_t status; + +- sdp_info = (pjsip_rdata_sdp_info*) +- rdata->endpt_info.mod_data[mod_inv.mod.id]; +- if (sdp_info) +- return sdp_info; ++ sdp_info = PJ_POOL_ZALLOC_T(pool, ++ pjsip_sdp_info); + +- sdp_info = PJ_POOL_ZALLOC_T(rdata->tp_info.pool, +- pjsip_rdata_sdp_info); + PJ_ASSERT_RETURN(mod_inv.mod.id >= 0, sdp_info); +- rdata->endpt_info.mod_data[mod_inv.mod.id] = sdp_info; + +- pjsip_media_type_init2(&app_sdp, "application", "sdp"); ++ if (!body) { ++ return sdp_info; ++ } + +- if (body && ctype_hdr && +- pj_stricmp(&ctype_hdr->media.type, &app_sdp.type)==0 && +- pj_stricmp(&ctype_hdr->media.subtype, &app_sdp.subtype)==0) ++ if (msg_media_type) { ++ msg_type = msg_media_type; ++ } else { ++ if (body->content_type.type.slen == 0) { ++ return sdp_info; ++ } ++ msg_type = &body->content_type; ++ } ++ ++ if (!search_media_type) { ++ pjsip_media_type_init2(&search_type, "application", "sdp"); ++ } else { ++ pj_memcpy(&search_type, search_media_type, sizeof(search_type)); ++ } ++ ++ pjsip_media_type_init2(&multipart_mixed, "multipart", "mixed"); ++ pjsip_media_type_init2(&multipart_alternative, "multipart", "alternative"); ++ ++ if (pjsip_media_type_cmp(msg_type, &search_type, PJ_FALSE) == 0) + { +- sdp_info->body.ptr = (char*)body->data; +- sdp_info->body.slen = body->len; +- } else if (body && ctype_hdr && +- pj_stricmp2(&ctype_hdr->media.type, "multipart")==0 && +- (pj_stricmp2(&ctype_hdr->media.subtype, "mixed")==0 || +- pj_stricmp2(&ctype_hdr->media.subtype, "alternative")==0)) ++ /* ++ * If the print_body function is print_sdp, we know that ++ * body->data is a pjmedia_sdp_session object and came from ++ * a tx_data. If not, it's the text representation of the ++ * sdp from an rx_data. ++ */ ++ if (body->print_body == print_sdp) { ++ sdp_info->sdp = body->data; ++ } else { ++ sdp_info->body.ptr = (char*)body->data; ++ sdp_info->body.slen = body->len; ++ } ++ } else if (pjsip_media_type_cmp(&multipart_mixed, msg_type, PJ_FALSE) == 0 || ++ pjsip_media_type_cmp(&multipart_alternative, msg_type, PJ_FALSE) == 0) + { +- pjsip_multipart_part *part; ++ pjsip_multipart_part *part; ++ part = pjsip_multipart_find_part(body, &search_type, NULL); ++ if (part) { ++ if (part->body->print_body == print_sdp) { ++ sdp_info->sdp = part->body->data; ++ } else { ++ sdp_info->body.ptr = (char*)part->body->data; ++ sdp_info->body.slen = part->body->len; ++ } ++ } ++ } + +- part = pjsip_multipart_find_part(body, &app_sdp, NULL); +- if (part) { +- sdp_info->body.ptr = (char*)part->body->data; +- sdp_info->body.slen = part->body->len; +- } ++ /* ++ * If the body was already a pjmedia_sdp_session, we can just ++ * return it. If not and there wasn't a text representation ++ * of the sdp either, we can also just return. ++ */ ++ if (sdp_info->sdp || !sdp_info->body.ptr) { ++ return sdp_info; + } + +- if (sdp_info->body.ptr) { +- pj_status_t status; +- status = pjmedia_sdp_parse(rdata->tp_info.pool, +- sdp_info->body.ptr, +- sdp_info->body.slen, +- &sdp_info->sdp); +- if (status == PJ_SUCCESS) +- status = pjmedia_sdp_validate2(sdp_info->sdp, PJ_FALSE); ++ /* ++ * If the body was the text representation of teh SDP, we need ++ * to parse it to create a pjmedia_sdp_session object. ++ */ ++ status = pjmedia_sdp_parse(pool, ++ sdp_info->body.ptr, ++ sdp_info->body.slen, ++ &sdp_info->sdp); ++ if (status == PJ_SUCCESS) ++ status = pjmedia_sdp_validate2(sdp_info->sdp, PJ_FALSE); + +- if (status != PJ_SUCCESS) { +- sdp_info->sdp = NULL; +- PJ_PERROR(1,(THIS_FILE, status, +- "Error parsing/validating SDP body")); +- } ++ if (status != PJ_SUCCESS) { ++ sdp_info->sdp = NULL; ++ PJ_PERROR(1, (THIS_FILE, status, ++ "Error parsing/validating SDP body")); ++ } ++ ++ sdp_info->sdp_err = status; ++ ++ return sdp_info; ++} ++ ++PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info2( ++ pjsip_rx_data *rdata, ++ const pjsip_media_type *search_media_type) ++{ ++ pjsip_media_type *msg_media_type = NULL; ++ pjsip_rdata_sdp_info *sdp_info; + +- sdp_info->sdp_err = status; ++ if (rdata->endpt_info.mod_data[mod_inv.mod.id]) { ++ return (pjsip_rdata_sdp_info *)rdata->endpt_info.mod_data[mod_inv.mod.id]; ++ } ++ ++ /* ++ * rdata should have a Content-Type header at this point but we'll ++ * make sure. ++ */ ++ if (rdata->msg_info.ctype) { ++ msg_media_type = &rdata->msg_info.ctype->media; + } ++ sdp_info = pjsip_get_sdp_info(rdata->tp_info.pool, ++ rdata->msg_info.msg->body, ++ msg_media_type, ++ search_media_type); ++ rdata->endpt_info.mod_data[mod_inv.mod.id] = sdp_info; + + return sdp_info; + } + ++PJ_DEF(pjsip_rdata_sdp_info*) pjsip_rdata_get_sdp_info(pjsip_rx_data *rdata) ++{ ++ return pjsip_rdata_get_sdp_info2(rdata, NULL); ++} ++ ++PJ_DEF(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info2( ++ pjsip_tx_data *tdata, ++ const pjsip_media_type *search_media_type) ++{ ++ pjsip_ctype_hdr *ctype_hdr = NULL; ++ pjsip_media_type *msg_media_type = NULL; ++ pjsip_tdata_sdp_info *sdp_info; ++ ++ if (tdata->mod_data[mod_inv.mod.id]) { ++ return (pjsip_tdata_sdp_info *)tdata->mod_data[mod_inv.mod.id]; ++ } ++ /* ++ * tdata won't usually have a Content-Type header at this point ++ * but we'll check just the same, ++ */ ++ ctype_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTENT_TYPE, NULL); ++ if (ctype_hdr) { ++ msg_media_type = &ctype_hdr->media; ++ } ++ ++ sdp_info = pjsip_get_sdp_info(tdata->pool, ++ tdata->msg->body, ++ msg_media_type, ++ search_media_type); ++ tdata->mod_data[mod_inv.mod.id] = sdp_info; ++ ++ return sdp_info; ++} ++ ++PJ_DEF(pjsip_tdata_sdp_info*) pjsip_tdata_get_sdp_info(pjsip_tx_data *tdata) ++{ ++ return pjsip_tdata_get_sdp_info2(tdata, NULL); ++} + + /* + * Verify incoming INVITE request. +@@ -1740,13 +1846,55 @@ PJ_DEF(pj_status_t) pjsip_create_sdp_bod + return PJ_SUCCESS; + } + ++static pjsip_multipart_part* create_sdp_part(pj_pool_t *pool, pjmedia_sdp_session *sdp) ++{ ++ pjsip_multipart_part *sdp_part; ++ pjsip_media_type media_type; ++ ++ pjsip_media_type_init2(&media_type, "application", "sdp"); ++ ++ sdp_part = pjsip_multipart_create_part(pool); ++ PJ_ASSERT_RETURN(sdp_part != NULL, NULL); ++ ++ sdp_part->body = PJ_POOL_ZALLOC_T(pool, pjsip_msg_body); ++ PJ_ASSERT_RETURN(sdp_part->body != NULL, NULL); ++ ++ pjsip_media_type_cp(pool, &sdp_part->body->content_type, &media_type); ++ ++ sdp_part->body->data = sdp; ++ sdp_part->body->clone_data = clone_sdp; ++ sdp_part->body->print_body = print_sdp; ++ ++ return sdp_part; ++} ++ ++PJ_DEF(pj_status_t) pjsip_create_multipart_sdp_body(pj_pool_t *pool, ++ pjmedia_sdp_session *sdp, ++ pjsip_msg_body **p_body) ++{ ++ pjsip_media_type media_type; ++ pjsip_msg_body *multipart; ++ pjsip_multipart_part *sdp_part; ++ ++ pjsip_media_type_init2(&media_type, "multipart", "mixed"); ++ multipart = pjsip_multipart_create(pool, &media_type, NULL); ++ PJ_ASSERT_RETURN(multipart != NULL, PJ_ENOMEM); ++ ++ sdp_part = create_sdp_part(pool, sdp); ++ PJ_ASSERT_RETURN(sdp_part != NULL, PJ_ENOMEM); ++ pjsip_multipart_add_part(pool, multipart, sdp_part); ++ *p_body = multipart; ++ ++ return PJ_SUCCESS; ++} ++ + static pjsip_msg_body *create_sdp_body(pj_pool_t *pool, + const pjmedia_sdp_session *c_sdp) + { + pjsip_msg_body *body; + pj_status_t status; + +- status = pjsip_create_sdp_body(pool, ++ status = pjsip_create_sdp_body(pool, + pjmedia_sdp_session_clone(pool, c_sdp), + &body); + +@@ -2069,6 +2217,7 @@ static pj_status_t inv_check_sdp_in_inco + ) + ) + { ++ pjsip_sdp_info *tdata_sdp_info; + const pjmedia_sdp_session *reoffer_sdp = NULL; + + PJ_LOG(4,(inv->obj_name, "Received %s response " +@@ -2077,14 +2226,15 @@ static pj_status_t inv_check_sdp_in_inco + (st_code/10==18? "early" : "final" ))); + + /* Retrieve original SDP offer from INVITE request */ +- reoffer_sdp = (const pjmedia_sdp_session*) +- tsx->last_tx->msg->body->data; ++ tdata_sdp_info = pjsip_tdata_get_sdp_info(tsx->last_tx); ++ reoffer_sdp = tdata_sdp_info->sdp; + + /* Feed the original offer to negotiator */ + status = pjmedia_sdp_neg_modify_local_offer2(inv->pool_prov, + inv->neg, + inv->sdp_neg_flags, + reoffer_sdp); ++ + if (status != PJ_SUCCESS) { + PJ_LOG(1,(inv->obj_name, "Error updating local offer for " + "forked 2xx/18x response (err=%d)", status)); +--- a/pjsip/src/test/inv_offer_answer_test.c ++++ b/pjsip/src/test/inv_offer_answer_test.c +@@ -137,6 +137,7 @@ typedef struct inv_test_param_t + pj_bool_t need_established; + unsigned count; + oa_t oa[4]; ++ pj_bool_t multipart_body; + } inv_test_param_t; + + typedef struct inv_test_t +@@ -257,6 +258,17 @@ static void on_media_update(pjsip_inv_se + } + } + ++ /* Special handling for standard offer/answer */ ++ if (inv_test.param.count == 1 && ++ inv_test.param.oa[0] == OFFERER_UAC && ++ inv_test.param.need_established) ++ { ++ jobs[job_cnt].type = ESTABLISH_CALL; ++ jobs[job_cnt].who = PJSIP_ROLE_UAS; ++ job_cnt++; ++ TRACE_((THIS_FILE, " C+++")); ++ } ++ + pj_assert(job_cnt <= PJ_ARRAY_SIZE(jobs)); + } + } +@@ -333,6 +345,15 @@ static pj_bool_t on_rx_request(pjsip_rx_ + NULL, &tdata); + pj_assert(status == PJ_SUCCESS); + ++ /* Use multipart body, if configured */ ++ if (sdp && inv_test.param.multipart_body) { ++ status = pjsip_create_multipart_sdp_body( ++ tdata->pool, ++ pjmedia_sdp_session_clone(tdata->pool, sdp), ++ &tdata->msg->body); ++ } ++ pj_assert(status == PJ_SUCCESS); ++ + status = pjsip_inv_send_msg(inv_test.uas, tdata); + pj_assert(status == PJ_SUCCESS); + +@@ -426,6 +447,7 @@ static int perform_test(inv_test_param_t + sdp = NULL; + + status = pjsip_inv_create_uac(dlg, sdp, inv_test.param.inv_option, &inv_test.uac); ++ //inv_test.uac->create_multipart = param->multipart_body; + PJ_ASSERT_RETURN(status==PJ_SUCCESS, -20); + + TRACE_((THIS_FILE, " Sending INVITE %s offer", (sdp ? "with" : "without"))); +@@ -436,8 +458,17 @@ static int perform_test(inv_test_param_t + status = pjsip_inv_invite(inv_test.uac, &tdata); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30); + ++ /* Use multipart body, if configured */ ++ if (sdp && param->multipart_body) { ++ status = pjsip_create_multipart_sdp_body( ++ tdata->pool, ++ pjmedia_sdp_session_clone(tdata->pool, sdp), ++ &tdata->msg->body); ++ } ++ PJ_ASSERT_RETURN(status==PJ_SUCCESS, -40); ++ + status = pjsip_inv_send_msg(inv_test.uac, tdata); +- PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30); ++ PJ_ASSERT_RETURN(status==PJ_SUCCESS, -50); + + /* + * Wait until test completes +@@ -525,13 +556,14 @@ static inv_test_param_t test_params[] = + 200/INVITE (answer) <-- + ACK --> + */ +-#if 0 ++#if 1 + { + "Standard INVITE with offer", + 0, + PJ_TRUE, + 1, +- { OFFERER_UAC } ++ { OFFERER_UAC }, ++ PJ_FALSE + }, + + { +@@ -539,7 +571,25 @@ static inv_test_param_t test_params[] = + PJSIP_INV_REQUIRE_100REL, + PJ_TRUE, + 1, +- { OFFERER_UAC } ++ { OFFERER_UAC }, ++ PJ_FALSE ++ }, ++ { ++ "Standard INVITE with offer, with Multipart", ++ 0, ++ PJ_TRUE, ++ 1, ++ { OFFERER_UAC }, ++ PJ_TRUE ++ }, ++ ++ { ++ "Standard INVITE with offer, with 100rel, with Multipart", ++ PJSIP_INV_REQUIRE_100REL, ++ PJ_TRUE, ++ 1, ++ { OFFERER_UAC }, ++ PJ_TRUE + }, + #endif + +@@ -555,7 +605,8 @@ static inv_test_param_t test_params[] = + 0, + PJ_TRUE, + 1, +- { OFFERER_UAS } ++ { OFFERER_UAS }, ++ PJ_FALSE + }, + + { +@@ -563,7 +614,25 @@ static inv_test_param_t test_params[] = + PJSIP_INV_REQUIRE_100REL, + PJ_TRUE, + 1, +- { OFFERER_UAS } ++ { OFFERER_UAS }, ++ PJ_FALSE ++ }, ++ { ++ "INVITE with no offer, with Multipart", ++ 0, ++ PJ_TRUE, ++ 1, ++ { OFFERER_UAS }, ++ PJ_TRUE ++ }, ++ ++ { ++ "INVITE with no offer, with 100rel, with Multipart", ++ PJSIP_INV_REQUIRE_100REL, ++ PJ_TRUE, ++ 1, ++ { OFFERER_UAS }, ++ PJ_TRUE + }, + #endif + +@@ -584,14 +653,24 @@ static inv_test_param_t test_params[] = + 0, + PJ_TRUE, + 2, +- { OFFERER_UAC, OFFERER_UAC } ++ { OFFERER_UAC, OFFERER_UAC }, ++ PJ_FALSE ++ }, ++ { ++ "INVITE and UPDATE by UAC, with Multipart", ++ 0, ++ PJ_TRUE, ++ 2, ++ { OFFERER_UAC, OFFERER_UAC }, ++ PJ_TRUE + }, + { + "INVITE and UPDATE by UAC, with 100rel", + PJSIP_INV_REQUIRE_100REL, + PJ_TRUE, + 2, +- { OFFERER_UAC, OFFERER_UAC } ++ { OFFERER_UAC, OFFERER_UAC }, ++ PJ_FALSE + }, + #endif + +@@ -617,6 +696,14 @@ static inv_test_param_t test_params[] = + 4, + { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS } + }, ++ { ++ "INVITE and many UPDATE by UAC and UAS, with Multipart", ++ 0, ++ PJ_TRUE, ++ 4, ++ { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS }, ++ PJ_TRUE ++ }, + + }; + diff --git a/libs/pjproject/patches/0140-Fix-incorrect-unescaping-of-tokens-during-parsing-29.patch b/libs/pjproject/patches/0140-Fix-incorrect-unescaping-of-tokens-during-parsing-29.patch new file mode 100644 index 0000000..deb9d8c --- /dev/null +++ b/libs/pjproject/patches/0140-Fix-incorrect-unescaping-of-tokens-during-parsing-29.patch @@ -0,0 +1,116 @@ +From 3faf1d2b4da553bbaee04f9a13a5d084b381e5fb Mon Sep 17 00:00:00 2001 +From: sauwming +Date: Tue, 4 Jan 2022 15:28:49 +0800 +Subject: [PATCH] Fix incorrect unescaping of tokens during parsing (#2933) + +--- + pjsip/src/pjsip/sip_parser.c | 29 +++++++++++++++++++++++++---- + pjsip/src/test/msg_test.c | 6 +++--- + 2 files changed, 28 insertions(+), 7 deletions(-) + +--- a/pjsip/src/pjsip/sip_parser.c ++++ b/pjsip/src/pjsip/sip_parser.c +@@ -378,17 +378,23 @@ static pj_status_t init_parser() + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str( &pconst.pjsip_TOKEN_SPEC, TOKEN); + ++ /* Token is allowed to have '%' so we do not need this. */ ++ /* + status = pj_cis_dup(&pconst.pjsip_TOKEN_SPEC_ESC, &pconst.pjsip_TOKEN_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_del_str(&pconst.pjsip_TOKEN_SPEC_ESC, "%"); ++ */ + + status = pj_cis_dup(&pconst.pjsip_VIA_PARAM_SPEC, &pconst.pjsip_TOKEN_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC, "[:]"); + ++ /* Token is allowed to have '%' */ ++ /* + status = pj_cis_dup(&pconst.pjsip_VIA_PARAM_SPEC_ESC, &pconst.pjsip_TOKEN_SPEC_ESC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC_ESC, "[:]"); ++ */ + + status = pj_cis_dup(&pconst.pjsip_HOST_SPEC, &pconst.pjsip_ALNUM_SPEC); + PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); +@@ -1210,7 +1216,11 @@ static void parse_param_imp( pj_scanner + unsigned option) + { + /* pname */ +- parser_get_and_unescape(scanner, pool, spec, esc_spec, pname); ++ if (!esc_spec) { ++ pj_scan_get(scanner, spec, pname); ++ } else { ++ parser_get_and_unescape(scanner, pool, spec, esc_spec, pname); ++ } + + /* init pvalue */ + pvalue->ptr = NULL; +@@ -1240,7 +1250,12 @@ static void parse_param_imp( pj_scanner + // pj_scan_get_until_ch(scanner, ']', pvalue); + // pj_scan_get_char(scanner); + } else if(pj_cis_match(spec, *scanner->curptr)) { +- parser_get_and_unescape(scanner, pool, spec, esc_spec, pvalue); ++ if (!esc_spec) { ++ pj_scan_get(scanner, spec, pvalue); ++ } else { ++ parser_get_and_unescape(scanner, pool, spec, esc_spec, ++ pvalue); ++ } + } + } + } +@@ -1252,7 +1267,10 @@ PJ_DEF(void) pjsip_parse_param_imp(pj_sc + unsigned option) + { + parse_param_imp(scanner, pool, pname, pvalue, &pconst.pjsip_TOKEN_SPEC, +- &pconst.pjsip_TOKEN_SPEC_ESC, option); ++ // Token does not need to be unescaped. ++ // Refer to PR #2933. ++ // &pconst.pjsip_TOKEN_SPEC_ESC, ++ NULL, option); + } + + +@@ -2168,7 +2186,10 @@ static void int_parse_via_param( pjsip_v + pj_scan_get_char(scanner); + parse_param_imp(scanner, pool, &pname, &pvalue, + &pconst.pjsip_VIA_PARAM_SPEC, +- &pconst.pjsip_VIA_PARAM_SPEC_ESC, ++ // Token does not need to be unescaped. ++ // Refer to PR #2933. ++ // &pconst.pjsip_VIA_PARAM_SPEC_ESC, ++ NULL, + 0); + + if (!parser_stricmp(pname, pconst.pjsip_BRANCH_STR) && pvalue.slen) { +--- a/pjsip/src/test/msg_test.c ++++ b/pjsip/src/test/msg_test.c +@@ -953,7 +953,7 @@ static int hdr_test_subject_utf(pjsip_hd + + + #define GENERIC_PARAM "p0=a;p1=\"ab:;cd\";p2=ab%3acd;p3" +-#define GENERIC_PARAM_PARSED "p0=a;p1=\"ab:;cd\";p2=ab:cd;p3" ++#define GENERIC_PARAM_PARSED "p0=a;p1=\"ab:;cd\";p2=ab%3acd;p3" + #define PARAM_CHAR "][/:&+$" + #define SIMPLE_ADDR_SPEC "sip:host" + #define ADDR_SPEC SIMPLE_ADDR_SPEC ";"PARAM_CHAR"="PARAM_CHAR ";p1=\";\"" +@@ -1401,7 +1401,7 @@ static int generic_param_test(pjsip_para + param = param->next; + if (pj_strcmp2(¶m->name, "p2")) + return -956; +- if (pj_strcmp2(¶m->value, "ab:cd")) ++ if (pj_strcmp2(¶m->value, "ab%3acd")) + return -957; + + param = param->next; +@@ -1621,7 +1621,7 @@ static int hdr_test_content_type(pjsip_h + prm = prm->next; + if (prm == &hdr->media.param) return -1960; + if (pj_strcmp2(&prm->name, "p2")) return -1961; +- if (pj_strcmp2(&prm->value, "ab:cd")) return -1962; ++ if (pj_strcmp2(&prm->value, "ab%3acd")) return -1962; + + prm = prm->next; + if (prm == &hdr->media.param) return -1970; diff --git a/libs/pjproject/patches/0150-Create-generic-pjsip_hdr_find-functions.patch b/libs/pjproject/patches/0150-Create-generic-pjsip_hdr_find-functions.patch new file mode 100644 index 0000000..5979a3b --- /dev/null +++ b/libs/pjproject/patches/0150-Create-generic-pjsip_hdr_find-functions.patch @@ -0,0 +1,169 @@ +From 7e3dfd8a15fd0f98dbf0e04d2d7a5bded90ee401 Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Tue, 11 Jan 2022 09:27:23 -0700 +Subject: [PATCH] Create generic pjsip_hdr_find functions + +pjsip_msg_find_hdr(), pjsip_msg_find_hdr_by_name(), and +pjsip_msg_find_hdr_by_names() require a pjsip_msg to be passed in +so if you need to search a header list that's not in a pjsip_msg, +you have to do it yourself. This commit adds generic versions of +those 3 functions that take in the actual header list head instead +of a pjsip_msg so if you need to search a list of headers in +something like a pjsip_multipart_part, you can do so easily. +--- + pjsip/include/pjsip/sip_msg.h | 53 +++++++++++++++++++++++++++++++++++ + pjsip/src/pjsip/sip_msg.c | 51 +++++++++++++++++++++++---------- + 2 files changed, 89 insertions(+), 15 deletions(-) + +--- a/pjsip/include/pjsip/sip_msg.h ++++ b/pjsip/include/pjsip/sip_msg.h +@@ -363,6 +363,59 @@ PJ_DECL(void*) pjsip_hdr_shallow_clone( + PJ_DECL(int) pjsip_hdr_print_on( void *hdr, char *buf, pj_size_t len); + + /** ++ * Find a header in a header list by the header type. ++ * ++ * @param hdr_list The "head" of the header list. ++ * @param type The header type to find. ++ * @param start The first header field where the search should begin. ++ * If NULL is specified, then the search will begin from the ++ * first header, otherwise the search will begin at the ++ * specified header. ++ * ++ * @return The header field, or NULL if no header with the specified ++ * type is found. ++ */ ++PJ_DECL(void*) pjsip_hdr_find( const void *hdr_list, ++ pjsip_hdr_e type, ++ const void *start); ++ ++/** ++ * Find a header in a header list by its name. ++ * ++ * @param hdr_list The "head" of the header list. ++ * @param name The header name to find. ++ * @param start The first header field where the search should begin. ++ * If NULL is specified, then the search will begin from the ++ * first header, otherwise the search will begin at the ++ * specified header. ++ * ++ * @return The header field, or NULL if no header with the specified ++ * type is found. ++ */ ++PJ_DECL(void*) pjsip_hdr_find_by_name( const void *hdr_list, ++ const pj_str_t *name, ++ const void *start); ++ ++/** ++ * Find a header in a header list by its name and short name version. ++ * ++ * @param hdr_list The "head" of the header list. ++ * @param name The header name to find. ++ * @param sname The short name version of the header name. ++ * @param start The first header field where the search should begin. ++ * If NULL is specified, then the search will begin from the ++ * first header, otherwise the search will begin at the ++ * specified header. ++ * ++ * @return The header field, or NULL if no header with the specified ++ * type is found. ++ */ ++PJ_DECL(void*) pjsip_hdr_find_by_names( const void *hdr_list, ++ const pj_str_t *name, ++ const pj_str_t *sname, ++ const void *start); ++ ++/** + * @} + */ + +--- a/pjsip/src/pjsip/sip_msg.c ++++ b/pjsip/src/pjsip/sip_msg.c +@@ -334,13 +334,13 @@ PJ_DEF(pjsip_msg*) pjsip_msg_clone( pj_p + return dst; + } + +-PJ_DEF(void*) pjsip_msg_find_hdr( const pjsip_msg *msg, +- pjsip_hdr_e hdr_type, const void *start) ++PJ_DEF(void*) pjsip_hdr_find( const void *hdr_list, ++ pjsip_hdr_e hdr_type, const void *start) + { +- const pjsip_hdr *hdr=(const pjsip_hdr*) start, *end=&msg->hdr; ++ const pjsip_hdr *hdr=(const pjsip_hdr*) start, *end=hdr_list; + + if (hdr == NULL) { +- hdr = msg->hdr.next; ++ hdr = end->next; + } + for (; hdr!=end; hdr = hdr->next) { + if (hdr->type == hdr_type) +@@ -349,14 +349,14 @@ PJ_DEF(void*) pjsip_msg_find_hdr( const + return NULL; + } + +-PJ_DEF(void*) pjsip_msg_find_hdr_by_name( const pjsip_msg *msg, +- const pj_str_t *name, +- const void *start) ++PJ_DEF(void*) pjsip_hdr_find_by_name( const void *hdr_list, ++ const pj_str_t *name, ++ const void *start) + { +- const pjsip_hdr *hdr=(const pjsip_hdr*)start, *end=&msg->hdr; ++ const pjsip_hdr *hdr=(const pjsip_hdr*) start, *end=hdr_list; + + if (hdr == NULL) { +- hdr = msg->hdr.next; ++ hdr = end->next; + } + for (; hdr!=end; hdr = hdr->next) { + if (pj_stricmp(&hdr->name, name) == 0) +@@ -365,15 +365,15 @@ PJ_DEF(void*) pjsip_msg_find_hdr_by_nam + return NULL; + } + +-PJ_DEF(void*) pjsip_msg_find_hdr_by_names( const pjsip_msg *msg, +- const pj_str_t *name, +- const pj_str_t *sname, +- const void *start) ++PJ_DEF(void*) pjsip_hdr_find_by_names( const void *hdr_list, ++ const pj_str_t *name, ++ const pj_str_t *sname, ++ const void *start) + { +- const pjsip_hdr *hdr=(const pjsip_hdr*)start, *end=&msg->hdr; ++ const pjsip_hdr *hdr=(const pjsip_hdr*) start, *end=hdr_list; + + if (hdr == NULL) { +- hdr = msg->hdr.next; ++ hdr = end->next; + } + for (; hdr!=end; hdr = hdr->next) { + if (pj_stricmp(&hdr->name, name) == 0) +@@ -384,6 +384,27 @@ PJ_DEF(void*) pjsip_msg_find_hdr_by_nam + return NULL; + } + ++PJ_DEF(void*) pjsip_msg_find_hdr( const pjsip_msg *msg, ++ pjsip_hdr_e hdr_type, const void *start) ++{ ++ return pjsip_hdr_find(&msg->hdr, hdr_type, start); ++} ++ ++PJ_DEF(void*) pjsip_msg_find_hdr_by_name( const pjsip_msg *msg, ++ const pj_str_t *name, ++ const void *start) ++{ ++ return pjsip_hdr_find_by_name(&msg->hdr, name, start); ++} ++ ++PJ_DEF(void*) pjsip_msg_find_hdr_by_names( const pjsip_msg *msg, ++ const pj_str_t *name, ++ const pj_str_t *sname, ++ const void *start) ++{ ++ return pjsip_hdr_find_by_names(&msg->hdr, name, sname, start); ++} ++ + PJ_DEF(void*) pjsip_msg_find_remove_hdr( pjsip_msg *msg, + pjsip_hdr_e hdr_type, void *start) + { diff --git a/libs/pjproject/patches/0160-Additional-multipart-improvements.patch b/libs/pjproject/patches/0160-Additional-multipart-improvements.patch new file mode 100644 index 0000000..3de67b5 --- /dev/null +++ b/libs/pjproject/patches/0160-Additional-multipart-improvements.patch @@ -0,0 +1,635 @@ +From b7ecff22e77887626fd8e8608c4dd73bc7b7366f Mon Sep 17 00:00:00 2001 +From: George Joseph +Date: Tue, 18 Jan 2022 06:14:31 -0700 +Subject: [PATCH] Additional multipart improvements + +Added the following APIs: +pjsip_multipart_find_part_by_header() +pjsip_multipart_find_part_by_header_str() +pjsip_multipart_find_part_by_cid_str() +pjsip_multipart_find_part_by_cid_uri() +--- + pjsip/include/pjsip/sip_multipart.h | 83 ++++++++++ + pjsip/src/pjsip/sip_multipart.c | 223 +++++++++++++++++++++++++++ + pjsip/src/test/multipart_test.c | 225 +++++++++++++++++++++++++++- + 3 files changed, 530 insertions(+), 1 deletion(-) + +--- a/pjsip/include/pjsip/sip_multipart.h ++++ b/pjsip/include/pjsip/sip_multipart.h +@@ -154,6 +154,89 @@ pjsip_multipart_find_part( const pjsip_m + const pjsip_multipart_part *start); + + /** ++ * Find a body inside multipart bodies which has a header matching the ++ * supplied one. Most useful for finding a part with a specific Content-ID. ++ * ++ * @param pool Memory pool to use for temp space. ++ * @param mp The multipart body. ++ * @param search_hdr Header to search for. ++ * @param start If specified, the search will begin at ++ * start->next part. Otherwise it will begin at ++ * the first part in the multipart bodies. ++ * ++ * @return The first part which has a header matching the ++ * specified one, or NULL if not found. ++ */ ++PJ_DECL(pjsip_multipart_part*) ++pjsip_multipart_find_part_by_header(pj_pool_t *pool, ++ const pjsip_msg_body *mp, ++ void *search_hdr, ++ const pjsip_multipart_part *start); ++ ++/** ++ * Find a body inside multipart bodies which has a header matching the ++ * supplied name and value. Most useful for finding a part with a specific ++ * Content-ID. ++ * ++ * @param pool Memory pool to use for temp space. ++ * @param mp The multipart body. ++ * @param hdr_name Header name to search for. ++ * @param hdr_value Header value search for. ++ * @param start If specified, the search will begin at ++ * start->next part. Otherwise it will begin at ++ * the first part in the multipart bodies. ++ * ++ * @return The first part which has a header matching the ++ * specified one, or NULL if not found. ++ */ ++PJ_DECL(pjsip_multipart_part*) ++pjsip_multipart_find_part_by_header_str(pj_pool_t *pool, ++ const pjsip_msg_body *mp, ++ const pj_str_t *hdr_name, ++ const pj_str_t *hdr_value, ++ const pjsip_multipart_part *start); ++ ++ ++ ++/** ++ * Find a body inside multipart bodies which has a Content-ID value matching the ++ * supplied "cid" URI in pj_str form. The "cid:" scheme will be assumed if the ++ * URL doesn't start with it. Enclosing angle brackets will also be handled ++ * correctly if they exist. ++ * ++ * @see RFC2392 Content-ID and Message-ID Uniform Resource Locators ++ * ++ * @param pool Memory pool to use for temp space. ++ * @param mp The multipart body. ++ * @param cid The "cid" URI to search for in pj_str form. ++ * ++ * @return The first part which has a Content-ID header matching the ++ * specified "cid" URI. or NULL if not found. ++ */ ++PJ_DECL(pjsip_multipart_part*) ++pjsip_multipart_find_part_by_cid_str(pj_pool_t *pool, ++ const pjsip_msg_body *mp, ++ pj_str_t *cid); ++ ++/** ++ * Find a body inside multipart bodies which has a Content-ID value matching the ++ * supplied "cid" URI. ++ * ++ * @see RFC2392 Content-ID and Message-ID Uniform Resource Locators ++ * ++ * @param pool Memory pool to use for temp space. ++ * @param mp The multipart body. ++ * @param cid The "cid" URI to search for. ++ * ++ * @return The first part which had a Content-ID header matching the ++ * specified "cid" URI. or NULL if not found. ++ */ ++PJ_DECL(pjsip_multipart_part*) ++pjsip_multipart_find_part_by_cid_uri(pj_pool_t *pool, ++ const pjsip_msg_body *mp, ++ pjsip_other_uri *cid_uri); ++ ++/** + * Parse multipart message. + * + * @param pool Memory pool. +--- a/pjsip/src/pjsip/sip_multipart.c ++++ b/pjsip/src/pjsip/sip_multipart.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -416,6 +417,220 @@ pjsip_multipart_find_part( const pjsip_m + return NULL; + } + ++/* ++ * Find a body inside multipart bodies which has the header and value. ++ */ ++PJ_DEF(pjsip_multipart_part*) ++pjsip_multipart_find_part_by_header_str(pj_pool_t *pool, ++ const pjsip_msg_body *mp, ++ const pj_str_t *hdr_name, ++ const pj_str_t *hdr_value, ++ const pjsip_multipart_part *start) ++{ ++ struct multipart_data *m_data; ++ pjsip_multipart_part *part; ++ pjsip_hdr *found_hdr; ++ pj_str_t found_hdr_str; ++ pj_str_t found_hdr_value; ++ pj_size_t expected_hdr_slen; ++ pj_size_t buf_size; ++ int hdr_name_len; ++#define REASONABLE_PADDING 32 ++#define SEPARATOR_LEN 2 ++ /* Must specify mandatory params */ ++ PJ_ASSERT_RETURN(mp && hdr_name && hdr_value, NULL); ++ ++ /* mp must really point to an actual multipart msg body */ ++ PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL); ++ ++ /* ++ * We'll need to "print" each header we find to test it but ++ * allocating a buffer of PJSIP_MAX_URL_SIZE is overkill. ++ * Instead, we'll allocate one large enough to hold the search ++ * header name, the ": " separator, the search hdr value, and ++ * the NULL terminator. If we can't print the found header ++ * into that buffer then it can't be a match. ++ * ++ * Some header print functions such as generic_int require enough ++ * space to print the maximum possible header length so we'll ++ * add a reasonable amount to the print buffer size. ++ */ ++ expected_hdr_slen = hdr_name->slen + SEPARATOR_LEN + hdr_value->slen; ++ buf_size = expected_hdr_slen + REASONABLE_PADDING; ++ found_hdr_str.ptr = pj_pool_alloc(pool, buf_size); ++ found_hdr_str.slen = 0; ++ hdr_name_len = hdr_name->slen + SEPARATOR_LEN; ++ ++ m_data = (struct multipart_data*)mp->data; ++ ++ if (start) ++ part = start->next; ++ else ++ part = m_data->part_head.next; ++ ++ while (part != &m_data->part_head) { ++ found_hdr = NULL; ++ while ((found_hdr = pjsip_hdr_find_by_name(&part->hdr, hdr_name, ++ (found_hdr ? found_hdr->next : NULL))) != NULL) { ++ ++ found_hdr_str.slen = pjsip_hdr_print_on((void*) found_hdr, found_hdr_str.ptr, buf_size); ++ /* ++ * If the buffer was too small (slen = -1) or the result wasn't ++ * the same length as the search header, it can't be a match. ++ */ ++ if (found_hdr_str.slen != expected_hdr_slen) { ++ continue; ++ } ++ /* ++ * Set the value overlay to start at the found header value... ++ */ ++ found_hdr_value.ptr = found_hdr_str.ptr + hdr_name_len; ++ found_hdr_value.slen = found_hdr_str.slen - hdr_name_len; ++ /* ...and compare it to the supplied header value. */ ++ if (pj_strcmp(hdr_value, &found_hdr_value) == 0) { ++ return part; ++ } ++ } ++ part = part->next; ++ } ++ return NULL; ++#undef SEPARATOR_LEN ++#undef REASONABLE_PADDING ++} ++ ++PJ_DEF(pjsip_multipart_part*) ++pjsip_multipart_find_part_by_header(pj_pool_t *pool, ++ const pjsip_msg_body *mp, ++ void *search_for, ++ const pjsip_multipart_part *start) ++{ ++ struct multipart_data *m_data; ++ pjsip_hdr *search_hdr = search_for; ++ pj_str_t search_buf; ++ ++ /* Must specify mandatory params */ ++ PJ_ASSERT_RETURN(mp && search_hdr, NULL); ++ ++ /* mp must really point to an actual multipart msg body */ ++ PJ_ASSERT_RETURN(mp->print_body==&multipart_print_body, NULL); ++ ++ /* ++ * Unfortunately, there isn't enough information to determine ++ * the maximum printed size of search_hdr at this point so we ++ * have to allocate a reasonable max. ++ */ ++ search_buf.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); ++ search_buf.slen = pjsip_hdr_print_on(search_hdr, search_buf.ptr, PJSIP_MAX_URL_SIZE - 1); ++ if (search_buf.slen <= 0) { ++ return NULL; ++ } ++ /* ++ * Set the header value to start after the header name plus the ":", then ++ * strip leading and trailing whitespace. ++ */ ++ search_buf.ptr += (search_hdr->name.slen + 1); ++ search_buf.slen -= (search_hdr->name.slen + 1); ++ pj_strtrim(&search_buf); ++ ++ return pjsip_multipart_find_part_by_header_str(pool, mp, &search_hdr->name, &search_buf, start); ++} ++ ++/* ++ * Convert a Content-ID URI to it's corresponding header value. ++ * RFC2392 says... ++ * A "cid" URL is converted to the corresponding Content-ID message ++ * header by removing the "cid:" prefix, converting the % encoded ++ * character(s) to their equivalent US-ASCII characters, and enclosing ++ * the remaining parts with an angle bracket pair, "<" and ">". ++ * ++ * This implementation will accept URIs with or without the "cid:" ++ * scheme and optional angle brackets. ++ */ ++static pj_str_t cid_uri_to_hdr_value(pj_pool_t *pool, pj_str_t *cid_uri) ++{ ++ pj_size_t cid_len = pj_strlen(cid_uri); ++ pj_size_t alloc_len = cid_len + 2 /* for the leading and trailing angle brackets */; ++ pj_str_t uri_overlay; ++ pj_str_t cid_hdr; ++ pj_str_t hdr_overlay; ++ ++ pj_strassign(&uri_overlay, cid_uri); ++ /* If the URI is already enclosed in angle brackets, remove them. */ ++ if (uri_overlay.ptr[0] == '<') { ++ uri_overlay.ptr++; ++ uri_overlay.slen -= 2; ++ } ++ /* If the URI starts with the "cid:" scheme, skip over it. */ ++ if (pj_strncmp2(&uri_overlay, "cid:", 4) == 0) { ++ uri_overlay.ptr += 4; ++ uri_overlay.slen -= 4; ++ } ++ /* Start building */ ++ cid_hdr.ptr = pj_pool_alloc(pool, alloc_len); ++ cid_hdr.ptr[0] = '<'; ++ cid_hdr.slen = 1; ++ hdr_overlay.ptr = cid_hdr.ptr + 1; ++ hdr_overlay.slen = 0; ++ pj_strcpy_unescape(&hdr_overlay, &uri_overlay); ++ cid_hdr.slen += hdr_overlay.slen; ++ cid_hdr.ptr[cid_hdr.slen] = '>'; ++ cid_hdr.slen++; ++ ++ return cid_hdr; ++} ++ ++PJ_DEF(pjsip_multipart_part*) ++pjsip_multipart_find_part_by_cid_str(pj_pool_t *pool, ++ const pjsip_msg_body *mp, ++ pj_str_t *cid) ++{ ++ struct multipart_data *m_data; ++ pjsip_multipart_part *part; ++ pjsip_generic_string_hdr *found_hdr; ++ pj_str_t found_hdr_value; ++ static pj_str_t hdr_name = { "Content-ID", 10}; ++ pj_str_t hdr_value; ++ ++ PJ_ASSERT_RETURN(pool && mp && cid && (pj_strlen(cid) > 0), NULL); ++ ++ hdr_value = cid_uri_to_hdr_value(pool, cid); ++ if (pj_strlen(&hdr_value) == 0) { ++ return NULL; ++ } ++ ++ m_data = (struct multipart_data*)mp->data; ++ part = m_data->part_head.next; ++ ++ while (part != &m_data->part_head) { ++ found_hdr = NULL; ++ while ((found_hdr = pjsip_hdr_find_by_name(&part->hdr, &hdr_name, ++ (found_hdr ? found_hdr->next : NULL))) != NULL) { ++ if (pj_strcmp(&hdr_value, &found_hdr->hvalue) == 0) { ++ return part; ++ } ++ } ++ part = part->next; ++ } ++ return NULL; ++} ++ ++PJ_DEF(pjsip_multipart_part*) ++pjsip_multipart_find_part_by_cid_uri(pj_pool_t *pool, ++ const pjsip_msg_body *mp, ++ pjsip_other_uri *cid_uri) ++{ ++ PJ_ASSERT_RETURN(pool && mp && cid_uri, NULL); ++ ++ if (pj_strcmp2(&cid_uri->scheme, "cid") != 0) { ++ return NULL; ++ } ++ /* ++ * We only need to pass the URI content so we ++ * can do that directly. ++ */ ++ return pjsip_multipart_find_part_by_cid_str(pool, mp, &cid_uri->content); ++} ++ + /* Parse a multipart part. "pct" is parent content-type */ + static pjsip_multipart_part *parse_multipart_part(pj_pool_t *pool, + char *start, +@@ -584,6 +799,7 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_ + (int)boundary.slen, boundary.ptr)); + } + ++ + /* Build the delimiter: + * delimiter = "--" boundary + */ +@@ -630,6 +846,8 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_ + if (*curptr=='\r') ++curptr; + if (*curptr!='\n') { + /* Expecting a newline here */ ++ PJ_LOG(2, (THIS_FILE, "Failed to find newline")); ++ + return NULL; + } + ++curptr; +@@ -645,6 +863,7 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_ + curptr = pj_strstr(&subbody, &delim); + if (!curptr) { + /* We're really expecting end delimiter to be found. */ ++ PJ_LOG(2, (THIS_FILE, "Failed to find end-delimiter")); + return NULL; + } + } +@@ -670,9 +889,13 @@ PJ_DEF(pjsip_msg_body*) pjsip_multipart_ + part = parse_multipart_part(pool, start_body, end_body - start_body, + ctype); + if (part) { ++ TRACE_((THIS_FILE, "Adding part")); + pjsip_multipart_add_part(pool, body, part); ++ } else { ++ PJ_LOG(2, (THIS_FILE, "Failed to add part")); + } + } ++ TRACE_((THIS_FILE, "pjsip_multipart_parse finished: %p", body)); + + return body; + } +--- a/pjsip/src/test/multipart_test.c ++++ b/pjsip/src/test/multipart_test.c +@@ -28,6 +28,7 @@ + typedef pj_status_t (*verify_ptr)(pj_pool_t*,pjsip_msg_body*); + + static pj_status_t verify1(pj_pool_t *pool, pjsip_msg_body *body); ++static pj_status_t verify2(pj_pool_t *pool, pjsip_msg_body *body); + + static struct test_t + { +@@ -68,7 +69,41 @@ static struct test_t + "This is epilogue, which should be ignored too", + + &verify1 ++ }, ++ { ++ /* Content-type */ ++ "multipart", "mixed", "12345", ++ ++ /* Body: */ ++ "This is the prolog, which should be ignored.\r\n" ++ "--12345\r\n" ++ "Content-Type: text/plain\r\n" ++ "Content-ID: \r\n" ++ "Content-ID: <\"header1\"@example.org>\r\n" ++ "Content-Length: 13\r\n" ++ "\r\n" ++ "has header1\r\n" ++ "--12345 \t\r\n" ++ "Content-Type: application/pidf+xml\r\n" ++ "Content-ID: \r\n" ++ "Content-ID: \r\n" ++ "Content-Length: 13\r\n" ++ "\r\n" ++ "has header2\r\n" ++ "--12345\r\n" ++ "Content-Type: text/plain\r\n" ++ "Content-ID: \r\n" ++ "Content-ID: \r\n" ++ "Content-ID: \r\n" ++ "Content-Length: 13\r\n" ++ "\r\n" ++ "has header4\r\n" ++ "--12345--\r\n" ++ "This is epilogue, which should be ignored too", ++ ++ &verify2 + } ++ + }; + + static void init_media_type(pjsip_media_type *mt, +@@ -87,6 +122,192 @@ static void init_media_type(pjsip_media_ + } + } + ++static int verify_hdr(pj_pool_t *pool, pjsip_msg_body *multipart_body, ++ void *hdr, char *part_body) ++{ ++ pjsip_media_type mt; ++ pjsip_multipart_part *part; ++ pj_str_t the_body; ++ ++ ++ part = pjsip_multipart_find_part_by_header(pool, multipart_body, hdr, NULL); ++ if (!part) { ++ return -1; ++ } ++ ++ the_body.ptr = (char*)part->body->data; ++ the_body.slen = part->body->len; ++ ++ if (pj_strcmp2(&the_body, part_body) != 0) { ++ return -2; ++ } ++ ++ return 0; ++} ++ ++static int verify_cid_str(pj_pool_t *pool, pjsip_msg_body *multipart_body, ++ pj_str_t cid_url, char *part_body) ++{ ++ pjsip_media_type mt; ++ pjsip_multipart_part *part; ++ pj_str_t the_body; ++ ++ part = pjsip_multipart_find_part_by_cid_str(pool, multipart_body, &cid_url); ++ if (!part) { ++ return -3; ++ } ++ ++ the_body.ptr = (char*)part->body->data; ++ the_body.slen = part->body->len; ++ ++ if (pj_strcmp2(&the_body, part_body) != 0) { ++ return -4; ++ } ++ ++ return 0; ++} ++ ++static int verify_cid_uri(pj_pool_t *pool, pjsip_msg_body *multipart_body, ++ pjsip_other_uri *cid_uri, char *part_body) ++{ ++ pjsip_media_type mt; ++ pjsip_multipart_part *part; ++ pj_str_t the_body; ++ ++ part = pjsip_multipart_find_part_by_cid_uri(pool, multipart_body, cid_uri); ++ if (!part) { ++ return -5; ++ } ++ ++ the_body.ptr = (char*)part->body->data; ++ the_body.slen = part->body->len; ++ ++ if (pj_strcmp2(&the_body, part_body) != 0) { ++ return -6; ++ } ++ ++ return 0; ++} ++ ++static pj_status_t verify2(pj_pool_t *pool, pjsip_msg_body *body) ++{ ++ int rc = 0; ++ int rcbase = 300; ++ pjsip_other_uri *cid_uri; ++ pjsip_ctype_hdr *ctype_hdr = pjsip_ctype_hdr_create(pool); ++ ++ ctype_hdr->media.type = pj_str("application"); ++ ctype_hdr->media.subtype = pj_str("pidf+xml"); ++ ++ rc = verify_hdr(pool, body, ctype_hdr, "has header2"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str("cid:header1@example.org"), "has header1"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str("%22header1%22@example.org"), "has header1"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "", ++ strlen(""), 0)); ++ rcbase += 10; ++ rc = verify_cid_uri(pool, body, cid_uri, "has header1"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str(""), "has header2"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str("cid:my%ffheader2@example.org"), "has header2"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "", ++ strlen(""), 0)); ++ rcbase += 10; ++ rc = verify_cid_uri(pool, body, cid_uri, "has header2"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str("cid:my%20header3@example.org"), "has header4"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str(""), "has header4"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ cid_uri = pjsip_uri_get_uri(pjsip_parse_uri(pool, "", ++ strlen(""), 0)); ++ rcbase += 10; ++ rc = verify_cid_uri(pool, body, cid_uri, "has header4"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str(""), "has header4"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ /* These should all fail for malformed or missing URI */ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str("cid:"), "has header4"); ++ if (!rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str(""), "has header4"); ++ if (!rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str("<>"), "has header4"); ++ if (!rc) { ++ return (rc - rcbase); ++ } ++ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str(""), "has header4"); ++ if (!rc) { ++ return (rc - rcbase); ++ } ++ ++ /* ++ * This is going to pass but the ' ' in the uri is un-encoded which is invalid ++ * so we should never see it. ++ */ ++ rcbase += 10; ++ rc = verify_cid_str(pool, body, pj_str("cid:my header3@example.org"), "has header4"); ++ if (rc) { ++ return (rc - rcbase); ++ } ++ ++ return 0; ++} ++ + static int verify_part(pjsip_multipart_part *part, + char *h_content_type, + char *h_content_subtype, +@@ -236,8 +457,10 @@ static int parse_test(void) + + pj_strdup2_with_null(pool, &str, p_tests[i].msg); + body = pjsip_multipart_parse(pool, str.ptr, str.slen, &ctype, 0); +- if (!body) ++ if (!body) { ++ pj_pool_release(pool); + return -100; ++ } + + if (p_tests[i].verify) { + rc = p_tests[i].verify(pool, body); From dcc8a89ee0196e7dd185afa480037673e3ff5103 Mon Sep 17 00:00:00 2001 From: Sebastian Kemper Date: Fri, 15 Apr 2022 16:25:50 +0200 Subject: [PATCH 3/5] asterisk: bump to version 18.11.2 - add two new modules (app_sf and func_json) - update 100-build-reproducibly.patch as upstream refactored some of the code - refresh patches This bump includes fixes for the following security issues: https://downloads.asterisk.org/pub/security/AST-2022-001.html https://downloads.asterisk.org/pub/security/AST-2022-002.html https://downloads.asterisk.org/pub/security/AST-2022-003.html Signed-off-by: Sebastian Kemper (cherry picked from commit 958401fa8f98e50df02917eded1eb4815997985d) --- net/asterisk/Makefile | 8 +++++-- .../patches/100-build-reproducibly.patch | 22 +++++++++---------- net/asterisk/patches/130-eventfd.patch | 2 +- .../patches/140-use-default-lua.patch | 2 +- ...170-time-add-support-for-time64-libc.patch | 12 +++++----- ...tall-launchd-issue-on-cross-platfrom.patch | 4 ++-- 6 files changed, 27 insertions(+), 23 deletions(-) diff --git a/net/asterisk/Makefile b/net/asterisk/Makefile index afa5c24..196a7e1 100644 --- a/net/asterisk/Makefile +++ b/net/asterisk/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=asterisk -PKG_VERSION:=18.7.1 +PKG_VERSION:=18.11.2 PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE:=asterisk-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://downloads.asterisk.org/pub/telephony/asterisk/releases -PKG_HASH:=11c8728718b59af74440276ba888484bc9201217719d56436e1e0e85bf533c17 +PKG_HASH:=b456d19610e53789446e097bb9773a82a04088922de0cfaff2b818326b67296b PKG_BUILD_DEPENDS:=libxml2/host @@ -88,6 +88,7 @@ MODULES_AVAILABLE:= \ app-sayunixtime \ app-senddtmf \ app-sendtext \ + app-sf \ app-skel \ app-sms \ app-softhangup \ @@ -192,6 +193,7 @@ MODULES_AVAILABLE:= \ func-holdintercept \ func-iconv \ func-jitterbuffer \ + func-json \ func-lock \ func-math \ func-md5 \ @@ -818,6 +820,7 @@ $(eval $(call BuildAsteriskModule,app-saycounted,Decline words,Decline words acc $(eval $(call BuildAsteriskModule,app-sayunixtime,Say Unix time,Say time.,,,app_sayunixtime,,)) $(eval $(call BuildAsteriskModule,app-senddtmf,Send DTMF digits,Send DTMF digits application.,,,app_senddtmf,,)) $(eval $(call BuildAsteriskModule,app-sendtext,Send text,Send text applications.,,,app_sendtext,,)) +$(eval $(call BuildAsteriskModule,app-sf,SF Sender and Receiver Applications,SF Sender and Receiver Applications.,,,app_sf,,)) $(eval $(call BuildAsteriskModule,app-skel,Skeleton [sample],Skeleton application.,,app_skel.conf,app_skel,,)) $(eval $(call BuildAsteriskModule,app-sms,SMS,SMS/PSTN handler.,,,app_sms,,)) $(eval $(call BuildAsteriskModule,app-softhangup,Hang up requested channel,Hangs up the requested channel.,,,app_softhangup,,)) @@ -922,6 +925,7 @@ $(eval $(call BuildAsteriskModule,func-hangupcause,HANGUPCAUSE related functions $(eval $(call BuildAsteriskModule,func-holdintercept,Hold interception dialplan function,Hold interception dialplan function.,,,func_holdintercept,,)) $(eval $(call BuildAsteriskModule,func-iconv,Charset conversion,Charset conversions.,,,func_iconv,,,$(ICONV_DEPENDS))) $(eval $(call BuildAsteriskModule,func-jitterbuffer,Jitter buffer for read side of channel,Jitter buffer for read side of channel.,,,func_jitterbuffer,,)) +$(eval $(call BuildAsteriskModule,func-json,JSON decoding function,JSON decoding function.,,,func_json,,)) $(eval $(call BuildAsteriskModule,func-lock,Dialplan mutexes,Dialplan mutexes.,,,func_lock,,)) $(eval $(call BuildAsteriskModule,func-math,Math functions,Mathematical dialplan function.,,,func_math,,)) $(eval $(call BuildAsteriskModule,func-md5,MD5 digest dialplan functions,MD5 digest dialplan functions.,,,func_md5,,)) diff --git a/net/asterisk/patches/100-build-reproducibly.patch b/net/asterisk/patches/100-build-reproducibly.patch index b4f017c..f16421b 100644 --- a/net/asterisk/patches/100-build-reproducibly.patch +++ b/net/asterisk/patches/100-build-reproducibly.patch @@ -15,14 +15,14 @@ cat << END /* * build.h ---- a/Makefile -+++ b/Makefile -@@ -489,7 +489,7 @@ doc/core-en_US.xml: makeopts .lastclean - @echo "" >> $@ - @for x in $(MOD_SUBDIRS); do \ - printf "$$x " ; \ -- for i in `find $$x -name '*.c'`; do \ -+ for i in `find $$x -name '*.c' | LC_ALL=C sort`; do \ - MODULEINFO=$$($(AWK) -f build_tools/get_moduleinfo $$i) ; \ - if [ -n "$$MODULEINFO" ] ; \ - then \ +--- a/build_tools/make_xml_documentation ++++ b/build_tools/make_xml_documentation +@@ -187,7 +187,7 @@ printf "Building Documentation For: " + for subdir in ${mod_subdirs} ; do + printf "%s " "${subdir}" + subdir_path="${source_tree}/${subdir}" +- for i in $(${FIND} "${subdir_path}" -name '*.c' -or -name '*.cc'); do ++ for i in $(${FIND} "${subdir_path}" -name '*.c' -or -name '*.cc' | LC_ALL=C sort); do + if [ "${with_moduleinfo}" -eq "1" ] ; then + MODULEINFO=$(${AWK} -f "${source_tree}/build_tools/get_moduleinfo" "${i}") + if [ "${MODULEINFO}" != "" ] ; then diff --git a/net/asterisk/patches/130-eventfd.patch b/net/asterisk/patches/130-eventfd.patch index c783a52..af6fa99 100644 --- a/net/asterisk/patches/130-eventfd.patch +++ b/net/asterisk/patches/130-eventfd.patch @@ -1,6 +1,6 @@ --- a/configure.ac +++ b/configure.ac -@@ -1205,7 +1205,7 @@ if test "${ac_cv_have_variable_fdset}x" +@@ -1260,7 +1260,7 @@ if test "${ac_cv_have_variable_fdset}x" fi AC_MSG_CHECKING([if we have usable eventfd support]) diff --git a/net/asterisk/patches/140-use-default-lua.patch b/net/asterisk/patches/140-use-default-lua.patch index c71aa8a..5f723cc 100644 --- a/net/asterisk/patches/140-use-default-lua.patch +++ b/net/asterisk/patches/140-use-default-lua.patch @@ -1,6 +1,6 @@ --- a/configure.ac +++ b/configure.ac -@@ -2556,7 +2556,7 @@ if test -z "$__opus_include" -o x"$__opu +@@ -2612,7 +2612,7 @@ if test -z "$__opus_include" -o x"$__opu fi AST_EXT_LIB_CHECK([OPUSFILE], [opusfile], [op_open_callbacks], [opus/opusfile.h], [], [$__opus_include]) diff --git a/net/asterisk/patches/170-time-add-support-for-time64-libc.patch b/net/asterisk/patches/170-time-add-support-for-time64-libc.patch index ff4c8b7..fbfdee4 100644 --- a/net/asterisk/patches/170-time-add-support-for-time64-libc.patch +++ b/net/asterisk/patches/170-time-add-support-for-time64-libc.patch @@ -108,7 +108,7 @@ Change-Id: Ic8d61b26033f5c486b917e738c9608b0923a844e } --- a/res/res_http_media_cache.c +++ b/res/res_http_media_cache.c -@@ -152,7 +152,7 @@ static void bucket_file_set_expiration(s +@@ -150,7 +150,7 @@ static void bucket_file_set_expiration(s } /* Use 'now' if we didn't get an expiration time */ @@ -117,7 +117,7 @@ Change-Id: Ic8d61b26033f5c486b917e738c9608b0923a844e ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf); } -@@ -302,7 +302,7 @@ static int bucket_file_expired(struct as +@@ -314,7 +314,7 @@ static int bucket_file_expired(struct as return 1; } @@ -128,7 +128,7 @@ Change-Id: Ic8d61b26033f5c486b917e738c9608b0923a844e --- a/res/res_odbc.c +++ b/res/res_odbc.c -@@ -1038,7 +1038,7 @@ static odbc_status odbc_obj_connect(stru +@@ -1029,7 +1029,7 @@ static odbc_status odbc_obj_connect(stru /* Dont connect while server is marked as unreachable via negative_connection_cache */ negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec; if (time(NULL) < negative_cache_expiration) { @@ -217,7 +217,7 @@ Change-Id: Ic8d61b26033f5c486b917e738c9608b0923a844e addr, --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c -@@ -4744,7 +4744,7 @@ static int persistence_expires_str2struc +@@ -4872,7 +4872,7 @@ static int persistence_expires_str2struc static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf) { const struct subscription_persistence *persistence = obj; @@ -228,7 +228,7 @@ Change-Id: Ic8d61b26033f5c486b917e738c9608b0923a844e #define RESOURCE_LIST_INIT_SIZE 4 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c -@@ -1272,7 +1272,7 @@ static void *check_expiration_thread(voi +@@ -1370,7 +1370,7 @@ static void *check_expiration_thread(voi while (check_interval) { sleep(check_interval); @@ -239,7 +239,7 @@ Change-Id: Ic8d61b26033f5c486b917e738c9608b0923a844e ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval); --- a/res/res_stir_shaken.c +++ b/res/res_stir_shaken.c -@@ -389,7 +389,7 @@ static void set_public_key_expiration(co +@@ -441,7 +441,7 @@ static void set_public_key_expiration(co actual_expires.tv_sec += EXPIRATION_BUFFER; } diff --git a/net/asterisk/patches/180_build-fix-bininstall-launchd-issue-on-cross-platfrom.patch b/net/asterisk/patches/180_build-fix-bininstall-launchd-issue-on-cross-platfrom.patch index 98d2595..cebaee6 100644 --- a/net/asterisk/patches/180_build-fix-bininstall-launchd-issue-on-cross-platfrom.patch +++ b/net/asterisk/patches/180_build-fix-bininstall-launchd-issue-on-cross-platfrom.patch @@ -32,7 +32,7 @@ Signed-off-by: Sergey V. Lobanov --- a/Makefile +++ b/Makefile -@@ -589,9 +589,9 @@ bininstall: _all installdirs $(SUBDIRS_I +@@ -558,9 +558,9 @@ bininstall: _all installdirs $(SUBDIRS_I $(INSTALL) -m 755 contrib/scripts/astversion "$(DESTDIR)$(ASTSBINDIR)/" $(INSTALL) -m 755 contrib/scripts/astgenkey "$(DESTDIR)$(ASTSBINDIR)/" $(INSTALL) -m 755 contrib/scripts/autosupport "$(DESTDIR)$(ASTSBINDIR)/" @@ -47,7 +47,7 @@ Signed-off-by: Sergey V. Lobanov $(INSTALL) -m 644 doc/core-*.xml "$(DESTDIR)$(ASTDATADIR)/documentation" --- a/makeopts.in +++ b/makeopts.in -@@ -369,3 +369,5 @@ SNDFILE_LIB=@SNDFILE_LIB@ +@@ -373,3 +373,5 @@ SNDFILE_LIB=@SNDFILE_LIB@ BEANSTALK_INCLUDE=@BEANSTALK_INCLUDE@ BEANSTALK_LIB=@BEANSTALK_LIB@ From 244e205bb3b092bb9537cc45fc8fd20cd96673ed Mon Sep 17 00:00:00 2001 From: Sebastian Kemper Date: Fri, 15 Apr 2022 17:15:38 +0200 Subject: [PATCH 4/5] asterisk: replace time64 patch This replaces the current patch with the one upstreamed by Philip. Signed-off-by: Sebastian Kemper (cherry picked from commit c1cb4fd1a4059df37c28b60b22f43adf5b11df85) --- ...170-time-add-support-for-time64-libc.patch | 250 ------------ ...70-time-add-support-for-time64-libcs.patch | 366 ++++++++++++++++++ 2 files changed, 366 insertions(+), 250 deletions(-) delete mode 100644 net/asterisk/patches/170-time-add-support-for-time64-libc.patch create mode 100644 net/asterisk/patches/170-time-add-support-for-time64-libcs.patch diff --git a/net/asterisk/patches/170-time-add-support-for-time64-libc.patch b/net/asterisk/patches/170-time-add-support-for-time64-libc.patch deleted file mode 100644 index fbfdee4..0000000 --- a/net/asterisk/patches/170-time-add-support-for-time64-libc.patch +++ /dev/null @@ -1,250 +0,0 @@ -From 472086370630e1547cf9b497295b4a53d811e872 Mon Sep 17 00:00:00 2001 -From: Sebastian Kemper -Date: Sun, 17 Oct 2021 20:17:57 +0200 -Subject: [PATCH] time: add support for time64 libc - -libcs are implementing changes to fix the year 2038 issue on 32 bit -platforms (see [1]). musl libc already went ahead and implemented it, -starting with musl-1.2.0 (see [2]). - -Running asterisk on a 32 bit box with a time64 libc causes some -problems. For instance registering to pjsip doesn't work. The -registration completes fine, but the AOR disappears immediately, making -the registered clients unreachable. - -This commit adds two new definitions to include/asterisk/time.h: - -TIME_T_INT_FMT -TIME_T_UINT_FMT - -If __USE_TIME_BITS64 is defined (by a time64 libc, see [1]), they're set -to the proper conversions for type int64_t, PRId64 and PRIu64 -respectively. If __USE_TIME_BITS64 is not defined, the status quo -remains unchanged ("%ld" and "%lu" are used). - -The new definitions are used in the different parts of asterisk, where -appropriate. - -These changes get rid of the new warnings that appeared with musl-1.2.0 and -make the pjsip registration work again. Below an example warning: - -In file included from ../include/asterisk.h:23, - from res_pjsip/location.c:19: -res_pjsip/location.c: In function 'expiration_struct2str': -../include/asterisk/astmm.h:270:72: warning: format '%ld' expects argument of type 'long int', but argument 6 has type 'time_t' {aka 'long long int'} [-Wformat=] - 270 | __ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, (ret), (fmt), __VA_ARGS__) - | ^~~~~ -res_pjsip/location.c:492:17: note: in expansion of macro 'ast_asprintf' - 492 | return (ast_asprintf(buf, "%ld", contact->expiration_time.tv_sec) < 0) ? -1 : 0; - | ^~~~~~~~~~~~ - -[1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign -[2] https://musl.libc.org/time64.html - -ASTERISK-29674 #close - -Signed-off-by: Sebastian Kemper -Change-Id: Ic8d61b26033f5c486b917e738c9608b0923a844e ---- - include/asterisk/time.h | 16 ++++++++++++++++ - res/res_calendar_caldav.c | 2 +- - res/res_calendar_icalendar.c | 2 +- - res/res_http_media_cache.c | 4 ++-- - res/res_odbc.c | 2 +- - res/res_pjsip/location.c | 2 +- - res/res_pjsip/pjsip_options.c | 2 +- - res/res_pjsip_history.c | 12 ++++++------ - res/res_pjsip_pubsub.c | 2 +- - res/res_pjsip_registrar.c | 2 +- - res/res_stir_shaken.c | 2 +- - 11 files changed, 32 insertions(+), 16 deletions(-) - ---- a/include/asterisk/time.h -+++ b/include/asterisk/time.h -@@ -29,6 +29,22 @@ - #include - #endif - -+#ifndef TIME_T_INT_FMT -+#ifdef __USE_TIME_BITS64 -+#define TIME_T_INT_FMT PRId64 -+#else -+#define TIME_T_INT_FMT "ld" -+#endif -+#endif -+ -+#ifndef TIME_T_UINT_FMT -+#ifdef __USE_TIME_BITS64 -+#define TIME_T_UINT_FMT PRIu64 -+#else -+#define TIME_T_UINT_FMT "lu" -+#endif -+#endif -+ - #ifdef HAVE_UNISTD_H - #include - #endif ---- a/res/res_calendar_caldav.c -+++ b/res/res_calendar_caldav.c -@@ -405,7 +405,7 @@ static void caldav_add_event(icalcompone - ast_string_field_set(event, uid, event->summary); - } else { - char tmp[100]; -- snprintf(tmp, sizeof(tmp), "%ld", event->start); -+ snprintf(tmp, sizeof(tmp), "%" TIME_T_INT_FMT, event->start); - ast_string_field_set(event, uid, tmp); - } - } ---- a/res/res_calendar_icalendar.c -+++ b/res/res_calendar_icalendar.c -@@ -246,7 +246,7 @@ static void icalendar_add_event(icalcomp - ast_string_field_set(event, uid, event->summary); - } else { - char tmp[100]; -- snprintf(tmp, sizeof(tmp), "%ld", event->start); -+ snprintf(tmp, sizeof(tmp), "%" TIME_T_INT_FMT, event->start); - ast_string_field_set(event, uid, tmp); - } - } ---- a/res/res_http_media_cache.c -+++ b/res/res_http_media_cache.c -@@ -150,7 +150,7 @@ static void bucket_file_set_expiration(s - } - - /* Use 'now' if we didn't get an expiration time */ -- snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec); -+ snprintf(time_buf, sizeof(time_buf), "%30" TIME_T_UINT_FMT, actual_expires.tv_sec); - - ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf); - } -@@ -314,7 +314,7 @@ static int bucket_file_expired(struct as - return 1; - } - -- if (sscanf(metadata->value, "%lu", &expires.tv_sec) != 1) { -+ if (sscanf(metadata->value, "%" TIME_T_UINT_FMT, &expires.tv_sec) != 1) { - return 1; - } - ---- a/res/res_odbc.c -+++ b/res/res_odbc.c -@@ -1029,7 +1029,7 @@ static odbc_status odbc_obj_connect(stru - /* Dont connect while server is marked as unreachable via negative_connection_cache */ - negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec; - if (time(NULL) < negative_cache_expiration) { -- ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %ld seconds\n", obj->parent->name, negative_cache_expiration - time(NULL)); -+ ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %" TIME_T_INT_FMT " seconds\n", obj->parent->name, negative_cache_expiration - time(NULL)); - return ODBC_FAIL; - } - ---- a/res/res_pjsip/location.c -+++ b/res/res_pjsip/location.c -@@ -489,7 +489,7 @@ static int expiration_str2struct(const s - static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf) - { - const struct ast_sip_contact *contact = obj; -- return (ast_asprintf(buf, "%ld", contact->expiration_time.tv_sec) < 0) ? -1 : 0; -+ return (ast_asprintf(buf, "%" TIME_T_INT_FMT, contact->expiration_time.tv_sec) < 0) ? -1 : 0; - } - - static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags) ---- a/res/res_pjsip/pjsip_options.c -+++ b/res/res_pjsip/pjsip_options.c -@@ -2733,7 +2733,7 @@ int ast_sip_format_contact_ami(void *obj - ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id); - ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri); - ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent); -- ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec); -+ ast_str_append(&buf, 0, "RegExpire: %" TIME_T_INT_FMT "\r\n", contact->expiration_time.tv_sec); - if (!ast_strlen_zero(contact->via_addr)) { - ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr); - if (contact->via_port) { ---- a/res/res_pjsip_history.c -+++ b/res/res_pjsip_history.c -@@ -199,7 +199,7 @@ static int evaluate_equal(struct operato - { - struct timeval right = { 0, }; - -- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) { -+ if (sscanf(op_right->field, "%" TIME_T_INT_FMT, &right.tv_sec) != 1) { - ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field); - return -1; - } -@@ -270,7 +270,7 @@ static int evaluate_less_than(struct ope - { - struct timeval right = { 0, }; - -- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) { -+ if (sscanf(op_right->field, "%" TIME_T_INT_FMT, &right.tv_sec) != 1) { - ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field); - return -1; - } -@@ -319,7 +319,7 @@ static int evaluate_greater_than(struct - { - struct timeval right = { 0, }; - -- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) { -+ if (sscanf(op_right->field, "%" TIME_T_INT_FMT, &right.tv_sec) != 1) { - ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field); - return -1; - } -@@ -668,7 +668,7 @@ static void sprint_list_entry(struct pjs - char uri[128]; - - pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->msg->line.req.uri, uri, sizeof(uri)); -- snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s %.*s %s SIP/2.0", -+ snprintf(line, len, "%-5.5d %-10.10" TIME_T_INT_FMT " %-5.5s %-24.24s %.*s %s SIP/2.0", - entry->number, - entry->timestamp.tv_sec, - entry->transmitted ? "* ==>" : "* <==", -@@ -677,7 +677,7 @@ static void sprint_list_entry(struct pjs - pj_strbuf(&entry->msg->line.req.method.name), - uri); - } else { -- snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s SIP/2.0 %u %.*s", -+ snprintf(line, len, "%-5.5d %-10.10" TIME_T_INT_FMT " %-5.5s %-24.24s SIP/2.0 %u %.*s", - entry->number, - entry->timestamp.tv_sec, - entry->transmitted ? "* ==>" : "* <==", -@@ -1169,7 +1169,7 @@ static void display_single_entry(struct - pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3); - } - -- ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10ld --->\n", -+ ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10" TIME_T_INT_FMT " --->\n", - entry->number, - entry->transmitted ? "Sent to" : "Received from", - addr, ---- a/res/res_pjsip_pubsub.c -+++ b/res/res_pjsip_pubsub.c -@@ -4872,7 +4872,7 @@ static int persistence_expires_str2struc - static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf) - { - const struct subscription_persistence *persistence = obj; -- return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0; -+ return (ast_asprintf(buf, "%" TIME_T_INT_FMT, persistence->expires.tv_sec) < 0) ? -1 : 0; - } - - #define RESOURCE_LIST_INIT_SIZE 4 ---- a/res/res_pjsip_registrar.c -+++ b/res/res_pjsip_registrar.c -@@ -1370,7 +1370,7 @@ static void *check_expiration_thread(voi - while (check_interval) { - sleep(check_interval); - -- sprintf(time, "%ld", ast_tvnow().tv_sec); -+ sprintf(time, "%" TIME_T_INT_FMT, ast_tvnow().tv_sec); - var = ast_variable_new("expiration_time <=", time, ""); - - ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval); ---- a/res/res_stir_shaken.c -+++ b/res/res_stir_shaken.c -@@ -441,7 +441,7 @@ static void set_public_key_expiration(co - actual_expires.tv_sec += EXPIRATION_BUFFER; - } - -- snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec); -+ snprintf(time_buf, sizeof(time_buf), "%30" TIME_T_UINT_FMT, actual_expires.tv_sec); - - ast_db_put(hash, "expiration", time_buf); - } diff --git a/net/asterisk/patches/170-time-add-support-for-time64-libcs.patch b/net/asterisk/patches/170-time-add-support-for-time64-libcs.patch new file mode 100644 index 0000000..6aa4354 --- /dev/null +++ b/net/asterisk/patches/170-time-add-support-for-time64-libcs.patch @@ -0,0 +1,366 @@ +From f50e793665ea66b5cea7c612cc95ca27bf45afb8 Mon Sep 17 00:00:00 2001 +From: Philip Prindeville +Date: Sun, 13 Feb 2022 12:06:37 -0700 +Subject: [PATCH] time: add support for time64 libcs + +Treat time_t's as entirely unique and use the POSIX API's for +converting to/from strings. + +Lastly, a 64-bit integer formats as 20 digits at most in base10. +Don't need to have any 100 byte buffers to hold that. + +ASTERISK-29674 #close + +Signed-off-by: Philip Prindeville +Change-Id: Id7b25bdca8f92e34229f6454f6c3e500f2cd6f56 +--- + include/asterisk/time.h | 20 ++++++++++++++++++++ + main/Makefile | 1 + + main/time.c | 29 +++++++++++++++++++++++++++++ + res/res_calendar_caldav.c | 4 ++-- + res/res_calendar_icalendar.c | 4 ++-- + res/res_http_media_cache.c | 7 ++++--- + res/res_odbc.c | 4 +++- + res/res_pjsip/location.c | 5 ++++- + res/res_pjsip/pjsip_options.c | 4 +++- + res/res_pjsip_history.c | 25 ++++++++++++++----------- + res/res_pjsip_pubsub.c | 6 +++++- + res/res_pjsip_registrar.c | 5 +++-- + res/res_stir_shaken.c | 6 ++++-- + 13 files changed, 94 insertions(+), 26 deletions(-) + +--- a/include/asterisk/time.h ++++ b/include/asterisk/time.h +@@ -35,6 +35,13 @@ + + #include "asterisk/inline_api.h" + ++/* A time_t can be represented as an unsigned long long (or uint64_t). ++ * Formatted in base 10, UINT64_MAX is 20 digits long, plus one for NUL. ++ * This should be the size of the receiving char buffer for calls to ++ * ast_time_t_to_string(). ++ */ ++#define AST_TIME_T_LEN 21 ++ + /* We have to let the compiler learn what types to use for the elements of a + struct timeval since on linux, it's time_t and suseconds_t, but on *BSD, + they are just a long. +@@ -316,4 +323,17 @@ struct timeval ast_time_create_by_unit(u + */ + struct timeval ast_time_create_by_unit_str(unsigned long val, const char *unit); + ++/*! ++ * \brief Converts to a string representation of a time_t as decimal ++ * seconds since the epoch. Returns -1 on failure, zero otherwise. ++ * ++ * The buffer should be at least 22 bytes long. ++ */ ++int ast_time_t_to_string(time_t time, char *buf, size_t length); ++ ++/*! ++ * \brief Returns a time_t from a string containing seconds since the epoch. ++ */ ++time_t ast_string_to_time_t(const char *str); ++ + #endif /* _ASTERISK_TIME_H */ +--- a/main/Makefile ++++ b/main/Makefile +@@ -169,6 +169,7 @@ sched.o: _ASTCFLAGS+=$(call get_menusele + tcptls.o: _ASTCFLAGS+=$(OPENSSL_INCLUDE) -Wno-deprecated-declarations + uuid.o: _ASTCFLAGS+=$(UUID_INCLUDE) + stasis.o: _ASTCFLAGS+=$(call get_menuselect_cflags,AO2_DEBUG) ++time.o: _ASTCFLAGS+=-D_XOPEN_SOURCE=700 + + + OBJS:=$(sort $(OBJS)) +--- a/main/time.c ++++ b/main/time.c +@@ -25,6 +25,7 @@ + + #include + #include ++#include + #include + + #include "asterisk/time.h" +@@ -143,3 +144,31 @@ struct timeval ast_time_create_by_unit_s + { + return ast_time_create_by_unit(val, ast_time_str_to_unit(unit)); + } ++ ++/*! ++ * \brief Returns a string representation of a time_t as decimal seconds ++ * since the epoch. ++ */ ++int ast_time_t_to_string(time_t time, char *buf, size_t length) ++{ ++ struct tm tm; ++ ++ localtime_r(&time, &tm); ++ return (strftime(buf, length, "%s", &tm) == 0) ? -1 : 0; ++} ++ ++/*! ++ * \brief Returns a time_t from a string containing seconds since the epoch. ++ */ ++time_t ast_string_to_time_t(const char *str) ++{ ++ struct tm tm = { 0, }; ++ ++ /* handle leading spaces */ ++ if (strptime(str, " %s", &tm) == NULL) { ++ return (time_t)-1; ++ } ++ tm.tm_isdst = -1; ++ return mktime(&tm); ++} ++ +--- a/res/res_calendar_caldav.c ++++ b/res/res_calendar_caldav.c +@@ -404,8 +404,8 @@ static void caldav_add_event(icalcompone + if (!ast_strlen_zero(event->summary)) { + ast_string_field_set(event, uid, event->summary); + } else { +- char tmp[100]; +- snprintf(tmp, sizeof(tmp), "%ld", event->start); ++ char tmp[AST_TIME_T_LEN]; ++ ast_time_t_to_string(event->start, tmp, sizeof(tmp)); + ast_string_field_set(event, uid, tmp); + } + } +--- a/res/res_calendar_icalendar.c ++++ b/res/res_calendar_icalendar.c +@@ -245,8 +245,8 @@ static void icalendar_add_event(icalcomp + if (!ast_strlen_zero(event->summary)) { + ast_string_field_set(event, uid, event->summary); + } else { +- char tmp[100]; +- snprintf(tmp, sizeof(tmp), "%ld", event->start); ++ char tmp[AST_TIME_T_LEN]; ++ ast_time_t_to_string(event->start, tmp, sizeof(tmp)); + ast_string_field_set(event, uid, tmp); + } + } +--- a/res/res_http_media_cache.c ++++ b/res/res_http_media_cache.c +@@ -116,7 +116,7 @@ static size_t curl_body_callback(void *p + static void bucket_file_set_expiration(struct ast_bucket_file *bucket_file) + { + struct ast_bucket_metadata *metadata; +- char time_buf[32]; ++ char time_buf[32], secs[AST_TIME_T_LEN]; + struct timeval actual_expires = ast_tvnow(); + + metadata = ast_bucket_file_metadata_get(bucket_file, "cache-control"); +@@ -150,7 +150,8 @@ static void bucket_file_set_expiration(s + } + + /* Use 'now' if we didn't get an expiration time */ +- snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec); ++ ast_time_t_to_string(actual_expires.tv_sec, secs, sizeof(secs)); ++ snprintf(time_buf, sizeof(time_buf), "%30s", secs); + + ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf); + } +@@ -314,7 +315,7 @@ static int bucket_file_expired(struct as + return 1; + } + +- if (sscanf(metadata->value, "%lu", &expires.tv_sec) != 1) { ++ if ((expires.tv_sec = ast_string_to_time_t(metadata->value)) == -1) { + return 1; + } + +--- a/res/res_odbc.c ++++ b/res/res_odbc.c +@@ -1029,7 +1029,9 @@ static odbc_status odbc_obj_connect(stru + /* Dont connect while server is marked as unreachable via negative_connection_cache */ + negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec; + if (time(NULL) < negative_cache_expiration) { +- ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %ld seconds\n", obj->parent->name, negative_cache_expiration - time(NULL)); ++ char secs[AST_TIME_T_LEN]; ++ ast_time_t_to_string(negative_cache_expiration - time(NULL), secs, sizeof(secs)); ++ ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %s seconds\n", obj->parent->name, secs); + return ODBC_FAIL; + } + +--- a/res/res_pjsip/location.c ++++ b/res/res_pjsip/location.c +@@ -489,7 +489,10 @@ static int expiration_str2struct(const s + static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf) + { + const struct ast_sip_contact *contact = obj; +- return (ast_asprintf(buf, "%ld", contact->expiration_time.tv_sec) < 0) ? -1 : 0; ++ char secs[AST_TIME_T_LEN]; ++ ++ ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs)); ++ return (ast_asprintf(buf, "%s", secs) < 0) ? -1 : 0; + } + + static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags) +--- a/res/res_pjsip/pjsip_options.c ++++ b/res/res_pjsip/pjsip_options.c +@@ -2722,6 +2722,7 @@ int ast_sip_format_contact_ami(void *obj + struct ast_sip_contact_status *status; + struct ast_str *buf; + const struct ast_sip_endpoint *endpoint = ami->arg; ++ char secs[AST_TIME_T_LEN]; + + buf = ast_sip_create_ami_event("ContactStatusDetail", ami); + if (!buf) { +@@ -2733,7 +2734,8 @@ int ast_sip_format_contact_ami(void *obj + ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id); + ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri); + ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent); +- ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec); ++ ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs)); ++ ast_str_append(&buf, 0, "RegExpire: %s\r\n", secs); + if (!ast_strlen_zero(contact->via_addr)) { + ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr); + if (contact->via_port) { +--- a/res/res_pjsip_history.c ++++ b/res/res_pjsip_history.c +@@ -199,7 +199,7 @@ static int evaluate_equal(struct operato + { + struct timeval right = { 0, }; + +- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) { ++ if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) { + ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field); + return -1; + } +@@ -270,7 +270,7 @@ static int evaluate_less_than(struct ope + { + struct timeval right = { 0, }; + +- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) { ++ if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) { + ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field); + return -1; + } +@@ -319,7 +319,7 @@ static int evaluate_greater_than(struct + { + struct timeval right = { 0, }; + +- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) { ++ if ((right.tv_sec = ast_string_to_time_t(op_right->field)) == -1) { + ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field); + return -1; + } +@@ -656,7 +656,7 @@ static struct pjsip_history_entry *pjsip + /*! \brief Format single line history entry */ + static void sprint_list_entry(struct pjsip_history_entry *entry, char *line, int len) + { +- char addr[64]; ++ char addr[64], secs[AST_TIME_T_LEN]; + + if (entry->transmitted) { + pj_sockaddr_print(&entry->dst, addr, sizeof(addr), 3); +@@ -664,22 +664,24 @@ static void sprint_list_entry(struct pjs + pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3); + } + ++ ast_time_t_to_string(entry->timestamp.tv_sec, secs, sizeof(secs)); ++ + if (entry->msg->type == PJSIP_REQUEST_MSG) { + char uri[128]; + + pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->msg->line.req.uri, uri, sizeof(uri)); +- snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s %.*s %s SIP/2.0", ++ snprintf(line, len, "%-5.5d %-10.10s %-5.5s %-24.24s %.*s %s SIP/2.0", + entry->number, +- entry->timestamp.tv_sec, ++ secs, + entry->transmitted ? "* ==>" : "* <==", + addr, + (int)pj_strlen(&entry->msg->line.req.method.name), + pj_strbuf(&entry->msg->line.req.method.name), + uri); + } else { +- snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s SIP/2.0 %u %.*s", ++ snprintf(line, len, "%-5.5d %-10.10s %-5.5s %-24.24s SIP/2.0 %u %.*s", + entry->number, +- entry->timestamp.tv_sec, ++ secs, + entry->transmitted ? "* ==>" : "* <==", + addr, + entry->msg->line.status.code, +@@ -1149,7 +1151,7 @@ static struct vector_history_t *filter_h + /*! \brief Print a detailed view of a single entry in the history to the CLI */ + static void display_single_entry(struct ast_cli_args *a, struct pjsip_history_entry *entry) + { +- char addr[64]; ++ char addr[64], secs[AST_TIME_T_LEN]; + char *buf; + + buf = ast_calloc(1, PJSIP_MAX_PKT_LEN * sizeof(char)); +@@ -1169,11 +1171,12 @@ static void display_single_entry(struct + pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3); + } + +- ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10ld --->\n", ++ ast_time_t_to_string(entry->timestamp.tv_sec, secs, sizeof(secs)); ++ ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10s --->\n", + entry->number, + entry->transmitted ? "Sent to" : "Received from", + addr, +- entry->timestamp.tv_sec); ++ secs); + ast_cli(a->fd, "%s\n", buf); + + ast_free(buf); +--- a/res/res_pjsip_pubsub.c ++++ b/res/res_pjsip_pubsub.c +@@ -4872,7 +4872,11 @@ static int persistence_expires_str2struc + static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf) + { + const struct subscription_persistence *persistence = obj; +- return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0; ++ char secs[AST_TIME_T_LEN]; ++ ++ ast_time_t_to_string(persistence->expires.tv_sec, secs, sizeof(secs)); ++ ++ return (ast_asprintf(buf, "%s", secs) < 0) ? -1 : 0; + } + + #define RESOURCE_LIST_INIT_SIZE 4 +--- a/res/res_pjsip_registrar.c ++++ b/res/res_pjsip_registrar.c +@@ -1365,12 +1365,13 @@ static void *check_expiration_thread(voi + { + struct ao2_container *contacts; + struct ast_variable *var; +- char *time = alloca(64); ++ char time[AST_TIME_T_LEN]; + + while (check_interval) { + sleep(check_interval); + +- sprintf(time, "%ld", ast_tvnow().tv_sec); ++ ast_time_t_to_string(ast_tvnow().tv_sec, time, sizeof(time)); ++ + var = ast_variable_new("expiration_time <=", time, ""); + + ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval); +--- a/res/res_stir_shaken.c ++++ b/res/res_stir_shaken.c +@@ -403,7 +403,7 @@ int ast_stir_shaken_add_verification(str + */ + static void set_public_key_expiration(const char *public_cert_url, const struct curl_cb_data *data) + { +- char time_buf[32]; ++ char time_buf[32], secs[AST_TIME_T_LEN]; + char *value; + struct timeval actual_expires = ast_tvnow(); + char hash[41]; +@@ -441,7 +441,9 @@ static void set_public_key_expiration(co + actual_expires.tv_sec += EXPIRATION_BUFFER; + } + +- snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec); ++ ast_time_t_to_string(actual_expires.tv_sec, secs, sizeof(secs)); ++ ++ snprintf(time_buf, sizeof(time_buf), "%30s", secs); + + ast_db_put(hash, "expiration", time_buf); + } From 814294e50e7cf64f43791e0b1930e48077722bf9 Mon Sep 17 00:00:00 2001 From: Sebastian Kemper Date: Fri, 15 Apr 2022 17:17:07 +0200 Subject: [PATCH 5/5] asterisk: add logger patch Add a patch from Philip that got upstreamed. This is in reference to issue #737. Signed-off-by: Sebastian Kemper (cherry picked from commit 23925c22f8e57098797343840b64ac80912e323d) --- ...around-woefully-small-BUFSIZ-in-MUSL.patch | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 net/asterisk/patches/190-logger-workaround-woefully-small-BUFSIZ-in-MUSL.patch diff --git a/net/asterisk/patches/190-logger-workaround-woefully-small-BUFSIZ-in-MUSL.patch b/net/asterisk/patches/190-logger-workaround-woefully-small-BUFSIZ-in-MUSL.patch new file mode 100644 index 0000000..f99da90 --- /dev/null +++ b/net/asterisk/patches/190-logger-workaround-woefully-small-BUFSIZ-in-MUSL.patch @@ -0,0 +1,76 @@ +From 140c19c2067a5e2dcedfbb4dfa08c57758b822cb Mon Sep 17 00:00:00 2001 +From: Philip Prindeville +Date: Mon, 21 Feb 2022 18:05:49 -0700 +Subject: [PATCH] logger: workaround woefully small BUFSIZ in MUSL + +MUSL defines BUFSIZ as 1024 which is not reasonable for log messages. + +More broadly, BUFSIZ is the amount of buffering stdio.h does, which +is arbitrary and largely orthogonal to what logging should accept +as the maximum message size. + +ASTERISK-29928 + +Signed-off-by: Philip Prindeville +Change-Id: Iaa49fbbab029c64ae3d95e4b18270e0442cce170 +--- + main/logger.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +--- a/main/logger.c ++++ b/main/logger.c +@@ -97,6 +97,11 @@ static int logger_queue_limit = 1000; + static int logger_messages_discarded; + static unsigned int high_water_alert; + ++/* On some platforms, like those with MUSL as the runtime, BUFSIZ is ++ * unreasonably small (1024). Use a larger value in those environments. ++ */ ++#define LOGMSG_SIZE MAX(BUFSIZ, 8192) ++ + static enum rotatestrategy { + NONE = 0, /* Do not rotate log files at all, instead rely on external mechanisms */ + SEQUENTIAL = 1 << 0, /* Original method - create a new file, in order */ +@@ -1665,7 +1670,7 @@ static struct sigaction handle_SIGXFSZ = + static void logger_print_normal(struct logmsg *logmsg) + { + struct logchannel *chan = NULL; +- char buf[BUFSIZ]; ++ char buf[LOGMSG_SIZE]; + int level = 0; + + AST_RWLIST_RDLOCK(&logchannels); +@@ -1698,13 +1703,13 @@ static void logger_print_normal(struct l + + /* Don't use LOG_MAKEPRI because it's broken in glibc<2.17 */ + syslog_level = chan->facility | syslog_level; /* LOG_MAKEPRI(chan->facility, syslog_level); */ +- if (!chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) { ++ if (!chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) { + syslog(syslog_level, "%s", buf); + } + } + break; + case LOGTYPE_CONSOLE: +- if (!chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) { ++ if (!chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) { + ast_console_puts_mutable_full(buf, logmsg->level, logmsg->sublevel); + } + break; +@@ -1716,7 +1721,7 @@ static void logger_print_normal(struct l + continue; + } + +- if (chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) { ++ if (chan->formatter.format_log(chan, logmsg, buf, sizeof(buf))) { + continue; + } + +@@ -1780,7 +1785,7 @@ static struct logmsg * __attribute__((fo + } + + /* Build string */ +- res = ast_str_set_va(&buf, BUFSIZ, fmt, ap); ++ res = ast_str_set_va(&buf, LOGMSG_SIZE, fmt, ap); + + /* If the build failed, then abort and free this structure */ + if (res == AST_DYNSTR_BUILD_FAILED) {