[server] / trunk / clients / asterisk / chan_woomera / chan_woomera.c Repository:
ViewVC logotype

Annotation of /trunk/clients/asterisk/chan_woomera/chan_woomera.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (view) (download)

1 : amartin 125 /*
2 :     * Asterisk -- A telephony toolkit for Linux.
3 :     *
4 :     * Woomera Channel Driver
5 : amartin 128 *
6 : amartin 157 * Copyright (C) 05-09
7 :     * Nenad Corbic
8 :     * David Yat Sin
9 : amartin 237 * Antony Martin (Dialogic Corp)
10 :     * John Tarlton (Dialogic Corp)
11 : amartin 157 * Anthony Minessale II
12 : amartin 125 *
13 : amartin 237 * Nenad Corbic <ncorbic@sangoma.com>
14 :     * David Yat Sin <davidy@sangoma.com>
15 :     * Antony Martin <antony.martin@dialogic.com>
16 :     * John Tarlton <john.tarlton@dialogic.com>
17 : amartin 125 * Anthony Minessale II <anthmct@yahoo.com>
18 :     *
19 :     * This program is free software, distributed under the terms of
20 :     * the GNU General Public License
21 :     * =============================================
22 : jtarlton 196 *
23 : jtarlton 261 * v1.54 John Tarlton <john.tarlton@dialogic.com>
24 :     * Jun 12 2009
25 :     * Set dnid channel var on incoming call.
26 :     *
27 :     * v1.53 John Tarlton <john.tarlton@dialogic.com>
28 :     * Jun 11 2009
29 :     * Parse profile name from dial string, falling back to 'default'
30 :     *
31 : amartin 237 * v1.52 John Tarlton <john.tarlton@dialogic.com>
32 : jtarlton 196 * May 28 2009
33 :     * Check for dsp when processing the DTMF header of a MEDIA message.
34 :     *
35 : amartin 237 * v1.51 Antony Martin <antony.martin@dialogic.com>
36 : amartin 157 * Apr 30 2009
37 :     * Added RTP Audio
38 :     *
39 : amartin 237 * v1.50 Nenad Corbic <ncorbic@sangoma.com>
40 :     * Apr 24 2009
41 :     * Bug fix on write socket. Check that write woomera socket failed.
42 :     * This update prevents socket warning messages on call congestion.
43 :     *
44 :     * v1.49 Nenad Corbic <ncorbic@sangoma.com>
45 :     * Apr 08 2009
46 :     * Bug fix on transfer. The owner was not
47 :     * properly updated causing unpredictable behaviour.
48 :     *
49 : amartin 125 * v1.48 Nenad Corbic <ncorbic@sangoma.com>
50 :     * Apr 05 2009
51 :     * Updated locking on pbx_start
52 : amartin 128 *
53 : amartin 125 * v1.47 Nenad Corbic <ncorbic@sangoma.com>
54 :     * Apr 03 2009
55 :     * Added BLOCKER sanity check.
56 :     *
57 :     * v1.46 Nenad Corbic <ncorbic@sangoma.com>
58 :     * Mar 29 2009
59 :     * Added hup_pending stat to call_status
60 :     * Let tech_hangup destroy softhungup channel
61 :     *
62 :     * v1.45 Nenad Corbic <ncorbic@sangoma.com>
63 :     * Mar 27 2009
64 :     * Major updates on channel locking.
65 :     * This update fixes potential crashing issues
66 : amartin 128 * under heavy load. Stress tested in 500+ call
67 :     * environment.
68 : amartin 125 *
69 :     * v1.44 Nenad Corbic <ncorbic@sangoma.com>
70 :     * Mar 55 2009
71 : amartin 128 * Updated woomera channel locking using
72 : amartin 125 * DEADLOCK_AVOIDANCE. Fixed RDNIS transmission issue.
73 :     *
74 :     * v1.43 David Yat Sin <dyatsin@sangoma.com>
75 :     * Mar 01 2009
76 :     * Fix to support Callweaver svn trunk
77 : amartin 128 *
78 : amartin 125 * v1.42 David Yat Sin <dyatsin@sangoma.com>
79 :     * Feb 25 2009
80 :     * Fix to support Callweaver svn trunk
81 :     *
82 :     * v1.41 Nenad Corbic <ncorbic@sangoma.com>
83 :     * Jan 29 2008
84 :     * Bug introduced in 1.40 if WOOMERA uil1p parameter
85 :     * was not there transcoding was misconfigued.
86 :     *
87 :     * v1.40 Nenad Corbic <ncorbic@sangoma.com>
88 :     * Jan 26 2008
89 :     * Call Bearer Capability Feature
90 :     * Updated for Callweaver
91 : amartin 128 *
92 : amartin 125 * v1.39 David Yat Sin <dyatsin@sangoma.com>
93 :     * Dec 19 2008
94 :     * Support for Asterisk 1.6
95 :     *
96 :     * v1.38 David Yat Sin <dyatsin@sangoma.com>
97 :     * Dec 05 2008
98 :     * Support for fax_detect using Asterisk software DSP
99 :     *
100 :     * v1.37 Nenad Corbic <ncorbic@sangoma.com>
101 :     * Nov 26 2008
102 :     * Bug Fix: tech_read try again now checks for hangup
103 :     *
104 :     * v1.36 David Yat Sin <dyatsin@sangoma.com>
105 :     * Oct 14 2008
106 :     * Bug Fix: Call hangup on call park
107 :     *
108 :     * v1.35 Nenad Corbic <ncorbic@sangoma.com>
109 :     * Jul 23 2008
110 :     * Bug Fix: Check for cid_name.
111 :     *
112 :     * v1.34 Nenad Corbic <ncorbic@sangoma.com>
113 :     * Jul 23 2008
114 :     * Added udp tagging and rx/tx sync options for
115 :     * voice streams debugging. Not for production.
116 :     *
117 :     * v1.33 Nenad Corbic <ncorbic@sangoma.com>
118 :     * Jul 18 2008
119 :     * Added UDP Sequencing to check for dropped frames
120 :     * Should only be used for debugging.
121 :     *
122 :     * v1.32 David Yat Sin <davidy@sangoma.com>
123 :     * Jun 3 2008
124 :     * Updated for callweaver v1.2.0
125 : amartin 128 *
126 : amartin 125 * v1.31 Nenad Corbic <ncorbic@sangoma.com>
127 :     * v1.30 Nenad Corbic <ncorbic@sangoma.com>
128 :     * Jun 2 2008
129 :     * Added AST_CTONROL_RING event on outgoing call.
130 :     * Updated for CallWeaver 1.2 SVN
131 :     *
132 :     * v1.29 David Yat Sin <davidy@sangoma.com>
133 :     * Apr 30 2008
134 :     * Added AST_CONTROL_SRCUPDATE in tech_indicate
135 :     *
136 :     * v1.29 David Yat Sin <davidy@sangoma.com>
137 :     * April 29 2008
138 :     * Support for HW DTMF
139 :     *
140 :     * v1.28 David Yat Sin <davidy@sangoma.com>
141 :     * Apr 29 2008
142 :     * Fix for compilation issues with Callweaver v1.99
143 :     *
144 :     * v1.27 David Yat Sin <davidy@sangoma.com>
145 :     * Feb 13 2008
146 : amartin 128 * Fix for ast_channel type not defined on
147 : amartin 125 * outgoing calls, causing PHP agi scripts
148 :     * to fail
149 :     *
150 :     * v1.26 Nenad Corbic <ncorbic@sangoma.com>
151 :     * Feb 13 2008
152 :     * Compilation Update for callweaver 1.2-rc5
153 :     *
154 :     * v1.25 Nenad Corbic <ncorbic@sangoma.com>
155 :     * Feb 06 2008
156 :     * Bug fix in woomera message declaration
157 :     * Possible memory overflow
158 :     *
159 :     * v1.24 Nenad Corbic <ncorbic@sangoma.com>
160 :     * Jan 23 2008
161 :     * Removed LISTEN on every woomera channel. Listen
162 :     * only on master. Fixed jitterbuffer support on AST1.4
163 :     *
164 :     * v1.23 Nenad Corbic <ncorbic@sangoma.com>
165 :     * Jan 22 2008
166 :     * Implemented Music on Hold.
167 :     *
168 :     * v1.22 David Yat Sin <davidy@sangoma.com>
169 :     * Jan 11 2008
170 : amartin 128 * rxgain and txgain configuration parameters
171 :     * are ignored if coding is not specified in
172 :     * woomera.conf
173 : amartin 125 *
174 :     * v1.21 David Yat Sin <davidy@sangoma.com>
175 :     * Dec 27 2007
176 : amartin 128 * Support for language
177 : amartin 125 *
178 :     * v1.20 David Yat Sin <davidy@sangoma.com>
179 :     * Dec 20 2007
180 :     * Support for call confirmation
181 :     * Support for default context
182 :     *
183 :     * v1.19 Nenad Corbic <ncorbic@sangoma.com>
184 :     * Nov 30 2007
185 :     * Updated for latest CallWeaver
186 :     * Updated smgversion update on master socket
187 :     * restart.
188 :     *
189 :     * v1.18 Nenad Corbic <ncorbic@sangoma.com>
190 :     * Updated Channel-Name on outbound call
191 :     * Check queued events on ABORT
192 :     * Major Unit Testing done
193 :     * Ability to change chan name from Makefile
194 :     *
195 :     * v1.17 Nenad Corbic <ncorbic@sangoma.com>
196 :     * Updates for Asterisk 1.4
197 :     * Updated the release causes
198 :     * Updated for tech_indication
199 : amartin 128 *
200 : amartin 125 * v1.16 Nenad Corbic <ncorbic@sangoma.com>
201 :     * Added support for Asterisk 1.4
202 :     * Updated support for Callweaver
203 :     *
204 :     * v1.15 Nenad Corbic <ncorbic@sangoma.com>
205 : amartin 128 * Added PRI_CAUSE and Q931-Cause-Code
206 : amartin 125 * in woomera protocol.
207 :     *
208 :     * v1.14 Nenad Corbic <ncorbic@sangoma.com>
209 :     * Updated for session support
210 :     *
211 :     * v1.13 Nenad Corbic <ncorbic@sangoma.com>
212 :     * Added CallWeaver Support
213 :     * |->(thanks to Andre Schwaller)
214 : amartin 128 * Updated codec negotiation for
215 : amartin 125 * mutliple profiles.
216 :     *
217 :     * v1.12 Nenad Corbic <ncorbic@sangoma.com>
218 :     * Updated DTMF locking
219 :     *
220 :     * v1.11 Nenad Corbic <ncorbic@sangoma.com>
221 : amartin 128 * Updated multiple profiles
222 : amartin 125 * Updated Dialect for OPAL Woomera
223 :     * Added call logging/debugging
224 :     *
225 :     * v1.10 Nenad Corbic <ncorbic@sangoma.com>
226 : amartin 128 * Bug fix in incoming hangup
227 :     *
228 : amartin 125 * v1.9 Nenad Corbic <ncorbic@sangoma.com>
229 :     * Fixed remote asterisk/woomera
230 :     * setup.
231 :     *
232 :     * v1.8 Nenad Corbic <ncorbic@sangoma.com>
233 :     * Added Woomera OPAL dialect.
234 :     * Code cleanup.
235 :     * Added cli call_status
236 :     *
237 :     * v1.7 Nenad Corbic <ncorbic@sangoma.com>
238 :     * Added smgdebug to enable smg debugging
239 :     * Added rdnis
240 :     *
241 :     * v1.6 Nenad Corbic <ncorbic@sangoma.com>
242 : amartin 128 * Added incoming trunk group context
243 : amartin 125 * The trunk number will be added to the
244 : amartin 128 * profile context name.
245 : amartin 125 * Added presentation feature.
246 :     *
247 :     * v1.5 Nenad Corbic <ncorbic@sangoma.com>
248 :     * Use only ALAW and MLAW not SLIN.
249 :     * This reduces the load quite a bit.
250 :     * Autodetect Format from HELLO Message.
251 :     * RxTx Gain supported in woomera.conf as well
252 :     * from CLI.
253 :     */
254 :    
255 :    
256 :     #if defined(CALLWEAVER) && defined(HAVE_CONFIG_H)
257 :     #include "confdefs.h"
258 :     #endif
259 :    
260 :     #include <stdio.h>
261 :     #include <string.h>
262 :     #include <stdlib.h>
263 :     #include <sys/types.h>
264 :     #include <sys/socket.h>
265 :     #include <netinet/in.h>
266 :     #include <arpa/inet.h>
267 :     #include <netdb.h>
268 :     #include <stdio.h>
269 :     #include <unistd.h>
270 :     #include <fcntl.h>
271 :     #include <signal.h>
272 :     #include <math.h>
273 :     #include <netinet/tcp.h>
274 :    
275 :    
276 :     #ifndef CALLWEAVER
277 :    
278 :    
279 :     #include "asterisk.h"
280 :     #include "asterisk/sched.h"
281 :     #include "asterisk/astobj.h"
282 :     #include "asterisk/lock.h"
283 :     #if defined(AST16)
284 :     #include "asterisk/linkedlists.h"
285 :     #include "asterisk/channel.h"
286 :     #endif
287 :     #if !defined (AST14) && !defined (AST16)
288 :     #include "asterisk/options.h"
289 :     #endif
290 :     #include "asterisk/manager.h"
291 :     #include "asterisk/pbx.h"
292 :     #include "asterisk/cli.h"
293 :     #include "asterisk/logger.h"
294 :     #include "asterisk/frame.h"
295 :     #include "asterisk/config.h"
296 :     #include "asterisk/module.h"
297 :     #include "asterisk/lock.h"
298 :     #include "asterisk/translate.h"
299 :     #include "asterisk/causes.h"
300 :     #include "asterisk/dsp.h"
301 :     #include "asterisk/musiconhold.h"
302 :     #include "asterisk/transcap.h"
303 : amartin 128 #include "asterisk/sched.h"
304 :     #include "asterisk/io.h"
305 :     #include "asterisk/rtp.h"
306 : amartin 125
307 :     ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.48 $")
308 :    
309 :     #else
310 :    
311 :     #include "callweaver.h"
312 :     #include "callweaver/sched.h"
313 :     #ifdef CALLWEAVER_CWOBJ
314 :     #include "callweaver/cwobj.h"
315 :     #else
316 :     #include "callweaver/astobj.h"
317 :     #endif
318 :     #include "callweaver/lock.h"
319 :     #include "callweaver/manager.h"
320 :     #include "callweaver/options.h"
321 :     #include "callweaver/channel.h"
322 :     #include "callweaver/pbx.h"
323 :     #include "callweaver/cli.h"
324 :     #include "callweaver/logger.h"
325 :     #include "callweaver/frame.h"
326 :     #include "callweaver/config.h"
327 :     #include "callweaver/module.h"
328 :     #include "callweaver/lock.h"
329 :     #include "callweaver/translate.h"
330 :     #include "callweaver/causes.h"
331 :     #include "callweaver/dsp.h"
332 :     #include "callweaver/transcap.h"
333 :     #include "callweaver.h"
334 :     #include "confdefs.h"
335 :    
336 :    
337 :     #ifdef CALLWEAVER_CWOBJ
338 :     #define ASTOBJ_COMPONENTS CWOBJ_COMPONENTS
339 :     #define ASTOBJ_CONTAINER_INIT CWOBJ_CONTAINER_INIT
340 :     #define ASTOBJ_CONTAINER_COMPONENTS CWOBJ_CONTAINER_COMPONENTS
341 :     #define ASTOBJ_CONTAINER_DESTROY CWOBJ_CONTAINER_DESTROY
342 :     #define ASTOBJ_CONTAINER_DESTROYALL CWOBJ_CONTAINER_DESTROYALL
343 :     #define ASTOBJ_UNLOCK CWOBJ_UNLOCK
344 :     #define ASTOBJ_RDLOCK CWOBJ_RDLOCK
345 :     #define ASTOBJ_CONTAINER_UNLINK CWOBJ_CONTAINER_UNLINK
346 :     #define ASTOBJ_CONTAINER_TRAVERSE CWOBJ_CONTAINER_TRAVERSE
347 :     #define ASTOBJ_CONTAINER_WRLOCK CWOBJ_CONTAINER_WRLOCK
348 :     #define ASTOBJ_CONTAINER_UNLOCK CWOBJ_CONTAINER_UNLOCK
349 :     #define ASTOBJ_CONTAINER_FIND CWOBJ_CONTAINER_FIND
350 :     #define ASTOBJ_CONTAINER_LINK CWOBJ_CONTAINER_LINK
351 :     #endif
352 :    
353 :    
354 : amartin 128 #if defined (CW_CONTROL_RINGING)
355 : amartin 125 #define CALLWEAVER_19 1
356 :     #endif
357 :    
358 :     CALLWEAVER_FILE_VERSION(__FILE__, "$Revision: 1.48 $")
359 :    
360 :     #if defined(DSP_FEATURE_FAX_CNG_DETECT)
361 :     #undef DSP_FEATURE_FAX_DETECT
362 :     #define DSP_FEATURE_FAX_DETECT DSP_FEATURE_FAX_CNG_DETECT
363 :     #endif
364 :    
365 :     #if !defined(macrocontext)
366 :     #undef macrocontext
367 :     #define macrocontext proc_context
368 :     #endif
369 :    
370 :     #if !defined(ast_tv)
371 :     #undef ast_tv
372 :     #define ast_tv opbx_tv
373 :     #endif
374 :    
375 :     /* CALLWEAVER v1.9 and later */
376 : amartin 128 #if defined (CALLWEAVER_19)
377 : amartin 125 #define ast_transfercapability2str cw_transfercapability2str
378 :     #define ast_config cw_config
379 :     #define AST_CONTROL_RINGING CW_CONTROL_RINGING
380 :     #define AST_CONTROL_BUSY CW_CONTROL_BUSY
381 :     #define AST_CONTROL_CONGESTION CW_CONTROL_CONGESTION
382 :     #define AST_CONTROL_PROCEEDING CW_CONTROL_PROCEEDING
383 :     #define AST_CONTROL_PROGRESS CW_CONTROL_PROGRESS
384 :     #define AST_CONTROL_HOLD CW_CONTROL_HOLD
385 :     #define AST_CONTROL_UNHOLD CW_CONTROL_UNHOLD
386 :     #define AST_CONTROL_VIDUPDATE CW_CONTROL_VIDUPDATE
387 :    
388 :     #define AST_TRANS_CAP_SPEECH CW_TRANS_CAP_SPEECH
389 :     #define AST_TRANS_CAP_3_1K_AUDIO CW_TRANS_CAP_3_1K_AUDIO
390 :     #define AST_TRANS_CAP_DIGITAL CW_TRANS_CAP_DIGITAL
391 :     #define AST_TRANS_CAP_RESTRICTED_DIGITAL CW_TRANS_CAP_RESTRICTED_DIGITAL
392 :     #define AST_TRANS_CAP_DIGITAL_W_TONES CW_TRANS_CAP_DIGITAL_W_TONES
393 :     #define AST_TRANS_CAP_VIDEO CW_TRANS_CAP_VIDEO
394 :    
395 :     #define AST_FORMAT_ADPCM CW_FORMAT_DVI_ADPCM
396 :    
397 :     #ifndef LOG_NOTICE
398 :     #define LOG_NOTICE CW_LOG_NOTICE
399 :     #endif
400 :    
401 :     #ifndef LOG_DEBUG
402 :     #define LOG_DEBUG CW_LOG_DEBUG
403 :     #endif
404 :    
405 :     #ifndef LOG_ERROR
406 :     #define LOG_ERROR CW_LOG_ERROR
407 :     #endif
408 :    
409 :     #ifndef LOG_WARNING
410 :     #define LOG_WARNING CW_LOG_WARNING
411 :     #endif
412 :    
413 :     #define AST_FORMAT_SLINEAR CW_FORMAT_SLINEAR
414 :     #define AST_FORMAT_ULAW CW_FORMAT_ULAW
415 :     #define AST_FORMAT_ALAW CW_FORMAT_ALAW
416 :     #define ast_mutex_t cw_mutex_t
417 :     #define ast_frame cw_frame
418 :     #define ast_verbose cw_verbose
419 :     #define AST_FRIENDLY_OFFSET CW_FRIENDLY_OFFSET
420 :     #define AST_MUTEX_DEFINE_STATIC CW_MUTEX_DEFINE_STATIC
421 :     #define AST_CONTROL_PROGRESS CW_CONTROL_PROGRESS
422 :     #define AST_CAUSE_REQUESTED_CHAN_UNAVAIL CW_CAUSE_REQUESTED_CHAN_UNAVAIL
423 :     #define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION CW_CAUSE_NORMAL_CIRCUIT_CONGESTION
424 :     #define AST_CAUSE_USER_BUSY CW_CAUSE_USER_BUSY
425 :     #define AST_CAUSE_NO_ANSWER CW_CAUSE_NO_ANSWER
426 :     #define AST_CAUSE_NORMAL_CLEARING CW_CAUSE_NORMAL_CLEARING
427 :     #define AST_SOFTHANGUP_EXPLICIT CW_SOFTHANGUP_EXPLICIT
428 :     #define AST_SOFTHANGUP_DEV CW_SOFTHANGUP_DEV
429 :     #define AST_CAUSE_NORMAL_CLEARING CW_CAUSE_NORMAL_CLEARING
430 :     #define AST_FRAME_DTMF CW_FRAME_DTMF
431 :     #define AST_FRAME_CONTROL CW_FRAME_CONTROL
432 :     #define AST_CONTROL_ANSWER CW_CONTROL_ANSWER
433 :     #define AST_STATE_UP CW_STATE_UP
434 :     #define AST_STATE_RINGING CW_STATE_RINGING
435 :     #define AST_STATE_DOWN CW_STATE_DOWN
436 :     #define AST_FLAGS_ALL CW_FLAGS_ALL
437 :     #define AST_FRAME_VOICE CW_FRAME_VOICE
438 :     #define ASTERISK_GPL_KEY 0
439 :     #define ast_channel_tech cw_channel_tech
440 :     #define ast_test_flag cw_test_flag
441 :     #define ast_queue_frame cw_queue_frame
442 :     #define ast_frdup cw_frdup
443 :     #define ast_channel cw_channel
444 :     #define ast_exists_extension cw_exists_extension
445 :     #define ast_hostent cw_hostent
446 :     #define ast_clear_flag cw_clear_flag
447 :     #define ast_log cw_log
448 :     #define ast_set_flag cw_set_flag
449 :     #define ast_copy_string cw_copy_string
450 :     #define ast_set_flag cw_set_flag
451 :     #define ast_set2_flag cw_set2_flag
452 :     #define ast_setstate cw_setstate
453 :     #define ast_test_flag cw_test_flag
454 :     #define ast_softhangup cw_softhangup
455 :     #define ast_softhangup_nolock cw_softhangup_nolock
456 :     #define ast_true cw_true
457 :     #define ast_false cw_false
458 :     #define ast_strlen_zero cw_strlen_zero
459 :     #define ast_exists_extension cw_exists_extension
460 :     #define ast_frame cw_frame
461 :     #define ast_jb_conf cw_jb_conf
462 :     #define ast_carefulwrite cw_carefulwrite
463 :     #define ast_channel_unregister cw_channel_unregister
464 :     #define ast_cli cw_cli
465 :     #define ast_cli_register cw_cli_register
466 :     #define ast_cli_unregister cw_cli_unregister
467 :     #define ast_jb_read_conf cw_jb_read_conf
468 :     #define ast_mutex_destroy cw_mutex_destroy
469 :     #define ast_mutex_init cw_mutex_init
470 :     #define ast_mutex_lock cw_mutex_lock
471 :     #define ast_mutex_unlock cw_mutex_unlock
472 :     #define ast_mutex_t cw_mutex_t
473 :     #define ast_queue_control cw_queue_control
474 :     #define ast_queue_frame cw_queue_frame
475 :     #define ast_queue_hangup cw_queue_hangup
476 :     #define ast_set_callerid cw_set_callerid
477 :     #define ast_variable cw_variable
478 :     #define ast_pthread_create cw_pthread_create
479 :     #define ast_cli_entry cw_cli_entry
480 :     #define ast_channel_register cw_channel_register
481 :     #define ast_config_load cw_config_load
482 :     #define ast_config_destroy cw_config_destroy
483 :     #define ast_category_browse cw_category_browse
484 :     #define ast_variable_browse cw_variable_browse
485 :     #define ast_gethostbyname cw_gethostbyname
486 :     #define ast_channel_alloc cw_channel_alloc
487 :     #define ast_dsp_new cw_dsp_new
488 :     #define ast_dsp cw_dsp
489 :     #define ast_dsp_set_features cw_dsp_set_features
490 :     #define ast_dsp_digitmode cw_dsp_digitmode
491 :     #define ast_dsp_set_call_progress_zone cw_dsp_set_call_progress_zone
492 :     #define ast_dsp_set_busy_count cw_dsp_set_busy_count
493 :     #define ast_dsp_set_busy_pattern cw_dsp_set_busy_pattern
494 :     #define ast_dsp_process cw_dsp_process
495 :     #define ast_strdupa cw_strdupa
496 :     #define ast_mutex_trylock cw_mutex_trylock
497 :     #define ast_cause2str cw_cause2str
498 :     #define ast_pbx_start cw_pbx_start
499 :     #define ast_hangup cw_hangup
500 :     #if !defined(ast_async_goto)
501 : amartin 128 #undef ast_async_goto
502 : amartin 125 #define ast_async_goto cw_async_goto_n
503 :     #endif
504 :     #else /* CALLWEAVER prior to v1.9 */
505 :    
506 :     #define ast_transfercapability2str opbx_transfercapability2str
507 :    
508 :     #define ast_config opbx_config
509 :     #define AST_CONTROL_RINGING OPBX_CONTROL_RINGING
510 :     #define AST_CONTROL_BUSY OPBX_CONTROL_BUSY
511 :     #define AST_CONTROL_CONGESTION OPBX_CONTROL_CONGESTION
512 :     #define AST_CONTROL_PROCEEDING OPBX_CONTROL_PROCEEDING
513 :     #define AST_CONTROL_PROGRESS OPBX_CONTROL_PROGRESS
514 :     #define AST_CONTROL_HOLD OPBX_CONTROL_HOLD
515 :     #define AST_CONTROL_UNHOLD OPBX_CONTROL_UNHOLD
516 :     #define AST_CONTROL_VIDUPDATE OPBX_CONTROL_VIDUPDATE
517 :    
518 :     #define AST_FORMAT_SLINEAR OPBX_FORMAT_SLINEAR
519 :     #define AST_FORMAT_ULAW OPBX_FORMAT_ULAW
520 :     #define AST_FORMAT_ALAW OPBX_FORMAT_ALAW
521 :    
522 :     #define AST_TRANS_CAP_SPEECH OPBX_TRANS_CAP_SPEECH
523 :     #define AST_TRANS_CAP_3_1K_AUDIO OPBX_TRANS_CAP_3_1K_AUDIO
524 :     #define AST_TRANS_CAP_DIGITAL OPBX_TRANS_CAP_DIGITAL
525 :     #define AST_TRANS_CAP_RESTRICTED_DIGITAL OPBX_TRANS_CAP_RESTRICTED_DIGITAL
526 :     #define AST_TRANS_CAP_DIGITAL_W_TONES OPBX_TRANS_CAP_DIGITAL_W_TONES
527 :     #define AST_TRANS_CAP_VIDEO OPBX_TRANS_CAP_VIDEO
528 : amartin 128
529 : amartin 125 #ifndef LOG_NOTICE
530 :     #define LOG_NOTICE OPBX_LOG_NOTICE
531 :     #endif
532 :    
533 :     #ifndef LOG_DEBUG
534 :     #define LOG_DEBUG OPBX_LOG_DEBUG
535 :     #endif
536 :    
537 :     #ifndef LOG_ERROR
538 :     #define LOG_ERROR OPBX_LOG_ERROR
539 :     #endif
540 :    
541 :     #ifndef LOG_WARNING
542 :     #define LOG_WARNING OPBX_LOG_WARNING
543 :     #endif
544 :    
545 :    
546 :     #define AST_FORMAT_SLINEAR OPBX_FORMAT_SLINEAR
547 :     #define AST_FORMAT_ULAW OPBX_FORMAT_ULAW
548 :     #define AST_FORMAT_ALAW OPBX_FORMAT_ALAW
549 :     #define AST_FORMAT_ADPCM OPBX_FORMAT_DVI_ADPCM
550 :    
551 :     #define ast_mutex_t opbx_mutex_t
552 :     #define ast_frame opbx_frame
553 :     #define ast_verbose opbx_verbose
554 :     #define AST_FRIENDLY_OFFSET OPBX_FRIENDLY_OFFSET
555 :     #define AST_MUTEX_DEFINE_STATIC OPBX_MUTEX_DEFINE_STATIC
556 :     #define AST_CONTROL_PROGRESS OPBX_CONTROL_PROGRESS
557 :     #define AST_CAUSE_REQUESTED_CHAN_UNAVAIL OPBX_CAUSE_REQUESTED_CHAN_UNAVAIL
558 :     #define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION OPBX_CAUSE_NORMAL_CIRCUIT_CONGESTION
559 :     #define AST_CAUSE_USER_BUSY OPBX_CAUSE_USER_BUSY
560 :     #define AST_CAUSE_NO_ANSWER OPBX_CAUSE_NO_ANSWER
561 :     #define AST_CAUSE_NORMAL_CLEARING OPBX_CAUSE_NORMAL_CLEARING
562 :     #define AST_SOFTHANGUP_EXPLICIT OPBX_SOFTHANGUP_EXPLICIT
563 :     #define AST_SOFTHANGUP_DEV OPBX_SOFTHANGUP_DEV
564 :     #define AST_CAUSE_NORMAL_CLEARING OPBX_CAUSE_NORMAL_CLEARING
565 :     #define AST_FRAME_DTMF OPBX_FRAME_DTMF
566 :     #define AST_FRAME_CONTROL OPBX_FRAME_CONTROL
567 :     #define AST_CONTROL_ANSWER OPBX_CONTROL_ANSWER
568 :     #define AST_STATE_UP OPBX_STATE_UP
569 :     #define AST_STATE_RINGING OPBX_STATE_RINGING
570 :     #define AST_STATE_DOWN OPBX_STATE_DOWN
571 :     #define AST_FLAGS_ALL OPBX_FLAGS_ALL
572 :     #define AST_FRAME_VOICE OPBX_FRAME_VOICE
573 :     #define AST_FRAME_NULL OPBX_FRAME_NULL
574 :     #define ASTERISK_GPL_KEY 0
575 :     #define ast_channel_tech opbx_channel_tech
576 :     #define ast_test_flag opbx_test_flag
577 :     #define ast_queue_frame opbx_queue_frame
578 :     #define ast_frdup opbx_frdup
579 :     #define ast_channel opbx_channel
580 :     #define ast_exists_extension opbx_exists_extension
581 :     #define ast_hostent opbx_hostent
582 :     #define ast_clear_flag opbx_clear_flag
583 :     #define ast_log opbx_log
584 :     #define ast_set_flag opbx_set_flag
585 :     #define ast_copy_string opbx_copy_string
586 :     #define ast_set_flag opbx_set_flag
587 :     #define ast_set2_flag opbx_set2_flag
588 :     #define ast_setstate opbx_setstate
589 :     #define ast_test_flag opbx_test_flag
590 :     #define ast_softhangup opbx_softhangup
591 :     #define ast_softhangup_nolock opbx_softhangup_nolock
592 :     #define ast_true opbx_true
593 :     #define ast_false opbx_false
594 :     #define ast_strlen_zero opbx_strlen_zero
595 :     #define ast_exists_extension opbx_exists_extension
596 :     #define ast_frame opbx_frame
597 :     #define ast_jb_conf opbx_jb_conf
598 :     #define ast_carefulwrite opbx_carefulwrite
599 :     #define ast_channel_unregister opbx_channel_unregister
600 :     #define ast_cli opbx_cli
601 :     #define ast_cli_register opbx_cli_register
602 :     #define ast_cli_unregister opbx_cli_unregister
603 :     #define ast_jb_read_conf opbx_jb_read_conf
604 :     #define ast_mutex_destroy opbx_mutex_destroy
605 :     #define ast_mutex_init opbx_mutex_init
606 :     #define ast_mutex_lock opbx_mutex_lock
607 :     #define ast_mutex_unlock opbx_mutex_unlock
608 :     #define ast_mutex_t opbx_mutex_t
609 :     #define ast_queue_control opbx_queue_control
610 :     #define ast_queue_frame opbx_queue_frame
611 :     #define ast_queue_hangup opbx_queue_hangup
612 :     #define ast_set_callerid opbx_set_callerid
613 :     #define ast_variable opbx_variable
614 :     #define ast_pthread_create opbx_pthread_create
615 :     #define ast_cli_entry opbx_cli_entry
616 :     #define ast_channel_register opbx_channel_register
617 :     #define ast_config_load opbx_config_load
618 :     #define ast_config_destroy opbx_config_destroy
619 :     #define ast_category_browse opbx_category_browse
620 :     #define ast_variable_browse opbx_variable_browse
621 :     #define ast_gethostbyname opbx_gethostbyname
622 :     #define ast_channel_alloc opbx_channel_alloc
623 :     #define ast_dsp_new opbx_dsp_new
624 :     #define ast_dsp opbx_dsp
625 :     #define ast_dsp_set_features opbx_dsp_set_features
626 :     #define ast_dsp_digitmode opbx_dsp_digitmode
627 :     #define ast_dsp_set_call_progress_zone opbx_dsp_set_call_progress_zone
628 :     #define ast_dsp_set_busy_count opbx_dsp_set_busy_count
629 :     #define ast_dsp_set_busy_pattern opbx_dsp_set_busy_pattern
630 :     #define ast_dsp_process opbx_dsp_process
631 :     #define ast_strdupa opbx_strdupa
632 :     #define ast_mutex_trylock opbx_mutex_trylock
633 :     #define ast_cause2str opbx_cause2str
634 :     #define ast_pbx_start opbx_pbx_start
635 :     #define ast_hangup opbx_hangup
636 :    
637 :     #if !defined(ast_async_goto)
638 : amartin 128 #undef ast_async_goto
639 : amartin 125 #define ast_async_goto opbx_async_goto
640 :     #endif
641 : amartin 128
642 : amartin 125 #endif /* CALLWEAVER_19 */
643 :     #endif
644 :    
645 :     #include "g711.h"
646 :     #include <errno.h>
647 :    
648 : amartin 130 //#define USE_TECH_INDICATE
649 : amartin 125 #ifdef USE_TECH_INDICATE
650 :     #define MEDIA_ANSWER "MEDIA"
651 :     #else
652 :     #define MEDIA_ANSWER "ACCEPT"
653 :     #endif
654 :    
655 :     #define USE_ANSWER 1
656 : amartin 128
657 : amartin 125 #ifndef ast_free
658 :     #define ast_free(x) free(x)
659 :     #define ast_malloc(x) malloc(x)
660 :     #endif
661 :    
662 :    
663 :     extern int option_verbose;
664 :    
665 : jtarlton 280 #define WOOMERA_VERSION "v1.54"
666 : amartin 125 #ifndef WOOMERA_CHAN_NAME
667 : amartin 128 #define WOOMERA_CHAN_NAME "WOOMERA"
668 : amartin 125 #endif
669 :    
670 : amartin 231 #if 1
671 :     #undef WOOMERA_PRINTF_DEBUG
672 :     #else
673 :     #warning "WOOMERA_PRINTF_DEBUG defined"
674 :     #define WOOMERA_PRINTF_DEBUG
675 :     #endif
676 :     #ifdef WOOMERA_PRINTF_DEBUG
677 :     #define woomera_printf(a,b,c,msg...) __woomera_printf(__FUNCTION__,__LINE__,a,b,c,##msg)
678 :     #else
679 :     #define woomera_printf(a,b,c,msg...) __woomera_printf(a,b,c,##msg)
680 :     #endif
681 :    
682 : amartin 125 static int tech_count = 0;
683 :    
684 :     static const char desc[] = "Woomera Channel Driver";
685 :     //static const char type[] = "WOOMERA";
686 :     static const char tdesc[] = "Woomera Channel Driver";
687 :     static char configfile[] = "woomera.conf";
688 :    
689 : jtarlton 280 static char svrversion_init = 0;
690 : jtarlton 255 static char svrversion[100] = "N/A";
691 :    
692 : amartin 125 static char mohinterpret[MAX_MUSICCLASS] = "default";
693 :     static char mohsuggest[MAX_MUSICCLASS] = "";
694 :    
695 :    
696 :     #if !defined (AST14) && !defined (AST16)
697 :     struct ast_frame ast_null_frame;
698 :     #endif
699 :    
700 :     #if defined (AST14) || defined (AST16)
701 :     #if !defined (AST_JB)
702 :     #define AST_JB 1
703 :     #endif
704 :     #endif
705 :    
706 :     #if defined (AST_JB)
707 :     #include "asterisk/abstract_jb.h"
708 :     /* Global jitterbuffer configuration - by default, jb is disabled */
709 :     static struct ast_jb_conf default_jbconf =
710 :     {
711 :     .flags = 0,
712 :     .max_size = -1,
713 :     .resync_threshold = -1,
714 :     .impl = ""
715 :     };
716 :     static struct ast_jb_conf global_jbconf;
717 :     #endif /* AST_JB */
718 :    
719 :    
720 :     #define WOOMERA_SLINEAR 0
721 :     #define WOOMERA_ULAW 1
722 :     #define WOOMERA_ALAW 2
723 :    
724 :     #define WOOMERA_MAX_MEDIA_PORTS 899
725 :    
726 :     #define WOOMERA_STRLEN 256
727 :     #define WOOMERA_ARRAY_LEN 50
728 :     #define WOOMERA_MIN_PORT 10000
729 :     #define WOOMERA_MAX_PORT WOOMERA_MIN_PORT+WOOMERA_MAX_MEDIA_PORTS
730 :     #define WOOMERA_BODYLEN 2048
731 :     #define WOOMERA_LINE_SEPARATOR "\r\n"
732 :     #define WOOMERA_RECORD_SEPARATOR "\r\n\r\n"
733 : jtarlton 255 #define WOOMERA_DEBUG_PREFIX "[WOOMERA] "
734 : amartin 128 #define WOOMERA_DEBUG_LINE "--------------------------------------------------------------------------------"
735 : amartin 125 #define WOOMERA_HARD_TIMEOUT -2000
736 :     #define WOOMERA_QLEN 10
737 :     #define WOOMERA_MAX_TRUNKGROUPS 64
738 :    
739 :     static int woomera_base_media_port = WOOMERA_MIN_PORT;
740 :     static int woomera_max_media_port = WOOMERA_MAX_PORT;
741 :    
742 :     /* this macro is not in all versions of asterisk */
743 :     #ifdef OLDERAST
744 :     #define ASTOBJ_CONTAINER_UNLINK(container,obj) \
745 :     ({ \
746 :     typeof((container)->head) found = NULL; \
747 :     typeof((container)->head) prev = NULL; \
748 :     ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
749 :     if (iterator== obj) { \
750 :     found = iterator; \
751 :     found->next[0] = NULL; \
752 :     ASTOBJ_CONTAINER_WRLOCK(container); \
753 :     if (prev) \
754 :     prev->next[0] = next; \
755 :     else \
756 :     (container)->head = next; \
757 :     ASTOBJ_CONTAINER_UNLOCK(container); \
758 :     } \
759 :     prev = iterator; \
760 :     } while (0)); \
761 :     found; \
762 : amartin 128 })
763 : amartin 125 #endif
764 :    
765 :    
766 :     #define FRAME_LEN 480
767 :    
768 :     #if 0
769 :     static int WFORMAT = AST_FORMAT_ALAW; //AST_FORMAT_SLINEAR;
770 :     #else
771 :     static int WFORMAT = AST_FORMAT_SLINEAR;
772 :     #endif
773 :    
774 :     typedef enum {
775 :     WFLAG_EXISTS = (1 << 0),
776 :     WFLAG_EVENT = (1 << 1),
777 :     WFLAG_CONTENT = (1 << 2),
778 :     } WFLAGS;
779 :    
780 :    
781 :     typedef enum {
782 :     WCFLAG_NOWAIT = (1 << 0)
783 :     } WCFLAGS;
784 :    
785 :    
786 :     typedef enum {
787 :     PFLAG_INBOUND = (1 << 0),
788 :     PFLAG_OUTBOUND = (1 << 1),
789 :     PFLAG_DYNAMIC = (1 << 2),
790 :     PFLAG_DISABLED = (1 << 3)
791 :     } PFLAGS;
792 :    
793 :     typedef enum {
794 :     TFLAG_MEDIA = (1 << 0),
795 :     TFLAG_INBOUND = (1 << 1),
796 :     TFLAG_OUTBOUND = (1 << 2),
797 :     TFLAG_INCOMING = (1 << 3),
798 :     TFLAG_PARSE_INCOMING = (1 << 4),
799 :     TFLAG_ACTIVATE = (1 << 5),
800 :     TFLAG_DTMF = (1 << 6),
801 :     TFLAG_DESTROY = (1 << 7),
802 :     TFLAG_ABORT = (1 << 8),
803 :     TFLAG_PBX = (1 << 9),
804 :     TFLAG_ANSWER = (1 << 10),
805 :     TFLAG_INTHREAD = (1 << 11),
806 :     TFLAG_TECHHANGUP = (1 << 12),
807 :     TFLAG_DESTROYED = (1 << 13),
808 :     TFLAG_UP = (1 << 14),
809 :     TFLAG_ACCEPT = (1 << 15),
810 :     TFLAG_ACCEPTED = (1 << 16),
811 :     TFLAG_ANSWER_RECEIVED = (1 << 17),
812 :     TFLAG_CONFIRM_ANSWER = (1 << 18),
813 :     TFLAG_CONFIRM_ANSWER_ENABLED = (1 << 19),
814 :     TFLAG_AST_HANGUP = (1 << 20)
815 :     } TFLAGS;
816 :    
817 :     static int usecnt = 0;
818 :    
819 :     struct woomera_message {
820 :     char callid[WOOMERA_STRLEN];
821 :     int mval;
822 :     char command[WOOMERA_STRLEN];
823 :     char command_args[WOOMERA_STRLEN];
824 :     char names[WOOMERA_ARRAY_LEN][WOOMERA_STRLEN];
825 :     char values[WOOMERA_ARRAY_LEN][WOOMERA_STRLEN];
826 :     char body[WOOMERA_BODYLEN];
827 : amartin 128 char cause[WOOMERA_STRLEN];
828 : amartin 125 unsigned int flags;
829 :     int last;
830 :     unsigned int queue_id;
831 :     struct woomera_message *next;
832 :     };
833 :    
834 :    
835 :     static struct {
836 : amartin 128 int next_woomera_port;
837 : amartin 125 int debug;
838 :     int panic;
839 :     int more_threads;
840 :     ast_mutex_t woomera_port_lock;
841 :     } globals;
842 :    
843 :     struct woomera_event_queue {
844 :     struct woomera_message *head;
845 :     ast_mutex_t lock;
846 :     };
847 :    
848 :     struct woomera_profile {
849 :     ASTOBJ_COMPONENTS(struct woomera_profile);
850 :     ast_mutex_t iolock;
851 :     ast_mutex_t call_count_lock;
852 :     char woomera_host[WOOMERA_STRLEN];
853 :     int max_calls;
854 :     int call_count;
855 :     int woomera_port;
856 :     char audio_ip[WOOMERA_STRLEN];
857 :     char context[WOOMERA_STRLEN];
858 :     pthread_t thread;
859 :     unsigned int flags;
860 :     int thread_running;
861 :     int dtmf_enable;
862 :     int faxdetect;
863 :     int woomera_socket;
864 :     struct woomera_event_queue event_queue;
865 :     int jb_enable;
866 : amartin 128 int rtp_enable;
867 : amartin 125 int progress_enable;
868 :     int coding;
869 : amartin 128 int videocoding;
870 : amartin 125 float rxgain_val;
871 :     float txgain_val;
872 :     unsigned char rxgain[256];
873 :     unsigned char txgain[256];
874 :     int call_out;
875 :     int call_in;
876 :     int call_ok;
877 :     int call_end;
878 :     int call_abort;
879 :     int call_ast_hungup;
880 :     char default_context[WOOMERA_STRLEN];
881 :     char* tg_context [WOOMERA_MAX_TRUNKGROUPS+1];
882 :     char language[WOOMERA_STRLEN];
883 :     char* tg_language [WOOMERA_MAX_TRUNKGROUPS+1];
884 :     int udp_seq;
885 :     int rx_sync_check_opt;
886 :     int tx_sync_check_opt;
887 :     int tx_sync_gen_opt;
888 :     };
889 :    
890 :    
891 :     struct private_object {
892 :     ASTOBJ_COMPONENTS(struct private_object);
893 :     ast_mutex_t iolock;
894 :     struct ast_channel *owner;
895 :     struct sockaddr_in udpread;
896 :     struct sockaddr_in udpwrite;
897 :     int command_channel;
898 :     int udp_socket;
899 :     unsigned int flags;
900 :     struct ast_frame frame;
901 :     short fdata[FRAME_LEN + AST_FRIENDLY_OFFSET];
902 :     struct woomera_message call_info;
903 :     struct woomera_profile *profile;
904 : amartin 128 char dest[WOOMERA_STRLEN];
905 : amartin 125 char proto[WOOMERA_STRLEN];
906 :     int port;
907 : amartin 128 int vport;
908 : amartin 125 struct timeval started;
909 :     int timeout;
910 :     char dtmfbuf[WOOMERA_STRLEN];
911 :     char cid_name[WOOMERA_STRLEN];
912 :     char cid_num[WOOMERA_STRLEN];
913 :     char mohinterpret[MAX_MUSICCLASS];
914 :     char mohsuggest[MAX_MUSICCLASS];
915 :     char *cid_rdnis;
916 :     int cid_pres;
917 :     char ds[WOOMERA_STRLEN];
918 : amartin 128 struct ast_dsp *dsp;
919 : amartin 125 int ast_dsp;
920 :     int dsp_features;
921 :     int faxdetect;
922 :     int faxhandled;
923 : amartin 128 int rtp_enable;
924 : amartin 125 int call_count;
925 :     char callid[WOOMERA_STRLEN];
926 :     pthread_t thread;
927 :     unsigned int callno;
928 :     int refcnt;
929 :     struct woomera_event_queue event_queue;
930 :     int coding;
931 : amartin 128 int videocoding;
932 : amartin 125 int pri_cause;
933 :     int rx_udp_seq;
934 :     int tx_udp_seq;
935 : jtarlton 260
936 : amartin 125 #ifdef AST_JB
937 : jtarlton 260 struct ast_jb_conf jbconf;
938 : amartin 125 #endif /* AST_JB */
939 :    
940 :     int sync_r;
941 :     int sync_w;
942 :     unsigned char sync_data_w;
943 :     unsigned char sync_data_r;
944 :     int capability;
945 : amartin 128 struct ast_rtp *rtp; /*!< RTP Session */
946 :     struct ast_rtp *vrtp; /*!< Video RTP session */
947 : amartin 125
948 :     };
949 :    
950 : jtarlton 260
951 :     #define WOOMERA_MAX_CALLS 720 /* 24 * E1 */
952 :    
953 :     static struct private_object *tech_pvt_idx[WOOMERA_MAX_CALLS];
954 :     static ast_mutex_t tech_pvt_idx_lock[WOOMERA_MAX_CALLS];
955 :    
956 : amartin 125 typedef struct private_object private_object;
957 :     typedef struct woomera_message woomera_message;
958 :     typedef struct woomera_profile woomera_profile;
959 :     typedef struct woomera_event_queue woomera_event_queue;
960 :    
961 : amartin 128 #ifndef DEADLOCK_AVOIDANCE
962 : amartin 125 #define ast_find_lock_info(a,b,c,d,e,f,g,h) -1
963 :     #define DEADLOCK_AVOIDANCE(lock) \
964 :     do { \
965 :     ast_mutex_unlock(lock); \
966 :     usleep(1); \
967 :     ast_mutex_lock(lock); \
968 :     } while (0)
969 :     #endif
970 :    
971 :    
972 :     static int my_ast_channel_trylock(struct ast_channel *chan)
973 :     {
974 :     #if defined (AST14) || defined (AST16)
975 :     return ast_channel_trylock(chan);
976 :     #else
977 :     return ast_mutex_trylock(&chan->lock);
978 :     #endif
979 :     }
980 :    
981 :     #if !defined (CALLWEAVER)
982 :     #if 0
983 :     static int my_ast_channel_lock(struct ast_channel *chan)
984 :     {
985 :     #if defined (AST14) || defined (AST16)
986 :     return ast_channel_lock(chan);
987 :     #else
988 :     return ast_mutex_lock(&chan->lock);
989 :     #endif
990 :     }
991 :     #endif
992 :     #endif
993 :    
994 :     static int my_ast_channel_unlock(struct ast_channel *chan)
995 :     {
996 :     #if defined (AST14) || defined (AST16)
997 :     return ast_channel_unlock(chan);
998 :     #else
999 :     return ast_mutex_unlock(&chan->lock);
1000 :     #endif
1001 :     }
1002 :    
1003 :     static int my_tech_pvt_and_owner_lock(private_object *tech_pvt)
1004 :     {
1005 :     ast_mutex_lock(&tech_pvt->iolock);
1006 : jtarlton 255 while(tech_pvt->owner && my_ast_channel_trylock(tech_pvt->owner)) {
1007 :     if (globals.debug > 2) {
1008 :     ast_log(LOG_NOTICE,"Tech Thread - Hanging up channel - deadlock avoidance\n");
1009 : amartin 125 }
1010 : jtarlton 255 DEADLOCK_AVOIDANCE(&tech_pvt->iolock);
1011 :     }
1012 : amartin 125 return 0;
1013 :     }
1014 :    
1015 : jtarlton 255
1016 : amartin 125 static int my_tech_pvt_and_owner_unlock(private_object *tech_pvt)
1017 :     {
1018 :     if (tech_pvt->owner) {
1019 : amartin 128 my_ast_channel_unlock(tech_pvt->owner);
1020 : amartin 125 }
1021 :     ast_mutex_unlock(&tech_pvt->iolock);
1022 :     return 0;
1023 :     }
1024 :    
1025 : jtarlton 255
1026 : amartin 125 static void my_ast_softhangup(struct ast_channel *chan, private_object *tech_pvt, int cause)
1027 :     {
1028 :     #if 1
1029 :     ast_queue_hangup(chan);
1030 :     //ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
1031 :     #else
1032 :     struct ast_frame f = { AST_FRAME_NULL };
1033 :    
1034 :     if (chan) {
1035 :     chan->_softhangup |= cause;
1036 :     ast_queue_frame(chan, &f);
1037 :     }
1038 : amartin 128
1039 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
1040 :     #endif
1041 :    
1042 :     #if 0
1043 :     if (tech_pvt->dsp) {
1044 :     tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT;
1045 : amartin 128 ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
1046 : jtarlton 280 tech_pvt->ast_dsp = 0;
1047 : amartin 125 }
1048 :     #endif
1049 :    
1050 :     }
1051 :    
1052 : jtarlton 260 /* For RTP audio */
1053 : amartin 128 static struct sched_context *sched; /*!< The scheduling context */
1054 :     static struct io_context *io; /*!< The IO context */
1055 : amartin 125
1056 : amartin 128
1057 : amartin 125 static struct private_object_container {
1058 :     ASTOBJ_CONTAINER_COMPONENTS(private_object);
1059 :     } private_object_list;
1060 :    
1061 :     static struct woomera_profile_container {
1062 :     ASTOBJ_CONTAINER_COMPONENTS(woomera_profile);
1063 :     } woomera_profile_list;
1064 :    
1065 :     static woomera_profile default_profile;
1066 :    
1067 :     /* some locks you will use for use count and for exclusive access to the main linked-list of private objects */
1068 :     AST_MUTEX_DEFINE_STATIC(usecnt_lock);
1069 :     AST_MUTEX_DEFINE_STATIC(lock);
1070 :    
1071 :     /* local prototypes */
1072 :     static void woomera_close_socket(int *socket);
1073 :     static void global_set_flag(int flags);
1074 : amartin 231 #ifdef WOOMERA_PRINTF_DEBUG
1075 :     static int __woomera_printf(const char* file, int line, woomera_profile *profile, int fd, char *fmt, ...);
1076 :     #else
1077 :     static int __woomera_printf(woomera_profile *profile, int fd, char *fmt, ...);
1078 :     #endif
1079 : amartin 125 static char *woomera_message_header(woomera_message *wmsg, char *key);
1080 :     static int woomera_enqueue_event(woomera_event_queue *event_queue, woomera_message *wmsg);
1081 :     static int woomera_dequeue_event(woomera_event_queue *event_queue, woomera_message *wmsg);
1082 :     static int woomera_message_parse(int fd, woomera_message *wmsg, int timeout, woomera_profile *profile, woomera_event_queue *event_queue);
1083 :     static int woomera_message_parse_wait(private_object *tech_pvt,woomera_message *wmsg);
1084 :     static int waitfor_socket(int fd, int timeout);
1085 :     static int woomera_profile_thread_running(woomera_profile *profile, int set, int new);
1086 :     static int woomera_locate_socket(woomera_profile *profile, int *woomera_socket);
1087 : amartin 128 static void *woomera_thread_run(void *obj);
1088 : amartin 125 static void launch_woomera_thread(woomera_profile *profile);
1089 : amartin 128 static void destroy_woomera_profile(woomera_profile *profile);
1090 : amartin 125 static woomera_profile *clone_woomera_profile(woomera_profile *new_profile, woomera_profile *default_profile);
1091 :     static woomera_profile *create_woomera_profile(woomera_profile *default_profile);
1092 :     static int config_woomera(void);
1093 :     static int create_udp_socket(char *ip, int port, struct sockaddr_in *sockaddr, int client);
1094 : amartin 128 static struct ast_rtp * create_rtp(char *ip);
1095 : amartin 125 static int connect_woomera(int *new_socket, woomera_profile *profile, int flags);
1096 :     static int init_woomera(void);
1097 : jtarlton 260
1098 : amartin 125 #if defined (AST16)
1099 :     static char *ast16_woomera_cli(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
1100 :     #endif
1101 : jtarlton 260
1102 : amartin 125 static int woomera_cli(int fd, int argc, char *argv[]);
1103 :     static void tech_destroy(private_object *tech_pvt, struct ast_channel *owner);
1104 :     static struct ast_channel *woomera_new(const char *type, int format, void *data, int *cause, woomera_profile *profile);
1105 :     static int launch_tech_thread(private_object *tech_pvt);
1106 :     static int tech_create_read_socket(private_object *tech_pvt);
1107 :     static int tech_activate(private_object *tech_pvt);
1108 :     static int tech_init(private_object *tech_pvt, woomera_profile *profile, int flags);
1109 :     static void *tech_monitor_thread(void *obj);
1110 :     static void tech_monitor_in_one_thread(void);
1111 :     static struct ast_channel * tech_get_owner( private_object *tech_pvt);
1112 :     int usecount(void);
1113 : jtarlton 260
1114 : amartin 125 #if 0
1115 :     static char *key(void);
1116 :     static char *description(void);
1117 :     #endif
1118 : jtarlton 260
1119 : amartin 125 int load_module(void);
1120 :     int unload_module(void);
1121 :     int reload(void);
1122 :    
1123 :    
1124 :     /********************CHANNEL METHOD PROTOTYPES*******************
1125 :     * You may or may not need all of these methods, remove any unnecessary functions/protos/mappings as needed.
1126 :     *
1127 :     */
1128 :     static struct ast_channel *tech_requester(const char *type, int format, void *data, int *cause);
1129 :     static int tech_send_digit(struct ast_channel *self, char digit);
1130 : jtarlton 280
1131 : amartin 125 #if defined (AST14) || defined (AST16)
1132 :     static int tech_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
1133 :     #endif
1134 : jtarlton 280
1135 : amartin 125 static int tech_call(struct ast_channel *self, char *dest, int timeout);
1136 :     static int tech_hangup(struct ast_channel *self);
1137 :     static int tech_answer(struct ast_channel *self);
1138 :     static struct ast_frame *tech_read(struct ast_channel *self);
1139 :     static struct ast_frame *tech_exception(struct ast_channel *self);
1140 :     static int tech_write(struct ast_channel *self, struct ast_frame *frame);
1141 : jtarlton 280
1142 : amartin 125 #ifdef USE_TECH_INDICATE
1143 :     # if defined (AST14) || defined (AST16)
1144 :     static int tech_indicate(struct ast_channel *self, int condition, const void *data, size_t datalen);
1145 :     # else
1146 :     static int tech_indicate(struct ast_channel *self, int condition);
1147 :     # endif
1148 :     #endif
1149 : jtarlton 280
1150 : amartin 125 static int tech_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
1151 :     static int tech_send_html(struct ast_channel *self, int subclass, const char *data, int datalen);
1152 :     static int tech_send_text(struct ast_channel *self, const char *text);
1153 :     static int tech_send_image(struct ast_channel *self, struct ast_frame *frame);
1154 :     static int tech_setoption(struct ast_channel *self, int option, void *data, int datalen);
1155 :     static int tech_queryoption(struct ast_channel *self, int option, void *data, int *datalen);
1156 :     //static enum ast_bridge_result tech_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
1157 :     static int tech_transfer(struct ast_channel *self, const char *newdest);
1158 :     static int tech_write_video(struct ast_channel *self, struct ast_frame *frame);
1159 :     //static struct ast_channel *tech_bridged_channel(struct ast_channel *self, struct ast_channel *bridge);
1160 :    
1161 :     static int woomera_event_incoming (private_object *tech_pvt);
1162 :     static int woomera_event_media (private_object *tech_pvt, woomera_message *wmsg);
1163 :     static void woomera_check_event (private_object *tech_pvt, int res, woomera_message *wmsg);
1164 :    
1165 :     /********************************************************************************
1166 :     * Constant structure for mapping local methods to the core interface.
1167 :     * This structure only needs to contain the methods the channel requires to operate
1168 :     * Not every channel needs all of them defined.
1169 :     */
1170 :    
1171 :     static const struct ast_channel_tech technology = {
1172 :     .type = WOOMERA_CHAN_NAME,
1173 :     .description = tdesc,
1174 :     .capabilities = (AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW),
1175 :     .requester = tech_requester,
1176 :     #if defined (AST14) || defined (AST16)
1177 :     .send_digit_begin = tech_send_digit,
1178 :     .send_digit_end = tech_digit_end,
1179 :     #else
1180 :     .send_digit = tech_send_digit,
1181 :     #endif
1182 :     .call = tech_call,
1183 :     //.bridge = tech_bridge,
1184 :     .hangup = tech_hangup,
1185 :     .answer = tech_answer,
1186 :     .transfer = tech_transfer,
1187 :     .write_video = tech_write_video,
1188 :     .read = tech_read,
1189 :     .write = tech_write,
1190 :     .exception = tech_exception,
1191 :     #ifdef USE_TECH_INDICATE
1192 :     .indicate = tech_indicate,
1193 :     #endif
1194 :     .fixup = tech_fixup,
1195 :     .send_html = tech_send_html,
1196 :     .send_text = tech_send_text,
1197 :     .send_image = tech_send_image,
1198 :     .setoption = tech_setoption,
1199 :     .queryoption = tech_queryoption,
1200 :     //.bridged_channel = tech_bridged_channel,
1201 :     .transfer = tech_transfer,
1202 :     };
1203 :    
1204 :    
1205 : amartin 128 static void woomera_close_socket(int *socket)
1206 : amartin 125 {
1207 :     if (*socket > -1) {
1208 :     close(*socket);
1209 :     }
1210 :     *socket = -1;
1211 :     }
1212 :    
1213 : jtarlton 195
1214 : amartin 128 static int woomera_message_reply_ok(woomera_message *wmsg)
1215 : amartin 125 {
1216 : jtarlton 260 if (!(wmsg->mval >= 200 && wmsg->mval <= 299)) {
1217 :     return -1;
1218 :     }
1219 :     return 0;
1220 : amartin 125 }
1221 :    
1222 :    
1223 :     static void global_set_flag(int flags)
1224 :     {
1225 :     private_object *tech_pvt;
1226 :    
1227 :     ASTOBJ_CONTAINER_TRAVERSE(&private_object_list, 1, do {
1228 :     ASTOBJ_RDLOCK(iterator);
1229 : jtarlton 255 tech_pvt = iterator;
1230 : amartin 125 ast_set_flag(tech_pvt, flags);
1231 :     ASTOBJ_UNLOCK(iterator);
1232 :     } while(0));
1233 : amartin 128 }
1234 : amartin 125
1235 : jtarlton 255
1236 : amartin 125 static void woomera_send_progress(private_object *tech_pvt)
1237 :     {
1238 :     struct ast_channel *owner = tech_pvt->owner;
1239 :    
1240 :     if (tech_pvt->profile->progress_enable && owner){
1241 : jtarlton 255 if (globals.debug > 2) {
1242 : jtarlton 260 ast_log(LOG_NOTICE, "Sending Progress %s\n", tech_pvt->callid);
1243 : jtarlton 255 }
1244 :     ast_queue_control(owner, AST_CONTROL_PROGRESS);
1245 :     }
1246 : amartin 125 }
1247 :    
1248 :    
1249 :     static int woomera_coding_to_ast(char *suil1p)
1250 :     {
1251 :     if (suil1p) {
1252 :     if (!strcasecmp(suil1p, "G_711_ULAW")) {
1253 :     return AST_FORMAT_ULAW;
1254 :     }
1255 :     if (!strcasecmp(suil1p, "G_711_ALAW")) {
1256 :     return AST_FORMAT_ALAW;
1257 :     }
1258 :     if (!strcasecmp(suil1p, "G_721")) {
1259 :     return AST_FORMAT_ADPCM;
1260 :     }
1261 :     }
1262 :     return -1;
1263 :     }
1264 :    
1265 : jtarlton 255
1266 : amartin 125 static char* woomera_ast_coding_to_string(int coding)
1267 :     {
1268 :     switch(coding) {
1269 :     case AST_FORMAT_ALAW:
1270 :     return "G_711_ALAW";
1271 :     case AST_FORMAT_ULAW:
1272 :     return "G_711_ULAW";
1273 :     case AST_FORMAT_ADPCM:
1274 :     return "G_721";
1275 :     }
1276 :     return "G_711_ALAW";
1277 :     }
1278 :    
1279 : jtarlton 255
1280 : amartin 125 static uint32_t woomera_capability_to_ast(char *sbearer_cap)
1281 :     {
1282 :     if (sbearer_cap) {
1283 :     if (!strcasecmp(sbearer_cap, "SPEECH")) {
1284 :     return AST_TRANS_CAP_SPEECH;
1285 :     }
1286 :     if (!strcasecmp(sbearer_cap, "3_1KHZ_AUDIO")) {
1287 :     return AST_TRANS_CAP_3_1K_AUDIO;
1288 : amartin 128 }
1289 : amartin 125 if (!strcasecmp(sbearer_cap, "64K_UNRESTRICTED") ||
1290 :     !strcasecmp(sbearer_cap, "ALTERNATE_SPEECH") ||
1291 :     !strcasecmp(sbearer_cap, "ALTERNATE_64K") ||
1292 :     !strcasecmp(sbearer_cap, "64K_PREFERRED") ||
1293 :     !strcasecmp(sbearer_cap, "384K_UNRESTRICTED") ||
1294 :     !strcasecmp(sbearer_cap, "2x64K_PREFERRED") ||
1295 :     !strcasecmp(sbearer_cap, "1536K_UNRESTRICTED") ||
1296 :     !strcasecmp(sbearer_cap, "1920K_UNRESTRICTED")) {
1297 : amartin 128
1298 : amartin 125 return AST_TRANS_CAP_DIGITAL;
1299 :     }
1300 :     }
1301 :     return AST_TRANS_CAP_SPEECH;
1302 :     }
1303 :    
1304 : jtarlton 260
1305 : amartin 125 static char* woomera_ast_transfercap_to_string(int transfercap)
1306 :     {
1307 :     switch(transfercap) {
1308 :     case AST_TRANS_CAP_SPEECH:
1309 :     return "SPEECH";
1310 :     case AST_TRANS_CAP_3_1K_AUDIO:
1311 :     return "3_1KHZ_AUDIO";
1312 :     case AST_TRANS_CAP_DIGITAL:
1313 :     case AST_TRANS_CAP_RESTRICTED_DIGITAL:
1314 :     case AST_TRANS_CAP_DIGITAL_W_TONES:
1315 : amartin 128 case AST_TRANS_CAP_VIDEO:
1316 : amartin 125 return "64K_UNRESTRICTED";
1317 :     }
1318 :    
1319 :     return "SPEECH";
1320 :     }
1321 :    
1322 :    
1323 :     static uint32_t string_to_release(char *code)
1324 :     {
1325 :     if (code) {
1326 :     if (!strcasecmp(code, "CHANUNAVAIL")) {
1327 :     return AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
1328 :     }
1329 :    
1330 :     if (!strcasecmp(code, "INVALID")) {
1331 :     return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
1332 :     }
1333 :    
1334 :     if (!strcasecmp(code, "ERROR")) {
1335 :     return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
1336 :     }
1337 :    
1338 :     if (!strcasecmp(code, "CONGESTION")) {
1339 :     return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
1340 :     }
1341 :    
1342 :     if (!strcasecmp(code, "BUSY")) {
1343 :     return AST_CAUSE_USER_BUSY;
1344 :     }
1345 :    
1346 :     if (!strcasecmp(code, "NOANSWER")) {
1347 :     return AST_CAUSE_NO_ANSWER;
1348 :     }
1349 :    
1350 :     if (!strcasecmp(code, "ANSWER")) {
1351 :     return AST_CAUSE_NORMAL_CLEARING;
1352 :     }
1353 :    
1354 :     if (!strcasecmp(code, "CANCEL")) {
1355 :     return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
1356 :     }
1357 :    
1358 :     if (!strcasecmp(code, "UNKNOWN")) {
1359 :     return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
1360 : amartin 128 }
1361 : amartin 125 }
1362 :     return AST_CAUSE_NORMAL_CLEARING;
1363 :     }
1364 :    
1365 :    
1366 : amartin 231 #ifdef WOOMERA_PRINTF_DEBUG
1367 :     static int __woomera_printf(const char* file, int line, woomera_profile *profile, int fd, char *fmt, ...)
1368 :     #else
1369 :     static int __woomera_printf(woomera_profile *profile, int fd, char *fmt, ...)
1370 :     #endif
1371 : amartin 125 {
1372 : jtarlton 255 char *stuff;
1373 :     int res = 0;
1374 : amartin 125
1375 :     if (fd < 0) {
1376 :     if (globals.debug > 4) {
1377 :     ast_log(LOG_ERROR, "Not gonna write to fd %d\n", fd);
1378 :     }
1379 : amartin 231 return -1;
1380 : amartin 125 }
1381 : amartin 128
1382 : jtarlton 236 va_list ap;
1383 :     va_start(ap, fmt);
1384 : amartin 125 #ifdef SOLARIS
1385 :     stuff = (char *)ast_malloc(10240);
1386 :     vsnprintf(stuff, 10240, fmt, ap);
1387 :     #else
1388 : jtarlton 236 res = vasprintf(&stuff, fmt, ap);
1389 : amartin 125 #endif
1390 : jtarlton 236 va_end(ap);
1391 :    
1392 :     if (res == -1) {
1393 :     ast_log(LOG_ERROR, "Out of memory\n");
1394 :     } else {
1395 :     res = 0;
1396 : amartin 125 if (profile && globals.debug) {
1397 :     if (option_verbose > 2) {
1398 : jtarlton 236 ast_verbose(WOOMERA_DEBUG_PREFIX "Send Message: {%s} [%s/%d]\n%s\n%s", profile->name, profile->woomera_host, profile->woomera_port, WOOMERA_DEBUG_LINE, stuff);
1399 : amartin 125 }
1400 :     }
1401 : jtarlton 236 res = ast_carefulwrite(fd, stuff, strlen(stuff), 100);
1402 : jtarlton 255
1403 : amartin 231 #ifdef WOOMERA_PRINTF_DEBUG
1404 :     if (res < 0) {
1405 : jtarlton 280 ast_log(LOG_ERROR,"%s:%d FAILED fd=%i %s\n", file, line, fd, strerror(errno));
1406 : amartin 231 }
1407 :     #endif
1408 : jtarlton 255 ast_free(stuff);
1409 : amartin 125 }
1410 :    
1411 : amartin 231 return res;
1412 : amartin 125 }
1413 :    
1414 : jtarlton 260
1415 : amartin 128 static char *woomera_message_header(woomera_message *wmsg, char *key)
1416 : amartin 125 {
1417 :     int x = 0;
1418 :     char *value = NULL;
1419 :    
1420 :     #if 0
1421 :     if (!strcasecmp(wmsg->command,"HANGUP")) {
1422 : jtarlton 236 ast_log(LOG_NOTICE, "Message Header for HANGUP\n");
1423 :     for (x = 0 ; x < wmsg->last ; x++) {
1424 :     ast_log(LOG_NOTICE, "Name=%s Value=%s\n",
1425 : jtarlton 280 wmsg->names[x], wmsg->values[x]);
1426 : jtarlton 236 if (!strcasecmp(wmsg->names[x], key)) {
1427 :     value = wmsg->values[x];
1428 :     break;
1429 :     }
1430 : amartin 125 }
1431 :     }
1432 :     #endif
1433 :    
1434 :     for (x = 0 ; x < wmsg->last ; x++) {
1435 :     if (!strcasecmp(wmsg->names[x], key)) {
1436 :     value = wmsg->values[x];
1437 :     break;
1438 :     }
1439 :     }
1440 :    
1441 :     return value;
1442 :     }
1443 :    
1444 : jtarlton 260
1445 : amartin 125 static int woomera_enqueue_event(woomera_event_queue *event_queue, woomera_message *wmsg)
1446 :     {
1447 :     woomera_message *new, *mptr;
1448 :    
1449 :     if ((new = ast_malloc(sizeof(woomera_message)))) {
1450 :     ast_mutex_lock(&event_queue->lock);
1451 :     memcpy(new, wmsg, sizeof(woomera_message));
1452 :     new->next = NULL;
1453 :     if (!event_queue->head) {
1454 :     event_queue->head = new;
1455 :     } else {
1456 :     for (mptr = event_queue->head; mptr && mptr->next ; mptr = mptr->next);
1457 :     mptr->next = new;
1458 :     }
1459 :     ast_mutex_unlock(&event_queue->lock);
1460 :     return 1;
1461 :     } else {
1462 :     ast_log(LOG_ERROR, "Memory Allocation Error!\n");
1463 :     }
1464 :    
1465 :     return 0;
1466 :     }
1467 :    
1468 : jtarlton 260
1469 : amartin 125 static int woomera_dequeue_event(woomera_event_queue *event_queue, woomera_message *wmsg)
1470 :     {
1471 :     woomera_message *mptr = NULL;
1472 : amartin 128
1473 : amartin 125 ast_mutex_lock(&event_queue->lock);
1474 :     if (event_queue->head) {
1475 :     mptr = event_queue->head;
1476 :     event_queue->head = mptr->next;
1477 :     }
1478 :    
1479 :     if (mptr) {
1480 :     memcpy(wmsg, mptr, sizeof(woomera_message));
1481 :     }
1482 :     ast_mutex_unlock(&event_queue->lock);
1483 :    
1484 : jtarlton 255 if (mptr) {
1485 : amartin 125 ast_free(mptr);
1486 :     return 1;
1487 :     } else {
1488 :     memset(wmsg, 0, sizeof(woomera_message));
1489 :     }
1490 : amartin 128
1491 : amartin 125 return 0;
1492 :     }
1493 :    
1494 :    
1495 : amartin 231 #if 0
1496 :     #include <execinfo.h>
1497 :     static void print_trace(void)
1498 : amartin 125 {
1499 : amartin 231 int i;
1500 :     void *stacktrace[100];
1501 :     size_t size;
1502 :     char **symbols;
1503 :    
1504 :     size = backtrace(stacktrace, sizeof(stacktrace)/sizeof(stacktrace[1]));
1505 :     symbols = backtrace_symbols(stacktrace, size);
1506 :    
1507 :     for (i=0;i<size;i++) {
1508 :     ast_log(LOG_ERROR,"%lu, %s\n", pthread_self(), symbols[i]);
1509 :    
1510 :     }
1511 :    
1512 :     if (symbols)
1513 :     free(symbols);
1514 :    
1515 :     }
1516 :     #endif
1517 :    
1518 :    
1519 : jtarlton 236 static int woomera_message_parse(int fd,
1520 :     woomera_message *wmsg,
1521 :     int timeout,
1522 :     woomera_profile *profile,
1523 :     woomera_event_queue *event_queue)
1524 : amartin 231 {
1525 : amartin 125 char *cur, *cr, *next = NULL, *eor = NULL;
1526 :     char buf[2048];
1527 :     int res = 0, bytes = 0, sanity = 0;
1528 :     struct timeval started, ended;
1529 :     int elapsed, loops = 0;
1530 : jtarlton 236 int fail_timeout = 0;
1531 : amartin 125
1532 :     memset(wmsg, 0, sizeof(woomera_message));
1533 :    
1534 :     if (fd < 0) {
1535 :     return -1;
1536 :     }
1537 :    
1538 :     gettimeofday(&started, NULL);
1539 :     memset(buf, 0, sizeof(buf));
1540 :    
1541 : jtarlton 238 /* -ve timeout values indicate that timeouts should be treated as a failure.
1542 :     */
1543 : amartin 125 if (timeout < 0) {
1544 :     timeout = abs(timeout);
1545 : jtarlton 236 fail_timeout = 1;
1546 : jtarlton 195 } else if (timeout == 0) {
1547 : amartin 125 timeout = -1;
1548 :     }
1549 :    
1550 :     while (!(eor = strstr(buf, WOOMERA_RECORD_SEPARATOR))) {
1551 :    
1552 :     if (!profile->thread_running) {
1553 :     return -1;
1554 :     }
1555 :    
1556 :     if (globals.panic > 2) {
1557 :     return -1;
1558 :     }
1559 :     /* Keep things moving.
1560 :     Stupid Sockets -Homer Simpson */
1561 : jtarlton 236 res = woomera_printf(NULL, fd, "%s", WOOMERA_RECORD_SEPARATOR);
1562 : amartin 231 if (res < 0) {
1563 :     return -1;
1564 :     }
1565 : amartin 125
1566 : jtarlton 236 if ((res = waitfor_socket(fd, (timeout > 0 ? timeout : 100)) > 0)) {
1567 : amartin 125 res = recv(fd, buf, sizeof(buf), MSG_PEEK);
1568 :     if (res == 0) {
1569 :     sanity++;
1570 :     } else if (res < 0) {
1571 :     if (option_verbose > 2) {
1572 : jtarlton 236 ast_verbose(WOOMERA_DEBUG_PREFIX "{%s} error during packet retry #%d\n", profile->name, loops);
1573 : amartin 125 }
1574 : jtarlton 236 return res;
1575 : amartin 125
1576 :     } else if (loops && globals.debug) {
1577 :     //ast_verbose(WOOMERA_DEBUG_PREFIX "{%s} Didnt get complete packet retry #%d\n", profile->name, loops);
1578 : jtarlton 236 res = woomera_printf(NULL, fd, "%s", WOOMERA_RECORD_SEPARATOR);
1579 : amartin 231 if (res < 0) {
1580 :     return res;
1581 :     }
1582 : amartin 125 usleep(100);
1583 :     }
1584 :    
1585 :     if (res > 0) {
1586 : jtarlton 236 sanity = 0;
1587 : amartin 125 }
1588 :     }
1589 :    
1590 :     if (res < 0) {
1591 :     return res;
1592 :     }
1593 :    
1594 :     if (sanity > 1000) {
1595 :     if (globals.debug > 2) {
1596 : jtarlton 236 ast_log(LOG_ERROR, "{%s} Failed Sanity Check! [errors] fd=%d\n",
1597 : jtarlton 280 profile->name, fd);
1598 : amartin 125 }
1599 :     return -100;
1600 :     }
1601 :    
1602 : jtarlton 236 gettimeofday(&ended, NULL);
1603 :     elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000));
1604 : amartin 125 if (timeout > 0 && (elapsed > timeout)) {
1605 : jtarlton 236 return fail_timeout ? -1 : 0;
1606 : amartin 125 }
1607 : amartin 128
1608 : amartin 125 loops++;
1609 :     }
1610 : jtarlton 236
1611 : amartin 125 *eor = '\0';
1612 :     bytes = strlen(buf) + 4;
1613 : amartin 128
1614 : amartin 125 memset(buf, 0, sizeof(buf));
1615 :     res = read(fd, buf, bytes);
1616 :     next = buf;
1617 :    
1618 :     if (globals.debug) {
1619 :     if (option_verbose > 2) {
1620 : jtarlton 195 ast_verbose(WOOMERA_DEBUG_PREFIX "Receive Message: {%s} [%s/%d]\n%s\n%s", profile->name, profile->woomera_host, profile->woomera_port, WOOMERA_DEBUG_LINE, buf);
1621 : amartin 125 }
1622 :     }
1623 :    
1624 : jtarlton 255 while ((cur = next)) {
1625 : amartin 125 if ((cr = strstr(cur, WOOMERA_LINE_SEPARATOR))) {
1626 :     *cr = '\0';
1627 :     next = cr + (sizeof(WOOMERA_LINE_SEPARATOR) - 1);
1628 :     if (!strcmp(next, WOOMERA_RECORD_SEPARATOR)) {
1629 :     break;
1630 :     }
1631 : amartin 128 }
1632 : amartin 125
1633 :     if (ast_strlen_zero(cur)) {
1634 :     break;
1635 :     }
1636 :    
1637 :     if (!wmsg->last) {
1638 :     ast_set_flag(wmsg, WFLAG_EXISTS);
1639 :     if (!strncasecmp(cur, "EVENT", 5)) {
1640 :     cur += 6;
1641 :     ast_set_flag(wmsg, WFLAG_EVENT);
1642 :    
1643 :     if (cur && (cr = strchr(cur, ' '))) {
1644 :     char *id;
1645 :    
1646 :     *cr = '\0';
1647 :     cr++;
1648 :     id = cr;
1649 :     if (cr && (cr = strchr(cr, ' '))) {
1650 :     *cr = '\0';
1651 :     cr++;
1652 :     strncpy(wmsg->command_args, cr, WOOMERA_STRLEN);
1653 :     }
1654 :     if(id) {
1655 :     ast_copy_string(wmsg->callid, id, sizeof(wmsg->callid));
1656 :     }
1657 :     }
1658 :     } else {
1659 :     if (cur && (cur = strchr(cur, ' '))) {
1660 :     *cur = '\0';
1661 :     cur++;
1662 :     wmsg->mval = atoi(buf);
1663 :     } else {
1664 :     ast_log(LOG_NOTICE, "Malformed Message!\n");
1665 :     break;
1666 :     }
1667 :     }
1668 :     if (cur) {
1669 :     strncpy(wmsg->command, cur, WOOMERA_STRLEN);
1670 :     } else {
1671 :     ast_log(LOG_NOTICE, "Malformed Message!\n");
1672 :     break;
1673 :     }
1674 :     } else {
1675 :     char *name, *val;
1676 :     name = cur;
1677 :     if ((val = strchr(name, ':'))) {
1678 :     *val = '\0';
1679 :     val++;
1680 :     while (*val == ' ') {
1681 :     *val = '\0';
1682 :     val++;
1683 :     }
1684 :     strncpy(wmsg->values[wmsg->last-1], val, WOOMERA_STRLEN);
1685 :     }
1686 :     strncpy(wmsg->names[wmsg->last-1], name, WOOMERA_STRLEN);
1687 :     if (name && val && !strcasecmp(name, "content-type")) {
1688 :     ast_set_flag(wmsg, WFLAG_CONTENT);
1689 :     bytes = atoi(val);
1690 :     }
1691 :    
1692 :     if (name && val && !strcasecmp(name, "content-length")) {
1693 : jtarlton 195 ast_set_flag(wmsg, WFLAG_CONTENT);
1694 :     bytes = atoi(val);
1695 :     }
1696 : amartin 125 }
1697 :     wmsg->last++;
1698 :    
1699 :     if (wmsg->last >= WOOMERA_ARRAY_LEN) {
1700 :     ast_log(LOG_NOTICE, "Woomera parse error: index overflow!\n");
1701 :     break;
1702 :     }
1703 :     }
1704 :    
1705 :     wmsg->last--;
1706 :    
1707 :     if (bytes && ast_test_flag(wmsg, WFLAG_CONTENT)) {
1708 : amartin 231 int terr;
1709 : jtarlton 255 terr = read(fd, wmsg->body, (bytes > sizeof(wmsg->body)) ? sizeof(wmsg->body) : bytes);
1710 : amartin 125 if (globals.debug) {
1711 :     if (option_verbose > 2) {
1712 :     ast_verbose("%s\n", wmsg->body);
1713 :     }
1714 :     }
1715 :     }
1716 :    
1717 :     if (event_queue && ast_test_flag(wmsg, WFLAG_EVENT)) {
1718 :     if (globals.debug) {
1719 :     if (option_verbose > 2) {
1720 :     ast_verbose(WOOMERA_DEBUG_PREFIX "Queue Event: {%s} [%s]\n", profile->name, wmsg->command);
1721 :     }
1722 :     }
1723 :     /* we don't want events we want a reply so we will stash them for later */
1724 :     woomera_enqueue_event(event_queue, wmsg);
1725 :    
1726 :     /* call ourself recursively to find the reply. we'll keep doing this as long we get events.
1727 :     * wmsg will be overwritten but it's ok we just queued it.
1728 :     */
1729 :     return woomera_message_parse(fd, wmsg, timeout, profile, event_queue);
1730 : amartin 128
1731 : amartin 125 } else if (wmsg->mval > 99 && wmsg->mval < 200) {
1732 : amartin 128 /* reply in the 100's are nice but we need to wait for another reply
1733 : amartin 125 call ourself recursively to find the reply > 199 and forget this reply.
1734 :     */
1735 :     return woomera_message_parse(fd, wmsg, timeout, profile, event_queue);
1736 :     } else {
1737 :     return ast_test_flag(wmsg, WFLAG_EXISTS);
1738 :     }
1739 :     }
1740 :    
1741 : jtarlton 260
1742 : amartin 125 static int woomera_message_parse_wait(private_object *tech_pvt, woomera_message *wmsg)
1743 :     {
1744 : jtarlton 255 int err = 0;
1745 : amartin 125
1746 :     for (;;) {
1747 : amartin 128
1748 : amartin 125 if (ast_test_flag(tech_pvt, TFLAG_ABORT)){
1749 : jtarlton 195 return -1;
1750 : amartin 128 }
1751 :    
1752 : jtarlton 195 err = woomera_message_parse(tech_pvt->command_channel,
1753 :     wmsg,
1754 :     100,
1755 :     tech_pvt->profile,
1756 :     &tech_pvt->event_queue);
1757 : amartin 125
1758 :     if (err == 0) {
1759 :     /* This is a timeout */
1760 :     continue;
1761 : amartin 128 }
1762 : amartin 125
1763 : jtarlton 195 break;
1764 : amartin 125 }
1765 : amartin 128
1766 :     return err;
1767 : amartin 125 }
1768 :    
1769 :    
1770 :     static int tech_create_read_socket(private_object *tech_pvt)
1771 :     {
1772 :     int retry=0;
1773 :     int ports=0;
1774 :    
1775 :     retry_udp:
1776 :    
1777 :     ast_mutex_lock(&globals.woomera_port_lock);
1778 :     globals.next_woomera_port++;
1779 :     if (globals.next_woomera_port >= woomera_max_media_port) {
1780 :     globals.next_woomera_port = woomera_base_media_port;
1781 :     }
1782 :     tech_pvt->port = globals.next_woomera_port;
1783 :     ports++;
1784 :     ast_mutex_unlock(&globals.woomera_port_lock);
1785 : amartin 128
1786 : amartin 125 if ((tech_pvt->udp_socket = create_udp_socket(tech_pvt->profile->audio_ip, tech_pvt->port, &tech_pvt->udpread, 0)) > -1) {
1787 :     struct ast_channel *owner = tech_get_owner(tech_pvt);
1788 :     if (owner) {
1789 :     owner->fds[0] = tech_pvt->udp_socket;
1790 :     } else {
1791 :     ast_log(LOG_ERROR, "Tech_pvt has no OWNER! %i\n",__LINE__);
1792 :     }
1793 :    
1794 :     } else {
1795 :    
1796 :     retry++;
1797 :     if (retry <= 10 || errno == EADDRINUSE) {
1798 :     if (ports < (woomera_max_media_port - woomera_base_media_port)) {
1799 :     goto retry_udp;
1800 :     }
1801 :     }
1802 :    
1803 :     if (globals.debug) {
1804 :     ast_log(LOG_ERROR,
1805 : jtarlton 195 "Error Creating udp socket %s/%i (%p) %s %s %s\n",
1806 :     tech_pvt->profile->audio_ip,
1807 :     tech_pvt->port,
1808 :     tech_pvt,
1809 :     tech_pvt->callid,
1810 :     ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT":"IN",
1811 :     strerror(errno));
1812 : amartin 125 }
1813 :     }
1814 :     return tech_pvt->udp_socket;
1815 :     }
1816 :    
1817 : jtarlton 195
1818 : amartin 128 static int tech_activate(private_object *tech_pvt)
1819 : amartin 125 {
1820 : jtarlton 242 int retry_activate_call = 0;
1821 : amartin 125 woomera_message wmsg;
1822 :     char *callid;
1823 : jtarlton 242 int err = 0;
1824 : amartin 125
1825 : jtarlton 242 memset(&wmsg, 0, sizeof(wmsg));
1826 :    
1827 : amartin 125 retry_activate_again:
1828 : amartin 128
1829 : amartin 125 if (!tech_pvt) {
1830 : jtarlton 195 ast_log(LOG_ERROR, "Critical Error: Where's my tech_pvt?\n");
1831 :     return -1;
1832 :     }
1833 : amartin 125
1834 :     if((connect_woomera(&tech_pvt->command_channel, tech_pvt->profile, 0)) > -1) {
1835 :     if (globals.debug > 2) {
1836 : amartin 128 ast_log(LOG_NOTICE,
1837 : jtarlton 195 "Connected to woomera! chfd=%i port=%i dir=%s callid=%s Count=%i tpvt=%p\n",
1838 :     tech_pvt->command_channel,
1839 :     tech_pvt->port,
1840 :     ast_test_flag(tech_pvt, TFLAG_OUTBOUND)?"OUT":"IN",
1841 :     ast_test_flag(tech_pvt, TFLAG_OUTBOUND)?"N/A" :
1842 :     tech_pvt->callid,
1843 :     tech_pvt->call_count,
1844 :     tech_pvt);
1845 : amartin 125 }
1846 :     } else {
1847 :    
1848 :     if (retry_activate_call <= 3) {
1849 :     retry_activate_call++;
1850 :     goto retry_activate_again;
1851 :     }
1852 : amartin 128
1853 : amartin 125 if (globals.debug > 1 && option_verbose > 1) {
1854 :     ast_log(LOG_ERROR, "Error: %s call connect to TCP/Woomera Server! tpvt=%p: %s\n",
1855 : jtarlton 195 ast_test_flag(tech_pvt, TFLAG_OUTBOUND)?"Out":"In",
1856 : jtarlton 255 tech_pvt, strerror(errno));
1857 : amartin 125 }
1858 :     goto tech_activate_failed;
1859 :     }
1860 :    
1861 : jtarlton 195 retry_activate_call = 0;
1862 : amartin 125
1863 :     if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
1864 :    
1865 : jtarlton 195 if (strlen(tech_pvt->proto) > 1) {
1866 :    
1867 :     if (tech_pvt->rtp_enable) {
1868 : amartin 231 err = woomera_printf(tech_pvt->profile,
1869 : amartin 128 tech_pvt->command_channel,
1870 :     "CALL %s:%s%s"
1871 :     "RTP-Audio: %s:%d%s"
1872 : jtarlton 277 "RTP-Audio-Format: ULAW"
1873 : amartin 128 "Local-Name: %s!%s%s"
1874 :     "Local-Number:%s%s"
1875 :     "Presentation:%d%s"
1876 :     "Screening:%d%s"
1877 :     "Bearer-Cap:%s%s"
1878 :     "uil1p:%s%s"
1879 :     "RDNIS:%s%s",
1880 :     tech_pvt->proto,
1881 :     tech_pvt->dest,
1882 :     WOOMERA_LINE_SEPARATOR,
1883 :     tech_pvt->profile->audio_ip,
1884 :     tech_pvt->port,
1885 :     WOOMERA_LINE_SEPARATOR,
1886 : jtarlton 277 /* TODO use real format */
1887 : amartin 128 WOOMERA_LINE_SEPARATOR,
1888 :     tech_pvt->cid_name,
1889 :     tech_pvt->cid_num,
1890 :     WOOMERA_LINE_SEPARATOR,
1891 :     tech_pvt->cid_num,
1892 :     WOOMERA_LINE_SEPARATOR,
1893 : jtarlton 277 (tech_pvt->cid_pres >> 5) & 0x7,
1894 : amartin 128 WOOMERA_LINE_SEPARATOR,
1895 : jtarlton 277 tech_pvt->cid_pres & 0xF,
1896 : amartin 128 WOOMERA_LINE_SEPARATOR,
1897 :     woomera_ast_transfercap_to_string(tech_pvt->capability),
1898 :     WOOMERA_LINE_SEPARATOR,
1899 :     woomera_ast_coding_to_string(tech_pvt->coding),
1900 :     WOOMERA_LINE_SEPARATOR,
1901 : jtarlton 277 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
1902 : amartin 128 WOOMERA_RECORD_SEPARATOR
1903 :     );
1904 : jtarlton 195 } else {
1905 : amartin 231 err = woomera_printf(tech_pvt->profile,
1906 : amartin 128 tech_pvt->command_channel,
1907 :     "CALL %s:%s%s"
1908 :     "Raw-Audio: %s:%d%s"
1909 :     "Local-Name: %s!%s%s"
1910 :     "Local-Number:%s%s"
1911 :     "Presentation:%d%s"
1912 :     "Screening:%d%s"
1913 :     "Bearer-Cap:%s%s"
1914 :     "uil1p:%s%s"
1915 :     "RDNIS:%s%s",
1916 :     tech_pvt->proto,
1917 :     tech_pvt->dest,
1918 :     WOOMERA_LINE_SEPARATOR,
1919 :     tech_pvt->profile->audio_ip,
1920 :     tech_pvt->port,
1921 :     WOOMERA_LINE_SEPARATOR,
1922 :     tech_pvt->cid_name,
1923 :     tech_pvt->cid_num,
1924 :     WOOMERA_LINE_SEPARATOR,
1925 :     tech_pvt->cid_num,
1926 :     WOOMERA_LINE_SEPARATOR,
1927 : jtarlton 277 (tech_pvt->cid_pres >> 5) & 0x7,
1928 : amartin 128 WOOMERA_LINE_SEPARATOR,
1929 :     tech_pvt->cid_pres&0xF,
1930 :     WOOMERA_LINE_SEPARATOR,
1931 :     woomera_ast_transfercap_to_string(tech_pvt->capability),
1932 :     WOOMERA_LINE_SEPARATOR,
1933 :     woomera_ast_coding_to_string(tech_pvt->coding),
1934 :     WOOMERA_LINE_SEPARATOR,
1935 : jtarlton 277 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
1936 : amartin 128 WOOMERA_RECORD_SEPARATOR
1937 :     );
1938 :     }
1939 :     }
1940 :     else
1941 :     {
1942 : jtarlton 195 if (tech_pvt->rtp_enable) {
1943 : amartin 231 err = woomera_printf(tech_pvt->profile,
1944 : amartin 128 tech_pvt->command_channel,
1945 :     "CALL %s%s"
1946 :     "RTP-Audio: %s:%d%s"
1947 : jtarlton 277 "RTP-Audio-Format: ULAW"
1948 : amartin 128 "Local-Name: %s!%s%s"
1949 :     "Local-Number:%s%s"
1950 :     "Presentation:%d%s"
1951 :     "Screening:%d%s"
1952 :     "Bearer-Cap:%s%s"
1953 :     "uil1p:%s%s"
1954 :     "RDNIS:%s%s",
1955 :     tech_pvt->dest,
1956 :     WOOMERA_LINE_SEPARATOR,
1957 :     tech_pvt->profile->audio_ip,
1958 :     tech_pvt->port,
1959 :     WOOMERA_LINE_SEPARATOR,
1960 : jtarlton 277 /* TODO use real format */
1961 : amartin 128 WOOMERA_LINE_SEPARATOR,
1962 :     tech_pvt->cid_name,
1963 :     tech_pvt->cid_num,
1964 :     WOOMERA_LINE_SEPARATOR,
1965 :     tech_pvt->cid_num,
1966 :     WOOMERA_LINE_SEPARATOR,
1967 : jtarlton 277 (tech_pvt->cid_pres >> 5) & 0x7,
1968 : amartin 128 WOOMERA_LINE_SEPARATOR,
1969 : jtarlton 277 tech_pvt->cid_pres & 0xF,
1970 : amartin 128 WOOMERA_LINE_SEPARATOR,
1971 :     woomera_ast_transfercap_to_string(tech_pvt->capability),
1972 :     WOOMERA_LINE_SEPARATOR,
1973 :     woomera_ast_coding_to_string(tech_pvt->coding),
1974 :     WOOMERA_LINE_SEPARATOR,
1975 : jtarlton 277 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
1976 : amartin 128 WOOMERA_RECORD_SEPARATOR
1977 :     );
1978 : jtarlton 195 } else {
1979 : amartin 231 err = woomera_printf(tech_pvt->profile,
1980 : amartin 128 tech_pvt->command_channel,
1981 :     "CALL %s%s"
1982 :     "Raw-Audio: %s:%d%s"
1983 :     "Local-Name: %s!%s%s"
1984 :     "Local-Number:%s%s"
1985 :     "Presentation:%d%s"
1986 :     "Screening:%d%s"
1987 :     "Bearer-Cap:%s%s"
1988 :     "uil1p:%s%s"
1989 :     "RDNIS:%s%s",
1990 :     tech_pvt->dest,
1991 :     WOOMERA_LINE_SEPARATOR,
1992 :     tech_pvt->profile->audio_ip,
1993 :     tech_pvt->port,
1994 :     WOOMERA_LINE_SEPARATOR,
1995 :     tech_pvt->cid_name,
1996 :     tech_pvt->cid_num,
1997 :     WOOMERA_LINE_SEPARATOR,
1998 :     tech_pvt->cid_num,
1999 :     WOOMERA_LINE_SEPARATOR,
2000 :     (tech_pvt->cid_pres>>5)&0x7,
2001 :     WOOMERA_LINE_SEPARATOR,
2002 :     tech_pvt->cid_pres&0xF,
2003 :     WOOMERA_LINE_SEPARATOR,
2004 :     woomera_ast_transfercap_to_string(tech_pvt->capability),
2005 :     WOOMERA_LINE_SEPARATOR,
2006 :     woomera_ast_coding_to_string(tech_pvt->coding),
2007 :     WOOMERA_LINE_SEPARATOR,
2008 : jtarlton 277 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "",
2009 : amartin 128 WOOMERA_RECORD_SEPARATOR
2010 :     );
2011 :     }
2012 : jtarlton 169 }
2013 : amartin 125
2014 : amartin 231 if (err < 0) {
2015 :     if (globals.debug > 2) {
2016 : jtarlton 255 ast_log(LOG_NOTICE, "Outbound call failed -write msg Call %s tpvt=%p\n",
2017 : jtarlton 242 tech_pvt->callid,tech_pvt);
2018 : amartin 231 }
2019 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
2020 : amartin 231 goto tech_activate_failed;
2021 :     }
2022 : amartin 128
2023 : jtarlton 242 err = woomera_message_parse_wait(tech_pvt,&wmsg);
2024 : amartin 231 if (err < 0) {
2025 :     if (globals.debug > 2) {
2026 : jtarlton 255 ast_log(LOG_NOTICE, "Outbound call failed -wait parse Call %s tpvt=%p\n",
2027 : jtarlton 242 tech_pvt->callid,tech_pvt);
2028 : amartin 231 }
2029 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2030 :     goto tech_activate_failed;
2031 :     }
2032 : amartin 157
2033 : amartin 231 if (woomera_message_reply_ok(&wmsg) != 0) {
2034 :     if (globals.debug > 2) {
2035 : jtarlton 255 ast_log(LOG_NOTICE, "Outbound call failed reply failed Call %s tpvt=%p\n",
2036 : amartin 231 tech_pvt->callid,tech_pvt);
2037 :     }
2038 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2039 :     }
2040 : jtarlton 235
2041 : amartin 231 callid = woomera_message_header(&wmsg, "Unique-Call-Id");
2042 :     if (callid) {
2043 : jtarlton 242 ast_copy_string(tech_pvt->callid, callid, sizeof(wmsg.callid));
2044 : amartin 231 }
2045 : jtarlton 235
2046 : amartin 125 } else {
2047 :     ast_set_flag(tech_pvt, TFLAG_PARSE_INCOMING);
2048 :     if (globals.debug > 2) {
2049 : amartin 231 ast_log(LOG_NOTICE, "Incoming Call %s tpvt=%p\n",
2050 : jtarlton 242 tech_pvt->callid, tech_pvt);
2051 : amartin 125 }
2052 : jtarlton 235
2053 : jtarlton 242 err = woomera_printf(tech_pvt->profile,
2054 :     tech_pvt->command_channel,
2055 :     "PROCEED %s%s"
2056 :     "Unique-Call-Id: %s%s",
2057 :     tech_pvt->callid,
2058 :     WOOMERA_LINE_SEPARATOR,
2059 :     tech_pvt->callid,
2060 :     WOOMERA_RECORD_SEPARATOR);
2061 : amartin 128
2062 : amartin 231 if (err < 0) {
2063 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2064 :     goto tech_activate_failed;
2065 :     }
2066 :    
2067 : jtarlton 242 err = woomera_message_parse_wait(tech_pvt, &wmsg);
2068 : amartin 231 if (err < 0) {
2069 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
2070 : amartin 231 goto tech_activate_failed;
2071 : amartin 125 }
2072 : amartin 231
2073 :     if (woomera_message_reply_ok(&wmsg) != 0) {
2074 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2075 :     /* Do not hangup on main because
2076 :     * socket connection has been
2077 :     * established */
2078 :     }
2079 : amartin 125 }
2080 :    
2081 :     if (globals.debug > 2) {
2082 : jtarlton 242 ast_log(LOG_NOTICE, "TECH ACTIVATE OK tech_pvt=%p\n", tech_pvt);
2083 : amartin 125 }
2084 :     return 0;
2085 :    
2086 :     tech_activate_failed:
2087 : jtarlton 195
2088 : amartin 125 if (globals.debug > 2) {
2089 : jtarlton 242 ast_log(LOG_NOTICE, "TECH ACTIVATE FAILED tech_pvt=%p\n", tech_pvt);
2090 : amartin 125 }
2091 : amartin 128
2092 : amartin 125 woomera_close_socket(&tech_pvt->command_channel);
2093 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2094 :    
2095 : amartin 128 /* At this point we cannot estabilsh a woomera
2096 :     * socket to the server. The server still doesnt know
2097 : amartin 125 * about the incoming call that is now pending.
2098 : amartin 128 * We must send a message to server to hangup the call */
2099 : amartin 125
2100 :     if (globals.debug > 2) {
2101 : jtarlton 195 ast_log(LOG_NOTICE, "Error: %s Call %s tpvt=%p Failed!\n",
2102 :     ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT":"IN",
2103 :     tech_pvt->callid,tech_pvt);
2104 : amartin 125 }
2105 :    
2106 :     return -1;
2107 :     }
2108 :    
2109 : jtarlton 260
2110 : amartin 128 static int tech_init(private_object *tech_pvt, woomera_profile *profile, int flags)
2111 : amartin 125 {
2112 : amartin 128 struct sockaddr_in us;
2113 : amartin 125 struct ast_channel *self = tech_get_owner(tech_pvt);
2114 :    
2115 :     gettimeofday(&tech_pvt->started, NULL);
2116 :    
2117 :     if (profile) {
2118 :     tech_pvt->profile = profile;
2119 :     } else {
2120 : jtarlton 238 ast_log(LOG_ERROR, "Tech init no profile!\n");
2121 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
2122 :     return -1;
2123 :     }
2124 :    
2125 : jtarlton 280 if (profile && profile->rtp_enable) {
2126 : amartin 128 tech_pvt->rtp_enable = 1;
2127 : jtarlton 280 } else {
2128 : amartin 128 tech_pvt->rtp_enable = 0;
2129 :     }
2130 :    
2131 : amartin 125 ast_set_flag(tech_pvt, flags);
2132 : amartin 128
2133 : jtarlton 235 if (tech_pvt->rtp_enable)
2134 : amartin 128 {
2135 :     tech_pvt->rtp = create_rtp(tech_pvt->profile->audio_ip);
2136 : jtarlton 195 if (tech_pvt->rtp) {
2137 : amartin 128 self->fds[0] = ast_rtp_fd(tech_pvt->rtp);
2138 : jtarlton 239 ast_rtp_get_us(tech_pvt->rtp, &us);
2139 : jtarlton 235 tech_pvt->port = ntohs(us.sin_port);
2140 : jtarlton 239 ast_log(LOG_DEBUG, "Created rtp audio. port=%d\n", tech_pvt->port);
2141 : jtarlton 195 } else {
2142 : jtarlton 239 ast_log(LOG_ERROR, "Failed to create rtp audio\n");
2143 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
2144 :     return -1;
2145 :     }
2146 : amartin 128
2147 :     tech_pvt->vrtp = create_rtp(tech_pvt->profile->audio_ip);
2148 : jtarlton 195 if (tech_pvt->vrtp) {
2149 : amartin 128 self->fds[1] = ast_rtp_fd(tech_pvt->vrtp);
2150 : jtarlton 239 ast_rtp_get_us(tech_pvt->vrtp, &us);
2151 : jtarlton 235 tech_pvt->vport = ntohs(us.sin_port);
2152 : jtarlton 239 ast_verbose("Created rtp video. port=%d\n", tech_pvt->vport);
2153 : jtarlton 195 } else {
2154 : jtarlton 239 ast_log(LOG_ERROR, "Failed to create rtp video\n");
2155 : amartin 128 ast_set_flag(tech_pvt, TFLAG_ABORT);
2156 :     return -1;
2157 :     }
2158 : jtarlton 280 } else {
2159 : amartin 128 if (tech_pvt->udp_socket < 0) {
2160 :     int rc;
2161 : jtarlton 235 rc = tech_create_read_socket(tech_pvt);
2162 : jtarlton 280 if (rc < 0) {
2163 : jtarlton 238 ast_log(LOG_ERROR, "Failed to create UDP Socket (%p)! %s\n",
2164 : jtarlton 239 tech_pvt, strerror(errno));
2165 : amartin 128 ast_set_flag(tech_pvt, TFLAG_ABORT);
2166 :     return -1;
2167 :     }
2168 :     }
2169 :     }
2170 : amartin 125
2171 :     ast_set_flag(tech_pvt, flags);
2172 :    
2173 :     tech_pvt->capability = self->transfercapability;
2174 : amartin 128
2175 : amartin 125 tech_pvt->coding = profile->coding;
2176 : amartin 128 tech_pvt->videocoding = profile->videocoding;
2177 :     self->nativeformats = tech_pvt->coding | tech_pvt->videocoding;
2178 :     self->writeformat = self->rawwriteformat = self->readformat = tech_pvt->coding | tech_pvt->videocoding;
2179 : amartin 125 tech_pvt->frame.subclass = tech_pvt->coding;
2180 :    
2181 :     ast_clear_flag(tech_pvt, TFLAG_CONFIRM_ANSWER);
2182 :     ast_clear_flag(tech_pvt, TFLAG_CONFIRM_ANSWER_ENABLED);
2183 :     ast_clear_flag(tech_pvt, TFLAG_ANSWER_RECEIVED);
2184 :    
2185 :     if (profile && profile->faxdetect) {
2186 : jtarlton 239 tech_pvt->faxdetect = 1;
2187 : amartin 125 }
2188 : amartin 128
2189 : amartin 125 if (profile->dtmf_enable) {
2190 : amartin 128
2191 : jtarlton 239 tech_pvt->dsp_features = 0;
2192 : amartin 125 tech_pvt->dsp = ast_dsp_new();
2193 :     if (tech_pvt->dsp) {
2194 :     #if 0
2195 :     i->dsp_features = features & ~DSP_PROGRESS_TALK;
2196 : amartin 128
2197 : amartin 125 /* We cannot do progress detection until receives PROGRESS message */
2198 :     if (i->outgoing && (i->sig == SIG_PRI)) {
2199 :     /* Remember requested DSP features, don't treat
2200 :     talking as ANSWER */
2201 :     features = 0;
2202 :     }
2203 :     #endif
2204 :     tech_pvt->dsp_features |= DSP_FEATURE_DTMF_DETECT;
2205 :     //tech_pvt->dsp_features |= DSP_FEATURE_BUSY_DETECT;
2206 :     //tech_pvt->dsp_features |= DSP_FEATURE_CALL_PROGRESS;
2207 :     if (tech_pvt->faxdetect) {
2208 :     tech_pvt->dsp_features |= DSP_FEATURE_FAX_DETECT;
2209 : amartin 128 }
2210 : amartin 125 ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
2211 :     ast_dsp_digitmode(tech_pvt->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
2212 : jtarlton 239 tech_pvt->ast_dsp = 1;
2213 : amartin 125 #if 0
2214 :     if (!ast_strlen_zero(progzone))
2215 :     ast_dsp_set_call_progress_zone(tech_pvt->dsp, progzone);
2216 :     if (i->busydetect && CANBUSYDETECT(i)) {
2217 :     ast_dsp_set_busy_count(tech_pvt->dsp, i->busycount);
2218 : jtarlton 239 ast_dsp_set_busy_pattern(tech_pvt->dsp, i->busy_tonelength, i->busy_quietlength);
2219 : amartin 128 }
2220 : amartin 125 #endif
2221 :     }
2222 :     }
2223 :    
2224 :     if (profile->jb_enable) {
2225 :     #if defined AST_JB
2226 :     /* Assign default jb conf to the new zt_pvt */
2227 :     memcpy(&tech_pvt->jbconf, &global_jbconf, sizeof(struct ast_jb_conf));
2228 :     ast_jb_configure(self, &tech_pvt->jbconf);
2229 : amartin 128
2230 : amartin 125 if (globals.debug > 1 && option_verbose > 10) {
2231 :     ast_log(LOG_NOTICE, "%s: Cfg JitterBuffer (F=%i MS=%li Rs=%li Impl=%s)\n",
2232 :     self->name,
2233 :     tech_pvt->jbconf.flags,
2234 :     tech_pvt->jbconf.max_size,
2235 :     tech_pvt->jbconf.resync_threshold,
2236 :     tech_pvt->jbconf.impl);
2237 :     }
2238 :     #else
2239 :     ast_log(LOG_ERROR, "Asterisk Jitter Buffer Not Compiled!\n");
2240 :     #endif
2241 : amartin 128 }
2242 : amartin 125
2243 : amartin 128 /* Asterisk being asterisk and all allows approx 1 nanosecond
2244 : amartin 125 * to try and establish a connetion here before it starts crying.
2245 :     * Now asterisk, being unsure of it's self will not enforce a lock while we work
2246 :     * and after even a 1 second delay it will give up on the lock and mess everything up
2247 : amartin 128 * This stems from the fact that asterisk will scan it's list of channels constantly for
2248 : amartin 125 * silly reasons like tab completion and cli output.
2249 :     *
2250 :     * Anyway, since we've already spent that nanosecond with the previous line of code
2251 :     * tech_create_read_socket(tech_pvt); to setup a read socket
2252 : jtarlton 235 * which, by the way, asterisk insists we have before going any furthur.
2253 : amartin 125 * So, in short, we are between a rock and a hard place and asterisk wants us to open a socket here
2254 :     * but it too impaitent to wait for us to make sure it's ready so in the case of outgoing calls
2255 : jtarlton 235 * we will defer the rest of the socket establishment process to the monitor thread. This is, of course, common
2256 : amartin 125 * knowledge since asterisk abounds in documentation right?, sorry to bother you with all this!
2257 :     */
2258 :     if (globals.more_threads) {
2259 :     int err;
2260 :     ast_set_flag(tech_pvt, TFLAG_ACTIVATE);
2261 :     /* we're gonna try "wasting" a thread to do a better realtime monitoring */
2262 : jtarlton 238 err = launch_tech_thread(tech_pvt);
2263 : amartin 125 if (err) {
2264 : jtarlton 238 ast_log(LOG_ERROR, "Failed to launch tech control thread\n");
2265 : amartin 125 ast_clear_flag(tech_pvt, TFLAG_ACTIVATE);
2266 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2267 :     return -1;
2268 : amartin 128 }
2269 :    
2270 : amartin 125 } else {
2271 :     if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
2272 :     ast_set_flag(tech_pvt, TFLAG_ACTIVATE);
2273 :     } else {
2274 :     tech_activate(tech_pvt);
2275 :     }
2276 :     }
2277 : amartin 128
2278 :    
2279 : amartin 125 if (globals.debug > 2) {
2280 :     ast_log(LOG_NOTICE, "TECH INIT tech_pvt=%p c=%p (use=%i)\n",
2281 : jtarlton 280 tech_pvt, tech_pvt->owner,usecount());
2282 : amartin 125 }
2283 : amartin 128
2284 : amartin 125 return 0;
2285 :     }
2286 :    
2287 :    
2288 : amartin 128 static void tech_destroy(private_object *tech_pvt, struct ast_channel *owner)
2289 : amartin 125 {
2290 :     ASTOBJ_CONTAINER_UNLINK(&private_object_list, tech_pvt);
2291 :    
2292 :     ast_set_flag(tech_pvt, TFLAG_DESTROY);
2293 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2294 :    
2295 :     if (globals.debug > 2) {
2296 :     ast_log(LOG_NOTICE, "Tech Destroy callid=%s tpvt=%p %s/%d\n",
2297 : jtarlton 195 tech_pvt->callid,
2298 :     tech_pvt,
2299 :     tech_pvt->profile ? tech_pvt->profile->audio_ip : "NA",
2300 :     tech_pvt->port);
2301 : amartin 125 }
2302 : amartin 128
2303 : amartin 125 if (tech_pvt->profile && tech_pvt->command_channel > -1) {
2304 :    
2305 :     if (globals.debug > 1 && option_verbose > 1) {
2306 : jtarlton 235 ast_log(LOG_NOTICE, "Tech Destroy sending HANGUP %s\n", tech_pvt->callid);
2307 : amartin 125 }
2308 : amartin 128 woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2309 : jtarlton 280 "HANGUP %s%scause: %s%s"
2310 :     "Q931-Cause-Code: %d%s"
2311 :     "Reason: %d%s"
2312 :     "Unique-Call-Id: %s%s",
2313 : jtarlton 195 tech_pvt->callid,
2314 :     WOOMERA_LINE_SEPARATOR,
2315 :     tech_pvt->ds,
2316 :     WOOMERA_LINE_SEPARATOR,
2317 :     tech_pvt->pri_cause,
2318 :     WOOMERA_LINE_SEPARATOR,
2319 : jtarlton 280 tech_pvt->pri_cause,
2320 :     WOOMERA_LINE_SEPARATOR,
2321 : jtarlton 195 tech_pvt->callid,
2322 :     WOOMERA_RECORD_SEPARATOR);
2323 :    
2324 : amartin 128 woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2325 : jtarlton 280 "BYE%s"
2326 : jtarlton 195 "Unique-Call-Id: %s%s",
2327 :     WOOMERA_LINE_SEPARATOR,
2328 :     tech_pvt->callid,
2329 :     WOOMERA_RECORD_SEPARATOR);
2330 :    
2331 : amartin 125 woomera_close_socket(&tech_pvt->command_channel);
2332 :     }
2333 :    
2334 :     woomera_close_socket(&tech_pvt->command_channel);
2335 :    
2336 : jtarlton 235 if (tech_pvt->rtp_enable) {
2337 :     if (tech_pvt->rtp) {
2338 : jtarlton 238 if (globals.debug > 2) {
2339 :     ast_log(LOG_NOTICE,"Tech Destroy ending audio rtp session\n");
2340 :     }
2341 : jtarlton 235 ast_rtp_destroy(tech_pvt->rtp);
2342 :     }
2343 :     if (tech_pvt->vrtp) {
2344 : jtarlton 238 if (globals.debug > 2) {
2345 :     ast_log(LOG_NOTICE,"Tech Destroy ending video rtp session\n");
2346 :     }
2347 : jtarlton 235 ast_rtp_destroy(tech_pvt->vrtp);
2348 :     }
2349 :     } else {
2350 :     woomera_close_socket(&tech_pvt->udp_socket);
2351 :     }
2352 : amartin 125
2353 :     /* Tech profile is allowed to be null in case the call
2354 :     * is blocked from the call_count */
2355 : amartin 128
2356 : amartin 125 #if 0
2357 :     ast_log(LOG_NOTICE, "---- Call END %p %s ----------------------------\n",
2358 : jtarlton 235 tech_pvt, tech_pvt->callid);
2359 : amartin 125 #endif
2360 :    
2361 :     if (owner) {
2362 :     if (globals.debug > 2) {
2363 : jtarlton 238 ast_log(LOG_NOTICE, "Tech Destroy doing AST HANGUP!\n");
2364 : amartin 125 }
2365 :     owner->tech_pvt = NULL;
2366 : jtarlton 195 tech_pvt->owner = NULL;
2367 : amartin 125 ast_hangup(owner);
2368 :     }
2369 : jtarlton 235 tech_pvt->owner = NULL;
2370 : amartin 125
2371 :     tech_count--;
2372 : jtarlton 235 if (tech_pvt->dsp) {
2373 : amartin 125 tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT;
2374 : jtarlton 195 ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
2375 : jtarlton 235 tech_pvt->ast_dsp = 0;
2376 : amartin 125 ast_free(tech_pvt->dsp);
2377 : jtarlton 195 tech_pvt->dsp = NULL;
2378 : amartin 125 }
2379 :    
2380 :     if (globals.debug > 2) {
2381 :     ast_log(LOG_NOTICE, "DESTROY Exit tech_pvt=%p (use=%i)\n",
2382 : jtarlton 235 tech_pvt, usecount());
2383 : amartin 125 }
2384 : amartin 128
2385 : amartin 125 ast_mutex_destroy(&tech_pvt->iolock);
2386 :     ast_mutex_destroy(&tech_pvt->event_queue.lock);
2387 :    
2388 : amartin 128 if (tech_pvt->cid_rdnis) {
2389 : amartin 125 ast_free(tech_pvt->cid_rdnis);
2390 : jtarlton 195 tech_pvt->cid_rdnis = NULL;
2391 : amartin 125 }
2392 :    
2393 : amartin 128 ast_free(tech_pvt);
2394 : jtarlton 235
2395 : amartin 125 ast_mutex_lock(&usecnt_lock);
2396 :     usecnt--;
2397 :     ast_mutex_unlock(&usecnt_lock);
2398 :     }
2399 :    
2400 :     #if 0
2401 :    
2402 : amartin 128 static int waitfor_socket(int fd, int timeout)
2403 : amartin 125 {
2404 :     struct pollfd pfds[1];
2405 :     int res;
2406 :     int errflags = (POLLERR | POLLHUP | POLLNVAL);
2407 : amartin 128
2408 : amartin 125 if (fd < 0) {
2409 :     return -1;
2410 :     }
2411 :    
2412 :     memset(&pfds[0], 0, sizeof(pfds[0]));
2413 :     pfds[0].fd = fd;
2414 :     pfds[0].events = POLLIN | errflags;
2415 :     res = poll(pfds, 1, timeout);
2416 :     if (res > 0) {
2417 :     if ((pfds[0].revents & errflags)) {
2418 :     res = -1;
2419 :     } else if ((pfds[0].revents & POLLIN)) {
2420 :     res = 1;
2421 :     } else {
2422 :     ast_log(LOG_ERROR, "System Error: Poll Event Error no event!\n");
2423 :     res = -1;
2424 :     }
2425 :     }
2426 : amartin 128
2427 : amartin 125 return res;
2428 :     }
2429 :    
2430 :     #else
2431 :    
2432 : amartin 128 static int waitfor_socket(int fd, int timeout)
2433 : amartin 125 {
2434 :     struct pollfd pfds[1];
2435 :     int res;
2436 :    
2437 :     if (fd < 0) {
2438 :     return -1;
2439 :     }
2440 :    
2441 :     memset(&pfds[0], 0, sizeof(pfds[0]));
2442 :     pfds[0].fd = fd;
2443 :     pfds[0].events = POLLIN | POLLERR;
2444 :     res = poll(pfds, 1, timeout);
2445 :     if (res > 0) {
2446 :     if ((pfds[0].revents & POLLERR)) {
2447 :     res = -1;
2448 :     } else if((pfds[0].revents & POLLIN)) {
2449 :     res = 1;
2450 :     } else {
2451 :     res = -1;
2452 :     }
2453 :     }
2454 : amartin 128
2455 : amartin 125 return res;
2456 :     }
2457 :    
2458 :     #endif
2459 :    
2460 :    
2461 : amartin 128 static void *tech_monitor_thread(void *obj)
2462 : amartin 125 {
2463 :     private_object *tech_pvt;
2464 :     woomera_message wmsg;
2465 :     char tcallid[WOOMERA_STRLEN];
2466 : jtarlton 255 int aborted = 0;
2467 : amartin 125
2468 :     int res = 0;
2469 :    
2470 :     tech_pvt = obj;
2471 : amartin 128
2472 : amartin 125 if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP)) {
2473 :     ast_log(LOG_NOTICE, "Tech Monitor: Call stopped before thread up!\n");
2474 :     return NULL;
2475 : amartin 128 }
2476 : amartin 125
2477 :     memset(tcallid,0,sizeof(tcallid));
2478 :     memset(&wmsg,0,sizeof(wmsg));
2479 :    
2480 :     if (globals.debug > 2) {
2481 : jtarlton 238 ast_log(LOG_NOTICE, "IN THREAD %s rxgain=%f txgain=%f\n",
2482 : jtarlton 195 tech_pvt->callid,
2483 :     tech_pvt->profile->rxgain_val,
2484 :     tech_pvt->profile->txgain_val);
2485 : amartin 125 }
2486 :     ast_mutex_lock(&tech_pvt->profile->call_count_lock);
2487 :     if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
2488 :     tech_pvt->profile->call_out++;
2489 :     } else {
2490 :     tech_pvt->profile->call_in++;
2491 :     }
2492 :     tech_pvt->profile->call_count++;
2493 :     ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
2494 :    
2495 :     for(;;) {
2496 : amartin 128
2497 : amartin 125 if (globals.panic) {
2498 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2499 :     }
2500 :    
2501 :     if (!tech_pvt->owner) {
2502 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2503 :     if (globals.debug > 2) {
2504 : jtarlton 195 ast_log(LOG_NOTICE, "Thread lost Owner Chan %s %p\n",
2505 :     tech_pvt->callid,
2506 : jtarlton 238 tech_pvt);
2507 : amartin 125 }
2508 :     }
2509 :    
2510 : amartin 128
2511 : amartin 125 /* finish the deferred crap asterisk won't allow us to do live */
2512 :     if (ast_test_flag(tech_pvt, TFLAG_ABORT)) {
2513 : jtarlton 235 int ast_hangup = 0;
2514 : amartin 125 struct woomera_profile *profile = tech_pvt->profile;;
2515 :    
2516 :     if (globals.debug > 2) {
2517 : amartin 128 ast_log(LOG_NOTICE, "ABORT GOT HANGUP CmdCh=%i %s %s/%i\n",
2518 : jtarlton 195 tech_pvt->command_channel, tech_pvt->callid,
2519 :     tech_pvt->profile ? tech_pvt->profile->audio_ip : "N/A",
2520 :     tech_pvt->port);
2521 : amartin 125 }
2522 :    
2523 : jtarlton 235 aborted |= 1;
2524 : amartin 125
2525 :     /* Check for queued events, looking for HANGUP messages,
2526 :     so we can return proper hangup cause */
2527 :     for (;;) {
2528 :     if ((res = woomera_dequeue_event(&tech_pvt->event_queue, &wmsg))) {
2529 : jtarlton 235 woomera_check_event(tech_pvt, res, &wmsg);
2530 : amartin 125 } else {
2531 :     break;
2532 :     }
2533 :     }
2534 : amartin 128
2535 : amartin 125 ast_mutex_lock(&tech_pvt->profile->call_count_lock);
2536 :     tech_pvt->profile->call_count--;
2537 :     ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
2538 :    
2539 :     if (tech_pvt->profile && tech_pvt->command_channel > -1) {
2540 :    
2541 :     if (globals.debug > 2) {
2542 : jtarlton 195 ast_log(LOG_NOTICE, "ABORT sent HANGUP on %s %p\n",
2543 :     tech_pvt->callid,
2544 :     tech_pvt);
2545 : amartin 125 }
2546 : jtarlton 195 aborted |= 2;
2547 :     woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2548 : jtarlton 280 "HANGUP %s%scause: %s%s"
2549 :     "Q931-Cause-Code: %d%s"
2550 :     "Reason: %d%s"
2551 :     "Unique-Call-Id: %s%s",
2552 : jtarlton 195 tech_pvt->callid,
2553 :     WOOMERA_LINE_SEPARATOR,
2554 :     tech_pvt->ds,
2555 :     WOOMERA_LINE_SEPARATOR,
2556 :     tech_pvt->pri_cause,
2557 :     WOOMERA_LINE_SEPARATOR,
2558 : jtarlton 280 tech_pvt->pri_cause,
2559 :     WOOMERA_LINE_SEPARATOR,
2560 : jtarlton 195 tech_pvt->callid,
2561 :     WOOMERA_RECORD_SEPARATOR);
2562 :    
2563 :     woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2564 : jtarlton 280 "BYE%s"
2565 : jtarlton 195 "Unique-Call-Id: %s%s",
2566 :     WOOMERA_LINE_SEPARATOR,
2567 :     tech_pvt->callid,
2568 :     WOOMERA_RECORD_SEPARATOR);
2569 :    
2570 : amartin 125 woomera_close_socket(&tech_pvt->command_channel);
2571 :     }
2572 :    
2573 : jtarlton 235 if (tech_pvt->rtp_enable) {
2574 :     if (tech_pvt->rtp) {
2575 : jtarlton 238 if (globals.debug > 2) {
2576 :     ast_log(LOG_NOTICE,"Tech Thread - ending audio rtp session\n");
2577 :     }
2578 : jtarlton 235 ast_rtp_destroy(tech_pvt->rtp);
2579 :     tech_pvt->rtp = 0;
2580 :     }
2581 :     if (tech_pvt->vrtp) {
2582 : jtarlton 238 if (globals.debug > 2) {
2583 :     ast_log(LOG_NOTICE,"Tech Thread - ending video rtp session\n");
2584 :     }
2585 : jtarlton 235 ast_rtp_destroy(tech_pvt->vrtp);
2586 :     tech_pvt->vrtp = 0;
2587 :     }
2588 :     } else {
2589 : amartin 125 woomera_close_socket(&tech_pvt->udp_socket);
2590 :     }
2591 :    
2592 :     if (globals.debug > 2) {
2593 :     ast_log(LOG_NOTICE,"Tech Thread - Hanging up channel\n");
2594 :     }
2595 :     ast_mutex_lock(&tech_pvt->iolock);
2596 : jtarlton 195 while (tech_pvt->owner && my_ast_channel_trylock(tech_pvt->owner)) {
2597 : amartin 125 if (globals.debug > 2) {
2598 : jtarlton 238 ast_log(LOG_NOTICE,"Tech Thread - Hanging up channel - deadlock avoidance\n");
2599 : amartin 125 }
2600 :     DEADLOCK_AVOIDANCE(&tech_pvt->iolock);
2601 : amartin 128 }
2602 : amartin 125
2603 :     if (tech_pvt->owner) {
2604 :     struct ast_channel *owner = tech_pvt->owner;
2605 :     if (ast_test_flag(tech_pvt, TFLAG_PBX) || owner->pbx) {
2606 : jtarlton 235 aborted |= 4;
2607 : amartin 125
2608 :     if (globals.debug > 2) {
2609 :     ast_log(LOG_NOTICE, "ABORT calling hangup on %s t=%p c=%p UP=%d\n",
2610 :     tech_pvt->callid,
2611 :     tech_pvt,
2612 :     owner,
2613 :     ast_test_flag(tech_pvt, TFLAG_UP));
2614 :     }
2615 :    
2616 :     /* Issue a softhangup */
2617 :     if (globals.debug > 2) {
2618 :     ast_log(LOG_NOTICE,"Tech Thread - Hanging up channel - soft hangup\n");
2619 :     }
2620 :    
2621 :     #if defined (AST14) || defined (AST16)
2622 :     if (ast_test_flag(owner, AST_FLAG_BLOCKING)) {
2623 : jtarlton 235 int cnt = 0;
2624 : amartin 125 while (!owner->blocker) {
2625 :     ast_log(LOG_ERROR, "Woomera: BLOCKER Set but no blocker!\n");
2626 :     usleep(50);
2627 :     cnt++;
2628 :     }
2629 :     if (cnt) {
2630 :     ast_log(LOG_ERROR, "Woomera: BLOCKER Set Got Blocker %s!\n",
2631 :     owner->blockproc);
2632 :     }
2633 :     }
2634 :     #endif
2635 :    
2636 :     ast_softhangup_nolock(owner, AST_SOFTHANGUP_DEV);
2637 :     ast_clear_flag(tech_pvt, TFLAG_INTHREAD);
2638 :     ast_set_flag(tech_pvt, TFLAG_AST_HANGUP);
2639 : jtarlton 235 tech_pvt->owner = NULL;
2640 : amartin 125
2641 :     /* After this point tech_pvt point should not be touched */
2642 : jtarlton 235 ast_hangup = 1;
2643 : amartin 125
2644 :     } else {
2645 :     if (1) { //globals.debug > 2) {
2646 :     ast_log(LOG_NOTICE,"Tech Thread - Hanging up channel - owner=%p pbx=%i \n",
2647 :     owner,ast_test_flag(tech_pvt, TFLAG_PBX));
2648 :     }
2649 :     }
2650 :     my_ast_channel_unlock(owner);
2651 :     }
2652 :    
2653 :    
2654 :     ast_mutex_unlock(&tech_pvt->iolock);
2655 : amartin 128
2656 : amartin 125 ast_mutex_lock(&profile->call_count_lock);
2657 :     profile->call_end++;
2658 :     ast_mutex_unlock(&profile->call_count_lock);
2659 :    
2660 :     /* Wait for tech_hangup to set this, so there is on
2661 : jtarlton 255 * race condition with asterisk
2662 :     */
2663 : amartin 125 //ast_set_flag(tech_pvt, TFLAG_DESTROY);
2664 :    
2665 :     if (ast_hangup) {
2666 :     ast_mutex_lock(&profile->call_count_lock);
2667 :     profile->call_ast_hungup++;
2668 :     ast_mutex_unlock(&profile->call_count_lock);
2669 :    
2670 :     /* Let Asterisk tech_hangup destroy tech_pvt */
2671 :     goto tech_thread_exit;
2672 :    
2673 :     } else {
2674 :     ast_mutex_lock(&tech_pvt->profile->call_count_lock);
2675 :     tech_pvt->profile->call_abort++;
2676 :     ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
2677 : amartin 128
2678 : amartin 125 if (globals.debug > 2) {
2679 :     ast_log(LOG_NOTICE, "NOTE: Skipping Wait on destroy timedout! %s tech_pvt=%p\n",
2680 : jtarlton 255 tech_pvt->callid, tech_pvt);
2681 : amartin 125 }
2682 :     ast_set_flag(tech_pvt, TFLAG_DESTROY);
2683 :     }
2684 :    
2685 : jtarlton 260 aborted |= 8;
2686 : amartin 125 tech_destroy(tech_pvt,tech_get_owner(tech_pvt));
2687 :     tech_pvt = NULL;
2688 :     break;
2689 :     }
2690 :    
2691 :    
2692 :     if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP) || !tech_pvt->owner) {
2693 :     ast_set_flag(tech_pvt, TFLAG_DESTROY);
2694 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2695 :     if (globals.debug > 2) {
2696 : jtarlton 195 ast_log(LOG_NOTICE, "Thread got HANGUP or no owner %s %p tpvt=%p\n",
2697 :     tech_pvt->callid,tech_pvt,tech_pvt->owner);
2698 : amartin 125 }
2699 :     goto tech_thread_continue;
2700 :     }
2701 :    
2702 :     if (ast_test_flag(tech_pvt, TFLAG_ACTIVATE)) {
2703 : amartin 128
2704 : amartin 125 struct ast_channel *owner;
2705 :     int err;
2706 : amartin 128
2707 : amartin 125 if (globals.debug > 2) {
2708 : jtarlton 195 ast_log(LOG_NOTICE, "ACTIVATE %s tpvt=%p\n",
2709 :     tech_pvt->callid,tech_pvt);
2710 : amartin 125 }
2711 :     ast_clear_flag(tech_pvt, TFLAG_ACTIVATE);
2712 : jtarlton 195 err = tech_activate(tech_pvt);
2713 : amartin 125 if (err < 0 || ast_test_flag(tech_pvt, TFLAG_ABORT)) {
2714 :     if (globals.debug > 2) {
2715 :     ast_log(LOG_NOTICE, "ACTIVATE ABORT Ch=%d\n",
2716 : jtarlton 195 tech_pvt->command_channel);
2717 : amartin 125 }
2718 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2719 :     goto tech_thread_continue;
2720 :     }
2721 :    
2722 :     my_tech_pvt_and_owner_lock(tech_pvt);
2723 :     owner = tech_pvt->owner;
2724 :     if (owner) {
2725 :     owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
2726 :     }
2727 :     my_tech_pvt_and_owner_unlock(tech_pvt);
2728 :    
2729 :     if (globals.debug > 2) {
2730 :     ast_log(LOG_NOTICE, "ACTIVATE DONE %s tpvt=%p\n",
2731 : jtarlton 195 tech_pvt->callid,tech_pvt);
2732 : amartin 125 }
2733 :     }
2734 :    
2735 :     if (ast_test_flag(tech_pvt, TFLAG_PARSE_INCOMING)) {
2736 :     int err;
2737 :    
2738 :     ast_clear_flag(tech_pvt, TFLAG_PARSE_INCOMING);
2739 :     ast_set_flag(tech_pvt, TFLAG_INCOMING);
2740 :    
2741 :     my_tech_pvt_and_owner_lock(tech_pvt);
2742 : jtarlton 195 err = woomera_event_incoming (tech_pvt);
2743 : amartin 125 my_tech_pvt_and_owner_unlock(tech_pvt);
2744 :    
2745 :     if (err != 0) {
2746 : jtarlton 235
2747 : jtarlton 255 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2748 : jtarlton 280 "HANGUP %s%s"
2749 :     "cause: Invalid call reference%s"
2750 : amartin 125 "Q931-Cause-Code: 81%s"
2751 : jtarlton 280 "Reason-String: Invalid call reference%s"
2752 :     "Reason: 81%s"
2753 : amartin 125 "Unique-Call-Id: %s%s",
2754 :     tech_pvt->callid,
2755 : amartin 128 WOOMERA_LINE_SEPARATOR,
2756 :     WOOMERA_LINE_SEPARATOR,
2757 :     WOOMERA_LINE_SEPARATOR,
2758 : jtarlton 280 WOOMERA_LINE_SEPARATOR,
2759 :     WOOMERA_LINE_SEPARATOR,
2760 : amartin 128 tech_pvt->callid,
2761 : amartin 125 WOOMERA_RECORD_SEPARATOR);
2762 :    
2763 :     /* Wait for Ack */
2764 : amartin 231 if (err >= 0) {
2765 : jtarlton 280 woomera_message_parse_wait(tech_pvt, &wmsg);
2766 : amartin 231 }
2767 : amartin 128
2768 : amartin 125 woomera_close_socket(&tech_pvt->command_channel);
2769 :    
2770 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2771 :     goto tech_thread_continue;
2772 : amartin 128
2773 : amartin 125 } else {
2774 : jtarlton 195 if (tech_pvt->rtp_enable) {
2775 : amartin 231 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2776 : amartin 128 "%s %s%s"
2777 :     "RTP-Audio: %s:%d%s"
2778 : jtarlton 277 "RTP-Audio-Format: ULAW%s"
2779 : amartin 128 "Unique-Call-Id: %s%s",
2780 :     MEDIA_ANSWER,
2781 :     tech_pvt->callid,
2782 :     WOOMERA_LINE_SEPARATOR,
2783 :     tech_pvt->profile->audio_ip,
2784 :     tech_pvt->port,
2785 :     WOOMERA_LINE_SEPARATOR,
2786 : jtarlton 277 /* TODO use real format */
2787 : amartin 128 WOOMERA_LINE_SEPARATOR,
2788 :     tech_pvt->callid,
2789 :     WOOMERA_RECORD_SEPARATOR);
2790 : jtarlton 195 } else {
2791 : amartin 231 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2792 : amartin 128 "%s %s%s"
2793 :     "Raw-Audio: %s:%d%s"
2794 :     "Request-Audio: Raw%s"
2795 :     "Unique-Call-Id: %s%s",
2796 :     MEDIA_ANSWER,
2797 :     tech_pvt->callid,
2798 :     WOOMERA_LINE_SEPARATOR,
2799 :     tech_pvt->profile->audio_ip,
2800 :     tech_pvt->port,
2801 :     WOOMERA_LINE_SEPARATOR,
2802 :     WOOMERA_LINE_SEPARATOR,
2803 :     tech_pvt->callid,
2804 :     WOOMERA_RECORD_SEPARATOR);
2805 :     }
2806 : amartin 125 }
2807 :    
2808 :     /* Wait for Ack */
2809 : amartin 231 if (err< 0 || woomera_message_parse_wait(tech_pvt,&wmsg) < 0) {
2810 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
2811 :     ast_log(LOG_NOTICE, "MEDIA ANSWER ABORT Ch=%d\n",
2812 :     tech_pvt->command_channel);
2813 :     ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
2814 : jtarlton 277 tech_pvt->pri_cause = 111;
2815 : amartin 125 goto tech_thread_continue;
2816 : amartin 128 }
2817 : amartin 125
2818 :     /* Confirm that the Ack is OK otherwise
2819 :     * hangup */
2820 :     if (woomera_message_reply_ok(&wmsg) != 0) {
2821 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2822 :     goto tech_thread_continue;
2823 :     }
2824 :    
2825 :     /* It is possible for ACCEPT to have media info
2826 :     * This is how Early Media is started */
2827 : jtarlton 169 err = woomera_event_media(tech_pvt, &wmsg);
2828 : amartin 125 if (err < 0) {
2829 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2830 :     goto tech_thread_continue;
2831 : amartin 128 }
2832 : amartin 125 }
2833 :    
2834 :     if (ast_test_flag(tech_pvt, TFLAG_ACCEPT) &&
2835 :     ast_test_flag(tech_pvt, TFLAG_INCOMING)) {
2836 : amartin 231 int err;
2837 : jtarlton 235
2838 : jtarlton 277 ast_set_flag(tech_pvt, TFLAG_ACCEPTED);
2839 :     ast_clear_flag(tech_pvt, TFLAG_ACCEPT);
2840 : amartin 128
2841 : jtarlton 195 if (tech_pvt->rtp_enable) {
2842 : amartin 231 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2843 : amartin 128 "ACCEPT %s%s"
2844 :     "RTP-Audio: %s:%d%s"
2845 : jtarlton 277 "RTP-Audio-Format: ULAW%s"
2846 : amartin 128 "Unique-Call-Id: %s%s",
2847 :     tech_pvt->callid,
2848 :     WOOMERA_LINE_SEPARATOR,
2849 :     tech_pvt->profile->audio_ip,
2850 :     tech_pvt->port,
2851 :     WOOMERA_LINE_SEPARATOR,
2852 : jtarlton 277 /* TODO use real format */
2853 : amartin 128 WOOMERA_LINE_SEPARATOR,
2854 :     tech_pvt->callid,
2855 :     WOOMERA_RECORD_SEPARATOR);
2856 : jtarlton 195 } else {
2857 : amartin 231 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2858 : amartin 128 "ACCEPT %s%s"
2859 :     "Raw-Audio: %s:%d%s"
2860 :     "Request-Audio: Raw%s"
2861 :     "Unique-Call-Id: %s%s",
2862 :     tech_pvt->callid,
2863 :     WOOMERA_LINE_SEPARATOR,
2864 :     tech_pvt->profile->audio_ip,
2865 :     tech_pvt->port,
2866 :     WOOMERA_LINE_SEPARATOR,
2867 :     WOOMERA_LINE_SEPARATOR,
2868 :     tech_pvt->callid,
2869 :     WOOMERA_RECORD_SEPARATOR);
2870 :     }
2871 :    
2872 : jtarlton 277 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
2873 : jtarlton 195 ast_set_flag(tech_pvt, TFLAG_ABORT);
2874 :     ast_log(LOG_NOTICE, "ACCEPT ABORT Ch=%d\n",
2875 :     tech_pvt->command_channel);
2876 :     ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
2877 : jtarlton 277 tech_pvt->pri_cause = 111;
2878 : jtarlton 195 goto tech_thread_continue;
2879 :     continue;
2880 :     }
2881 : amartin 125 }
2882 :    
2883 :     if (ast_test_flag(tech_pvt, TFLAG_ANSWER)) {
2884 : amartin 231 int err;
2885 : amartin 128
2886 : amartin 125 if (globals.debug > 2) {
2887 : jtarlton 195 ast_log(LOG_NOTICE, "ANSWER %s tpvt=%p\n",
2888 :     tech_pvt->callid,tech_pvt);
2889 : amartin 125 }
2890 :     ast_clear_flag(tech_pvt, TFLAG_ANSWER);
2891 : amartin 128
2892 : amartin 125 if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
2893 :     ast_log(LOG_ERROR,"Error: ANSWER on OUTBOUND Call! (skipped) %s\n",
2894 : jtarlton 195 tech_pvt->callid);
2895 : amartin 128 } else {
2896 : amartin 125 #ifdef USE_ANSWER
2897 : amartin 231 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2898 : amartin 125 "ANSWER %s%s"
2899 :     "Unique-Call-Id: %s%s",
2900 : amartin 128 tech_pvt->callid,
2901 : amartin 125 WOOMERA_LINE_SEPARATOR,
2902 :     tech_pvt->callid,
2903 :     WOOMERA_RECORD_SEPARATOR);
2904 : amartin 128
2905 : jtarlton 277 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
2906 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
2907 :     ast_log(LOG_NOTICE, "ANSWER ABORT Ch=%d\n",
2908 : jtarlton 195 tech_pvt->command_channel);
2909 : amartin 125 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
2910 : jtarlton 277 tech_pvt->pri_cause = 111;
2911 : amartin 125 goto tech_thread_continue;
2912 :     continue;
2913 :     }
2914 : amartin 128
2915 : amartin 125 ast_mutex_lock(&tech_pvt->profile->call_count_lock);
2916 :     tech_pvt->profile->call_ok++;
2917 :     ast_mutex_unlock(&tech_pvt->profile->call_count_lock);
2918 :     #endif
2919 :     }
2920 :     }
2921 : amartin 128
2922 : amartin 125 if (ast_test_flag(tech_pvt, TFLAG_DTMF)) {
2923 : amartin 231 int err;
2924 : amartin 125 if (globals.debug > 2) {
2925 : jtarlton 195 ast_log(LOG_NOTICE, "DTMF %s tpvt=%p %s\n",
2926 : jtarlton 277 tech_pvt->callid, tech_pvt, tech_pvt->dtmfbuf);
2927 : amartin 125 }
2928 :    
2929 :     //DIALECT
2930 :     ast_mutex_lock(&tech_pvt->iolock);
2931 :     #if 0
2932 : amartin 128 woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2933 : amartin 125 "DTMF %s %s%s",
2934 : amartin 128 tech_pvt->callid,
2935 :     tech_pvt->dtmfbuf,
2936 : amartin 125 WOOMERA_LINE_SEPARATOR);
2937 :     #else
2938 : jtarlton 235 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel,
2939 : amartin 125 "DTMF %sUnique-Call-Id:%s%sContent-Length:%d%s%s%s%s",
2940 :     WOOMERA_LINE_SEPARATOR,
2941 :     tech_pvt->callid,
2942 :     WOOMERA_LINE_SEPARATOR,
2943 :     strlen(tech_pvt->dtmfbuf),
2944 :     WOOMERA_LINE_SEPARATOR,
2945 :     WOOMERA_LINE_SEPARATOR,
2946 :     tech_pvt->dtmfbuf,
2947 :     WOOMERA_RECORD_SEPARATOR);
2948 :     #endif
2949 : amartin 128
2950 : amartin 125 ast_clear_flag(tech_pvt, TFLAG_DTMF);
2951 :     memset(tech_pvt->dtmfbuf, 0, sizeof(tech_pvt->dtmfbuf));
2952 :     ast_mutex_unlock(&tech_pvt->iolock);
2953 :    
2954 : jtarlton 277 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) {
2955 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
2956 :     ast_log(LOG_NOTICE, "DTMF ABORT Ch=%d\n",
2957 : jtarlton 195 tech_pvt->command_channel);
2958 : amartin 125 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds));
2959 : jtarlton 277 tech_pvt->pri_cause = 111;
2960 : amartin 125 goto tech_thread_continue;
2961 :     continue;
2962 :     }
2963 :     }
2964 :    
2965 :     if(tech_pvt->timeout) {
2966 :     struct timeval now;
2967 :     int elapsed;
2968 :     gettimeofday(&now, NULL);
2969 : amartin 128 elapsed = (((now.tv_sec * 1000) + now.tv_usec / 1000) -
2970 : jtarlton 195 ((tech_pvt->started.tv_sec * 1000) + tech_pvt->started.tv_usec / 1000));
2971 : amartin 125 if (elapsed > tech_pvt->timeout) {
2972 :     /* call timed out! */
2973 :     if (globals.debug > 2) {
2974 : jtarlton 195 ast_log(LOG_NOTICE, "CALL TIMED OUT %s tpvt=%p\n",
2975 : jtarlton 277 tech_pvt->callid, tech_pvt);
2976 : amartin 125 }
2977 :     ast_set_flag(tech_pvt, TFLAG_ABORT);
2978 :     ast_copy_string(tech_pvt->ds, "RECOVERY_ON_TIMER_EXPIRE", sizeof(tech_pvt->ds));
2979 : jtarlton 277 tech_pvt->pri_cause = 102;
2980 : amartin 125 }
2981 :     }
2982 : amartin 128
2983 : amartin 125 if (globals.debug > 2) {
2984 :     if (tcallid[0] == 0) {
2985 : jtarlton 280 strncpy(tcallid, tech_pvt->callid, sizeof(tcallid)-1);
2986 : amartin 125 }
2987 :     }
2988 : amartin 128
2989 : amartin 125 if (tech_pvt->command_channel < 0) {
2990 :     if (!globals.more_threads) {
2991 :     goto tech_thread_continue;
2992 :     continue;
2993 :     } else {
2994 :     if (globals.debug > 2) {
2995 : jtarlton 195 ast_log(LOG_NOTICE, "No Command Channel %s tpvt=%p\n",
2996 : jtarlton 277 tech_pvt->callid, tech_pvt);
2997 : amartin 125 }
2998 :     ast_copy_string(tech_pvt->ds, "REQUESTED_CHAN_UNAVAIL", sizeof(tech_pvt->ds));
2999 : jtarlton 277 tech_pvt->pri_cause = 44;
3000 : amartin 125 ast_set_flag(tech_pvt, TFLAG_ABORT);
3001 :     goto tech_thread_continue;
3002 :     continue;
3003 :     }
3004 :     }
3005 :     /* Check for events */
3006 :     if((res = woomera_dequeue_event(&tech_pvt->event_queue, &wmsg)) ||
3007 :     (res = woomera_message_parse(tech_pvt->command_channel,
3008 : jtarlton 195 &wmsg,
3009 :     100,
3010 :     tech_pvt->profile,
3011 :     NULL
3012 :     ))) {
3013 : amartin 125
3014 : amartin 128 woomera_check_event (tech_pvt, res, &wmsg);
3015 : amartin 125 if (ast_test_flag(tech_pvt, TFLAG_ABORT)) {
3016 :     continue;
3017 :     }
3018 :    
3019 :     }
3020 :     if (globals.debug > 4) {
3021 :     if (option_verbose > 2) {
3022 : amartin 128 ast_verbose(WOOMERA_DEBUG_PREFIX "CHECK {%s} (%d) %s\n",
3023 : jtarlton 195 tech_pvt->profile->name,
3024 :     res,tech_pvt->callid);
3025 : amartin 125 }
3026 :     }
3027 : amartin 128
3028 : amartin 125 tech_thread_continue:
3029 : amartin 128
3030 : amartin 125 if (!globals.more_threads) {
3031 :     ast_log(LOG_NOTICE, "EXITING THREAD on more threads %s\n",
3032 :     tcallid);
3033 :     break;
3034 :     }
3035 : amartin 128
3036 : amartin 125 }
3037 :    
3038 :     tech_thread_exit:
3039 :    
3040 :     if (globals.debug > 2) {
3041 :     ast_log(LOG_NOTICE, "OUT THREAD %s 0x%X\n",tcallid,aborted);
3042 :     }
3043 : amartin 128
3044 : amartin 125 return NULL;
3045 :     }
3046 :    
3047 : amartin 128 static int woomera_profile_thread_running(woomera_profile *profile, int set, int new)
3048 : amartin 125 {
3049 :     int running = 0;
3050 :    
3051 :     ast_mutex_lock(&profile->iolock);
3052 :     if (set) {
3053 :     profile->thread_running = new;
3054 :     }
3055 :     running = profile->thread_running;
3056 :     ast_mutex_unlock(&profile->iolock);
3057 :     return running;
3058 : amartin 128
3059 : amartin 125 }
3060 :    
3061 : amartin 128 static int woomera_locate_socket(woomera_profile *profile, int *woomera_socket)
3062 : amartin 125 {
3063 :     woomera_message wmsg;
3064 :    
3065 : amartin 128 memset(&wmsg,0,sizeof(wmsg));
3066 :    
3067 : amartin 125 for (;;) {
3068 :    
3069 :     while (connect_woomera(woomera_socket, profile, 0) < 0) {
3070 :     if(!woomera_profile_thread_running(profile, 0, 0)) {
3071 :     break;
3072 :     }
3073 :     if (globals.panic > 2) {
3074 :     break;
3075 :     }
3076 : amartin 128 ast_log(LOG_NOTICE,
3077 :     "Woomera {%s} Cannot Reconnect! retry in 5 seconds...\n",
3078 : amartin 125 profile->name);
3079 :    
3080 : jtarlton 255 /* When we establish connection update the version */
3081 :     svrversion_init = 0;
3082 : amartin 125 sleep(5);
3083 :     }
3084 :    
3085 :     if (*woomera_socket > -1) {
3086 :     if (ast_test_flag(profile, PFLAG_INBOUND)) {
3087 : amartin 231 int err;
3088 : amartin 125 if (globals.debug > 2) {
3089 : jtarlton 195 ast_log(LOG_NOTICE, "Woomera Master Socket \n");
3090 : amartin 125 }
3091 : amartin 231
3092 :     err = woomera_printf(profile, *woomera_socket, "LISTEN MASTER%s", WOOMERA_RECORD_SEPARATOR);
3093 : jtarlton 255 if (err < 0) {
3094 : amartin 231 if (*woomera_socket > -1) {
3095 :     woomera_close_socket(woomera_socket);
3096 :     }
3097 :     continue;
3098 :     }
3099 :    
3100 : amartin 125 if (woomera_message_parse(*woomera_socket,
3101 :     &wmsg,
3102 :     WOOMERA_HARD_TIMEOUT,
3103 :     profile,
3104 :     &profile->event_queue
3105 :     ) < 0) {
3106 : amartin 128 ast_log(LOG_ERROR, "{%s} %s:%d HELP! Woomera is broken!\n",
3107 : jtarlton 195 profile->name,__FUNCTION__,__LINE__);
3108 : amartin 125 if (*woomera_socket > -1) {
3109 :     woomera_close_socket(woomera_socket);
3110 :     }
3111 :     continue;
3112 :     }
3113 :     }
3114 :    
3115 :     }
3116 :     usleep(100);
3117 :     break;
3118 : amartin 128 }
3119 : amartin 125 return *woomera_socket;
3120 :     }
3121 :    
3122 : amartin 128 static void tech_monitor_in_one_thread(void)
3123 : amartin 125 {
3124 :     private_object *tech_pvt;
3125 :    
3126 :     ASTOBJ_CONTAINER_TRAVERSE(&private_object_list, 1, do {
3127 :     ASTOBJ_RDLOCK(iterator);
3128 :     tech_pvt = iterator;
3129 :     tech_monitor_thread(tech_pvt);
3130 :     ASTOBJ_UNLOCK(iterator);
3131 :     } while(0));
3132 :     }
3133 :    
3134 : amartin 128 static void *woomera_thread_run(void *obj)
3135 : amartin 125 {
3136 : jtarlton 195 int woomera_socket = -1, res = 0, res2 = 0;
3137 : amartin 125 woomera_message wmsg;
3138 :     woomera_profile *profile;
3139 :    
3140 : jtarlton 255 memset(&wmsg, 0, sizeof(wmsg));
3141 : amartin 125
3142 :     profile = obj;
3143 :     ast_log(LOG_NOTICE, "Started Woomera Thread {%s}.\n", profile->name);
3144 : amartin 128
3145 : amartin 125 profile->thread_running = 1;
3146 :    
3147 : jtarlton 255 while (woomera_profile_thread_running(profile, 0, 0)) {
3148 : amartin 125 /* listen on socket and handle events */
3149 :    
3150 :     if (globals.panic > 2) {
3151 :     break;
3152 :     }
3153 :    
3154 :     if (globals.panic == 2) {
3155 :     ast_log(LOG_NOTICE, "Woomera is disabled!\n");
3156 :     sleep(5);
3157 :     continue;
3158 :     }
3159 :    
3160 :     if (woomera_socket < 0) {
3161 :     if (woomera_locate_socket(profile, &woomera_socket)) {
3162 :     globals.panic = 0;
3163 :     }
3164 :     if (!woomera_profile_thread_running(profile, 0, 0)) {
3165 :     break;
3166 :     }
3167 :     profile->woomera_socket=woomera_socket;
3168 : amartin 128 ast_log(LOG_NOTICE, "Woomera Thread Up {%s} %s/%d\n",
3169 : jtarlton 195 profile->name, profile->woomera_host, profile->woomera_port);
3170 : amartin 125
3171 :     }
3172 :    
3173 :     if (globals.panic) {
3174 :     if (globals.panic != 2) {
3175 :     ast_log(LOG_ERROR, "Help I'm in a state of panic!\n");
3176 :     }
3177 :     if (woomera_socket > -1) {
3178 :     woomera_close_socket(&woomera_socket);
3179 : amartin 231 profile->woomera_socket = -1;
3180 : amartin 125 }
3181 :     continue;
3182 :     }
3183 :     if (!globals.more_threads) {
3184 :     if (woomera_socket > -1) {
3185 :     tech_monitor_in_one_thread();
3186 :     }
3187 :     }
3188 :    
3189 :     if ((res = woomera_dequeue_event(&profile->event_queue, &wmsg) ||
3190 :     (res2 = woomera_message_parse(woomera_socket,
3191 : jtarlton 195 &wmsg,
3192 :     /* if we are not stingy with threads we can block forever */
3193 :     globals.more_threads ? 0 : 500,
3194 :     profile,
3195 :     NULL
3196 :     )))) {
3197 : amartin 125
3198 :     if (res2 < 0) {
3199 :     ast_log(LOG_ERROR, "{%s} HELP! I lost my connection to woomera!\n", profile->name);
3200 :     if (woomera_socket > -1) {
3201 :     woomera_close_socket(&woomera_socket);
3202 : amartin 231 profile->woomera_socket = -1;
3203 : amartin 125 }
3204 :     global_set_flag(TFLAG_ABORT);
3205 :     if (globals.panic > 2) {
3206 :     break;
3207 :     }
3208 :    
3209 :     continue;
3210 :    
3211 :     if (woomera_socket > -1) {
3212 :     if (ast_test_flag(profile, PFLAG_INBOUND)) {
3213 :     if (globals.debug > 2) {
3214 : jtarlton 195 ast_log(LOG_NOTICE, "%s:%d Incoming Call \n",__FUNCTION__,__LINE__);
3215 : amartin 125 }
3216 :    
3217 :     #if 0
3218 :     /* We only want a single listener */
3219 :     woomera_printf(profile, woomera_socket, "LISTEN%s", WOOMERA_RECORD_SEPARATOR);
3220 : jtarlton 280 if (woomera_message_parse(woomera_socket,
3221 : amartin 125 &wmsg,
3222 :     WOOMERA_HARD_TIMEOUT,
3223 :     profile,
3224 :     &profile->event_queue
3225 :     ) < 0) {
3226 : jtarlton 280 ast_log(LOG_ERROR, "{%s} %s:%d HELP! Woomera is broken!\n", profile->name, __FUNCTION__, __LINE__);
3227 : amartin 125 woomera_close_socket(&woomera_socket);
3228 : amartin 231 profile->woomera_socket = -1;
3229 : amartin 125 }
3230 : amartin 128 #endif
3231 : amartin 125 }
3232 :     if (woomera_socket > -1) {
3233 :     ast_log(LOG_NOTICE, "Woomera Thread Up {%s} %s/%d\n", profile->name, profile->woomera_host, profile->woomera_port);
3234 :     }
3235 :     }
3236 :     continue;
3237 :     }
3238 :    
3239 :     if (!strcasecmp(wmsg.command, "INCOMING")) {
3240 : amartin 128
3241 : jtarlton 260 int err = 1;
3242 : amartin 125 int cause = 0;
3243 :     struct ast_channel *inchan;
3244 :     char *name = "Woomera";
3245 :    
3246 :     if (!(name = woomera_message_header(&wmsg, "Channel-Name"))) {
3247 :     name = woomera_message_header(&wmsg,"Remote-Address");
3248 :     }
3249 :    
3250 :     if (!name) {
3251 : jtarlton 260 name = wmsg.callid;
3252 : amartin 125 }
3253 :    
3254 :     if (!name) {
3255 : jtarlton 260 name = "smg";
3256 : amartin 125 }
3257 :    
3258 : amartin 128 if (globals.debug > 2) {
3259 : jtarlton 280 ast_log(LOG_NOTICE, "New Inbound Call %s\n", wmsg.callid);
3260 : amartin 125 }
3261 :    
3262 :     if ((inchan = woomera_new(WOOMERA_CHAN_NAME, profile->coding, name, &cause, profile))) {
3263 :     private_object *tech_pvt;
3264 :     char *callid;
3265 :     tech_pvt = inchan->tech_pvt;
3266 : amartin 128
3267 : amartin 125 /* Save the call id */
3268 :     tech_pvt->call_info = wmsg;
3269 : jtarlton 277 memcpy(tech_pvt->callid, wmsg.callid, sizeof(tech_pvt->callid));
3270 : amartin 128
3271 : amartin 125 callid = woomera_message_header(&wmsg, "Unique-Call-Id");
3272 :     if (callid) {
3273 : jtarlton 280 ast_copy_string(tech_pvt->callid, callid, sizeof(wmsg.callid));
3274 : amartin 125 }
3275 : amartin 128
3276 : jtarlton 277 err = tech_init(tech_pvt, profile, TFLAG_INBOUND);
3277 : amartin 125 if (err) {
3278 : jtarlton 280 if (globals.debug > 2) {
3279 :     ast_log(LOG_ERROR, "Inbound Call Failed %s %p\n",
3280 :     wmsg.callid, tech_pvt);
3281 : amartin 125 }
3282 :     tech_destroy(tech_pvt,inchan);
3283 :     }
3284 :     } else {
3285 :     ast_log(LOG_ERROR, "Cannot Create new Inbound Channel!\n");
3286 :     }
3287 : amartin 128
3288 : amartin 125 /* It is the job of the server to timeout on this call
3289 :     if the call is not started */
3290 :     }
3291 :     }
3292 :     if(globals.debug > 4) {
3293 :     if (option_verbose > 2) {
3294 :     ast_verbose(WOOMERA_DEBUG_PREFIX "Main Thread {%s} Select Return %d\n", profile->name, res);
3295 :     }
3296 :     }
3297 :     usleep(100);
3298 :     }
3299 :    
3300 : amartin 128
3301 : amartin 125 if (woomera_socket > -1) {
3302 : amartin 231 int err;
3303 :     err = woomera_printf(profile, woomera_socket, "BYE%s", WOOMERA_RECORD_SEPARATOR);
3304 : jtarlton 255 if (err < 0 || woomera_message_parse(woomera_socket,
3305 : amartin 231 &wmsg,
3306 :     WOOMERA_HARD_TIMEOUT,
3307 :     profile,
3308 :     &profile->event_queue
3309 :     ) < 0) {
3310 : amartin 125 }
3311 :     woomera_close_socket(&woomera_socket);
3312 : amartin 231 profile->woomera_socket = -1;
3313 : amartin 125 }
3314 :    
3315 :     ast_set_flag(profile, PFLAG_DISABLED);
3316 :    
3317 :     ast_log(LOG_NOTICE, "Ended Woomera Thread {%s}.\n", profile->name);
3318 :     woomera_profile_thread_running(profile, 1, -1);
3319 :     return NULL;
3320 :     }
3321 :    
3322 : jtarlton 280
3323 : amartin 128 static void launch_woomera_thread(woomera_profile *profile)
3324 : amartin 125 {
3325 :     pthread_attr_t attr;
3326 :     int result = 0;
3327 :    
3328 :     result = pthread_attr_init(&attr);
3329 :     pthread_attr_setschedpolicy(&attr, SCHED_RR);
3330 :     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3331 :     result = ast_pthread_create(&profile->thread, &attr, woomera_thread_run, profile);
3332 :     result = pthread_attr_destroy(&attr);
3333 :     }
3334 :    
3335 :    
3336 : amartin 128 static int launch_tech_thread(private_object *tech_pvt)
3337 : amartin 125 {
3338 :     pthread_attr_t attr;
3339 :     int result = 0;
3340 :    
3341 :     if (globals.debug > 2) {
3342 :     if (option_verbose > 2) {
3343 : jtarlton 242 ast_verbose(WOOMERA_DEBUG_PREFIX "Tech Thread entry\n");
3344 : amartin 125 }
3345 :     }
3346 :    
3347 :     if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP)) {
3348 :     /* Sanity check should never happen */
3349 :     ast_log(LOG_NOTICE,"Tech Thread failed call already hangup!\n");
3350 :     return -1;
3351 : amartin 128 }
3352 : amartin 125
3353 :     result = pthread_attr_init(&attr);
3354 :     pthread_attr_setschedpolicy(&attr, SCHED_RR);
3355 :     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3356 :     ast_set_flag(tech_pvt, TFLAG_INTHREAD);
3357 :     result = ast_pthread_create(&tech_pvt->thread, &attr, tech_monitor_thread, tech_pvt);
3358 :     if (result) {
3359 :     ast_clear_flag(tech_pvt, TFLAG_INTHREAD);
3360 : jtarlton 242 ast_log(LOG_ERROR, "Failed to launch tech thread %s\n",
3361 :     strerror(errno));
3362 : amartin 125 }
3363 :     pthread_attr_destroy(&attr);
3364 : amartin 128
3365 : amartin 125 return result;
3366 :     }
3367 :    
3368 : amartin 128 static void woomera_config_gain(woomera_profile *profile, float gain_val, int rx)
3369 : amartin 125 {
3370 :     int j;
3371 :     int k;
3372 :     float linear_gain = pow(10.0, gain_val / 20.0);
3373 :     unsigned char *gain;
3374 :    
3375 :     if (profile->coding == AST_FORMAT_SLINEAR){
3376 :     ast_log(LOG_WARNING, "Coding not specified, %s value ignored\n", (rx)? "rxgain":"txgain");
3377 :     return;
3378 :     }
3379 : amartin 128
3380 : amartin 125 if (gain_val == 0) {
3381 :     goto woomera_config_gain_skip;
3382 :     }
3383 : jtarlton 195
3384 : amartin 125 if (rx) {
3385 :     gain = profile->rxgain;
3386 :     } else {
3387 :     gain = profile->txgain;
3388 :     }
3389 : amartin 128
3390 : amartin 125 switch (profile->coding) {
3391 : amartin 128
3392 : amartin 125 case AST_FORMAT_ALAW:
3393 :     for (j = 0; j < 256; j++) {
3394 :     if (gain_val) {
3395 :     k = (int) (((float) alaw_to_linear(j)) * linear_gain);
3396 :     if (k > 32767) k = 32767;
3397 :     if (k < -32767) k = -32767;
3398 :     gain[j] = linear_to_alaw(k);
3399 :     } else {
3400 :     gain[j] = j;
3401 :     }
3402 :     }
3403 :     break;
3404 :     case AST_FORMAT_ULAW:
3405 :     for (j = 0; j < 256; j++) {
3406 :     if (gain_val) {
3407 :     k = (int) (((float) ulaw_to_linear(j)) * linear_gain);
3408 :     if (k > 32767) k = 32767;
3409 :     if (k < -32767) k = -32767;
3410 :     gain[j] = linear_to_ulaw(k);
3411 :     } else {
3412 :     gain[j] = j;
3413 :     }
3414 :     }
3415 :     break;
3416 : amartin 128 }
3417 : amartin 125
3418 :     woomera_config_gain_skip:
3419 :    
3420 :     if (rx) {
3421 :     profile->rxgain_val=gain_val;
3422 :     } else {
3423 :     profile->txgain_val=gain_val;
3424 :     }
3425 :    
3426 :     }
3427 :    
3428 : amartin 128 static void destroy_woomera_profile(woomera_profile *profile)
3429 : amartin 125 {
3430 :     int i;
3431 :     if (profile && ast_test_flag(profile, PFLAG_DYNAMIC)) {
3432 : jtarlton 255 for ( i = 0; i <= WOOMERA_MAX_TRUNKGROUPS; i++) {
3433 :     if(profile->tg_context[i] != NULL) {
3434 : amartin 125 ast_free(profile->tg_context[i]);
3435 :     }
3436 : jtarlton 255 if(profile->tg_language[i] != NULL) {
3437 : amartin 125 ast_free(profile->tg_language[i]);
3438 :     }
3439 : amartin 128 }
3440 : amartin 125 ast_mutex_destroy(&profile->iolock);
3441 :     ast_mutex_destroy(&profile->call_count_lock);
3442 :     ast_mutex_destroy(&profile->event_queue.lock);
3443 :     ast_free(profile);
3444 :     }
3445 :     }
3446 :    
3447 : amartin 128 static woomera_profile *clone_woomera_profile(woomera_profile *new_profile, woomera_profile *default_profile)
3448 : amartin 125 {
3449 :     return memcpy(new_profile, default_profile, sizeof(woomera_profile));
3450 :     }
3451 :    
3452 : amartin 128 static woomera_profile *create_woomera_profile(woomera_profile *default_profile)
3453 : amartin 125 {
3454 :     woomera_profile *profile;
3455 :    
3456 :     if((profile = ast_malloc(sizeof(woomera_profile)))) {
3457 :     clone_woomera_profile(profile, default_profile);
3458 :     ast_mutex_init(&profile->iolock);
3459 :     ast_mutex_init(&profile->call_count_lock);
3460 :     ast_mutex_init(&profile->event_queue.lock);
3461 :     ast_set_flag(profile, PFLAG_DYNAMIC);
3462 :     }
3463 :     return profile;
3464 :     }
3465 :    
3466 : amartin 128 static int config_woomera(void)
3467 : amartin 125 {
3468 :     struct ast_config *cfg;
3469 :     #if defined (AST16)
3470 :     struct ast_flags config_flags = {0};
3471 :     #endif
3472 :     char *entry;
3473 :     struct ast_variable *v;
3474 :     woomera_profile *profile;
3475 :     int default_context_set = 0;
3476 :     int count = 0;
3477 :    
3478 :     memset(&default_profile, 0, sizeof(default_profile));
3479 :     #if defined (AST_JB)
3480 :     memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
3481 :     #endif
3482 : amartin 128
3483 : jtarlton 260 default_profile.coding = 0;
3484 : amartin 125
3485 :     #if defined (AST16)
3486 :     if ((cfg = ast_config_load(configfile, config_flags))) {
3487 :     #else
3488 :     if ((cfg = ast_config_load(configfile))) {
3489 :     #endif
3490 :     for (entry = ast_category_browse(cfg, NULL); entry != NULL; entry = ast_category_browse(cfg, entry)) {
3491 :     if (strcmp(entry, "settings") == 0) {
3492 : amartin 128
3493 : amartin 125 for (v = ast_variable_browse(cfg, entry); v ; v = v->next) {
3494 :    
3495 :     if (!strcmp(v->name, "debug")) {
3496 :     globals.debug = atoi(v->value);
3497 :     } else if (!strcmp(v->name, "more_threads")) {
3498 :     globals.more_threads = ast_true(v->value);
3499 :     }
3500 :     #if defined (AST_JB)
3501 :     if (ast_jb_read_conf(&global_jbconf, v->name, v->value) == 0) {
3502 : amartin 128 ast_log(LOG_NOTICE, "Woomera AST JB Opt %s = %s \n",
3503 : amartin 125 v->name,v->value);
3504 :     continue;
3505 :     }
3506 :     #endif
3507 :     }
3508 :    
3509 :     } else {
3510 :     int new = 0;
3511 :     float gain;
3512 :     count++;
3513 :     if (!strcmp(entry, "default")) {
3514 :     profile = &default_profile;
3515 :     } else {
3516 : jtarlton 260 if ((profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, entry))) {
3517 : amartin 125 clone_woomera_profile(profile, &default_profile);
3518 :     } else {
3519 :     if((profile = create_woomera_profile(&default_profile))) {
3520 :     new = 1;
3521 :     } else {
3522 :     ast_log(LOG_ERROR, "Memory Error!\n");
3523 :     }
3524 :     }
3525 :     }
3526 :     strncpy(profile->name, entry, sizeof(profile->name) - 1);
3527 :     profile->coding=AST_FORMAT_SLINEAR;
3528 :    
3529 :     /*default is inbound and outbound enabled */
3530 :     ast_set_flag(profile, PFLAG_INBOUND | PFLAG_OUTBOUND);
3531 :     for (v = ast_variable_browse(cfg, entry); v ; v = v->next) {
3532 :     if (!strcmp(v->name, "audio_ip")) {
3533 :     strncpy(profile->audio_ip, v->value, sizeof(profile->audio_ip) - 1);
3534 :     } else if (!strcmp(v->name, "host")) {
3535 :     strncpy(profile->woomera_host, v->value, sizeof(profile->woomera_host) - 1);
3536 :     } else if (!strcmp(v->name, "max_calls")) {
3537 :     int max = atoi(v->value);
3538 :     if (max > 0) {
3539 :     profile->max_calls = max;
3540 :     }
3541 :     } else if (!strcmp(v->name, "port")) {
3542 :     profile->woomera_port = atoi(v->value);
3543 :     } else if (!strcmp(v->name, "disabled")) {
3544 :     ast_set2_flag(profile, ast_true(v->value), PFLAG_DISABLED);
3545 :     } else if (!strcmp(v->name, "inbound")) {
3546 :     if (ast_false(v->value)) {
3547 :     ast_clear_flag(profile, PFLAG_INBOUND);
3548 :     }
3549 :     } else if (!strcmp(v->name, "outbound")) {
3550 :     if (ast_false(v->value)) {
3551 :     ast_clear_flag(profile, PFLAG_OUTBOUND);
3552 :     }
3553 :     } else if (!strcmp(v->name, "context")) {
3554 :     if(!default_context_set){
3555 : jtarlton 239 default_context_set = 1;
3556 : amartin 125 strncpy(profile->default_context, v->value, sizeof(profile->default_context) - 1);
3557 :     }
3558 :     strncpy(profile->context, v->value, sizeof(profile->context) - 1);
3559 :     } else if (!strcmp(v->name, "default_context")) {
3560 : jtarlton 239 default_context_set = 1;
3561 : amartin 125 strncpy(profile->default_context, v->value, sizeof(profile->default_context) - 1);
3562 :     } else if (!strcmp(v->name, "group")) {
3563 :     int group_num = atoi(v->value);
3564 :     if (group_num < 0) {
3565 : amartin 128 ast_log(LOG_ERROR, "Invalid group:%d (less than zero) - ignoring\n", group_num);
3566 : jtarlton 239 } else if (group_num > WOOMERA_MAX_TRUNKGROUPS) {
3567 : amartin 125 ast_log(LOG_ERROR, "Invalid trunkgroup:%d (exceeds max:%d) -ignoring\n", group_num, WOOMERA_MAX_TRUNKGROUPS);
3568 :     } else {
3569 : jtarlton 239 if (profile->tg_context[group_num] != NULL) {
3570 : amartin 125 ast_free(profile->tg_context[group_num]);
3571 :     }
3572 :     profile->tg_context[group_num] = strdup(profile->context);
3573 :    
3574 : jtarlton 239 if (profile->tg_language[group_num] != NULL) {
3575 : amartin 125 ast_free(profile->tg_language[group_num]);
3576 :     }
3577 : jtarlton 239 if (strlen(profile->language)){
3578 : amartin 125 profile->tg_language[group_num] = strdup(profile->language);
3579 :     }
3580 :     }
3581 :     } else if (!strcmp(v->name, "language")) {
3582 :     strncpy(profile->language, v->value, sizeof(profile->language) - 1);
3583 :     } else if (!strcmp(v->name, "dtmf_enable")) {
3584 :     profile->dtmf_enable = atoi(v->value);
3585 : amartin 128 } else if (!strcmp(v->name, "rtp_enable")) {
3586 :     profile->rtp_enable = atoi(v->value);
3587 : amartin 125 } else if (!strcmp(v->name, "fax_detect")) {
3588 :     profile->faxdetect = atoi(v->value);
3589 :     ast_log(LOG_NOTICE, "Profile {%s} Fax Detect %s %p \n",
3590 :     entry, profile->faxdetect?"Enabled":"Disabled", profile);
3591 :    
3592 :     } else if (!strcmp(v->name, "jb_enable")) {
3593 :     profile->jb_enable = atoi(v->value);
3594 :     ast_log(LOG_NOTICE, "Profile {%s} Jitter Buffer %s %p \n",
3595 :     entry,profile->jb_enable?"Enabled":"Disabled",profile);
3596 :    
3597 :     } else if (!strcmp(v->name, "jbenable")) {
3598 :     profile->jb_enable = atoi(v->value);
3599 :     ast_log(LOG_NOTICE, "Profile {%s} Jitter Buffer %s %p\n",
3600 :     entry,profile->jb_enable?"Enabled":"Disabled",profile);
3601 :    
3602 :     } else if (!strcmp(v->name, "progress_enable")) {
3603 :     profile->progress_enable = atoi(v->value);
3604 : amartin 128
3605 : amartin 125 } else if (!strcmp(v->name, "coding")) {
3606 :     if (strcmp(v->value, "alaw") == 0) {
3607 :     profile->coding=AST_FORMAT_ALAW;
3608 : amartin 128 }
3609 : amartin 125 if (strcmp(v->value, "ulaw") == 0) {
3610 :     profile->coding=AST_FORMAT_ULAW;
3611 : amartin 128 }
3612 :    
3613 :     } else if (!strcmp(v->name, "videocoding")) {
3614 :     if (strcmp(v->value, "h263") == 0) {
3615 :     profile->videocoding=AST_FORMAT_H263;
3616 :     }
3617 : amartin 125 } else if (!strcmp(v->name, "woomera_udp_seq")) {
3618 :     int udp_seq = atoi(v->value);
3619 :     if (udp_seq > 0) {
3620 :     profile->udp_seq=1;
3621 :     }
3622 :    
3623 :     } else if (!strcmp(v->name, "base_media_port")) {
3624 :     int base_port = atoi(v->value);
3625 :     if (base_port > 0) {
3626 :     woomera_base_media_port = base_port;
3627 :     woomera_max_media_port = woomera_base_media_port + WOOMERA_MAX_MEDIA_PORTS;
3628 :     }
3629 :    
3630 :     } else if (!strcmp(v->name, "max_media_ports")) {
3631 :     int max_ports = atoi(v->value);
3632 :     if (max_ports > 0 && max_ports > WOOMERA_MAX_MEDIA_PORTS) {
3633 :     woomera_max_media_port = woomera_base_media_port + max_ports;
3634 :     }
3635 :    
3636 :     } else if (!strcmp(v->name, "rxgain") && profile->coding) {
3637 :     if (sscanf(v->value, "%f", &gain) != 1) {
3638 :     ast_log(LOG_NOTICE, "Invalid rxgain: %s\n", v->value);
3639 :     } else {
3640 :     woomera_config_gain(profile,gain,1);
3641 : amartin 128 }
3642 : amartin 125 } else if (!strcmp(v->name, "txgain") && profile->coding) {
3643 :     if (sscanf(v->value, "%f", &gain) != 1) {
3644 :     ast_log(LOG_NOTICE, "Invalid txgain: %s\n", v->value);
3645 :     } else {
3646 :     woomera_config_gain(profile,gain,0);
3647 : amartin 128 }
3648 :     }
3649 : amartin 125 }
3650 :    
3651 :     ASTOBJ_CONTAINER_LINK(&woomera_profile_list, profile);
3652 :     }
3653 :     }
3654 :     ast_config_destroy(cfg);
3655 :     } else {
3656 :     return 0;
3657 :     }
3658 :    
3659 :     return count;
3660 :    
3661 :     }
3662 :    
3663 :     static int create_udp_socket(char *ip, int port, struct sockaddr_in *sockaddr, int client)
3664 :     {
3665 :     int rc, sd = -1;
3666 :     struct sockaddr_in servAddr, *addr, cliAddr;
3667 :     struct hostent hps, *hp;
3668 :     struct hostent *result;
3669 :     char buf[512];
3670 : jtarlton 238 int err = 0;
3671 : amartin 125
3672 :     memset(&hps,0,sizeof(hps));
3673 : jtarlton 238 hp = &hps;
3674 : amartin 125
3675 :     if(sockaddr) {
3676 :     addr = sockaddr;
3677 :     } else {
3678 :     addr = &servAddr;
3679 :     }
3680 : amartin 128
3681 : amartin 125 if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) > -1) {
3682 : amartin 128
3683 : amartin 125 gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err);
3684 :     if (result) {
3685 : amartin 128
3686 : amartin 125 addr->sin_family = hp->h_addrtype;
3687 :     memcpy((char *) &addr->sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
3688 :     addr->sin_port = htons(port);
3689 :    
3690 : amartin 128 if (globals.debug > 4) {
3691 : jtarlton 238 ast_log(LOG_NOTICE, "MEDIA udp IP=%s:%d\n", ast_inet_ntoa(addr->sin_addr), port);
3692 : amartin 125 }
3693 :    
3694 :     if (client) {
3695 :     cliAddr.sin_family = AF_INET;
3696 :     cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
3697 :     cliAddr.sin_port = htons(0);
3698 :     rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
3699 :     } else {
3700 :     rc = bind(sd, (struct sockaddr *) addr, sizeof(cliAddr));
3701 :     }
3702 :     if (rc < 0) {
3703 :     if (globals.debug > 4) {
3704 :     ast_log(LOG_ERROR,
3705 : jtarlton 238 "Failed to bind to udp socket %s/%i %s\n",
3706 : amartin 157 ip, port, strerror(errno));
3707 : amartin 125 }
3708 : amartin 128
3709 : amartin 125 woomera_close_socket(&sd);
3710 : amartin 128
3711 : amartin 125 } else if (globals.debug > 5) {
3712 : amartin 128 ast_log(LOG_NOTICE, "Socket Binded %s to %s/%d\n",
3713 : amartin 125 client ? "client" : "server", ip, port);
3714 :     }
3715 : amartin 128
3716 : amartin 125 } else {
3717 :     ast_log(LOG_ERROR,
3718 :     "Error opening udp: gethostbyname failed %s/%i %s\n",
3719 : jtarlton 238 ip, port, strerror(errno));
3720 : amartin 128
3721 : amartin 125 woomera_close_socket(&sd);
3722 :     }
3723 :     } else {
3724 :     ast_log(LOG_ERROR,
3725 : jtarlton 238 "failed to create a socket! %s/%i %s\n",
3726 :     ip, port, strerror(errno));
3727 : amartin 125 }
3728 :    
3729 :     return sd;
3730 :     }
3731 :    
3732 : jtarlton 260
3733 : amartin 128 static struct ast_rtp * create_rtp(char *ip)
3734 :     {
3735 :     struct hostent hps, *hp;
3736 :     struct hostent *result;
3737 :     char buf[512];
3738 : jtarlton 238 int err = 0;
3739 : amartin 128 struct ast_rtp *rtp = NULL;
3740 :     struct in_addr addr;
3741 :     struct sockaddr_in us;
3742 : amartin 157
3743 : jtarlton 238 memset(&hps, 0, sizeof(hps));
3744 :     hp = &hps;
3745 : amartin 125
3746 : amartin 128 gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err);
3747 :     if (result)
3748 :     {
3749 :     memcpy((char *) &addr, hp->h_addr_list[0], hp->h_length);
3750 : amartin 157 rtp = ast_rtp_new_with_bindaddr(sched, io, 1 /*rtcp*/, 0, addr);
3751 : amartin 128
3752 :     if (rtp)
3753 :     {
3754 : amartin 157 ast_rtp_get_us(rtp, &us);
3755 : jtarlton 238 ast_log(LOG_NOTICE,"Created RTP IP=%s\n", ast_inet_ntoa(addr));
3756 : amartin 128 }
3757 :     else
3758 :     {
3759 : jtarlton 238 ast_log(LOG_ERROR,"Failed to create RTP IP=%s %s\n", ip, strerror(errno));
3760 : amartin 128 }
3761 :     }
3762 :     else
3763 :     {
3764 :     ast_log(LOG_ERROR,
3765 : jtarlton 238 "Failed to get host for RTP IP=%s %s\n",
3766 : amartin 128 ip, strerror(errno));
3767 :     }
3768 :    
3769 :     return rtp;
3770 :     }
3771 :    
3772 : jtarlton 260
3773 : amartin 128 static int connect_woomera(int *new_socket, woomera_profile *profile, int flags)
3774 : amartin 125 {
3775 :     struct sockaddr_in localAddr, remoteAddr;
3776 :     struct hostent *hp, *result;
3777 :     struct hostent ahp;
3778 : jtarlton 238 int res = 0, err = 0;
3779 :     hp = &ahp;
3780 : amartin 125 char buf[512];
3781 :    
3782 : jtarlton 238 *new_socket = -1;
3783 : amartin 125
3784 :     gethostbyname_r(profile->woomera_host, hp, buf, sizeof(buf), &result, &err);
3785 :     if (result) {
3786 :     remoteAddr.sin_family = hp->h_addrtype;
3787 :     memcpy((char *) &remoteAddr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
3788 :     remoteAddr.sin_port = htons(profile->woomera_port);
3789 :     do {
3790 :     /* create socket */
3791 :     *new_socket = socket(AF_INET, SOCK_STREAM, 0);
3792 :     if (*new_socket < 0) {
3793 : jtarlton 238 ast_log(LOG_ERROR, "Cannot open socket to %s/%d\n", profile->woomera_host, profile->woomera_port);
3794 : amartin 125 res = 0;
3795 :     break;
3796 :     }
3797 : amartin 128
3798 : amartin 125 /* bind any port number */
3799 :     localAddr.sin_family = AF_INET;
3800 :     localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
3801 :     localAddr.sin_port = htons(0);
3802 : amartin 128
3803 : amartin 125 res = bind(*new_socket, (struct sockaddr *) &localAddr, sizeof(localAddr));
3804 :     if (res < 0) {
3805 : jtarlton 238 ast_log(LOG_ERROR, "Cannot bind to %s/%d\n", profile->woomera_host, profile->woomera_port);
3806 : amartin 125 woomera_close_socket(new_socket);
3807 :     res = 0;
3808 :     break;
3809 :     }
3810 : amartin 128
3811 : amartin 125 /* connect to server */
3812 :     res = connect(*new_socket, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr));
3813 :     if (res < 0) {
3814 : jtarlton 238 ast_log(LOG_ERROR, "Cannot connect to {%s} %s/%d\n", profile->name, profile->woomera_host, profile->woomera_port);
3815 : amartin 125 res = 0;
3816 :     woomera_close_socket(new_socket);
3817 :     break;
3818 :     }
3819 :     res = 1;
3820 :     } while(0);
3821 : amartin 128
3822 : amartin 125 } else {
3823 :     if (globals.debug > 2) {
3824 : jtarlton 238 ast_log(LOG_ERROR, "Host lookup failed for {%s} %s/%d\n",
3825 :     profile->name, profile->woomera_host, profile->woomera_port);
3826 : amartin 125 }
3827 :     res = 0;
3828 :     }
3829 :     if (res > 0) {
3830 :     int flag = 1;
3831 :     woomera_message wmsg;
3832 :     memset(&wmsg,0,sizeof(wmsg));
3833 :    
3834 :     /* disable nagle's algorythm */
3835 :     res = setsockopt(*new_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
3836 :    
3837 :     if (!(flags & WCFLAG_NOWAIT)) {
3838 :     /* kickstart the session waiting for a HELLO */
3839 : amartin 231 res = woomera_printf(NULL, *new_socket, "%s", WOOMERA_RECORD_SEPARATOR);
3840 : jtarlton 238 if (res < 0 ) {
3841 : amartin 231 woomera_close_socket(new_socket);
3842 :     return *new_socket;
3843 : jtarlton 235 }
3844 : amartin 231
3845 : amartin 125 if ((res = woomera_message_parse(*new_socket,
3846 : jtarlton 195 &wmsg,
3847 : jtarlton 239 -5000, /*WOOMERA_HARD_TIMEOUT,*/
3848 : jtarlton 195 profile,
3849 :     NULL
3850 :     )) < 0) {
3851 : amartin 125 ast_log(LOG_ERROR, "{%s} Timed out waiting for a hello from woomera!\n", profile->name);
3852 :     woomera_close_socket(new_socket);
3853 : amartin 231 return *new_socket;
3854 : amartin 125 }
3855 : jtarlton 235
3856 : amartin 125 if (res > 0 && strcasecmp(wmsg.command, "HELLO")) {
3857 :     ast_log(LOG_ERROR, "{%s} unexpected reply [%s] while waiting for a hello from woomera!\n", profile->name, wmsg.command);
3858 :     woomera_close_socket(new_socket);
3859 : jtarlton 195 } else {
3860 : amartin 125 char *audio_format;
3861 :     if (globals.debug > 2) {
3862 : jtarlton 238 ast_log(LOG_NOTICE, "Woomera Got HELLO on connect! %s Version %s\n", profile->name, woomera_message_header(&wmsg, "Version"));
3863 : amartin 125 }
3864 : jtarlton 255 if (!svrversion_init && woomera_message_header(&wmsg, "Version")) {
3865 :     svrversion_init = 1;
3866 :     strncpy(svrversion,
3867 : jtarlton 238 woomera_message_header(&wmsg, "Version"),
3868 : jtarlton 255 sizeof(svrversion)-1);
3869 : amartin 125 }
3870 : amartin 128
3871 : amartin 125 audio_format = woomera_message_header(&wmsg, "Raw-Format");
3872 :     if (!audio_format) {
3873 :     audio_format = woomera_message_header(&wmsg, "Raw-Audio-Format");
3874 :     }
3875 : amartin 128 if (!audio_format) {
3876 :     audio_format = woomera_message_header(&wmsg, "RTP-Audio-Format");
3877 :     }
3878 :    
3879 : amartin 125 if (audio_format) {
3880 : amartin 128
3881 : jtarlton 238 profile->coding = AST_FORMAT_SLINEAR;
3882 : amartin 128
3883 : jtarlton 238 if (strncasecmp(audio_format, "PCM-16", 20) == 0){
3884 :     profile->coding = AST_FORMAT_SLINEAR;
3885 :     } else if (strncasecmp(audio_format, "ULAW", 15) == 0) {
3886 :     profile->coding = AST_FORMAT_ULAW;
3887 :     } else if (strncasecmp(audio_format, "ALAW", 15) == 0) {
3888 :     profile->coding = AST_FORMAT_ALAW;
3889 : amartin 125 } else {
3890 :     ast_log(LOG_ERROR, "Error: Invalid Raw-Format %s\n",
3891 : jtarlton 195 audio_format);
3892 : amartin 125 }
3893 : amartin 128
3894 : amartin 125 if (globals.debug > 2) {
3895 : jtarlton 238 ast_log(LOG_NOTICE, "Setting RAW Format to %s %i (p%i:u%i:a%i)\n",
3896 :     audio_format, profile->coding,
3897 :     AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, AST_FORMAT_ALAW);
3898 : amartin 125 }
3899 :     }
3900 :     }
3901 :     }
3902 :    
3903 :     } else {
3904 :     if (globals.debug > 2) {
3905 : jtarlton 238 ast_log(LOG_ERROR, "Woomera {%s} connection failed: %s/%d %s\n",
3906 :     profile->name, profile->woomera_host, profile->woomera_port, strerror(errno));
3907 : amartin 125 }
3908 :     woomera_close_socket(new_socket);
3909 :     }
3910 :    
3911 :     return *new_socket;
3912 :     }
3913 :    
3914 : jtarlton 260
3915 : amartin 128 static int init_woomera(void)
3916 : amartin 125 {
3917 :     woomera_profile *profile;
3918 :     ast_mutex_lock(&lock);
3919 : amartin 128
3920 : amartin 125 if (!config_woomera()) {
3921 :     ast_mutex_unlock(&lock);
3922 :     return 0;
3923 :     }
3924 : amartin 128
3925 : amartin 125 ASTOBJ_CONTAINER_TRAVERSE(&woomera_profile_list, 1, do {
3926 :     ASTOBJ_RDLOCK(iterator);
3927 :     profile = iterator;
3928 :     if (!ast_test_flag(profile, PFLAG_DISABLED)) {
3929 :     launch_woomera_thread(profile);
3930 :     }
3931 :     ASTOBJ_UNLOCK(iterator);
3932 :     } while(0));
3933 :    
3934 :     ast_mutex_unlock(&lock);
3935 :     return 1;
3936 :     }
3937 :    
3938 : jtarlton 260
3939 : jtarlton 238 static struct ast_channel *woomera_new(const char *type,
3940 :     int format,
3941 :     void *data,
3942 :     int *cause,
3943 :     woomera_profile *parent_profile)
3944 : amartin 125 {
3945 :     private_object *tech_pvt;
3946 :     struct ast_channel *chan = NULL;
3947 :     char name[100];
3948 :    
3949 :     snprintf(name, sizeof(name), "%s/%s-%04x", type, (char *)data, rand() & 0xffff);
3950 :    
3951 :     if (!(tech_pvt = ast_malloc(sizeof(private_object)))) {
3952 :     ast_log(LOG_ERROR, "Memory Error!\n");
3953 :     return NULL;
3954 :     }
3955 :     memset(tech_pvt, 0, sizeof(private_object));
3956 :    
3957 :     #if defined (AST14) || defined (AST16)
3958 :     chan = ast_channel_alloc(0, AST_STATE_DOWN, "", "", "", "", "", 0, "%s", name);
3959 :     #else
3960 :     chan = ast_channel_alloc(1);
3961 :     #endif
3962 :     if (chan) {
3963 :     chan->nativeformats = WFORMAT;
3964 :     #if !defined (AST14) && !defined (AST16)
3965 :     chan->type = type;
3966 :     snprintf(chan->name, sizeof(chan->name), "%s/%s-%04x", chan->type, (char *)data, rand() & 0xffff);
3967 :     #endif
3968 : amartin 128
3969 : amartin 125 chan->writeformat = chan->rawwriteformat = chan->readformat = WFORMAT;
3970 :     chan->_state = AST_STATE_DOWN;
3971 :     chan->_softhangup = 0;
3972 : amartin 128
3973 : amartin 125 tech_count++;
3974 : jtarlton 255 tech_pvt->coding = WFORMAT;
3975 : amartin 128
3976 : amartin 125 ast_mutex_init(&tech_pvt->iolock);
3977 :     ast_mutex_init(&tech_pvt->event_queue.lock);
3978 :     tech_pvt->command_channel = -1;
3979 :     chan->tech_pvt = tech_pvt;
3980 :     chan->tech = &technology;
3981 :     tech_pvt->udp_socket = -1;
3982 :    
3983 :     ast_clear_flag(chan, AST_FLAGS_ALL);
3984 :     memset(&tech_pvt->frame, 0, sizeof(tech_pvt->frame));
3985 :     tech_pvt->frame.frametype = AST_FRAME_VOICE;
3986 :     tech_pvt->frame.subclass = WFORMAT;
3987 :     tech_pvt->frame.offset = AST_FRIENDLY_OFFSET;
3988 :    
3989 :     tech_pvt->owner = chan;
3990 :    
3991 :     chan->nativeformats = tech_pvt->coding;
3992 :     chan->writeformat = chan->rawwriteformat = chan->readformat = tech_pvt->coding;
3993 :     tech_pvt->frame.subclass = tech_pvt->coding;
3994 :    
3995 : jtarlton 238 tech_pvt->pri_cause = AST_CAUSE_NORMAL_CLEARING;
3996 : amartin 128
3997 : jtarlton 255 ast_copy_string(tech_pvt->mohinterpret, mohinterpret, sizeof(tech_pvt->mohinterpret));
3998 :     ast_copy_string(tech_pvt->mohsuggest, mohsuggest, sizeof(tech_pvt->mohsuggest));
3999 : amartin 125
4000 :     ASTOBJ_CONTAINER_LINK(&private_object_list, tech_pvt);
4001 : amartin 128
4002 : amartin 125 ast_mutex_lock(&usecnt_lock);
4003 :     usecnt++;
4004 :     ast_mutex_unlock(&usecnt_lock);
4005 :    
4006 :     } else {
4007 :     ast_log(LOG_ERROR, "Can't allocate a channel\n");
4008 :     }
4009 :    
4010 : amartin 128
4011 : amartin 125 return chan;
4012 :     }
4013 :    
4014 :    
4015 :     /********************CHANNEL METHOD LIBRARY********************
4016 :     * This is the actual functions described by the prototypes above.
4017 :     *
4018 :     */
4019 :    
4020 :    
4021 : jtarlton 260 /*!
4022 :     * parse 'data' a url-like destination string, allocate a channel and a private
4023 :     * structure and return the newly-setup channel.
4024 : amartin 125 */
4025 :     static struct ast_channel *tech_requester(const char *type, int format, void *data, int *cause)
4026 :     {
4027 :     struct ast_channel *chan = NULL;
4028 :    
4029 :     if (globals.panic) {
4030 :     return NULL;
4031 :     }
4032 :    
4033 :     if ((chan = woomera_new(type, format, data, cause, NULL))) {
4034 :     private_object *tech_pvt;
4035 : amartin 128
4036 : amartin 125 tech_pvt = chan->tech_pvt;
4037 :    
4038 :     if (tech_pvt->owner) {
4039 :     tech_pvt->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
4040 :     }
4041 :    
4042 :     ast_set_flag(tech_pvt, TFLAG_PBX); /* so we know we dont have to free the channel ourselves */
4043 : amartin 128
4044 : amartin 125 if (globals.debug > 1 && option_verbose > 1) {
4045 :     if (option_verbose > 2) {
4046 :     ast_verbose(WOOMERA_DEBUG_PREFIX "+++REQ %s\n", chan->name);
4047 :     }
4048 :     }
4049 :    
4050 :     } else {
4051 :     ast_log(LOG_ERROR, "Woomera: Can't allocate a channel\n");
4052 :     }
4053 :    
4054 :     return chan;
4055 :     }
4056 :    
4057 :     #if defined (AST14) || defined (AST16)
4058 :     static int tech_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
4059 :     {
4060 :     return 0;
4061 :     }
4062 :     #endif
4063 :    
4064 : jtarlton 260
4065 :     /*!
4066 :     * Send a DTMF character
4067 :     */
4068 : amartin 125 static int tech_send_digit(struct ast_channel *self, char digit)
4069 :     {
4070 :     private_object *tech_pvt = self->tech_pvt;
4071 :     int res = 0;
4072 :    
4073 :     if (globals.debug > 1 && option_verbose > 2) {
4074 :     if (option_verbose > 2) {
4075 :     ast_verbose(WOOMERA_DEBUG_PREFIX "+++DIGIT %s '%c'\n",self->name, digit);
4076 :     }
4077 :     }
4078 :    
4079 : amartin 128 /* we don't have time to make sure the dtmf command is successful cos asterisk again
4080 : amartin 125 is much too impaitent... so we will cache the digits so the monitor thread can send
4081 :     it for us when it has time to actually wait.
4082 :     */
4083 :     ast_mutex_lock(&tech_pvt->iolock);
4084 :     snprintf(tech_pvt->dtmfbuf + strlen(tech_pvt->dtmfbuf), sizeof(tech_pvt->dtmfbuf), "%c", digit);
4085 :     ast_set_flag(tech_pvt, TFLAG_DTMF);
4086 :     ast_mutex_unlock(&tech_pvt->iolock);
4087 :    
4088 :     return res;
4089 :     }
4090 :    
4091 : jtarlton 260
4092 :     /*!
4093 :     * Initiate a call on a channel. 'dest' has been passed telling you
4094 :     * where to call but you may already have that information from the requester
4095 :     * method not sure why it sends it twice, maybe it changed since then *shrug*
4096 : amartin 125 * You also have timeout (in ms) so you can tell how long the caller
4097 :     * is willing to wait for the call to be complete.
4098 :     */
4099 :     static int tech_call(struct ast_channel *self, char *dest, int timeout)
4100 :     {
4101 :     private_object *tech_pvt = self->tech_pvt;
4102 :     char *workspace;
4103 :     char *p;
4104 :     char *c;
4105 :    
4106 :     #if !defined (AST14) && !defined (AST16)
4107 : amartin 128 self->type = WOOMERA_CHAN_NAME;
4108 : amartin 125 #endif
4109 : amartin 128
4110 : amartin 125 self->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
4111 :    
4112 :     if (globals.panic) {
4113 :     goto tech_call_failed;
4114 :     }
4115 : jtarlton 242
4116 : amartin 125 if (globals.debug > 2) {
4117 :     ast_log(LOG_NOTICE, "TECH CALL %s (%s <%s>) pres=0x%02X dest=%s\n",
4118 : jtarlton 242 self->name, self->cid.cid_name,
4119 :     self->cid.cid_num,
4120 :     self->cid.cid_pres,
4121 :     dest);
4122 : amartin 125 }
4123 :    
4124 :     if (self->cid.cid_name) {
4125 :     strncpy(tech_pvt->cid_name, self->cid.cid_name, sizeof(tech_pvt->cid_name)-1);
4126 :     }
4127 : jtarlton 242
4128 : amartin 125 if (self->cid.cid_num) {
4129 :     strncpy(tech_pvt->cid_num, self->cid.cid_num, sizeof(tech_pvt->cid_num)-1);
4130 :     }
4131 : jtarlton 242
4132 : amartin 125 tech_pvt->cid_pres = self->cid.cid_pres;
4133 :    
4134 :     if (self->cid.cid_rdnis) {
4135 : jtarlton 235 tech_pvt->cid_rdnis = strdup(self->cid.cid_rdnis);
4136 : amartin 125 }
4137 :    
4138 : jtarlton 246 /* Parse out dialstring parts.
4139 :     * [profile/][protocol:]address
4140 :     */
4141 : amartin 125 if ((workspace = ast_strdupa(dest))) {
4142 : jtarlton 246 char *addr, *profile_name, *protocol = NULL;
4143 : amartin 125 woomera_profile *profile;
4144 :     int err;
4145 :    
4146 :     if ((addr = strchr(workspace, ':'))) {
4147 : jtarlton 248 *addr = '\0';
4148 :     addr++;
4149 : jtarlton 246 if ((protocol = strchr(workspace, '/'))) {
4150 : jtarlton 242 profile_name = workspace;
4151 : jtarlton 246 *protocol = '\0';
4152 :     protocol++;
4153 : amartin 125 }
4154 : jtarlton 242 else {
4155 :     profile_name = "default";
4156 : jtarlton 246 protocol = workspace;
4157 : jtarlton 242 }
4158 : amartin 125 } else {
4159 : jtarlton 242 profile_name = "default";
4160 : jtarlton 246 protocol = NULL;
4161 : amartin 125 addr = workspace;
4162 :     }
4163 : amartin 128
4164 : amartin 125 if (! (profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, profile_name))) {
4165 : jtarlton 247 ast_log(LOG_WARNING, "Profile %s not found, using default\n", profile_name);
4166 : amartin 125 profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, "default");
4167 :     }
4168 : amartin 128
4169 : amartin 125 if (!profile) {
4170 : jtarlton 242 ast_log(LOG_ERROR, "Call aborted, unable to find profile: %s\n", profile_name);
4171 : amartin 125 goto tech_call_failed;
4172 :     }
4173 : amartin 128
4174 : amartin 125 if (!ast_test_flag(profile, PFLAG_OUTBOUND)) {
4175 : jtarlton 242 ast_log(LOG_ERROR, "This profile (%s) is not allowed to make outbound calls! Call Aborted!\n", profile_name);
4176 : amartin 125 goto tech_call_failed;
4177 :     }
4178 :    
4179 :     if (profile->max_calls) {
4180 :     if (profile->call_count >= profile->max_calls) {
4181 :     if (globals.debug > 1 && option_verbose > 2) {
4182 : jtarlton 242 ast_log(LOG_ERROR, "This profile (%s) is at call limit of %d\n",
4183 :     profile_name, profile->max_calls);
4184 : amartin 125 }
4185 :     goto tech_call_failed;
4186 : amartin 128 }
4187 : amartin 125 }
4188 :    
4189 :     snprintf(tech_pvt->dest, sizeof(tech_pvt->dest), "%s", addr ? addr : "");
4190 : jtarlton 246 snprintf(tech_pvt->proto, sizeof(tech_pvt->proto), "%s", protocol ? protocol : "");
4191 : amartin 125
4192 :     if (globals.debug > 2) {
4193 : jtarlton 247 ast_log(LOG_NOTICE, "TECH CALL: profile=%s proto=%s addr=%s Coding=%i\n",
4194 :     profile_name, protocol, addr, profile->coding);
4195 : amartin 125 }
4196 :    
4197 :     tech_pvt->timeout = timeout;
4198 : jtarlton 242 err = tech_init(tech_pvt, profile, TFLAG_OUTBOUND);
4199 : amartin 128 if (err) {
4200 : amartin 125 if (globals.debug > 2) {
4201 :     ast_log(LOG_ERROR, "Error: Outbound Call Failed \n");
4202 :     }
4203 :     goto tech_call_failed;
4204 :     }
4205 : amartin 128
4206 :     #if 1
4207 : amartin 125 if ((p = strrchr(self->name, '/'))) {
4208 :     c = p-1;
4209 : jtarlton 242 if (*c == 'c' || *c== 'C') {
4210 : amartin 125 ast_set_flag(tech_pvt, TFLAG_CONFIRM_ANSWER_ENABLED);
4211 :     ast_set_flag(tech_pvt, TFLAG_CONFIRM_ANSWER);
4212 :     }
4213 :     }
4214 : amartin 128 #endif
4215 :    
4216 : amartin 125 woomera_send_progress(tech_pvt);
4217 :     }
4218 :     self->hangupcause = AST_CAUSE_NORMAL_CLEARING;
4219 :     return 0;
4220 :    
4221 :     tech_call_failed:
4222 : jtarlton 195
4223 : amartin 125 if (globals.debug > 1 && option_verbose > 2) {
4224 :     ast_log(LOG_ERROR, "Error: Outbound Call Failed %p \n",tech_pvt);
4225 :     }
4226 :     self->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
4227 :     my_ast_softhangup(self, tech_pvt, AST_SOFTHANGUP_EXPLICIT);
4228 :     return -1;
4229 :     }
4230 :    
4231 :    
4232 : jtarlton 260 /*!
4233 :     * End a call on channel 'self'
4234 : amartin 125 * Now is your chance to tear down and free the private object
4235 :     * from the channel it's about to be freed so you must do so now
4236 :     * or the object is lost. Well I guess you could tag it for reuse
4237 :     * or for destruction and let a monitor thread deal with it too.
4238 :     * during the load_module routine you have every right to start up
4239 : amartin 128 * your own fancy schmancy bunch of threads or whatever else
4240 : amartin 125 * you want to do.
4241 :     */
4242 :     static int tech_hangup(struct ast_channel *self)
4243 :     {
4244 :     const char *ds;
4245 :     private_object *tech_pvt = self->tech_pvt;
4246 :     int res = 0;
4247 :    
4248 :     if (globals.debug > 2) {
4249 :     ast_log(LOG_NOTICE, "TECH HANGUP [%s] tech_pvt=%p c=%p\n",self->name,tech_pvt,self);
4250 :     }
4251 :    
4252 :     if (tech_pvt) {
4253 :    
4254 :     ast_mutex_lock(&tech_pvt->iolock);
4255 :    
4256 :     ast_set_flag(tech_pvt, TFLAG_TECHHANGUP);
4257 :     tech_pvt->owner=NULL;
4258 :     self->tech_pvt=NULL;
4259 :    
4260 : amartin 128 if (!self ||
4261 :     (!(ds = pbx_builtin_getvar_helper(self, "DIALSTATUS")) &&
4262 : amartin 125 !(ds = ast_cause2str(self->hangupcause)))) {
4263 :     ds = "NOEXIST";
4264 :     }
4265 :    
4266 :     ast_copy_string(tech_pvt->ds, ds, sizeof(tech_pvt->ds));
4267 :    
4268 :     ds=pbx_builtin_getvar_helper(self, "PRI_CAUSE");
4269 :     if (ds && atoi(ds)) {
4270 : jtarlton 255 tech_pvt->pri_cause = atoi(ds);
4271 : amartin 125 } else if (self->hangupcause) {
4272 : jtarlton 255 tech_pvt->pri_cause = self->hangupcause;
4273 : amartin 125 } else {
4274 : jtarlton 255 tech_pvt->pri_cause = AST_CAUSE_NORMAL_CLEARING;
4275 : amartin 125 }
4276 : amartin 128
4277 : amartin 125 if (globals.debug > 2) {
4278 :     ast_log(LOG_NOTICE, "TECH HANGUP [%s] Cause=%i HangCause=%i ds=%s\n",
4279 : jtarlton 255 self->name, tech_pvt->pri_cause, self->hangupcause, ds?ds:"N/A");
4280 : amartin 125 }
4281 :    
4282 :     if (tech_pvt->dsp) {
4283 : jtarlton 195 tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT;
4284 :     ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features);
4285 : jtarlton 255 tech_pvt->ast_dsp = 0;
4286 : jtarlton 195 }
4287 : amartin 125
4