Anders Dahnielson
<anders@mysite.se>
2002-07-10
To speed development and simplify deployment of custom applications, Bayonne offers it's own native script interpreter which may be directly extended thru modular DSO plugins and TGI scripted applications. TGI, "Telephony Gateway Interface", allows Bayonne to be easily integrated with other system resources, such as web servers, databases, and other application servers using standard and familiar tools that are well understood such as Perl, TCL, and Python.
Bayonne can be used today most completely under GNU/Linux with an ever wider selection of telephony hardware. Bayonne has also been built under, and can be used with, FreeBSD and the new Voicetronix API. Bayonne is highly portable and will compile under most multi-threaded POSIX operating systems, including Solaris and Unixware. As Bayonne's telephony hardware and next generation media support broadens, support for functional deployment under operating systems beyond GNU/Linux will continue to increase.
The most current release represents milestone #8, and represents the
final form of GNU Bayonne for the 1.0 release, scheduled for early July.
Between now and July the existing package will be refined and this
documentation will be extensively revised.
With Milestone #7 we introduced broad support for high density digital
telephony hardware, primarily from Intel/Dialogic and Aculab. With high
density digital (PRI) support, it became possible to use GNU Bayonne for
various carrier class applications.
Milestone #6 introduced support for XML based scripting. XML support was
created by directly transcoding XML content into the Bayonne ccScript virtual
execution environment, and then running standard Bayonne applications.
Starting With milestone #5, Bayonne supported FreeBSD in addition to GNU/Linux
(and possibly Solaris). 0.5.0 is the first release which demonstrability
works under FreeBSD and also happens to support the Voicetronix 4 port
analog DSP card which will be used as the core of Bayonne VoIP
development in coming weeks. In addition, support for Aculab and Dialogic
hardware has been initiated, though it is not yet complete.
The fourth Bayonne milestone featured many changes, starting with
international support and the new French language vocabulary. There are
many less visible changes that effect and expand the scope of DSO
capabilities for the Bayonne server as well as greatly improve stability
of the server. With 0.4.2, expanded support for initiating dial-out
sessions has been added along with preliminary support for locating
streams and the Dialogic SDK.
The 3rd milestone release of Bayonne is being made available from
ftp://www.voxilla.org/pub/bayonne immediately. This release represents
both a more rigorously tested server, and a "usable" or "deployable"
server. An audio library has been recorded for use with the new
phrasebook system, and some documentation has been drafted. Many
features have also been clarified and greatly expanded upon for better
use in deployable servers. A lot of bugs were also found and fixed
between 0.2.1 and 0.3.
In particular a number of new issues were identified for both QuickNet
and Pika hardware. In the case of QuickNet cards, it was found to be
necessary to do a full close/reopen of the /dev/phone devices to reset
the card otherwise they stop responding between calls, and this was
done in 0.2. When the server is started as root, the /dev/phone devices
are initially opened under root, but then the server reduces its
privilege to "mail" and can no longer re-open /dev/phone. In 0.3,
the server now resets file ownership of /dev/phone devices.
GNU Bayonne 2.0 already has architectural support for high availability hardware and concepts like de-activating live ports. Support for direct use of switching is also provided for to enable use of applications such as a complete integrated telephone system hosted on free software.
GNU GENERAL PUBLIC LICENSE Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software-to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that re-distributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sub-license, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sub-license or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.> Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items-whatever suits your program.
You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
URL: http://www.ostel.com
URL: http://www.mysite.se
Why we choose not to use an existing framework is also simple to explain. We knew we needed threading, and socket support, and a few other things. There were no single framework that did all these things except a few that were very large and complex which did far more than we needed. We wanted a small footprint for Bayonne, and the most adaptable framework that we found at the time typically added several megabyte of core image just for the runtime library.
GNU Common C++ (originally APE) was created to provide a very easy to comprehend and portable class abstraction for threads, sockets, semaphores, exceptions, etc. This has since grown into it's own and is now used as a foundation of a number of projects as well as being a part of GNU.
In addition to having portable C++ threading, we needed a scripting engine. This scripting system had to operate in conjunction with a non-blocking state-transition call processing system. It also had to offer immediate call response, and support several hundred to a thousand instances running concurrently in one server image.
Many extension languages assume a separate execution instance (thread or process) for each interpreter instance. These were unsuitable. Many extension languages assume expression parsing with non-deterministic run time. An expression could invoke recursive functions or entire subprograms for example. Again, since we wanted not to have a separate execution instance for each interpreter instance, and have each instance respond to the leading edge of an event call-back from the telephony driver as it steps through a state machine, none of the existing common solutions like TCL, Perl, guile, etc, would immediately work for us. Instead, we created a non-blocking and deterministic scripting engine, GNU ccScript.
GNU ccScript is unique in several ways. It is step executed, and is non-blocking. Statements either execute and return immediately, or they schedule their completion for a later time with the executive. A given "step" is executed, rather than linearly. This allows a single thread to invoke and manage multiple interpreter instances. While GNU Bayonne can support interacting with hundreds of simultaneous telephone callers on high density carrier scale hardware, we do not require hundreds of native "thread" instances running in the server, and we have a very modest CPU load.
Another way GNU ccScript is unique is in support for memory loaded scripts. To avoid delay or blocking while loading scripts, all scripts are loaded and parsed into a virtual machine structure in memory. When we wish to change scripts, a brand new virtual machine instance is created to contain these scripts. Calls currently in progress continue under the old virtual machine and new callers are offered the new virtual machine. When the last old call terminates, the entire old virtual machine is then disposed of. This allows for 100 % uptime even while services are modified.
Finally, GNU ccScript allows direct class extension of the script interpreter. This allows one to easily create a derived dialect specific to a given application, or even specific to a given GNU Bayonne driver, simply by deriving it from the core language through standard C++ class extension.
To do this, we made Bayonne itself operate as a series of base classes, and then create derived classes which implement functionality as separate plug-in modules with static initialized objects. The server exports it's own symbol map much like a library, and so when the derived plug-in is loaded, the static objects are instantiated, and their constructors are called. These constructors link with and are resolved to base class constructors in the server image which are then automatically invoked and are used to register the plug-in with the server.
The server itself also instantiates some objects at startup even before main() runs. These are typically objects related to plug-in registration or parsing of the configuration file.
These differences are substantial enough that the very concept of configuration and deployment of GNU Bayonne differs significantly from ACS. This document is not meant to highlight those differences, but to identify issues and configuration options relevant to each driver and telephony vendor that is supported in GNU Bayonne.
This section will provide information on the telephony hardware currently supported by GNU Bayonne and about each of the associated GNU Bayonne plug-in drivers related to that hardware.
In addition to telephony device "drivers", there are plugins for "integration" services. These typically are used for switch integration, such as the Bayonne "SMDI" module. Other modules offer extended call logging capabilities, network integration, VoIP stacks modified to operate as runtime loadable modules, and script language extensions.
While all other forms of drivers and plugins are optional, Bayonne requires at minimum a telephony device and API "driver" (.ivr) to be selected for Bayonne to execute. Furthermore, at present only one such driver can be selected and made active in any running instance of the Bayonne server.
The primary telephony driver API is selected in the [paths] section of the /etc/bayonne.conf file. The name of the driver to load is specified directly, in the form "driver=drivername", such as "driver=phonedev". A matching "phonedev.ivr" plug-in is then loaded when the Bayonne server is started.
When Bayonne is "configured" (by running ./configure) it will detect what telephony API's have been installed on the host system. If it fails to find the files associated with a given telephony API, then that API will be excluded from Bayonne. If you later add a telephony API, you will need to remove config.cache and then re-run "./configure" before Bayonne will recognize and build drivers for it.
The remaining sections of this document will cover the various driver and plug-in modules currently supported by Bayonne, as well as vendor specific issues.
The phonedev module does try to treat phone devices in a fully vendor neutral manner. /dev/phone device drivers from different vendors can be loaded and mixed in kernel memory under separate device nodes, and the phonedev.ivr module will accept such a mixed vendor environment as well as query /dev/phone devices for specific features and capabilities that will be supported on each instance in Bayonne.
Furthermore, in that Bayonne executes in "user" mode, the Bayonne server will only open and access "phone" devices that are actually made available to the current user id that Bayonne is running under. This means that if one wants to use, for example, three QuickNet "linejack" cards with Bayonne for servicing incoming calls (say /dev/phone1-4), and yet preserve a QuickNet "phonejack" card for "private" use (say with GnomeMeeting or Speak Freely), then one can simply set the ownership of the linejack cards to match the user id Bayonne will run under, and preserve the phonejack (/dev/phone0) as owned under a different user id (say the user-id of the workstation user who wishes to use Speak Freely).
Finally, the phonedev.ivr can be used in multiple instances of the Bayonne server. Hence, one can run different "application servers" by starting multiple instances of Bayonne under different user id's. Different sets of /dev/phone devices can be marked as owned by each of the expected server user id's, and each server will then operate only with the /dev/phone devices that user id has been granted access to.
One should never start more than one instance of Bayonne under the same effective user id. Also, when using user permissions to partition /dev/phone devices between multiple instances of Bayonne, these device nodes must never be marked with shared group "write" permission, otherwise the device may be accessed under multiple images.
When starting the server under the "root" user, one may find additional problems. Bayonne will change itself from root to a new effective user id once started. Due to a bug in the QuickNet cards, the /dev/phone device must be closed and re-opened between each telephone call. Hence while root, /dev/phone will initially open, but once the server is running /dev/phone devices may no longer work unless they are given r/w access permissions under the effective user id the server is now running under. By default this will be the effective user id of the "mail" account, although it can be changed in [server].
The "phonedev.ivr" uses service threads to service event queues for driving the call processor of each of the open /dev/phone devices. The total number of such devices that will be supported is indicated in the [phone] section of /etc/bayonne using the "devices =" keyword. The default value is currently "16". The maximum value that may be specified is "240". As each device represents an individual telephone line, it is possible some cards may support multiple /dev/phone nodes from a single card. This value thus represents the total "port" capacity that will be tested for rather than the total number of cards that may be supported in a single chassis.
Normally only one or at most two service threads are needed, and these can be selected using the [thread] service = keyword option as described in the bayonne.conf man page. Generally the service threads should run either at or a higher priority than Bayonne itself. The phonedev.ivr can support a maximum of 240 device nodes (sufficient for 10 T-1 spans or 8 E-1 spans), hence, in a very high capacity /dev/phone based SMP server one might wish to select 4 or even 8 service threads.
At the time of this writing, only the QuickNet cards are known to be using /dev/phone drivers under Linux. However, the Voicetronix multi-port analog telephony cards will likely soon also use /dev/phone based Linux kernel modules. It has been assumed a maximum of 16 QuickNet cards can be installed in a single cabinet. It is possible to also have up to 16 Voicetronix cards in a single cabinet, with each card servicing 4 analog telephone lines, for a total capacity of 64 ports.
You can get the Voicetronix driver package at http://www.voicetronix.com.au/.
The vpb.ivr module requires that Bayonne is started under ``root''. This is necessary for Bayonne to access io ports under both the Linux kernel and FreeBSD. Once started, Bayonne will reduce itself to the effective user privilege specified in the [server] section of bayonne.conf.
The [vpb] section of Bayonne must be configured properly before you attempt to start it. If you are using an ISA based Voicetronix card, you must set base address of the ``first'' card (in 0x3x0 range). Bayonne assumes all Voicetronix cards will be in sequential addresses, and hence, if you define the first card as 0x340, and specify two cards, the second card must be set for 0x350.
If you will be using more than one card, you should also set the total number of cards in the system with the ``cards'' variable, as Bayonne cannot currently detect the number of cards in the system.
Multiple instances of Bayonne can be started so long as each instance uses a different set of cards.
A separate service thread is started in Bayonne for each Voicetronix card. This service thread performs all event dispatch and may be tuned for process priority scheduling and by scheduling policy for optimal performance. The current implementation uses the special bayonne mode of the Voicetronix driver, which puts some of the scheduling burden on Bayonne. It is suspected that many things (such as call progress detection and ``pips'') do not work properly in this mode, and users who need those features should try the experimental code which does event dispatching using the normal event mode of the Voicetronix driver.
It is possible to have up to 16 Voicetronix cards in a single PC, for a total capacity of 64 analog telephony ports.
Voicetronix recently released their OpenSwitch12 card, which provides 12 hybrid FXO/FXS ports which are each user-configurable to be either FXS or FXO ports. This card does not currently work under Bayonne, although effort to port the new card to Bayonne is underway.
Note that the Voicetronix cards do not have hardware hangup detection. Hangup detection is currently done via recognition of dialtone, which is almost always played after the telephone company equipment detects remote hangup. However, in certain situations, such as multi-party calls, dialtone will not be played. Be careful to deal with this situation via a timeout or similar workaround if you encounter it when developing your application. Also be careful if you are placing outbound calls and a dialtone occurs during the dialing sequence, as your script will just terminate after hearing the dialtone.
The dialtone detection currently requires 2000 milliseconds of steady dialtone, which may be a bit long for some applications. In particular, outbound dialing currently listens for dialtone for a maximum of 800 milliseconds before deciding there is none and it stops trying to dial out. In those cases, set the ``dialtone'' key in the configuration file to 3500 milliseconds or so.
The Voicetronix API has a software-configurable tone detector which can be set via the VPB_TONE environment variable if your telephone company uses tones the card does not recognize. Consult the Voicetronix documentation in the header of the envtone_read_tone_from_env() function, located in src/envtone.cpp of your Voicetronix library source tree.
Caller ID support is currently broken for some local carriers in the current driver version. Contact Voicetronix for the patch.
Note that systems which do not set the OSTYPE environment variable, (such as newer RedHat distributions and Debian) will fail to compile the Voicetronix library. Set OSTYPE to ``Linux'' in these cases and the library will compile properly. BSD users do not need to worry, as the Makefile defaults to compilation for a BSD system.
Before you can use Dialogic support, you must install the Dialogic UNIX SDK for your platform. Bayonne is designed "generically" for the standard UNIX SDK, and will work with it under both Solaris and UnixWare, as well as under GNU/Linux. When using GNU/Linux, you must also install the appropriate release of the LiS streams package to match your Dialogic runtime release.
The dialogic.ivr module has been developed to autodetect Dialogic resources at startup. It should detect both analog and digital telephony devices, and will support both with the same ivr driver module, even if both types of devices are mixed on the same system. Currently, Digital support has been tested with classic ISA and PCI T1/E1 span cards using the PRI firmware.
The dialogic.ivr analyses and assigns ALL dialogic devices that it finds at startup. Hence, only one instance of Bayonne may be executed on any given server.
The current implementation does ``static'' assignment of DSP resources at startup, and requires that sufficient vox ports exist for all digital telephony interfaces found in the system. This means one cannot use plain DTI cards unless one has sufficient sc bus voice resource cards also available. This may change in future releases.
The ``sieze'' handlers are already known to be mispelled. If Pika ever reinstates Linux support, it will be fixed.
At the moment I assume that root permission is required to access the Aculab, though this may be incorrect.
The aculab module does automatic card timeslot assignment and will detect and allocate aculab timeslot and card resources during startup. In that all devices are allocated at startup, only one instance of Bayonne can be executed on a single server.
A single service thread is maintained for event dispatch, and a service thread is available for each telephone port. This may change later on.
There is an active workgroup working on aculab support, and the mailing list for this can be found at bayonne-aculab@lists.sourceforge.net.
After download you can unpack it with:
tar -zxvf bayonne-{VERSION}.tar.gz
Substitute VERSION with the version of your package. This will unpack the Bayonne distribution in a new directory with the same name as the package.
If you want to retrieve Bayonne from CVS, use the following command sequence:
for i in ccaudio ccrtp ccscript bayonne; do cvs -z3 -d :pserver:anoncvs@subversions.gnu.org:/cvsroot/$i co $i; done
cvs -z3 -d :pserver:anoncvs@subversions.gnu.org:/cvsroot/commoncpp co commoncpp2
Then you can use ``cvs diff'' to create patches if you want to submit patches to the Bayonne mailing list (bayonne-devel@lists.sourceforge.net). Don't forget to run ``cvs update'' before you start each work session!
A Mac OS X build was tried by Jason Spence on hardware loaned from Apple, but Common C++ does not support the pthread system used on OS X, so the attempts were unsuccessful.
With Milestone #5, Bayonne now supports FreeBSD in addition to GNU/Linux (and possibly Solaris).
/usr/share/aaprompts{/voice} | Bayonne supplied default prompt library. These include phrasebook prompts and anything else found useful to distribute with Bayonne itself. User application voice libraries should never be installed here. |
/usr/share/aaprompts/scrname{/voice} | Phrase library that is specific to a specified script file. For example, a ``play xx'' command in yy.scr would look for xx.au in /usr/share/aaprompts/yy{/voice}. This allows script files to have their own local voice libraries. |
/usr/share/altprompts{/voice} | Maybe optionally created for single product turnkey servers. This directory is generally referenced by prompts, as in "play myprompt". |
/usr/share/aascripts | Default system scripts supplied with Bayonne. These include test scripts and any simple applications supplied entirely with Bayonne. Turnkey applications may place script files here, though it is not generally recommended except for turnkey product servers. |
/usr/share/aawrappers | This is a special directory to hold user supplied executables that will be executed thru the bayonne_wrapper program. These programs are generally initiated under the apache user id and converted to the bayonne user id by bayonne_wrapper. |
/usr/libexec/bayonne | This is the default directory for Bayonne supplied TGI applications. Bayonne distributions will in time add a number of useful tgi libexec files. User supplied TGI applications must also be installed here, as these run under the Bayonne server's user id. |
/usr/lib/bayonne/{version}/ | This is the install directory for all loadable modules and plugins. There is only one directory, and DSO's are assumed to be compiled against a specific Bayonne version. User created DSO's should be installed here. |
/var/bayonne/tmp | A place to record temporary files |
/var/bayonne/save | A save filespace for serialized classes. |
/var/bayonne/prompts | Used by the play and record script. |
/var/bayonne/maps | Used for loadable map files. |
Individual
/home/bayonne/apps | Starting with 0.5.20, this is now the preferred base prefix for installing new Bayonne applications. |
/home/bayonne/php | A prefix for PHP include and drop files. |
/home/bayonne/admin | A working directory for plug-in PHP admin forms. |
/home/bayonne/html | The primary document root for Bayonne integrated web applications. These are typically execute using an Apache server running under the "bayonne" user id rather than the nobody or http user. This is used for applications that include web services like unified messaging. Other kinds of Bayonne apps might integrate with an existing web application by using bayonne_wrappers instead. "Click-to-dial" typically uses wrappers rather than a seperate apache server. |
/home/bayonne/apps/aascripts | User supplied application scripts are installed here. |
/home/bayonne/apps/{APP}/{%voice} | Each application gets it's own private voice library, which is also fully multi-lingual. For a script file to refer to it's APP prompt directory, it must use APP:: notation in play commands. For example, to play the voice mail intro prompt, one might use: "play VMS::intro". This will then play from "/home/bayonne/apps/VMS/UsEngM/intro.au". This allows one to refer to both default prompts supplied in bayonne and application specific prompts installed locally. |
/.bayonnerc | Can be used to override some things found in /etc/bayonne.conf. |
/.bayonne{.ctrl,.nodes,.mixers} | Local user privileged versions of /var/run files. |
/.bayonne/schedule.conf | User's private scheduler. |
/.bayonne/tgi | User's private tgi directory when non-privileged Bayonne is ran. |
/.bayonne/aascripts | User's private scripts. |
/.bayonne/aaprompts/{%voice} | User's private "" prompt path. Hence, a play myprompt" should go to here. |
/.bayonne/aaprompts/APPS/{%voice} | When not running under a privileged user id, the Bayonne application specific working directory will be located in the user's home rather than in /home/bayonne/apps. Hence, a "play myapp::intro" will go to " /.bayonne/aaprompts/myapp/UsEngM/intro.au" |
Change to the directory where the sources was unpacked and type the following to run 'configure':
./configure
Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for.
By default, Bayonne will attempt to build and install all of the telephony servers supported in the distribution. Since most often only a specific set of servers to support specific vendor telephony hardware you have available are needed, there are ways to select and remove vendor specific server implementations through configure. The advantage of doing this is a shorter compile time and the elimination of distractions from errors in building unneeded API trees.
The ``without-pika'' option removes all Pika Monte Carlo related, modules, and libraries from the build tree. The ``without-phonedev'' option removes all GNU/Linux /dev/phone support.
If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself.
If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it.
make
To make sure everything went ok. Type the following to run any self-tests that come with the package:
make check
To install the programs and any data files and documentation type:
make install
You can remove the program binaries and object files from the source code directory by typing:
make clean
To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution.
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure}
Or on systems that have the `env' program, you can do it like this:
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture.
For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `x-includes=DIR' and `x-libraries=DIR' to specify their locations.
CPU-COMPANY-SYSTEM
See the file `config.sub' for the possible values of each field. If config.sub' isn't included in this package, then this package doesn't need to know the host type.
If you are building compiler tools for cross-compiling, you can also use the target=TYPE' option to select the type of system they will produce code for and the build=TYPE' option to select the type of system on which you are compiling the package.
cache-file=FILE
Use and save the results of the tests in FILE instead of
./config.cache'. Set FILE to /dev/null' to disable caching, for
debugging configure'.
help
Print a summary of the options to configure', and exit.
quiet
silent
-q
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to /dev/null' (any error
messages will still be shown).
srcdir=DIR
Look for the package's source code in directory DIR. Usually
configure' can determine that directory automatically.
version
Print the version of Autoconf used to generate the configure'
script, and exit.
configure' also accepts some other, not widely useful, options.
http://lightconsulting.com/thalakan/code.html
The protocol has two basic types of messages, ``*MON'' packets and ``*BUD'' packets. The MON packets are Bayonne's way of saying ``Hi, I'm here, and here's what I'm doing''. They contain the state of the current ports, the version of Bayonne, and other useful status information.
BUD packets are used as part of the Bayonne buddy election protocol. If Bayonne detects at least one other copy of itself via MON broadcast packets, all copies will initiate the buddy election procedure. This will cause FIXME what? Failover? I don't understand the code.
time\_t update;
The string ``*MON'' or ``*BUD'', indicating the type of packet.
char name[16];
The name of the Bayonne node. This is usually the hostname of the machine, although this can be overridden in bayonne.conf if you, say, had more than one instance of Bayonne running on a machine.
struct in\_addr addr;
FIXME I'm not sure... seems to be used only for BUD packets.
unsigned char version;
The protocol version used. Should be 1 in the endian of the sending machine.
unsigned char buddies;
The number of other Bayonne nodes found so far by the sending node.
unsigned char ports;
The number of DSO ports this instance of Bayonne has running.
char stat[255];
A string indicating the current state of all the DSO ports on the sending instance of Bayonne. Each port gets one character see the source code for your driver to figure out what characters mean which states. For example ``-'' means idle and ``p'' means play for most drivers. Note that only the characters up to the number of the ports on the machine are filled in, the remainder are blank.
If you intend to run Bayonne on a big system with more than 255 ports and want to change the size of this statnode_t member, note that if the packet becomes larger than the UDP MTU for your network medium (1514 for Ethernet), you will have fragmented UDP broadcasts being sent. This shouldn't usually be a problem, but someone had to stick a warning in the manual :)
The Bayonne driver architecture uses a ``plug-in'' style interface to abstract driver-specific details from the ccScript application accessing the hardware. Each plug-in provides state handlers for each call state (ringing, playing audio, conferenced, etc) and possibly an event thread.
All Bayonne drivers have a static instance of their driver class defined at the bottom of driver.cpp. For example, the Voicetronix driver has the following statement at the bottom of its driver.cpp file:
VPBDriver vpbivr;
The VPBDriver class (which represents the driver for all Voicetronix cards in the system) inherits from the Driver class, so a call to the Driver class constructor is triggered when the Voicetronix driver is opened. This is a feature of most UNIX implementations of C++. On those platforms (which are at least BSD and Linux), if at run-time, a shared object containing a static instance of a class is loaded, that class' constructor will be called as well as constructors for any parent classes.
The Driver class constructor is defined as follows:
Driver::Driver() : aaScript() { active = false; if(driver) throw(this); groups = NULL; driver = this; status = NULL; memset(spans, 0, sizeof(spans)); memset(cards, 0, sizeof(cards)); }
The ``driver'' variable seen here is of type ``Driver *'' and is a static global variable defined in bayonne.h. After pointing the ``driver'' global pointer to the instance of the driver containined in the driver plug-in, the result is that the rest of the bayone code (mainly in server.cpp) can now access the underlying driver via the abstraction functions defined in class Driver. The two most important functions are start() and stop(), which allow Bayonne to control a driver's active state. There are also several ``get'' functions defined in class Driver which allows Bayonne to interrogate a driver's capabilities and port count. To recap, here's a summary of the driver start-up sequence:
1) The driver DSO is loaded via plugins.loadDrivers().
2) This results in a call to Driver::Driver().
3) This causes the global ``driver'' pointer to point to the newly created instance of the child class driver.
4) The child class driver constructor (e.g. VPBDriver::VPBdriver()) is called. This is where ports actually get initialized and the hardware is prepared to begin receiving calls.
5) Bayonne calls driver->start().
6) This results in a call to the driver-specific start() function, because Driver::start() is declared virtual. In the case of the Voicetronix driver, this is VPBDriver::start(). Any event threads are started up and the hardware begins processing calls.
The proposed solution is to create a libbayonne.so and have a simple wrapper program that starts up Bayonne and links in the drivers at run-time. This has not been completed as of yet.
Each state's state handler is a function of the name ``Trunk::stateHandler'', where Trunk is the driver's trunk class (DialogicTrunk, VPBTrunk), and ``state'' is replaced with the state name that will be handled. For example, the ring handler for the capi driver is CapiTrunk::ringHandler. The state handlers are handed arguments of type TrunkEvent, which contains the event ID and a union containing data the event handler will need to serve the event (such as digits to be dialed or timeout durations).
Each state handler is initially called with an event type of TRUNK_ENTER_STATE by postEvent, which gives the state handler a chance to set up anything it needs to service other events while in that state. postEvent and the event thread(s) (if any) then continue to call the event handler as events come in and need to be processed. Note that the execution of the state handler (or rather the ``handler'' function pointer defined in the Trunk coass for the driver) is protected by a mutex so that it is not possible to have more than one state handler executing concurrently on a given trunk.
However, state handlers do execute concurrently across trunks. That is, a machine with 4 analog trunks will most likely have four trunk threads going simultaneously, possibly served by a single event thread. The programmer is urged to keep in mind the current thread context whenever dealing with data that could possibly be accessed by several trunks simultaneously, and use mutexes as appropriate to protect the data.
accept
Supported by: dialogic
Comes from: step
Goes to: step
Accepts an incoming ISDN call and opens up a timeslot for it. See reject.
answer
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Places the port off-hook.
busy
Supported by: dialogic, dummy, phonedev, pika, vmodem, vpb
Comes from: idle
Goes to: idle
Busies out the port so incoming calls are denied. For analog cards,
places the port off-hook. For digital cards, FIXME does what?
collect
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Begins collecting digits into the digit buffer. When the specified
number of digits has been collected or the specified timeout has
occured, stops collecting digits and continues executing the script.
detect
Supported by: capi20 (broken), pika (broken)
Comes from: dial, step
Goes to: step
For the Pika driver, handles tone events from the event thread. The
reference in the capi20 driver is an anomaly and will be removed.
dial
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: flash, step
Goes to: step
Dials DTMF digits.
duplex
Supported by: capi20, pika
Comes from: step
Goes to: step, exit
Begins recording and playing audio. Its presence in the capi20 driver
is an anomaly.
exit
Supported by: pika
Comes from: duplex, play, record
Goes to: play
FIXME: not sure
flash
Supported by: aculab (broken),
Comes from: step
Goes to: step, dial
Does a hookflash.
flashon
Supported by: capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: dial, step, flashoff
Places the port temporarily on-hook to start a hookflash.
flashoff
Supported by: dialogic, dummy, phonedev, pika, vpb
Comes from: flashon
Goes to: dial, step
Places the port back off-hook at the end of a hookflash.
hangup
Supported by: aculab, capi20, dialogic, dummy, oh323, phonedev, pika, rtp, vpb
Comes from: hangup, seize, dial, step
Goes to: idle
Places the port on-hook (analog cards) or shuts down the timeslot
(digital cards).
idle
Supported by: all drivers (this is a required state)
Comes from: driver startup, hangup, ring
Goes to: busy, seize, step, release, ring
Stops activity on the port and shuts down any executing script images.
join
Supported by: aculab, capi20, dialogic, pika, vpb
Comes from: step
Goes to: step
Joins two ports together so they can hear and speak to each other.
The target port must be in the ``wait'' state.
load
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Loads an XML service. See the section on web services in this manual.
play
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Begins playing audio from a file.
playwait
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step, play
Waits for the completion of a play service thread.
record
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Begins recording audio to a file.
reject
Supported by: dialogic
Comes from: step
Goes to: step
Rejects an incoming call via the digital signalling channel. See
accept.
release
Supported by: dialogic
Comes from: (nowhere)
Goes to: idle
FIXME: Doesn't seem to be called from anywhere in the Dialogic driver.
ring
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vmodem, vpb
Comes from: idle
Goes to: step, idle
Recognizes an incoming ring event and increments the ring counter,
then determines whether to start up a script. In some drivers (such
as Voicetronix), captures caller ID.
rtp
Supported by: vpb (broken)
Comes from: (broken)
Goes to: (broken)
Connects a call with a RTP stream. Doesn't work right now.
seize
Supported by: dialogic, dummy, phonedev, vmodem, vpb
Comes from: idle
Goes to: step, hangup
Grabs a port in preparation for outbound dialing.
sleep
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Waits for a specified duration or number of rings.
step
Supported by: all drivers (this is a required state)
Comes from: all states
Goes to: most states
Executes the next step in the script image and changes the current
state if needed. This is probably the most frequently used state.
tone
Supported by: aculab, capi20, dialogic, pika, vpb
Comes from: step
Goes to: step
Generates a tone of user-specified frequency and duration.
wait
Supported by: phonedev, vpb
Comes from: step
Goes to: step, dial
FIXME: I'm not sure what's going on in the phonedev driver, but the
vpb driver is placed into the wait state in preparation for a join
from another port.
ccscript itself offers a programming model that is easy to embed in C++, that is fully thread safe, and that can be extended thru C++ class inheritance. It also offers extremely low call overhead, and has a two phase compile/memory resident runtime environment. Finally, ccscript allows direct runtime reloading of script images without displacing currently executing scripts.
In the case of Bayonne, we extend ccscript to support telephony functions of the server. The main server offers extensions to the core ccscript language, and each driver can also bind it's own driver specific commands. In some cases plugins other than drivers will also bind extensions to the script interpreter.
When the server is started, or when a new "compile" request is made, the server builds the core memory script image. While runtime replacement will happen in a live Bayonne server, it will only occur when a "compile" request is made thru the fifo interface.
Each script is composed of three parts; an event flag as appropriate, a script command statement, and script command arguments.
The exception to this rule is hangup and error events. These cannot be blocked, and will always execute except from within the event handlers for hangup and/or error themselves. Event handlers can be thought of as being like "soft" signals.
In addition to marking script locations, the script "event mask" for the current line can also be modified. When the event mask is modified, that script statement may be set to ignore or process an event that may occur.
The following event identifiers are considered "standard" for Bayonne:
identifier | default | description |
hangup or êxit | detach | the calling party has disconnected |
^error | advance | a script error is being reported |
^dtmf | - | any unclaimed dtmf events |
^timeout | advance | timed operation timed out |
^0 to 9, a to d | - | dtmf digits |
^pound or star | - | dtmf "#" or "*" key hit |
^tone | - | tone event heard on line |
^busy | - | busytone heard on line |
^signal | detach | notify while waiting for other trunk |
^part or cancel | detach | conference/join disconnect |
^fail or învalid | advance | failed process |
^event | - | event message received |
^child | - | notify child exiting |
ccscript also recognizes symbol scope. Local symbols are created within symbol scope, resulting in unique instances within subroutines. In addition, all local symbols in symbol scope are removed when returning from a subroutine. global symbols are visible everywhere under the same instance. A ``global'' symbol uses ``.'' notion, as in %myapp.name, where a ``local'' symbol uses a simple name, as in %name, for example. Generally it is suggested that a given script should organize it's global symbols under a scriptname.xxx format to make it easier to read and understand.
A fourth class of symbol exists only at compile time, $defined symbols are substituted when the script file is compiled, and usually reduce to a simple constant, though variables can be named for the compiler. All constants are defined in the [script] section of bayonne.conf.
You can concatenate symbols and constant strings with either non-quoted whitespace or the comma operator. For example,
set %a ``a'' ``b'', ``c''
results in %a being set to ``abc''.
The following variables are commonly defined:
%session.id | id, timeslot, or trunk device number |
%script.error | last error message |
%session.date | current date |
%session.time | current time |
%return | return value of last libexeced TGI script |
%session.gid | global call identifier |
%session.digits | currently collected dtmf digits in the digit buffer |
%session.count | count of number of digits collected |
%session.starttime | time of call starting |
%session.startdate | date of call starting |
%session.duration | current call duration |
%session.callerid | identity of calling party |
%session.calledid | identity of how they called us |
%session.home | initial script invoked |
%session.schedule | script that was scheduled |
%pstn.dnid | did number if available |
%pstn.clid | ani or caller id number if available |
%pstn.name | caller name if passed in callerid |
%pstn.redirect | if origin is a telco redirect |
%pstn.ringid | if distinctive ringing is available |
%pstn.infodigits | if telco infodigits were passed to us |
%pstn.rings | number of rings so far |
%policy.name | name of policy for this session |
%policy.member | nth member of this policy |
%policy.* | various policy variables. |
%session.language | current language in effect (default = "english") |
%session.voice | current voice library in effect (default = "UsEngM") |
%audio.volume | volume level in 0-100 for play and record. |
%audio.extension | default audio file extension (.au, .wav, etc) |
%audio.format | default audio format (ulaw, alaw, g721, etc) |
%audio.annotation | annotation of last played or for recorded file |
%audio.played | samples played from played file |
%audio.recorded | samples recorded to record file |
%audio.created | date played file was created |
%audio.timeout | timeout in a play wait |
%audio.trim | minimal number of samples to trim at end of file |
%server.ports | total ports on bayonne server |
%server.version | version of bayonne server |
%server.software | software identifier; "bayonne" |
%server.driver | which driver we are running |
%server.node | node id of our server |
In addition, DSO based functions will create variables for storing results under the name of the function call, and the DSO lookup module will create a %lookup object to contain lookup results. Also, server initiated scripts can pass and initialize variable arguments.
set %var values...
set var=value ...
set[.min|.max] %var values...
Set a variable to a known value. Can also set multiple variables.
Can also set a variable to the minimum or maximum value of
a set of values.
clear %var ...
Clear (empty) one or more variables. It does not
de-allocate. This means that if you need to determine whether
a variable is ``there'' or not in a TGI script which is passed
the variable, the empty string is equivalent to a nonexistent
variable. For example (using the Perl TGI module):
cleartest.scr:
set %var ``abcdefg'' clear %var libexec 10 mytgi.pl %somevar
mytgi.pl:
use TGI; my $var = $TGI::QUERY { 'var' } if($var eq '' || $var eq '(null)') { $var = undef; } if(defined $var) { # do whatever you need to do... }
The first if() block in mytgi.pl will be executed because %var is actually passed to the TGI application. However, no value is passed for the variable, which causes the TGI parser to assign the empty string (or the special string ``(null)'' in some cases) to the variable.
init %var values...
init var=value ...
init[.min|.max] %var values...
Initialize a new system variable with default values. If the
variable already exists, it is skipped. Optionally multiple
variables may be initialized at one. Can also init a variable
to a minimum or maximum value of a set of values.
const %var values...
const var=value ...
Set a constant which may not be altered later. Alternately
multiple constants may be initialized.
stack[.size] count %var [value ...]
Create a ccScript ``stack'' variable. Stack variables are lifo
objects and unwind automatically on reference.
fifo[.size] count %var [value ...]
Create a ccScript fifo ``stack'' variable. This creates a variable
that automatically unwinds from first in to last in when referenced.
array[.size] count [values...]
Create a ccScript array composite object.
list[.size] values ...
Create a ccScript array composite with constant values.
sequence[.size] count %var [value ...]
Create a ccScript repeating sequence variable. This repeats content
of a sequence in the order set.
cache[.size] count %var [value ...]
Create a ccScript fifo cache variable. This creates a variable
that logs and returns content in reverse order.
counter %var
Create a variable that automatically increments as it is referenced.
arm %var
Arm a variable so that it will auto-branch if modified.
disarm %var
Disarm an armed variable.
dup %var %dest
Duplicate an existing object into a new one.
post %var value ...
Post one or more additional values into a stack, fifo, sequence,
or cache.
remove %var value ...
Remove a specific value entry from a stack, fifo, sequence, or
cache variable.
ref %ref components ...
This can be used by a subroutine to form a local instance of a
reference object that points to a real object in the public name
space by building a target public object name from components that
are then glued with ``.'' notation. This is different from an
alias since a simple named alias can only reference the local scope
in a subroutine.
alias %name value
Create an alias symbol name that points to a real symbol name when
referenced. The alias and target must be in the same scope, hence
local aliases cannot reference global objects in subroutines.
size space %var...
Pre-allocate "space" bytes for the following variables.
select value match label [..match-label pairs] [var=val...]
Select is used to branch to a new script based on matching a value
or variable to a list of possible values. For each match, a different
script or event handler may be selected. Options include
"select.prefix" to match string prefixes, "select.suffix" to match
by tailing values only, "select.length" to match by length,
and "select.value" to match by numeric value. If a branch is
found, an optional list of variables can be conditionally set.
inc[.day|.hour|.min|.sec] %timevar [offset]
Increment a variable, perhaps with a specified offset,
otherwise by "1". Inc is aware of "time" units and can
adjust dates by number of days, or times by hours, minutes,
or seconds.
dec[.day|.hour|.min.sec] %timevar [offset]
Decrement a variable, perhaps with a specified offset,
otherwise by "1". Dec is aware of "time" unites and can
adjust dates by number of days, or times by hours, minutes,
or seconds.
goto value [var=value ...]
Goto a named script or event handler in a script. If the
goto is successful, an optional list of variables can be
conditionally set.
try values... [var=value ...]
Attempt to goto one or more labels. If the label is not found
in an existing script, the next one in the list will be tried.
If any branch attempt is successful, then optionally variables
may also be set.
gosub[.public|.protected] value [var=value ...]
call[.public|.protected] value
Call a named script or event handler as a subroutine. If the
call is successful, an optional list of variables can be
conditionally set. ``.public'' can be used to specify that
the subroutine is ran without a local stack, and ``.protected''
can be used to share the current stack with the subroutine
directly rather than having it create a new local context.
load[.get|.post] timeout url [variables]
Invoke a URL thru the plugin XML parser. This internally creates
a special script set. Either the get or post method may be
used, and an optional set of variables may be specified for the
method.
return [label]
Return from a gosub. You can also return to a specific label or
handler within the parent script you are returning to.
pop
Pop a gosub off the stack.
use modulename ...
Load one or more ``.pkg'' ccScript generic shared command extension
packages. These are loaded from /usr/lib/ccscript2/modulename.pkg.
Modules exist for date and time manipulation, for url string encoding,
and file manipulation.
skip [label]
Skip may be used alone to skip over a case statement. This is
similar to what c/c++ does with cases if no intervening break is
present. Since ccScript automatically behaves as if break is
present, skip is needed to flow into another case. The second
use of skip is to branch to a local label as defined by the
label keyword.
label value ...
Create a named local label to receive a skip command request.
if value op value [and | or ...] label [var=value ...]
Used to test two values or variables against each other and
branch when the expression is found true. There are both
"string" equity and "value" equity operations, as well as
substring tests, etc. Optionally a set of variables can
be initialized based on the conditional branch. Multiple
conditions may be chained together using either and or
or.
if value op value [and | or ...] then [script command]
Used to test two values or variables against each other and
execute a single statement if the expression is true. Multiple
conditions may be chained together using either and or
or.
The valid values for the op argument come in two flavors: ``shell style'' and ``c style''. The two styles for a given type of operator are exactly alike and trigger the same code segment (e.g. both -ne and <> do exactly the same thing). For consistency, it is recommended that only one style is used throughout a given application.
-eq / =
Returns true if the two numeric arguments are equal. Uses
atol(3) to convert the two arguments to numbers before
comparison. Note that this will result in non-numeric strings
being treated as equal when in fact they are not because
atol() returns 0 if it cannot convert a string to a number.
-ne / <>
Returns true if the two numeric arguments are not equal.
Uses atol(3) to convert the two arguments to numbers before
comparison. Note that this will result in non-numeric strings
being treated as equal when in fact they are not because
atol() returns 0 if it cannot convert a string to a number.
.eq. / ==
Returns true if the two alphanumeric arguments are equal.
Uses stricmp(3) to do the comparison. This operator is
case-insensitive. Note that older versions of the parser may
have problems with the ``=='' version of the operator due to
how ccScript used to handle equal signs. If you don't get the
expected results, use ``.eq.'' instead.
.ne. / !=
Returns true if the two alphanumeric arguments are equal.
This operator is case-insensitive.
$
Returns true if the string given by the left argument is
found in the string given by the right argument using
strstr(2). This operator is case-sensitive. Example:
set %a ``Hello'' set %b ``Hello World!'' if %a $ %b ::next # returns true set %a ``World'' set %b ``Hello World!'' if %a $ %b ::next # returns true set %a ``hello'' set %b ``Hello World!'' if %a $ %b ::next # returns false slog ``Could not find string'' # This gets printed
$< / $+
Returns true if the argument on the left is found in the
argument on the right using strnicmp(3). If the argument on
the left is shorter than the argument on the right, only the
first n characters will be compared, where n is the length of
the argument on the left. This operator is case-insensitive.
Example:
set %a ``abc'' set %b ``abc123'' if %a $< %b ::next # returns true set %a ``abcdef'' set %b ``abc123'' if %a $< %b ::next # returns false
$> / $-
Returns true if the argument on the left is found in the
argument on the right using strnicmp(3). If the argument on
the left is shorter than the argument on the right, then only
the n rightmost characters will be compared, where n is the
length of the argument on the left. This operator is
case-insensitive. Example:
set %a ``123'' set %b ``abc123'' if %a $> %b ::next # returns true set %a ``abcdef'' set %b ``abc123'' if %a $> %b ::next # returns false
-lt / <
Returns true if the numeric argument on the left is less than
the numeric argument on the right.
-le / <= / =<
Returns true if the numeric argument on the left is less than
or equal to the numeric argument on the right.
-gt / >
Returns true if the numeric argument on the left is greater than
the numeric argument on the right.
-ge / >= / =>
Returns true if the numeric argument on the left is greater than
or equal to the numeric argument on the right.
if value op value [and | or ...]
then
else
endif
Used to test two values or variables against each other and
start a multi-line conditional block. This block is enclosed
in a ``then'' line and completed with a ``endif'' line. A
``else'' statement line may exist in between.
for %var values...
Assign %var to a list of values within a loop. A for loop may
include case statements.
foreach[.offset] %var %packed
Assign %var from items found in a packed list. An optional
offset can be used to skip the first n items. A foreach loop
may include case statements.
tryeach[.offset] %packed [var=value ...]
Attempt to branch to a script based on the values held in a
packed list. Each item will be tried in term, starting from
the offset if one is specified. If a branch point exists
an optional list of variables may be conditionally initialized.
do [value op value]
Start of a loop. Can optionally have a conditional test (see if). A
do loop may include case statements.
loop [value op value][ and | or ...]
Continuation of a for or do loop. Can optionally have a
conditional test (see if).
continue [value op value][ and | or ...]
Continue a loop immediately. Can optionally have a conditional
test (see if).
break [value op value][ and | or ...]
Break out of a loop. Can optionally have a conditional test (see
if).
case [value op value][ and | or ...]
The case statement is a multiline conditional branch. A single
case (or otherwise) line can be entered based on a list
of separate case identifiers within a given do or for loop.
slog[.info|.err|.crit|.debug message...
Port a message to the system log as a SYSLOG message. The
logging level can be specified as part of the command. If
Bayonne or the stand-alone ccScript interpreter are running on
a console or under initlog(8), the messages will be output on
the standard error descriptor, not standard output. Note that
you cannot use % characters in the strings to be outputted.
exit
Terminate script interpreter.
hangup
This is the same as exit, though it can be "trapped" with a hangup handler.
audit[.log|.clear|.post] key1=value1 key2=value2...
Declare or post a CDR record.
import %var ...vars
Import a variable value from "global" name space. Normally each
Bayonne trunk has it's own private name space.
export %var ..vars
Export one or more variables into the "global" name space.'
debug message..
Send a message to the debugging monitor.
sleep timeout [rings]
Sleep a specified number of seconds. Can also sleep until the
specified number of rings have occurred. Millisecond timeouts
may also be specified using ms, as in ``100ms''.
sync timeout [rings]
Wait for a specific number of seconds from the time the call
was initiated. This is a time synchronized form of "sleep".
A specific number of rings can also be waited for.
pack %var values...
Form comma separated content in a packed %var.
unpack[.offset] %var targets
Unpack a common separated variable object into separate variables.
Sometimes operations like "lookup" will return a list of values
or data fields.
packed char
Allows one to specify an alternate delimiter for packing and
unpacking data fields.
once label
Within a single script, once is guaranteed to only goto a new
script (like a goto) "once".
on trap label
Allows one to test for a previously blocked signal and see if
it had occurred. If the signal had occurred, then the branch
will be taken.
answer [rings [ringtime]]
Answer the line if it has not been answered yet. Optionally wait
for a specified number of rings before answering, and allow a
maximum inter-ring timeout before considering that ringing has
"stopped". If the rings are stopped before the count has been
reached, then the call is treated as a hangup (abandon).
collect digits [timeout [term [ignore]]]
Collect up to a specified number of DTMF digits from the user.
A interdigit timeout is normally specified. In addition, certain
digits can be listed as "terminating" digits (terminate input),
and others can be "ignored".
flash offtime ontime
Flash the line a specified number of milliseconds (offtime) and
then wait for ontime. If dialtone occurs, then may be used as
a branch.
play[.any|.all|.one|.tmp] audiofile(s)
Play one or more audio files in sequence to the user. Bayonne
supports raw samples, ".au" samples, and ".wav" files. Different
telephony cards support different codecs, so it's best to use
ulaw/alaw files if you expect to use them on any Bayonne server.
Optionally one can play any of the messages found, or only the
first message found, or a temp file which is then erased after
play.
record[.append] audiofile [timelimit [abort]]
Record user audio to a file, up to a specified time limit, and
support optional abort digits (DTMF). Optionally one can
append to an existing file.
dial number [..more digits]
Dial the specified telephone number. A "F" may be used to flash
the line, and a "W" to specify a wait for dialtone.
dtmf digits [...more digits]
Generate DTMF digits, like with dial, but do not perform call
progress analysis.
transfer number [..more digits]
Dial the specified telephone number and then exit. This is in
effect a "blind" transfer/call release, and should use appropriate
digits to achieve this effect.
hold
Put a call on hold and release the trunk. Script can be restarted
by a hold-recall from the pbx, for example...
map[.prefix|.suffix|.absolute] mapname keyvalue [prefix..]
lookup a key value in a named map table. Optionally strip off
a "prefix" from the keyvalue before searching if the prefix
value is found. When the key is found in the map table, the
specified script is executed with map variables set. Suffix
mapping can be used to reduce a route by the reverse order
digits.
start[.offset|.group|.wait] [expire] offset|group script [parms]
start a script on another trunk port as offset from the current
port %id or by issuing a request against another trunk group.
Hence "start 1 test" starts script test on the port next to the
current one, for example. Normally, a large offset like
"start 24 test" might be used to start a script on the next
T span. Start can start a script immediately, or time delayed as
a queued request. A ``var=varname'' can be used to save the started
session id to a variable.
libexec[.once|.play] timeout program [query-parms]
Execute an external application or system script file thru the
Bayonne TGI service. This can be used to run Perl scripts,
shell scripts, etc. A timeout specifies how long to wait for
the program to complete. A timeout of 0 can be used for
starting "detached" commands. Optionally one can set libexec
to execute only one instance within a given script, or use
.play to run an external tgi that will generate an audio file
which will then be played and removed automatically when the
tgi exits. IMPORTANT: There is currently a bug that will
cause bayonne to segfault inexplicably if you return a TGI
variable without a value. Make sure that your TGI script
returns a value that takes up a space of one character or
more.
speak[.any|.all] phrasebook-rules words...
Used to implement phrasebook rules based prompt generation. See
PROMPTS.TXT.
tone tone-name [duration-msec [repeat]]
This can be used to emit tones defined from the bayonne.conf file.
has keyword label
Perform a branch operation if a specified keyword exists (as in
a test for a bound module).
missing keyword label
Perform a branch operation if a specified keyword is missing.
schedule name or *
Select alternate scheduling "name" to be in effect or use "*"
to clear.
signal trunk [msg]
Send a signal to a trunk in a wait state such as joinable.
idle timeout
Set idle timeout value.
read %var...
read.from script
Read data lines embedded in a script into a set of variables.
One can also specify the script to start reading from.
data values...
Embed data for a read statement in a script.
gather %packed member
Gather a packed list of the names of all scripts that contain
a specific or named ::member script. This can be used to
determine what scripts or apps are present and to generate
a menu based on that at runtime.
swap %var1 %var2
Swap two variables.
alias %var %newvar
Alias a variable so that every reference to %var will
automatically goto %newvar.
dirname %var
Much like the shell dirname, to extract a directory name
from a path.
basename %var [extensions...]
Reduce a variable to a simple base filename, and strip any
of the optionally listed extensions from it.
fullpath %var fullpath
If %var is a partial pathname, then merge it with the passed
path to form a complete pathname.
insert[.offset|.end] %var values...
This can be used to insert new digit values into a string
either at the start, or a specific offset.
delete[.offset|.end] %var patterns...
This is used to strip patterns of digits either from the start
or a specific offset in, a digit string. If a given pattern
is found, it is removed.
chop[.offset|.end] %var count...
This is used to chop out a specific count of digits from within
a string.
trim[.offset|.end] %var count..
This is used to trim leading and trailing digits outside of
the range of count and offset specified. It's the inverse of
chop.
join trunk duration
Join a joinable trunk for a specified duration.
wait duration
Indicate we are joinable for a specified duration.
rtp address portnbr [portbind]
Connect a telephony port to a RTP session directly.
duplex recordfile [playfiles...]
Simultaneous play and record.
enter id
Join a TDM conference resource.
leave
Leave the currently joined conference.
detect timeout
Perform call progress detection for a specified timeout.
The collect command adds to %session.digits, it doesn't overwrite it. Make sure that you're clearing %session.digits before each collect (unless you really do intend to append).
Don't use '=', use '-eq' to check for equality. Also, '==' is broken in older versions of Bayonne. Use '.eq.' instead.
Are you confusing the name of a script (like ``foo'') with a label name (like ``::foo'')?
Remember that the pound sign is used as a comment character. Things like ``dial #'' don't work because ccscript thinks you're starting a comment. Quote the ``#'' character instead.
Make sure you are using the *::foo syntax when playing prompts, and that you have %application.language set properly. ``play foo'' is almost certainly not going to do what it looks like it should do. Use ``play *::foo'' instead.
Make sure that if you use a variable returned by a TGI script that the TGI script defined it. Otherwise bayonne dumps core (as of 0.6.4).
Did the ccscript engine print out any interesting error messages during startup or 'bayctrl compile'? Perhaps you should review them.
Did you remember to run 'bayctrl compile' or to restart bayonne after you modified your script?
If you do things like "goto script", and script.scr looks like this:
::start do stuff do stuff ^event ^event goto script
The goto will fail. Instead, say "goto script::start".
Make sure that after you deal with an event, the script jumps somewhere. If the path of execution falls off the bottom of the file (or hits another label), then the script engine will jump back to the beginning of the file (or the current label) ad infinitum. Keep in mind that you are developing a telephony application, and you must be constantly interacting with the user or they think you've hung up on them.
When jumping as the result of a conditional (like "if %return -eq 1 goto main"), you don't say ``goto''. State it in the form "if %return -eq 1 main". The goto is implied after the if conditional.
If you're using Perl and it's DBI module for doing database accesses through TGI, here's one way you can retrieve data from the database via fetchall_arrayref(). The syntax seems to be easily forgettable for some reason.
$ref = $sth->fetchall_arrayref(); $row0_col0 = $$ref[0][0]; $row1_col1 = $$ref[1][1]; $row0_col1 = $$ref[0][1];
The standard way to get digits so the caller can interrupt the message is:
clear %session.digits play *::1 # "Press 1 for foo, press 2 for baz, press 3 for gronk..." sleep 60 ^dtmf collect 1 5 "*#" "ABCD" if %session.digits -eq 1 ::label1 if %session.digits -eq 2 ::label2 goto ::invalid
The standard way to get digits so the caller can't interrupt the message is:
clear %session.digits play *::1 # "Press 1 for foo, press 2 for baz, press 3 for gronk..." collect 1 5 "*#" "ABCD" if %session.digits -eq 1 ::label1 if %session.digits -eq 2 ::label2 goto ::invalid
It's a good idea to document your TGI return values in your program header. Make a template for all your TGI programs and stick to it. Make sure there's a section for the return values in the headers and use it. One convention seen around the OST code is to use 1 for a successful call, 0 for an unsuccessful call, and -1 for an internal script error.
Remember that the value of the %return variable is persistent. If you aren't careful, your TGI scripts will fall through without setting a return value. This is especially annoying if you forget to set a return value which means "operation successful" If you don't see a line like this in the server logs:
fifo: cmd=SET&2&return&1
Then your TGI script isn't setting a return value. The ccscript that's executing your TGI will then use the return value from the last ccscript you executed, which is just hours of debugging fun. Especially when one of your TGIs is working just fine (but doesn't set a return value) and your ccscript checks the return value to see if an error occurred, and guess what, it's the return value from the TGI script you called before the current one. Chances are that that return value doesn't have anything to do with the return value from the TGI script you just executed, which leads to very confusing results.
Document your database schema. Make sure that you put the column indexes into the database schema document, and you include a Big Fat Warning that tells any potential modifiers of said document that if they touch the document, they get to audit any database access code that uses hard-coded column indexes. The idea is that if they change the database schema, those column indexes may no longer be valid. An even better solution (if your TGI language supports it) is to define a set of symbolic constants for the database columns in one file and include the constant definitions in all the database access code.
Phrase rules can be placed in bayonne.conf proper under the appropriate language and in application specific conf files as found in /etc/bayonne.d. English "rules" are found under section [english] in the .conf files, for example.
Phrasebook prompts are used to build prompts that are effected by content. Lets take the example of a phrase like "you have ... message(s) waiting". In english this phrase has several possibilities. Depending on the quantity involved, you may wish to use a singular or plural form of message. You may wish to substitute the word "no" for a zero quantity.
In Bayonne phrasebook, we may define this as follows:
in your script command:
speak &msgswaiting %msgcount no msgwaiting msgswaiting
We would then define under [english] something like:
msgswaiting = youhave &number &zero &singular &plural
This assumes you have the following prompt files defined for your application:
youhave.au "you have"
no.au "no"
msgwaiting.au "message waiting"
msgswaiting.au "messages waiting"
The system will apply the remaining rules based on the content of %msgcount. In this sense, phrasebook defined rules act as a kind of "printf" ruleset. You can also apply rules inline, though they become less generic for multilingual systems. The assumption is that the base rules can be placed in the [...] language area, and that often the same voice prompts can be used for different effect under different target languages.
The speaking of numbers itself is held in the default Bayonne distribution, though the default prompt list can also be replaced with your own. Rules can also appear "within" your statement, though this generally makes them non-flexible for different languages.
Speaking of currency "values" have specific phrasebook rules. Currency values are also subject to the "&zero" rule, so for example:
balance=youhave &cy &zero remaining
and using:
speak &balance %balance nomoney
can use the alternate "no monay" .au prompt rather than saying "0 dollars".
&number | speak a number unless zero |
&unit | speak a number as units; zero spoken |
&order | speak a "order", as in 1st, 2nd, 3rd, etc. |
&skip | skip next word if spoken number was zero. |
&ignore | always ignore the next word (needed to match multilingual). |
&use | always use the next word (needed to match multilingual). |
&spell | spell the word or speak individual digits of a number. |
&zero | substitute a word if value is zero else skip. |
&single | substitute word if last number spoken was 1. |
&plural | substitute word if last number spoken was not 1. |
&date | speak a date. |
&day | speak only day of the week of a date. |
&weekday | speak the current day of the week. |
&time | speak a time. |
&primary | speak primary currency value (dollar(s) and cent(s)) |
&local | speak local currency |
&duration | speak hours, minutes, and seconds, for duration values. |
&cy | speak default currency (either primary, local, or both) |
The TGI equivalent of ``Hello World'' in Perl using the TGI module is:
hello.scr:
answer 2 # pick up the phone libexec 10 hello.pl slog %return
hello.pl:
use TGI; use lib $ENV{'SERVER_LIBEXEC'}; TGI::set(return => 'Hello World!');
This will cause the message 'Hello World!' to be slogged from Bayonne. Here's a more complex example:
hello.scr:
answer 2 set %a 1 set %b 1 libexec 10 adder.pl %a %b if % return -eq -1 ::error slog %return # outputs ``2'' ::error play *::999 # ``An error has occured, please see the server error log for details.'' slog ``Something went wrong a couple lines ago. Bailing out.'' hangup exit
adder.pl:
use TGI; use lib $ENV{'SERVER_LIBEXEC'}; my $a = $TGI::QUERY{'a'}; my $b = $TGI::QUERY{'b'}; if(! defined $a || ! defined $b) { printf(``Missing either A or B or both.''); TGI::set(return => -1); exit(1); } TGI::set(return => $a + $b);
This should output the number 2. Note the extensive error checking.
Telephony applications are very unlike other computer applications in that they need to be more ``fail-soft'' than a traditional windowed application. In other words, only very serious errors such as an inability to contact a database server or a critical transaction failure should prevent the user from continuing with the telephone call. If a possible error really isn't that serious and it's possible to continue with the phone call even if it occurs, make sure to insert a comment noting that fact in your code.
The rule of thumb for handling TGI errors is: hanging up on users without telling them why is just plain rude. Don't do it. Make sure that you have consistency in your error handlers and that you always play a speech message indicating that something went wrong before hanging up. It's a good idea to have the generic error message include an instruction for the caller to ``call the people who are hosting the application with the current time'' as that will help them search the error logs for the output that occurred during the failed call.
use TGI.pm; use lib $ENV{'SERVER_LIBEXEC'}; TGI::set(return => 0); # 0 is the return value exit(0);
Variables set with the TGI::set method become accessible in the calling ccScript via the ccScript variable of the same name. In this example, the %return variable will be set to 0. These return values can be numbers or characters. You can return as many or as few variables as you want, but it's typical for an application to return a numeric error code in the %return variable so that error checking code after libexecs is more consistent.
This is done in the [wrappers] section of Bayonne.conf. Basically one enters the user id and a list of permitted scripts. This list of permitted scripts always execute from /usr(/local)/share/bayonne/aawrappers. Bayonne_wrapper itself runs as a setuid executable, and the scripts or shell commands found in aawrappers are given the user id of the Bayonne server. These scripts also receive useful information in their environment space that is similar to "TGI", but without port specific information.
In particular, a wrapper initiated image receives the server software and version information (BAYONNE_SOFTWARE, BAYONNE_PROTOCOL, BAYONNE_PLATFORM), the token separator to use for fifo control (BAYONNE_TOKEN), the Bayonne node id (BAYONNE_NODE), and the location of the Bayonne fifo and control files (BAYONNE_CONTROL). In addition, the defined trunk group policies are passed as "BAYONNE_POLICIES". No "PORT_xxx" symbols are passed since the wrapper script is not necessarily executing on behalf of a specific and dedicated port resource.
NOTE: These symbols were originally named "SERVER_" in bayonne_wrapper, but were changed to "BAYONNE_" starting with 0.5.17 to avoid conflicts with CGI initiated scripts.
A web server or any other application can use wrapper to invoke executables in aawrappers that manipulate the Bayonne server in a controlled and secure fashion. A wrapper can be invoked thru a CGI and then receive both the web server's CGI state information, and the Bayonne symbol set. A CGI executed wrapper of course can send html back thru stdout to form a web page for the user.
Starting with "0.5.17", Bayonne wrappers can also be used to execute scripts that require interpreters in a fairly direct fashion. For example, if we have a "webdial.cgi" script written in Perl, you will be able to specify as the first line of your script file:
#!/usr/bin/bayonne_wrapper -perl
This will re-execute the script with the Perl interpreter under the specified user id of Bayonne. Similarly, one can then use -bash for /bin/bash, and others for other common shells and interpreters. This provides a simple and direct means to integrate cgi operation with a Bayonne server. In fact, one could use the alias map of apache or other web servers to map the aawrappers directory under a "/bayonne" url as a convenient means to access commonly used wrappers in this way, and in the future some scripts will be provided in the default distribution of Bayonne for this purpose.
Bayonne_wrappers support the use of "ssh" to invoke a bayonne wrapper application on a Bayonne server from a remote machine. This is done by placing a truncated /etc/bayonne.conf file which indicates the node name of the Bayonne server it should contact, and the wrapper permissions to use. The "bayonne_wrapper" will assume to automatically use ssh if the /usr/share/aawrappers directory is not found on the local machine.
On the remote (web server) machine, you will need to create a bayonne "user id". This user id should contain a .ssh/config "entry" with the same name as the Bayonne "node" id in the local /etc/bayonne.conf file, and should list the hostname to actually contact.
You will also need a passwordless ssh key to use between the Bayonne server and the web server. This will allow the bayonne_wrapper to automatically hop between the machines.
The bayonne_wrapper can be symlinked or placed in the web server's cgi directory under the name you will execute the program in "aawrapper" on the Bayonne server under. Hence, you would take bayonne_wrapper, call it for example "webdial.cgi", and place it on the cgi directory of your web server. Since there is no local aawrappers directory, it will initiate a ssh to the Bayonne box and then execute the "real" webdial.cgi from the aawrappers directory there.
SSH does not automatically preserve environment state variables. While bayonne_wrapper has supported ssh for awhile, it is only with 0.5.17 and above does it now preserves key CGI environment variables when it hops between the local and remote machine.
Certainly one can execute and access Bayonne resources directly if one places a web server on a machine running Bayonne and then has it execute under the same user id that Bayonne does. This allows one to use one of the various highly efficient "mod_xxx" interpreters (like mod_php or mod_perl) to build a web integrated Bayonne service rather than requiring cgi wrappers everywhere.
Incidentally, Bayonne can of course alternately be executed under the same user id as the web server. Which one to change probably depends on your actual need. You can of course also run multiple web server daemons, and have one of them execute under Bayonne's user id.
GNU Bayonne ``2'' already includes an integrated http server which will be used to serve both XML encoded system management content and provide support for remote XMLRPC invocation. This interface uses authenticated http headers and can be used to integrate GNU Bayonne with web services directly.
For the desktop user, and to telephony enable desktop applications, like pop-up screens when calls come in, or dialing names from an address book, TOSI will be used, and Bayonne will offer a TOSI server for desktop applications to access using the TOSI interface library definition. I do not know if TOSI will also ever be used for the purposes of Web integration, but it is not impossible. GNU Bayonne ``2'' also supports a TCP command monitor which can be used to remotely access and control a running GNU Bayonne server.
This document was generated using the LaTeX2HTML translator Version 2002 (1.62)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -nosubdir -split 0 manual.tex
The translation was initiated by David Sugar on 2002-10-05