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