diff options
-rw-r--r-- | apps/app_record.c | 56 | ||||
-rw-r--r-- | channels/chan_pjsip.c | 25 | ||||
-rw-r--r-- | include/asterisk/http_websocket.h | 9 | ||||
-rw-r--r-- | include/asterisk/sorcery.h | 37 | ||||
-rw-r--r-- | main/audiohook.c | 4 | ||||
-rw-r--r-- | main/plc.c | 2 | ||||
-rw-r--r-- | main/sorcery.c | 52 | ||||
-rw-r--r-- | res/res_hep_pjsip.c | 90 | ||||
-rw-r--r-- | res/res_http_websocket.c | 50 | ||||
-rw-r--r-- | res/res_pjsip_transport_websocket.c | 12 | ||||
-rw-r--r-- | res/res_sorcery_astdb.c | 38 | ||||
-rw-r--r-- | res/res_sorcery_config.c | 31 | ||||
-rw-r--r-- | res/res_sorcery_memory.c | 25 | ||||
-rw-r--r-- | res/res_sorcery_memory_cache.c | 46 | ||||
-rw-r--r-- | res/res_sorcery_realtime.c | 20 |
15 files changed, 410 insertions, 87 deletions
diff --git a/apps/app_record.c b/apps/app_record.c index 8c3a577ef..b9014fed7 100644 --- a/apps/app_record.c +++ b/apps/app_record.c @@ -137,6 +137,12 @@ enum { OPTION_NO_TRUNCATE = (1 << 9), }; +enum dtmf_response { + RESPONSE_NO_MATCH = 0, + RESPONSE_OPERATOR, + RESPONSE_DTMF, +}; + AST_APP_OPTIONS(app_opts,{ AST_APP_OPTION('a', OPTION_APPEND), AST_APP_OPTION('k', OPTION_KEEP), @@ -160,24 +166,22 @@ AST_APP_OPTIONS(app_opts,{ * \param dtmf_integer the integer value of the DTMF key received * \param terminator key currently set to be pressed for normal termination * - * \retval 0 do not exit - * \retval -1 do exit + * \returns One of enum dtmf_response */ -static int record_dtmf_response(struct ast_channel *chan, struct ast_flags *flags, int dtmf_integer, int terminator) +static enum dtmf_response record_dtmf_response(struct ast_channel *chan, + struct ast_flags *flags, int dtmf_integer, int terminator) { if ((dtmf_integer == OPERATOR_KEY) && (ast_test_flag(flags, OPTION_OPERATOR_EXIT))) { - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "OPERATOR"); - return -1; + return RESPONSE_OPERATOR; } if ((dtmf_integer == terminator) || (ast_test_flag(flags, OPTION_ANY_TERMINATE))) { - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "DTMF"); - return -1; + return RESPONSE_DTMF; } - return 0; + return RESPONSE_NO_MATCH; } static int create_destination_directory(const char *path) @@ -246,6 +250,7 @@ static int record_exec(struct ast_channel *chan, const char *data) ); int ms; struct timeval start; + const char *status_response = "ERROR"; /* The next few lines of code parse out the filename and header from the input string */ if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */ @@ -343,7 +348,7 @@ static int record_exec(struct ast_channel *chan, const char *data) if (res) { ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan)); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; goto out; } @@ -379,7 +384,7 @@ static int record_exec(struct ast_channel *chan, const char *data) if (create_destination_directory(tmp)) { ast_log(LOG_WARNING, "Could not create directory for file %s\n", args.filename); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; goto out; } @@ -388,7 +393,7 @@ static int record_exec(struct ast_channel *chan, const char *data) if (!s) { ast_log(LOG_WARNING, "Could not create file %s\n", args.filename); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; goto out; } @@ -423,7 +428,7 @@ static int record_exec(struct ast_channel *chan, const char *data) if (res) { ast_log(LOG_WARNING, "Problem writing frame\n"); ast_frfree(f); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; break; } @@ -439,7 +444,7 @@ static int record_exec(struct ast_channel *chan, const char *data) /* Ended happily with silence */ ast_frfree(f); gotsilence = 1; - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "SILENCE"); + status_response = "SILENCE"; break; } } @@ -448,12 +453,26 @@ static int record_exec(struct ast_channel *chan, const char *data) if (res) { ast_log(LOG_WARNING, "Problem writing frame\n"); - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "ERROR"); + status_response = "ERROR"; ast_frfree(f); break; } } else if (f->frametype == AST_FRAME_DTMF) { - if (record_dtmf_response(chan, &flags, f->subclass.integer, terminator)) { + enum dtmf_response rc = + record_dtmf_response(chan, &flags, f->subclass.integer, terminator); + switch(rc) { + case RESPONSE_NO_MATCH: + break; + case RESPONSE_OPERATOR: + status_response = "OPERATOR"; + ast_debug(1, "Got OPERATOR\n"); + break; + case RESPONSE_DTMF: + status_response = "DTMF"; + ast_debug(1, "Got DTMF\n"); + break; + } + if (rc != RESPONSE_NO_MATCH) { ast_frfree(f); break; } @@ -463,13 +482,13 @@ static int record_exec(struct ast_channel *chan, const char *data) if (maxduration > 0 && !ms) { gottimeout = 1; - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "TIMEOUT"); + status_response = "TIMEOUT"; } if (!f) { ast_debug(1, "Got hangup\n"); res = -1; - pbx_builtin_setvar_helper(chan, "RECORD_STATUS", "HANGUP"); + status_response = "HANGUP"; if (!ast_test_flag(&flags, OPTION_KEEP)) { ast_filedelete(args.filename, NULL); } @@ -504,6 +523,9 @@ out: if (sildet) { ast_dsp_free(sildet); } + + pbx_builtin_setvar_helper(chan, "RECORD_STATUS", status_response); + return res; } diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 0160425e6..e4e8fa586 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -672,7 +672,19 @@ static int answer(void *data) pjsip_inv_dec_ref(session->inv_session); #endif - return (status == PJ_SUCCESS) ? 0 : -1; + if (status != PJ_SUCCESS) { + char err[PJ_ERR_MSG_SIZE]; + + pj_strerror(status, err, sizeof(err)); + ast_log(LOG_WARNING,"Cannot answer '%s': %s\n", + ast_channel_name(session->channel), err); + /* + * Return this value so we can distinguish between this + * failure and the threadpool synchronous push failing. + */ + return -2; + } + return 0; } /*! \brief Function called by core when we should answer a PJSIP session */ @@ -680,6 +692,7 @@ static int chan_pjsip_answer(struct ast_channel *ast) { struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(ast); struct ast_sip_session *session; + int res; if (ast_channel_state(ast) == AST_STATE_UP) { return 0; @@ -700,11 +713,15 @@ static int chan_pjsip_answer(struct ast_channel *ast) can occur between this thread and bridging (specifically when native bridging attempts to do direct media) */ ast_channel_unlock(ast); - if (ast_sip_push_task_synchronous(session->serializer, answer, session)) { - ast_log(LOG_WARNING, "Unable to push answer task to the threadpool. Cannot answer call\n"); + res = ast_sip_push_task_synchronous(session->serializer, answer, session); + if (res) { + if (res == -1) { + ast_log(LOG_ERROR,"Cannot answer '%s': Unable to push answer task to the threadpool.\n", + ast_channel_name(session->channel)); #ifdef HAVE_PJSIP_INV_SESSION_REF - pjsip_inv_dec_ref(session->inv_session); + pjsip_inv_dec_ref(session->inv_session); #endif + } ao2_ref(session, -1); ast_channel_lock(ast); return -1; diff --git a/include/asterisk/http_websocket.h b/include/asterisk/http_websocket.h index cd49dbe48..2180ef46b 100644 --- a/include/asterisk/http_websocket.h +++ b/include/asterisk/http_websocket.h @@ -345,6 +345,15 @@ AST_OPTIONAL_API(int, ast_websocket_fd, (struct ast_websocket *session), { errno AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_remote_address, (struct ast_websocket *session), {return NULL;}); /*! + * \brief Get the local address for a WebSocket connection session. + * + * \retval ast_sockaddr Local address + * + * \since 13.19.0 + */ +AST_OPTIONAL_API(struct ast_sockaddr *, ast_websocket_local_address, (struct ast_websocket *session), {return NULL;}); + +/*! * \brief Get whether the WebSocket session is using a secure transport or not. * * \retval 0 if unsecure diff --git a/include/asterisk/sorcery.h b/include/asterisk/sorcery.h index 896633816..fcc8a542e 100644 --- a/include/asterisk/sorcery.h +++ b/include/asterisk/sorcery.h @@ -315,6 +315,14 @@ struct ast_sorcery_wizard { /* \brief Callback for whether or not the wizard believes the object is stale */ int (*is_stale)(const struct ast_sorcery *sorcery, void *data, void *object); + + /*! \brief Optional callback for retrieving multiple objects by matching their id with a prefix */ + void (*retrieve_prefix)(const struct ast_sorcery *sorcery, + void *data, + const char *type, + struct ao2_container *objects, + const char *prefix, + const size_t prefix_len); }; /*! \brief Interface for a sorcery object type observer */ @@ -367,9 +375,20 @@ int ast_sorcery_init(void); int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module); /*! + * \brief Register a sorcery wizard + * + * \param interface Pointer to a wizard interface + * \param module Pointer to the module implementing the interface + * + * \retval 0 success + * \retval -1 failure + */ +int __ast_sorcery_wizard_register_with_prefix(const struct ast_sorcery_wizard *interface, struct ast_module *module); + +/*! * \brief See \ref __ast_sorcery_wizard_register() */ -#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register(interface, AST_MODULE_SELF) +#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register_with_prefix(interface, ast_module_info ? ast_module_info->self : NULL) /*! * \brief Unregister a sorcery wizard @@ -1241,6 +1260,22 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex); /*! + * \brief Retrieve multiple objects whose id begins with the specified prefix + * \since 13.19.0 + * + * \param sorcery Pointer to a sorcery structure + * \param type Type of object to retrieve + * \param prefix Object id prefix + * \param prefix_len The length of prefix in bytes + * + * \retval non-NULL if error occurs + * \retval NULL success + * + * \note The prefix is matched in a case sensitive manner. + */ +struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len); + +/*! * \brief Update an object * * \param sorcery Pointer to a sorcery structure diff --git a/main/audiohook.c b/main/audiohook.c index 2cba2de6e..04a379fef 100644 --- a/main/audiohook.c +++ b/main/audiohook.c @@ -950,7 +950,9 @@ static struct ast_frame *audio_audiohook_write_list(struct ast_channel *chan, st * rely on actual media being present to do things. */ if (!middle_frame->data.ptr) { - ast_frfree(middle_frame); + if (middle_frame != start_frame) { + ast_frfree(middle_frame); + } return start_frame; } diff --git a/main/plc.c b/main/plc.c index b649357dc..739f7276d 100644 --- a/main/plc.c +++ b/main/plc.c @@ -96,7 +96,7 @@ static void normalise_history(plc_state_t *s) if (s->buf_ptr == 0) return; memcpy(tmp, s->history, sizeof(int16_t)*s->buf_ptr); - memcpy(s->history, s->history + s->buf_ptr, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr)); + memmove(s->history, s->history + s->buf_ptr, sizeof(int16_t) * (PLC_HISTORY_LEN - s->buf_ptr)); memcpy(s->history + PLC_HISTORY_LEN - s->buf_ptr, tmp, sizeof(int16_t) * s->buf_ptr); s->buf_ptr = 0; } diff --git a/main/sorcery.c b/main/sorcery.c index 5ff1d106c..4e8384409 100644 --- a/main/sorcery.c +++ b/main/sorcery.c @@ -552,6 +552,28 @@ static void sorcery_internal_wizard_destructor(void *obj) int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module) { + struct ast_sorcery_wizard compat = { + .name = interface->name, + .open = interface->open, + .load = interface->load, + .reload = interface->reload, + .create = interface->create, + .retrieve_id = interface->retrieve_id, + .retrieve_regex = interface->retrieve_regex, + .retrieve_fields = interface->retrieve_fields, + .retrieve_multiple = interface->retrieve_multiple, + .update = interface->update, + .delete = interface->delete, + .close = interface->close, + .is_stale = interface->is_stale, + .retrieve_prefix = NULL, + }; + + return __ast_sorcery_wizard_register_with_prefix(&compat, module); +} + +int __ast_sorcery_wizard_register_with_prefix(const struct ast_sorcery_wizard *interface, struct ast_module *module) +{ struct ast_sorcery_internal_wizard *wizard; int res = -1; @@ -2036,6 +2058,36 @@ struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *so return objects; } +struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len) +{ + RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup); + struct ao2_container *objects; + int i; + + if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) { + return NULL; + } + + AST_VECTOR_RW_RDLOCK(&object_type->wizards); + for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) { + struct ast_sorcery_object_wizard *wizard = + AST_VECTOR_GET(&object_type->wizards, i); + + if (!wizard->wizard->callbacks.retrieve_prefix) { + continue; + } + + wizard->wizard->callbacks.retrieve_prefix(sorcery, wizard->data, object_type->name, objects, prefix, prefix_len); + + if (wizard->caching && ao2_container_count(objects)) { + break; + } + } + AST_VECTOR_RW_UNLOCK(&object_type->wizards); + + return objects; +} + /*! \brief Internal function which returns if the wizard has created the object */ static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details) { diff --git a/res/res_hep_pjsip.c b/res/res_hep_pjsip.c index 13efbfa6a..b5be4a102 100644 --- a/res/res_hep_pjsip.c +++ b/res/res_hep_pjsip.c @@ -89,35 +89,44 @@ static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) pjsip_cid_hdr *cid_hdr; pjsip_from_hdr *from_hdr; pjsip_to_hdr *to_hdr; - pjsip_tpmgr_fla2_param prm; capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start)); if (!capture_info) { return PJ_SUCCESS; } - /* Attempt to determine what IP address will we send this packet out of */ - pjsip_tpmgr_fla2_param_default(&prm); - prm.tp_type = tdata->tp_info.transport->key.type; - pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); - prm.local_if = PJ_TRUE; + if (!(tdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) { + pjsip_tpmgr_fla2_param prm; - /* If we can't get the local address use what we have already */ - if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { - pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); - } else { - if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { - snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", - (int)pj_strlen(&prm.ret_addr), - pj_strbuf(&prm.ret_addr), - prm.ret_port); + /* Attempt to determine what IP address will we send this packet out of */ + pjsip_tpmgr_fla2_param_default(&prm); + prm.tp_type = tdata->tp_info.transport->key.type; + pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); + prm.local_if = PJ_TRUE; + + /* If we can't get the local address use what we have already */ + if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { + pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } else { - snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", - (int)pj_strlen(&prm.ret_addr), - pj_strbuf(&prm.ret_addr), - prm.ret_port); + if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { + snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } else { + snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } } + } else { + /* For reliable transports they can only ever come from the transport + * local address. + */ + pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } + pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3); cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg); @@ -150,7 +159,6 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) char remote_buf[256]; char *uuid; struct hepv3_capture_info *capture_info; - pjsip_tpmgr_fla2_param prm; capture_info = hepv3_create_capture_info(&rdata->pkt_info.packet, rdata->pkt_info.len); if (!capture_info) { @@ -162,27 +170,33 @@ static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata) } pj_sockaddr_print(&rdata->pkt_info.src_addr, remote_buf, sizeof(remote_buf), 3); - /* Attempt to determine what IP address we probably received this packet on */ - pjsip_tpmgr_fla2_param_default(&prm); - prm.tp_type = rdata->tp_info.transport->key.type; - pj_strset2(&prm.dst_host, rdata->pkt_info.src_name); - prm.local_if = PJ_TRUE; + if (!(rdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) { + pjsip_tpmgr_fla2_param prm; - /* If we can't get the local address use what we have already */ - if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) { - pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); - } else { - if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { - snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", - (int)pj_strlen(&prm.ret_addr), - pj_strbuf(&prm.ret_addr), - prm.ret_port); + /* Attempt to determine what IP address we probably received this packet on */ + pjsip_tpmgr_fla2_param_default(&prm); + prm.tp_type = rdata->tp_info.transport->key.type; + pj_strset2(&prm.dst_host, rdata->pkt_info.src_name); + prm.local_if = PJ_TRUE; + + /* If we can't get the local address use what we have already */ + if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), rdata->tp_info.pool, &prm) != PJ_SUCCESS) { + pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } else { - snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", - (int)pj_strlen(&prm.ret_addr), - pj_strbuf(&prm.ret_addr), - prm.ret_port); + if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { + snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } else { + snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", + (int)pj_strlen(&prm.ret_addr), + pj_strbuf(&prm.ret_addr), + prm.ret_port); + } } + } else { + pj_sockaddr_print(&rdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } uuid = assign_uuid(&rdata->msg_info.cid->id, &rdata->msg_info.to->tag, &rdata->msg_info.from->tag); diff --git a/res/res_http_websocket.c b/res/res_http_websocket.c index 8e9aae9dd..c1f9a29d6 100644 --- a/res/res_http_websocket.c +++ b/res/res_http_websocket.c @@ -86,18 +86,19 @@ /*! \brief Structure definition for session */ struct ast_websocket { - struct ast_iostream *stream; /*!< iostream of the connection */ - struct ast_sockaddr address; /*!< Address of the remote client */ - enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */ - size_t payload_len; /*!< Length of the payload */ - char *payload; /*!< Pointer to the payload */ - size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */ - int timeout; /*!< The timeout for operations on the socket */ - unsigned int secure:1; /*!< Bit to indicate that the transport is secure */ - unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */ - unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */ - struct websocket_client *client; /*!< Client object when connected as a client websocket */ - char session_id[AST_UUID_STR_LEN]; /*!< The identifier for the websocket session */ + struct ast_iostream *stream; /*!< iostream of the connection */ + struct ast_sockaddr remote_address; /*!< Address of the remote client */ + struct ast_sockaddr local_address; /*!< Our local address */ + enum ast_websocket_opcode opcode; /*!< Cached opcode for multi-frame messages */ + size_t payload_len; /*!< Length of the payload */ + char *payload; /*!< Pointer to the payload */ + size_t reconstruct; /*!< Number of bytes before a reconstructed payload will be returned and a new one started */ + int timeout; /*!< The timeout for operations on the socket */ + unsigned int secure:1; /*!< Bit to indicate that the transport is secure */ + unsigned int closing:1; /*!< Bit to indicate that the session is in the process of being closed */ + unsigned int close_sent:1; /*!< Bit to indicate that the session close opcode has been sent and no further data will be sent */ + struct websocket_client *client; /*!< Client object when connected as a client websocket */ + char session_id[AST_UUID_STR_LEN]; /*!< The identifier for the websocket session */ }; /*! \brief Hashing function for protocols */ @@ -183,7 +184,7 @@ static void session_destroy_fn(void *obj) ast_iostream_close(session->stream); session->stream = NULL; ast_verb(2, "WebSocket connection %s '%s' closed\n", session->client ? "to" : "from", - ast_sockaddr_stringify(&session->address)); + ast_sockaddr_stringify(&session->remote_address)); } } @@ -318,7 +319,7 @@ int AST_OPTIONAL_API_NAME(ast_websocket_close)(struct ast_websocket *session, ui ast_iostream_close(session->stream); session->stream = NULL; ast_verb(2, "WebSocket connection %s '%s' forcefully closed due to fatal write error\n", - session->client ? "to" : "from", ast_sockaddr_stringify(&session->address)); + session->client ? "to" : "from", ast_sockaddr_stringify(&session->remote_address)); } ao2_unlock(session); @@ -432,7 +433,12 @@ int AST_OPTIONAL_API_NAME(ast_websocket_fd)(struct ast_websocket *session) struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_remote_address)(struct ast_websocket *session) { - return &session->address; + return &session->remote_address; +} + +struct ast_sockaddr * AST_OPTIONAL_API_NAME(ast_websocket_local_address)(struct ast_websocket *session) +{ + return &session->local_address; } int AST_OPTIONAL_API_NAME(ast_websocket_is_secure)(struct ast_websocket *session) @@ -899,11 +905,21 @@ int AST_OPTIONAL_API_NAME(ast_websocket_uri_cb)(struct ast_tcptls_session_instan return 0; } + /* Get our local address for the connected socket */ + if (ast_getsockname(ast_iostream_get_fd(ser->stream), &session->local_address)) { + ast_log(LOG_WARNING, "WebSocket connection from '%s' could not be accepted - failed to get local address\n", + ast_sockaddr_stringify(&ser->remote_address)); + websocket_bad_request(ser); + ao2_ref(session, -1); + ao2_ref(protocol_handler, -1); + return 0; + } + ast_verb(2, "WebSocket connection from '%s' for protocol '%s' accepted using version '%d'\n", ast_sockaddr_stringify(&ser->remote_address), protocol ? : "", version); /* Populate the session with all the needed details */ session->stream = ser->stream; - ast_sockaddr_copy(&session->address, &ser->remote_address); + ast_sockaddr_copy(&session->remote_address, &ser->remote_address); session->opcode = -1; session->reconstruct = DEFAULT_RECONSTRUCTION_CEILING; session->secure = ast_iostream_get_ssl(ser->stream) ? 1 : 0; @@ -1357,7 +1373,7 @@ static enum ast_websocket_result websocket_client_connect(struct ast_websocket * ws->stream = ws->client->ser->stream; ws->secure = ast_iostream_get_ssl(ws->stream) ? 1 : 0; ws->client->ser->stream = NULL; - ast_sockaddr_copy(&ws->address, &ws->client->ser->remote_address); + ast_sockaddr_copy(&ws->remote_address, &ws->client->ser->remote_address); return WS_OK; } diff --git a/res/res_pjsip_transport_websocket.c b/res/res_pjsip_transport_websocket.c index 22ec19540..b5b6a3e0a 100644 --- a/res/res_pjsip_transport_websocket.c +++ b/res/res_pjsip_transport_websocket.c @@ -206,20 +206,16 @@ static int transport_create(void *data) pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.key.rem_addr); if (newtransport->transport.key.rem_addr.addr.sa_family == pj_AF_INET6()) { newtransport->transport.key.type = transport_type_wss_ipv6; - newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN); - pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET6_ADDRSTRLEN, 0); } else { newtransport->transport.key.type = transport_type_wss; - newtransport->transport.local_name.host.ptr = (char *)pj_pool_alloc(pool, PJ_INET_ADDRSTRLEN); - pj_sockaddr_print(&newtransport->transport.key.rem_addr, newtransport->transport.local_name.host.ptr, PJ_INET_ADDRSTRLEN, 0); } newtransport->transport.addr_len = pj_sockaddr_get_len(&newtransport->transport.key.rem_addr); - pj_sockaddr_cp(&newtransport->transport.local_addr, &newtransport->transport.key.rem_addr); - - newtransport->transport.local_name.host.slen = pj_ansi_strlen(newtransport->transport.local_name.host.ptr); - newtransport->transport.local_name.port = pj_sockaddr_get_port(&newtransport->transport.key.rem_addr); + ws_addr_str = ast_sockaddr_stringify(ast_websocket_local_address(newtransport->ws_session)); + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, ws_addr_str), &newtransport->transport.local_addr); + pj_strdup2(pool, &newtransport->transport.local_name.host, ast_sockaddr_stringify_host(ast_websocket_local_address(newtransport->ws_session))); + newtransport->transport.local_name.port = ast_sockaddr_port(ast_websocket_local_address(newtransport->ws_session)); newtransport->transport.flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)newtransport->transport.key.type); newtransport->transport.info = (char *)pj_pool_alloc(newtransport->transport.pool, 64); diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index 8d1633511..8b93b57ba 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -44,6 +44,7 @@ static void *sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, vo static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len); static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object); static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_astdb_close(void *data); @@ -56,6 +57,7 @@ static struct ast_sorcery_wizard astdb_object_wizard = { .retrieve_fields = sorcery_astdb_retrieve_fields, .retrieve_multiple = sorcery_astdb_retrieve_multiple, .retrieve_regex = sorcery_astdb_retrieve_regex, + .retrieve_prefix = sorcery_astdb_retrieve_prefix, .update = sorcery_astdb_update, .delete = sorcery_astdb_delete, .close = sorcery_astdb_close, @@ -327,6 +329,42 @@ static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void regfree(&expression); } +static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + const char *family_prefix = data; + size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */ + char family[family_len + 1]; + char tree[prefix_len + sizeof("%")]; + RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); + struct ast_db_entry *entry; + + snprintf(tree, sizeof(tree), "%.*s%%", (int) prefix_len, prefix); + snprintf(family, sizeof(family), "%s/%s", family_prefix, type); + + if (!(entries = ast_db_gettree(family, tree))) { + return; + } + + for (entry = entries; entry; entry = entry->next) { + /* The key in the entry includes the family, so we need to strip it out */ + const char *key = entry->key + family_len + 2; + RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); + struct ast_json_error error; + RAII_VAR(void *, object, NULL, ao2_cleanup); + RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); + + if (!(json = ast_json_load_string(entry->data, &error)) + || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) + || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) + || !(object = ast_sorcery_alloc(sorcery, type, key)) + || ast_sorcery_objectset_apply(sorcery, object, objset)) { + return; + } + + ao2_link(objects, object); + } +} + static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object) { const char *prefix = data; diff --git a/res/res_sorcery_config.c b/res/res_sorcery_config.c index 0de34c640..20178883b 100644 --- a/res/res_sorcery_config.c +++ b/res/res_sorcery_config.c @@ -71,6 +71,12 @@ struct sorcery_config_fields_cmp_params { /*! \brief Regular expression for checking object id */ regex_t *regex; + /*! \brief Prefix for matching object id */ + const char *prefix; + + /*! \brief Prefix length in bytes for matching object id */ + const size_t prefix_len; + /*! \brief Optional container to put object into */ struct ao2_container *container; }; @@ -83,6 +89,7 @@ static void *sorcery_config_retrieve_fields(const struct ast_sorcery *sorcery, v static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len); static void sorcery_config_close(void *data); static struct ast_sorcery_wizard config_object_wizard = { @@ -94,6 +101,7 @@ static struct ast_sorcery_wizard config_object_wizard = { .retrieve_fields = sorcery_config_retrieve_fields, .retrieve_multiple = sorcery_config_retrieve_multiple, .retrieve_regex = sorcery_config_retrieve_regex, + .retrieve_prefix = sorcery_config_retrieve_prefix, .close = sorcery_config_close, }; @@ -118,6 +126,11 @@ static int sorcery_config_fields_cmp(void *obj, void *arg, int flags) ao2_link(params->container, obj); } return 0; + } else if (params->prefix) { + if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) { + ao2_link(params->container, obj); + } + return 0; } else if (params->fields && (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) || (!ast_variable_lists_match(objset, params->fields, 0)))) { @@ -206,6 +219,24 @@ static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, voi regfree(&expression); } +static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + struct sorcery_config *config = data; + RAII_VAR(struct ao2_container *, config_objects, ao2_global_obj_ref(config->objects), ao2_cleanup); + struct sorcery_config_fields_cmp_params params = { + .sorcery = sorcery, + .container = objects, + .prefix = prefix, + .prefix_len = prefix_len, + }; + + if (!config_objects) { + return; + } + + ao2_callback(config_objects, OBJ_NODATA | OBJ_MULTIPLE, sorcery_config_fields_cmp, ¶ms); +} + /*! \brief Internal function which determines if criteria has been met for considering an object set applicable */ static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria) { diff --git a/res/res_sorcery_memory.c b/res/res_sorcery_memory.c index 57d5eace0..6c91dad2d 100644 --- a/res/res_sorcery_memory.c +++ b/res/res_sorcery_memory.c @@ -46,6 +46,7 @@ static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, v static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len); static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object); static int sorcery_memory_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_memory_close(void *data); @@ -58,6 +59,7 @@ static struct ast_sorcery_wizard memory_object_wizard = { .retrieve_fields = sorcery_memory_retrieve_fields, .retrieve_multiple = sorcery_memory_retrieve_multiple, .retrieve_regex = sorcery_memory_retrieve_regex, + .retrieve_prefix = sorcery_memory_retrieve_prefix, .update = sorcery_memory_update, .delete = sorcery_memory_delete, .close = sorcery_memory_close, @@ -74,6 +76,12 @@ struct sorcery_memory_fields_cmp_params { /*! \brief Regular expression for checking object id */ regex_t *regex; + /*! \brief Prefix for matching object id */ + const char *prefix; + + /*! \brief Prefix length in bytes for matching object id */ + const size_t prefix_len; + /*! \brief Optional container to put object into */ struct ao2_container *container; }; @@ -125,6 +133,11 @@ static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags) ao2_link(params->container, obj); } return 0; + } else if (params->prefix) { + if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) { + ao2_link(params->container, obj); + } + return 0; } else if (params->fields && (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) || (!ast_variable_lists_match(objset, params->fields, 0)))) { @@ -198,6 +211,18 @@ static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, voi regfree(&expression); } +static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + struct sorcery_memory_fields_cmp_params params = { + .sorcery = sorcery, + .container = objects, + .prefix = prefix, + .prefix_len = prefix_len, + }; + + ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms); +} + static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object) { RAII_VAR(void *, existing, NULL, ao2_cleanup); diff --git a/res/res_sorcery_memory_cache.c b/res/res_sorcery_memory_cache.c index bf2347ccd..30e6ef04b 100644 --- a/res/res_sorcery_memory_cache.c +++ b/res/res_sorcery_memory_cache.c @@ -185,6 +185,10 @@ struct sorcery_memory_cache_fields_cmp_params { const struct ast_variable *fields; /*! \brief Regular expression for checking object id */ regex_t *regex; + /*! \brief Prefix for matching object id */ + const char *prefix; + /*! \brief Prefix length in bytes for matching object id */ + const size_t prefix_len; /*! \brief Optional container to put object into */ struct ao2_container *container; }; @@ -201,6 +205,8 @@ static void sorcery_memory_cache_retrieve_multiple(const struct ast_sorcery *sor struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_memory_cache_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *prefix, const size_t prefix_len); static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_memory_cache_close(void *data); @@ -216,6 +222,7 @@ static struct ast_sorcery_wizard memory_cache_object_wizard = { .retrieve_fields = sorcery_memory_cache_retrieve_fields, .retrieve_multiple = sorcery_memory_cache_retrieve_multiple, .retrieve_regex = sorcery_memory_cache_retrieve_regex, + .retrieve_prefix = sorcery_memory_cache_retrieve_prefix, .close = sorcery_memory_cache_close, }; @@ -1253,6 +1260,11 @@ static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags) ao2_link(params->container, cached->object); } return 0; + } else if (params->prefix) { + if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) { + ao2_link(params->container, cached->object); + } + return 0; } else if (params->fields && (!ast_variable_lists_match(cached->objectset, params->fields, 0))) { /* If we can't turn the object into an object set OR if differences exist between the fields @@ -1378,6 +1390,40 @@ static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcer /*! * \internal + * \brief Callback function to retrieve multiple objects whose id matches a prefix + * + * \param sorcery The sorcery instance + * \param data The sorcery memory cache + * \param type The type of the object to retrieve + * \param objects Container to place the objects into + * \param prefix Prefix to match against the object id + */ +static void sorcery_memory_cache_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + struct sorcery_memory_cache *cache = data; + struct sorcery_memory_cache_fields_cmp_params params = { + .sorcery = sorcery, + .cache = cache, + .container = objects, + .prefix = prefix, + .prefix_len = prefix_len, + }; + + if (is_passthru_update() || !cache->full_backend_cache) { + return; + } + + memory_cache_full_update(sorcery, type, cache); + ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, ¶ms); + + if (ao2_container_count(objects)) { + memory_cache_stale_check(sorcery, cache); + } +} + +/*! + * \internal * \brief Callback function to finish configuring the memory cache * * \param data The sorcery memory cache diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c index 3f114046c..a858cbcef 100644 --- a/res/res_sorcery_realtime.c +++ b/res/res_sorcery_realtime.c @@ -57,6 +57,8 @@ static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields); static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex); +static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *prefix, const size_t prefix_len); static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object); static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object); static void sorcery_realtime_close(void *data); @@ -69,6 +71,7 @@ static struct ast_sorcery_wizard realtime_object_wizard = { .retrieve_fields = sorcery_realtime_retrieve_fields, .retrieve_multiple = sorcery_realtime_retrieve_multiple, .retrieve_regex = sorcery_realtime_retrieve_regex, + .retrieve_prefix = sorcery_realtime_retrieve_prefix, .update = sorcery_realtime_update, .delete = sorcery_realtime_delete, .close = sorcery_realtime_close, @@ -260,6 +263,23 @@ static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, v sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields); } +static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, + struct ao2_container *objects, const char *prefix, const size_t prefix_len) +{ + char field[strlen(UUID_FIELD) + 6], value[prefix_len + 2]; + RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy); + + if (prefix_len) { + snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); + snprintf(value, sizeof(value), "%.*s%%", (int) prefix_len, prefix); + if (!(fields = ast_variable_new(field, value, ""))) { + return; + } + } + + sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields); +} + static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object) { struct sorcery_config *config = data; |