[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 130 - (view) (download)

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