📄 sip_util.c
字号:
/* $Id: sip_util.c 1121 2007-04-01 22:58:47Z bennylp $ *//* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <pjsip/sip_util.h>#include <pjsip/sip_transport.h>#include <pjsip/sip_msg.h>#include <pjsip/sip_endpoint.h>#include <pjsip/sip_event.h>#include <pjsip/sip_transaction.h>#include <pjsip/sip_module.h>#include <pjsip/sip_errno.h>#include <pj/log.h>#include <pj/string.h>#include <pj/guid.h>#include <pj/pool.h>#include <pj/except.h>#include <pj/rand.h>#include <pj/assert.h>#include <pj/errno.h>#define THIS_FILE "endpoint"static const char *event_str[] = { "UNIDENTIFIED", "TIMER", "TX_MSG", "RX_MSG", "TRANSPORT_ERROR", "TSX_STATE", "USER",};static pj_str_t str_TEXT = { "text", 4}, str_PLAIN = { "plain", 5 };/* * Initialize transmit data (msg) with the headers and optional body. * This will just put the headers in the message as it is. Be carefull * when calling this function because once a header is put in a message, * it CAN NOT be put in other message until the first message is deleted, * because the way the header is put in the list. * That's why the session will shallow_clone it's headers before calling * this function. */static void init_request_throw( pjsip_endpoint *endpt, pjsip_tx_data *tdata, pjsip_method *method, pjsip_uri *param_target, pjsip_from_hdr *param_from, pjsip_to_hdr *param_to, pjsip_contact_hdr *param_contact, pjsip_cid_hdr *param_call_id, pjsip_cseq_hdr *param_cseq, const pj_str_t *param_text){ pjsip_msg *msg; pjsip_msg_body *body; pjsip_via_hdr *via; const pjsip_hdr *endpt_hdr; /* Create the message. */ msg = tdata->msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG); /* Init request URI. */ pj_memcpy(&msg->line.req.method, method, sizeof(*method)); msg->line.req.uri = param_target; /* Add additional request headers from endpoint. */ endpt_hdr = pjsip_endpt_get_request_headers(endpt)->next; while (endpt_hdr != pjsip_endpt_get_request_headers(endpt)) { pjsip_hdr *hdr = pjsip_hdr_shallow_clone(tdata->pool, endpt_hdr); pjsip_msg_add_hdr( tdata->msg, hdr ); endpt_hdr = endpt_hdr->next; } /* Add From header. */ if (param_from->tag.slen == 0) pj_create_unique_string(tdata->pool, ¶m_from->tag); pjsip_msg_add_hdr(msg, (void*)param_from); /* Add To header. */ pjsip_msg_add_hdr(msg, (void*)param_to); /* Add Contact header. */ if (param_contact) { pjsip_msg_add_hdr(msg, (void*)param_contact); } /* Add Call-ID header. */ pjsip_msg_add_hdr(msg, (void*)param_call_id); /* Add CSeq header. */ pjsip_msg_add_hdr(msg, (void*)param_cseq); /* Add a blank Via header in the front of the message. */ via = pjsip_via_hdr_create(tdata->pool); via->rport_param = 0; pjsip_msg_insert_first_hdr(msg, (void*)via); /* Add header params as request headers */ if (PJSIP_URI_SCHEME_IS_SIP(param_target) || PJSIP_URI_SCHEME_IS_SIPS(param_target)) { pjsip_sip_uri *uri = (pjsip_sip_uri*) pjsip_uri_get_uri(param_target); pjsip_param *hparam; hparam = uri->header_param.next; while (hparam != &uri->header_param) { pjsip_generic_string_hdr *hdr; hdr = pjsip_generic_string_hdr_create(tdata->pool, &hparam->name, &hparam->value); pjsip_msg_add_hdr(msg, (pjsip_hdr*)hdr); hparam = hparam->next; } } /* Create message body. */ if (param_text) { body = pj_pool_calloc(tdata->pool, 1, sizeof(pjsip_msg_body)); body->content_type.type = str_TEXT; body->content_type.subtype = str_PLAIN; body->data = pj_pool_alloc(tdata->pool, param_text->slen ); pj_memcpy(body->data, param_text->ptr, param_text->slen); body->len = param_text->slen; body->print_body = &pjsip_print_text_body; msg->body = body; } PJ_LOG(5,(THIS_FILE, "%s created.", pjsip_tx_data_get_info(tdata)));}/* * Create arbitrary request. */PJ_DEF(pj_status_t) pjsip_endpt_create_request( pjsip_endpoint *endpt, const pjsip_method *method, const pj_str_t *param_target, const pj_str_t *param_from, const pj_str_t *param_to, const pj_str_t *param_contact, const pj_str_t *param_call_id, int param_cseq, const pj_str_t *param_text, pjsip_tx_data **p_tdata){ pjsip_uri *target; pjsip_tx_data *tdata; pjsip_from_hdr *from; pjsip_to_hdr *to; pjsip_contact_hdr *contact; pjsip_cseq_hdr *cseq = NULL; /* = NULL, warning in VC6 */ pjsip_cid_hdr *call_id; pj_str_t tmp; pj_status_t status; PJ_USE_EXCEPTION; status = pjsip_endpt_create_tdata(endpt, &tdata); if (status != PJ_SUCCESS) return status; /* Init reference counter to 1. */ pjsip_tx_data_add_ref(tdata); PJ_TRY { /* Request target. */ pj_strdup_with_null(tdata->pool, &tmp, param_target); target = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 0); if (target == NULL) { status = PJSIP_EINVALIDREQURI; goto on_error; } /* From */ from = pjsip_from_hdr_create(tdata->pool); pj_strdup_with_null(tdata->pool, &tmp, param_from); from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (from->uri == NULL) { status = PJSIP_EINVALIDHDR; goto on_error; } pj_create_unique_string(tdata->pool, &from->tag); /* To */ to = pjsip_to_hdr_create(tdata->pool); pj_strdup_with_null(tdata->pool, &tmp, param_to); to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (to->uri == NULL) { status = PJSIP_EINVALIDHDR; goto on_error; } /* Contact. */ if (param_contact) { contact = pjsip_contact_hdr_create(tdata->pool); pj_strdup_with_null(tdata->pool, &tmp, param_contact); contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR); if (contact->uri == NULL) { status = PJSIP_EINVALIDHDR; goto on_error; } } else { contact = NULL; } /* Call-ID */ call_id = pjsip_cid_hdr_create(tdata->pool); if (param_call_id != NULL && param_call_id->slen) pj_strdup(tdata->pool, &call_id->id, param_call_id); else pj_create_unique_string(tdata->pool, &call_id->id); /* CSeq */ cseq = pjsip_cseq_hdr_create(tdata->pool); if (param_cseq >= 0) cseq->cseq = param_cseq; else cseq->cseq = pj_rand() & 0xFFFF; /* Method */ pjsip_method_copy(tdata->pool, &cseq->method, method); /* Create the request. */ init_request_throw( endpt, tdata, &cseq->method, target, from, to, contact, call_id, cseq, param_text); } PJ_CATCH_ANY { status = PJ_ENOMEM; goto on_error; } PJ_END *p_tdata = tdata; return PJ_SUCCESS;on_error: pjsip_tx_data_dec_ref(tdata); return status;}PJ_DEF(pj_status_t)pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt, const pjsip_method *method, const pjsip_uri *param_target, const pjsip_from_hdr *param_from, const pjsip_to_hdr *param_to, const pjsip_contact_hdr *param_contact, const pjsip_cid_hdr *param_call_id, int param_cseq, const pj_str_t *param_text, pjsip_tx_data **p_tdata){ pjsip_uri *target; pjsip_tx_data *tdata; pjsip_from_hdr *from; pjsip_to_hdr *to; pjsip_contact_hdr *contact; pjsip_cid_hdr *call_id; pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */ pj_status_t status; PJ_USE_EXCEPTION; /* Check arguments. */ PJ_ASSERT_RETURN(endpt && method && param_target && param_from && param_to && p_tdata, PJ_EINVAL); /* Create new transmit data. */ status = pjsip_endpt_create_tdata(endpt, &tdata); if (status != PJ_SUCCESS) return status; /* Set initial reference counter to 1. */ pjsip_tx_data_add_ref(tdata); PJ_TRY { /* Duplicate target URI and headers. */ target = pjsip_uri_clone(tdata->pool, param_target); from = pjsip_hdr_clone(tdata->pool, param_from); pjsip_fromto_hdr_set_from(from); to = pjsip_hdr_clone(tdata->pool, param_to); pjsip_fromto_hdr_set_to(to); if (param_contact) contact = pjsip_hdr_clone(tdata->pool, param_contact); else contact = NULL; call_id = pjsip_hdr_clone(tdata->pool, param_call_id); cseq = pjsip_cseq_hdr_create(tdata->pool); if (param_cseq >= 0) cseq->cseq = param_cseq; else cseq->cseq = pj_rand() % 0xFFFF; pjsip_method_copy(tdata->pool, &cseq->method, method); /* Copy headers to the request. */ init_request_throw(endpt, tdata, &cseq->method, target, from, to, contact, call_id, cseq, param_text); } PJ_CATCH_ANY { status = PJ_ENOMEM; goto on_error; } PJ_END; *p_tdata = tdata; return PJ_SUCCESS;on_error: pjsip_tx_data_dec_ref(tdata); return status;}/* * Construct a minimal response message for the received request. */PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt, const pjsip_rx_data *rdata, int st_code, const pj_str_t *st_text, pjsip_tx_data **p_tdata){ pjsip_tx_data *tdata; pjsip_msg *msg, *req_msg; pjsip_hdr *hdr; pjsip_via_hdr *via; pjsip_rr_hdr *rr; pj_status_t status; /* Check arguments. */ PJ_ASSERT_RETURN(endpt && rdata && p_tdata, PJ_EINVAL); /* Check status code. */ PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL); /* rdata must be a request message. */ req_msg = rdata->msg_info.msg; pj_assert(req_msg->type == PJSIP_REQUEST_MSG); /* Request MUST NOT be ACK request! */ PJ_ASSERT_RETURN(req_msg->line.req.method.id != PJSIP_ACK_METHOD, PJ_EINVALIDOP); /* Create a new transmit buffer. */ status = pjsip_endpt_create_tdata( endpt, &tdata); if (status != PJ_SUCCESS) return status; /* Set initial reference count to 1. */ pjsip_tx_data_add_ref(tdata); /* Create new response message. */ tdata->msg = msg = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG); /* Set status code and reason text. */ msg->line.status.code = st_code; if (st_text) pj_strdup(tdata->pool, &msg->line.status.reason, st_text); else msg->line.status.reason = *pjsip_get_status_text(st_code); /* Set TX data attributes. */ tdata->rx_timestamp = rdata->pkt_info.timestamp; /* Copy all the via headers, in order. */ via = rdata->msg_info.via; while (via) { pjsip_msg_add_hdr( msg, pjsip_hdr_clone(tdata->pool, via)); via = via->next; if (via != (void*)&req_msg->hdr) via = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via); else break; } /* Copy all Record-Route headers, in order. */ rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL); while (rr) { pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, rr)); rr = rr->next; if (rr != (void*)&req_msg->hdr) rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, rr); else break; } /* Copy Call-ID header. */ hdr = pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL); pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, hdr)); /* Copy From header. */ hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.from); pjsip_msg_add_hdr( msg, hdr); /* Copy To header. */ hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.to); pjsip_msg_add_hdr( msg, hdr); /* Copy CSeq header. */ hdr = pjsip_hdr_clone(tdata->pool, rdata->msg_info.cseq); pjsip_msg_add_hdr( msg, hdr); /* All done. */ *p_tdata = tdata; PJ_LOG(5,(THIS_FILE, "%s created", pjsip_tx_data_get_info(tdata))); return PJ_SUCCESS;}/* * Construct ACK for 3xx-6xx final response (according to chapter 17.1.1 of * RFC3261). Note that the generation of ACK for 2xx response is different, * and one must not use this function to generate such ACK. */PJ_DEF(pj_status_t) pjsip_endpt_create_ack( pjsip_endpoint *endpt, const pjsip_tx_data *tdata, const pjsip_rx_data *rdata, pjsip_tx_data **ack_tdata){ pjsip_tx_data *ack = NULL; const pjsip_msg *invite_msg; const pjsip_from_hdr *from_hdr; const pjsip_to_hdr *to_hdr; const pjsip_cid_hdr *cid_hdr; const pjsip_cseq_hdr *cseq_hdr; const pjsip_hdr *hdr; pjsip_hdr *via; pjsip_to_hdr *to; pj_status_t status; /* rdata must be a non-2xx final response. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -