Parent Directory
|
Revision Log
Fix in clone_woomera_profile
1 /* 2 * Asterisk -- A telephony toolkit for Linux. 3 * 4 * Woomera Channel Driver 5 * 6 * Copyright (C) 05-09 7 * Nenad Corbic 8 * David Yat Sin 9 * Antony Martin (Dialogic Corp) 10 * John Tarlton (Dialogic Corp) 11 * Anthony Minessale II 12 * 13 * Nenad Corbic <ncorbic@sangoma.com> 14 * David Yat Sin <davidy@sangoma.com> 15 * Antony Martin <antony.martin@dialogic.com> 16 * John Tarlton <john.tarlton@dialogic.com> 17 * Anthony Minessale II <anthmct@yahoo.com> 18 * 19 * This program is free software, distributed under the terms of 20 * the GNU General Public License 21 * ============================================= 22 * 23 * v1.59 Antony Martin <antony.martin@dialogic.com> 24 * Apr 22 2010 25 * Fix in clone_woomera_profile. 26 * 27 * v1.58 John Tarlton <john.tarlton@dialogic.com> 28 * Mar 19 2010 29 * New app WoomeraStop currently allows WoomeraBackground 30 * 31 * v1.57 John Tarlton <john.tarlton@dialogic.com> 32 * Nov 4 2009 33 * Ensure rx gain processing is done on voice frames only. 34 * 35 * v1.56 Antony Martin <antony.martin@dialogic.com> 36 * Sep 30 2009 37 * Added Woomera play and record functionality. 38 * Native bridging support. 39 * 40 * v1.55 Antony Martin <antony.martin@dialogic.com> 41 * Jul 09 2009 42 * Changes for Asterisk 1.6.1 compatibility. 43 * 44 * v1.54 John Tarlton <john.tarlton@dialogic.com> 45 * Jun 12 2009 46 * Set dnid channel var on incoming call. 47 * 48 * v1.53 John Tarlton <john.tarlton@dialogic.com> 49 * Jun 11 2009 50 * Parse profile name from dial string, falling back to 'default' 51 * 52 * v1.52 John Tarlton <john.tarlton@dialogic.com> 53 * May 28 2009 54 * Check for dsp when processing the DTMF header of a MEDIA message. 55 * 56 * v1.51 Antony Martin <antony.martin@dialogic.com> 57 * Apr 30 2009 58 * Added RTP Audio 59 * 60 * v1.50 Nenad Corbic <ncorbic@sangoma.com> 61 * Apr 24 2009 62 * Bug fix on write socket. Check that write woomera socket failed. 63 * This update prevents socket warning messages on call congestion. 64 * 65 * v1.49 Nenad Corbic <ncorbic@sangoma.com> 66 * Apr 08 2009 67 * Bug fix on transfer. The owner was not 68 * properly updated causing unpredictable behaviour. 69 * 70 * v1.48 Nenad Corbic <ncorbic@sangoma.com> 71 * Apr 05 2009 72 * Updated locking on pbx_start 73 * 74 * v1.47 Nenad Corbic <ncorbic@sangoma.com> 75 * Apr 03 2009 76 * Added BLOCKER sanity check. 77 * 78 * v1.46 Nenad Corbic <ncorbic@sangoma.com> 79 * Mar 29 2009 80 * Added hup_pending stat to call_status 81 * Let tech_hangup destroy softhungup channel 82 * 83 * v1.45 Nenad Corbic <ncorbic@sangoma.com> 84 * Mar 27 2009 85 * Major updates on channel locking. 86 * This update fixes potential crashing issues 87 * under heavy load. Stress tested in 500+ call 88 * environment. 89 * 90 * v1.44 Nenad Corbic <ncorbic@sangoma.com> 91 * Mar 55 2009 92 * Updated woomera channel locking using 93 * DEADLOCK_AVOIDANCE. Fixed RDNIS transmission issue. 94 * 95 * v1.43 David Yat Sin <dyatsin@sangoma.com> 96 * Mar 01 2009 97 * Fix to support Callweaver svn trunk 98 * 99 * v1.42 David Yat Sin <dyatsin@sangoma.com> 100 * Feb 25 2009 101 * Fix to support Callweaver svn trunk 102 * 103 * v1.41 Nenad Corbic <ncorbic@sangoma.com> 104 * Jan 29 2008 105 * Bug introduced in 1.40 if WOOMERA uil1p parameter 106 * was not there transcoding was misconfigued. 107 * 108 * v1.40 Nenad Corbic <ncorbic@sangoma.com> 109 * Jan 26 2008 110 * Call Bearer Capability Feature 111 * Updated for Callweaver 112 * 113 * v1.39 David Yat Sin <dyatsin@sangoma.com> 114 * Dec 19 2008 115 * Support for Asterisk 1.6 116 * 117 * v1.38 David Yat Sin <dyatsin@sangoma.com> 118 * Dec 05 2008 119 * Support for fax_detect using Asterisk software DSP 120 * 121 * v1.37 Nenad Corbic <ncorbic@sangoma.com> 122 * Nov 26 2008 123 * Bug Fix: tech_read try again now checks for hangup 124 * 125 * v1.36 David Yat Sin <dyatsin@sangoma.com> 126 * Oct 14 2008 127 * Bug Fix: Call hangup on call park 128 * 129 * v1.35 Nenad Corbic <ncorbic@sangoma.com> 130 * Jul 23 2008 131 * Bug Fix: Check for cid_name. 132 * 133 * v1.34 Nenad Corbic <ncorbic@sangoma.com> 134 * Jul 23 2008 135 * Added udp tagging and rx/tx sync options for 136 * voice streams debugging. Not for production. 137 * 138 * v1.33 Nenad Corbic <ncorbic@sangoma.com> 139 * Jul 18 2008 140 * Added UDP Sequencing to check for dropped frames 141 * Should only be used for debugging. 142 * 143 * v1.32 David Yat Sin <davidy@sangoma.com> 144 * Jun 3 2008 145 * Updated for callweaver v1.2.0 146 * 147 * v1.31 Nenad Corbic <ncorbic@sangoma.com> 148 * v1.30 Nenad Corbic <ncorbic@sangoma.com> 149 * Jun 2 2008 150 * Added AST_CTONROL_RING event on outgoing call. 151 * Updated for CallWeaver 1.2 SVN 152 * 153 * v1.29 David Yat Sin <davidy@sangoma.com> 154 * Apr 30 2008 155 * Added AST_CONTROL_SRCUPDATE in tech_indicate 156 * 157 * v1.29 David Yat Sin <davidy@sangoma.com> 158 * April 29 2008 159 * Support for HW DTMF 160 * 161 * v1.28 David Yat Sin <davidy@sangoma.com> 162 * Apr 29 2008 163 * Fix for compilation issues with Callweaver v1.99 164 * 165 * v1.27 David Yat Sin <davidy@sangoma.com> 166 * Feb 13 2008 167 * Fix for ast_channel type not defined on 168 * outgoing calls, causing PHP agi scripts 169 * to fail 170 * 171 * v1.26 Nenad Corbic <ncorbic@sangoma.com> 172 * Feb 13 2008 173 * Compilation Update for callweaver 1.2-rc5 174 * 175 * v1.25 Nenad Corbic <ncorbic@sangoma.com> 176 * Feb 06 2008 177 * Bug fix in woomera message declaration 178 * Possible memory overflow 179 * 180 * v1.24 Nenad Corbic <ncorbic@sangoma.com> 181 * Jan 23 2008 182 * Removed LISTEN on every woomera channel. Listen 183 * only on master. Fixed jitterbuffer support on AST1.4 184 * 185 * v1.23 Nenad Corbic <ncorbic@sangoma.com> 186 * Jan 22 2008 187 * Implemented Music on Hold. 188 * 189 * v1.22 David Yat Sin <davidy@sangoma.com> 190 * Jan 11 2008 191 * rxgain and txgain configuration parameters 192 * are ignored if coding is not specified in 193 * woomera.conf 194 * 195 * v1.21 David Yat Sin <davidy@sangoma.com> 196 * Dec 27 2007 197 * Support for language 198 * 199 * v1.20 David Yat Sin <davidy@sangoma.com> 200 * Dec 20 2007 201 * Support for call confirmation 202 * Support for default context 203 * 204 * v1.19 Nenad Corbic <ncorbic@sangoma.com> 205 * Nov 30 2007 206 * Updated for latest CallWeaver 207 * Updated smgversion update on master socket 208 * restart. 209 * 210 * v1.18 Nenad Corbic <ncorbic@sangoma.com> 211 * Updated Channel-Name on outbound call 212 * Check queued events on ABORT 213 * Major Unit Testing done 214 * Ability to change chan name from Makefile 215 * 216 * v1.17 Nenad Corbic <ncorbic@sangoma.com> 217 * Updates for Asterisk 1.4 218 * Updated the release causes 219 * Updated for tech_indication 220 * 221 * v1.16 Nenad Corbic <ncorbic@sangoma.com> 222 * Added support for Asterisk 1.4 223 * Updated support for Callweaver 224 * 225 * v1.15 Nenad Corbic <ncorbic@sangoma.com> 226 * Added PRI_CAUSE and Q931-Cause-Code 227 * in woomera protocol. 228 * 229 * v1.14 Nenad Corbic <ncorbic@sangoma.com> 230 * Updated for session support 231 * 232 * v1.13 Nenad Corbic <ncorbic@sangoma.com> 233 * Added CallWeaver Support 234 * |->(thanks to Andre Schwaller) 235 * Updated codec negotiation for 236 * mutliple profiles. 237 * 238 * v1.12 Nenad Corbic <ncorbic@sangoma.com> 239 * Updated DTMF locking 240 * 241 * v1.11 Nenad Corbic <ncorbic@sangoma.com> 242 * Updated multiple profiles 243 * Updated Dialect for OPAL Woomera 244 * Added call logging/debugging 245 * 246 * v1.10 Nenad Corbic <ncorbic@sangoma.com> 247 * Bug fix in incoming hangup 248 * 249 * v1.9 Nenad Corbic <ncorbic@sangoma.com> 250 * Fixed remote asterisk/woomera 251 * setup. 252 * 253 * v1.8 Nenad Corbic <ncorbic@sangoma.com> 254 * Added Woomera OPAL dialect. 255 * Code cleanup. 256 * Added cli call_status 257 * 258 * v1.7 Nenad Corbic <ncorbic@sangoma.com> 259 * Added smgdebug to enable smg debugging 260 * Added rdnis 261 * 262 * v1.6 Nenad Corbic <ncorbic@sangoma.com> 263 * Added incoming trunk group context 264 * The trunk number will be added to the 265 * profile context name. 266 * Added presentation feature. 267 * 268 * v1.5 Nenad Corbic <ncorbic@sangoma.com> 269 * Use only ALAW and MLAW not SLIN. 270 * This reduces the load quite a bit. 271 * Autodetect Format from HELLO Message. 272 * RxTx Gain supported in woomera.conf as well 273 * from CLI. 274 */ 275 276 /*! 277 * \file chan_woomera.c 278 * \brief Woomera Channel driver for Asterisk 279 */ 280 281 #if defined(CALLWEAVER) && defined(HAVE_CONFIG_H) 282 #include "confdefs.h" 283 #endif 284 285 #include <stdio.h> 286 #include <string.h> 287 #include <stdlib.h> 288 #include <sys/types.h> 289 #include <sys/socket.h> 290 #include <netinet/in.h> 291 #include <arpa/inet.h> 292 #include <netdb.h> 293 #include <stdio.h> 294 #include <unistd.h> 295 #include <fcntl.h> 296 #include <signal.h> 297 #include <math.h> 298 #include <netinet/tcp.h> 299 300 301 #ifndef CALLWEAVER 302 303 304 #include "asterisk.h" 305 #include "asterisk/sched.h" 306 #include "asterisk/astobj.h" 307 #include "asterisk/lock.h" 308 #if defined(AST16) 309 #include "asterisk/linkedlists.h" 310 #include "asterisk/channel.h" 311 #endif 312 #if !defined (AST14) && !defined (AST16) 313 #include "asterisk/options.h" 314 #endif 315 #include "asterisk/manager.h" 316 #include "asterisk/pbx.h" 317 #include "asterisk/cli.h" 318 #include "asterisk/logger.h" 319 #include "asterisk/frame.h" 320 #include "asterisk/config.h" 321 #include "asterisk/module.h" 322 #include "asterisk/lock.h" 323 #include "asterisk/translate.h" 324 #include "asterisk/causes.h" 325 #include "asterisk/dsp.h" 326 #include "asterisk/musiconhold.h" 327 #include "asterisk/transcap.h" 328 #include "asterisk/sched.h" 329 #include "asterisk/io.h" 330 #include "asterisk/rtp.h" 331 332 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 1.55 $") 333 334 #else 335 336 #include "callweaver.h" 337 #include "callweaver/sched.h" 338 #ifdef CALLWEAVER_CWOBJ 339 #include "callweaver/cwobj.h" 340 #else 341 #include "callweaver/astobj.h" 342 #endif 343 #include "callweaver/lock.h" 344 #include "callweaver/manager.h" 345 #include "callweaver/options.h" 346 #include "callweaver/channel.h" 347 #include "callweaver/pbx.h" 348 #include "callweaver/cli.h" 349 #include "callweaver/logger.h" 350 #include "callweaver/frame.h" 351 #include "callweaver/config.h" 352 #include "callweaver/module.h" 353 #include "callweaver/lock.h" 354 #include "callweaver/translate.h" 355 #include "callweaver/causes.h" 356 #include "callweaver/dsp.h" 357 #include "callweaver/transcap.h" 358 #include "callweaver.h" 359 #include "confdefs.h" 360 361 362 #ifdef CALLWEAVER_CWOBJ 363 #define ASTOBJ_COMPONENTS CWOBJ_COMPONENTS 364 #define ASTOBJ_CONTAINER_INIT CWOBJ_CONTAINER_INIT 365 #define ASTOBJ_CONTAINER_COMPONENTS CWOBJ_CONTAINER_COMPONENTS 366 #define ASTOBJ_CONTAINER_DESTROY CWOBJ_CONTAINER_DESTROY 367 #define ASTOBJ_CONTAINER_DESTROYALL CWOBJ_CONTAINER_DESTROYALL 368 #define ASTOBJ_UNLOCK CWOBJ_UNLOCK 369 #define ASTOBJ_RDLOCK CWOBJ_RDLOCK 370 #define ASTOBJ_CONTAINER_UNLINK CWOBJ_CONTAINER_UNLINK 371 #define ASTOBJ_CONTAINER_TRAVERSE CWOBJ_CONTAINER_TRAVERSE 372 #define ASTOBJ_CONTAINER_WRLOCK CWOBJ_CONTAINER_WRLOCK 373 #define ASTOBJ_CONTAINER_UNLOCK CWOBJ_CONTAINER_UNLOCK 374 #define ASTOBJ_CONTAINER_FIND CWOBJ_CONTAINER_FIND 375 #define ASTOBJ_CONTAINER_LINK CWOBJ_CONTAINER_LINK 376 #endif 377 378 379 #if defined (CW_CONTROL_RINGING) 380 #define CALLWEAVER_19 1 381 #endif 382 383 CALLWEAVER_FILE_VERSION(__FILE__, "$Revision: 1.55 $") 384 385 #if defined(DSP_FEATURE_FAX_CNG_DETECT) 386 #undef DSP_FEATURE_FAX_DETECT 387 #define DSP_FEATURE_FAX_DETECT DSP_FEATURE_FAX_CNG_DETECT 388 #endif 389 390 #if !defined(macrocontext) 391 #undef macrocontext 392 #define macrocontext proc_context 393 #endif 394 395 #if !defined(ast_tv) 396 #undef ast_tv 397 #define ast_tv opbx_tv 398 #endif 399 400 /* CALLWEAVER v1.9 and later */ 401 #if defined (CALLWEAVER_19) 402 #define ast_transfercapability2str cw_transfercapability2str 403 #define ast_config cw_config 404 #define AST_CONTROL_RINGING CW_CONTROL_RINGING 405 #define AST_CONTROL_BUSY CW_CONTROL_BUSY 406 #define AST_CONTROL_CONGESTION CW_CONTROL_CONGESTION 407 #define AST_CONTROL_PROCEEDING CW_CONTROL_PROCEEDING 408 #define AST_CONTROL_PROGRESS CW_CONTROL_PROGRESS 409 #define AST_CONTROL_HOLD CW_CONTROL_HOLD 410 #define AST_CONTROL_UNHOLD CW_CONTROL_UNHOLD 411 #define AST_CONTROL_VIDUPDATE CW_CONTROL_VIDUPDATE 412 413 #define AST_TRANS_CAP_SPEECH CW_TRANS_CAP_SPEECH 414 #define AST_TRANS_CAP_3_1K_AUDIO CW_TRANS_CAP_3_1K_AUDIO 415 #define AST_TRANS_CAP_DIGITAL CW_TRANS_CAP_DIGITAL 416 #define AST_TRANS_CAP_RESTRICTED_DIGITAL CW_TRANS_CAP_RESTRICTED_DIGITAL 417 #define AST_TRANS_CAP_DIGITAL_W_TONES CW_TRANS_CAP_DIGITAL_W_TONES 418 #define AST_TRANS_CAP_VIDEO CW_TRANS_CAP_VIDEO 419 420 #define AST_FORMAT_ADPCM CW_FORMAT_DVI_ADPCM 421 422 #ifndef LOG_NOTICE 423 #define LOG_NOTICE CW_LOG_NOTICE 424 #endif 425 426 #ifndef LOG_DEBUG 427 #define LOG_DEBUG CW_LOG_DEBUG 428 #endif 429 430 #ifndef LOG_ERROR 431 #define LOG_ERROR CW_LOG_ERROR 432 #endif 433 434 #ifndef LOG_WARNING 435 #define LOG_WARNING CW_LOG_WARNING 436 #endif 437 438 #define AST_FORMAT_SLINEAR CW_FORMAT_SLINEAR 439 #define AST_FORMAT_ULAW CW_FORMAT_ULAW 440 #define AST_FORMAT_ALAW CW_FORMAT_ALAW 441 #define ast_mutex_t cw_mutex_t 442 #define ast_frame cw_frame 443 #define ast_verbose cw_verbose 444 #define AST_FRIENDLY_OFFSET CW_FRIENDLY_OFFSET 445 #define AST_MUTEX_DEFINE_STATIC CW_MUTEX_DEFINE_STATIC 446 #define AST_CONTROL_PROGRESS CW_CONTROL_PROGRESS 447 #define AST_CAUSE_REQUESTED_CHAN_UNAVAIL CW_CAUSE_REQUESTED_CHAN_UNAVAIL 448 #define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION CW_CAUSE_NORMAL_CIRCUIT_CONGESTION 449 #define AST_CAUSE_USER_BUSY CW_CAUSE_USER_BUSY 450 #define AST_CAUSE_NO_ANSWER CW_CAUSE_NO_ANSWER 451 #define AST_CAUSE_NORMAL_CLEARING CW_CAUSE_NORMAL_CLEARING 452 #define AST_SOFTHANGUP_EXPLICIT CW_SOFTHANGUP_EXPLICIT 453 #define AST_SOFTHANGUP_DEV CW_SOFTHANGUP_DEV 454 #define AST_CAUSE_NORMAL_CLEARING CW_CAUSE_NORMAL_CLEARING 455 #define AST_FRAME_DTMF CW_FRAME_DTMF 456 #define AST_FRAME_CONTROL CW_FRAME_CONTROL 457 #define AST_CONTROL_ANSWER CW_CONTROL_ANSWER 458 #define AST_STATE_UP CW_STATE_UP 459 #define AST_STATE_RINGING CW_STATE_RINGING 460 #define AST_STATE_DOWN CW_STATE_DOWN 461 #define AST_FLAGS_ALL CW_FLAGS_ALL 462 #define AST_FRAME_VOICE CW_FRAME_VOICE 463 #define ASTERISK_GPL_KEY 0 464 #define ast_channel_tech cw_channel_tech 465 #define ast_test_flag cw_test_flag 466 #define ast_queue_frame cw_queue_frame 467 #define ast_frdup cw_frdup 468 #define ast_channel cw_channel 469 #define ast_exists_extension cw_exists_extension 470 #define ast_hostent cw_hostent 471 #define ast_clear_flag cw_clear_flag 472 #define ast_log cw_log 473 #define ast_set_flag cw_set_flag 474 #define ast_copy_string cw_copy_string 475 #define ast_set_flag cw_set_flag 476 #define ast_set2_flag cw_set2_flag 477 #define ast_setstate cw_setstate 478 #define ast_test_flag cw_test_flag 479 #define ast_softhangup cw_softhangup 480 #define ast_softhangup_nolock cw_softhangup_nolock 481 #define ast_true cw_true 482 #define ast_false cw_false 483 #define ast_strlen_zero cw_strlen_zero 484 #define ast_exists_extension cw_exists_extension 485 #define ast_frame cw_frame 486 #define ast_jb_conf cw_jb_conf 487 #define ast_carefulwrite cw_carefulwrite 488 #define ast_channel_unregister cw_channel_unregister 489 #define ast_cli cw_cli 490 #define ast_cli_register cw_cli_register 491 #define ast_cli_unregister cw_cli_unregister 492 #define ast_jb_read_conf cw_jb_read_conf 493 #define ast_mutex_destroy cw_mutex_destroy 494 #define ast_mutex_init cw_mutex_init 495 #define ast_mutex_lock cw_mutex_lock 496 #define ast_mutex_unlock cw_mutex_unlock 497 #define ast_mutex_t cw_mutex_t 498 #define ast_queue_control cw_queue_control 499 #define ast_queue_frame cw_queue_frame 500 #define ast_queue_hangup cw_queue_hangup 501 #define ast_set_callerid cw_set_callerid 502 #define ast_variable cw_variable 503 #define ast_pthread_create cw_pthread_create 504 #define ast_cli_entry cw_cli_entry 505 #define ast_channel_register cw_channel_register 506 #define ast_config_load cw_config_load 507 #define ast_config_destroy cw_config_destroy 508 #define ast_category_browse cw_category_browse 509 #define ast_variable_browse cw_variable_browse 510 #define ast_gethostbyname cw_gethostbyname 511 #define ast_channel_alloc cw_channel_alloc 512 #define ast_dsp_new cw_dsp_new 513 #define ast_dsp cw_dsp 514 #define ast_dsp_set_features cw_dsp_set_features 515 #define ast_dsp_digitmode cw_dsp_digitmode 516 #define ast_dsp_set_call_progress_zone cw_dsp_set_call_progress_zone 517 #define ast_dsp_set_busy_count cw_dsp_set_busy_count 518 #define ast_dsp_set_busy_pattern cw_dsp_set_busy_pattern 519 #define ast_dsp_process cw_dsp_process 520 #define ast_strdupa cw_strdupa 521 #define ast_mutex_trylock cw_mutex_trylock 522 #define ast_cause2str cw_cause2str 523 #define ast_pbx_start cw_pbx_start 524 #define ast_hangup cw_hangup 525 526 #if !defined(ast_async_goto) 527 #undefast_async_goto 528 #define ast_async_goto cw_async_goto_n 529 #endif 530 #else /* CALLWEAVER prior to v1.9 */ 531 532 #define ast_transfercapability2str opbx_transfercapability2str 533 #define ast_config opbx_config 534 #define AST_CONTROL_RINGING OPBX_CONTROL_RINGING 535 #define AST_CONTROL_BUSY OPBX_CONTROL_BUSY 536 #define AST_CONTROL_CONGESTION OPBX_CONTROL_CONGESTION 537 #define AST_CONTROL_PROCEEDING OPBX_CONTROL_PROCEEDING 538 #define AST_CONTROL_PROGRESS OPBX_CONTROL_PROGRESS 539 #define AST_CONTROL_HOLD OPBX_CONTROL_HOLD 540 #define AST_CONTROL_UNHOLD OPBX_CONTROL_UNHOLD 541 #define AST_CONTROL_VIDUPDATE OPBX_CONTROL_VIDUPDATE 542 543 #define AST_FORMAT_SLINEAR OPBX_FORMAT_SLINEAR 544 #define AST_FORMAT_ULAW OPBX_FORMAT_ULAW 545 #define AST_FORMAT_ALAW OPBX_FORMAT_ALAW 546 547 #define AST_TRANS_CAP_SPEECH OPBX_TRANS_CAP_SPEECH 548 #define AST_TRANS_CAP_3_1K_AUDIO OPBX_TRANS_CAP_3_1K_AUDIO 549 #define AST_TRANS_CAP_DIGITAL OPBX_TRANS_CAP_DIGITAL 550 #define AST_TRANS_CAP_RESTRICTED_DIGITAL OPBX_TRANS_CAP_RESTRICTED_DIGITAL 551 #define AST_TRANS_CAP_DIGITAL_W_TONES OPBX_TRANS_CAP_DIGITAL_W_TONES 552 #define AST_TRANS_CAP_VIDEO OPBX_TRANS_CAP_VIDEO 553 554 #ifndef LOG_NOTICE 555 #define LOG_NOTICE OPBX_LOG_NOTICE 556 #endif 557 558 #ifndef LOG_DEBUG 559 #define LOG_DEBUG OPBX_LOG_DEBUG 560 #endif 561 562 #ifndef LOG_ERROR 563 #define LOG_ERROR OPBX_LOG_ERROR 564 #endif 565 566 #ifndef LOG_WARNING 567 #define LOG_WARNING OPBX_LOG_WARNING 568 #endif 569 570 571 #define AST_FORMAT_SLINEAR OPBX_FORMAT_SLINEAR 572 #define AST_FORMAT_ULAW OPBX_FORMAT_ULAW 573 #define AST_FORMAT_ALAW OPBX_FORMAT_ALAW 574 #define AST_FORMAT_ADPCM OPBX_FORMAT_DVI_ADPCM 575 576 #define ast_mutex_t opbx_mutex_t 577 #define ast_frame opbx_frame 578 #define ast_verbose opbx_verbose 579 #define AST_FRIENDLY_OFFSET OPBX_FRIENDLY_OFFSET 580 #define AST_MUTEX_DEFINE_STATIC OPBX_MUTEX_DEFINE_STATIC 581 #define AST_CONTROL_PROGRESS OPBX_CONTROL_PROGRESS 582 #define AST_CAUSE_REQUESTED_CHAN_UNAVAIL OPBX_CAUSE_REQUESTED_CHAN_UNAVAIL 583 #define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION OPBX_CAUSE_NORMAL_CIRCUIT_CONGESTION 584 #define AST_CAUSE_USER_BUSY OPBX_CAUSE_USER_BUSY 585 #define AST_CAUSE_NO_ANSWER OPBX_CAUSE_NO_ANSWER 586 #define AST_CAUSE_NORMAL_CLEARING OPBX_CAUSE_NORMAL_CLEARING 587 #define AST_SOFTHANGUP_EXPLICIT OPBX_SOFTHANGUP_EXPLICIT 588 #define AST_SOFTHANGUP_DEV OPBX_SOFTHANGUP_DEV 589 #define AST_CAUSE_NORMAL_CLEARING OPBX_CAUSE_NORMAL_CLEARING 590 #define AST_FRAME_DTMF OPBX_FRAME_DTMF 591 #define AST_FRAME_CONTROL OPBX_FRAME_CONTROL 592 #define AST_CONTROL_ANSWER OPBX_CONTROL_ANSWER 593 #define AST_STATE_UP OPBX_STATE_UP 594 #define AST_STATE_RINGING OPBX_STATE_RINGING 595 #define AST_STATE_DOWN OPBX_STATE_DOWN 596 #define AST_FLAGS_ALL OPBX_FLAGS_ALL 597 #define AST_FRAME_VOICE OPBX_FRAME_VOICE 598 #define AST_FRAME_NULL OPBX_FRAME_NULL 599 #define ASTERISK_GPL_KEY 0 600 #define ast_channel_tech opbx_channel_tech 601 #define ast_test_flag opbx_test_flag 602 #define ast_queue_frame opbx_queue_frame 603 #define ast_frdup opbx_frdup 604 #define ast_channel opbx_channel 605 #define ast_exists_extension opbx_exists_extension 606 #define ast_hostent opbx_hostent 607 #define ast_clear_flag opbx_clear_flag 608 #define ast_log opbx_log 609 #define ast_set_flag opbx_set_flag 610 #define ast_copy_string opbx_copy_string 611 #define ast_set_flag opbx_set_flag 612 #define ast_set2_flag opbx_set2_flag 613 #define ast_setstate opbx_setstate 614 #define ast_test_flag opbx_test_flag 615 #define ast_softhangup opbx_softhangup 616 #define ast_softhangup_nolock opbx_softhangup_nolock 617 #define ast_true opbx_true 618 #define ast_false opbx_false 619 #define ast_strlen_zero opbx_strlen_zero 620 #define ast_exists_extension opbx_exists_extension 621 #define ast_frame opbx_frame 622 #define ast_jb_conf opbx_jb_conf 623 #define ast_carefulwrite opbx_carefulwrite 624 #define ast_channel_unregister opbx_channel_unregister 625 #define ast_cli opbx_cli 626 #define ast_cli_register opbx_cli_register 627 #define ast_cli_unregister opbx_cli_unregister 628 #define ast_jb_read_conf opbx_jb_read_conf 629 #define ast_mutex_destroy opbx_mutex_destroy 630 #define ast_mutex_init opbx_mutex_init 631 #define ast_mutex_lock opbx_mutex_lock 632 #define ast_mutex_unlock opbx_mutex_unlock 633 #define ast_mutex_t opbx_mutex_t 634 #define ast_queue_control opbx_queue_control 635 #define ast_queue_frame opbx_queue_frame 636 #define ast_queue_hangup opbx_queue_hangup 637 #define ast_set_callerid opbx_set_callerid 638 #define ast_variable opbx_variable 639 #define ast_pthread_create opbx_pthread_create 640 #define ast_cli_entry opbx_cli_entry 641 #define ast_channel_register opbx_channel_register 642 #define ast_config_load opbx_config_load 643 #define ast_config_destroy opbx_config_destroy 644 #define ast_category_browse opbx_category_browse 645 #define ast_variable_browse opbx_variable_browse 646 #define ast_gethostbyname opbx_gethostbyname 647 #define ast_channel_alloc opbx_channel_alloc 648 #define ast_dsp_new opbx_dsp_new 649 #define ast_dsp opbx_dsp 650 #define ast_dsp_set_features opbx_dsp_set_features 651 #define ast_dsp_digitmode opbx_dsp_digitmode 652 #define ast_dsp_set_call_progress_zone opbx_dsp_set_call_progress_zone 653 #define ast_dsp_set_busy_count opbx_dsp_set_busy_count 654 #define ast_dsp_set_busy_pattern opbx_dsp_set_busy_pattern 655 #define ast_dsp_process opbx_dsp_process 656 #define ast_strdupa opbx_strdupa 657 #define ast_mutex_trylock opbx_mutex_trylock 658 #define ast_cause2str opbx_cause2str 659 #define ast_pbx_start opbx_pbx_start 660 #define ast_hangup opbx_hangup 661 662 #if !defined(ast_async_goto) 663 #undef ast_async_goto 664 #define ast_async_goto opbx_async_goto 665 #endif 666 667 #endif /* CALLWEAVER_19 */ 668 #endif 669 670 #include "g711.h" 671 #include <errno.h> 672 673 //#define USE_TECH_INDICATE 674 #ifdef USE_TECH_INDICATE 675 #define MEDIA_ANSWER "MEDIA" 676 #else 677 #define MEDIA_ANSWER "ACCEPT" 678 #endif 679 680 #define USE_ANSWER 1 681 682 #ifndef ast_free 683 #define ast_free(x) free(x) 684 #define ast_malloc(x) malloc(x) 685 #endif 686 687 688 extern int option_verbose; 689 690 #define WOOMERA_VERSION "v1.59" 691 #ifndef WOOMERA_CHAN_NAME 692 #define WOOMERA_CHAN_NAME "WOOMERA" 693 #endif 694 695 #if 1 696 #undef WOOMERA_PRINTF_DEBUG 697 #else 698 #warning "WOOMERA_PRINTF_DEBUG defined" 699 #define WOOMERA_PRINTF_DEBUG 700 #endif 701 #ifdef WOOMERA_PRINTF_DEBUG 702 #define woomera_printf(a,b,c,msg...) __woomera_printf(__FUNCTION__,__LINE__,a,b,c,##msg) 703 #else 704 #define woomera_printf(a,b,c,msg...) __woomera_printf(a,b,c,##msg) 705 #endif 706 707 static int tech_count = 0; 708 709 static const char desc[] = "Woomera Channel Driver"; 710 //static const char type[] = "WOOMERA"; 711 static const char tdesc[] = "Woomera Channel Driver"; 712 static char configfile[] = "woomera.conf"; 713 714 static char svrversion_init = 0; 715 static char svrversion[100] = "N/A"; 716 717 static char mohinterpret[MAX_MUSICCLASS] = "default"; 718 static char mohsuggest[MAX_MUSICCLASS] = ""; 719 720 721 static char *woomeraplaybackdesc = "Play audio and / or video on the Woomera Server\n"; 722 static char *woomeraplaybackapp = "WoomeraPlayback"; 723 static char *woomeraplaybacksynopsis = "Execute a play on chan_woomera"; 724 725 static char *woomerabackgrounddesc = "Play audio and / or video in the background on the Woomera Server\n"; 726 static char *woomerabackgroundapp = "WoomeraBackground"; 727 static char *woomerabackgroundsynopsis = "Execute a background play on chan_woomera"; 728 729 static char *woomerarecorddesc = "Record audio and / or video on the Woomera Server\n"; 730 static char *woomerarecordapp = "WoomeraRecord"; 731 static char *woomerarecordsynopsis = "Execute a Record on chan_woomera"; 732 733 static char *woomerastopdesc = "Stop the current background play on the Woomera Server\n"; 734 static char *woomerastopapp = "WoomeraStop"; 735 static char *woomerastopsynopsis = "Stop the current WoomeraBackground "; 736 737 static char *woomeraringbackdesc = "Play audio and / or video ringback until the caall is answered\n"; 738 static char *woomeraringbackapp = "WoomeraRingback"; 739 static char *woomeraringbacksynopsis = "Execute a play ringback on chan_woomera"; 740 741 742 #if !defined (AST14) && !defined (AST16) 743 struct ast_frame ast_null_frame; 744 #endif 745 746 #if defined (AST14) || defined (AST16) 747 #if !defined (AST_JB) 748 #define AST_JB 1 749 #endif 750 #endif 751 752 #if !defined(DSP_FEATURE_DTMF_DETECT) && defined(DSP_FEATURE_DIGIT_DETECT) 753 #define DSP_FEATURE_DTMF_DETECT DSP_FEATURE_DIGIT_DETECT 754 #define ast_dsp_digitmode ast_dsp_set_digitmode 755 #define woo_ast_data_ptr data.ptr 756 #else 757 #define woo_ast_data_ptr data 758 #endif 759 760 #if defined (AST_JB) 761 #include "asterisk/abstract_jb.h" 762 /* Global jitterbuffer configuration - by default, jb is disabled */ 763 static struct ast_jb_conf default_jbconf = 764 { 765 .flags = 0, 766 .max_size = -1, 767 .resync_threshold = -1, 768 .impl = "" 769 }; 770 static struct ast_jb_conf global_jbconf; 771 #endif /* AST_JB */ 772 773 774 #define WOOMERA_SLINEAR 0 775 #define WOOMERA_ULAW 1 776 #define WOOMERA_ALAW 2 777 778 #define WOOMERA_MAX_MEDIA_PORTS 899 779 780 #define WOOMERA_STRLEN 256 781 #define WOOMERA_ARRAY_LEN 50 782 #define WOOMERA_MIN_PORT 10000 783 #define WOOMERA_MAX_PORT WOOMERA_MIN_PORT+WOOMERA_MAX_MEDIA_PORTS 784 #define WOOMERA_BODYLEN 2048 785 #define WOOMERA_LINE_SEPARATOR "\r\n" 786 #define WOOMERA_RECORD_SEPARATOR "\r\n\r\n" 787 #define WOOMERA_DEBUG_PREFIX "[WOOMERA] " 788 #define WOOMERA_DEBUG_LINE "--------------------------------------------------------------------------------" 789 #define WOOMERA_HARD_TIMEOUT -2000 790 #define WOOMERA_QLEN 10 791 #define WOOMERA_MAX_TRUNKGROUPS 64 792 793 static int woomera_base_media_port = WOOMERA_MIN_PORT; 794 static int woomera_max_media_port = WOOMERA_MAX_PORT; 795 796 /* this macro is not in all versions of asterisk */ 797 #ifdef OLDERAST 798 #define ASTOBJ_CONTAINER_UNLINK(container,obj) \ 799 ({ \ 800 typeof((container)->head) found = NULL; \ 801 typeof((container)->head) prev = NULL; \ 802 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \ 803 if (iterator== obj) { \ 804 found = iterator; \ 805 found->next[0] = NULL; \ 806 ASTOBJ_CONTAINER_WRLOCK(container); \ 807 if (prev) \ 808 prev->next[0] = next; \ 809 else \ 810 (container)->head = next; \ 811 ASTOBJ_CONTAINER_UNLOCK(container); \ 812 } \ 813 prev = iterator; \ 814 } while (0)); \ 815 found; \ 816 }) 817 #endif 818 819 820 #define FRAME_LEN 480 821 822 #if 0 823 static int WFORMAT = AST_FORMAT_ALAW; //AST_FORMAT_SLINEAR; 824 #else 825 static int WFORMAT = AST_FORMAT_SLINEAR; 826 #endif 827 828 typedef enum { 829 WFLAG_EXISTS = (1 << 0), 830 WFLAG_EVENT = (1 << 1), 831 WFLAG_CONTENT = (1 << 2), 832 } WFLAGS; 833 834 835 typedef enum { 836 WCFLAG_NOWAIT = (1 << 0) 837 } WCFLAGS; 838 839 840 typedef enum { 841 PFLAG_INBOUND = (1 << 0), 842 PFLAG_OUTBOUND = (1 << 1), 843 PFLAG_DYNAMIC = (1 << 2), 844 PFLAG_DISABLED = (1 << 3) 845 } PFLAGS; 846 847 typedef enum { 848 TFLAG_MEDIA = (1 << 0), 849 TFLAG_INBOUND = (1 << 1), 850 TFLAG_OUTBOUND = (1 << 2), 851 TFLAG_INCOMING = (1 << 3), 852 TFLAG_PARSE_INCOMING = (1 << 4), 853 TFLAG_ACTIVATE = (1 << 5), 854 TFLAG_DTMF = (1 << 6), 855 TFLAG_DESTROY = (1 << 7), 856 TFLAG_ABORT = (1 << 8), 857 TFLAG_PBX = (1 << 9), 858 TFLAG_ANSWER = (1 << 10), 859 TFLAG_INTHREAD = (1 << 11), 860 TFLAG_TECHHANGUP = (1 << 12), 861 TFLAG_DESTROYED = (1 << 13), 862 TFLAG_UP = (1 << 14), 863 TFLAG_ACCEPT = (1 << 15), 864 TFLAG_ACCEPTED = (1 << 16), 865 TFLAG_ANSWER_RECEIVED = (1 << 17), 866 TFLAG_CONFIRM_ANSWER = (1 << 18), 867 TFLAG_CONFIRM_ANSWER_ENABLED = (1 << 19), 868 TFLAG_AST_HANGUP = (1 << 20), 869 TFLAG_PLAY = (1 << 21), 870 TFLAG_PLAY_COMPLETED = (1 << 22), 871 TFLAG_RECORD = (1 << 23), 872 TFLAG_RECORD_COMPLETED = (1 << 24), 873 TFLAG_STOP = (1 << 25), 874 TFLAG_STOP_COMPLETED = (1 << 26), 875 TFLAG_BRIDGE = (1 << 27), 876 TFLAG_CONNECTED = (1 << 28) 877 } TFLAGS; 878 879 static int usecnt = 0; 880 881 struct woomera_message { 882 char callid[WOOMERA_STRLEN]; 883 int mval; 884 char command[WOOMERA_STRLEN]; 885 char command_args[WOOMERA_STRLEN]; 886 char names[WOOMERA_ARRAY_LEN][WOOMERA_STRLEN]; 887 char values[WOOMERA_ARRAY_LEN][WOOMERA_STRLEN]; 888 char body[WOOMERA_BODYLEN]; 889 char cause[WOOMERA_STRLEN]; 890 unsigned int flags; 891 int last; 892 unsigned int queue_id; 893 struct woomera_message *next; 894 }; 895 896 897 static struct { 898 int next_woomera_port; 899 int debug; 900 int panic; 901 int more_threads; 902 ast_mutex_t woomera_port_lock; 903 } globals; 904 905 static struct { 906 int woomeraplayback; 907 int woomerabackground; 908 int woomerarecord; 909 int woomeraringback; 910 } capabilities; 911 912 struct woomera_event_queue { 913 struct woomera_message *head; 914 ast_mutex_t lock; 915 }; 916 917 struct woomera_profile { 918 ASTOBJ_COMPONENTS(struct woomera_profile); 919 ast_mutex_t iolock; 920 ast_mutex_t call_count_lock; 921 char woomera_host[WOOMERA_STRLEN]; 922 int max_calls; 923 int call_count; 924 int woomera_port; 925 char audio_ip[WOOMERA_STRLEN]; 926 char context[WOOMERA_STRLEN]; 927 pthread_t thread; 928 unsigned int flags; 929 int thread_running; 930 int dtmf_enable; 931 int send_dtmf_enable; 932 int faxdetect; 933 int woomera_socket; 934 struct woomera_event_queue event_queue; 935 int jb_enable; 936 int rtp_enable; 937 int vrtp_enable; 938 int bridge_enable; 939 int progress_enable; 940 int coding; 941 int videocoding; 942 float rxgain_val; 943 float txgain_val; 944 unsigned char rxgain[256]; 945 unsigned char txgain[256]; 946 int call_out; 947 int call_in; 948 int call_ok; 949 int call_end; 950 int call_abort; 951 int call_ast_hungup; 952 char default_context[WOOMERA_STRLEN]; 953 char* tg_context [WOOMERA_MAX_TRUNKGROUPS+1]; 954 char language[WOOMERA_STRLEN]; 955 char* tg_language [WOOMERA_MAX_TRUNKGROUPS+1]; 956 int udp_seq; 957 int rx_sync_check_opt; 958 int tx_sync_check_opt; 959 int tx_sync_gen_opt; 960 }; 961 962 963 struct private_object { 964 ASTOBJ_COMPONENTS(struct private_object); 965 ast_mutex_t iolock; 966 struct ast_channel *owner; 967 struct sockaddr_in udpread; 968 struct sockaddr_in udpwrite; 969 int command_channel; 970 int udp_socket; 971 unsigned int flags; 972 struct ast_frame frame; 973 short fdata[FRAME_LEN + AST_FRIENDLY_OFFSET]; 974 struct woomera_message call_info; 975 struct woomera_profile *profile; 976 char dest[WOOMERA_STRLEN]; 977 char proto[WOOMERA_STRLEN]; 978 int port; 979 int vport; 980 struct timeval started; 981 int timeout; 982 char dtmfbuf[WOOMERA_STRLEN]; 983 char cid_name[WOOMERA_STRLEN]; 984 char cid_num[WOOMERA_STRLEN]; 985 char mohinterpret[MAX_MUSICCLASS]; 986 char mohsuggest[MAX_MUSICCLASS]; 987 char *cid_rdnis; 988 int cid_pres; 989 char ds[WOOMERA_STRLEN]; 990 struct ast_dsp *dsp; 991 int ast_dsp; 992 int dsp_features; 993 int faxdetect; 994 int faxhandled; 995 int rtp_enable; 996 int vrtp_enable; 997 int send_dtmf_enable; 998 int bridge_enable; 999 int call_count; 1000 char callid[WOOMERA_STRLEN]; 1001 pthread_t thread; 1002 unsigned int callno; 1003 int refcnt; 1004 struct woomera_event_queue event_queue; 1005 int coding; 1006 int videocoding; 1007 int pri_cause; 1008 int rx_udp_seq; 1009 int tx_udp_seq; 1010 char audio_uri[WOOMERA_STRLEN]; 1011 char video_uri[WOOMERA_STRLEN]; 1012 char stop_digits[12+1]; 1013 char repeat[WOOMERA_STRLEN]; /* Integer string (1..n) or "infinite" */ 1014 int beep; 1015 1016 #ifdef AST_JB 1017 struct ast_jb_conf jbconf; 1018 #endif /* AST_JB */ 1019 1020 int sync_r; 1021 int sync_w; 1022 unsigned char sync_data_w; 1023 unsigned char sync_data_r; 1024 int capability; 1025 struct ast_rtp *rtp; /* Audio RTP Session */ 1026 struct ast_rtp *vrtp; /* Video RTP session */ 1027 struct sockaddr_in audio_bridge_ip; /* Bridge destination for our Audio RTP */ 1028 struct sockaddr_in video_bridge_ip; /* Bridge destination for our Video RTP */ 1029 1030 }; 1031 1032 1033 #define WOOMERA_MAX_CALLS 720 /* 24 * E1 */ 1034 1035 static struct private_object *tech_pvt_idx[WOOMERA_MAX_CALLS]; 1036 static ast_mutex_t tech_pvt_idx_lock[WOOMERA_MAX_CALLS]; 1037 1038 typedef struct private_object private_object; 1039 typedef struct woomera_message woomera_message; 1040 typedef struct woomera_profile woomera_profile; 1041 typedef struct woomera_event_queue woomera_event_queue; 1042 1043 #ifndef DEADLOCK_AVOIDANCE 1044 #define ast_find_lock_info(a,b,c,d,e,f,g,h) -1 1045 #define DEADLOCK_AVOIDANCE(lock) \ 1046 do { \ 1047 ast_mutex_unlock(lock); \ 1048 usleep(1); \ 1049 ast_mutex_lock(lock); \ 1050 } while (0) 1051 #endif 1052 1053 1054 static int my_ast_channel_trylock(struct ast_channel *chan) 1055 { 1056 #if defined (AST14) || defined (AST16) 1057 return ast_channel_trylock(chan); 1058 #else 1059 return ast_mutex_trylock(&chan->lock); 1060 #endif 1061 } 1062 1063 #if !defined (CALLWEAVER) 1064 #if 0 1065 static int my_ast_channel_lock(struct ast_channel *chan) 1066 { 1067 #if defined (AST14) || defined (AST16) 1068 return ast_channel_lock(chan); 1069 #else 1070 return ast_mutex_lock(&chan->lock); 1071 #endif 1072 } 1073 #endif 1074 #endif 1075 1076 static int my_ast_channel_unlock(struct ast_channel *chan) 1077 { 1078 #if defined (AST14) || defined (AST16) 1079 return ast_channel_unlock(chan); 1080 #else 1081 return ast_mutex_unlock(&chan->lock); 1082 #endif 1083 } 1084 1085 /*! 1086 * Lock both the private object and the owning channel. 1087 */ 1088 static int my_tech_pvt_and_owner_lock(private_object *tech_pvt) 1089 { 1090 ast_mutex_lock(&tech_pvt->iolock); 1091 while (tech_pvt->owner && my_ast_channel_trylock(tech_pvt->owner)) { 1092 if (globals.debug > 2) { 1093 ast_log(LOG_NOTICE, "my_tech_pvt_and_owner_lock() - deadlock avoidance\n"); 1094 } 1095 DEADLOCK_AVOIDANCE(&tech_pvt->iolock); 1096 } 1097 return 0; 1098 } 1099 1100 /*! 1101 * Unlock both the private object and the owning channel. 1102 */ 1103 static int my_tech_pvt_and_owner_unlock(private_object *tech_pvt) 1104 { 1105 if (tech_pvt->owner) { 1106 my_ast_channel_unlock(tech_pvt->owner); 1107 } 1108 ast_mutex_unlock(&tech_pvt->iolock); 1109 return 0; 1110 } 1111 1112 1113 static void my_ast_softhangup(struct ast_channel *chan, private_object *tech_pvt, int cause) 1114 { 1115 #if 1 1116 ast_queue_hangup(chan); 1117 //ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT); 1118 #else 1119 struct ast_frame f = { AST_FRAME_NULL }; 1120 1121 if (chan) { 1122 chan->_softhangup |= cause; 1123 ast_queue_frame(chan, &f); 1124 } 1125 1126 ast_set_flag(tech_pvt, TFLAG_ABORT); 1127 #endif 1128 1129 #if 0 1130 if (tech_pvt->dsp) { 1131 tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT; 1132 ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features); 1133 tech_pvt->ast_dsp = 0; 1134 } 1135 #endif 1136 1137 } 1138 1139 /* For RTP audio */ 1140 static struct sched_context *sched; /*!< The scheduling context */ 1141 static struct io_context *io; /*!< The IO context */ 1142 1143 1144 static struct private_object_container { 1145 ASTOBJ_CONTAINER_COMPONENTS(private_object); 1146 } private_object_list; 1147 1148 static struct woomera_profile_container { 1149 ASTOBJ_CONTAINER_COMPONENTS(woomera_profile); 1150 } woomera_profile_list; 1151 1152 static woomera_profile default_profile; 1153 1154 /* some locks you will use for use count and for exclusive access to the main linked-list of private objects */ 1155 AST_MUTEX_DEFINE_STATIC(usecnt_lock); 1156 AST_MUTEX_DEFINE_STATIC(lock); 1157 1158 /* local prototypes */ 1159 static void woomera_close_socket(int *socket); 1160 static void global_set_flag(int flags); 1161 #ifdef WOOMERA_PRINTF_DEBUG 1162 static int __woomera_printf(const char* file, int line, woomera_profile *profile, int fd, char *fmt, ...); 1163 #else 1164 static int __woomera_printf(woomera_profile *profile, int fd, char *fmt, ...); 1165 #endif 1166 static char *woomera_message_header(woomera_message *wmsg, char *key); 1167 static int woomera_enqueue_event(woomera_event_queue *event_queue, woomera_message *wmsg); 1168 static int woomera_dequeue_event(woomera_event_queue *event_queue, woomera_message *wmsg); 1169 static int woomera_message_parse(int fd, woomera_message *wmsg, int timeout, woomera_profile *profile, woomera_event_queue *event_queue); 1170 static int woomera_message_parse_wait(private_object *tech_pvt,woomera_message *wmsg); 1171 static int waitfor_socket(int fd, int timeout); 1172 static int woomera_profile_thread_running(woomera_profile *profile, int set, int new); 1173 static int woomera_locate_socket(woomera_profile *profile, int *woomera_socket); 1174 static void *woomera_thread_run(void *obj); 1175 static void launch_woomera_thread(woomera_profile *profile); 1176 static void destroy_woomera_profile(woomera_profile *profile); 1177 static woomera_profile *clone_woomera_profile(woomera_profile *new_profile, woomera_profile *default_profile); 1178 static woomera_profile *create_woomera_profile(woomera_profile *default_profile); 1179 static int config_woomera(void); 1180 static int create_udp_socket(char *ip, int port, struct sockaddr_in *sockaddr, int client); 1181 static struct ast_rtp * create_rtp(char *ip); 1182 static int connect_woomera(int *new_socket, woomera_profile *profile, int flags); 1183 static int init_woomera(void); 1184 1185 #if defined (AST16) 1186 static char *ast16_woomera_cli(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); 1187 #endif 1188 1189 static int woomera_cli(int fd, int argc, char *argv[]); 1190 static void tech_destroy(private_object *tech_pvt, struct ast_channel *owner); 1191 static struct ast_channel *woomera_new(const char *type, int format, void *data, int *cause, woomera_profile *profile); 1192 static int launch_tech_thread(private_object *tech_pvt); 1193 static int tech_create_read_socket(private_object *tech_pvt); 1194 static int tech_activate(private_object *tech_pvt); 1195 static int tech_init(private_object *tech_pvt, woomera_profile *profile, int flags); 1196 static void *tech_monitor_thread(void *obj); 1197 static void tech_monitor_in_one_thread(void); 1198 static struct ast_channel * tech_get_owner( private_object *tech_pvt); 1199 int usecount(void); 1200 1201 #if 0 1202 static char *key(void); 1203 static char *description(void); 1204 #endif 1205 1206 int load_module(void); 1207 int unload_module(void); 1208 int reload(void); 1209 1210 /********************CHANNEL METHOD PROTOTYPES********************************** 1211 * You may or may not need all of these methods, 1212 * remove any unnecessary functions/protos/mappings as needed. 1213 */ 1214 static struct ast_channel *tech_requester(const char *type, int format, void *data, int *cause); 1215 static int tech_send_digit(struct ast_channel *self, char digit); 1216 1217 #if defined (AST14) || defined (AST16) 1218 static int tech_digit_end(struct ast_channel *ast, char digit, unsigned int duration); 1219 #endif 1220 1221 static int tech_call(struct ast_channel *self, char *dest, int timeout); 1222 static int tech_hangup(struct ast_channel *self); 1223 static int tech_answer(struct ast_channel *self); 1224 static struct ast_frame *tech_read(struct ast_channel *self); 1225 static struct ast_frame *tech_exception(struct ast_channel *self); 1226 static int tech_write(struct ast_channel *self, struct ast_frame *frame); 1227 1228 #ifdef USE_TECH_INDICATE 1229 # if defined (AST14) || defined (AST16) 1230 static int tech_indicate(struct ast_channel *self, int condition, const void *data, size_t datalen); 1231 # else 1232 static int tech_indicate(struct ast_channel *self, int condition); 1233 # endif 1234 #endif 1235 1236 static int tech_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); 1237 static int tech_send_html(struct ast_channel *self, int subclass, const char *data, int datalen); 1238 static int tech_send_text(struct ast_channel *self, const char *text); 1239 static int tech_send_image(struct ast_channel *self, struct ast_frame *frame); 1240 static int tech_setoption(struct ast_channel *self, int option, void *data, int datalen); 1241 static int tech_queryoption(struct ast_channel *self, int option, void *data, int *datalen); 1242 //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); 1243 static int tech_transfer(struct ast_channel *self, const char *newdest); 1244 static int tech_write_video(struct ast_channel *self, struct ast_frame *frame); 1245 //static struct ast_channel *tech_bridged_channel(struct ast_channel *self, struct ast_channel *bridge); 1246 1247 static enum ast_rtp_get_result tech_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp); 1248 static enum ast_rtp_get_result tech_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp); 1249 //static enum ast_rtp_get_result tech_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp); 1250 1251 #if defined (AST16) 1252 static int tech_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, struct ast_rtp *trtp, int codecs, int nat_active); 1253 #else 1254 static int tech_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active); 1255 #endif 1256 1257 static int tech_get_codec(struct ast_channel *chan); 1258 1259 static int woomera_event_incoming (private_object *tech_pvt); 1260 static int woomera_event_media (private_object *tech_pvt, woomera_message *wmsg); 1261 static void woomera_check_event (private_object *tech_pvt, int res, woomera_message *wmsg); 1262 1263 /******************************************************************************* 1264 * Constant structure for mapping local methods to the core interface. 1265 * This structure only needs to contain the methods the channel requires to operate 1266 * Not every channel needs all of them defined. 1267 */ 1268 1269 static const struct ast_channel_tech technology = { 1270 .type = WOOMERA_CHAN_NAME, 1271 .description = tdesc, 1272 .capabilities = (AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW), 1273 .requester = tech_requester, 1274 #if defined (AST14) || defined (AST16) 1275 .send_digit_begin = tech_send_digit, 1276 .send_digit_end = tech_digit_end, 1277 #else 1278 .send_digit = tech_send_digit, 1279 #endif 1280 .call = tech_call, 1281 .bridge = ast_rtp_bridge, 1282 // .early_bridge = ast_rtp_early_bridge, 1283 .hangup = tech_hangup, 1284 .answer = tech_answer, 1285 .transfer = tech_transfer, 1286 .write_video = tech_write_video, 1287 .read = tech_read, 1288 .write = tech_write, 1289 .exception = tech_exception, 1290 #ifdef USE_TECH_INDICATE 1291 .indicate = tech_indicate, 1292 #endif 1293 .fixup = tech_fixup, 1294 .send_html = tech_send_html, 1295 .send_text = tech_send_text, 1296 .send_image = tech_send_image, 1297 .setoption = tech_setoption, 1298 .queryoption = tech_queryoption, 1299 //.bridged_channel = tech_bridged_channel, 1300 .transfer = tech_transfer, 1301 }; 1302 1303 1304 /*! 1305 * Interface structure with callbacks used to connect to RTP module 1306 */ 1307 static struct ast_rtp_protocol tech_rtp = { 1308 .type = "WOOMERA", 1309 .get_rtp_info = tech_get_rtp_peer, 1310 .get_vrtp_info = tech_get_vrtp_peer, 1311 // .get_trtp_info = tech_get_trtp_peer, 1312 .set_rtp_peer = tech_set_rtp_peer, 1313 .get_codec = tech_get_codec, 1314 }; 1315 1316 /******************************************************************************/ 1317 1318 static void woomera_close_socket(int *socket) 1319 { 1320 if (*socket > -1) { 1321 close(*socket); 1322 } 1323 *socket = -1; 1324 } 1325 1326 1327 static int woomera_message_reply_ok(woomera_message *wmsg) 1328 { 1329 if (!(wmsg->mval >= 200 && wmsg->mval <= 299)) { 1330 return -1; 1331 } 1332 return 0; 1333 } 1334 1335 1336 static void global_set_flag(int flags) 1337 { 1338 private_object *tech_pvt; 1339 1340 ASTOBJ_CONTAINER_TRAVERSE(&private_object_list, 1, do { 1341 ASTOBJ_RDLOCK(iterator); 1342 tech_pvt = iterator; 1343 ast_set_flag(tech_pvt, flags); 1344 ASTOBJ_UNLOCK(iterator); 1345 } while(0)); 1346 } 1347 1348 1349 static void woomera_send_progress(private_object *tech_pvt) 1350 { 1351 struct ast_channel *owner = tech_pvt->owner; 1352 1353 if (tech_pvt->profile->progress_enable && owner) { 1354 if (globals.debug > 2) { 1355 ast_log(LOG_NOTICE, "Sending Progress %s\n", tech_pvt->callid); 1356 } 1357 ast_queue_control(owner, AST_CONTROL_PROGRESS); 1358 } 1359 } 1360 1361 1362 static int woomera_coding_to_ast(char *suil1p) 1363 { 1364 if (suil1p) { 1365 if (!strcasecmp(suil1p, "G_711_ULAW")) { 1366 return AST_FORMAT_ULAW; 1367 } 1368 if (!strcasecmp(suil1p, "G_711_ALAW")) { 1369 return AST_FORMAT_ALAW; 1370 } 1371 if (!strcasecmp(suil1p, "G_721")) { 1372 return AST_FORMAT_ADPCM; 1373 } 1374 } 1375 return -1; 1376 } 1377 1378 1379 static char* woomera_ast_coding_to_string(int coding) 1380 { 1381 switch(coding) { 1382 case AST_FORMAT_ALAW: 1383 return "G_711_ALAW"; 1384 case AST_FORMAT_ULAW: 1385 return "G_711_ULAW"; 1386 case AST_FORMAT_ADPCM: 1387 return "G_721"; 1388 } 1389 return "G_711_ALAW"; 1390 } 1391 1392 1393 static uint32_t woomera_capability_to_ast(char *sbearer_cap) 1394 { 1395 if (sbearer_cap) { 1396 if (!strcasecmp(sbearer_cap, "SPEECH")) { 1397 return AST_TRANS_CAP_SPEECH; 1398 } 1399 if (!strcasecmp(sbearer_cap, "3_1KHZ_AUDIO")) { 1400 return AST_TRANS_CAP_3_1K_AUDIO; 1401 } 1402 if (!strcasecmp(sbearer_cap, "64K_UNRESTRICTED") || 1403 !strcasecmp(sbearer_cap, "ALTERNATE_SPEECH") || 1404 !strcasecmp(sbearer_cap, "ALTERNATE_64K") || 1405 !strcasecmp(sbearer_cap, "64K_PREFERRED") || 1406 !strcasecmp(sbearer_cap, "384K_UNRESTRICTED") || 1407 !strcasecmp(sbearer_cap, "2x64K_PREFERRED") || 1408 !strcasecmp(sbearer_cap, "1536K_UNRESTRICTED") || 1409 !strcasecmp(sbearer_cap, "1920K_UNRESTRICTED")) { 1410 1411 return AST_TRANS_CAP_DIGITAL; 1412 } 1413 } 1414 return AST_TRANS_CAP_SPEECH; 1415 } 1416 1417 1418 static char* woomera_ast_transfercap_to_string(int transfercap) 1419 { 1420 switch(transfercap) { 1421 case AST_TRANS_CAP_SPEECH: 1422 return "SPEECH"; 1423 case AST_TRANS_CAP_3_1K_AUDIO: 1424 return "3_1KHZ_AUDIO"; 1425 case AST_TRANS_CAP_DIGITAL: 1426 case AST_TRANS_CAP_RESTRICTED_DIGITAL: 1427 case AST_TRANS_CAP_DIGITAL_W_TONES: 1428 case AST_TRANS_CAP_VIDEO: 1429 return "64K_UNRESTRICTED"; 1430 } 1431 1432 return "SPEECH"; 1433 } 1434 1435 1436 static uint32_t string_to_release(char *code) 1437 { 1438 if (code) { 1439 if (!strcasecmp(code, "CHANUNAVAIL")) { 1440 return AST_CAUSE_REQUESTED_CHAN_UNAVAIL; 1441 } 1442 1443 if (!strcasecmp(code, "INVALID")) { 1444 return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; 1445 } 1446 1447 if (!strcasecmp(code, "ERROR")) { 1448 return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; 1449 } 1450 1451 if (!strcasecmp(code, "CONGESTION")) { 1452 return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; 1453 } 1454 1455 if (!strcasecmp(code, "BUSY")) { 1456 return AST_CAUSE_USER_BUSY; 1457 } 1458 1459 if (!strcasecmp(code, "NOANSWER")) { 1460 return AST_CAUSE_NO_ANSWER; 1461 } 1462 1463 if (!strcasecmp(code, "ANSWER")) { 1464 return AST_CAUSE_NORMAL_CLEARING; 1465 } 1466 1467 if (!strcasecmp(code, "CANCEL")) { 1468 return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; 1469 } 1470 1471 if (!strcasecmp(code, "UNKNOWN")) { 1472 return AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; 1473 } 1474 } 1475 return AST_CAUSE_NORMAL_CLEARING; 1476 } 1477 1478 1479 /*! 1480 * \brief Send a message to a Woomera server. 1481 */ 1482 #ifdef WOOMERA_PRINTF_DEBUG 1483 static int __woomera_printf(const char* file, int line, woomera_profile *profile, int fd, char *fmt, ...) 1484 #else 1485 static int __woomera_printf(woomera_profile *profile, int fd, char *fmt, ...) 1486 #endif 1487 { 1488 char *stuff; 1489 int res = 0; 1490 1491 if (fd < 0) { 1492 if (globals.debug > 4) { 1493 ast_log(LOG_ERROR, "Not gonna write to fd %d\n", fd); 1494 } 1495 return -1; 1496 } 1497 1498 va_list ap; 1499 va_start(ap, fmt); 1500 #ifdef SOLARIS 1501 stuff = (char *)ast_malloc(10240); 1502 vsnprintf(stuff, 10240, fmt, ap); 1503 #else 1504 res = vasprintf(&stuff, fmt, ap); 1505 #endif 1506 va_end(ap); 1507 1508 if (res == -1) { 1509 ast_log(LOG_ERROR, "Out of memory\n"); 1510 } else { 1511 res = 0; 1512 if (profile && globals.debug) { 1513 if (option_verbose > 2) { 1514 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); 1515 } 1516 } 1517 res = ast_carefulwrite(fd, stuff, strlen(stuff), 100); 1518 1519 #ifdef WOOMERA_PRINTF_DEBUG 1520 if (res < 0) { 1521 ast_log(LOG_ERROR,"%s:%d FAILED fd=%i %s\n", file, line, fd, strerror(errno)); 1522 } 1523 #endif 1524 ast_free(stuff); 1525 } 1526 1527 return res; 1528 } 1529 1530 1531 /*! 1532 * \brief Lookup a message header by name and return its value (null if not found). 1533 */ 1534 static char *woomera_message_header(woomera_message *wmsg, char *key) 1535 { 1536 int x = 0; 1537 char *value = NULL; 1538 1539 #if 0 1540 if (!strcasecmp(wmsg->command,"HANGUP")) { 1541 ast_log(LOG_NOTICE, "Message Header for HANGUP\n"); 1542 for (x = 0 ; x < wmsg->last ; x++) { 1543 ast_log(LOG_NOTICE, "Name=%s Value=%s\n", 1544 wmsg->names[x], wmsg->values[x]); 1545 if (!strcasecmp(wmsg->names[x], key)) { 1546 value = wmsg->values[x]; 1547 break; 1548 } 1549 } 1550 } 1551 #endif 1552 1553 for (x = 0 ; x < wmsg->last ; x++) { 1554 if (!strcasecmp(wmsg->names[x], key)) { 1555 value = wmsg->values[x]; 1556 break; 1557 } 1558 } 1559 1560 return value; 1561 } 1562 1563 /*! 1564 * \brief Queue an event. Used store events that arrive while we are waiting 1565 * for a command to complete. 1566 */ 1567 static int woomera_enqueue_event(woomera_event_queue *event_queue, woomera_message *wmsg) 1568 { 1569 woomera_message *new, *mptr; 1570 1571 if ((new = ast_malloc(sizeof(woomera_message)))) { 1572 ast_mutex_lock(&event_queue->lock); 1573 memcpy(new, wmsg, sizeof(woomera_message)); 1574 new->next = NULL; 1575 if (!event_queue->head) { 1576 event_queue->head = new; 1577 } else { 1578 for (mptr = event_queue->head; mptr && mptr->next ; mptr = mptr->next); 1579 mptr->next = new; 1580 } 1581 ast_mutex_unlock(&event_queue->lock); 1582 return 1; 1583 } else { 1584 ast_log(LOG_ERROR, "Memory Allocation Error!\n"); 1585 } 1586 1587 return 0; 1588 } 1589 1590 /*! 1591 * \brief Remove one event from the queue. 1592 */ 1593 static int woomera_dequeue_event(woomera_event_queue *event_queue, woomera_message *wmsg) 1594 { 1595 woomera_message *mptr = NULL; 1596 1597 ast_mutex_lock(&event_queue->lock); 1598 if (event_queue->head) { 1599 mptr = event_queue->head; 1600 event_queue->head = mptr->next; 1601 } 1602 1603 if (mptr) { 1604 memcpy(wmsg, mptr, sizeof(woomera_message)); 1605 } 1606 ast_mutex_unlock(&event_queue->lock); 1607 1608 if (mptr) { 1609 ast_free(mptr); 1610 return 1; 1611 } else { 1612 memset(wmsg, 0, sizeof(woomera_message)); 1613 } 1614 1615 return 0; 1616 } 1617 1618 1619 #if 0 1620 #include <execinfo.h> 1621 static void print_trace(void) 1622 { 1623 int i; 1624 void *stacktrace[100]; 1625 size_t size; 1626 char **symbols; 1627 1628 size = backtrace(stacktrace, sizeof(stacktrace)/sizeof(stacktrace[1])); 1629 symbols = backtrace_symbols(stacktrace, size); 1630 1631 for (i = 0; i < size; i++) { 1632 ast_log(LOG_ERROR, "%lu, %s\n", pthread_self(), symbols[i]); 1633 1634 } 1635 1636 if (symbols) 1637 free(symbols); 1638 1639 } 1640 #endif 1641 1642 1643 /*! 1644 * \brief Read from the socket and parse into a message object. 1645 * This will block until message is received. 1646 */ 1647 static int woomera_message_parse(int fd, 1648 woomera_message *wmsg, 1649 int timeout, 1650 woomera_profile *profile, 1651 woomera_event_queue *event_queue) 1652 { 1653 char *cur, *cr, *next = NULL, *eor = NULL; 1654 char buf[2048]; 1655 int res = 0, bytes = 0, sanity = 0; 1656 struct timeval started, ended; 1657 int elapsed, loops = 0; 1658 int fail_timeout = 0; 1659 1660 memset(wmsg, 0, sizeof(woomera_message)); 1661 1662 if (fd < 0) { 1663 return -1; 1664 } 1665 1666 gettimeofday(&started, NULL); 1667 memset(buf, 0, sizeof(buf)); 1668 1669 /* -ve timeout values indicate that timeouts should be treated as a failure. 1670 */ 1671 if (timeout < 0) { 1672 timeout = abs(timeout); 1673 fail_timeout = 1; 1674 } else if (timeout == 0) { 1675 timeout = -1; 1676 } 1677 1678 while (!(eor = strstr(buf, WOOMERA_RECORD_SEPARATOR))) { 1679 1680 if (!profile->thread_running) { 1681 return -1; 1682 } 1683 1684 if (globals.panic > 2) { 1685 return -1; 1686 } 1687 1688 res = woomera_printf(NULL, fd, "%s", WOOMERA_RECORD_SEPARATOR); 1689 if (res < 0) { 1690 return -1; 1691 } 1692 1693 if ((res = waitfor_socket(fd, (timeout > 0 ? timeout : 100)) > 0)) { 1694 res = recv(fd, buf, sizeof(buf), MSG_PEEK); 1695 if (res == 0) { 1696 sanity++; 1697 } else if (res < 0) { 1698 if (option_verbose > 2) { 1699 ast_verbose(WOOMERA_DEBUG_PREFIX "{%s} error during packet retry #%d\n", profile->name, loops); 1700 } 1701 return res; 1702 1703 } else if (loops && globals.debug) { 1704 //ast_verbose(WOOMERA_DEBUG_PREFIX "{%s} Didnt get complete packet retry #%d\n", profile->name, loops); 1705 res = woomera_printf(NULL, fd, "%s", WOOMERA_RECORD_SEPARATOR); 1706 if (res < 0) { 1707 return res; 1708 } 1709 usleep(100); 1710 } 1711 1712 if (res > 0) { 1713 sanity = 0; 1714 } 1715 } 1716 1717 if (res < 0) { 1718 return res; 1719 } 1720 1721 if (sanity > 1000) { 1722 if (globals.debug > 2) { 1723 ast_log(LOG_ERROR, "{%s} Failed Sanity Check! [errors] fd=%d\n", 1724 profile->name, fd); 1725 } 1726 return -100; 1727 } 1728 1729 gettimeofday(&ended, NULL); 1730 elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000)); 1731 if (timeout > 0 && (elapsed > timeout)) { 1732 return fail_timeout ? -1 : 0; 1733 } 1734 1735 loops++; 1736 } 1737 1738 *eor = '\0'; 1739 bytes = strlen(buf) + 4; 1740 1741 memset(buf, 0, sizeof(buf)); 1742 res = read(fd, buf, bytes); 1743 next = buf; 1744 1745 if (globals.debug) { 1746 if (option_verbose > 2) { 1747 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); 1748 } 1749 } 1750 1751 while ((cur = next)) { 1752 if ((cr = strstr(cur, WOOMERA_LINE_SEPARATOR))) { 1753 *cr = '\0'; 1754 next = cr + (sizeof(WOOMERA_LINE_SEPARATOR) - 1); 1755 if (!strcmp(next, WOOMERA_RECORD_SEPARATOR)) { 1756 break; 1757 } 1758 } 1759 1760 if (ast_strlen_zero(cur)) { 1761 break; 1762 } 1763 1764 if (!wmsg->last) { 1765 ast_set_flag(wmsg, WFLAG_EXISTS); 1766 if (!strncasecmp(cur, "EVENT", 5)) { 1767 cur += 6; 1768 ast_set_flag(wmsg, WFLAG_EVENT); 1769 1770 if (cur && (cr = strchr(cur, ' '))) { 1771 char *id; 1772 1773 *cr = '\0'; 1774 cr++; 1775 id = cr; 1776 if (cr && (cr = strchr(cr, ' '))) { 1777 *cr = '\0'; 1778 cr++; 1779 strncpy(wmsg->command_args, cr, WOOMERA_STRLEN); 1780 } 1781 if(id) { 1782 ast_copy_string(wmsg->callid, id, sizeof(wmsg->callid)); 1783 } 1784 } 1785 } else { 1786 if (cur && (cur = strchr(cur, ' '))) { 1787 *cur = '\0'; 1788 cur++; 1789 wmsg->mval = atoi(buf); 1790 } else { 1791 ast_log(LOG_NOTICE, "Malformed Message!\n"); 1792 break; 1793 } 1794 } 1795 if (cur) { 1796 strncpy(wmsg->command, cur, WOOMERA_STRLEN); 1797 } else { 1798 ast_log(LOG_NOTICE, "Malformed Message!\n"); 1799 break; 1800 } 1801 } else { 1802 char *name, *val; 1803 name = cur; 1804 if ((val = strchr(name, ':'))) { 1805 *val = '\0'; 1806 val++; 1807 while (*val == ' ') { 1808 *val = '\0'; 1809 val++; 1810 } 1811 strncpy(wmsg->values[wmsg->last-1], val, WOOMERA_STRLEN); 1812 } 1813 strncpy(wmsg->names[wmsg->last-1], name, WOOMERA_STRLEN); 1814 if (name && val && !strcasecmp(name, "content-type")) { 1815 ast_set_flag(wmsg, WFLAG_CONTENT); 1816 bytes = atoi(val); 1817 } 1818 1819 if (name && val && !strcasecmp(name, "content-length")) { 1820 ast_set_flag(wmsg, WFLAG_CONTENT); 1821 bytes = atoi(val); 1822 } 1823 } 1824 wmsg->last++; 1825 1826 if (wmsg->last >= WOOMERA_ARRAY_LEN) { 1827 ast_log(LOG_NOTICE, "Woomera parse error: index overflow!\n"); 1828 break; 1829 } 1830 } 1831 1832 wmsg->last--; 1833 1834 if (bytes && ast_test_flag(wmsg, WFLAG_CONTENT)) { 1835 int terr; 1836 terr = read(fd, wmsg->body, (bytes > sizeof(wmsg->body)) ? sizeof(wmsg->body) : bytes); 1837 if (globals.debug) { 1838 if (option_verbose > 2) { 1839 ast_verbose("%s\n", wmsg->body); 1840 } 1841 } 1842 } 1843 1844 if (event_queue && ast_test_flag(wmsg, WFLAG_EVENT)) { 1845 if (globals.debug) { 1846 if (option_verbose > 2) { 1847 ast_verbose(WOOMERA_DEBUG_PREFIX "Queue Event: {%s} [%s]\n", profile->name, wmsg->command); 1848 } 1849 } 1850 /* we don't want events we want a reply so we will stash them for later */ 1851 woomera_enqueue_event(event_queue, wmsg); 1852 1853 /* call ourself recursively to find the reply. we'll keep doing this as long we get events. 1854 * wmsg will be overwritten but it's ok we just queued it. 1855 */ 1856 return woomera_message_parse(fd, wmsg, timeout, profile, event_queue); 1857 1858 } else if (wmsg->mval > 99 && wmsg->mval < 200) { 1859 /* reply in the 100's are nice but we need to wait for another reply 1860 * call ourself recursively to find the reply > 199 and forget this reply. 1861 */ 1862 return woomera_message_parse(fd, wmsg, timeout, profile, event_queue); 1863 } else { 1864 return ast_test_flag(wmsg, WFLAG_EXISTS); 1865 } 1866 } 1867 1868 1869 /*! 1870 * \brief Block until a message arrives, an error occurs or the call is aborte. 1871 */ 1872 static int woomera_message_parse_wait(private_object *tech_pvt, woomera_message *wmsg) 1873 { 1874 int err = 0; 1875 1876 for (;;) { 1877 1878 if (ast_test_flag(tech_pvt, TFLAG_ABORT)){ 1879 return -1; 1880 } 1881 1882 err = woomera_message_parse(tech_pvt->command_channel, 1883 wmsg, 1884 100, 1885 tech_pvt->profile, 1886 &tech_pvt->event_queue); 1887 1888 if (err == 0) { 1889 /* This is a timeout */ 1890 continue; 1891 } 1892 1893 break; 1894 } 1895 1896 return err; 1897 } 1898 1899 1900 /*! 1901 * \brief Create a udp socket for raw audio. 1902 */ 1903 static int tech_create_read_socket(private_object *tech_pvt) 1904 { 1905 int retry=0; 1906 int ports=0; 1907 1908 retry_udp: 1909 1910 ast_mutex_lock(&globals.woomera_port_lock); 1911 globals.next_woomera_port++; 1912 if (globals.next_woomera_port >= woomera_max_media_port) { 1913 globals.next_woomera_port = woomera_base_media_port; 1914 } 1915 tech_pvt->port = globals.next_woomera_port; 1916 ports++; 1917 ast_mutex_unlock(&globals.woomera_port_lock); 1918 1919 if ((tech_pvt->udp_socket = create_udp_socket(tech_pvt->profile->audio_ip, 1920 tech_pvt->port, 1921 &tech_pvt->udpread, 0)) > -1) { 1922 struct ast_channel *owner = tech_get_owner(tech_pvt); 1923 if (owner) { 1924 owner->fds[0] = tech_pvt->udp_socket; 1925 } else { 1926 ast_log(LOG_ERROR, "Tech_pvt has no OWNER! %i\n",__LINE__); 1927 } 1928 1929 } else { 1930 1931 retry++; 1932 if (retry <= 10 || errno == EADDRINUSE) { 1933 if (ports < (woomera_max_media_port - woomera_base_media_port)) { 1934 goto retry_udp; 1935 } 1936 } 1937 1938 if (globals.debug) { 1939 ast_log(LOG_ERROR, 1940 "Error Creating udp socket %s/%i (%p) %s %s %s\n", 1941 tech_pvt->profile->audio_ip, 1942 tech_pvt->port, 1943 tech_pvt, 1944 tech_pvt->callid, 1945 ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT" : "IN", 1946 strerror(errno)); 1947 } 1948 } 1949 return tech_pvt->udp_socket; 1950 } 1951 1952 /*! 1953 * \brief Start a call 1954 */ 1955 static int tech_activate(private_object *tech_pvt) 1956 { 1957 int retry_activate_call = 0; 1958 woomera_message wmsg; 1959 char *callid; 1960 int err = 0; 1961 1962 memset(&wmsg, 0, sizeof(wmsg)); 1963 1964 retry_activate_again: 1965 1966 if (!tech_pvt) { 1967 ast_log(LOG_ERROR, "Critical Error: Where's my tech_pvt?\n"); 1968 return -1; 1969 } 1970 1971 if ((connect_woomera(&tech_pvt->command_channel, tech_pvt->profile, 0)) > -1) { 1972 if (globals.debug > 2) { 1973 ast_log(LOG_NOTICE, 1974 "Connected to woomera! chfd=%i port=%i dir=%s callid=%s Count=%i tpvt=%p\n", 1975 tech_pvt->command_channel, 1976 tech_pvt->port, 1977 ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT" : "IN", 1978 ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "N/A" : tech_pvt->callid, 1979 tech_pvt->call_count, 1980 tech_pvt); 1981 } 1982 } else { 1983 1984 if (retry_activate_call <= 3) { 1985 retry_activate_call++; 1986 goto retry_activate_again; 1987 } 1988 1989 if (globals.debug > 1 && option_verbose > 1) { 1990 ast_log(LOG_ERROR, "Error: %s call connect to TCP/Woomera Server! tpvt=%p: %s\n", 1991 ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "Out" : "In", 1992 tech_pvt, strerror(errno)); 1993 } 1994 goto tech_activate_failed; 1995 } 1996 1997 retry_activate_call = 0; 1998 1999 if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) { 2000 2001 if (strlen(tech_pvt->proto) > 1) { 2002 if (tech_pvt->vrtp_enable) { 2003 err = woomera_printf(tech_pvt->profile, 2004 tech_pvt->command_channel, 2005 "CALL %s:%s%s" 2006 "RTP-Audio: %s:%d%s" 2007 "RTP-Audio-Format: %s%s" 2008 "RTP-Video: %s:%d%s" 2009 "RTP-Video-Format: %s%s" 2010 "Local-Name: %s!%s%s" 2011 "Local-Number:%s%s" 2012 "Presentation:%d%s" 2013 "Screening:%d%s" 2014 "Bearer-Cap:%s%s" 2015 "uil1p:%s%s" 2016 "RDNIS:%s%s", 2017 tech_pvt->proto, 2018 tech_pvt->dest, 2019 WOOMERA_LINE_SEPARATOR, 2020 tech_pvt->profile->audio_ip, 2021 tech_pvt->port, 2022 WOOMERA_LINE_SEPARATOR, 2023 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0), 2024 WOOMERA_LINE_SEPARATOR, 2025 tech_pvt->profile->audio_ip, /* use same ip for video */ 2026 tech_pvt->vport, 2027 WOOMERA_LINE_SEPARATOR, 2028 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->videocoding, 0), 2029 WOOMERA_LINE_SEPARATOR, 2030 tech_pvt->cid_name, 2031 tech_pvt->cid_num, 2032 WOOMERA_LINE_SEPARATOR, 2033 tech_pvt->cid_num, 2034 WOOMERA_LINE_SEPARATOR, 2035 (tech_pvt->cid_pres >> 5) & 0x7, 2036 WOOMERA_LINE_SEPARATOR, 2037 tech_pvt->cid_pres & 0xF, 2038 WOOMERA_LINE_SEPARATOR, 2039 woomera_ast_transfercap_to_string(tech_pvt->capability), 2040 WOOMERA_LINE_SEPARATOR, 2041 woomera_ast_coding_to_string(tech_pvt->coding), 2042 WOOMERA_LINE_SEPARATOR, 2043 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "", 2044 WOOMERA_RECORD_SEPARATOR 2045 ); 2046 }else if (tech_pvt->rtp_enable) { 2047 err = woomera_printf(tech_pvt->profile, 2048 tech_pvt->command_channel, 2049 "CALL %s:%s%s" 2050 "RTP-Audio: %s:%d%s" 2051 "RTP-Audio-Format: %s%s" 2052 "Local-Name: %s!%s%s" 2053 "Local-Number:%s%s" 2054 "Presentation:%d%s" 2055 "Screening:%d%s" 2056 "Bearer-Cap:%s%s" 2057 "uil1p:%s%s" 2058 "RDNIS:%s%s", 2059 tech_pvt->proto, 2060 tech_pvt->dest, 2061 WOOMERA_LINE_SEPARATOR, 2062 tech_pvt->profile->audio_ip, 2063 tech_pvt->port, 2064 WOOMERA_LINE_SEPARATOR, 2065 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0), 2066 WOOMERA_LINE_SEPARATOR, 2067 tech_pvt->cid_name, 2068 tech_pvt->cid_num, 2069 WOOMERA_LINE_SEPARATOR, 2070 tech_pvt->cid_num, 2071 WOOMERA_LINE_SEPARATOR, 2072 (tech_pvt->cid_pres >> 5) & 0x7, 2073 WOOMERA_LINE_SEPARATOR, 2074 tech_pvt->cid_pres & 0xF, 2075 WOOMERA_LINE_SEPARATOR, 2076 woomera_ast_transfercap_to_string(tech_pvt->capability), 2077 WOOMERA_LINE_SEPARATOR, 2078 woomera_ast_coding_to_string(tech_pvt->coding), 2079 WOOMERA_LINE_SEPARATOR, 2080 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "", 2081 WOOMERA_RECORD_SEPARATOR 2082 ); 2083 } else { 2084 err = woomera_printf(tech_pvt->profile, 2085 tech_pvt->command_channel, 2086 "CALL %s:%s%s" 2087 "Raw-Audio: %s:%d%s" 2088 "Local-Name: %s!%s%s" 2089 "Local-Number:%s%s" 2090 "Presentation:%d%s" 2091 "Screening:%d%s" 2092 "Bearer-Cap:%s%s" 2093 "uil1p:%s%s" 2094 "RDNIS:%s%s", 2095 tech_pvt->proto, 2096 tech_pvt->dest, 2097 WOOMERA_LINE_SEPARATOR, 2098 tech_pvt->profile->audio_ip, 2099 tech_pvt->port, 2100 WOOMERA_LINE_SEPARATOR, 2101 tech_pvt->cid_name, 2102 tech_pvt->cid_num, 2103 WOOMERA_LINE_SEPARATOR, 2104 tech_pvt->cid_num, 2105 WOOMERA_LINE_SEPARATOR, 2106 (tech_pvt->cid_pres >> 5) & 0x7, 2107 WOOMERA_LINE_SEPARATOR, 2108 tech_pvt->cid_pres & 0xF, 2109 WOOMERA_LINE_SEPARATOR, 2110 woomera_ast_transfercap_to_string(tech_pvt->capability), 2111 WOOMERA_LINE_SEPARATOR, 2112 woomera_ast_coding_to_string(tech_pvt->coding), 2113 WOOMERA_LINE_SEPARATOR, 2114 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "", 2115 WOOMERA_RECORD_SEPARATOR 2116 ); 2117 } 2118 } 2119 else 2120 { 2121 if (tech_pvt->vrtp_enable) { 2122 err = woomera_printf(tech_pvt->profile, 2123 tech_pvt->command_channel, 2124 "CALL %s%s" 2125 "RTP-Audio: %s:%d%s" 2126 "RTP-Audio-Format: %s%s" 2127 "RTP-Video: %s:%d%s" 2128 "RTP-Video-Format: %s%s" 2129 "Local-Name: %s!%s%s" 2130 "Local-Number:%s%s" 2131 "Presentation:%d%s" 2132 "Screening:%d%s" 2133 "Bearer-Cap:%s%s" 2134 "uil1p:%s%s" 2135 "RDNIS:%s%s", 2136 tech_pvt->dest, 2137 WOOMERA_LINE_SEPARATOR, 2138 tech_pvt->profile->audio_ip, 2139 tech_pvt->port, 2140 WOOMERA_LINE_SEPARATOR, 2141 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0), 2142 WOOMERA_LINE_SEPARATOR, 2143 tech_pvt->profile->audio_ip, 2144 tech_pvt->vport, 2145 WOOMERA_LINE_SEPARATOR, 2146 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->videocoding, 0), 2147 WOOMERA_LINE_SEPARATOR, 2148 tech_pvt->cid_name, 2149 tech_pvt->cid_num, 2150 WOOMERA_LINE_SEPARATOR, 2151 tech_pvt->cid_num, 2152 WOOMERA_LINE_SEPARATOR, 2153 (tech_pvt->cid_pres >> 5) & 0x7, 2154 WOOMERA_LINE_SEPARATOR, 2155 tech_pvt->cid_pres & 0xF, 2156 WOOMERA_LINE_SEPARATOR, 2157 woomera_ast_transfercap_to_string(tech_pvt->capability), 2158 WOOMERA_LINE_SEPARATOR, 2159 woomera_ast_coding_to_string(tech_pvt->coding), 2160 WOOMERA_LINE_SEPARATOR, 2161 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "", 2162 WOOMERA_RECORD_SEPARATOR 2163 ); 2164 } else if (tech_pvt->rtp_enable) { 2165 err = woomera_printf(tech_pvt->profile, 2166 tech_pvt->command_channel, 2167 "CALL %s%s" 2168 "RTP-Audio: %s:%d%s" 2169 "RTP-Audio-Format: %s%s" 2170 "Local-Name: %s!%s%s" 2171 "Local-Number:%s%s" 2172 "Presentation:%d%s" 2173 "Screening:%d%s" 2174 "Bearer-Cap:%s%s" 2175 "uil1p:%s%s" 2176 "RDNIS:%s%s", 2177 tech_pvt->dest, 2178 WOOMERA_LINE_SEPARATOR, 2179 tech_pvt->profile->audio_ip, 2180 tech_pvt->port, 2181 WOOMERA_LINE_SEPARATOR, 2182 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0), 2183 WOOMERA_LINE_SEPARATOR, 2184 tech_pvt->cid_name, 2185 tech_pvt->cid_num, 2186 WOOMERA_LINE_SEPARATOR, 2187 tech_pvt->cid_num, 2188 WOOMERA_LINE_SEPARATOR, 2189 (tech_pvt->cid_pres >> 5) & 0x7, 2190 WOOMERA_LINE_SEPARATOR, 2191 tech_pvt->cid_pres & 0xF, 2192 WOOMERA_LINE_SEPARATOR, 2193 woomera_ast_transfercap_to_string(tech_pvt->capability), 2194 WOOMERA_LINE_SEPARATOR, 2195 woomera_ast_coding_to_string(tech_pvt->coding), 2196 WOOMERA_LINE_SEPARATOR, 2197 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "", 2198 WOOMERA_RECORD_SEPARATOR 2199 ); 2200 } else { 2201 err = woomera_printf(tech_pvt->profile, 2202 tech_pvt->command_channel, 2203 "CALL %s%s" 2204 "Raw-Audio: %s:%d%s" 2205 "Local-Name: %s!%s%s" 2206 "Local-Number:%s%s" 2207 "Presentation:%d%s" 2208 "Screening:%d%s" 2209 "Bearer-Cap:%s%s" 2210 "uil1p:%s%s" 2211 "RDNIS:%s%s", 2212 tech_pvt->dest, 2213 WOOMERA_LINE_SEPARATOR, 2214 tech_pvt->profile->audio_ip, 2215 tech_pvt->port, 2216 WOOMERA_LINE_SEPARATOR, 2217 tech_pvt->cid_name, 2218 tech_pvt->cid_num, 2219 WOOMERA_LINE_SEPARATOR, 2220 tech_pvt->cid_num, 2221 WOOMERA_LINE_SEPARATOR, 2222 (tech_pvt->cid_pres >> 5) & 0x7, 2223 WOOMERA_LINE_SEPARATOR, 2224 tech_pvt->cid_pres & 0xF, 2225 WOOMERA_LINE_SEPARATOR, 2226 woomera_ast_transfercap_to_string(tech_pvt->capability), 2227 WOOMERA_LINE_SEPARATOR, 2228 woomera_ast_coding_to_string(tech_pvt->coding), 2229 WOOMERA_LINE_SEPARATOR, 2230 tech_pvt->cid_rdnis ? tech_pvt->cid_rdnis : "", 2231 WOOMERA_RECORD_SEPARATOR 2232 ); 2233 } 2234 } 2235 2236 if (err < 0) { 2237 if (globals.debug > 2) { 2238 ast_log(LOG_NOTICE, "Outbound call failed, -write msg Call %s tpvt=%p\n", 2239 tech_pvt->callid, tech_pvt); 2240 } 2241 ast_set_flag(tech_pvt, TFLAG_ABORT); 2242 goto tech_activate_failed; 2243 } 2244 2245 err = woomera_message_parse_wait(tech_pvt, &wmsg); 2246 if (err < 0) { 2247 if (globals.debug > 2) { 2248 ast_log(LOG_NOTICE, "Outbound call failed, -wait parse Call %s tpvt=%p\n", 2249 tech_pvt->callid, tech_pvt); 2250 } 2251 ast_set_flag(tech_pvt, TFLAG_ABORT); 2252 goto tech_activate_failed; 2253 } 2254 2255 if (woomera_message_reply_ok(&wmsg) != 0) { 2256 if (globals.debug > 2) { 2257 ast_log(LOG_NOTICE, "Outbound call failed, got bad reply. Call %s tpvt=%p response=%d\n", 2258 tech_pvt->callid, tech_pvt, wmsg.mval); 2259 } 2260 if (wmsg.mval == 503) { 2261 ast_queue_control(tech_pvt->owner, AST_CONTROL_CONGESTION); 2262 } 2263 ast_set_flag(tech_pvt, TFLAG_ABORT); 2264 } 2265 2266 callid = woomera_message_header(&wmsg, "Unique-Call-Id"); 2267 if (callid) { 2268 ast_copy_string(tech_pvt->callid, callid, sizeof(wmsg.callid)); 2269 } 2270 2271 } else { 2272 ast_set_flag(tech_pvt, TFLAG_PARSE_INCOMING); 2273 if (globals.debug > 2) { 2274 ast_log(LOG_NOTICE, "Incoming Call %s tpvt=%p\n", 2275 tech_pvt->callid, tech_pvt); 2276 } 2277 2278 err = woomera_printf(tech_pvt->profile, 2279 tech_pvt->command_channel, 2280 "PROCEED %s%s" 2281 "Unique-Call-Id: %s%s", 2282 tech_pvt->callid, 2283 WOOMERA_LINE_SEPARATOR, 2284 tech_pvt->callid, 2285 WOOMERA_RECORD_SEPARATOR); 2286 2287 if (err < 0) { 2288 ast_set_flag(tech_pvt, TFLAG_ABORT); 2289 goto tech_activate_failed; 2290 } 2291 2292 err = woomera_message_parse_wait(tech_pvt, &wmsg); 2293 if (err < 0) { 2294 ast_set_flag(tech_pvt, TFLAG_ABORT); 2295 goto tech_activate_failed; 2296 } 2297 2298 if (woomera_message_reply_ok(&wmsg) != 0) { 2299 ast_set_flag(tech_pvt, TFLAG_ABORT); 2300 /* Do not hangup on main because 2301 * socket connection has been 2302 * established */ 2303 } 2304 } 2305 2306 if (globals.debug > 2) { 2307 ast_log(LOG_NOTICE, "TECH ACTIVATE OK tech_pvt=%p\n", tech_pvt); 2308 } 2309 return 0; 2310 2311 tech_activate_failed: 2312 2313 if (globals.debug > 2) { 2314 ast_log(LOG_NOTICE, "TECH ACTIVATE FAILED tech_pvt=%p\n", tech_pvt); 2315 } 2316 2317 woomera_close_socket(&tech_pvt->command_channel); 2318 ast_set_flag(tech_pvt, TFLAG_ABORT); 2319 2320 /* At this point we cannot estabilsh a woomera 2321 * socket to the server. The server still doesnt know 2322 * about the incoming call that is now pending. 2323 * We must send a message to server to hangup the call */ 2324 2325 if (globals.debug > 2) { 2326 ast_log(LOG_NOTICE, "Error: %s Call %s tpvt=%p Failed!\n", 2327 ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT" : "IN", 2328 tech_pvt->callid, tech_pvt); 2329 } 2330 2331 return -1; 2332 } 2333 2334 2335 /*! 2336 * Initialise pvt object, called at the start of a call. 2337 */ 2338 static int tech_init(private_object *tech_pvt, woomera_profile *profile, int flags) 2339 { 2340 struct sockaddr_in us; 2341 struct ast_channel *self = tech_get_owner(tech_pvt); 2342 2343 gettimeofday(&tech_pvt->started, NULL); 2344 2345 if (profile) { 2346 tech_pvt->profile = profile; 2347 } else { 2348 ast_log(LOG_ERROR, "Tech init no profile!\n"); 2349 ast_set_flag(tech_pvt, TFLAG_ABORT); 2350 return -1; 2351 } 2352 2353 if (profile && profile->send_dtmf_enable) { 2354 tech_pvt->send_dtmf_enable = 1; 2355 } else { 2356 tech_pvt->send_dtmf_enable = 0; 2357 } 2358 2359 if (profile && profile->rtp_enable) { 2360 tech_pvt->rtp_enable = 1; 2361 } else { 2362 tech_pvt->rtp_enable = 0; 2363 } 2364 2365 if (profile && profile->vrtp_enable) { 2366 tech_pvt->vrtp_enable = 1; 2367 } else { 2368 tech_pvt->vrtp_enable = 0; 2369 } 2370 2371 if (profile && profile->bridge_enable) { 2372 tech_pvt->bridge_enable = 1; 2373 } else { 2374 tech_pvt->bridge_enable = 0; 2375 } 2376 2377 ast_set_flag(tech_pvt, flags); 2378 2379 if (tech_pvt->rtp_enable) { 2380 tech_pvt->rtp = create_rtp(tech_pvt->profile->audio_ip); 2381 if (tech_pvt->rtp) { 2382 self->fds[0] = ast_rtp_fd(tech_pvt->rtp); 2383 ast_rtp_get_us(tech_pvt->rtp, &us); 2384 tech_pvt->port = ntohs(us.sin_port); 2385 if (globals.debug > 2) { 2386 ast_log(LOG_DEBUG, "Created rtp audio. port=%d\n", tech_pvt->port); 2387 } 2388 } else { 2389 ast_log(LOG_ERROR, "Failed to create rtp audio\n"); 2390 ast_set_flag(tech_pvt, TFLAG_ABORT); 2391 return -1; 2392 } 2393 2394 if (tech_pvt->vrtp_enable) { 2395 tech_pvt->vrtp = create_rtp(tech_pvt->profile->audio_ip); /* same ip for both */ 2396 if (tech_pvt->vrtp) { 2397 self->fds[1] = ast_rtp_fd(tech_pvt->vrtp); 2398 ast_rtp_get_us(tech_pvt->vrtp, &us); 2399 tech_pvt->vport = ntohs(us.sin_port); 2400 if (globals.debug > 2) { 2401 ast_log(LOG_DEBUG, "Created rtp video. port=%d\n", tech_pvt->vport); 2402 } 2403 } else { 2404 ast_log(LOG_ERROR, "Failed to create rtp video\n"); 2405 ast_set_flag(tech_pvt, TFLAG_ABORT); 2406 return -1; 2407 } 2408 } 2409 2410 } else { 2411 if (tech_pvt->udp_socket < 0) { 2412 int rc; 2413 rc = tech_create_read_socket(tech_pvt); 2414 if (rc < 0) { 2415 ast_log(LOG_ERROR, "Failed to create UDP Socket (%p)! %s\n", 2416 tech_pvt, strerror(errno)); 2417 ast_set_flag(tech_pvt, TFLAG_ABORT); 2418 return -1; 2419 } 2420 } 2421 } 2422 2423 ast_set_flag(tech_pvt, flags); 2424 2425 tech_pvt->capability = self->transfercapability; 2426 2427 tech_pvt->coding = profile->coding; 2428 tech_pvt->videocoding = profile->videocoding; 2429 self->nativeformats = tech_pvt->coding | tech_pvt->videocoding; 2430 self->writeformat = self->rawwriteformat = self->readformat = tech_pvt->coding | tech_pvt->videocoding; 2431 tech_pvt->frame.subclass = tech_pvt->coding | tech_pvt->videocoding; 2432 2433 ast_clear_flag(tech_pvt, TFLAG_CONFIRM_ANSWER); 2434 ast_clear_flag(tech_pvt, TFLAG_CONFIRM_ANSWER_ENABLED); 2435 ast_clear_flag(tech_pvt, TFLAG_ANSWER_RECEIVED); 2436 2437 if (profile && profile->faxdetect) { 2438 tech_pvt->faxdetect = 1; 2439 } 2440 2441 if (profile->dtmf_enable) { 2442 2443 tech_pvt->dsp_features = 0; 2444 tech_pvt->dsp = ast_dsp_new(); 2445 if (tech_pvt->dsp) { 2446 #if 0 2447 i->dsp_features = features & ~DSP_PROGRESS_TALK; 2448 2449 /* We cannot do progress detection until receives PROGRESS message */ 2450 if (i->outgoing && (i->sig == SIG_PRI)) { 2451 /* Remember requested DSP features, don't treat 2452 talking as ANSWER */ 2453 features = 0; 2454 } 2455 #endif 2456 tech_pvt->dsp_features |= DSP_FEATURE_DTMF_DETECT; 2457 //tech_pvt->dsp_features |= DSP_FEATURE_BUSY_DETECT; 2458 //tech_pvt->dsp_features |= DSP_FEATURE_CALL_PROGRESS; 2459 if (tech_pvt->faxdetect) { 2460 tech_pvt->dsp_features |= DSP_FEATURE_FAX_DETECT; 2461 } 2462 ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features); 2463 ast_dsp_digitmode(tech_pvt->dsp, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF); 2464 tech_pvt->ast_dsp = 1; 2465 #if 0 2466 if (!ast_strlen_zero(progzone)) 2467 ast_dsp_set_call_progress_zone(tech_pvt->dsp, progzone); 2468 if (i->busydetect && CANBUSYDETECT(i)) { 2469 ast_dsp_set_busy_count(tech_pvt->dsp, i->busycount); 2470 ast_dsp_set_busy_pattern(tech_pvt->dsp, i->busy_tonelength, i->busy_quietlength); 2471 } 2472 #endif 2473 } 2474 } 2475 2476 if (profile->jb_enable) { 2477 #if defined AST_JB 2478 /* Assign default jb conf to the new zt_pvt */ 2479 memcpy(&tech_pvt->jbconf, &global_jbconf, sizeof(struct ast_jb_conf)); 2480 ast_jb_configure(self, &tech_pvt->jbconf); 2481 2482 if (globals.debug > 2 && option_verbose > 10) { 2483 ast_log(LOG_NOTICE, "%s: Cfg JitterBuffer (F=%i MS=%li Rs=%li Impl=%s)\n", 2484 self->name, 2485 tech_pvt->jbconf.flags, 2486 tech_pvt->jbconf.max_size, 2487 tech_pvt->jbconf.resync_threshold, 2488 tech_pvt->jbconf.impl); 2489 } 2490 #else 2491 ast_log(LOG_ERROR, "Asterisk Jitter Buffer Not Compiled!\n"); 2492 #endif 2493 } 2494 2495 /* Asterisk allows approx 1 nanosecond to try and establish a connetion here. 2496 * Now asterisk, will not enforce a lock while we work 2497 * and after even a 1 second delay it will give up on the lock and mess everything up 2498 * This stems from the fact that asterisk will scan it's list of channels constantly for 2499 * reasons like tab completion and cli output. 2500 * 2501 * Anyway, since we've already spent that nanosecond with the previous line of code 2502 * tech_create_read_socket(tech_pvt); to setup a read socket 2503 * which, by the way, asterisk insists we have before going any furthur. 2504 * So, in short, we are between a rock and a hard place and asterisk wants us to open a socket here 2505 * but it too impaitent to wait for us to make sure it's ready so in the case of outgoing calls 2506 * we will defer the rest of the socket establishment process to the monitor thread. 2507 */ 2508 if (globals.more_threads) { 2509 int err; 2510 ast_set_flag(tech_pvt, TFLAG_ACTIVATE); 2511 /* we're gonna try "wasting" a thread to do a better realtime monitoring */ 2512 err = launch_tech_thread(tech_pvt); 2513 if (err) { 2514 ast_log(LOG_ERROR, "Failed to launch tech control thread\n"); 2515 ast_clear_flag(tech_pvt, TFLAG_ACTIVATE); 2516 ast_set_flag(tech_pvt, TFLAG_ABORT); 2517 return -1; 2518 } 2519 2520 } else { 2521 if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) { 2522 ast_set_flag(tech_pvt, TFLAG_ACTIVATE); 2523 } else { 2524 tech_activate(tech_pvt); 2525 } 2526 } 2527 2528 if (globals.debug > 2) { 2529 ast_log(LOG_NOTICE, "TECH INIT tech_pvt=%p c=%p (use=%i)\n", 2530 tech_pvt, tech_pvt->owner,usecount()); 2531 } 2532 2533 return 0; 2534 } 2535 2536 2537 /*! 2538 * \brief End a call. 2539 */ 2540 static void tech_destroy(private_object *tech_pvt, struct ast_channel *owner) 2541 { 2542 ASTOBJ_CONTAINER_UNLINK(&private_object_list, tech_pvt); 2543 2544 ast_set_flag(tech_pvt, TFLAG_DESTROY); 2545 ast_set_flag(tech_pvt, TFLAG_ABORT); 2546 2547 if (globals.debug > 2) { 2548 ast_log(LOG_NOTICE, "Tech Destroy callid=%s tpvt=%p %s/%d\n", 2549 tech_pvt->callid, 2550 tech_pvt, 2551 tech_pvt->profile ? tech_pvt->profile->audio_ip : "NA", 2552 tech_pvt->port); 2553 } 2554 2555 if (tech_pvt->profile && tech_pvt->command_channel > -1) { 2556 2557 if (globals.debug > 1 && option_verbose > 1) { 2558 ast_log(LOG_NOTICE, "Tech Destroy sending HANGUP %s\n", tech_pvt->callid); 2559 } 2560 woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 2561 "HANGUP %s%s" 2562 "cause: %s%s" 2563 "Q931-Cause-Code: %d%s" 2564 "Reason-String: %s%s" 2565 "Reason: %d%s" 2566 "Unique-Call-Id: %s%s", 2567 tech_pvt->callid, 2568 WOOMERA_LINE_SEPARATOR, 2569 tech_pvt->ds, 2570 WOOMERA_LINE_SEPARATOR, 2571 tech_pvt->pri_cause, 2572 WOOMERA_LINE_SEPARATOR, 2573 tech_pvt->ds, 2574 WOOMERA_LINE_SEPARATOR, 2575 tech_pvt->pri_cause, 2576 WOOMERA_LINE_SEPARATOR, 2577 tech_pvt->callid, 2578 WOOMERA_RECORD_SEPARATOR); 2579 2580 woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 2581 "BYE%s" 2582 "Unique-Call-Id: %s%s", 2583 WOOMERA_LINE_SEPARATOR, 2584 tech_pvt->callid, 2585 WOOMERA_RECORD_SEPARATOR); 2586 2587 woomera_close_socket(&tech_pvt->command_channel); 2588 } 2589 2590 woomera_close_socket(&tech_pvt->command_channel); 2591 2592 if (tech_pvt->rtp_enable) { 2593 if (tech_pvt->rtp) { 2594 if (globals.debug > 2) { 2595 ast_log(LOG_NOTICE,"Tech Destroy ending audio rtp session\n"); 2596 } 2597 ast_rtp_destroy(tech_pvt->rtp); 2598 } 2599 if (tech_pvt->vrtp) { 2600 if (globals.debug > 2) { 2601 ast_log(LOG_NOTICE,"Tech Destroy ending video rtp session\n"); 2602 } 2603 ast_rtp_destroy(tech_pvt->vrtp); 2604 } 2605 } else { 2606 woomera_close_socket(&tech_pvt->udp_socket); 2607 } 2608 2609 /* Tech profile is allowed to be null in case the call 2610 * is blocked from the call_count */ 2611 2612 #if 0 2613 ast_log(LOG_NOTICE, "---- Call END %p %s ----------------------------\n", 2614 tech_pvt, tech_pvt->callid); 2615 #endif 2616 2617 if (owner) { 2618 if (globals.debug > 2) { 2619 ast_log(LOG_NOTICE, "Tech Destroy doing AST HANGUP!\n"); 2620 } 2621 owner->tech_pvt = NULL; 2622 tech_pvt->owner = NULL; 2623 ast_hangup(owner); 2624 } 2625 tech_pvt->owner = NULL; 2626 2627 tech_count--; 2628 if (tech_pvt->dsp) { 2629 tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT; 2630 ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features); 2631 tech_pvt->ast_dsp = 0; 2632 ast_free(tech_pvt->dsp); 2633 tech_pvt->dsp = NULL; 2634 } 2635 2636 if (globals.debug > 2) { 2637 ast_log(LOG_NOTICE, "DESTROY Exit tech_pvt=%p (use=%i)\n", 2638 tech_pvt, usecount()); 2639 } 2640 2641 ast_mutex_destroy(&tech_pvt->iolock); 2642 ast_mutex_destroy(&tech_pvt->event_queue.lock); 2643 2644 if (tech_pvt->cid_rdnis) { 2645 ast_free(tech_pvt->cid_rdnis); 2646 tech_pvt->cid_rdnis = NULL; 2647 } 2648 2649 ast_free(tech_pvt); 2650 2651 ast_mutex_lock(&usecnt_lock); 2652 usecnt--; 2653 ast_mutex_unlock(&usecnt_lock); 2654 } 2655 2656 #if 0 2657 2658 static int waitfor_socket(int fd, int timeout) 2659 { 2660 struct pollfd pfds[1]; 2661 int res; 2662 int errflags = (POLLERR | POLLHUP | POLLNVAL); 2663 2664 if (fd < 0) { 2665 return -1; 2666 } 2667 2668 memset(&pfds[0], 0, sizeof(pfds[0])); 2669 pfds[0].fd = fd; 2670 pfds[0].events = POLLIN | errflags; 2671 res = poll(pfds, 1, timeout); 2672 if (res > 0) { 2673 if ((pfds[0].revents & errflags)) { 2674 res = -1; 2675 } else if ((pfds[0].revents & POLLIN)) { 2676 res = 1; 2677 } else { 2678 ast_log(LOG_ERROR, "System Error: Poll Event Error no event!\n"); 2679 res = -1; 2680 } 2681 } 2682 2683 return res; 2684 } 2685 2686 #else 2687 2688 /*! 2689 *\brief Wait for an event on a socket. 2690 * \return 1 - event ready 2691 * \return 0 - timeout 2692 * \return -1 - error 2693 */ 2694 static int waitfor_socket(int fd, int timeout) 2695 { 2696 struct pollfd pfds[1]; 2697 int res; 2698 2699 if (fd < 0) { 2700 return -1; 2701 } 2702 2703 memset(&pfds[0], 0, sizeof(pfds[0])); 2704 pfds[0].fd = fd; 2705 pfds[0].events = POLLIN | POLLERR; 2706 res = poll(pfds, 1, timeout); 2707 if (res > 0) { 2708 if ((pfds[0].revents & POLLERR)) { 2709 res = -1; 2710 } else if((pfds[0].revents & POLLIN)) { 2711 res = 1; 2712 } else { 2713 res = -1; 2714 } 2715 } 2716 2717 return res; 2718 } 2719 2720 #endif 2721 2722 /*! 2723 * \brief Per call event monitoring. 2724 */ 2725 static void *tech_monitor_thread(void *obj) 2726 { 2727 private_object *tech_pvt; 2728 woomera_message wmsg; 2729 char tcallid[WOOMERA_STRLEN]; 2730 int aborted = 0; 2731 2732 int res = 0; 2733 2734 tech_pvt = obj; 2735 2736 if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP)) { 2737 ast_log(LOG_NOTICE, "Tech Monitor: Call stopped before thread up!\n"); 2738 return NULL; 2739 } 2740 2741 memset(tcallid, 0, sizeof(tcallid)); 2742 memset(&wmsg, 0, sizeof(wmsg)); 2743 2744 if (globals.debug > 2) { 2745 ast_log(LOG_NOTICE, "IN THREAD %s rxgain=%f txgain=%f\n", 2746 tech_pvt->callid, 2747 tech_pvt->profile->rxgain_val, 2748 tech_pvt->profile->txgain_val); 2749 } 2750 ast_mutex_lock(&tech_pvt->profile->call_count_lock); 2751 if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) { 2752 tech_pvt->profile->call_out++; 2753 } else { 2754 tech_pvt->profile->call_in++; 2755 } 2756 tech_pvt->profile->call_count++; 2757 ast_mutex_unlock(&tech_pvt->profile->call_count_lock); 2758 2759 for(;;) { 2760 2761 if (globals.panic) { 2762 ast_set_flag(tech_pvt, TFLAG_ABORT); 2763 } 2764 2765 if (!tech_pvt->owner) { 2766 ast_set_flag(tech_pvt, TFLAG_ABORT); 2767 if (globals.debug > 2) { 2768 ast_log(LOG_NOTICE, "Thread lost Owner Chan %s %p\n", 2769 tech_pvt->callid, 2770 tech_pvt); 2771 } 2772 } 2773 2774 /* finish the deferred stuff asterisk won't allow us to do live */ 2775 if (ast_test_flag(tech_pvt, TFLAG_ABORT)) { 2776 int ast_hangup = 0; 2777 struct woomera_profile *profile = tech_pvt->profile;; 2778 2779 if (globals.debug > 2) { 2780 ast_log(LOG_NOTICE, "ABORT GOT HANGUP CmdCh=%i %s %s/%i\n", 2781 tech_pvt->command_channel, tech_pvt->callid, 2782 tech_pvt->profile ? tech_pvt->profile->audio_ip : "N/A", 2783 tech_pvt->port); 2784 } 2785 2786 aborted |= 1; 2787 2788 /* Check for queued events, looking for HANGUP messages, 2789 so we can return proper hangup cause */ 2790 for (;;) { 2791 if ((res = woomera_dequeue_event(&tech_pvt->event_queue, &wmsg))) { 2792 woomera_check_event(tech_pvt, res, &wmsg); 2793 } else { 2794 break; 2795 } 2796 } 2797 2798 ast_mutex_lock(&tech_pvt->profile->call_count_lock); 2799 tech_pvt->profile->call_count--; 2800 ast_mutex_unlock(&tech_pvt->profile->call_count_lock); 2801 2802 if (tech_pvt->profile && tech_pvt->command_channel > -1) { 2803 2804 if (globals.debug > 2) { 2805 ast_log(LOG_NOTICE, "ABORT sent HANGUP on %s %p\n", 2806 tech_pvt->callid, 2807 tech_pvt); 2808 } 2809 aborted |= 2; 2810 woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 2811 "HANGUP %s%s" 2812 "cause: %s%s" 2813 "Q931-Cause-Code: %d%s" 2814 "Reason-String: %s%s" 2815 "Reason: %d%s" 2816 "Unique-Call-Id: %s%s", 2817 tech_pvt->callid, 2818 WOOMERA_LINE_SEPARATOR, 2819 tech_pvt->ds, 2820 WOOMERA_LINE_SEPARATOR, 2821 tech_pvt->pri_cause, 2822 WOOMERA_LINE_SEPARATOR, 2823 tech_pvt->ds, 2824 WOOMERA_LINE_SEPARATOR, 2825 tech_pvt->pri_cause, 2826 WOOMERA_LINE_SEPARATOR, 2827 tech_pvt->callid, 2828 WOOMERA_RECORD_SEPARATOR); 2829 2830 woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 2831 "BYE%s" 2832 "Unique-Call-Id: %s%s", 2833 WOOMERA_LINE_SEPARATOR, 2834 tech_pvt->callid, 2835 WOOMERA_RECORD_SEPARATOR); 2836 2837 woomera_close_socket(&tech_pvt->command_channel); 2838 } 2839 2840 if (tech_pvt->rtp_enable) { 2841 if (tech_pvt->rtp) { 2842 if (globals.debug > 2) { 2843 ast_log(LOG_NOTICE, "Tech Thread - ending audio rtp session\n"); 2844 } 2845 ast_rtp_destroy(tech_pvt->rtp); 2846 tech_pvt->rtp = 0; 2847 } 2848 if (tech_pvt->vrtp) { 2849 if (globals.debug > 2) { 2850 ast_log(LOG_NOTICE, "Tech Thread - ending video rtp session\n"); 2851 } 2852 ast_rtp_destroy(tech_pvt->vrtp); 2853 tech_pvt->vrtp = 0; 2854 } 2855 } else { 2856 woomera_close_socket(&tech_pvt->udp_socket); 2857 } 2858 2859 if (globals.debug > 2) { 2860 ast_log(LOG_NOTICE, "Tech Thread - Hanging up channel\n"); 2861 } 2862 ast_mutex_lock(&tech_pvt->iolock); 2863 while (tech_pvt->owner && my_ast_channel_trylock(tech_pvt->owner)) { 2864 if (globals.debug > 2) { 2865 ast_log(LOG_NOTICE, "Tech Thread - Hanging up channel - deadlock avoidance\n"); 2866 } 2867 DEADLOCK_AVOIDANCE(&tech_pvt->iolock); 2868 } 2869 2870 if (tech_pvt->owner) { 2871 struct ast_channel *owner = tech_pvt->owner; 2872 if (ast_test_flag(tech_pvt, TFLAG_PBX) || owner->pbx) { 2873 aborted |= 4; 2874 2875 if (globals.debug > 2) { 2876 ast_log(LOG_NOTICE, "ABORT calling hangup on %s t=%p c=%p UP=%d\n", 2877 tech_pvt->callid, 2878 tech_pvt, 2879 owner, 2880 ast_test_flag(tech_pvt, TFLAG_UP)); 2881 } 2882 2883 /* Issue a softhangup */ 2884 if (globals.debug > 2) { 2885 ast_log(LOG_NOTICE, "Tech Thread - Hanging up channel - soft hangup\n"); 2886 } 2887 2888 #if defined (AST14) || defined (AST16) 2889 if (ast_test_flag(owner, AST_FLAG_BLOCKING)) { 2890 int cnt = 0; 2891 while (!owner->blocker) { 2892 ast_log(LOG_ERROR, "Woomera: BLOCKER Set but no blocker!\n"); 2893 usleep(50); 2894 cnt++; 2895 } 2896 if (cnt) { 2897 ast_log(LOG_ERROR, "Woomera: BLOCKER Set Got Blocker %s!\n", 2898 owner->blockproc); 2899 } 2900 } 2901 #endif 2902 2903 ast_softhangup_nolock(owner, AST_SOFTHANGUP_DEV); 2904 ast_clear_flag(tech_pvt, TFLAG_INTHREAD); 2905 ast_set_flag(tech_pvt, TFLAG_AST_HANGUP); 2906 tech_pvt->owner = NULL; 2907 2908 /* After this point tech_pvt point should not be touched */ 2909 ast_hangup = 1; 2910 2911 } else { 2912 if (globals.debug > 2) { 2913 ast_log(LOG_NOTICE,"Tech Thread - Hanging up channel - owner=%p pbx=%i \n", 2914 owner, ast_test_flag(tech_pvt, TFLAG_PBX)); 2915 } 2916 } 2917 my_ast_channel_unlock(owner); 2918 } 2919 2920 ast_mutex_unlock(&tech_pvt->iolock); 2921 2922 ast_mutex_lock(&profile->call_count_lock); 2923 profile->call_end++; 2924 ast_mutex_unlock(&profile->call_count_lock); 2925 2926 /* Wait for tech_hangup to set this, so there is on 2927 * race condition with asterisk 2928 */ 2929 //ast_set_flag(tech_pvt, TFLAG_DESTROY); 2930 2931 if (ast_hangup) { 2932 ast_mutex_lock(&profile->call_count_lock); 2933 profile->call_ast_hungup++; 2934 ast_mutex_unlock(&profile->call_count_lock); 2935 2936 /* Let Asterisk tech_hangup destroy tech_pvt */ 2937 goto tech_thread_exit; 2938 2939 } else { 2940 ast_mutex_lock(&tech_pvt->profile->call_count_lock); 2941 tech_pvt->profile->call_abort++; 2942 ast_mutex_unlock(&tech_pvt->profile->call_count_lock); 2943 2944 if (globals.debug > 2) { 2945 ast_log(LOG_NOTICE, "NOTE: Skipping Wait on destroy timedout! %s tech_pvt=%p\n", 2946 tech_pvt->callid, tech_pvt); 2947 } 2948 ast_set_flag(tech_pvt, TFLAG_DESTROY); 2949 } 2950 2951 aborted |= 8; 2952 tech_destroy(tech_pvt, tech_get_owner(tech_pvt)); 2953 tech_pvt = NULL; 2954 break; 2955 } 2956 2957 if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP) || !tech_pvt->owner) { 2958 ast_set_flag(tech_pvt, TFLAG_DESTROY); 2959 ast_set_flag(tech_pvt, TFLAG_ABORT); 2960 if (globals.debug > 2) { 2961 ast_log(LOG_NOTICE, "Thread got HANGUP or no owner %s %p tpvt=%p\n", 2962 tech_pvt->callid, tech_pvt, tech_pvt->owner); 2963 } 2964 goto tech_thread_continue; 2965 } 2966 2967 if (ast_test_flag(tech_pvt, TFLAG_ACTIVATE)) { 2968 2969 struct ast_channel *owner; 2970 int err; 2971 2972 if (globals.debug > 2) { 2973 ast_log(LOG_NOTICE, "ACTIVATE %s tpvt=%p\n", 2974 tech_pvt->callid, tech_pvt); 2975 } 2976 ast_clear_flag(tech_pvt, TFLAG_ACTIVATE); 2977 err = tech_activate(tech_pvt); 2978 if (err < 0 || ast_test_flag(tech_pvt, TFLAG_ABORT)) { 2979 if (globals.debug > 2) { 2980 ast_log(LOG_NOTICE, "ACTIVATE ABORT Ch=%d\n", 2981 tech_pvt->command_channel); 2982 } 2983 ast_set_flag(tech_pvt, TFLAG_ABORT); 2984 goto tech_thread_continue; 2985 } 2986 2987 my_tech_pvt_and_owner_lock(tech_pvt); 2988 owner = tech_pvt->owner; 2989 if (owner) { 2990 owner->hangupcause = AST_CAUSE_NORMAL_CLEARING; 2991 } 2992 my_tech_pvt_and_owner_unlock(tech_pvt); 2993 2994 if (globals.debug > 2) { 2995 ast_log(LOG_NOTICE, "ACTIVATE DONE %s tpvt=%p\n", 2996 tech_pvt->callid, tech_pvt); 2997 } 2998 } 2999 3000 if (ast_test_flag(tech_pvt, TFLAG_PARSE_INCOMING)) { 3001 int err; 3002 3003 ast_clear_flag(tech_pvt, TFLAG_PARSE_INCOMING); 3004 ast_set_flag(tech_pvt, TFLAG_INCOMING); 3005 3006 my_tech_pvt_and_owner_lock(tech_pvt); 3007 err = woomera_event_incoming(tech_pvt); 3008 my_tech_pvt_and_owner_unlock(tech_pvt); 3009 3010 if (err != 0) { 3011 3012 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3013 "HANGUP %s%s" 3014 "cause: Invalid call reference%s" 3015 "Q931-Cause-Code: 81%s" 3016 "Reason-String: Invalid call reference%s" 3017 "Reason: 81%s" 3018 "Unique-Call-Id: %s%s", 3019 tech_pvt->callid, 3020 WOOMERA_LINE_SEPARATOR, 3021 WOOMERA_LINE_SEPARATOR, 3022 WOOMERA_LINE_SEPARATOR, 3023 WOOMERA_LINE_SEPARATOR, 3024 WOOMERA_LINE_SEPARATOR, 3025 tech_pvt->callid, 3026 WOOMERA_RECORD_SEPARATOR); 3027 3028 /* Wait for Ack */ 3029 if (err >= 0) { 3030 woomera_message_parse_wait(tech_pvt, &wmsg); 3031 } 3032 3033 woomera_close_socket(&tech_pvt->command_channel); 3034 3035 ast_set_flag(tech_pvt, TFLAG_ABORT); 3036 goto tech_thread_continue; 3037 3038 } else { 3039 if (tech_pvt->vrtp_enable) { 3040 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3041 "%s %s%s" 3042 "RTP-Audio: %s:%d%s" 3043 "RTP-Audio-Format: %s%s" 3044 "RTP-Video: %s:%d%s" 3045 "RTP-Video-Format: %s%s" 3046 "Unique-Call-Id: %s%s", 3047 MEDIA_ANSWER, 3048 tech_pvt->callid, 3049 WOOMERA_LINE_SEPARATOR, 3050 tech_pvt->profile->audio_ip, 3051 tech_pvt->port, 3052 WOOMERA_LINE_SEPARATOR, 3053 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0), 3054 WOOMERA_LINE_SEPARATOR, 3055 tech_pvt->profile->audio_ip, /* use same */ 3056 tech_pvt->vport, 3057 WOOMERA_LINE_SEPARATOR, 3058 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->videocoding, 0), 3059 WOOMERA_LINE_SEPARATOR, 3060 tech_pvt->callid, 3061 WOOMERA_RECORD_SEPARATOR); 3062 } else if (tech_pvt->rtp_enable) { 3063 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3064 "%s %s%s" 3065 "RTP-Audio: %s:%d%s" 3066 "RTP-Audio-Format: %s%s" 3067 "Unique-Call-Id: %s%s", 3068 MEDIA_ANSWER, 3069 tech_pvt->callid, 3070 WOOMERA_LINE_SEPARATOR, 3071 tech_pvt->profile->audio_ip, 3072 tech_pvt->port, 3073 WOOMERA_LINE_SEPARATOR, 3074 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0), 3075 WOOMERA_LINE_SEPARATOR, 3076 tech_pvt->callid, 3077 WOOMERA_RECORD_SEPARATOR); 3078 } else { 3079 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3080 "%s %s%s" 3081 "Raw-Audio: %s:%d%s" 3082 "Request-Audio: Raw%s" 3083 "Unique-Call-Id: %s%s", 3084 MEDIA_ANSWER, 3085 tech_pvt->callid, 3086 WOOMERA_LINE_SEPARATOR, 3087 tech_pvt->profile->audio_ip, 3088 tech_pvt->port, 3089 WOOMERA_LINE_SEPARATOR, 3090 WOOMERA_LINE_SEPARATOR, 3091 tech_pvt->callid, 3092 WOOMERA_RECORD_SEPARATOR); 3093 } 3094 } 3095 3096 /* Wait for Ack */ 3097 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) { 3098 ast_set_flag(tech_pvt, TFLAG_ABORT); 3099 ast_log(LOG_NOTICE, "MEDIA ANSWER ABORT Ch=%d\n", 3100 tech_pvt->command_channel); 3101 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 3102 tech_pvt->pri_cause = 111; 3103 goto tech_thread_continue; 3104 } 3105 3106 /* Confirm that the Ack is OK otherwise 3107 * hangup */ 3108 if (woomera_message_reply_ok(&wmsg) != 0) { 3109 ast_set_flag(tech_pvt, TFLAG_ABORT); 3110 goto tech_thread_continue; 3111 } 3112 3113 /* It is possible for ACCEPT to have media info 3114 * This is how Early Media is started */ 3115 err = woomera_event_media(tech_pvt, &wmsg); 3116 if (err < 0) { 3117 ast_set_flag(tech_pvt, TFLAG_ABORT); 3118 goto tech_thread_continue; 3119 } 3120 } 3121 3122 if (ast_test_flag(tech_pvt, TFLAG_ACCEPT) && 3123 ast_test_flag(tech_pvt, TFLAG_INCOMING)) { 3124 int err; 3125 3126 ast_set_flag(tech_pvt, TFLAG_ACCEPTED); 3127 ast_clear_flag(tech_pvt, TFLAG_ACCEPT); 3128 3129 if (tech_pvt->vrtp_enable) { 3130 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3131 "ACCEPT %s%s" 3132 "RTP-Audio: %s:%d%s" 3133 "RTP-Audio-Format: %s%s" 3134 "RTP-Video: %s:%d%s" 3135 "RTP-Video-Format: %s%s" 3136 "Unique-Call-Id: %s%s", 3137 tech_pvt->callid, 3138 WOOMERA_LINE_SEPARATOR, 3139 tech_pvt->profile->audio_ip, 3140 tech_pvt->port, 3141 WOOMERA_LINE_SEPARATOR, 3142 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0), 3143 WOOMERA_LINE_SEPARATOR, 3144 tech_pvt->profile->audio_ip, 3145 tech_pvt->vport, 3146 WOOMERA_LINE_SEPARATOR, 3147 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->videocoding, 0), 3148 WOOMERA_LINE_SEPARATOR, 3149 tech_pvt->callid, 3150 WOOMERA_RECORD_SEPARATOR); 3151 } else if (tech_pvt->rtp_enable) { 3152 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3153 "ACCEPT %s%s" 3154 "RTP-Audio: %s:%d%s" 3155 "RTP-Audio-Format: %s%s" 3156 "Unique-Call-Id: %s%s", 3157 tech_pvt->callid, 3158 WOOMERA_LINE_SEPARATOR, 3159 tech_pvt->profile->audio_ip, 3160 tech_pvt->port, 3161 WOOMERA_LINE_SEPARATOR, 3162 ast_rtp_lookup_mime_subtype(1, tech_pvt->profile->coding, 0), 3163 WOOMERA_LINE_SEPARATOR, 3164 tech_pvt->callid, 3165 WOOMERA_RECORD_SEPARATOR); 3166 } else { 3167 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3168 "ACCEPT %s%s" 3169 "Raw-Audio: %s:%d%s" 3170 "Request-Audio: Raw%s" 3171 "Unique-Call-Id: %s%s", 3172 tech_pvt->callid, 3173 WOOMERA_LINE_SEPARATOR, 3174 tech_pvt->profile->audio_ip, 3175 tech_pvt->port, 3176 WOOMERA_LINE_SEPARATOR, 3177 WOOMERA_LINE_SEPARATOR, 3178 tech_pvt->callid, 3179 WOOMERA_RECORD_SEPARATOR); 3180 } 3181 3182 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) { 3183 ast_set_flag(tech_pvt, TFLAG_ABORT); 3184 ast_log(LOG_NOTICE, "ACCEPT ABORT Ch=%d\n", tech_pvt->command_channel); 3185 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 3186 tech_pvt->pri_cause = 111; 3187 goto tech_thread_continue; 3188 continue; 3189 } 3190 } 3191 3192 if (ast_test_flag(tech_pvt, TFLAG_ANSWER)) { 3193 int err; 3194 3195 if (globals.debug > 2) { 3196 ast_log(LOG_NOTICE, "ANSWER %s tpvt=%p\n", tech_pvt->callid, tech_pvt); 3197 } 3198 ast_clear_flag(tech_pvt, TFLAG_ANSWER); 3199 3200 if (ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) { 3201 ast_log(LOG_ERROR,"Error: ANSWER on OUTBOUND Call! (skipped) %s\n", 3202 tech_pvt->callid); 3203 } else { 3204 #ifdef USE_ANSWER 3205 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3206 "ANSWER %s%s" 3207 "Unique-Call-Id: %s%s", 3208 tech_pvt->callid, 3209 WOOMERA_LINE_SEPARATOR, 3210 tech_pvt->callid, 3211 WOOMERA_RECORD_SEPARATOR); 3212 3213 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) { 3214 ast_set_flag(tech_pvt, TFLAG_ABORT); 3215 ast_log(LOG_NOTICE, "ANSWER ABORT Ch=%d\n", tech_pvt->command_channel); 3216 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 3217 tech_pvt->pri_cause = 111; 3218 goto tech_thread_continue; 3219 continue; 3220 } 3221 ast_set_flag(tech_pvt, TFLAG_CONNECTED); 3222 ast_mutex_lock(&tech_pvt->profile->call_count_lock); 3223 tech_pvt->profile->call_ok++; 3224 ast_mutex_unlock(&tech_pvt->profile->call_count_lock); 3225 #endif 3226 } 3227 } 3228 3229 if (ast_test_flag(tech_pvt, TFLAG_DTMF)) { 3230 int err; 3231 if (globals.debug > 2) { 3232 ast_log(LOG_NOTICE, "DTMF %s tpvt=%p %s\n", 3233 tech_pvt->callid, tech_pvt, tech_pvt->dtmfbuf); 3234 } 3235 3236 //DIALECT 3237 ast_mutex_lock(&tech_pvt->iolock); 3238 #if 0 3239 woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3240 "DTMF %s %s%s", 3241 tech_pvt->callid, 3242 tech_pvt->dtmfbuf, 3243 WOOMERA_LINE_SEPARATOR); 3244 #else 3245 err = woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 3246 "DTMF %sUnique-Call-Id:%s%sContent-Length:%d%s%s%s%s", 3247 WOOMERA_LINE_SEPARATOR, 3248 tech_pvt->callid, 3249 WOOMERA_LINE_SEPARATOR, 3250 strlen(tech_pvt->dtmfbuf), 3251 WOOMERA_LINE_SEPARATOR, 3252 WOOMERA_LINE_SEPARATOR, 3253 tech_pvt->dtmfbuf, 3254 WOOMERA_RECORD_SEPARATOR); 3255 #endif 3256 3257 ast_clear_flag(tech_pvt, TFLAG_DTMF); 3258 memset(tech_pvt->dtmfbuf, 0, sizeof(tech_pvt->dtmfbuf)); 3259 ast_mutex_unlock(&tech_pvt->iolock); 3260 3261 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) { 3262 ast_set_flag(tech_pvt, TFLAG_ABORT); 3263 ast_log(LOG_NOTICE, "DTMF ABORT Ch=%d\n", tech_pvt->command_channel); 3264 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 3265 tech_pvt->pri_cause = 111; 3266 goto tech_thread_continue; 3267 continue; 3268 } 3269 } 3270 3271 if (ast_test_flag(tech_pvt, TFLAG_PLAY)) { 3272 int err; 3273 if (globals.debug > 2) { 3274 ast_log(LOG_NOTICE, "PLAY %s tpvt=%p AudioUri=%s VideoUri=%s\n", 3275 tech_pvt->callid, tech_pvt, tech_pvt->audio_uri, tech_pvt->video_uri); 3276 } 3277 3278 ast_mutex_lock(&tech_pvt->iolock); 3279 err = woomera_printf(tech_pvt->profile, 3280 tech_pvt->command_channel, 3281 "PLAY%s" 3282 "Unique-Call-Id: %s%s" 3283 "Audio-Uri: %s%s" 3284 "Video-Uri: %s%s" 3285 "Stop-Digits: %s%s" 3286 "Language: %s%s" 3287 "Repeat: %s%s", 3288 WOOMERA_LINE_SEPARATOR, 3289 tech_pvt->callid, 3290 WOOMERA_LINE_SEPARATOR, 3291 tech_pvt->audio_uri, 3292 WOOMERA_LINE_SEPARATOR, 3293 tech_pvt->video_uri, 3294 WOOMERA_LINE_SEPARATOR, 3295 tech_pvt->stop_digits, 3296 WOOMERA_LINE_SEPARATOR, 3297 tech_pvt->owner->language, 3298 WOOMERA_LINE_SEPARATOR, 3299 tech_pvt->repeat, 3300 WOOMERA_RECORD_SEPARATOR 3301 ); 3302 3303 ast_clear_flag(tech_pvt, TFLAG_PLAY); 3304 memset(tech_pvt->audio_uri, 0, sizeof(tech_pvt->audio_uri)); 3305 memset(tech_pvt->video_uri, 0, sizeof(tech_pvt->video_uri)); 3306 ast_mutex_unlock(&tech_pvt->iolock); 3307 3308 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) { 3309 ast_set_flag(tech_pvt, TFLAG_ABORT); 3310 ast_log(LOG_NOTICE, "PLAY ABORT Ch=%d\n", tech_pvt->command_channel); 3311 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 3312 tech_pvt->pri_cause = 111; 3313 goto tech_thread_continue; 3314 continue; 3315 } 3316 if ( wmsg.mval > 200 ) { 3317 pbx_builtin_setvar_helper(tech_pvt->owner, "WOOMERAPLAYSTATUS", "error"); 3318 pbx_builtin_setvar_helper(tech_pvt->owner, "WOOMERAPLAYDURATION", "0"); 3319 ast_set_flag(tech_pvt, TFLAG_PLAY_COMPLETED); 3320 } 3321 } 3322 3323 if (ast_test_flag(tech_pvt, TFLAG_RECORD)) { 3324 int err; 3325 if (globals.debug > 2) { 3326 ast_log(LOG_NOTICE, "RECORD %s tpvt=%p AudioUri=%s VideoUri=%s\n", 3327 tech_pvt->callid, tech_pvt, tech_pvt->audio_uri, tech_pvt->video_uri); 3328 } 3329 3330 ast_mutex_lock(&tech_pvt->iolock); 3331 err = woomera_printf(tech_pvt->profile, 3332 tech_pvt->command_channel, 3333 "RECORD%s" 3334 "Unique-Call-Id: %s%s" 3335 "Audio-Uri: %s%s" 3336 "Video-Uri: %s%s" 3337 "Stop-Digits: %s%s" 3338 "Beep: %s%s" 3339 "Language: %s%s", 3340 WOOMERA_LINE_SEPARATOR, 3341 tech_pvt->callid, 3342 WOOMERA_LINE_SEPARATOR, 3343 tech_pvt->audio_uri, 3344 WOOMERA_LINE_SEPARATOR, 3345 tech_pvt->video_uri, 3346 WOOMERA_LINE_SEPARATOR, 3347 tech_pvt->stop_digits, 3348 WOOMERA_LINE_SEPARATOR, 3349 (tech_pvt->beep ? "yes" : "no"), 3350 WOOMERA_LINE_SEPARATOR, 3351 tech_pvt->owner->language, 3352 WOOMERA_RECORD_SEPARATOR 3353 ); 3354 ast_clear_flag(tech_pvt, TFLAG_RECORD); 3355 memset(tech_pvt->audio_uri, 0, sizeof(tech_pvt->audio_uri)); 3356 memset(tech_pvt->video_uri, 0, sizeof(tech_pvt->video_uri)); 3357 ast_mutex_unlock(&tech_pvt->iolock); 3358 3359 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) { 3360 ast_set_flag(tech_pvt, TFLAG_ABORT); 3361 ast_log(LOG_NOTICE, "RECORD ABORT Ch=%d\n", 3362 tech_pvt->command_channel); 3363 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 3364 tech_pvt->pri_cause = 111; 3365 goto tech_thread_continue; 3366 continue; 3367 } 3368 if ( wmsg.mval > 200 ) { 3369 pbx_builtin_setvar_helper(tech_pvt->owner, "WOOMERARECORDSTATUS", "error"); 3370 pbx_builtin_setvar_helper(tech_pvt->owner, "WOOMERARECORDDURATION", "0"); 3371 ast_set_flag(tech_pvt, TFLAG_RECORD_COMPLETED); 3372 } 3373 } 3374 3375 if (ast_test_flag(tech_pvt, TFLAG_STOP)) { 3376 int err; 3377 if (globals.debug > 2) { 3378 ast_log(LOG_NOTICE, "STOP %s tpvt=%p\n", tech_pvt->callid, tech_pvt); 3379 } 3380 3381 ast_mutex_lock(&tech_pvt->iolock); 3382 err = woomera_printf(tech_pvt->profile, 3383 tech_pvt->command_channel, 3384 "STOP%s" 3385 "Unique-Call-Id: %s%s", 3386 WOOMERA_LINE_SEPARATOR, 3387 tech_pvt->callid, 3388 WOOMERA_RECORD_SEPARATOR 3389 ); 3390 3391 ast_clear_flag(tech_pvt, TFLAG_STOP); 3392 ast_mutex_unlock(&tech_pvt->iolock); 3393 3394 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) { 3395 ast_set_flag(tech_pvt, TFLAG_ABORT); 3396 ast_log(LOG_NOTICE, "STOP ABORT Ch=%d\n", tech_pvt->command_channel); 3397 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 3398 tech_pvt->pri_cause = 111; 3399 goto tech_thread_continue; 3400 continue; 3401 } 3402 ast_set_flag(tech_pvt, TFLAG_STOP_COMPLETED); 3403 if ( wmsg.mval > 200 ) { 3404 /* prevents us getting stuck in woomera_stop_exec() */ 3405 ast_set_flag(tech_pvt, TFLAG_PLAY_COMPLETED); 3406 } 3407 } 3408 3409 if (ast_test_flag(tech_pvt, TFLAG_BRIDGE) && ast_test_flag(tech_pvt, TFLAG_CONNECTED)) { 3410 int err; 3411 if (globals.debug > 2) { 3412 ast_log(LOG_NOTICE, "BRIDGE %s tpvt=%p RTP-Audio=%s:%d RTP-Video=%s:%d\n", 3413 tech_pvt->callid, tech_pvt, 3414 ast_inet_ntoa(tech_pvt->audio_bridge_ip.sin_addr), 3415 ntohs(tech_pvt->audio_bridge_ip.sin_port), 3416 ast_inet_ntoa(tech_pvt->video_bridge_ip.sin_addr), 3417 ntohs(tech_pvt->video_bridge_ip.sin_port) 3418 ); 3419 } 3420 /* update rtp end-points*/ 3421 ast_mutex_lock(&tech_pvt->iolock); 3422 err = woomera_printf(tech_pvt->profile, 3423 tech_pvt->command_channel, 3424 "UPDATE%s" 3425 "Unique-Call-Id: %s%s" 3426 "RTP-Audio: %s:%d%s" 3427 "RTP-Video: %s:%d%s", 3428 WOOMERA_LINE_SEPARATOR, 3429 tech_pvt->callid, 3430 WOOMERA_LINE_SEPARATOR, 3431 ast_inet_ntoa(tech_pvt->audio_bridge_ip.sin_addr), 3432 ntohs(tech_pvt->audio_bridge_ip.sin_port), 3433 WOOMERA_LINE_SEPARATOR, 3434 ast_inet_ntoa(tech_pvt->video_bridge_ip.sin_addr), 3435 ntohs(tech_pvt->video_bridge_ip.sin_port), 3436 WOOMERA_RECORD_SEPARATOR 3437 ); 3438 ast_clear_flag(tech_pvt, TFLAG_BRIDGE); 3439 ast_mutex_unlock(&tech_pvt->iolock); 3440 3441 if (err < 0 || woomera_message_parse_wait(tech_pvt, &wmsg) < 0) { 3442 ast_set_flag(tech_pvt, TFLAG_ABORT); 3443 ast_log(LOG_NOTICE, "BRIDGE ABORT Ch=%d\n", 3444 tech_pvt->command_channel); 3445 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 3446 tech_pvt->pri_cause = 111; 3447 goto tech_thread_continue; 3448 continue; 3449 } 3450 } 3451 3452 if (tech_pvt->timeout) { 3453 struct timeval now; 3454 int elapsed; 3455 gettimeofday(&now, NULL); 3456 elapsed = (((now.tv_sec * 1000) + now.tv_usec / 1000) - 3457 ((tech_pvt->started.tv_sec * 1000) + tech_pvt->started.tv_usec / 1000)); 3458 if (elapsed > tech_pvt->timeout) { 3459 /* call timed out! */ 3460 if (globals.debug > 2) { 3461 ast_log(LOG_NOTICE, "Call timed out %s tpvt=%p\n", 3462 tech_pvt->callid, tech_pvt); 3463 } 3464 ast_set_flag(tech_pvt, TFLAG_ABORT); 3465 ast_copy_string(tech_pvt->ds, "RECOVERY_ON_TIMER_EXPIRE", sizeof(tech_pvt->ds)); 3466 tech_pvt->pri_cause = 102; 3467 } 3468 } 3469 3470 if (globals.debug > 2) { 3471 if (tcallid[0] == 0) { 3472 strncpy(tcallid, tech_pvt->callid, sizeof(tcallid)-1); 3473 } 3474 } 3475 3476 if (tech_pvt->command_channel < 0) { 3477 if (!globals.more_threads) { 3478 goto tech_thread_continue; 3479 continue; 3480 } else { 3481 if (globals.debug > 2) { 3482 ast_log(LOG_NOTICE, "No Command Channel %s tpvt=%p\n", 3483 tech_pvt->callid, tech_pvt); 3484 } 3485 ast_copy_string(tech_pvt->ds, "REQUESTED_CHAN_UNAVAIL", sizeof(tech_pvt->ds)); 3486 tech_pvt->pri_cause = 44; 3487 ast_set_flag(tech_pvt, TFLAG_ABORT); 3488 goto tech_thread_continue; 3489 continue; 3490 } 3491 } 3492 /* Check for events */ 3493 if((res = woomera_dequeue_event(&tech_pvt->event_queue, &wmsg)) || 3494 (res = woomera_message_parse(tech_pvt->command_channel, 3495 &wmsg, 3496 100, 3497 tech_pvt->profile, 3498 NULL 3499 ))) { 3500 3501 woomera_check_event (tech_pvt, res, &wmsg); 3502 if (ast_test_flag(tech_pvt, TFLAG_ABORT)) { 3503 continue; 3504 } 3505 3506 } 3507 if (globals.debug > 4) { 3508 if (option_verbose > 2) { 3509 ast_verbose(WOOMERA_DEBUG_PREFIX "CHECK {%s} (%d) %s\n", 3510 tech_pvt->profile->name, 3511 res,tech_pvt->callid); 3512 } 3513 } 3514 3515 tech_thread_continue: 3516 3517 if (!globals.more_threads) { 3518 ast_log(LOG_NOTICE, "EXITING THREAD on more threads %s\n", 3519 tcallid); 3520 break; 3521 } 3522 3523 } 3524 3525 tech_thread_exit: 3526 3527 if (globals.debug > 2) { 3528 ast_log(LOG_NOTICE, "OUT THREAD %s 0x%X\n",tcallid,aborted); 3529 } 3530 3531 return NULL; 3532 } 3533 3534 3535 static int woomera_profile_thread_running(woomera_profile *profile, int set, int new) 3536 { 3537 int running = 0; 3538 3539 ast_mutex_lock(&profile->iolock); 3540 if (set) { 3541 profile->thread_running = new; 3542 } 3543 running = profile->thread_running; 3544 ast_mutex_unlock(&profile->iolock); 3545 return running; 3546 } 3547 3548 3549 /*! 3550 * \brief Connect to the Woomera server defined by the profile. 3551 */ 3552 static int woomera_locate_socket(woomera_profile *profile, int *woomera_socket) 3553 { 3554 woomera_message wmsg; 3555 3556 memset(&wmsg, 0, sizeof(wmsg)); 3557 3558 for (;;) { 3559 3560 while (connect_woomera(woomera_socket, profile, 0) < 0) { 3561 if(!woomera_profile_thread_running(profile, 0, 0)) { 3562 break; 3563 } 3564 if (globals.panic > 2) { 3565 break; 3566 } 3567 /* ast_log(LOG_NOTICE, 3568 "Woomera {%s} Cannot Reconnect! retry in 5 seconds...\n", 3569 profile->name); 3570 */ 3571 /* When we establish connection update the version */ 3572 svrversion_init = 0; 3573 sleep(5); 3574 } 3575 3576 if (*woomera_socket > -1) { 3577 if (ast_test_flag(profile, PFLAG_INBOUND)) { 3578 int err; 3579 if (globals.debug > 2) { 3580 ast_log(LOG_NOTICE, "Woomera Master Socket \n"); 3581 } 3582 3583 err = woomera_printf(profile, *woomera_socket, "LISTEN MASTER%s", WOOMERA_RECORD_SEPARATOR); 3584 if (err < 0) { 3585 if (*woomera_socket > -1) { 3586 woomera_close_socket(woomera_socket); 3587 } 3588 continue; 3589 } 3590 3591 if (woomera_message_parse(*woomera_socket, 3592 &wmsg, 3593 WOOMERA_HARD_TIMEOUT, 3594 profile, 3595 &profile->event_queue 3596 ) < 0) { 3597 ast_log(LOG_ERROR, "{%s} %s:%d HELP! Woomera is broken!\n", 3598 profile->name,__FUNCTION__,__LINE__); 3599 if (*woomera_socket > -1) { 3600 woomera_close_socket(woomera_socket); 3601 } 3602 continue; 3603 } 3604 } 3605 3606 } 3607 usleep(100); 3608 break; 3609 } 3610 return *woomera_socket; 3611 } 3612 3613 3614 static void tech_monitor_in_one_thread(void) 3615 { 3616 private_object *tech_pvt; 3617 3618 ASTOBJ_CONTAINER_TRAVERSE(&private_object_list, 1, do { 3619 ASTOBJ_RDLOCK(iterator); 3620 tech_pvt = iterator; 3621 tech_monitor_thread(tech_pvt); 3622 ASTOBJ_UNLOCK(iterator); 3623 } while(0)); 3624 } 3625 3626 3627 /*! 3628 * \brief Per profile Woomera socket listener. 3629 */ 3630 static void *woomera_thread_run(void *obj) 3631 { 3632 int woomera_socket = -1, res = 0, res2 = 0; 3633 woomera_message wmsg; 3634 woomera_profile *profile; 3635 3636 memset(&wmsg, 0, sizeof(wmsg)); 3637 3638 profile = obj; 3639 ast_log(LOG_NOTICE, "Started Woomera Thread {%s}.\n", profile->name); 3640 3641 profile->thread_running = 1; 3642 3643 while (woomera_profile_thread_running(profile, 0, 0)) { 3644 /* listen on socket and handle events */ 3645 3646 if (globals.panic > 2) { 3647 break; 3648 } 3649 3650 if (globals.panic == 2) { 3651 ast_log(LOG_NOTICE, "Woomera is disabled!\n"); 3652 sleep(5); 3653 continue; 3654 } 3655 3656 if (woomera_socket < 0) { 3657 if (woomera_locate_socket(profile, &woomera_socket)) { 3658 globals.panic = 0; 3659 } 3660 if (!woomera_profile_thread_running(profile, 0, 0)) { 3661 break; 3662 } 3663 profile->woomera_socket = woomera_socket; 3664 ast_log(LOG_NOTICE, "Woomera Thread Up {%s} %s:%d\n", 3665 profile->name, profile->woomera_host, profile->woomera_port); 3666 } 3667 3668 if (globals.panic) { 3669 if (globals.panic != 2) { 3670 ast_log(LOG_ERROR, "Help I'm in a state of panic!\n"); 3671 } 3672 if (woomera_socket > -1) { 3673 woomera_close_socket(&woomera_socket); 3674 profile->woomera_socket = -1; 3675 } 3676 continue; 3677 } 3678 if (!globals.more_threads) { 3679 if (woomera_socket > -1) { 3680 tech_monitor_in_one_thread(); 3681 } 3682 } 3683 3684 if ((res = woomera_dequeue_event(&profile->event_queue, &wmsg) || 3685 (res2 = woomera_message_parse(woomera_socket, 3686 &wmsg, 3687 /* if we are not stingy with threads we can block forever */ 3688 globals.more_threads ? 0 : 500, 3689 profile, 3690 NULL 3691 )))) { 3692 3693 if (res2 < 0) { 3694 ast_log(LOG_ERROR, "{%s} Lost my connection to Woomera Server %s:%d\n", profile->name, profile->woomera_host, profile->woomera_port); 3695 if (woomera_socket > -1) { 3696 woomera_close_socket(&woomera_socket); 3697 profile->woomera_socket = -1; 3698 } 3699 global_set_flag(TFLAG_ABORT); 3700 if (globals.panic > 2) { 3701 break; 3702 } 3703 3704 continue; 3705 3706 if (woomera_socket > -1) { 3707 if (ast_test_flag(profile, PFLAG_INBOUND)) { 3708 if (globals.debug > 2) { 3709 ast_log(LOG_NOTICE, "%s:%d Incoming Call \n",__FUNCTION__,__LINE__); 3710 } 3711 3712 #if 0 3713 /* We only want a single listener */ 3714 woomera_printf(profile, woomera_socket, "LISTEN%s", WOOMERA_RECORD_SEPARATOR); 3715 if (woomera_message_parse(woomera_socket, 3716 &wmsg, 3717 WOOMERA_HARD_TIMEOUT, 3718 profile, 3719 &profile->event_queue 3720 ) < 0) { 3721 ast_log(LOG_ERROR, "{%s} %s:%d HELP! Woomera is broken!\n", profile->name, __FUNCTION__, __LINE__); 3722 woomera_close_socket(&woomera_socket); 3723 profile->woomera_socket = -1; 3724 } 3725 #endif 3726 } 3727 if (woomera_socket > -1) { 3728 ast_log(LOG_NOTICE, "Woomera Thread Up {%s} %s/%d\n", profile->name, profile->woomera_host, profile->woomera_port); 3729 } 3730 } 3731 continue; 3732 } 3733 3734 if (!strcasecmp(wmsg.command, "INCOMING")) { 3735 3736 int err = 1; 3737 int cause = 0; 3738 struct ast_channel *inchan; 3739 char *name = "Woomera"; 3740 3741 if (!(name = woomera_message_header(&wmsg, "Channel-Name"))) { 3742 name = woomera_message_header(&wmsg,"Remote-Address"); 3743 } 3744 3745 if (!name) { 3746 name = wmsg.callid; 3747 } 3748 3749 if (!name) { 3750 name = "smg"; 3751 } 3752 3753 if (globals.debug > 2) { 3754 ast_log(LOG_NOTICE, "New Inbound Call %s\n", wmsg.callid); 3755 } 3756 3757 if ((inchan = woomera_new(WOOMERA_CHAN_NAME, profile->coding, name, &cause, profile))) { 3758 private_object *tech_pvt; 3759 char *callid; 3760 tech_pvt = inchan->tech_pvt; 3761 3762 /* Save the call id */ 3763 tech_pvt->call_info = wmsg; 3764 memcpy(tech_pvt->callid, wmsg.callid, sizeof(tech_pvt->callid)); 3765 3766 callid = woomera_message_header(&wmsg, "Unique-Call-Id"); 3767 if (callid) { 3768 ast_copy_string(tech_pvt->callid, callid, sizeof(wmsg.callid)); 3769 } 3770 3771 err = tech_init(tech_pvt, profile, TFLAG_INBOUND); 3772 if (err) { 3773 if (globals.debug > 2) { 3774 ast_log(LOG_ERROR, "Inbound Call Failed %s %p\n", 3775 wmsg.callid, tech_pvt); 3776 } 3777 tech_destroy(tech_pvt, inchan); 3778 } 3779 } else { 3780 ast_log(LOG_ERROR, "Cannot Create new Inbound Channel!\n"); 3781 } 3782 3783 /* It is the job of the server to timeout on this call 3784 if the call is not started */ 3785 } 3786 } 3787 if(globals.debug > 4) { 3788 if (option_verbose > 2) { 3789 ast_verbose(WOOMERA_DEBUG_PREFIX "Main Thread {%s} Select Return %d\n", profile->name, res); 3790 } 3791 } 3792 usleep(100); 3793 } 3794 3795 if (woomera_socket > -1) { 3796 int err; 3797 err = woomera_printf(profile, woomera_socket, "BYE%s", WOOMERA_RECORD_SEPARATOR); 3798 if (err < 0 || woomera_message_parse(woomera_socket, 3799 &wmsg, 3800 WOOMERA_HARD_TIMEOUT, 3801 profile, 3802 &profile->event_queue 3803 ) < 0) { 3804 } 3805 woomera_close_socket(&woomera_socket); 3806 profile->woomera_socket = -1; 3807 } 3808 3809 ast_set_flag(profile, PFLAG_DISABLED); 3810 3811 ast_log(LOG_NOTICE, "Ended Woomera Thread {%s}.\n", profile->name); 3812 woomera_profile_thread_running(profile, 1, -1); 3813 return NULL; 3814 } 3815 3816 3817 /*! 3818 * \brief Create a new thread using woomera_thread_run() as the entry point. 3819 */ 3820 static void launch_woomera_thread(woomera_profile *profile) 3821 { 3822 pthread_attr_t attr; 3823 int result = 0; 3824 3825 result = pthread_attr_init(&attr); 3826 pthread_attr_setschedpolicy(&attr, SCHED_RR); 3827 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 3828 result = ast_pthread_create(&profile->thread, &attr, woomera_thread_run, profile); 3829 result = pthread_attr_destroy(&attr); 3830 } 3831 3832 3833 /*! 3834 * \brief Create a new thread using tech_monitor_thread() as the entry point. 3835 */ 3836 static int launch_tech_thread(private_object *tech_pvt) 3837 { 3838 pthread_attr_t attr; 3839 int result = 0; 3840 3841 if (globals.debug > 2) { 3842 if (option_verbose > 2) { 3843 ast_verbose(WOOMERA_DEBUG_PREFIX "Tech Thread entry\n"); 3844 } 3845 } 3846 3847 if (ast_test_flag(tech_pvt, TFLAG_TECHHANGUP)) { 3848 /* Sanity check should never happen */ 3849 ast_log(LOG_NOTICE,"Tech Thread failed call already hangup!\n"); 3850 return -1; 3851 } 3852 3853 result = pthread_attr_init(&attr); 3854 pthread_attr_setschedpolicy(&attr, SCHED_RR); 3855 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 3856 ast_set_flag(tech_pvt, TFLAG_INTHREAD); 3857 result = ast_pthread_create(&tech_pvt->thread, &attr, tech_monitor_thread, tech_pvt); 3858 if (result) { 3859 ast_clear_flag(tech_pvt, TFLAG_INTHREAD); 3860 ast_log(LOG_ERROR, "Failed to launch tech thread %s\n", 3861 strerror(errno)); 3862 } 3863 pthread_attr_destroy(&attr); 3864 3865 return result; 3866 } 3867 3868 3869 /*! 3870 * \brief Apply gain settings for a profile. 3871 */ 3872 static void woomera_config_gain(woomera_profile *profile, float gain_val, int rx) 3873 { 3874 int j; 3875 int k; 3876 float linear_gain = pow(10.0, gain_val / 20.0); 3877 unsigned char *gain; 3878 3879 if (profile->coding == AST_FORMAT_SLINEAR){ 3880 ast_log(LOG_WARNING, "Coding not specified, %s value ignored\n", (rx)? "rxgain":"txgain"); 3881 return; 3882 } 3883 3884 if (gain_val == 0) { 3885 goto woomera_config_gain_skip; 3886 } 3887 3888 if (rx) { 3889 gain = profile->rxgain; 3890 } else { 3891 gain = profile->txgain; 3892 } 3893 3894 switch (profile->coding) { 3895 3896 case AST_FORMAT_ALAW: 3897 for (j = 0; j < 256; j++) { 3898 if (gain_val) { 3899 k = (int) (((float) alaw_to_linear(j)) * linear_gain); 3900 if (k > 32767) k = 32767; 3901 if (k < -32767) k = -32767; 3902 gain[j] = linear_to_alaw(k); 3903 } else { 3904 gain[j] = j; 3905 } 3906 } 3907 break; 3908 case AST_FORMAT_ULAW: 3909 for (j = 0; j < 256; j++) { 3910 if (gain_val) { 3911 k = (int) (((float) ulaw_to_linear(j)) * linear_gain); 3912 if (k > 32767) k = 32767; 3913 if (k < -32767) k = -32767; 3914 gain[j] = linear_to_ulaw(k); 3915 } else { 3916 gain[j] = j; 3917 } 3918 } 3919 break; 3920 } 3921 3922 woomera_config_gain_skip: 3923 3924 if (rx) { 3925 profile->rxgain_val=gain_val; 3926 } else { 3927 profile->txgain_val=gain_val; 3928 } 3929 } 3930 3931 3932 /*! 3933 * \brief Delete a woomera profile. 3934 */ 3935 static void destroy_woomera_profile(woomera_profile *profile) 3936 { 3937 int i; 3938 if (profile && ast_test_flag(profile, PFLAG_DYNAMIC)) { 3939 for ( i = 0; i <= WOOMERA_MAX_TRUNKGROUPS; i++) { 3940 if (profile->tg_context[i] != NULL) { 3941 ast_free(profile->tg_context[i]); 3942 } 3943 if (profile->tg_language[i] != NULL) { 3944 ast_free(profile->tg_language[i]); 3945 } 3946 } 3947 ast_mutex_destroy(&profile->iolock); 3948 ast_mutex_destroy(&profile->call_count_lock); 3949 ast_mutex_destroy(&profile->event_queue.lock); 3950 ast_free(profile); 3951 } 3952 } 3953 3954 3955 /*! 3956 * \brief Copy a woomera profile. 3957 */ 3958 static woomera_profile *clone_woomera_profile(woomera_profile *new_profile, 3959 woomera_profile *default_profile) 3960 { 3961 memcpy(new_profile, default_profile, sizeof(woomera_profile)); 3962 memset(new_profile->tg_context, 0, sizeof(new_profile->tg_context)); 3963 memset(new_profile->tg_language, 0, sizeof(new_profile->tg_language)); 3964 return new_profile; 3965 } 3966 3967 3968 /*! 3969 * \brief Create a new woomera profile. 3970 */ 3971 static woomera_profile *create_woomera_profile(woomera_profile *default_profile) 3972 { 3973 woomera_profile *profile; 3974 3975 if((profile = ast_malloc(sizeof(woomera_profile)))) { 3976 clone_woomera_profile(profile, default_profile); 3977 ast_mutex_init(&profile->iolock); 3978 ast_mutex_init(&profile->call_count_lock); 3979 ast_mutex_init(&profile->event_queue.lock); 3980 ast_set_flag(profile, PFLAG_DYNAMIC); 3981 } 3982 return profile; 3983 } 3984 3985 3986 /*! 3987 * \brief Load the woomera.conf file. 3988 */ 3989 static int config_woomera(void) 3990 { 3991 struct ast_config *cfg; 3992 #if defined (AST16) 3993 struct ast_flags config_flags = {0}; 3994 #endif 3995 char *entry; 3996 struct ast_variable *v; 3997 woomera_profile *profile; 3998 int default_context_set = 0; 3999 int count = 0; 4000 4001 memset(&default_profile, 0, sizeof(default_profile)); 4002 4003 #if defined (AST_JB) 4004 memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf)); 4005 #endif 4006 4007 default_profile.coding = 0; 4008 4009 #if defined (AST16) 4010 if ((cfg = ast_config_load(configfile, config_flags))) { 4011 #else 4012 if ((cfg = ast_config_load(configfile))) { 4013 #endif 4014 for (entry = ast_category_browse(cfg, NULL); entry != NULL; entry = ast_category_browse(cfg, entry)) { 4015 if (strcmp(entry, "settings") == 0) { 4016 4017 for (v = ast_variable_browse(cfg, entry); v ; v = v->next) { 4018 if (!strcmp(v->name, "debug")) { 4019 globals.debug = atoi(v->value); 4020 } else if (!strcmp(v->name, "more_threads")) { 4021 globals.more_threads = ast_true(v->value); 4022 } 4023 #if defined (AST_JB) 4024 if (ast_jb_read_conf(&global_jbconf, v->name, v->value) == 0) { 4025 ast_log(LOG_NOTICE, "Woomera AST JB Opt %s = %s \n", 4026 v->name,v->value); 4027 continue; 4028 } 4029 #endif 4030 } 4031 4032 } else if (strcmp(entry, "applications") == 0) { 4033 for (v = ast_variable_browse(cfg, entry); v ; v = v->next) { 4034 if (!strcasecmp(v->name, "woomeraplayback")) { 4035 capabilities.woomeraplayback = atoi(v->value); 4036 } else if (!strcasecmp(v->name, "woomerabackground")) { 4037 capabilities.woomerabackground = ast_true(v->value); 4038 } else if (!strcasecmp(v->name, "woomerarecord")) { 4039 capabilities.woomerarecord = ast_true(v->value); 4040 } else if (!strcasecmp(v->name, "woomeraringback")) { 4041 capabilities.woomeraringback = ast_true(v->value); 4042 } 4043 } 4044 4045 } else { 4046 int new = 0; 4047 float gain; 4048 count++; 4049 if (!strcmp(entry, "default")) { 4050 profile = &default_profile; 4051 } else { 4052 if ((profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, entry))) { 4053 clone_woomera_profile(profile, &default_profile); 4054 } else { 4055 if ((profile = create_woomera_profile(&default_profile))) { 4056 new = 1; 4057 } else { 4058 ast_log(LOG_ERROR, "Memory Error!\n"); 4059 } 4060 } 4061 } 4062 strncpy(profile->name, entry, sizeof(profile->name) - 1); 4063 profile->coding = AST_FORMAT_SLINEAR; 4064 profile->send_dtmf_enable = 1; 4065 4066 /*default is inbound and outbound enabled */ 4067 ast_set_flag(profile, PFLAG_INBOUND | PFLAG_OUTBOUND); 4068 for (v = ast_variable_browse(cfg, entry); v ; v = v->next) { 4069 if (!strcmp(v->name, "audio_ip")) { 4070 strncpy(profile->audio_ip, v->value, sizeof(profile->audio_ip) - 1); 4071 } else if (!strcmp(v->name, "host")) { 4072 strncpy(profile->woomera_host, v->value, sizeof(profile->woomera_host) - 1); 4073 } else if (!strcmp(v->name, "max_calls")) { 4074 int max = atoi(v->value); 4075 if (max > 0) { 4076 profile->max_calls = max; 4077 } 4078 } else if (!strcmp(v->name, "port")) { 4079 profile->woomera_port = atoi(v->value); 4080 } else if (!strcmp(v->name, "disabled")) { 4081 ast_set2_flag(profile, ast_true(v->value), PFLAG_DISABLED); 4082 } else if (!strcmp(v->name, "inbound")) { 4083 if (ast_false(v->value)) { 4084 ast_clear_flag(profile, PFLAG_INBOUND); 4085 } 4086 } else if (!strcmp(v->name, "outbound")) { 4087 if (ast_false(v->value)) { 4088 ast_clear_flag(profile, PFLAG_OUTBOUND); 4089 } 4090 } else if (!strcmp(v->name, "context")) { 4091 if(!default_context_set){ 4092 default_context_set = 1; 4093 strncpy(profile->default_context, v->value, sizeof(profile->default_context) - 1); 4094 } 4095 strncpy(profile->context, v->value, sizeof(profile->context) - 1); 4096 } else if (!strcmp(v->name, "default_context")) { 4097 default_context_set = 1; 4098 strncpy(profile->default_context, v->value, sizeof(profile->default_context) - 1); 4099 } else if (!strcmp(v->name, "language")) { 4100 strncpy(profile->language, v->value, sizeof(profile->language) - 1); 4101 } else if (!strcmp(v->name, "group")) { 4102 int group_num = atoi(v->value); 4103 if (group_num < 0) { 4104 ast_log(LOG_ERROR, "Invalid group:%d (less than zero) - ignoring\n", group_num); 4105 } else if (group_num > WOOMERA_MAX_TRUNKGROUPS) { 4106 ast_log(LOG_ERROR, "Invalid trunkgroup:%d (exceeds max:%d) -ignoring\n", group_num, WOOMERA_MAX_TRUNKGROUPS); 4107 } else { 4108 if (profile->tg_context[group_num] != NULL) { 4109 ast_free(profile->tg_context[group_num]); 4110 } 4111 profile->tg_context[group_num] = strdup(profile->context); 4112 4113 if (profile->tg_language[group_num] != NULL) { 4114 ast_free(profile->tg_language[group_num]); 4115 } 4116 if (strlen(profile->language)){ 4117 profile->tg_language[group_num] = strdup(profile->language); 4118 } 4119 } 4120 4121 } else if (!strcmp(v->name, "dtmf_enable")) { 4122 profile->dtmf_enable = atoi(v->value); 4123 } else if (!strcmp(v->name, "send_dtmf")) { 4124 profile->send_dtmf_enable = atoi(v->value); 4125 } else if (!strcmp(v->name, "rtp_enable")) { 4126 profile->rtp_enable = atoi(v->value); 4127 } else if (!strcmp(v->name, "vrtp_enable")) { 4128 profile->vrtp_enable = atoi(v->value); 4129 } else if (!strcmp(v->name, "bridge_enable")) { 4130 profile->bridge_enable = atoi(v->value); 4131 } else if (!strcmp(v->name, "fax_detect")) { 4132 profile->faxdetect = atoi(v->value); 4133 ast_log(LOG_NOTICE, "Profile {%s} Fax Detect %s %p \n", 4134 entry, profile->faxdetect?"Enabled":"Disabled", profile); 4135 4136 } else if (!strcmp(v->name, "jb_enable")) { 4137 profile->jb_enable = atoi(v->value); 4138 ast_log(LOG_NOTICE, "Profile {%s} Jitter Buffer %s %p \n", 4139 entry, profile->jb_enable ? "Enabled" : "Disabled", profile); 4140 4141 } else if (!strcmp(v->name, "jbenable")) { 4142 profile->jb_enable = atoi(v->value); 4143 ast_log(LOG_NOTICE, "Profile {%s} Jitter Buffer %s %p\n", 4144 entry, profile->jb_enable ? "Enabled" : "Disabled", profile); 4145 4146 } else if (!strcmp(v->name, "progress_enable")) { 4147 profile->progress_enable = atoi(v->value); 4148 4149 } else if (!strcmp(v->name, "coding")) { 4150 if (strcasecmp(v->value, "alaw") == 0) { 4151 profile->coding = AST_FORMAT_ALAW; 4152 } 4153 else if (strcasecmp(v->value, "pcma") == 0) { 4154 profile->coding = AST_FORMAT_ALAW; 4155 } 4156 else if (strcasecmp(v->value, "ulaw") == 0) { 4157 profile->coding = AST_FORMAT_ULAW; 4158 } 4159 else if (strcasecmp(v->value, "pcmu") == 0) { 4160 profile->coding = AST_FORMAT_ULAW; 4161 } 4162 4163 } else if (!strcmp(v->name, "videocoding")) { 4164 if (strcasecmp(v->value, "h263") == 0) { 4165 profile->videocoding = AST_FORMAT_H263; 4166 } 4167 else if (strcasecmp(v->value, "mpeg4") == 0) { 4168 profile->videocoding = AST_FORMAT_MP4_VIDEO; 4169 } 4170 4171 } else if (!strcmp(v->name, "woomera_udp_seq")) { 4172 int udp_seq = atoi(v->value); 4173 if (udp_seq > 0) { 4174 profile->udp_seq = 1; 4175 } 4176 4177 } else if (!strcmp(v->name, "base_media_port")) { 4178 int base_port = atoi(v->value); 4179 if (base_port > 0) { 4180 woomera_base_media_port = base_port; 4181 woomera_max_media_port = woomera_base_media_port + WOOMERA_MAX_MEDIA_PORTS; 4182 } 4183 4184 } else if (!strcmp(v->name, "max_media_ports")) { 4185 int max_ports = atoi(v->value); 4186 if (max_ports > 0 && max_ports > WOOMERA_MAX_MEDIA_PORTS) { 4187 woomera_max_media_port = woomera_base_media_port + max_ports; 4188 } 4189 4190 } else if (!strcmp(v->name, "rxgain") && profile->coding) { 4191 if (sscanf(v->value, "%f", &gain) != 1) { 4192 ast_log(LOG_NOTICE, "Invalid rxgain: %s\n", v->value); 4193 } else { 4194 woomera_config_gain(profile,gain, 1); 4195 } 4196 } else if (!strcmp(v->name, "txgain") && profile->coding) { 4197 if (sscanf(v->value, "%f", &gain) != 1) { 4198 ast_log(LOG_NOTICE, "Invalid txgain: %s\n", v->value); 4199 } else { 4200 woomera_config_gain(profile, gain, 0); 4201 } 4202 } 4203 } 4204 ASTOBJ_CONTAINER_LINK(&woomera_profile_list, profile); 4205 } 4206 } 4207 ast_config_destroy(cfg); 4208 } else { 4209 return 0; 4210 } 4211 4212 return count; 4213 4214 } 4215 4216 4217 /*! 4218 * \brief Create a raw media socket. 4219 */ 4220 static int create_udp_socket(char *ip, int port, struct sockaddr_in *sockaddr, int client) 4221 { 4222 int rc, sd = -1; 4223 struct sockaddr_in servAddr, *addr, cliAddr; 4224 struct hostent hps, *hp; 4225 struct hostent *result; 4226 char buf[512]; 4227 int err = 0; 4228 4229 memset(&hps, 0, sizeof(hps)); 4230 hp = &hps; 4231 4232 if(sockaddr) { 4233 addr = sockaddr; 4234 } else { 4235 addr = &servAddr; 4236 } 4237 4238 if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) > -1) { 4239 4240 gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err); 4241 if (result) { 4242 4243 addr->sin_family = hp->h_addrtype; 4244 memcpy((char *) &addr->sin_addr.s_addr, hp->h_addr_list[0], hp->h_length); 4245 addr->sin_port = htons(port); 4246 4247 if (globals.debug > 4) { 4248 ast_log(LOG_NOTICE, "MEDIA udp IP=%s:%d\n", ast_inet_ntoa(addr->sin_addr), port); 4249 } 4250 4251 if (client) { 4252 cliAddr.sin_family = AF_INET; 4253 cliAddr.sin_addr.s_addr = htonl(INADDR_ANY); 4254 cliAddr.sin_port = htons(0); 4255 rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr)); 4256 } else { 4257 rc = bind(sd, (struct sockaddr *) addr, sizeof(cliAddr)); 4258 } 4259 if (rc < 0) { 4260 if (globals.debug > 4) { 4261 ast_log(LOG_ERROR, 4262 "Failed to bind to udp socket %s/%i %s\n", 4263 ip, port, strerror(errno)); 4264 } 4265 4266 woomera_close_socket(&sd); 4267 4268 } else if (globals.debug > 5) { 4269 ast_log(LOG_NOTICE, "Socket Binded %s to %s/%d\n", 4270 client ? "client" : "server", ip, port); 4271 } 4272 4273 } else { 4274 ast_log(LOG_ERROR, 4275 "Error opening udp: gethostbyname failed %s/%i %s\n", 4276 ip, port, strerror(errno)); 4277 4278 woomera_close_socket(&sd); 4279 } 4280 } else { 4281 ast_log(LOG_ERROR, 4282 "failed to create a socket! %s/%i %s\n", 4283 ip, port, strerror(errno)); 4284 } 4285 4286 return sd; 4287 } 4288 4289 /*! 4290 * \brief Create an rtp session. 4291 */ 4292 static struct ast_rtp * create_rtp(char *ip) 4293 { 4294 struct hostent hps, *hp; 4295 struct hostent *result; 4296 char buf[512]; 4297 int err = 0; 4298 struct ast_rtp *rtp = NULL; 4299 struct in_addr addr; 4300 struct sockaddr_in us; 4301 4302 memset(&hps, 0, sizeof(hps)); 4303 hp = &hps; 4304 4305 gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err); 4306 if (result) 4307 { 4308 memcpy((char *) &addr, hp->h_addr_list[0], hp->h_length); 4309 rtp = ast_rtp_new_with_bindaddr(sched, io, 1 /*rtcp*/, 0, addr); 4310 4311 if (rtp) 4312 { 4313 ast_rtp_get_us(rtp, &us); 4314 if (globals.debug > 2) { 4315 ast_log(LOG_DEBUG,"Created RTP IP=%s\n", ast_inet_ntoa(addr)); 4316 } 4317 } 4318 else 4319 { 4320 ast_log(LOG_ERROR,"Failed to create RTP IP=%s %s\n", ip, strerror(errno)); 4321 } 4322 } 4323 else 4324 { 4325 ast_log(LOG_ERROR, 4326 "Failed to get host for RTP IP=%s %s\n", 4327 ip, strerror(errno)); 4328 } 4329 4330 return rtp; 4331 } 4332 4333 4334 /*! 4335 * \brief Create a socket and connect it to the Woomera server specified in the profile. 4336 */ 4337 static int connect_woomera(int *new_socket, woomera_profile *profile, int flags) 4338 { 4339 struct sockaddr_in localAddr, remoteAddr; 4340 struct hostent *hp, *result; 4341 struct hostent ahp; 4342 int res = 0, err = 0; 4343 hp = &ahp; 4344 char buf[512]; 4345 4346 *new_socket = -1; 4347 4348 gethostbyname_r(profile->woomera_host, hp, buf, sizeof(buf), &result, &err); 4349 if (result) { 4350 remoteAddr.sin_family = hp->h_addrtype; 4351 memcpy((char *) &remoteAddr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length); 4352 remoteAddr.sin_port = htons(profile->woomera_port); 4353 do { 4354 /* create socket */ 4355 *new_socket = socket(AF_INET, SOCK_STREAM, 0); 4356 if (*new_socket < 0) { 4357 ast_log(LOG_ERROR, "Cannot open socket to %s/%d\n", profile->woomera_host, profile->woomera_port); 4358 res = 0; 4359 break; 4360 } 4361 4362 /* bind any port number */ 4363 localAddr.sin_family = AF_INET; 4364 localAddr.sin_addr.s_addr = htonl(INADDR_ANY); 4365 localAddr.sin_port = htons(0); 4366 4367 res = bind(*new_socket, (struct sockaddr *) &localAddr, sizeof(localAddr)); 4368 if (res < 0) { 4369 ast_log(LOG_ERROR, "Cannot bind to %s/%d\n", profile->woomera_host, profile->woomera_port); 4370 woomera_close_socket(new_socket); 4371 res = 0; 4372 break; 4373 } 4374 4375 /* connect to server */ 4376 res = connect(*new_socket, (struct sockaddr *) &remoteAddr, sizeof(remoteAddr)); 4377 if (res < 0) { 4378 //ast_log(LOG_ERROR, "Cannot connect to {%s} %s:%d\n", profile->name, profile->woomera_host, profile->woomera_port); 4379 res = 0; 4380 woomera_close_socket(new_socket); 4381 break; 4382 } 4383 res = 1; 4384 } while(0); 4385 4386 } else { 4387 if (globals.debug > 2) { 4388 ast_log(LOG_ERROR, "Host lookup failed for {%s} %s/%d\n", 4389 profile->name, profile->woomera_host, profile->woomera_port); 4390 } 4391 res = 0; 4392 } 4393 if (res > 0) { 4394 int flag = 1; 4395 woomera_message wmsg; 4396 memset(&wmsg,0,sizeof(wmsg)); 4397 4398 /* disable nagle's algorythm */ 4399 res = setsockopt(*new_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); 4400 4401 if (!(flags & WCFLAG_NOWAIT)) { 4402 /* kickstart the session waiting for a HELLO */ 4403 res = woomera_printf(NULL, *new_socket, "%s", WOOMERA_RECORD_SEPARATOR); 4404 if (res < 0 ) { 4405 woomera_close_socket(new_socket); 4406 return *new_socket; 4407 } 4408 4409 if ((res = woomera_message_parse(*new_socket, 4410 &wmsg, 4411 -5000, /*WOOMERA_HARD_TIMEOUT,*/ 4412 profile, 4413 NULL 4414 )) < 0) { 4415 ast_log(LOG_ERROR, "{%s} Timed out waiting for a hello from woomera!\n", profile->name); 4416 woomera_close_socket(new_socket); 4417 return *new_socket; 4418 } 4419 4420 if (res > 0 && strcasecmp(wmsg.command, "HELLO")) { 4421 ast_log(LOG_ERROR, "{%s} unexpected reply [%s] while waiting for a hello from woomera!\n", profile->name, wmsg.command); 4422 woomera_close_socket(new_socket); 4423 } else { 4424 char *audio_format, *video_format; 4425 if (globals.debug > 2) { 4426 ast_log(LOG_NOTICE, "Woomera Got HELLO on connect! %s Version %s\n", profile->name, woomera_message_header(&wmsg, "Version")); 4427 } 4428 if (!svrversion_init && woomera_message_header(&wmsg, "Version")) { 4429 svrversion_init = 1; 4430 strncpy(svrversion, 4431 woomera_message_header(&wmsg, "Version"), 4432 sizeof(svrversion)-1); 4433 } 4434 4435 audio_format = woomera_message_header(&wmsg, "Raw-Format"); 4436 if (!audio_format) { 4437 audio_format = woomera_message_header(&wmsg, "Raw-Audio-Format"); 4438 } 4439 if (!audio_format) { 4440 audio_format = woomera_message_header(&wmsg, "RTP-Audio-Format"); 4441 } 4442 4443 if (audio_format) { 4444 4445 profile->coding = AST_FORMAT_SLINEAR; 4446 4447 if (strncasecmp(audio_format, "PCM-16", 6) == 0) { 4448 profile->coding = AST_FORMAT_SLINEAR; 4449 } else if (strncasecmp(audio_format, "ULAW", 4) == 0) { 4450 profile->coding = AST_FORMAT_ULAW; 4451 } else if (strncasecmp(audio_format, "PCMU", 4) == 0) { 4452 profile->coding = AST_FORMAT_ULAW; 4453 } else if (strncasecmp(audio_format, "ALAW", 4) == 0) { 4454 profile->coding = AST_FORMAT_ALAW; 4455 } else if (strncasecmp(audio_format, "PCMA", 4) == 0) { 4456 profile->coding = AST_FORMAT_ALAW; 4457 } else { 4458 ast_log(LOG_ERROR, "Error: Invalid audio format %s\n", 4459 audio_format); 4460 } 4461 4462 if (globals.debug > 2) { 4463 ast_log(LOG_NOTICE, "Setting audio format to %s %i (p%i:u%i:a%i)\n", 4464 audio_format, profile->coding, 4465 AST_FORMAT_SLINEAR, AST_FORMAT_ULAW, AST_FORMAT_ALAW); 4466 } 4467 } 4468 4469 video_format = woomera_message_header(&wmsg, "RTP-Video-Format"); 4470 if (video_format) { 4471 profile->videocoding = AST_FORMAT_H261; 4472 if (strncasecmp(video_format, "H261", 4) == 0) { 4473 profile->videocoding = AST_FORMAT_H261; 4474 } else if (strncasecmp(video_format, "H263", 4) == 0) { 4475 profile->videocoding = AST_FORMAT_H263; 4476 } else if (strncasecmp(video_format, "H263-1998", 9) == 0) { 4477 profile->videocoding = AST_FORMAT_H263_PLUS; 4478 } else if (strncasecmp(video_format, "H264", 4) == 0) { 4479 profile->videocoding = AST_FORMAT_H264; 4480 } else if (strncasecmp(video_format, "MPV4-ES", 5) == 0) { 4481 profile->videocoding = AST_FORMAT_MP4_VIDEO; 4482 } else { 4483 ast_log(LOG_ERROR, "Error: Invalid video format %s\n", video_format); 4484 } 4485 } 4486 } 4487 } 4488 } else { 4489 /* 4490 if (globals.debug > 2) { 4491 ast_log(LOG_ERROR, "Woomera {%s} connection failed: %s/%d %s\n", 4492 profile->name, profile->woomera_host, profile->woomera_port, strerror(errno)); 4493 } 4494 */ 4495 woomera_close_socket(new_socket); 4496 } 4497 4498 return *new_socket; 4499 } 4500 4501 4502 /*! 4503 * \brief Create a thread for each profile defined in the conf file. 4504 */ 4505 static int init_woomera(void) 4506 { 4507 woomera_profile *profile; 4508 ast_mutex_lock(&lock); 4509 4510 if (!config_woomera()) { 4511 ast_mutex_unlock(&lock); 4512 return 0; 4513 } 4514 ASTOBJ_CONTAINER_TRAVERSE(&woomera_profile_list, 1, do { 4515 ASTOBJ_RDLOCK(iterator); 4516 profile = iterator; 4517 if (!ast_test_flag(profile, PFLAG_DISABLED)) { 4518 launch_woomera_thread(profile); 4519 } 4520 ASTOBJ_UNLOCK(iterator); 4521 } while(0)); 4522 4523 ast_mutex_unlock(&lock); 4524 return 1; 4525 } 4526 4527 4528 /*! 4529 * \brief Allocate and initialise a channel struct. 4530 */ 4531 static struct ast_channel *woomera_new(const char *type, 4532 int format, 4533 void *data, 4534 int *cause, 4535 woomera_profile *parent_profile) 4536 { 4537 private_object *tech_pvt; 4538 struct ast_channel *chan = NULL; 4539 char name[100]; 4540 4541 snprintf(name, sizeof(name), "%s/%s-%04x", type, (char *)data, rand() & 0xffff); 4542 4543 if (!(tech_pvt = ast_malloc(sizeof(private_object)))) { 4544 ast_log(LOG_ERROR, "Memory Error!\n"); 4545 return NULL; 4546 } 4547 memset(tech_pvt, 0, sizeof(private_object)); 4548 4549 #if defined (AST14) || defined (AST16) 4550 chan = ast_channel_alloc(0, AST_STATE_DOWN, "", "", "", "", "", 0, "%s", name); 4551 #else 4552 chan = ast_channel_alloc(1); 4553 #endif 4554 4555 if (chan) { 4556 chan->nativeformats = WFORMAT; 4557 #if !defined (AST14) && !defined (AST16) 4558 chan->type = type; 4559 snprintf(chan->name, sizeof(chan->name), "%s/%s-%04x", chan->type, (char *)data, rand() & 0xffff); 4560 #endif 4561 4562 chan->writeformat = chan->rawwriteformat = chan->readformat = WFORMAT; 4563 chan->_state = AST_STATE_DOWN; 4564 chan->_softhangup = 0; 4565 4566 tech_count++; 4567 tech_pvt->coding = WFORMAT; 4568 4569 ast_mutex_init(&tech_pvt->iolock); 4570 ast_mutex_init(&tech_pvt->event_queue.lock); 4571 tech_pvt->command_channel = -1; 4572 chan->tech_pvt = tech_pvt; 4573 chan->tech = &technology; 4574 tech_pvt->udp_socket = -1; 4575 4576 ast_clear_flag(chan, AST_FLAGS_ALL); 4577 memset(&tech_pvt->frame, 0, sizeof(tech_pvt->frame)); 4578 tech_pvt->frame.frametype = AST_FRAME_VOICE; 4579 tech_pvt->frame.subclass = WFORMAT; 4580 tech_pvt->frame.offset = AST_FRIENDLY_OFFSET; 4581 4582 tech_pvt->owner = chan; 4583 4584 chan->nativeformats = tech_pvt->coding | tech_pvt->videocoding; 4585 chan->writeformat = chan->rawwriteformat = chan->readformat = tech_pvt->coding; 4586 tech_pvt->frame.subclass = tech_pvt->coding; 4587 4588 tech_pvt->pri_cause = AST_CAUSE_NORMAL_CLEARING; 4589 4590 ast_copy_string(tech_pvt->mohinterpret, mohinterpret, sizeof(tech_pvt->mohinterpret)); 4591 ast_copy_string(tech_pvt->mohsuggest, mohsuggest, sizeof(tech_pvt->mohsuggest)); 4592 4593 ASTOBJ_CONTAINER_LINK(&private_object_list, tech_pvt); 4594 4595 ast_mutex_lock(&usecnt_lock); 4596 usecnt++; 4597 ast_mutex_unlock(&usecnt_lock); 4598 4599 } else { 4600 ast_log(LOG_ERROR, "Can't allocate a channel\n"); 4601 } 4602 4603 return chan; 4604 } 4605 4606 4607 /**************************** CHANNEL INTERFACES ******************************/ 4608 4609 4610 /*! 4611 * Channel interface. 4612 * \brief Parse 'data' a url-like destination string, allocate a channel and a private 4613 * structure and return the newly-setup channel. 4614 */ 4615 static struct ast_channel *tech_requester(const char *type, int format, void *data, int *cause) 4616 { 4617 struct ast_channel *chan = NULL; 4618 4619 if (globals.panic) { 4620 return NULL; 4621 } 4622 4623 if ((chan = woomera_new(type, format, data, cause, NULL))) { 4624 private_object *tech_pvt; 4625 4626 tech_pvt = chan->tech_pvt; 4627 4628 if (tech_pvt->owner) { 4629 tech_pvt->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING; 4630 } 4631 4632 ast_set_flag(tech_pvt, TFLAG_PBX); /* so we know we don't have to free the channel ourselves */ 4633 4634 if (globals.debug > 1 && option_verbose > 1) { 4635 if (option_verbose > 2) { 4636 ast_verbose(WOOMERA_DEBUG_PREFIX "+++REQ %s\n", chan->name); 4637 } 4638 } 4639 4640 } else { 4641 ast_log(LOG_ERROR, "Woomera: Can't allocate a channel\n"); 4642 } 4643 4644 return chan; 4645 } 4646 4647 #if defined (AST14) || defined (AST16) 4648 4649 /*! 4650 * Channel interface. 4651 */ 4652 static int tech_digit_end(struct ast_channel *ast, char digit, unsigned int duration) 4653 { 4654 return 0; 4655 } 4656 #endif 4657 4658 4659 /*! 4660 * Channel interface. 4661 * \brief Send a DTMF character. 4662 */ 4663 static int tech_send_digit(struct ast_channel *self, char digit) 4664 { 4665 private_object *tech_pvt = self->tech_pvt; 4666 4667 if ( tech_pvt->send_dtmf_enable == 0 ) { 4668 /* Returning non-zero to cause Asterisk to send the digits using 4669 * in-band tones. 4670 */ 4671 return 1; 4672 } 4673 4674 int res = 0; 4675 4676 if (globals.debug > 1 && option_verbose > 2) { 4677 if (option_verbose > 2) { 4678 ast_verbose(WOOMERA_DEBUG_PREFIX "+++DIGIT %s '%c'\n", self->name, digit); 4679 } 4680 } 4681 4682 /* Save the digits for the monitor thread to send the DTMF command. 4683 */ 4684 ast_mutex_lock(&tech_pvt->iolock); 4685 snprintf(tech_pvt->dtmfbuf + strlen(tech_pvt->dtmfbuf), sizeof(tech_pvt->dtmfbuf), "%c", digit); 4686 ast_set_flag(tech_pvt, TFLAG_DTMF); 4687 ast_mutex_unlock(&tech_pvt->iolock); 4688 4689 return res; 4690 } 4691 4692 4693 /*! 4694 * Channel interface. 4695 * \brief Initiate a call on a channel. 4696 * 'dest' has been passed telling you where to call but you may already have 4697 * that information from the requester method not sure why it sends it twice, 4698 * maybe it changed since then *shrug* You also have timeout (in ms) so you can 4699 * tell how long the caller is willing to wait for the call to be complete. 4700 */ 4701 static int tech_call(struct ast_channel *self, char *dest, int timeout) 4702 { 4703 private_object *tech_pvt = self->tech_pvt; 4704 char *workspace; 4705 char *p; 4706 char *c; 4707 4708 #if !defined (AST14) && !defined (AST16) 4709 self->type = WOOMERA_CHAN_NAME; 4710 #endif 4711 4712 self->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; 4713 4714 if (globals.panic) { 4715 goto tech_call_failed; 4716 } 4717 4718 if (globals.debug > 2) { 4719 ast_log(LOG_NOTICE, "TECH CALL %s (%s <%s>) pres=0x%02X dest=%s\n", 4720 self->name, self->cid.cid_name, 4721 self->cid.cid_num, 4722 self->cid.cid_pres, 4723 dest); 4724 } 4725 4726 if (self->cid.cid_name) { 4727 strncpy(tech_pvt->cid_name, self->cid.cid_name, sizeof(tech_pvt->cid_name)-1); 4728 } 4729 4730 if (self->cid.cid_num) { 4731 strncpy(tech_pvt->cid_num, self->cid.cid_num, sizeof(tech_pvt->cid_num)-1); 4732 } 4733 4734 tech_pvt->cid_pres = self->cid.cid_pres; 4735 4736 if (self->cid.cid_rdnis) { 4737 tech_pvt->cid_rdnis = strdup(self->cid.cid_rdnis); 4738 } 4739 4740 /* Parse out dialstring parts. 4741 * [profile/][protocol:]address 4742 */ 4743 if ((workspace = ast_strdupa(dest))) { 4744 char *addr, *profile_name, *protocol = NULL; 4745 woomera_profile *profile; 4746 int err; 4747 4748 if ((addr = strchr(workspace, ':'))) { 4749 *addr = '\0'; 4750 addr++; 4751 if ((protocol = strchr(workspace, '/'))) { 4752 profile_name = workspace; 4753 *protocol = '\0'; 4754 protocol++; 4755 } 4756 else { 4757 profile_name = "default"; 4758 protocol = workspace; 4759 } 4760 } else { 4761 profile_name = "default"; 4762 protocol = NULL; 4763 addr = workspace; 4764 } 4765 4766 if (! (profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, profile_name))) { 4767 ast_log(LOG_WARNING, "Profile %s not found, using default\n", profile_name); 4768 profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, "default"); 4769 } 4770 4771 if (!profile) { 4772 ast_log(LOG_ERROR, "Call aborted, unable to find profile: %s\n", profile_name); 4773 goto tech_call_failed; 4774 } 4775 4776 if (!ast_test_flag(profile, PFLAG_OUTBOUND)) { 4777 ast_log(LOG_ERROR, "This profile (%s) is not allowed to make outbound calls! Call Aborted!\n", profile_name); 4778 goto tech_call_failed; 4779 } 4780 4781 if (profile->max_calls) { 4782 if (profile->call_count >= profile->max_calls) { 4783 if (globals.debug > 1 && option_verbose > 2) { 4784 ast_log(LOG_ERROR, "This profile (%s) is at call limit of %d\n", 4785 profile_name, profile->max_calls); 4786 } 4787 goto tech_call_failed; 4788 } 4789 } 4790 4791 snprintf(tech_pvt->dest, sizeof(tech_pvt->dest), "%s", addr ? addr : ""); 4792 snprintf(tech_pvt->proto, sizeof(tech_pvt->proto), "%s", protocol ? protocol : ""); 4793 4794 if (globals.debug > 2) { 4795 ast_log(LOG_NOTICE, "TECH CALL: profile=%s proto=%s addr=%s audiocoding=%x videocoding=%x\n", 4796 profile_name, protocol, addr, profile->coding, profile->videocoding); 4797 } 4798 4799 tech_pvt->timeout = timeout; 4800 err = tech_init(tech_pvt, profile, TFLAG_OUTBOUND); 4801 if (err) { 4802 if (globals.debug > 2) { 4803 ast_log(LOG_ERROR, "Outbound Call Failed \n"); 4804 } 4805 goto tech_call_failed; 4806 } 4807 4808 #if 1 4809 if ((p = strrchr(self->name, '/'))) { 4810 c = p-1; 4811 if (*c == 'c' || *c == 'C') { 4812 ast_set_flag(tech_pvt, TFLAG_CONFIRM_ANSWER_ENABLED); 4813 ast_set_flag(tech_pvt, TFLAG_CONFIRM_ANSWER); 4814 } 4815 } 4816 #endif 4817 4818 woomera_send_progress(tech_pvt); 4819 } 4820 self->hangupcause = AST_CAUSE_NORMAL_CLEARING; 4821 return 0; 4822 4823 tech_call_failed: 4824 4825 if (globals.debug > 1 && option_verbose > 2) { 4826 ast_log(LOG_ERROR, "Error: Outbound Call Failed %p \n", tech_pvt); 4827 } 4828 self->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION; 4829 my_ast_softhangup(self, tech_pvt, AST_SOFTHANGUP_EXPLICIT); 4830 return -1; 4831 } 4832 4833 4834 /*! 4835 * Channel interface. 4836 * End a call on channel 'self' 4837 * Now is your chance to tear down and free the private object 4838 * from the channel it's about to be freed so you must do so now 4839 * or the object is lost. Well I guess you could tag it for reuse 4840 * or for destruction and let a monitor thread deal with it too. 4841 * during the load_module routine you have every right to start up 4842 * your own fancy schmancy bunch of threads or whatever else 4843 * you want to do. 4844 */ 4845 static int tech_hangup(struct ast_channel *self) 4846 { 4847 const char *ds; 4848 private_object *tech_pvt = self->tech_pvt; 4849 int res = 0; 4850 4851 if (globals.debug > 2) { 4852 ast_log(LOG_NOTICE, "TECH HANGUP [%s] tech_pvt=%p c=%p\n", self->name, tech_pvt, self); 4853 } 4854 4855 if (tech_pvt) { 4856 4857 ast_mutex_lock(&tech_pvt->iolock); 4858 4859 ast_set_flag(tech_pvt, TFLAG_TECHHANGUP); 4860 tech_pvt->owner = NULL; 4861 self->tech_pvt = NULL; 4862 4863 if (!self || 4864 (!(ds = pbx_builtin_getvar_helper(self, "DIALSTATUS")) && 4865 !(ds = ast_cause2str(self->hangupcause)))) { 4866 ds = "NOEXIST"; 4867 } 4868 4869 ast_copy_string(tech_pvt->ds, ds, sizeof(tech_pvt->ds)); 4870 4871 ds = pbx_builtin_getvar_helper(self, "PRI_CAUSE"); 4872 if (ds && atoi(ds)) { 4873 tech_pvt->pri_cause = atoi(ds); 4874 } else if (self->hangupcause) { 4875 tech_pvt->pri_cause = self->hangupcause; 4876 } else { 4877 tech_pvt->pri_cause = AST_CAUSE_NORMAL_CLEARING; 4878 } 4879 4880 if (globals.debug > 2) { 4881 ast_log(LOG_NOTICE, "TECH HANGUP [%s] Cause=%i HangCause=%i ds=%s\n", 4882 self->name, tech_pvt->pri_cause, self->hangupcause, ds ? ds : "N/A"); 4883 } 4884 4885 if (tech_pvt->dsp) { 4886 tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT; 4887 ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features); 4888 tech_pvt->ast_dsp = 0; 4889 } 4890 4891 if (ast_test_flag(tech_pvt, TFLAG_INTHREAD)) { 4892 ast_set_flag(tech_pvt, TFLAG_ABORT); 4893 ast_set_flag(tech_pvt, TFLAG_DESTROY); 4894 4895 if (globals.debug > 2) { 4896 ast_log(LOG_NOTICE, "TECH HANGUP IN THREAD! tpvt=%p\n", 4897 tech_pvt); 4898 } 4899 4900 self->tech_pvt = NULL; 4901 ast_mutex_unlock(&tech_pvt->iolock); 4902 4903 } else { 4904 int ast_hangup = 0; 4905 4906 if (globals.debug > 4) { 4907 ast_log(LOG_NOTICE, "TECH HANGUP: Destroying tech not in thread! Callid=%s tech_pvt=%p Dir=%s\n", 4908 tech_pvt->callid, tech_pvt, 4909 ast_test_flag(tech_pvt, TFLAG_OUTBOUND) ? "OUT" : "IN" ); 4910 } 4911 4912 if (ast_test_flag(tech_pvt, TFLAG_AST_HANGUP)) { 4913 ast_hangup = 1; 4914 } 4915 self->tech_pvt = NULL; 4916 ast_mutex_unlock(&tech_pvt->iolock); 4917 4918 if (!ast_test_flag(tech_pvt, TFLAG_DESTROY)) { 4919 4920 if (ast_hangup && tech_pvt->profile) { 4921 ast_mutex_lock(&tech_pvt->profile->call_count_lock); 4922 tech_pvt->profile->call_ast_hungup--; 4923 ast_mutex_unlock(&tech_pvt->profile->call_count_lock); 4924 } 4925 4926 tech_destroy(tech_pvt,NULL); 4927 if (globals.debug > 2) { 4928 ast_log(LOG_NOTICE, "TECH HANGUP NOT IN THREAD!\n"); 4929 } 4930 } else { 4931 ast_log(LOG_ERROR, "Tech Hangup -> Device already destroyed. Should not happend! \n"); 4932 } 4933 } 4934 } else { 4935 if (globals.debug > 2) { 4936 ast_log(LOG_NOTICE, "ERROR: NO TECH ON TECH HANGUP!\n"); 4937 } 4938 } 4939 4940 self->tech_pvt = NULL; 4941 4942 return res; 4943 } 4944 4945 4946 /*! 4947 * Channel interface. 4948 * Answer a call on a channel. 4949 * If being 'answered' means anything special to your channel 4950 * now is your chance to do it! 4951 */ 4952 static int tech_answer(struct ast_channel *self) 4953 { 4954 private_object *tech_pvt; 4955 int res = 0; 4956 4957 tech_pvt = self->tech_pvt; 4958 if (!tech_pvt) { 4959 return -1; 4960 } 4961 4962 ast_mutex_lock(&tech_pvt->iolock); 4963 4964 if (globals.debug > 1 && option_verbose > 1) { 4965 if (option_verbose > 2) { 4966 ast_verbose(WOOMERA_DEBUG_PREFIX "+++ANSWER %s\n", self->name); 4967 } 4968 } 4969 4970 if (!ast_test_flag(tech_pvt, TFLAG_OUTBOUND)) { 4971 /* Only answer the inbound calls */ 4972 ast_set_flag(tech_pvt, TFLAG_ANSWER); 4973 } else { 4974 ast_log(LOG_ERROR, "Warning: AST trying to Answer OUTBOUND Call!\n"); 4975 } 4976 4977 ast_set_flag(tech_pvt, TFLAG_UP); 4978 ast_setstate(self, AST_STATE_UP); 4979 4980 ast_mutex_unlock(&tech_pvt->iolock); 4981 4982 return res; 4983 } 4984 4985 /*! 4986 * Try to route faxes to the 'fax' extension. 4987 */ 4988 static void handle_fax(private_object *tech_pvt) 4989 { 4990 struct ast_channel *owner; 4991 4992 owner = tech_pvt->owner; 4993 4994 if (tech_pvt->owner) { 4995 ast_verbose(WOOMERA_DEBUG_PREFIX "FAX TONE %s\n", tech_pvt->callid); 4996 4997 if (!tech_pvt->faxhandled) { 4998 tech_pvt->faxhandled++; 4999 if (strcmp(owner->exten, "fax")) { 5000 #if defined (AST14) || defined (AST16) 5001 const char *target_context = S_OR(owner->macrocontext, owner->context); 5002 #else 5003 const char *target_context = ast_strlen_zero(owner->macrocontext) ? owner->context : owner->macrocontext; 5004 #endif 5005 if (ast_exists_extension(owner, target_context, "fax", 1, owner->cid.cid_num)) { 5006 if (option_verbose > 2) { 5007 ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", owner->name); 5008 } 5009 5010 pbx_builtin_setvar_helper(owner, "FAXEXTEN", owner->exten); 5011 if (ast_async_goto(owner, target_context, "fax", 1)) 5012 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", owner->name, target_context); 5013 } else { 5014 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); 5015 } 5016 } 5017 } 5018 } 5019 } 5020 5021 5022 /*! 5023 * Channel interface. 5024 * \brief Read an audio frame from a channel. 5025 * You need to read data from your channel and convert/transfer the 5026 * data into a newly allocated struct ast_frame object. 5027 */ 5028 static struct ast_frame *tech_read(struct ast_channel *self) 5029 { 5030 private_object *tech_pvt = self->tech_pvt; 5031 int res = 0; 5032 struct ast_frame *f,*rf; 5033 5034 rf = NULL; 5035 5036 if (!tech_pvt || globals.panic || ast_test_flag(tech_pvt, TFLAG_ABORT)) 5037 { 5038 return NULL; 5039 } 5040 5041 if (tech_pvt->rtp_enable) 5042 { 5043 switch(self->fdno) { 5044 case 0: 5045 rf = ast_rtp_read(tech_pvt->rtp); /* RTP Audio */ 5046 break; 5047 5048 case 1: 5049 rf = ast_rtp_read(tech_pvt->vrtp); /* RTP Video */ 5050 if (globals.debug > 4) { 5051 if (option_verbose > 4) { 5052 ast_verbose(WOOMERA_DEBUG_PREFIX "VIDEO READ %s \n", self->name); 5053 } 5054 } 5055 break; 5056 5057 default: 5058 ast_verbose(WOOMERA_DEBUG_PREFIX "tech_read() %s fdno=%d \n", self->name, self->fdno); 5059 break; 5060 } 5061 5062 if (rf) 5063 { 5064 /* Don't forward RFC2833 */ 5065 if (rf->frametype == AST_FRAME_DTMF_BEGIN || rf->frametype == AST_FRAME_DTMF_END) { 5066 ast_log(LOG_DTMF, " Ignoring DTMF (%c) in RTP frame \n", rf->subclass); 5067 tech_pvt->frame.frametype = AST_FRAME_NULL; 5068 } else { 5069 tech_pvt->frame.frametype = rf->frametype; 5070 tech_pvt->frame.subclass = rf->subclass; 5071 tech_pvt->frame.offset = rf->offset; 5072 tech_pvt->frame.datalen = rf->datalen; 5073 tech_pvt->frame.samples = rf->samples; 5074 tech_pvt->frame.data = rf->data; 5075 } 5076 } 5077 } 5078 else 5079 { 5080 5081 tech_read_again: 5082 5083 if (!tech_pvt || globals.panic || ast_test_flag(tech_pvt, TFLAG_ABORT)) { 5084 return NULL; 5085 } 5086 5087 res = waitfor_socket(tech_pvt->udp_socket, 1000); 5088 5089 if (res < 1) { 5090 return NULL; 5091 5092 } else if (res == 0) { 5093 goto tech_read_again; 5094 } 5095 5096 res = read(tech_pvt->udp_socket, tech_pvt->fdata + AST_FRIENDLY_OFFSET, FRAME_LEN); 5097 5098 if (res < 1) { 5099 return NULL; 5100 } 5101 5102 /* Used for adding sequence numbers to udp packets. 5103 should only be used for debugging */ 5104 if (tech_pvt->profile->udp_seq){ 5105 char *rxdata = (char*)(tech_pvt->fdata + AST_FRIENDLY_OFFSET); 5106 res -= 4; 5107 5108 if (tech_pvt->rx_udp_seq == 0) { 5109 tech_pvt->rx_udp_seq = *((unsigned int*)(&rxdata[res])); 5110 if (globals.debug > 2) { 5111 ast_log(LOG_NOTICE, "%s: Starting Rx Sequence %i Len=%i!\n", self->name,tech_pvt->rx_udp_seq, res); 5112 } 5113 } else { 5114 tech_pvt->rx_udp_seq++; 5115 if (tech_pvt->rx_udp_seq != *((unsigned int*)(&rxdata[res]))) { 5116 ast_log(LOG_NOTICE, "%s: Error: Missing Rx Sequence Expect %i Received %i!\n", 5117 self->name,tech_pvt->rx_udp_seq, *((unsigned int*)(&rxdata[res]))); 5118 tech_pvt->rx_udp_seq = *((unsigned int*)(&rxdata[res])); 5119 } 5120 } 5121 } 5122 5123 /* Used for checking incoming udp stream. Should only be used for debugging. */ 5124 if (tech_pvt->profile->rx_sync_check_opt) { 5125 int i; 5126 unsigned char *data = (unsigned char*)(tech_pvt->fdata + AST_FRIENDLY_OFFSET); 5127 for (i = 0; i < res; i++) { 5128 if (tech_pvt->sync_r == 0) { 5129 if (data[i] == 0x01) { 5130 if (globals.debug > 2) { 5131 ast_log(LOG_NOTICE, "%s: R Sync Acheived Offset=%i\n", self->name,i); 5132 } 5133 tech_pvt->sync_r = 1; 5134 tech_pvt->sync_data_r = data[i]; 5135 } 5136 } else { 5137 tech_pvt->sync_data_r++; 5138 if (tech_pvt->sync_data_r != data[i]) { 5139 ast_log(LOG_NOTICE, "%s: R Sync Lost: Expected %i Got %i Offset=%i\n", 5140 self->name, tech_pvt->sync_data_r, data[i], i); 5141 tech_pvt->sync_r = 0; 5142 } 5143 } 5144 } 5145 } 5146 5147 tech_pvt->frame.frametype = AST_FRAME_VOICE; 5148 tech_pvt->frame.subclass = tech_pvt->coding; 5149 tech_pvt->frame.offset = AST_FRIENDLY_OFFSET; 5150 tech_pvt->frame.datalen = res; 5151 tech_pvt->frame.samples = res; 5152 tech_pvt->frame.woo_ast_data_ptr = tech_pvt->fdata + AST_FRIENDLY_OFFSET; 5153 } 5154 5155 f = &tech_pvt->frame; 5156 5157 /* 5158 * adjust rx levels on raw voice frames. 5159 */ 5160 if ((tech_pvt->frame.frametype == AST_FRAME_VOICE) && tech_pvt->profile->rxgain_val) { 5161 int i; 5162 unsigned char *data = tech_pvt->frame.woo_ast_data_ptr; 5163 for (i = 0; i < tech_pvt->frame.datalen; i++ ) { 5164 data[i] = tech_pvt->profile->rxgain[data[i]]; 5165 } 5166 } 5167 5168 if (tech_pvt->owner && (tech_pvt->faxdetect || tech_pvt->ast_dsp)) { 5169 f = ast_dsp_process(tech_pvt->owner, tech_pvt->dsp, &tech_pvt->frame); 5170 if (f && f->frametype == AST_FRAME_DTMF) { 5171 int answer = 0; 5172 5173 if(ast_test_flag(tech_pvt, TFLAG_CONFIRM_ANSWER_ENABLED)) { 5174 ast_mutex_lock(&tech_pvt->iolock); 5175 if(ast_test_flag(tech_pvt, TFLAG_CONFIRM_ANSWER)){ 5176 ast_clear_flag(tech_pvt, TFLAG_CONFIRM_ANSWER); 5177 if(ast_test_flag(tech_pvt, TFLAG_ANSWER_RECEIVED)) { 5178 answer = 1; 5179 } 5180 } 5181 ast_mutex_unlock(&tech_pvt->iolock); 5182 if (answer){ 5183 struct ast_frame answer_frame = {AST_FRAME_CONTROL, AST_CONTROL_ANSWER}; 5184 struct ast_channel *owner = tech_get_owner(tech_pvt); 5185 ast_log(LOG_DEBUG, "Confirm answer on %s!\n", self->name); 5186 5187 if (owner) { 5188 ast_setstate(owner, AST_STATE_UP); 5189 ast_queue_frame(owner, &answer_frame); 5190 ast_set_flag(tech_pvt, TFLAG_UP); 5191 5192 ast_mutex_lock(&tech_pvt->profile->call_count_lock); 5193 tech_pvt->profile->call_ok++; 5194 ast_mutex_unlock(&tech_pvt->profile->call_count_lock); 5195 } else { 5196 ast_copy_string(tech_pvt->ds, "REQUESTED_CHAN_UNAVAIL", sizeof(tech_pvt->ds)); 5197 tech_pvt->pri_cause = 44; 5198 ast_set_flag(tech_pvt, TFLAG_ABORT); 5199 } 5200 } 5201 } 5202 if (f->subclass == 'f' && tech_pvt->faxdetect) { 5203 handle_fax(tech_pvt); 5204 } 5205 if (answer == 0 && globals.debug > 2) { 5206 ast_log(LOG_NOTICE, "%s: Detected inband DTMF digit: %c\n", 5207 self->name, f->subclass); 5208 } 5209 } 5210 //woomera_tx2ast_frm(tech_pvt, tech_pvt->frame.data, tech_pvt->frame.datalen); 5211 } 5212 5213 if (globals.debug > 4) { 5214 if (option_verbose > 2) { 5215 ast_verbose(WOOMERA_DEBUG_PREFIX "+++READ %s %d coding %d\n", self->name, res, 5216 tech_pvt->coding); 5217 } 5218 } 5219 5220 return f; 5221 } 5222 5223 5224 /*! 5225 * Channel interface. 5226 * \brief Write an audio frame to a channel. 5227 * Yep, this is the opposite of tech_read, you need to examine 5228 * a frame and transfer the data to your technology's audio stream. 5229 * You do not have any responsibility to destroy this frame and you should 5230 * consider it to be read-only. 5231 */ 5232 static int tech_write(struct ast_channel *self, struct ast_frame *frame) 5233 { 5234 private_object *tech_pvt = self->tech_pvt; 5235 int res = 0, i = 0; 5236 5237 if (!tech_pvt || globals.panic || ast_test_flag(tech_pvt, TFLAG_ABORT)) { 5238 return -1; 5239 } 5240 5241 /* Used for debugging only never in production */ 5242 if (tech_pvt->profile->tx_sync_check_opt) { 5243 unsigned char *data = frame->woo_ast_data_ptr; 5244 for (i = 0; i < frame->datalen; i++) { 5245 if (tech_pvt->sync_w == 0) { 5246 if (data[i] == 0x01 && data[i+1] == 0x02) { 5247 ast_log(LOG_NOTICE, "%s: W Sync Acheived Offset=%i\n", self->name,i); 5248 tech_pvt->sync_w = 1; 5249 tech_pvt->sync_data_w = data[i]; 5250 } 5251 } else if (tech_pvt->sync_w == 1) { 5252 tech_pvt->sync_data_w++; 5253 if (tech_pvt->sync_data_w != data[i]) { 5254 ast_log(LOG_NOTICE, "%s: W Sync Lost: Expected %i Got %i Offset=%i\n", 5255 self->name, 5256 tech_pvt->sync_data_w, data[i], i); 5257 tech_pvt->sync_w = 0; 5258 if (0) { 5259 int x; 5260 ast_log(LOG_NOTICE, "%s: PRINTING FRAME Len=%i\n", 5261 self->name,frame->datalen); 5262 for (x = 0; x < frame->datalen; x++) { 5263 ast_log(LOG_NOTICE, "%s: Off=%i Data %i\n", 5264 self->name, x, data[x]); 5265 } 5266 } 5267 } 5268 } 5269 } 5270 5271 /* Used for debugging only never in production */ 5272 } else if (tech_pvt->profile->tx_sync_gen_opt) { 5273 unsigned char *data = frame->woo_ast_data_ptr; 5274 int x; 5275 for (x = 0; x < frame->datalen; x++) { 5276 data[x] = ++tech_pvt->sync_data_w; 5277 } 5278 } 5279 5280 if (ast_test_flag(tech_pvt, TFLAG_MEDIA) && frame->datalen) { 5281 if (frame->frametype == AST_FRAME_VOICE) { 5282 5283 if (tech_pvt->profile->txgain_val) { 5284 unsigned char *data = frame->woo_ast_data_ptr; 5285 for (i = 0; i < frame->datalen; i++) { 5286 data[i] = tech_pvt->profile->txgain[data[i]]; 5287 } 5288 } 5289 5290 if (tech_pvt->profile->udp_seq){ 5291 unsigned char *txdata = frame->woo_ast_data_ptr; 5292 tech_pvt->tx_udp_seq++; 5293 *((unsigned int*)&txdata[frame->datalen]) = tech_pvt->tx_udp_seq; 5294 frame->datalen += 4; 5295 } 5296 5297 if (tech_pvt->rtp_enable){ 5298 i = ast_rtp_write(tech_pvt->rtp, frame); 5299 } 5300 else { 5301 i = sendto(tech_pvt->udp_socket, frame->woo_ast_data_ptr, frame->datalen, 0, 5302 (struct sockaddr *) &tech_pvt->udpwrite, sizeof(tech_pvt->udpwrite)); 5303 } 5304 5305 if (i < 0) { 5306 return -1; 5307 } 5308 if (globals.debug > 4) { 5309 if (option_verbose > 4) { 5310 ast_verbose(WOOMERA_DEBUG_PREFIX "+++AUDIO WRITE %s %d\n", self->name, i); 5311 } 5312 } 5313 5314 5315 } else { 5316 ast_log(LOG_NOTICE, "Invalid frame type %d sent\n", frame->frametype); 5317 } 5318 } 5319 5320 return res; 5321 } 5322 5323 5324 /*! 5325 * Channel interface. 5326 * \brief Write a video frame to my channel. 5327 */ 5328 static int tech_write_video(struct ast_channel *self, struct ast_frame *frame) 5329 { 5330 private_object *tech_pvt; 5331 int res = 0; 5332 5333 tech_pvt = self->tech_pvt; 5334 if (tech_pvt->vrtp) 5335 { 5336 res = ast_rtp_write(tech_pvt->vrtp, frame); 5337 } 5338 5339 if (globals.debug > 4) { 5340 if (option_verbose > 4) { 5341 ast_verbose(WOOMERA_DEBUG_PREFIX "+++VIDEO WRITE %s %d\n", self->name, res); 5342 } 5343 } 5344 return res; 5345 } 5346 5347 5348 /*! 5349 * Channel interface. 5350 * \brief Read an exception audio frame from my channel. 5351 */ 5352 static struct ast_frame *tech_exception(struct ast_channel *self) 5353 { 5354 private_object *tech_pvt; 5355 5356 tech_pvt = self->tech_pvt; 5357 if (globals.debug > 1 && option_verbose > 2) { 5358 if (option_verbose > 2) { 5359 ast_verbose(WOOMERA_DEBUG_PREFIX "+++EXCEPT %s\n", self->name); 5360 } 5361 } 5362 5363 return &ast_null_frame; 5364 } 5365 5366 5367 /*! 5368 * Channel interface. 5369 * \brief Indicate a condition to a channe. 5370 */ 5371 #ifdef USE_TECH_INDICATE 5372 #if defined (AST14) || defined (AST16) 5373 static int tech_indicate(struct ast_channel *self, int condition, const void *data, size_t datalen) 5374 #else 5375 static int tech_indicate(struct ast_channel *self, int condition) 5376 #endif 5377 { 5378 private_object *tech_pvt; 5379 int res = -1; 5380 5381 tech_pvt = self->tech_pvt; 5382 if (!tech_pvt) { 5383 return res; 5384 } 5385 5386 ast_mutex_lock(&tech_pvt->iolock); 5387 5388 switch (condition) { 5389 5390 case AST_CONTROL_RINGING: 5391 if (globals.debug > 3) { 5392 ast_log(LOG_NOTICE, "TECH INDICATE: Ringing\n"); 5393 } 5394 if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) { 5395 ast_set_flag(tech_pvt, TFLAG_ACCEPT); 5396 } 5397 break; 5398 5399 case AST_CONTROL_BUSY:/home/test/woomera/clients/asterisk/chan_woomera 5400 if (globals.debug > 3) { 5401 ast_log(LOG_NOTICE, "TECH INDICATE: Busy\n"); 5402 } 5403 ast_copy_string(tech_pvt->ds, "BUSY", sizeof(tech_pvt->ds)); 5404 tech_pvt->pri_cause = 17; 5405 ast_set_flag(tech_pvt, TFLAG_ABORT); 5406 break; 5407 5408 case AST_CONTROL_CONGESTION: 5409 if (globals.debug > 3) { 5410 ast_log(LOG_NOTICE, "TECH INDICATE: Congestion\n"); 5411 } 5412 ast_copy_string(tech_pvt->ds, "BUSY", sizeof(tech_pvt->ds)); 5413 tech_pvt->pri_cause = 17; 5414 ast_set_flag(tech_pvt, TFLAG_ABORT); 5415 break; 5416 5417 case AST_CONTROL_PROCEEDING: 5418 if (globals.debug > 3) { 5419 ast_log(LOG_NOTICE, "TECH INDICATE: Proceeding\n"); 5420 } 5421 if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) { 5422 ast_set_flag(tech_pvt, TFLAG_ACCEPT); 5423 } 5424 break; 5425 5426 case AST_CONTROL_PROGRESS: 5427 if (globals.debug > 3) { 5428 ast_log(LOG_NOTICE, "TECH INDICATE: Progress\n"); 5429 } 5430 if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) { 5431 ast_set_flag(tech_pvt, TFLAG_ACCEPT); 5432 } 5433 break; 5434 5435 case AST_CONTROL_HOLD: 5436 if (globals.debug > 3) { 5437 ast_log(LOG_NOTICE, "TECH INDICATE: Hold\n"); 5438 } 5439 if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) { 5440 ast_set_flag(tech_pvt, TFLAG_ACCEPT); 5441 } 5442 #if defined (AST14) || defined (AST16) 5443 ast_moh_start(self, data, tech_pvt->mohinterpret); 5444 #endif 5445 break; 5446 5447 case AST_CONTROL_UNHOLD: 5448 if (globals.debug > 3) { 5449 ast_log(LOG_NOTICE, "TECH INDICATE: UnHold\n"); 5450 } 5451 if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) { 5452 ast_set_flag(tech_pvt, TFLAG_ACCEPT); 5453 } 5454 #if defined (AST14) || defined (AST16) 5455 ast_moh_stop(self); 5456 #endif 5457 break; 5458 5459 case AST_CONTROL_VIDUPDATE: 5460 if (globals.debug > 3) { 5461 ast_log(LOG_NOTICE, "TECH INDICATE: Vidupdate\n"); 5462 } 5463 if (!ast_test_flag(tech_pvt, TFLAG_ACCEPTED)) { 5464 ast_set_flag(tech_pvt, TFLAG_ACCEPT); 5465 } 5466 break; 5467 5468 #ifdef WOO_CONTROL_SRC_FEATURE 5469 case AST_CONTROL_SRCUPDATE: 5470 res = 0; 5471 break; 5472 #endif 5473 case -1: 5474 res = -1; 5475 break; 5476 5477 default: 5478 ast_log(LOG_NOTICE, "Don't know how to indicate condition %d\n", condition); 5479 res = -1; 5480 break; 5481 } 5482 5483 ast_mutex_unlock(&tech_pvt->iolock); 5484 5485 return res; 5486 } 5487 #endif 5488 5489 /*! 5490 * Channel interface. 5491 * \brief Add any finishing touches to a channel if it is masqueraded. 5492 */ 5493 static int tech_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) 5494 { 5495 struct private_object *p; 5496 5497 if (!oldchan || !newchan) { 5498 ast_log(LOG_ERROR, "Error: Invalid Pointers oldchan=%p newchan=%p\n", oldchan, newchan); 5499 return -1; 5500 } 5501 if (!newchan->tech_pvt) { 5502 ast_log(LOG_ERROR, "Error: Invalid Pointer newchan->tech_pvt=%p\n", 5503 newchan->tech_pvt); 5504 return -1; 5505 } 5506 5507 p = newchan->tech_pvt; 5508 5509 ast_mutex_lock(&p->iolock); 5510 if (p->owner == oldchan) { 5511 p->owner = newchan; 5512 } else { 5513 ast_log(LOG_ERROR, "Error: New p owner=%p instead of %p \n", 5514 p->owner, oldchan); 5515 } 5516 5517 #if 0 5518 if (newchan->_state == AST_STATE_RINGING) 5519 dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0); 5520 5521 update_conf(p); 5522 #endif 5523 5524 if (globals.debug > 1 && option_verbose > 2) { 5525 if (option_verbose > 2) { 5526 ast_verbose(WOOMERA_DEBUG_PREFIX "+++FIXUP ChOld=%s ChNew=%s\n", 5527 oldchan->name, newchan->name); 5528 } 5529 } 5530 5531 ast_mutex_unlock(&p->iolock); 5532 return 0; 5533 } 5534 5535 5536 /*! 5537 * Channel interface. 5538 * \brief Send html data on a channel. 5539 */ 5540 static int tech_send_html(struct ast_channel *self, int subclass, const char *data, int datalen) 5541 { 5542 private_object *tech_pvt; 5543 int res = 0; 5544 5545 tech_pvt = self->tech_pvt; 5546 return res; 5547 } 5548 5549 5550 /*! 5551 * Channel interface. 5552 * \brief Send plain text data on a channel. 5553 */ 5554 static int tech_send_text(struct ast_channel *self, const char *text) 5555 { 5556 int res = 0; 5557 return res; 5558 } 5559 5560 5561 /*! 5562 * Channel interface. 5563 * \brief Send image data on a channel. 5564 */ 5565 static int tech_send_image(struct ast_channel *self, struct ast_frame *frame) 5566 { 5567 int res = 0; 5568 return res; 5569 } 5570 5571 5572 /*! 5573 * Channel interface. 5574 * \brief Set options on a channel. 5575 */ 5576 static int tech_setoption(struct ast_channel *self, int option, void *data, int datalen) 5577 { 5578 int res = 0; 5579 5580 if (globals.debug > 1 && option_verbose > 2) { 5581 if (option_verbose > 2) { 5582 ast_verbose(WOOMERA_DEBUG_PREFIX "+++SETOPT %s\n",self->name); 5583 } 5584 } 5585 return res; 5586 5587 } 5588 5589 5590 /*! 5591 * Channel interface. 5592 * \brief Get options from a channel. 5593 */ 5594 static int tech_queryoption(struct ast_channel *self, int option, void *data, int *datalen) 5595 { 5596 int res = 0; 5597 5598 if (globals.debug > 1 && option_verbose > 2) { 5599 if (option_verbose > 2) { 5600 ast_verbose(WOOMERA_DEBUG_PREFIX "+++GETOPT %s\n", self->name); 5601 } 5602 } 5603 return res; 5604 } 5605 5606 5607 /*! 5608 * Channel interface. 5609 * \brief Get a pointer to a channel that may be bridged to our channel. 5610 */ 5611 #if 0 5612 static struct ast_channel *tech_bridged_channel(struct ast_channel *self, struct ast_channel *bridge) 5613 { 5614 struct ast_channel *chan = NULL; 5615 5616 if (globals.debug > 1 && option_verbose > 2) { 5617 ast_verbose(WOOMERA_DEBUG_PREFIX "+++BRIDGED %s\n", self->name); 5618 } 5619 return chan; 5620 } 5621 #endif 5622 5623 5624 /*! 5625 * Channel interface. 5626 * \brief Technology-specific code executed to perform a transfer. 5627 */ 5628 static int tech_transfer(struct ast_channel *self, const char *newdest) 5629 { 5630 int res = -1; 5631 5632 if (globals.debug > 1 && option_verbose > 2) { 5633 if (option_verbose > 2) { 5634 ast_verbose(WOOMERA_DEBUG_PREFIX "+++TRANSFER %s\n", self->name); 5635 } 5636 } 5637 return res; 5638 } 5639 5640 5641 /*! 5642 * \brief Technology-specific code executed to natively bridge 2 of our channels 5643 */ 5644 #if 0 5645 static enum ast_bridge_result tech_bridge(struct ast_channel *c0, 5646 struct ast_channel *c1, 5647 int flags, 5648 struct ast_frame **fo, 5649 struct ast_channel **rc, 5650 int timeoutms) 5651 { 5652 int res = -1; 5653 5654 if (globals.debug > 1) { 5655 ast_verbose(WOOMERA_DEBUG_PREFIX "+++BRIDGE %s\n", c0->name); 5656 } 5657 return res; 5658 } 5659 #endif 5660 5661 5662 #if defined(AST16) 5663 static char *ast16_woomera_cli(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) 5664 { 5665 switch (cmd) { 5666 case CLI_INIT: 5667 e->command = "woomera"; 5668 e->usage = "Usage: woomera <profile> <cmd> <option>\n"; 5669 return NULL; 5670 case CLI_GENERATE: 5671 return NULL; 5672 } 5673 5674 woomera_cli(a->fd, a->argc, a->argv); 5675 return CLI_SUCCESS; 5676 } 5677 #endif 5678 5679 5680 /*! 5681 * \brief Command line handler. 5682 */ 5683 static int woomera_cli(int fd, int argc, char *argv[]) 5684 { 5685 struct woomera_profile *profile; 5686 char *profile_name = "default"; 5687 5688 if (argc > 2) { 5689 5690 profile_name = argv[1]; 5691 profile = ASTOBJ_CONTAINER_FIND(&woomera_profile_list, profile_name); 5692 if (!profile) { 5693 5694 if (strcmp(profile_name,"version") == 0) { 5695 ast_cli(fd, "Woomera version %s : Server version %s \n", 5696 WOOMERA_VERSION, svrversion); 5697 return 0; 5698 } 5699 5700 ast_cli(fd, "Woomera: Invalid profile name %s\n", profile_name); 5701 return 0; 5702 } 5703 5704 if (!strcmp(argv[2], "debug")) { 5705 if (argc > 3) { 5706 globals.debug = atoi(argv[3]); 5707 } 5708 ast_cli(fd, "Woomera debug=%d\n", globals.debug); 5709 5710 5711 } else if (!strcmp(argv[2], "coding")) { 5712 5713 switch (profile->coding) { 5714 case AST_FORMAT_ALAW: 5715 ast_cli(fd, " Woomera {%s} coding=ALAW (PCMA)\n", profile_name); 5716 break; 5717 case AST_FORMAT_ULAW: 5718 ast_cli(fd, " Woomera {%s} coding=ULAW (PCMU)\n", profile_name); 5719 break; 5720 case AST_FORMAT_SLINEAR: 5721 ast_cli(fd, " Woomera {%s} coding=PCM-16\n", profile_name); 5722 break; 5723 default: 5724 ast_cli(fd, " Woomera {%s} invalid coding=%d {internal error}", 5725 profile_name, profile->coding); 5726 break; 5727 5728 } 5729 5730 } else if (!strcmp(argv[2], "videocoding")) { 5731 5732 switch (profile->videocoding) { 5733 case AST_FORMAT_H261: 5734 ast_cli(fd, " Woomera {%s} videocoding=H261\n", profile_name); 5735 break; 5736 case AST_FORMAT_H263: 5737 ast_cli(fd, " Woomera {%s} videocoding=H263\n", profile_name); 5738 break; 5739 case AST_FORMAT_H263_PLUS: 5740 ast_cli(fd, " Woomera {%s} videocoding=H263-1998\n", profile_name); 5741 break; 5742 case AST_FORMAT_H264: 5743 ast_cli(fd, " Woomera {%s} videocoding=H264\n", profile_name); 5744 break; 5745 case AST_FORMAT_MP4_VIDEO: 5746 ast_cli(fd, " Woomera {%s} videocoding=MPV4-ES\n", profile_name); 5747 break; 5748 default: 5749 ast_cli(fd, " Woomera {%s} invalid coding=%d {internal error}", 5750 profile_name, profile->coding); 5751 break; 5752 } 5753 } else if (!strcmp(argv[2], "call_status")) { 5754 5755 ast_cli(fd, "Woomera {%s} calls=%d tcalls=%d (out=%d in=%d ok=%d end=%d abort=%d hup_pend=%d use=%d)\n", 5756 profile->name, 5757 profile->call_count, 5758 profile->call_out+profile->call_in, 5759 profile->call_out, 5760 profile->call_in, 5761 profile->call_ok, 5762 profile->call_end, 5763 profile->call_abort, 5764 profile->call_ast_hungup, 5765 usecnt); 5766 5767 } else if (!strcmp(argv[2], "version")) { 5768 5769 ast_cli(fd, "Woomera version %s : Server version %s \n", 5770 WOOMERA_VERSION, svrversion); 5771 5772 } else if (!strcmp(argv[2], "panic")) { 5773 if (argc > 3) { 5774 globals.panic = atoi(argv[3]); 5775 } 5776 ast_cli(fd, "Woomera panic=%d \n", globals.panic); 5777 5778 } else if (!strcmp(argv[2], "rxgain")) { 5779 float gain; 5780 if (argc > 3) { 5781 if (sscanf(argv[3], "%f", &gain) != 1) { 5782 ast_cli(fd, "Woomera Invalid rxgain: %s\n", argv[3]); 5783 } else { 5784 woomera_config_gain(profile,gain,1); 5785 } 5786 } 5787 ast_cli(fd, "Woomera {%s} rxgain: %f\n", profile_name, profile->rxgain_val); 5788 5789 } else if (!strcmp(argv[2], "txgain")) { 5790 float gain; 5791 if (argc > 3) { 5792 if (sscanf(argv[3], "%f", &gain) != 1) { 5793 ast_cli(fd, "Woomera Invalid txgain: %s\n", argv[3]); 5794 } else { 5795 woomera_config_gain(profile,gain,0); 5796 } 5797 } 5798 ast_cli(fd, "Woomera {%s} txgain: %f\n", profile_name, profile->txgain_val); 5799 5800 } else if (!strcmp(argv[2], "threads")) { 5801 ast_cli(fd, "chan_woomera is using %s threads!\n", 5802 globals.more_threads ? "more" : "less"); 5803 5804 } else if (!strcmp(argv[2], "debug")) { 5805 5806 if (argc > 3) { 5807 int debuglevel = atoi(argv[3]); 5808 if (debuglevel < 0 || debuglevel > 5) { 5809 ast_cli(fd, "Invalid Woomera debug level: %i\n", debuglevel); 5810 } else { 5811 ast_cli(fd,"Setting Woomera debug level to %i\n", debuglevel); 5812 globals.debug = debuglevel; 5813 } 5814 } else { 5815 ast_cli(fd, "Invalid Woomera debug usage\n"); 5816 } 5817 } else if (!strcmp(argv[2], "abort")) { 5818 global_set_flag(TFLAG_ABORT); 5819 } 5820 5821 } else { 5822 ast_cli(fd, "Usage: woomera <profile> <cmd> <option>\n"); 5823 } 5824 return 0; 5825 } 5826 5827 5828 5829 5830 #ifdef CALLWEAVER 5831 #ifdef CALLWEAVER_OPBX_CLI_ENTRY 5832 static struct opbx_cli_entry cli_woomera[] = { 5833 # else 5834 #ifdef CALLWEAVER_CW_CLI_ENTRY 5835 static struct cw_cli_entry cli_woomera[] = { 5836 #else 5837 static struct cw_clicmd cli_woomera[] = { 5838 #endif 5839 #endif 5840 { 5841 .cmda = { "woomera", "default", "version", NULL }, 5842 .handler = woomera_cli, 5843 .summary = "Woomera Version", 5844 //.usage = pri_debug_help, 5845 //.generator = complete_span_4, 5846 }, 5847 }; 5848 5849 #else 5850 /*! 5851 * Woomera Cli commands definition 5852 */ 5853 #if defined (AST16) 5854 static struct ast_cli_entry cli_woomera[] = { 5855 AST_CLI_DEFINE(ast16_woomera_cli, "Prints Woomera options"), 5856 }; 5857 #else 5858 static struct ast_cli_entry cli_woomera = { { "woomera", NULL }, woomera_cli, "Woomera", "Woomera" }; 5859 #endif 5860 #endif 5861 5862 /******************************* CORE INTERFACE ******************************************** 5863 * These are module-specific interface functions that are common to every module 5864 * To be used to initilize/de-initilize, reload and track the use count of a loadable module. 5865 */ 5866 5867 static void urg_handler(int num) 5868 { 5869 signal(num, urg_handler); 5870 return; 5871 } 5872 5873 5874 int usecount(void) 5875 { 5876 int res; 5877 ast_mutex_lock(&usecnt_lock); 5878 res = usecnt; 5879 ast_mutex_unlock(&usecnt_lock); 5880 return res; 5881 } 5882 5883 5884 #if 0 5885 static char *key(void) 5886 { 5887 return ASTERISK_GPL_KEY; 5888 } 5889 5890 5891 /* returns a descriptive string to the system console */ 5892 char *description(void) 5893 { 5894 return (char *) desc; 5895 } 5896 #endif 5897 5898 /*! 5899 * \brief get the channel. 5900 */ 5901 static struct ast_channel * tech_get_owner( private_object *tech_pvt) 5902 { 5903 struct ast_channel *owner = NULL; 5904 5905 ast_mutex_lock(&tech_pvt->iolock); 5906 if (!ast_test_flag(tech_pvt, TFLAG_TECHHANGUP) && tech_pvt->owner) { 5907 owner = tech_pvt->owner; 5908 } 5909 ast_mutex_unlock(&tech_pvt->iolock); 5910 5911 return owner; 5912 } 5913 5914 5915 /*! 5916 * \brief Handle EVENT MEDIA message. 5917 */ 5918 static int woomera_event_media(private_object *tech_pvt, woomera_message *wmsg) 5919 { 5920 char *raw_audio_header; 5921 char *rtp_video_header; 5922 char *rtp_audio_header; 5923 5924 char *hw_dtmf; 5925 char ip[25]; 5926 char vip[25]; 5927 5928 char *ptr; 5929 int port = 0; 5930 int vport = 0; 5931 5932 struct hostent hps, *hp; 5933 struct hostent *result; 5934 struct ast_channel *owner; 5935 char buf[512]; 5936 int err = 0; 5937 5938 memset(&hps, 0, sizeof(hps)); 5939 hp = &hps; 5940 5941 if (tech_pvt->rtp_enable) { 5942 rtp_audio_header = woomera_message_header(wmsg, "RTP-Audio"); 5943 if (rtp_audio_header == NULL) { 5944 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 5945 tech_pvt->pri_cause = 111; 5946 return 1; 5947 } 5948 5949 strncpy(ip, rtp_audio_header, sizeof(ip) - 1); 5950 if ((ptr = strchr(ip, '/'))) { 5951 *ptr = '\0'; 5952 ptr++; 5953 port = atoi(ptr); 5954 } 5955 else if ((ptr = strchr(ip, ':'))) { 5956 *ptr = '\0'; 5957 ptr++; 5958 port = atoi(ptr); 5959 } 5960 5961 rtp_video_header = woomera_message_header(wmsg, "RTP-Video"); 5962 if (rtp_video_header) { 5963 strncpy(vip, rtp_video_header, sizeof(vip) - 1); 5964 if ((ptr = strchr(vip, '/'))) { 5965 *ptr = '\0'; 5966 ptr++; 5967 vport = atoi(ptr); 5968 } 5969 else if ((ptr = strchr(vip, ':'))) { 5970 *ptr = '\0'; 5971 ptr++; 5972 vport = atoi(ptr); 5973 } 5974 } 5975 } 5976 else 5977 { 5978 raw_audio_header = woomera_message_header(wmsg, "Raw-Audio"); 5979 if (raw_audio_header == NULL) { 5980 ast_copy_string(tech_pvt->ds, "PROTOCOL_ERROR", sizeof(tech_pvt->ds)); 5981 tech_pvt->pri_cause = 111; 5982 return 1; 5983 } 5984 5985 strncpy(ip, raw_audio_header, sizeof(ip) - 1); 5986 if ((ptr = strchr(ip, '/'))) { 5987 *ptr = '\0'; 5988 ptr++; 5989 port = atoi(ptr); 5990 } else if ((ptr = strchr(ip, ':'))) { 5991 *ptr = '\0'; 5992 ptr++; 5993 port = atoi(ptr); 5994 } 5995 5996 #if 0 5997 audio_codec = woomera_message_header(wmsg, "Receive-Audio-Codec"); 5998 if (audio_codec) { 5999 if (!strcasecmp(audio_codec,"G.711-uLaw-64k")) { 6000 tech_pvt->coding = AST_FORMAT_ULAW; 6001 ast_log(LOG_NOTICE, "MEDIA GOT ULAW\n"); 6002 } else if (!strcasecmp(audio_codec,"G.711-aLaw-64k")) { 6003 tech_pvt->coding = AST_FORMAT_ALAW; 6004 ast_log(LOG_NOTICE, "MEDIA GOT ALAW\n"); 6005 } 6006 } 6007 #endif 6008 } 6009 6010 hw_dtmf = woomera_message_header(wmsg, "DTMF"); 6011 if (hw_dtmf != NULL) { 6012 if (strncmp(hw_dtmf, "OutofBand", 9) == 0) { 6013 if (option_verbose > 2) { 6014 ast_verbose(WOOMERA_DEBUG_PREFIX "HW DTMF supported %s\n", tech_pvt->callid); 6015 } 6016 if (tech_pvt->dsp) { 6017 tech_pvt->dsp_features &= ~DSP_FEATURE_DTMF_DETECT; 6018 ast_dsp_set_features(tech_pvt->dsp, tech_pvt->dsp_features); 6019 } 6020 } else { 6021 if (option_verbose > 2) { 6022 ast_verbose(WOOMERA_DEBUG_PREFIX "HW DTMF not supported %s\n", tech_pvt->callid); 6023 } 6024 } 6025 } 6026 6027 /* If we are already in MEDIA mode then 6028 * ignore this message */ 6029 if (ast_test_flag(tech_pvt, TFLAG_MEDIA)) { 6030 return 0; 6031 } 6032 6033 gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err); 6034 if (result) { 6035 6036 tech_pvt->udpwrite.sin_family = hp->h_addrtype; 6037 memcpy((char *) &tech_pvt->udpwrite.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length); 6038 tech_pvt->udpwrite.sin_port = htons(port); 6039 6040 if (globals.debug > 4) { 6041 ast_log(LOG_NOTICE,"MEDIA EVENT UdpWrite IP=%s:%d\n", 6042 ast_inet_ntoa(tech_pvt->udpwrite.sin_addr), port); 6043 } 6044 6045 if ( vport ) { 6046 struct sockaddr_in video; 6047 gethostbyname_r(ip, hp, buf, sizeof(buf), &result, &err); 6048 if (result) 6049 { 6050 video.sin_family = hp->h_addrtype; 6051 memcpy((char *) &video.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length); 6052 video.sin_port = htons(vport); 6053 if (tech_pvt->vrtp) 6054 ast_rtp_set_peer(tech_pvt->vrtp, &video); 6055 } 6056 } 6057 6058 ast_set_flag(tech_pvt, TFLAG_MEDIA); 6059 tech_pvt->timeout = 0; 6060 6061 if (tech_pvt->rtp_enable) { 6062 ast_rtp_set_peer(tech_pvt->rtp, &tech_pvt->udpwrite); 6063 } 6064 6065 my_tech_pvt_and_owner_lock(tech_pvt); 6066 6067 owner = tech_pvt->owner; 6068 if (!owner) { 6069 tech_pvt->pri_cause = 44; 6070 ast_copy_string(tech_pvt->ds, "REQUESTED_CHAN_UNAVAIL", sizeof(tech_pvt->ds)); 6071 my_tech_pvt_and_owner_unlock(tech_pvt); 6072 return -1; 6073 } 6074 6075 if (ast_test_flag(tech_pvt, TFLAG_INBOUND)) { 6076 int pbx_res; 6077 6078 #if defined (AST14) || defined (AST16) 6079 ast_setstate(owner, AST_STATE_RINGING); 6080 #endif 6081 pbx_res = ast_pbx_start(owner); 6082 6083 if (pbx_res) { 6084 6085 my_tech_pvt_and_owner_unlock(tech_pvt); 6086 6087 ast_log(LOG_NOTICE, "Failed to start PBX on %s \n", tech_pvt->callid); 6088 ast_set_flag(tech_pvt, TFLAG_ABORT); 6089 ast_clear_flag(tech_pvt, TFLAG_PBX); 6090 owner->tech_pvt = NULL; 6091 tech_pvt->owner = NULL; 6092 ast_copy_string(tech_pvt->ds, "SWITCH_CONGESTION", sizeof(tech_pvt->ds)); 6093 tech_pvt->pri_cause = 42; 6094 ast_hangup(owner); 6095 /* Let destroy hangup */ 6096 return -1; 6097 } else { 6098 #if !defined (AST14) && !defined (AST16) 6099 ast_setstate(owner, AST_STATE_RINGING); 6100 #endif 6101 ast_set_flag(tech_pvt, TFLAG_PBX); 6102 owner->hangupcause = AST_CAUSE_NORMAL_CLEARING; 6103 6104 woomera_send_progress(tech_pvt); 6105 } 6106 } else { /* OUTBOUND */ 6107 #if 1 6108 ast_queue_control(owner, AST_CONTROL_RINGING); 6109 if (owner->_state != AST_STATE_UP) { 6110 ast_setstate(owner, AST_STATE_RINGING); 6111 } 6112 #endif 6113 /* Do nothing for the outbound call, the PBX flag was already set. 6114 */ 6115 } 6116 6117 my_tech_pvt_and_owner_unlock(tech_pvt); 6118 return 0; 6119 6120 } else { 6121 if (globals.debug) { 6122 ast_log(LOG_ERROR, "{%s} Cannot resolve %s\n", tech_pvt->profile->name, ip); 6123 } 6124 ast_copy_string(tech_pvt->ds, "NO_ROUTE_DESTINATION", sizeof(tech_pvt->ds)); 6125 tech_pvt->pri_cause = 3; 6126 return -1; 6127 } 6128 6129 return -1; 6130 } 6131 6132 6133 /*! 6134 * \brief Handle an EVENT INCOMING message. 6135 */ 6136 static int woomera_event_incoming(private_object *tech_pvt) 6137 { 6138 char *exten; 6139 char *cid_name=NULL; 6140 char *cid_num; 6141 char *cid_rdnis; 6142 char *tg_string = "1"; 6143 char *pres_string; 6144 char *screen_string; 6145 char *bearer_cap_string; 6146 char *uil1p_string; /* User Layer 1 Info */ 6147 int validext; 6148 int presentation = 0; 6149 woomera_message wmsg; 6150 struct ast_channel *owner; 6151 6152 wmsg = tech_pvt->call_info; 6153 6154 if (globals.debug > 2) { 6155 ast_log(LOG_NOTICE, "WOOMERA EVENT %s : callid=%s tech_callid=%s tpvt=%p\n", 6156 wmsg.command, wmsg.callid, tech_pvt->callid, tech_pvt); 6157 } 6158 6159 if (ast_strlen_zero(tech_pvt->profile->context)) { 6160 if (globals.debug > 2) { 6161 ast_log(LOG_NOTICE, "No Context Found %s tpvt=%p\n", tech_pvt->callid, tech_pvt); 6162 } 6163 ast_log(LOG_NOTICE, "No context configured for inbound calls aborting call!\n"); 6164 ast_set_flag(tech_pvt, TFLAG_ABORT); 6165 return -1; 6166 } 6167 6168 exten = woomera_message_header(&wmsg, "Local-Number"); 6169 if (!exten || ast_strlen_zero(exten)) { 6170 exten = "s"; 6171 } 6172 6173 tg_string = woomera_message_header(&wmsg, "Trunk-Group"); 6174 if (!tg_string || ast_strlen_zero(tg_string)) { 6175 tg_string = "1"; 6176 } 6177 6178 pres_string = woomera_message_header(&wmsg, "Presentation"); 6179 if (pres_string && !ast_strlen_zero(pres_string)) { 6180 presentation |= ( atoi(pres_string) << 5) & 0xF0; 6181 } 6182 6183 screen_string = woomera_message_header(&wmsg, "Screening"); 6184 if (screen_string && !ast_strlen_zero(screen_string)) { 6185 presentation |= atoi(screen_string) & 0x0F; 6186 } 6187 6188 cid_name = woomera_message_header(&wmsg, "Remote-Name"); 6189 if (cid_name) { 6190 cid_name = ast_strdupa(woomera_message_header(&wmsg, "Remote-Name")); 6191 } 6192 6193 if (cid_name && (cid_num = strchr(cid_name, '!'))) { 6194 *cid_num = '\0'; 6195 cid_num++; 6196 } else { 6197 cid_num = woomera_message_header(&wmsg, "Remote-Number"); 6198 } 6199 6200 bearer_cap_string = woomera_message_header(&wmsg, "Bearer-Cap"); 6201 tech_pvt->capability = woomera_capability_to_ast(bearer_cap_string); 6202 6203 uil1p_string = woomera_message_header(&wmsg, "uil1p"); 6204 tech_pvt->coding = woomera_coding_to_ast(uil1p_string); 6205 if (tech_pvt->coding < 0) { 6206 tech_pvt->coding = tech_pvt->profile->coding; 6207 } 6208 6209 cid_rdnis = woomera_message_header(&wmsg, "RDNIS"); 6210 6211 owner = tech_pvt->owner; 6212 if (owner) { 6213 int group = atoi(tg_string); 6214 if (group >= 0 && 6215 group <= WOOMERA_MAX_TRUNKGROUPS && 6216 tech_pvt->profile->tg_context[group] != NULL) { 6217 6218 strncpy(owner->context, tech_pvt->profile->tg_context[group], sizeof(owner->context) - 1); 6219 6220 if (tech_pvt->profile->tg_language[group] != NULL && 6221 strlen(tech_pvt->profile->tg_language[group])) { 6222 ast_string_field_set(owner, language, (char*)tech_pvt->profile->tg_language[group]); 6223 } 6224 } else { 6225 snprintf(owner->context, sizeof(owner->context) - 1, 6226 "%s%s", 6227 tech_pvt->profile->default_context, 6228 tg_string); 6229 } 6230 6231 owner->transfercapability = tech_pvt->capability; 6232 pbx_builtin_setvar_helper(owner, "TRANSFERCAPABILITY", ast_transfercapability2str(tech_pvt->capability)); 6233 pbx_builtin_setvar_helper(owner, "CALLTYPE", ast_transfercapability2str(tech_pvt->capability)); 6234 6235 owner->nativeformats = tech_pvt->coding | tech_pvt->videocoding; 6236 owner->writeformat = owner->rawwriteformat = owner->readformat = tech_pvt->coding; 6237 tech_pvt->frame.subclass = tech_pvt->coding; 6238 6239 strncpy(owner->exten, exten, sizeof(owner->exten) - 1); 6240 ast_set_callerid(owner, cid_num, cid_name, cid_num); 6241 owner->cid.cid_pres = presentation; 6242 owner->cid.cid_dnid = ast_strdup(woomera_message_header(&wmsg, "Local-Number")); 6243 6244 if (cid_rdnis) { 6245 owner->cid.cid_rdnis = ast_strdup(cid_rdnis); 6246 pbx_builtin_setvar_helper(owner, "RDNIS", cid_rdnis); 6247 } 6248 6249 validext = ast_exists_extension(owner, 6250