|
@@ -52,10 +52,16 @@
|
|
|
#include "../../parser/parser_f.h"
|
|
|
#include "../../ut.h"
|
|
|
#include "../../parser/msg_parser.h"
|
|
|
+#include "../../parser/contact/parse_contact.h"
|
|
|
#include "t_msgbuilder.h"
|
|
|
#include "uac.h"
|
|
|
|
|
|
|
|
|
+#define ROUTE_PREFIX "Route: "
|
|
|
+#define ROUTE_PREFIX_LEN (sizeof(ROUTE_PREFIX) - 1)
|
|
|
+
|
|
|
+#define ROUTE_SEPARATOR ", "
|
|
|
+#define ROUTE_SEPARATOR_LEN (sizeof(ROUTE_SEPARATOR) - 1)
|
|
|
|
|
|
#define append_mem_block(_d,_s,_len) \
|
|
|
do{\
|
|
@@ -182,6 +188,304 @@ error:
|
|
|
}
|
|
|
|
|
|
|
|
|
+struct rte {
|
|
|
+ rr_t* ptr;
|
|
|
+ struct rte* next;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static inline void free_rte_list(struct rte* list)
|
|
|
+{
|
|
|
+ struct rte* ptr;
|
|
|
+
|
|
|
+ while(list) {
|
|
|
+ ptr = list;
|
|
|
+ list = list->next;
|
|
|
+ pkg_free(ptr);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static inline int process_routeset(struct sip_msg* msg, str* contact, struct rte** list, str* ruri, str* next_hop)
|
|
|
+{
|
|
|
+ struct hdr_field* ptr;
|
|
|
+ rr_t* p;
|
|
|
+ struct rte* t, *head;
|
|
|
+ struct sip_uri puri;
|
|
|
+
|
|
|
+ ptr = msg->record_route;
|
|
|
+ head = 0;
|
|
|
+ while(ptr) {
|
|
|
+ if (ptr->type == HDR_RECORDROUTE) {
|
|
|
+ if (parse_rr(ptr) < 0) {
|
|
|
+ LOG(L_ERR, "process_routeset: Error while parsing Record-Route header\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ p = (rr_t*)ptr->parsed;
|
|
|
+ while(p) {
|
|
|
+ t = (struct rte*)pkg_malloc(sizeof(struct rte));
|
|
|
+ if (!t) {
|
|
|
+ LOG(L_ERR, "process_routeset: No memory left\n");
|
|
|
+ free_rte_list(head);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ t->ptr = p;
|
|
|
+ t->next = head;
|
|
|
+ head = t;
|
|
|
+ p = p->next;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ptr = ptr->next;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (head) {
|
|
|
+ if (parse_uri(head->ptr->nameaddr.uri.s, head->ptr->nameaddr.uri.len, &puri) == -1) {
|
|
|
+ LOG(L_ERR, "process_routeset: Error while parsing URI\n");
|
|
|
+ free_rte_list(head);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (puri.lr.s) {
|
|
|
+ /* Next hop is loose router */
|
|
|
+ *ruri = *contact;
|
|
|
+ *next_hop = head->ptr->nameaddr.uri;
|
|
|
+ } else {
|
|
|
+ /* Next hop is strict router */
|
|
|
+ *ruri = head->ptr->nameaddr.uri;
|
|
|
+ *next_hop = *ruri;
|
|
|
+ t = head;
|
|
|
+ head = head->next;
|
|
|
+ pkg_free(t);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* No routes */
|
|
|
+ *ruri = *contact;
|
|
|
+ *next_hop = *contact;
|
|
|
+ }
|
|
|
+
|
|
|
+ *list = head;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static inline int calc_routeset_len(struct rte* list, str* contact)
|
|
|
+{
|
|
|
+ struct rte* ptr;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (list || contact) {
|
|
|
+ ret = ROUTE_PREFIX_LEN + CRLF_LEN;
|
|
|
+ } else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ ptr = list;
|
|
|
+ while(ptr) {
|
|
|
+ if (ptr != list) {
|
|
|
+ ret += ROUTE_SEPARATOR_LEN;
|
|
|
+ }
|
|
|
+ ret += ptr->ptr->len;
|
|
|
+ ptr = ptr->next;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (contact) {
|
|
|
+ if (list) ret += ROUTE_SEPARATOR_LEN;
|
|
|
+ ret += 2 + contact->len;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Print the route set
|
|
|
+ */
|
|
|
+static inline char* print_rs(char* p, struct rte* list, str* contact)
|
|
|
+{
|
|
|
+ struct rte* ptr;
|
|
|
+
|
|
|
+ if (list || contact) {
|
|
|
+ memapp(p, ROUTE_PREFIX, ROUTE_PREFIX_LEN);
|
|
|
+ } else {
|
|
|
+ return p;
|
|
|
+ }
|
|
|
+
|
|
|
+ ptr = list;
|
|
|
+ while(ptr) {
|
|
|
+ if (ptr != list) {
|
|
|
+ memapp(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ memapp(p, ptr->ptr->nameaddr.name.s, ptr->ptr->len);
|
|
|
+ ptr = ptr->next;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (contact) {
|
|
|
+ if (list) memapp(p, ROUTE_SEPARATOR, ROUTE_SEPARATOR_LEN);
|
|
|
+ *p++ = '<';
|
|
|
+ append_str(p, *contact);
|
|
|
+ *p++ = '>';
|
|
|
+ }
|
|
|
+
|
|
|
+ memapp(p, CRLF, CRLF_LEN);
|
|
|
+ return p;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Parse Contact header field body and extract URI
|
|
|
+ * Does not parse headers !
|
|
|
+ */
|
|
|
+static inline int get_contact_uri(struct sip_msg* msg, str* uri)
|
|
|
+{
|
|
|
+ contact_t* c;
|
|
|
+
|
|
|
+ uri->len = 0;
|
|
|
+ if (!msg->contact) return 1;
|
|
|
+
|
|
|
+ if (parse_contact(msg->contact) < 0) {
|
|
|
+ LOG(L_ERR, "get_contact_uri: Error while parsing Contact body\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ c = ((contact_body_t*)msg->contact->parsed)->contacts;
|
|
|
+
|
|
|
+ if (!c) {
|
|
|
+ LOG(L_ERR, "get_contact_uri: Empty body or * contact\n");
|
|
|
+ return -2;
|
|
|
+ }
|
|
|
+
|
|
|
+ *uri = c->uri;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The function creates an ACK to 200 OK. Route set will be created
|
|
|
+ * and parsed and next_hop parameter will contain uri the which the
|
|
|
+ * request should be send. The function is used by tm when it generates
|
|
|
+ * local ACK to 200 OK (on behalf of applications using uac
|
|
|
+ */
|
|
|
+char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans, unsigned int branch,
|
|
|
+ str* to, unsigned int *len, str *next_hop)
|
|
|
+{
|
|
|
+ char *req_buf, *p, *via;
|
|
|
+ unsigned int via_len;
|
|
|
+ char branch_buf[MAX_BRANCH_PARAM_LEN];
|
|
|
+ int branch_len;
|
|
|
+ str branch_str;
|
|
|
+ struct hostport hp;
|
|
|
+ struct rte* list;
|
|
|
+ str contact, ruri, *cont;
|
|
|
+ struct socket_info* send_sock;
|
|
|
+ union sockaddr_union to_su;
|
|
|
+
|
|
|
+ if (get_contact_uri(rpl, &contact) < 0) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (process_routeset(rpl, &contact, &list, &ruri, next_hop) < 0) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((contact.s != ruri.s) || (contact.len != ruri.len)) {
|
|
|
+ /* contact != ruri means that the next
|
|
|
+ * hop is a strict router, cont will be non-zero
|
|
|
+ * and print_routeset will append it at the end
|
|
|
+ * of the route set
|
|
|
+ */
|
|
|
+ cont = &contact;
|
|
|
+ } else {
|
|
|
+ /* Next hop is a loose router, nothing to append */
|
|
|
+ cont = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* method, separators, version: "ACK sip:[email protected] SIP/2.0" */
|
|
|
+ *len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
|
|
|
+ *len += ruri.len;
|
|
|
+
|
|
|
+
|
|
|
+ /* via */
|
|
|
+ send_sock = uri2sock(next_hop, &to_su, PROTO_NONE);
|
|
|
+ if (!send_sock) {
|
|
|
+ LOG(L_ERR, "build_dlg_ack: no socket found\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!t_calc_branch(Trans, branch, branch_buf, &branch_len)) goto error;
|
|
|
+ branch_str.s = branch_buf;
|
|
|
+ branch_str.len = branch_len;
|
|
|
+ set_hostport(&hp, 0);
|
|
|
+ via = via_builder(&via_len, send_sock, &branch_str, 0, send_sock->proto, &hp);
|
|
|
+ if (!via) {
|
|
|
+ LOG(L_ERR, "build_dlg_ack: No via header got from builder\n");
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ *len+= via_len;
|
|
|
+
|
|
|
+ /*headers*/
|
|
|
+ *len += Trans->from.len + Trans->callid.len + to->len + Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN;
|
|
|
+
|
|
|
+ /* copy'n'paste Route headers */
|
|
|
+
|
|
|
+ *len += calc_routeset_len(list, cont);
|
|
|
+
|
|
|
+ /* User Agent */
|
|
|
+ if (server_signature) *len += USER_AGENT_LEN + CRLF_LEN;
|
|
|
+ /* Content Length, EoM */
|
|
|
+ *len += CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN;
|
|
|
+
|
|
|
+ req_buf = shm_malloc(*len + 1);
|
|
|
+ if (!req_buf) {
|
|
|
+ LOG(L_ERR, "build_dlg_ack: Cannot allocate memory\n");
|
|
|
+ goto error01;
|
|
|
+ }
|
|
|
+ p = req_buf;
|
|
|
+
|
|
|
+ append_mem_block( p, ACK, ACK_LEN );
|
|
|
+ append_mem_block( p, " ", 1 );
|
|
|
+ append_str(p, ruri);
|
|
|
+ append_mem_block( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);
|
|
|
+
|
|
|
+ /* insert our via */
|
|
|
+ append_mem_block(p, via, via_len);
|
|
|
+
|
|
|
+ /*other headers*/
|
|
|
+ append_str(p, Trans->from);
|
|
|
+ append_str(p, Trans->callid);
|
|
|
+ append_str(p, *to);
|
|
|
+
|
|
|
+ append_str(p, Trans->cseq_n);
|
|
|
+ append_mem_block( p, " ", 1 );
|
|
|
+ append_mem_block( p, ACK, ACK_LEN);
|
|
|
+ append_mem_block(p, CRLF, CRLF_LEN);
|
|
|
+
|
|
|
+ /* Routeset */
|
|
|
+ p = print_rs(p, list, cont);
|
|
|
+
|
|
|
+ /* User Agent header */
|
|
|
+ if (server_signature) {
|
|
|
+ append_mem_block(p, USER_AGENT CRLF, USER_AGENT_LEN + CRLF_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Content Length, EoM */
|
|
|
+ append_mem_block(p, CONTENT_LENGTH "0" CRLF CRLF, CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
|
|
|
+ *p = 0;
|
|
|
+
|
|
|
+ pkg_free(via);
|
|
|
+ free_rte_list(list);
|
|
|
+ return req_buf;
|
|
|
+
|
|
|
+ error01:
|
|
|
+ pkg_free(via);
|
|
|
+ error:
|
|
|
+ free_rte_list(list);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* Convert lenght of body into asciiz
|
|
|
*/
|