blob: 734e8e9bd4e2969e1836ce69b0672a82528a4551 [file] [log] [blame]
Benny Prijono77998ce2007-06-20 10:03:46 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/**
21 * invtester.c
22 *
23 * Send INVITE/re-INVITE without SDP.
24 */
25
26
27/* Include all headers. */
28#include <pjsip.h>
29#include <pjlib-util.h>
30#include <pjlib.h>
31
32#define THIS_FILE "invtester.c"
33
34#define PORT 50060
35#define PORT_STR ":50060"
36#define SAME_BRANCH 0
37#define ACK_HAS_SDP 1
38
39static pjsip_endpoint *sip_endpt;
40static pj_bool_t quit_flag;
41static pjsip_dialog *dlg;
42
43
44/* Callback to handle incoming requests. */
45static void on_tsx_state(pjsip_transaction *tsx, pjsip_event *event);
46
47static pjsip_module mod_app =
48{
49 NULL, NULL, /* prev, next. */
50 { "mod-app", 7 }, /* Name. */
51 -1, /* Id */
52 PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
53 NULL, /* load() */
54 NULL, /* start() */
55 NULL, /* stop() */
56 NULL, /* unload() */
57 NULL, /* on_rx_request() */
58 NULL, /* on_rx_response() */
59 NULL, /* on_tx_request. */
60 NULL, /* on_tx_response() */
61 &on_tsx_state /* on_tsx_state() */
62};
63
64
65/* Worker thread */
66static int worker_thread(void *arg)
67{
68 PJ_UNUSED_ARG(arg);
69
70 while (!quit_flag) {
71 pj_time_val timeout = {0, 500};
72 pjsip_endpt_handle_events(sip_endpt, &timeout);
73 }
74
75 return 0;
76}
77
78/* Send request */
79static void send_request(const pjsip_method *method,
80 int cseq,
81 const pj_str_t *branch,
82 pj_bool_t with_offer)
83{
84 pjsip_tx_data *tdata;
85 pj_str_t dummy_sdp_str =
86 {
87 "v=0\r\n"
88 "o=- 3360842071 3360842071 IN IP4 192.168.0.68\r\n"
89 "s=pjmedia\r\n"
90 "c=IN IP4 192.168.0.68\r\n"
91 "t=0 0\r\n"
92 "m=audio 4000 RTP/AVP 0 101\r\n"
93 "a=rtcp:4001 IN IP4 192.168.0.68\r\n"
94 "a=rtpmap:0 PCMU/8000\r\n"
95 "a=sendrecv\r\n"
96 "a=rtpmap:101 telephone-event/8000\r\n"
97 "a=fmtp:101 0-15\r\n",
98 0
99 };
100 pj_status_t status;
101
102 status = pjsip_dlg_create_request(dlg, method, cseq, &tdata);
103 pj_assert(status == PJ_SUCCESS);
104
105 if (branch) {
106 pjsip_via_hdr *via;
107
108 via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
109 pj_strdup(tdata->pool, &via->branch_param, branch);
110 }
111
112 if (with_offer) {
113 pjsip_msg_body *body;
114 pj_str_t mime_application = { "application", 11};
115 pj_str_t mime_sdp = {"sdp", 3};
116
117
118 dummy_sdp_str.slen = pj_ansi_strlen(dummy_sdp_str.ptr);
119 body = pjsip_msg_body_create(tdata->pool,
120 &mime_application, &mime_sdp,
121 &dummy_sdp_str);
122 tdata->msg->body = body;
123 }
124
125 status = pjsip_dlg_send_request(dlg, tdata, -1, NULL);
126 pj_assert(status == PJ_SUCCESS);
127}
128
129/* Callback to handle incoming requests. */
130static void on_tsx_state(pjsip_transaction *tsx, pjsip_event *event)
131{
132 if (tsx->role == PJSIP_ROLE_UAC) {
133 if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->state == PJSIP_TSX_STATE_TERMINATED) {
134#if SAME_BRANCH
135 send_request(&pjsip_ack_method, tsx->cseq, &tsx->branch, ACK_HAS_SDP);
136#else
137 send_request(&pjsip_ack_method, tsx->cseq, NULL, ACK_HAS_SDP);
138#endif
139 }
140
141 } else {
142 if (event->type == PJSIP_EVENT_RX_MSG && tsx->state == PJSIP_TSX_STATE_TRYING) {
143 pjsip_tx_data *tdata;
144
145 pjsip_dlg_create_response(dlg, event->body.tsx_state.src.rdata,
146 200, NULL, &tdata);
147 pjsip_dlg_send_response(dlg, tsx, tdata);
148 }
149 }
150}
151
152/* make call */
153void make_call(char *uri, pj_bool_t with_offer)
154{
155 pj_str_t local = pj_str("sip:localhost" PORT_STR);
156 pj_str_t remote = pj_str(uri);
157 pj_status_t status;
158
159 status = pjsip_dlg_create_uac(pjsip_ua_instance(),
160 &local, &local, &remote, &remote, &dlg);
161 pj_assert(status == PJ_SUCCESS);
162
163 pjsip_dlg_inc_lock(dlg);
164
165 status = pjsip_dlg_add_usage(dlg, &mod_app, NULL);
166 pj_assert(status == PJ_SUCCESS);
167
168 pjsip_dlg_inc_session(dlg, &mod_app);
169
170 send_request(&pjsip_invite_method, -1, NULL, with_offer);
171
172 pjsip_dlg_dec_lock(dlg);
173}
174
175/* reinvite */
176void reinvite(pj_bool_t with_offer)
177{
178 send_request(&pjsip_invite_method, -1, NULL, with_offer);
179}
180
181/* hangup call */
182void hangup(void)
183{
184 send_request(&pjsip_bye_method, -1, NULL, PJ_FALSE);
185 pjsip_dlg_dec_session(dlg, &mod_app);
186}
187
188/*
189 * main()
190 *
191 */
192int main(int argc, char *argv[])
193{
194 pj_caching_pool cp;
195 pj_thread_t *thread;
196 pj_pool_t *pool;
197 pj_status_t status;
198
199 if (argc != 2) {
200 puts("Error: destination URL needed");
201 return 0;
202 }
203
204 /* Must init PJLIB first: */
205 status = pj_init();
206 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
207
208
209 /* Then init PJLIB-UTIL: */
210 status = pjlib_util_init();
211 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
212
213 /* Must create a pool factory before we can allocate any memory. */
214 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
215
216
217 /* Create the endpoint: */
218 status = pjsip_endpt_create(&cp.factory, "sipstateless",
219 &sip_endpt);
220 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
221
222 /*
223 * Add UDP transport, with hard-coded port
224 */
225 {
226 pj_sockaddr_in addr;
227
228 addr.sin_family = PJ_AF_INET;
229 addr.sin_addr.s_addr = 0;
230 addr.sin_port = pj_htons(PORT);
231
232 status = pjsip_udp_transport_start( sip_endpt, &addr, NULL, 1, NULL);
233 if (status != PJ_SUCCESS) {
234 PJ_LOG(3,(THIS_FILE,
235 "Error starting UDP transport (port in use?)"));
236 return 1;
237 }
238 }
239
240 status = pjsip_tsx_layer_init_module(sip_endpt);
241 pj_assert(status == PJ_SUCCESS);
242
243 status = pjsip_ua_init_module(sip_endpt, NULL);
244 pj_assert(status == PJ_SUCCESS);
245
246 /*
247 * Register our module to receive incoming requests.
248 */
249 status = pjsip_endpt_register_module( sip_endpt, &mod_app);
250 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
251
252 pool = pjsip_endpt_create_pool(sip_endpt, "", 1000, 1000);
253
254 status = pj_thread_create(pool, "", &worker_thread, NULL, 0, 0, &thread);
255 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
256
257 printf("Destination URL: %s\n", argv[1]);
258
259 for (;;) {
260 char line[10];
261
262 fgets(line, sizeof(line), stdin);
263
264 switch (line[0]) {
265 case 'm':
266 make_call(argv[1], PJ_FALSE);
267 break;
268 case 'M':
269 make_call(argv[1], PJ_TRUE);
270 break;
271 case 'r':
272 reinvite(PJ_FALSE);
273 break;
274 case 'R':
275 reinvite(PJ_TRUE);
276 break;
277 case 'h':
278 hangup();
279 break;
280 case 'q':
281 goto on_quit;
282 }
283 }
284
285on_quit:
286 quit_flag = 1;
287 pj_thread_join(thread);
288
289 pjsip_endpt_destroy(sip_endpt);
290 pj_caching_pool_destroy(&cp);
291 pj_shutdown();
292 return 0;
293}
294