1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <pjsip/sip_util.h>
21 #include <pjsip/sip_module.h>
22 #include <pjsip/sip_endpoint.h>
23 #include <pjsip/sip_transaction.h>
24 #include <pjsip/sip_event.h>
25 #include <pjsip/sip_errno.h>
26 #include <pj/assert.h>
27 #include <pj/log.h>
28 #include <pj/pool.h>
29 #include <pj/string.h>
30 
31 struct tsx_data
32 {
33     void *token;
34     void (*cb)(void*, pjsip_event*);
35 };
36 
37 static void mod_util_on_tsx_state(pjsip_transaction*, pjsip_event*);
38 
39 /* This module will be registered in pjsip_endpt.c */
40 
41 pjsip_module mod_stateful_util =
42 {
43     NULL, NULL,			    /* prev, next.			*/
44     { "mod-stateful-util", 17 },    /* Name.				*/
45     -1,				    /* Id				*/
46     PJSIP_MOD_PRIORITY_APPLICATION, /* Priority				*/
47     NULL,			    /* load()				*/
48     NULL,			    /* start()				*/
49     NULL,			    /* stop()				*/
50     NULL,			    /* unload()				*/
51     NULL,			    /* on_rx_request()			*/
52     NULL,			    /* on_rx_response()			*/
53     NULL,			    /* on_tx_request.			*/
54     NULL,			    /* on_tx_response()			*/
55     &mod_util_on_tsx_state,	    /* on_tsx_state()			*/
56 };
57 
mod_util_on_tsx_state(pjsip_transaction * tsx,pjsip_event * event)58 static void mod_util_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event)
59 {
60     struct tsx_data *tsx_data;
61 
62     /* Check if the module has been unregistered (see ticket #1535) and also
63      * verify the event type.
64      */
65     if (mod_stateful_util.id < 0 || event->type != PJSIP_EVENT_TSX_STATE)
66 	return;
67 
68     tsx_data = (struct tsx_data*) tsx->mod_data[mod_stateful_util.id];
69     if (tsx_data == NULL)
70 	return;
71 
72     if (tsx->status_code < 200)
73 	return;
74 
75     /* Call the callback, if any, and prevent the callback to be called again
76      * by clearing the transaction's module_data.
77      */
78     tsx->mod_data[mod_stateful_util.id] = NULL;
79 
80     if (tsx_data->cb) {
81 	(*tsx_data->cb)(tsx_data->token, event);
82     }
83 }
84 
85 
pjsip_endpt_send_request(pjsip_endpoint * endpt,pjsip_tx_data * tdata,pj_int32_t timeout,void * token,pjsip_endpt_send_callback cb)86 PJ_DEF(pj_status_t) pjsip_endpt_send_request(  pjsip_endpoint *endpt,
87 					       pjsip_tx_data *tdata,
88 					       pj_int32_t timeout,
89 					       void *token,
90 					       pjsip_endpt_send_callback cb)
91 {
92     pjsip_transaction *tsx;
93     struct tsx_data *tsx_data;
94     pj_status_t status;
95 
96     PJ_ASSERT_RETURN(endpt && tdata && (timeout==-1 || timeout>0), PJ_EINVAL);
97 
98     /* Check that transaction layer module is registered to endpoint */
99     PJ_ASSERT_RETURN(mod_stateful_util.id != -1, PJ_EINVALIDOP);
100 
101     PJ_UNUSED_ARG(timeout);
102 
103     status = pjsip_tsx_create_uac(&mod_stateful_util, tdata, &tsx);
104     if (status != PJ_SUCCESS) {
105 	pjsip_tx_data_dec_ref(tdata);
106 	return status;
107     }
108 
109     pjsip_tsx_set_transport(tsx, &tdata->tp_sel);
110 
111     tsx_data = PJ_POOL_ALLOC_T(tsx->pool, struct tsx_data);
112     tsx_data->token = token;
113     tsx_data->cb = cb;
114 
115     tsx->mod_data[mod_stateful_util.id] = tsx_data;
116 
117     status = pjsip_tsx_send_msg(tsx, NULL);
118     if (status != PJ_SUCCESS)
119 	pjsip_tx_data_dec_ref(tdata);
120 
121     return status;
122 }
123 
124 
125 /*
126  * Send response statefully.
127  */
pjsip_endpt_respond(pjsip_endpoint * endpt,pjsip_module * tsx_user,pjsip_rx_data * rdata,int st_code,const pj_str_t * st_text,const pjsip_hdr * hdr_list,const pjsip_msg_body * body,pjsip_transaction ** p_tsx)128 PJ_DEF(pj_status_t) pjsip_endpt_respond(  pjsip_endpoint *endpt,
129 					  pjsip_module *tsx_user,
130 					  pjsip_rx_data *rdata,
131 					  int st_code,
132 					  const pj_str_t *st_text,
133 					  const pjsip_hdr *hdr_list,
134 					  const pjsip_msg_body *body,
135 					  pjsip_transaction **p_tsx )
136 {
137     pj_status_t status;
138     pjsip_tx_data *tdata;
139     pjsip_transaction *tsx;
140 
141     /* Validate arguments. */
142     PJ_ASSERT_RETURN(endpt && rdata, PJ_EINVAL);
143 
144     if (p_tsx) *p_tsx = NULL;
145 
146     /* Create response message */
147     status = pjsip_endpt_create_response( endpt, rdata, st_code, st_text,
148 					  &tdata);
149     if (status != PJ_SUCCESS)
150 	return status;
151 
152     /* Add the message headers, if any */
153     if (hdr_list) {
154 	const pjsip_hdr *hdr = hdr_list->next;
155 	while (hdr != hdr_list) {
156 	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)
157 	    		      pjsip_hdr_clone(tdata->pool, hdr) );
158 	    hdr = hdr->next;
159 	}
160     }
161 
162     /* Add the message body, if any. */
163     if (body) {
164 	tdata->msg->body = pjsip_msg_body_clone( tdata->pool, body );
165 	if (tdata->msg->body == NULL) {
166 	    pjsip_tx_data_dec_ref(tdata);
167 	    return status;
168 	}
169     }
170 
171     /* Create UAS transaction. */
172     status = pjsip_tsx_create_uas(tsx_user, rdata, &tsx);
173     if (status != PJ_SUCCESS) {
174 	pjsip_tx_data_dec_ref(tdata);
175 	return status;
176     }
177 
178     /* Feed the request to the transaction. */
179     pjsip_tsx_recv_msg(tsx, rdata);
180 
181     /* Send the message. */
182     status = pjsip_tsx_send_msg(tsx, tdata);
183     if (status != PJ_SUCCESS) {
184 	pjsip_tx_data_dec_ref(tdata);
185     } else if (p_tsx) {
186 	*p_tsx = tsx;
187     }
188 
189     return status;
190 }
191 
192 
193