diff --git a/.gitignore b/.gitignore
index 053abd7afb6..fdc064bb037 100644
--- a/.gitignore
+++ b/.gitignore
@@ -143,6 +143,20 @@ Release/
/libs/libcodec2/unittest/Makefile.in
/libs/mpg123-1.13.2/
/libs/spandsp/src/cielab_luts.h
+/dll
+/test
+/libs/libbfcp/bfcpmsg/*.o
+/libs/libbfcp/bfcpmsg/*.obj
+/libs/libbfcp/bfcpmsg/libbfcp*
+/libs/libbfcp/bfcpmsg/testcode*
+/libs/libbfcp/bfcpsrvclt/bfcpclt/*.o
+/libs/libbfcp/bfcpsrvclt/bfcpclt/*.obj
+/libs/libbfcp/bfcpsrvclt/bfcpclt/libbfcp*
+/libs/libbfcp/bfcpsrvclt/bfcpclt/bfcp_participant
+/libs/libbfcp/bfcpsrvclt/bfcpsrv/*.o
+/libs/libbfcp/bfcpsrvclt/bfcpsrv/*.obj
+/libs/libbfcp/bfcpsrvclt/bfcpsrv/libbfcp*
+/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_server
/scripts/fsxs
/scripts/gentls_cert
diff --git a/build/modules.conf.in b/build/modules.conf.in
index 14ad5dd080b..ce36ef3e081 100644
--- a/build/modules.conf.in
+++ b/build/modules.conf.in
@@ -2,6 +2,7 @@
applications/mod_av
#applications/mod_avmd
#applications/mod_bert
+applications/mod_bfcp
#applications/mod_blacklist
#applications/mod_callcenter
#applications/mod_cidlookup
diff --git a/conf/vanilla/autoload_configs/bfcp.conf.xml b/conf/vanilla/autoload_configs/bfcp.conf.xml
new file mode 100644
index 00000000000..f4581fbf572
--- /dev/null
+++ b/conf/vanilla/autoload_configs/bfcp.conf.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/configure.ac b/configure.ac
index 7c7df126f5b..591fcc5bf9d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1853,6 +1853,7 @@ AC_CONFIG_FILES([Makefile
src/mod/applications/mod_abstraction/Makefile
src/mod/applications/mod_avmd/Makefile
src/mod/applications/mod_bert/Makefile
+ src/mod/applications/mod_bfcp/Makefile
src/mod/applications/mod_blacklist/Makefile
src/mod/applications/mod_callcenter/Makefile
src/mod/applications/mod_cidlookup/Makefile
diff --git a/freeswitch.spec b/freeswitch.spec
index 4fa22123058..8df6f4c6239 100644
--- a/freeswitch.spec
+++ b/freeswitch.spec
@@ -1498,7 +1498,7 @@ export QA_RPATHS=$[ 0x0001|0x0002 ]
######################################################################################################################
APPLICATION_MODULES_AC="applications/mod_abstraction applications/mod_avmd applications/mod_blacklist \
applications/mod_callcenter applications/mod_cidlookup \
- applications/mod_commands applications/mod_conference applications/mod_curl"
+ applications/mod_commands applications/mod_conference applications/mod_curl applications/mod_bfcp"
APPLICATION_MODULES_DE="applications/mod_db applications/mod_directory applications/mod_distributor \
applications/mod_dptools applications/mod_easyroute applications/mod_enum applications/mod_esf \
applications/mod_expr "
diff --git a/libs/libbfcp/.gitignore b/libs/libbfcp/.gitignore
new file mode 100644
index 00000000000..51a4a986a2c
--- /dev/null
+++ b/libs/libbfcp/.gitignore
@@ -0,0 +1,15 @@
+/dll
+/test
+/bfcpmsg/*.o
+/bfcpmsg/*.obj
+/bfcpmsg/libbfcp*
+/bfcpmsg/testcode*
+/bfcpsrvclt/bfcpclt/*.o
+/bfcpsrvclt/bfcpclt/*.obj
+/bfcpsrvclt/bfcpclt/libbfcp*
+/bfcpsrvclt/bfcpclt/bfcp_participant
+/bfcpsrvclt/bfcpsrv/*.o
+/bfcpsrvclt/bfcpsrv/*.obj
+/bfcpsrvclt/bfcpsrv/libbfcp*
+/bfcpsrvclt/bfcpsrv/bfcp_server
+*~
diff --git a/libs/libbfcp/COPYING b/libs/libbfcp/COPYING
new file mode 100644
index 00000000000..4362b49151d
--- /dev/null
+++ b/libs/libbfcp/COPYING
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, 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 library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+ 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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+ If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be 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.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+ 9. 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 Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+
+ 11. 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 Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. 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.
+
+
+ Copyright (C)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/libs/libbfcp/README.md b/libs/libbfcp/README.md
new file mode 100644
index 00000000000..1574657174f
--- /dev/null
+++ b/libs/libbfcp/README.md
@@ -0,0 +1,14 @@
+BFCP message/client/server libraries
+====================================
+
+This repository contains a set of libraries implementing different aspects of the BFCP ([Binary Floor Control Protocol](https://tools.ietf.org/html/rfc4582)), specifically:
+
+* `bfcpmsg`: a library to implement parsing/building capabilities for the protocol;
+* `bfcpclt`: a library to implement the client side of the protocol;
+* `bfcpsrv`: a library to implement the server side of the protocol.
+
+The libraries were originally implemented by Lorenzo Miniero (University of Napoli Federico II) and Oscar Novo (Ericsson), and are now hosted in a [Meetecho](http://www.meetecho.com) repository to make them more easily accessible.
+
+The license for all libraries is LGPL 2.1 ([GNU Lesser General Public License v2.1](COPYING)).
+
+**NOTE WELL**: This code is _unmantained_. We're not going to address issues or pull requests.
diff --git a/libs/libbfcp/bfcpmsg/Makefile b/libs/libbfcp/bfcpmsg/Makefile
new file mode 100644
index 00000000000..49cab5c4d9e
--- /dev/null
+++ b/libs/libbfcp/bfcpmsg/Makefile
@@ -0,0 +1,49 @@
+PREFIX = /usr
+CC = gcc
+CC_W32 = i686-pc-mingw32-gcc
+OBJS = bfcp_messages.o bfcp_messages_build.o bfcp_messages_parse.o bfcp_strings.o
+OBJS_W32 = bfcp_messages.obj bfcp_messages_build.obj bfcp_messages_parse.obj bfcp_strings.obj
+OPTS = -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -O2 -Werror -Wunused
+LIBS = -lpthread
+LIBS_W32 = -lws2_32 #-s
+DEPS_W32 = -L./
+WIN32 = -DWIN32
+BASE = ../../..
+INC = -I$(BASE)/src/include -I$(BASE)/libs/libteletone/src
+
+so : $(OBJS)
+ $(CC) -ggdb -shared -Wl,-soname,libbfcpmsg.so.0 -o libbfcpmsg.so.0.0.7 $(OBJS) $(OPTS) $(LIBS)
+
+%.o: %.c
+ $(CC) -fPIC -ggdb -c $(INC) $< -o $@ $(OPTS)
+
+dll : $(OBJS_W32)
+ $(CC_W32) $(WIN32) -ggdb -shared -o libbfcpmsg.dll $(OBJS_W32) $(OPTS) $(DEPS_W32) $(LIBS_W32)
+
+%.obj: %.c
+ $(CC_W32) $(WIN32) -ggdb -c $< -o $@ $(OPTS)
+
+linux : testcode.o $(OBJS)
+ $(CC) -ggdb -o testcode testcode.o $(OBJS) $(OPTS) $(LIBS) -lbfcpmsg
+
+win32 : testcode.obj $(OBJS_W32)
+ $(CC_W32) $(WIN32) -ggdb -o testcode.exe testcode.obj $(OBJS_W32) $(OPTS) $(DEPS_W32) $(LIBS_W32)
+
+clean :
+ rm -f *.o *.obj libbfcp* testcode testcode.exe
+
+install:
+ @echo Installing BFCP messages library to $(PREFIX)/lib/:
+ install -m 755 libbfcpmsg.so.0.0.7 $(PREFIX)/lib/
+ ln -sf $(PREFIX)/lib/libbfcpmsg.so.0.0.7 $(PREFIX)/lib/libbfcpmsg.so.0
+ ln -sf $(PREFIX)/lib/libbfcpmsg.so.0 $(PREFIX)/lib/libbfcpmsg.so
+ @echo Installing BFCP messages headers to $(PREFIX)/include/:
+ install -m 755 bfcp_messages.h $(PREFIX)/include/
+ install -m 755 bfcp_strings.h $(PREFIX)/include/
+
+uninstall:
+ @echo Uninstalling BFCP messages library from $(PREFIX)/lib/:
+ rm -f $(PREFIX)/lib/libbfcpmsg*
+ @echo Uninstalling BFCP messages headers from $(PREFIX)/include/:
+ rm -f $(PREFIX)/include/bfcp_messages.h
+ rm -f $(PREFIX)/include/bfcp_strings.h
diff --git a/libs/libbfcp/bfcpmsg/README.md b/libs/libbfcp/bfcpmsg/README.md
new file mode 100644
index 00000000000..1a21c4df0fd
--- /dev/null
+++ b/libs/libbfcp/bfcpmsg/README.md
@@ -0,0 +1,31 @@
+BFCP messages library
+=====================
+
+This is a brief guide to the compilation of the BFCP (Binary Floor Control Protocol) building and parsing libraries, according to the RFC specifications (attached), and of the test application that has been made available to show its use. Notice that this library only implements the message build and parsing functionality: for a BFCP client and/or server, you'll the `bfcpclt`/`bfcpsrv` libraries as well, or you'll need to implement the client/server behaviour yourself.
+
+## Compiling the library
+
+Edit the Makefile according to your settings and compiler. By default gcc will be used, and each library installed to /usr as destination prefix (/usr/include, /usr/lib).
+
+There are several available targets to compile the code:
+
+- `make linux` will compile the testcode and the library, creating an executable file for Linux;
+- `make win32` will compile the testcode and the library, creating an executable file for Windows;
+- `make so` will only compile the library, creating a shared object for Linux;
+- `make dll` will only compile the library, creating a DLL for Windows.
+
+If you want to compile all the available targets, just use:
+
+ make all
+
+To install the compiled library (on Linux only), type, as root:
+
+ make install
+
+To install the libraries in a Windows environment you'll need to manually copy the headers file to your include folder, and copy the resulting DLL(s) where needed.
+
+## Testing the library
+
+A command line sample application is available to test the library. Just play with it according to your needs to learn how the library works and to make tests on your own.
+
+The test code that is available is testcode.c, a small application that builds a BFCP message, saves it to a file (mesg.hex), opens the file again, reads its contents and finally parses the built message, showing all the attributes. By default the test code will build a ChairAction message: just change the primitive name and the required arguments to try to build a message of your choice.
diff --git a/libs/libbfcp/bfcpmsg/bfcp_messages.c b/libs/libbfcp/bfcpmsg/bfcp_messages.c
new file mode 100644
index 00000000000..fb1b04b83ec
--- /dev/null
+++ b/libs/libbfcp/bfcpmsg/bfcp_messages.c
@@ -0,0 +1,604 @@
+#include "bfcp_messages.h"
+
+/* Create a New Arguments Structure */
+bfcp_arguments *bfcp_new_arguments(void)
+{
+ bfcp_arguments *arguments = calloc(1, sizeof(bfcp_arguments));
+ if(!arguments) /* We could not allocate the memory, return with a failure */
+ return NULL;
+ arguments->primitive = 0;
+ arguments->entity = NULL;
+ arguments->fID = NULL;
+ arguments->frqID = 0;
+ arguments->bID = 0;
+ arguments->priority = 0;
+ arguments->frqInfo = 0;
+ arguments->beneficiary = NULL;
+ arguments->rs = NULL;
+ arguments->pInfo = NULL;
+ arguments->sInfo = NULL;
+ arguments->error = NULL;
+ arguments->eInfo = NULL;
+ arguments->primitives = NULL;
+ arguments->attributes = NULL;
+ arguments->nonce = 0;
+ arguments->digest = NULL;
+ return arguments;
+}
+
+/* Free an Arguments Structure */
+int bfcp_free_arguments(bfcp_arguments *arguments)
+{
+ int res = 0; /* We keep track here of the results of the sub-freeing methods*/
+ if(!arguments) /* There's nothing to free, return with a failure */
+ return -1;
+ if(arguments->entity)
+ res += bfcp_free_entity(arguments->entity);
+ if(arguments->fID)
+ res += bfcp_free_floor_id_list(arguments->fID);
+ if(arguments->frqInfo)
+ res += bfcp_free_floor_request_information_list(arguments->frqInfo);
+ if(arguments->beneficiary)
+ res += bfcp_free_user_information(arguments->beneficiary);
+ if(arguments->rs)
+ res += bfcp_free_request_status(arguments->rs);
+ if(arguments->pInfo)
+ free(arguments->pInfo);
+ if(arguments->sInfo)
+ free(arguments->sInfo);
+ if(arguments->error)
+ res += bfcp_free_error(arguments->error);
+ if(arguments->eInfo)
+ free(arguments->eInfo);
+ if(arguments->primitives)
+ res += bfcp_free_supported_list(arguments->primitives);
+ if(arguments->attributes)
+ res += bfcp_free_supported_list(arguments->attributes);
+ if(arguments->digest)
+ res += bfcp_free_digest(arguments->digest);
+ free(arguments);
+ if(!res) /* No error occurred, succesfully freed the structure */
+ return 0;
+ else /* res was not 0, so some error occurred, return with a failure */
+ return -1;
+}
+
+/* Create a New Message (if buffer is NULL or length is 0, creates an empty message) */
+bfcp_message *bfcp_new_message(unsigned char *buffer, unsigned short int length)
+{
+ bfcp_message *message = calloc(1, sizeof(bfcp_message));
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ if(!buffer) { /* Buffer is empty, so we want an empy message, a template */
+ message->buffer = calloc(BFCP_MAX_ALLOWED_SIZE, sizeof(unsigned char));
+ message->position = 12; /* We start after the Common Header (12 octets) */
+ message->length = 12; /* even if we haven't written it yet */
+ } else { /* Buffer is not empty, create a message around it */
+ message->buffer = calloc(length, sizeof(unsigned char));
+ memcpy(message->buffer, buffer, length); /* We copy the buffer in our message */
+ message->position = 0; /* Start from the beginning */
+ message->length = length; /* The length of the message is the length we pass */
+ }
+ return message;
+}
+
+/* Create a Copy of a Message */
+bfcp_message *bfcp_copy_message(bfcp_message *message)
+{
+ if(!message) /* The message is not valid, return with a failure */
+ return NULL;
+ bfcp_message *copy = calloc(sizeof(bfcp_message), sizeof(unsigned char));
+ if(!copy) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ copy->position = 0;
+ copy->length = message->length;
+ copy->buffer = calloc(copy->length, sizeof(unsigned char));
+ memcpy(copy->buffer, message->buffer, copy->length);
+ return copy;
+}
+
+/* Free a Message */
+int bfcp_free_message(bfcp_message *message)
+{
+ if(!message) /* There's nothing to free, return with a failure */
+ return -1;
+ if(message->buffer)
+ free(message->buffer);
+ free(message);
+ return 0;
+}
+
+/* Create a New Entity (Conference ID, Transaction ID, User ID) */
+bfcp_entity *bfcp_new_entity(unsigned long int conferenceID, unsigned short int transactionID, unsigned short int userID)
+{
+ bfcp_entity *entity = calloc(1, sizeof(bfcp_entity));
+ if(!entity) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ entity->conferenceID = conferenceID;
+ entity->transactionID = transactionID;
+ entity->userID = userID;
+ return entity;
+}
+
+/* Free an Entity */
+int bfcp_free_entity(bfcp_entity *entity)
+{
+ if(!entity) /* There's nothing to free, return with a failure */
+ return -1;
+ free(entity);
+ return 0;
+}
+
+/* Create a new Floor ID list (first argument must be a valid ID, last argument MUST be 0) */
+bfcp_floor_id_list *bfcp_new_floor_id_list(unsigned short int fID, ...)
+{
+ bfcp_floor_id_list *first, *previous, *next;
+ va_list ap;
+ va_start(ap, fID);
+ first = calloc(1, sizeof(bfcp_floor_id_list));
+ if(!first) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ first->ID = fID;
+ first->next = NULL;
+ previous = first;
+ fID = va_arg(ap, int);
+ while(fID) {
+ next = calloc(1, sizeof(bfcp_floor_id_list));
+ if(!next) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ next->ID = fID;
+ next->next = NULL;
+ previous->next = next;
+ previous = next;
+ fID = va_arg(ap, int);
+ }
+ va_end(ap);
+ return first;
+}
+
+/* Add IDs to an existing Floor ID list (last argument MUST be 0) */
+int bfcp_add_floor_id_list(bfcp_floor_id_list *list, unsigned short int fID, ...)
+{
+ bfcp_floor_id_list *previous, *next;
+ va_list ap;
+ va_start(ap, fID);
+ if(!list) /* List doesn't exist, return a with failure */
+ return -1;
+ next = list;
+ while(next) { /* We search the last element in the list, to append the new IDs to */
+ previous = next;
+ next = previous->next;
+ } /* previous is now the pointer to the actually last element in the list */
+ while(fID) {
+ next = calloc(1, sizeof(bfcp_floor_id_list));
+ if(!next) /* We could not allocate the memory, return a with failure */
+ return -1;
+ next->ID = fID;
+ next->next = NULL;
+ previous->next = next; /* We append the new ID to the list */
+ previous = next; /* and we update the pointers */
+ fID = va_arg(ap, int);
+ }
+ va_end(ap);
+ return 0;
+}
+
+/* Free a Floor ID list */
+int bfcp_free_floor_id_list(bfcp_floor_id_list *list)
+{
+ if(!list) /* There's nothing to free, return with a failure */
+ return -1;
+ bfcp_floor_id_list *next = NULL, *temp = list;
+ while(temp) {
+ next = temp->next;
+ free(temp);
+ temp = next;
+ }
+ return 0;
+}
+
+/* Create a new Supported (Primitives/Attributes) list (last argument MUST be 0) */
+bfcp_supported_list *bfcp_new_supported_list(unsigned short int element, ...)
+{
+ bfcp_supported_list *first, *previous, *next;
+ va_list ap;
+ va_start(ap, element);
+ first = calloc(1, sizeof(bfcp_supported_list));
+ if(!first) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ first->element = element;
+ previous = first;
+ element = va_arg(ap, int);
+ while(element) {
+ next = calloc(1, sizeof(bfcp_supported_list));
+ if(!next) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ next->element = element;
+ previous->next = next;
+ previous = next;
+ element = va_arg(ap, int);
+ }
+ va_end(ap);
+ return first;
+}
+
+/* Free a Supported (Primitives/Attributes) list */
+int bfcp_free_supported_list(bfcp_supported_list *list)
+{
+ if(!list) /* There's nothing to free, return with a failure */
+ return -1;
+ bfcp_supported_list *next = NULL, *temp = list;
+ while(temp) {
+ next = temp->next;
+ free(temp);
+ temp = next;
+ }
+ return 0;
+}
+
+/* Create a New Request Status (RequestStatus/QueuePosition) */
+bfcp_request_status *bfcp_new_request_status(unsigned short int rs, unsigned short int qp)
+{
+ bfcp_request_status *request_status = calloc(1, sizeof(bfcp_request_status));
+ if(!request_status) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ request_status->rs = rs;
+ request_status->qp = qp;
+ return request_status;
+}
+
+/* Free a Request Status (RequestStatus/QueuePosition) */
+int bfcp_free_request_status(bfcp_request_status *request_status)
+{
+ if(!request_status) /* There's nothing to free, return with a failure */
+ return -1;
+ free(request_status);
+ return 0;
+}
+
+/* Create a New Error (Code/Details) */
+bfcp_error *bfcp_new_error(unsigned short int code, void *details)
+{
+ bfcp_error *error = calloc(1, sizeof(bfcp_error));
+ if(!error) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ error->code = code;
+ error->details = details;
+ return error;
+}
+
+/* Free an Error (Code/Details) */
+int bfcp_free_error(bfcp_error *error)
+{
+ if(!error) /* There's nothing to free, return with a failure */
+ return -1;
+ return bfcp_free_unknown_m_error_details_list(error->details);
+}
+
+/* Create a New Error Details list (for Error 4: UNKNOWN_M) (last argument MUST be 0) */
+bfcp_unknown_m_error_details *bfcp_new_unknown_m_error_details_list(unsigned short int attribute, ...)
+{
+ bfcp_unknown_m_error_details *first, *previous, *next;
+ va_list ap;
+ va_start(ap, attribute);
+ first = calloc(1, sizeof(bfcp_unknown_m_error_details));
+ if(!first) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ first->unknown_type = attribute;
+ first->reserved = 0;
+ previous = first;
+ attribute = va_arg(ap, int);
+ while(attribute) {
+ next = calloc(1, sizeof(bfcp_unknown_m_error_details));
+ if(!next) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ next->unknown_type = attribute;
+ next->reserved = 0;
+ previous->next = next;
+ previous = next;
+ attribute = va_arg(ap, int);
+ }
+ va_end(ap);
+ return first;
+}
+
+/* Add Attributes to an existing Error Details list (for Error 4: UNKNOWN_M) (last argument MUST be 0) */
+int bfcp_add_unknown_m_error_details_list(bfcp_unknown_m_error_details *list, unsigned short int attribute, ...)
+{
+ bfcp_unknown_m_error_details *previous, *next;
+ va_list ap;
+ va_start(ap, attribute);
+ if(!list) /* List doesn't exist, return a with failure */
+ return -1;
+ next = list;
+ while(next) { /* We search the last element in the list, to append the new Attributes to */
+ previous = next;
+ next = previous->next;
+ } /* previous is now the pointer to the actually last element in the list */
+ while(attribute) {
+ next = calloc(1, sizeof(bfcp_unknown_m_error_details));
+ if(!next) /* We could not allocate the memory, return a with failure */
+ return -1;
+ next->unknown_type = attribute;
+ next->reserved = 0;
+ previous->next = next; /* We append the new ID to the list */
+ previous = next; /* and we update the pointers */
+ attribute = va_arg(ap, int);
+ }
+ va_end(ap);
+ return 0;
+}
+
+/* Free an Error Details list */
+int bfcp_free_unknown_m_error_details_list(bfcp_unknown_m_error_details *details)
+{
+ if(!details) /* There's nothing to free, return with a failure */
+ return -1;
+ bfcp_unknown_m_error_details *next = NULL, *temp = details;
+ while(temp) {
+ next = temp->next;
+ free(temp);
+ temp = next;
+ }
+ return 0;
+}
+
+/* Create a New User (Beneficiary/RequestedBy) Information */
+bfcp_user_information *bfcp_new_user_information(unsigned short int ID, char *display, char *uri)
+{
+ bfcp_user_information *info = calloc(1, sizeof(bfcp_user_information));
+ if(!info) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ info->ID = ID;
+ if(display) {
+ info->display = calloc(strlen(display)+1, sizeof(char));
+ info->display = strcpy(info->display, display); /* We copy the Display string */
+ }
+ if(uri) {
+ info->uri = calloc(strlen(uri)+1, sizeof(char));
+ info->uri = strcpy(info->uri, uri); /* We copy the URI string */
+ }
+ return info;
+}
+
+/* Free an User (Beneficiary/RequestedBy) Information */
+int bfcp_free_user_information(bfcp_user_information *info)
+{
+ if(!info) /* There's nothing to free, return with a failure */
+ return -1;
+ if(info->display)
+ free(info->display);
+ if(info->uri)
+ free(info->uri);
+ free(info);
+ return 0;
+}
+
+/* Create a new Floor Request Information */
+bfcp_floor_request_information *bfcp_new_floor_request_information(unsigned short int frqID, bfcp_overall_request_status *oRS, bfcp_floor_request_status *fRS, bfcp_user_information *beneficiary, bfcp_user_information *requested_by, unsigned short int priority , char *pInfo)
+{
+ bfcp_floor_request_information *frqInfo = calloc(1, sizeof(bfcp_floor_request_information));
+ if(!frqInfo) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ frqInfo->frqID = frqID;
+ frqInfo->oRS = oRS;
+ frqInfo->fRS = fRS;
+ frqInfo->beneficiary = beneficiary;
+ frqInfo->requested_by = requested_by;
+ frqInfo->priority = priority;
+ if(pInfo) {
+ frqInfo->pInfo = calloc(strlen(pInfo)+1, sizeof(char));
+ frqInfo->pInfo = strcpy(frqInfo->pInfo, pInfo); /* We copy the Participant Provided Info */
+ }
+ frqInfo->next = NULL; /* We link them through bfcp_list_floor_request_information (...) */
+ return frqInfo;
+}
+
+/* Create a Floor Request Information list (last argument MUST be NULL) */
+int bfcp_list_floor_request_information(bfcp_floor_request_information *frqInfo, ...)
+{
+ bfcp_floor_request_information *previous, *next;
+ va_list ap;
+ va_start(ap, frqInfo);
+ if(!frqInfo) /* The lead pointer is not valid, return a with failure */
+ return -1;
+ previous = frqInfo;
+ next = va_arg(ap, bfcp_floor_request_information *);
+ while(next) {
+ previous->next = next;
+ previous = next;
+ next = va_arg(ap, bfcp_floor_request_information *);
+ }
+ va_end(ap);
+ return 0;
+}
+
+/* Add elements to an existing Floor Request Information list (last argument MUST be NULL) */
+int bfcp_add_floor_request_information_list(bfcp_floor_request_information *list, ...)
+{
+ bfcp_floor_request_information *previous, *next;
+ va_list ap;
+ va_start(ap, list);
+ if(!list) /* List doesn't exist, return a with failure */
+ return -1;
+ next = list;
+ while(next) { /* We search the last element in the list, to append the new IDs to */
+ previous = next;
+ next = previous->next;
+ } /* previous is now the pointer to the actually last element in the list */
+ next = va_arg(ap, bfcp_floor_request_information *);
+ while(next) {
+ previous->next = next; /* We append the new ID to the list */
+ previous = next; /* and we update the pointers */
+ next = va_arg(ap, bfcp_floor_request_information *);
+ }
+ va_end(ap);
+ return 0;
+}
+
+/* Free a Floor Request Information list */
+int bfcp_free_floor_request_information_list(bfcp_floor_request_information *frqInfo)
+{
+ int res = 0; /* We keep track here of the results of the sub-freeing methods*/
+ if(!frqInfo) /* There's nothing to free, return with a failure */
+ return -1;
+ bfcp_floor_request_information *next = NULL, *temp = frqInfo;
+ while(temp) {
+ next = temp->next;
+ if(temp->oRS)
+ res += bfcp_free_overall_request_status(temp->oRS);
+ if(temp->fRS)
+ res += bfcp_free_floor_request_status_list(temp->fRS);
+ if(temp->beneficiary)
+ res += bfcp_free_user_information(temp->beneficiary);
+ if(temp->requested_by)
+ res += bfcp_free_user_information(temp->requested_by);
+ if(temp->pInfo)
+ free(temp->pInfo);
+ free(temp);
+ temp = next;
+ }
+ if(!res) /* No error occurred, succesfully freed the structure */
+ return 0;
+ else /* res was not 0, so some error occurred, return with a failure */
+ return -1;
+}
+
+/* Create a New Floor Request Status (FloorID/RequestStatus/QueuePosition/StatusInfo) */
+bfcp_floor_request_status *bfcp_new_floor_request_status(unsigned short int fID, unsigned short int rs, unsigned short int qp, char *sInfo)
+{
+ bfcp_floor_request_status *floor_request_status = calloc(1, sizeof(bfcp_floor_request_status));
+ if(!floor_request_status) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ floor_request_status->fID = fID;
+ floor_request_status->rs = bfcp_new_request_status(rs, qp);
+ if(!floor_request_status->rs)
+ return NULL;
+ if(sInfo) {
+ floor_request_status->sInfo = calloc(strlen(sInfo)+1, sizeof(char));
+ if(!floor_request_status->sInfo)
+ return NULL;
+ floor_request_status->sInfo = strcpy(floor_request_status->sInfo, sInfo); /* We copy the Status Info */
+ }
+ floor_request_status->next = NULL; /* We link them through bfcp_list_floor_request_status (...) */
+ return floor_request_status;
+}
+
+/* Create a Floor Request Status list (last argument MUST be NULL) */
+int bfcp_list_floor_request_status(bfcp_floor_request_status *fRS, ...)
+{
+ bfcp_floor_request_status *previous, *next;
+ va_list ap;
+ va_start(ap, fRS);
+ if(!fRS) /* The lead pointer is not valid, return a with failure */
+ return -1;
+ previous = fRS;
+ next = va_arg(ap, bfcp_floor_request_status *);
+ while(next) {
+ previous->next = next;
+ previous = next;
+ next = va_arg(ap, bfcp_floor_request_status *);
+ }
+ va_end(ap);
+ return 0;
+}
+
+/* Add elements to an existing Floor Request Status list (last argument MUST be NULL) */
+int bfcp_add_floor_request_status_list(bfcp_floor_request_status *list, ...)
+{
+ bfcp_floor_request_status *previous, *next;
+ va_list ap;
+ va_start(ap, list);
+ if(!list) /* List doesn't exist, return a with failure */
+ return -1;
+ next = list;
+ while(next) { /* We search the last element in the list, to append the new IDs to */
+ previous = next;
+ next = previous->next;
+ } /* previous is now the pointer to the actually last element in the list */
+ next = va_arg(ap, bfcp_floor_request_status *);
+ while(next) {
+ previous->next = next; /* We append the new ID to the list */
+ previous = next; /* and we update the pointers */
+ next = va_arg(ap, bfcp_floor_request_status *);
+ }
+ va_end(ap);
+ return 0;
+}
+
+/* Free a Floor Request Status list */
+int bfcp_free_floor_request_status_list(bfcp_floor_request_status *floor_request_status)
+{
+ int res = 0; /* We keep track here of the results of the sub-freeing methods*/
+ if(!floor_request_status) /* There's nothing to free, return with a failure */
+ return -1;
+ bfcp_floor_request_status *next = NULL, *temp = floor_request_status;
+ while(temp) {
+ next = temp->next;
+ if(temp->rs)
+ res += bfcp_free_request_status(temp->rs);
+ if(temp->sInfo)
+ free(temp->sInfo);
+ free(temp);
+ temp = next;
+ }
+ if(!res) /* No error occurred, succesfully freed the structure */
+ return 0;
+ else /* res was not 0, so some error occurred, return with a failure */
+ return -1;
+}
+
+/* Create a New Overall Request Status (FloorRequestID/RequestStatus/QueuePosition/StatusInfo) */
+bfcp_overall_request_status *bfcp_new_overall_request_status(unsigned short int frqID, unsigned short int rs, unsigned short int qp, char *sInfo)
+{
+ bfcp_overall_request_status *overall_request_status = calloc(1, sizeof(bfcp_overall_request_status));
+ if(!overall_request_status) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ overall_request_status->frqID = frqID;
+ overall_request_status->rs = bfcp_new_request_status(rs, qp);
+ if(!overall_request_status->rs)
+ return NULL;
+ if(sInfo) {
+ overall_request_status->sInfo = calloc(strlen(sInfo)+1, sizeof(char));
+ if(!overall_request_status->sInfo)
+ return NULL;
+ overall_request_status->sInfo = strcpy(overall_request_status->sInfo, sInfo); /* We copy the Status Info */
+ }
+ return overall_request_status;
+}
+
+/* Free an Overall Request Status */
+int bfcp_free_overall_request_status(bfcp_overall_request_status *overall_request_status)
+{
+ int res = 0; /* We keep track here of the results of the sub-freeing methods*/
+ if(!overall_request_status) /* There's nothing to free, return with a failure */
+ return -1;
+ if(overall_request_status->rs)
+ res += bfcp_free_request_status(overall_request_status->rs);
+ if(overall_request_status->sInfo)
+ free(overall_request_status->sInfo);
+ free(overall_request_status);
+ return res;
+}
+
+/* Create a New Digest */
+bfcp_digest *bfcp_new_digest(unsigned short int algorithm)
+{
+ bfcp_digest *digest = calloc(1, sizeof(bfcp_digest));
+ if(!digest) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ digest->algorithm = algorithm;
+ digest->text = NULL;
+ return digest;
+}
+
+/* Free a Digest */
+int bfcp_free_digest(bfcp_digest *digest)
+{
+ if(!digest) /* There's nothing to free, return with a failure */
+ return -1;
+ if(digest->text)
+ free(digest->text);
+ free(digest);
+ return 0;
+}
diff --git a/libs/libbfcp/bfcpmsg/bfcp_messages.h b/libs/libbfcp/bfcpmsg/bfcp_messages.h
new file mode 100644
index 00000000000..aab01de82b3
--- /dev/null
+++ b/libs/libbfcp/bfcpmsg/bfcp_messages.h
@@ -0,0 +1,393 @@
+#ifndef _BFCP_MESSAGES_H
+#define _BFCP_MESSAGES_H
+
+#ifndef WIN32
+#include /* For htonl and htons */
+#else
+#include /* For htonl and htons (Win32) */
+#endif
+#include /* For functions with variable arguments */
+#include /* For calloc */
+#include /* For memcpy */
+
+#include
+
+#include "switch.h"
+
+
+/* Primitives */
+#define FloorRequest 1
+#define FloorRelease 2
+#define FloorRequestQuery 3
+#define FloorRequestStatus 4
+#define UserQuery 5
+#define UserStatus 6
+#define FloorQuery 7
+#define FloorStatus 8
+#define ChairAction 9
+#define ChairActionAck 10
+#define Hello 11
+#define HelloAck 12
+#define Error 13
+#define FloorRequestStatusAck 14
+#define ErrorAck 15
+#define FloorStatusAck 16
+
+/* Attributes */
+#define BENEFICIARY_ID 1
+#define FLOOR_ID 2
+#define FLOOR_REQUEST_ID 3
+#define PRIORITY 4
+#define REQUEST_STATUS 5
+#define ERROR_CODE 6
+#define ERROR_INFO 7
+#define PARTICIPANT_PROVIDED_INFO 8
+#define STATUS_INFO 9
+#define SUPPORTED_ATTRIBUTES 10
+#define SUPPORTED_PRIMITIVES 11
+#define USER_DISPLAY_NAME 12
+#define USER_URI 13
+#define BENEFICIARY_INFORMATION 14
+#define FLOOR_REQUEST_INFORMATION 15
+#define REQUESTED_BY_INFORMATION 16
+#define FLOOR_REQUEST_STATUS 17
+#define OVERALL_REQUEST_STATUS 18
+#define NONCE 19
+#define DIGEST 20
+
+/* Request Status Values */
+#define BFCP_PENDING 1
+#define BFCP_ACCEPTED 2
+#define BFCP_GRANTED 3
+#define BFCP_DENIED 4
+#define BFCP_CANCELLED 5
+#define BFCP_RELEASED 6
+#define BFCP_REVOKED 7
+
+/* Priority Values */
+#define BFCP_LOWEST_PRIORITY 0
+#define BFCP_LOW_PRIORITY 1
+#define BFCP_NORMAL_PRIORITY 2
+#define BFCP_HIGH_PRIORITY 3
+#define BFCP_HIGHEST_PRIORITY 4
+
+
+/* Error Codes */
+#define BFCP_CONFERENCE_DOES_NOT_EXIST 1
+#define BFCP_USER_DOES_NOT_EXIST 2
+#define BFCP_UNKNOWN_PRIMITIVE 3
+#define BFCP_UNKNOWN_MANDATORY_ATTRIBUTE 4
+#define BFCP_UNAUTHORIZED_OPERATION 5
+#define BFCP_INVALID_FLOORID 6
+#define BFCP_FLOORREQUEST_DOES_NOT_EXIST 7
+#define BFCP_MAX_FLOORREQUESTS_REACHED 8
+#define BFCP_USE_TLS 9
+#define BFCP_DIGEST_ATTRIBUTE_REQUIRED 10
+#define BFCP_INVALID_NONCE 11
+#define BFCP_AUTHENTICATION_FAILED 12
+
+/* Parsing-specific Error Codes */
+#define BFCP_WRONG_VERSION 1
+#define BFCP_RESERVED_NOT_ZERO 2
+#define BFCP_UNKNOWN_PRIMITIVE 3
+#define BFCP_UNKNOWN_ATTRIBUTE 4
+#define BFCP_WRONG_LENGTH 5
+#define BFCP_PARSING_ERROR 6
+
+
+/* Maximum allow size for BFCP messages is 64Kbytes, since the Payload Length in the header is 16 bit */
+#define BFCP_MAX_ALLOWED_SIZE 65535
+
+
+/* BFCP Message */
+typedef struct bfcp_message {
+ unsigned char *buffer; /* The buffer containing the message */
+ unsigned short int position; /* The position indicator for the buffer */
+ unsigned short int length; /* The length of the message */
+} bfcp_message;
+
+/* Helping Structures for bit masks and so on */
+typedef struct bfcp_entity {
+ unsigned long int conferenceID;
+ unsigned short int transactionID;
+ unsigned short int userID;
+} bfcp_entity;
+
+typedef struct bfcp_floor_id_list { /* FLOOR-ID list, to manage the multiple FLOOR-ID attributes */
+ unsigned short int ID; /* FLOOR-ID */
+ struct bfcp_floor_id_list *next; /* Pointer to next FLOOR-ID instance */
+} bfcp_floor_id_list;
+
+typedef struct bfcp_supported_list { /* list to manage all the supported attributes and primitives */
+ unsigned short int element; /* Element (Attribute/Primitive) */
+ struct bfcp_supported_list *next; /* Pointer to next supported element instance */
+} bfcp_supported_list;
+
+typedef struct bfcp_request_status {
+ unsigned short int rs; /* Request Status */
+ unsigned short int qp; /* Queue Position */
+} bfcp_request_status;
+
+typedef struct bfcp_error {
+ unsigned short int code; /* Error Code */
+ void *details; /* Error Details */
+} bfcp_error;
+
+typedef struct bfcp_unknown_m_error_details { /* These are specific details for error 4: UNKNOWN_M */
+ unsigned short int unknown_type; /* 7-bits to specify the unknown received mandatory attribute */
+ unsigned short int reserved; /* A reserved bit, which must be set to 0 and ignored, at the moment */
+ struct bfcp_unknown_m_error_details *next; /* This is a linked list */
+} bfcp_unknown_m_error_details;
+
+typedef struct bfcp_user_information { /* Help structure for BENEFICIARY-INFORMATION and REQUESTED-BY-INFORMATION */
+ unsigned short int ID; /* For the INFORMATION-HEADER */
+ char *display; /* USER-DISPLAY-NAME, optional */
+ char *uri; /* USER-URI, optional */
+} bfcp_user_information;
+
+typedef struct bfcp_floor_request_status { /* Help structure for FLOOR-REQUEST-STATUS */
+ unsigned short int fID; /* FLOOR-REQUEST-STATUS-HEADER */
+ bfcp_request_status *rs; /* REQUEST-STATUS, optional */
+ char *sInfo; /* STATUS-INFO, optional */
+ struct bfcp_floor_request_status *next; /* pointer to next instance (to manage lists) */
+} bfcp_floor_request_status;
+
+typedef struct bfcp_overall_request_status { /* Help structure for OVERALL-REQUEST-STATUS */
+ unsigned short int frqID; /* OVERALL-REQUEST-STATUS-HEADER */
+ bfcp_request_status *rs; /* REQUEST-STATUS, optional */
+ char *sInfo; /* STATUS-INFO, optional */
+} bfcp_overall_request_status;
+
+typedef struct bfcp_floor_request_information { /* Help structure for FLOOR-REQUEST-INFORMATION */
+ unsigned short int frqID; /* FLOOR-REQUEST-INFORMATION-HEADER */
+ bfcp_overall_request_status *oRS; /* OVERALL-REQUEST-STATUS, optional */
+ bfcp_floor_request_status *fRS; /* FLOOR-REQUEST-STATUS list */
+ bfcp_user_information *beneficiary; /* BENEFICIARY-INFORMATION, optional */
+ bfcp_user_information *requested_by; /* REQUESTED-BY-INFORMATION, optional */
+ unsigned short int priority; /* PRIORITY, optional */
+ char *pInfo; /* PARTICIPANT-PROVIDED-INFO, optional */
+ struct bfcp_floor_request_information *next; /* pointer to next instance (to manage lists) */
+} bfcp_floor_request_information;
+
+typedef struct bfcp_digest {
+ unsigned short int algorithm; /* (currently UNUSED) */
+ char *text; /* (currently UNUSED) */
+} bfcp_digest;
+
+typedef struct bfcp_arguments {
+ unsigned short int primitive; /* Message Primitive */
+ bfcp_entity *entity; /* Conference ID, Transaction ID, User ID */
+ bfcp_floor_id_list *fID; /* Floor ID list */
+ unsigned short int frqID; /* Floor Request ID */
+ unsigned short int bID; /* Beneficiary ID */
+ unsigned short int priority; /* Priority */
+ bfcp_floor_request_information *frqInfo; /* Floor Request Information */
+ bfcp_user_information *beneficiary; /* Beneficiary Information */
+ bfcp_request_status *rs; /* Request Status */
+ char *pInfo; /* Participant Provided Info */
+ char *sInfo; /* Status Info */
+ bfcp_error *error; /* Error Code & Details */
+ char *eInfo; /* Error Info */
+ bfcp_supported_list *primitives; /* Supported Primitives list */
+ bfcp_supported_list *attributes; /* Supported Primitives list */
+ unsigned short int nonce; /* Nonce (currently UNUSED) */
+ bfcp_digest *digest; /* Digest Algorithm & Text */
+} bfcp_arguments;
+
+/* Parsing Help Structures */
+typedef struct bfcp_received_attribute { /* A chained list to manage all attributes in a received message */
+ int type; /* The attribute type */
+ int mandatory_bit; /* The Mandatory Bit */
+ int length; /* The length of the attribute */
+ int position; /* Its position in the message buffer */
+ int valid; /* If errors occur in parsing, the attribute is marked as not valid */
+ struct bfcp_received_attribute *next; /* Pointer to next attribute in the message */
+} bfcp_received_attribute;
+
+typedef struct bfcp_received_message {
+ bfcp_arguments *arguments; /* The message unpacked in its original arguments */
+ int version; /* The version of the received message */
+ int reserved; /* The reserved bits */
+ int primitive; /* The primitive of the message */
+ int length; /* The length of the message */
+ bfcp_entity *entity; /* The entities of the message (IDs) */
+ bfcp_received_attribute *first_attribute; /* A list of all attributes in the message */
+ struct bfcp_received_message_error *errors; /* If errors occur, we write them here */
+} bfcp_received_message;
+
+typedef struct bfcp_received_message_error {
+ int attribute; /* The attribute where the error happened */
+ int code; /* The Parsing-specific Error Code */
+ struct bfcp_received_message_error *next; /* There could be more errors, it's a linked list */
+} bfcp_received_message_error;
+
+
+#if defined __cplusplus
+ extern "C" {
+#endif
+/* Creating and Freeing Methods for the Structures */
+/* Create a New Arguments Structure */
+bfcp_arguments *bfcp_new_arguments(void);
+/* Free an Arguments Structure */
+int bfcp_free_arguments(bfcp_arguments *arguments);
+
+/* Create a New Message (if buffer is NULL, creates an empty message) */
+bfcp_message *bfcp_new_message(unsigned char *buffer, unsigned short int length);
+/* Create a Copy of a Message */
+bfcp_message *bfcp_copy_message(bfcp_message *message);
+/* Free a Message */
+int bfcp_free_message(bfcp_message *message);
+
+/* Create a New Entity (Conference ID, Transaction ID, User ID) */
+bfcp_entity *bfcp_new_entity(unsigned long int conferenceID, unsigned short int transactionID, unsigned short int userID);
+/* Free an Entity */
+int bfcp_free_entity(bfcp_entity *entity);
+
+/* Create a new Floor ID list (first argument must be a valid ID, last argument MUST be 0) */
+bfcp_floor_id_list *bfcp_new_floor_id_list(unsigned short int fID, ...);
+/* Add IDs to an existing Floor ID list (last argument MUST be 0) */
+int bfcp_add_floor_id_list(bfcp_floor_id_list *list, unsigned short int fID, ...);
+/* Free a Floor ID list */
+int bfcp_free_floor_id_list(bfcp_floor_id_list *list);
+
+/* Create a new Supported (Primitives/Attributes) list (last argument MUST be 0) */
+bfcp_supported_list *bfcp_new_supported_list(unsigned short int element, ...);
+/* Free a Supported (Primitives/Attributes) list */
+int bfcp_free_supported_list(bfcp_supported_list *list);
+
+/* Create a New Request Status (RequestStatus/QueuePosition) */
+bfcp_request_status *bfcp_new_request_status(unsigned short int rs, unsigned short int qp);
+/* Free a Request Status (RequestStatus/QueuePosition) */
+int bfcp_free_request_status(bfcp_request_status *request_status);
+
+/* Create a New Error (Code/Details) */
+bfcp_error *bfcp_new_error(unsigned short int code, void *details);
+/* Free an Error (Code/Details) */
+int bfcp_free_error(bfcp_error *error);
+
+/* Create a New Error Details list (for Error 4: UNKNOWN_M) (last argument MUST be 0) */
+bfcp_unknown_m_error_details *bfcp_new_unknown_m_error_details_list(unsigned short int attribute, ...);
+/* Add Attributes to an existing Error Details list (for Error 4: UNKNOWN_M) (last argument MUST be 0) */
+int bfcp_add_unknown_m_error_details_list(bfcp_unknown_m_error_details *list, unsigned short int attribute, ...);
+/* Free an Error Details list */
+int bfcp_free_unknown_m_error_details_list(bfcp_unknown_m_error_details *details);
+
+/* Create a New User (Beneficiary/RequestedBy) Information */
+bfcp_user_information *bfcp_new_user_information(unsigned short int ID, char *display, char *uri);
+/* Free an User (Beneficiary/RequestedBy) Information */
+int bfcp_free_user_information(bfcp_user_information *info);
+
+/* Create a new Floor Request Information */
+bfcp_floor_request_information *bfcp_new_floor_request_information(unsigned short int frqID, bfcp_overall_request_status *oRS, bfcp_floor_request_status *fRS, bfcp_user_information *beneficiary, bfcp_user_information *requested_by, unsigned short int priority ,char *pInfo);
+/* Create a Floor Request Information list (last argument MUST be NULL) */
+int bfcp_list_floor_request_information(bfcp_floor_request_information *frqInfo, ...);
+/* Add elements to an existing Floor Request Information list (last argument MUST be NULL) */
+int bfcp_add_floor_request_information_list(bfcp_floor_request_information *list, ...);
+/* Free a Floor Request Information list */
+int bfcp_free_floor_request_information_list(bfcp_floor_request_information *frqInfo);
+
+/* Create a New Floor Request Status (FloorID/RequestStatus/QueuePosition/StatusInfo) */
+bfcp_floor_request_status *bfcp_new_floor_request_status(unsigned short int fID, unsigned short int rs, unsigned short int qp, char *sInfo);
+/* Create a Floor Request Status list (last argument MUST be NULL) */
+int bfcp_list_floor_request_status(bfcp_floor_request_status *fRS, ...);
+/* Add elements to an existing Floor Request Status list (last argument MUST be NULL) */
+int bfcp_add_floor_request_status_list(bfcp_floor_request_status *list, ...);
+/* Free a Floor Request Status list */
+int bfcp_free_floor_request_status_list(bfcp_floor_request_status *floor_request_status);
+
+/* Create a New Overall Request Status (FloorRequestID/RequestStatus/QueuePosition/StatusInfo) */
+bfcp_overall_request_status *bfcp_new_overall_request_status(unsigned short int frqID, unsigned short int rs, unsigned short int qp, char *sInfo);
+/* Free an Overall Request Status */
+int bfcp_free_overall_request_status(bfcp_overall_request_status *overall_request_status);
+
+/* Create a New Digest */
+bfcp_digest *bfcp_new_digest(unsigned short int algorithm);
+/* Free a Digest */
+int bfcp_free_digest(bfcp_digest *digest);
+
+
+/* Build Methods */
+/* Generic BuildMessage Method */
+bfcp_message *bfcp_build_message(bfcp_arguments* arguments);
+/* Build Headers */
+void bfcp_build_commonheader(bfcp_message *message, bfcp_entity *entity, unsigned short int primitive);
+void bfcp_build_attribute_tlv(bfcp_message *message, unsigned short int position, unsigned short int type, unsigned short int mandatory_bit, unsigned short int length);
+/* Build Specific Messages */
+bfcp_message *bfcp_build_message_FloorRequest(bfcp_entity *entity, bfcp_floor_id_list *fID, unsigned short int bID, char *pInfo, unsigned short int priority);
+bfcp_message *bfcp_build_message_FloorRelease(bfcp_entity *entity, unsigned short int frqID);
+bfcp_message *bfcp_build_message_FloorRequestQuery(bfcp_entity *entity, unsigned short int frqID);
+bfcp_message *bfcp_build_message_FloorRequestStatus(bfcp_entity *entity, bfcp_floor_request_information *frqInfo);
+bfcp_message *bfcp_build_message_UserQuery(bfcp_entity *entity, unsigned short int bID);
+bfcp_message *bfcp_build_message_UserStatus(bfcp_entity *entity, bfcp_user_information *beneficiary, bfcp_floor_request_information *frqInfo);
+bfcp_message *bfcp_build_message_FloorQuery(bfcp_entity *entity, bfcp_floor_id_list *fID);
+bfcp_message *bfcp_build_message_FloorStatus(bfcp_entity *entity, bfcp_floor_id_list *fID, bfcp_floor_request_information *frqInfo);
+bfcp_message *bfcp_build_message_ChairAction(bfcp_entity *entity, bfcp_floor_request_information *frqInfo);
+bfcp_message *bfcp_build_message_ChairActionAck(bfcp_entity *entity);
+bfcp_message *bfcp_build_message_Hello(bfcp_entity *entity);
+bfcp_message *bfcp_build_message_HelloAck(bfcp_entity *entity, bfcp_supported_list *primitives, bfcp_supported_list *attributes);
+bfcp_message *bfcp_build_message_Error(bfcp_entity *entity, bfcp_error *error, char *eInfo);
+
+/* Build Attributes */
+int bfcp_build_attribute_BENEFICIARY_ID(bfcp_message *message, unsigned short int bID);
+int bfcp_build_attribute_FLOOR_ID(bfcp_message *message, unsigned short int fID);
+int bfcp_build_attribute_FLOOR_REQUEST_ID(bfcp_message *message, unsigned short int frqID);
+int bfcp_build_attribute_PRIORITY(bfcp_message *message, unsigned short int priority);
+int bfcp_build_attribute_REQUEST_STATUS(bfcp_message *message, bfcp_request_status *rs);
+int bfcp_build_attribute_ERROR_CODE(bfcp_message *message, bfcp_error *error);
+int bfcp_build_attribute_ERROR_INFO(bfcp_message *message, char *eInfo);
+int bfcp_build_attribute_PARTICIPANT_PROVIDED_INFO(bfcp_message *message, char *pInfo);
+int bfcp_build_attribute_STATUS_INFO(bfcp_message *message, char *sInfo);
+int bfcp_build_attribute_SUPPORTED_ATTRIBUTES(bfcp_message *message, bfcp_supported_list *attributes);
+int bfcp_build_attribute_SUPPORTED_PRIMITIVES(bfcp_message *message, bfcp_supported_list *primitives);
+int bfcp_build_attribute_USER_DISPLAY_NAME(bfcp_message *message, char *display);
+int bfcp_build_attribute_USER_URI(bfcp_message *message, char *uri);
+int bfcp_build_attribute_BENEFICIARY_INFORMATION(bfcp_message *message, bfcp_user_information *beneficiary);
+int bfcp_build_attribute_FLOOR_REQUEST_INFORMATION(bfcp_message *message, bfcp_floor_request_information *frqInfo);
+int bfcp_build_attribute_REQUESTED_BY_INFORMATION(bfcp_message *message, bfcp_user_information *requested_by);
+int bfcp_build_attribute_FLOOR_REQUEST_STATUS(bfcp_message *message, bfcp_floor_request_status *fRS);
+int bfcp_build_attribute_OVERALL_REQUEST_STATUS(bfcp_message *message, bfcp_overall_request_status *oRS);
+int bfcp_build_attribute_NONCE(bfcp_message *message, unsigned short int nonce);
+int bfcp_build_attribute_DIGEST(bfcp_message *message, bfcp_digest *digest);
+
+
+/* Parse Methods */
+unsigned short int bfcp_get_length(bfcp_message *message);
+int bfcp_get_primitive(bfcp_message *message);
+unsigned long int bfcp_get_conferenceID(bfcp_message *message);
+unsigned short int bfcp_get_transactionID(bfcp_message *message);
+unsigned short int bfcp_get_userID(bfcp_message *message);
+bfcp_received_message *bfcp_new_received_message(void);
+int bfcp_free_received_message(bfcp_received_message *recvM);
+bfcp_received_message_error *bfcp_received_message_add_error(bfcp_received_message_error *error, unsigned short int attribute, unsigned short int code);
+int bfcp_free_received_message_errors(bfcp_received_message_error *errors);
+bfcp_received_attribute *bfcp_new_received_attribute(void);
+int bfcp_free_received_attribute(bfcp_received_attribute *recvA);
+bfcp_received_message *bfcp_parse_message(bfcp_message *message);
+bfcp_received_attribute *bfcp_parse_attribute(bfcp_message *message);
+int bfcp_parse_arguments(bfcp_received_message *recvM, bfcp_message *message);
+int bfcp_parse_attribute_BENEFICIARY_ID(bfcp_message *message, bfcp_received_attribute *recvA);
+int bfcp_parse_attribute_FLOOR_ID(bfcp_message *message, bfcp_received_attribute *recvA);
+int bfcp_parse_attribute_FLOOR_REQUEST_ID(bfcp_message *message, bfcp_received_attribute *recvA);
+int bfcp_parse_attribute_PRIORITY(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_request_status *bfcp_parse_attribute_REQUEST_STATUS(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_error *bfcp_parse_attribute_ERROR_CODE(bfcp_message *message, bfcp_received_attribute *recvA);
+char *bfcp_parse_attribute_ERROR_INFO(bfcp_message *message, bfcp_received_attribute *recvA);
+char *bfcp_parse_attribute_PARTICIPANT_PROVIDED_INFO(bfcp_message *message, bfcp_received_attribute *recvA);
+char *bfcp_parse_attribute_STATUS_INFO(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_supported_list *bfcp_parse_attribute_SUPPORTED_ATTRIBUTES(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_supported_list *bfcp_parse_attribute_SUPPORTED_PRIMITIVES(bfcp_message *message, bfcp_received_attribute *recvA);
+char *bfcp_parse_attribute_USER_DISPLAY_NAME(bfcp_message *message, bfcp_received_attribute *recvA);
+char *bfcp_parse_attribute_USER_URI(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_user_information *bfcp_parse_attribute_BENEFICIARY_INFORMATION(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_floor_request_information *bfcp_parse_attribute_FLOOR_REQUEST_INFORMATION(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_user_information *bfcp_parse_attribute_REQUESTED_BY_INFORMATION(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_floor_request_status *bfcp_parse_attribute_FLOOR_REQUEST_STATUS(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_overall_request_status *bfcp_parse_attribute_OVERALL_REQUEST_STATUS(bfcp_message *message, bfcp_received_attribute *recvA);
+int bfcp_parse_attribute_NONCE(bfcp_message *message, bfcp_received_attribute *recvA);
+bfcp_digest *bfcp_parse_attribute_DIGEST(bfcp_message *message, bfcp_received_attribute *recvA);
+
+#if defined __cplusplus
+ }
+#endif
+
+#endif
diff --git a/libs/libbfcp/bfcpmsg/bfcp_messages_build.c b/libs/libbfcp/bfcpmsg/bfcp_messages_build.c
new file mode 100644
index 00000000000..3ef88d64c4f
--- /dev/null
+++ b/libs/libbfcp/bfcpmsg/bfcp_messages_build.c
@@ -0,0 +1,905 @@
+#include "bfcp_messages.h"
+#include "bfcp_strings.h"
+/* Generic BuildMessage Method */
+bfcp_message *bfcp_build_message(bfcp_arguments* arguments)
+{
+ if(!(arguments->entity)) /* Conference ID, Transaction ID and User ID are missing */
+ return NULL; /* This is a fatal error, return with a failure */
+ if((arguments->primitive) == 0) /* The Primitive identifier is missing or invalid */
+ return NULL; /* This is a fatal error, return with a failure */
+
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "bfcp_build_message primitive[%d/%s]\n",
+ arguments->primitive,
+ get_bfcp_primitive(arguments->primitive));
+
+ switch(arguments->primitive) {
+ case FloorRequest:
+ return bfcp_build_message_FloorRequest(arguments->entity, arguments->fID, arguments->bID, arguments->pInfo, arguments->priority);
+ case FloorRelease:
+ return bfcp_build_message_FloorRelease(arguments->entity, arguments->frqID);
+ case FloorRequestQuery:
+ return bfcp_build_message_FloorRequestQuery(arguments->entity, arguments->frqID);
+ case FloorRequestStatus:
+ return bfcp_build_message_FloorRequestStatus(arguments->entity, arguments->frqInfo);
+ case UserQuery:
+ return bfcp_build_message_UserQuery(arguments->entity, arguments->bID);
+ case UserStatus:
+ return bfcp_build_message_UserStatus(arguments->entity, arguments->beneficiary, arguments->frqInfo);
+ case FloorQuery:
+ return bfcp_build_message_FloorQuery(arguments->entity, arguments->fID);
+ case FloorStatus:
+ return bfcp_build_message_FloorStatus(arguments->entity, arguments->fID, arguments->frqInfo);
+ case ChairAction:
+ return bfcp_build_message_ChairAction(arguments->entity, arguments->frqInfo);
+ case ChairActionAck:
+ return bfcp_build_message_ChairActionAck(arguments->entity);
+ case Hello:
+ return bfcp_build_message_Hello(arguments->entity);
+ case HelloAck:
+ return bfcp_build_message_HelloAck(arguments->entity, arguments->primitives, arguments->attributes);
+ case Error:
+ return bfcp_build_message_Error(arguments->entity, arguments->error, arguments->eInfo);
+ default:
+ return NULL; /* Unrecognized Primitive: return with a failure */
+ }
+}
+
+/* Build the message Common Header */
+void bfcp_build_commonheader(bfcp_message *message, bfcp_entity *entity, unsigned short int primitive)
+{
+ unsigned int ch32; /* 32 bits */
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer;
+ ch32 = (((ch32 & !(0xE0000000)) | (1)) << 29) + /* First the Version (3 bits, set to 001) */
+ (((ch32 & !(0x1F000000)) | (0)) << 24) + /* then the Reserved (5 bits, ignored) */
+ (((ch32 & !(0x00FF0000)) | (primitive)) << 16) + /* the Primitive (8 bits) */
+ ((ch32 & !(0x0000FFFF)) | (message->length - 12)/4); /* and the payload length (16 bits), dividing it by 4 to be 4-byte units */
+ ch32 = htonl(ch32); /* We want all protocol values in network-byte-order */
+ memcpy(buffer, &ch32, 4);
+ buffer = buffer+4;
+ ch32 = htonl(entity->conferenceID);
+ memcpy(buffer, &ch32, 4);
+ buffer = buffer+4;
+ ch16 = htons(entity->transactionID);
+ memcpy(buffer, &ch16, 2);
+ ch16 = htons(entity->userID);
+ buffer = buffer+2;
+ memcpy(buffer, &ch16, 2);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Primitive - (%d-%s)\n", primitive, get_bfcp_primitive(primitive));
+}
+
+/* Build the first 16 bits of the Attribute */
+void bfcp_build_attribute_tlv(bfcp_message *message, unsigned short int position, unsigned short int type, unsigned short int mandatory_bit, unsigned short int length)
+{
+ unsigned short int tlv;
+ unsigned char *buffer = message->buffer+position;
+ tlv = (((tlv & !(0xFE00)) | (type)) << 9) + /* Type takes 7 bits */
+ (((tlv & !(0x0100)) | (mandatory_bit)) << 8) + /* M is a bit */
+ ((tlv & !(0x00FF)) | (length)); /* The Lenght takes 8 bits (max 255 bytes) */
+ tlv = htons(tlv);
+ memcpy(buffer, &tlv, 2); /* We copy the TLV to the buffer */
+}
+
+
+
+/* Build Messages */
+
+/* 1*[FLOOR-ID] */
+bfcp_message *bfcp_build_message_FloorRequest(bfcp_entity *entity, bfcp_floor_id_list *fID, unsigned short int bID, char *pInfo, unsigned short int priority)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ bfcp_floor_id_list *temp = fID;
+ while(temp) { /* There can be more than one FLOOR-ID attribute */
+ if(!temp->ID) /* We need a valid FloorID */
+ return NULL;
+ err = bfcp_build_attribute_FLOOR_ID(message, temp->ID);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ temp = temp->next;
+ }
+ if(bID) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_BENEFICIARY_ID(message, bID);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ }
+ if(pInfo) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_PARTICIPANT_PROVIDED_INFO(message, pInfo);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ }
+ if(priority<5) { /* This attribute is not compulsory (must be between 0 and 4) */
+ err = bfcp_build_attribute_PRIORITY(message, priority);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ }
+ /* Append the attributes buffer to the common header one */
+ bfcp_build_commonheader(message, entity, FloorRequest);
+ return message;
+}
+
+bfcp_message *bfcp_build_message_FloorRelease(bfcp_entity *entity, unsigned short int frqID)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ if(!frqID) /* We need a valid FloorRequestID */
+ return NULL;
+ err = bfcp_build_attribute_FLOOR_REQUEST_ID(message, frqID); /* This attribute is compulsory */
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ bfcp_build_commonheader(message, entity, FloorRelease);
+ return message;
+}
+
+bfcp_message *bfcp_build_message_FloorRequestQuery(bfcp_entity *entity, unsigned short int frqID)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ if(!frqID) /* We need a valid FloorRequestID */
+ return NULL;
+ err = bfcp_build_attribute_FLOOR_REQUEST_ID(message, frqID); /* This attribute is compulsory */
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ bfcp_build_commonheader(message, entity, FloorRequestQuery);
+ return message;
+}
+
+bfcp_message *bfcp_build_message_FloorRequestStatus(bfcp_entity *entity, bfcp_floor_request_information *frqInfo)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ if(!frqInfo) /* We need a valid FloorRequestInformation */
+ return NULL;
+ err = bfcp_build_attribute_FLOOR_REQUEST_INFORMATION(message, frqInfo); /* This attribute is compulsory */
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ bfcp_build_commonheader(message, entity, FloorRequestStatus);
+ return message;
+}
+
+bfcp_message *bfcp_build_message_UserQuery(bfcp_entity *entity, unsigned short int bID)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ if(bID) {
+ err = bfcp_build_attribute_BENEFICIARY_ID(message, bID); /*This attribute is not compulsory */
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ }
+ bfcp_build_commonheader(message, entity, UserQuery);
+ return message;
+}
+
+/* 1*[FLOOR-REQUEST-INFORMATION] */
+bfcp_message *bfcp_build_message_UserStatus(bfcp_entity *entity, bfcp_user_information *beneficiary, bfcp_floor_request_information *frqInfo)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ if(beneficiary) /* This attribute is not compulsory */
+ bfcp_build_attribute_BENEFICIARY_INFORMATION(message, beneficiary);
+ bfcp_floor_request_information *temp = frqInfo;
+ while(temp) { /* There can be more than one FLOOR-REQUEST-INFORMATION attribute */
+ err = bfcp_build_attribute_FLOOR_REQUEST_INFORMATION(message, temp);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ temp = temp->next;
+ }
+ bfcp_build_commonheader(message, entity, UserStatus);
+ return message;
+}
+
+/* 1*[FLOOR-ID] */
+bfcp_message *bfcp_build_message_FloorQuery(bfcp_entity *entity, bfcp_floor_id_list *fID)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ bfcp_floor_id_list *temp = fID;
+ if(temp) { /* FLOOR-ID is not compulsory: if missing, the client is not interested */
+ /* in receiving information on any floor anymore */
+ while(temp) { /* There can be more than one FLOOR-ID attribute */
+ if(!temp->ID) /* We need a valid FloorID */
+ return NULL;
+ err = bfcp_build_attribute_FLOOR_ID(message, temp->ID);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ temp = temp->next;
+ }
+ }
+ bfcp_build_commonheader(message, entity, FloorQuery);
+ return message;
+}
+
+/* *[FLOOR-REQUEST-INFORMATION] */
+bfcp_message *bfcp_build_message_FloorStatus(bfcp_entity *entity, bfcp_floor_id_list *fID, bfcp_floor_request_information *frqInfo)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ bfcp_floor_request_information *temp = frqInfo;
+ if(fID) { /* FLOOR-ID is not compulsory: if missing, the client was not interested */
+ /* in receiving information on any floor anymore, so this is just an ack */
+ if(!fID->ID) /* We need a valid FloorID */
+ return NULL;
+ err = bfcp_build_attribute_FLOOR_ID(message, fID->ID); /* This attribute is compulsory */
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ }
+ /* There can be more than one FLOOR-REQUEST-INFORMATION attribute */
+ /* but the attribute is not compulsory */
+ if(temp) {
+ while(temp) { /* There can be more than one FLOOR-REQUEST-INFORMATION attribute */
+ err = bfcp_build_attribute_FLOOR_REQUEST_INFORMATION(message, temp);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ temp = temp->next;
+ }
+ }
+ bfcp_build_commonheader(message, entity, FloorStatus);
+ return message;
+}
+
+/* 1*[FLOOR-ID] */
+bfcp_message *bfcp_build_message_ChairAction(bfcp_entity *entity, bfcp_floor_request_information *frqInfo)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ if(!frqInfo) /* We need a valid FloorRequestInformation */
+ return NULL;
+ err = bfcp_build_attribute_FLOOR_REQUEST_INFORMATION(message, frqInfo); /* This attribute is compulsory */
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ bfcp_build_commonheader(message, entity, ChairAction);
+ return message;
+}
+
+bfcp_message *bfcp_build_message_ChairActionAck(bfcp_entity *entity)
+{
+ bfcp_message *message = bfcp_new_message(NULL, 0); /* This primitive has no attributes */
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ bfcp_build_commonheader(message, entity, ChairActionAck);
+ return message;
+}
+
+bfcp_message *bfcp_build_message_Hello(bfcp_entity *entity)
+{
+ bfcp_message *message = bfcp_new_message(NULL, 0); /* This primitive has no attributes */
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ bfcp_build_commonheader(message, entity, Hello);
+ return message;
+}
+
+bfcp_message *bfcp_build_message_HelloAck(bfcp_entity *entity, bfcp_supported_list *primitives, bfcp_supported_list *attributes)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ err = bfcp_build_attribute_SUPPORTED_PRIMITIVES(message, primitives);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ err = bfcp_build_attribute_SUPPORTED_ATTRIBUTES(message, attributes);
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ bfcp_build_commonheader(message, entity, HelloAck);
+ return message;
+}
+
+bfcp_message *bfcp_build_message_Error(bfcp_entity *entity, bfcp_error *error, char *eInfo)
+{
+ int err;
+ bfcp_message *message = bfcp_new_message(NULL, 0);
+ if(!message) /* We could not allocate the memory, return a with failure */
+ return NULL;
+ err = bfcp_build_attribute_ERROR_CODE(message, error); /* This attribute is compulsory */
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ if(eInfo) {
+ err = bfcp_build_attribute_ERROR_INFO(message, eInfo); /* This attribute is not compulsory */
+ if(err == -1) /* We couldn't build this attribute, return with a failure */
+ return NULL;
+ }
+ bfcp_build_commonheader(message, entity, Error);
+ return message;
+}
+
+
+
+/* Build Attributes */
+
+int bfcp_build_attribute_BENEFICIARY_ID(bfcp_message *message, unsigned short int bID)
+{
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw = htons(bID); /* We want all protocol values in network-byte-order */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "BENEFICIARY_ID [%d]\n", bID);
+ memcpy(buffer, &raw, 2); /* We copy the ID to the buffer */
+ bfcp_build_attribute_tlv(message, position, BENEFICIARY_ID, 1, 4); /* Lenght is fixed (4 octets) */
+ message->length = message->length+4;
+ message->position = message->position+4;
+ return 4;
+}
+
+int bfcp_build_attribute_FLOOR_ID(bfcp_message *message, unsigned short int fID)
+{
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw = htons(fID); /* We want all protocol values in network-byte-order */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FLOOR_ID [%d]\n", fID);
+ memcpy(buffer, &raw, 2); /* We copy the ID to the buffer */
+ bfcp_build_attribute_tlv(message, position, FLOOR_ID, 1, 4); /* Lenght is fixed (4 octets) */
+ message->length = message->length+4;
+ message->position = message->position+4;
+ return 4;
+}
+
+int bfcp_build_attribute_FLOOR_REQUEST_ID(bfcp_message *message, unsigned short int frqID)
+{
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw = htons(frqID); /* We want all protocol values in network-byte-order */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"FLOOR_REQUEST_ID [%d]\n", frqID);
+ memcpy(buffer, &raw, 2); /* We copy the ID to the buffer */
+ bfcp_build_attribute_tlv(message, position, FLOOR_REQUEST_ID, 1, 4); /* Lenght is fixed (4 octets) */
+ message->length = message->length+4;
+ message->position = message->position+4;
+ return 4;
+}
+
+int bfcp_build_attribute_PRIORITY(bfcp_message *message, unsigned short int priority)
+{
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw; /* The 2-octets completing the Attribute */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "PRIORITY [%d/%s]\n", priority, get_bfcp_priority(priority));
+ raw = (((raw & !(0xE000)) | (priority)) << 13) + /* First the Priority (3 bits) */
+ ((raw & !(0x1FFF)) | 0); /* and then the 13 Reserved bits */
+ raw = htons(raw); /* We want all protocol values in network-byte-order */
+ memcpy(buffer, &raw, 2); /* We copy the Priority to the buffer */
+ bfcp_build_attribute_tlv(message, position, PRIORITY, 1, 4); /* Lenght is fixed (4 octets) */
+ message->length = message->length+4;
+ message->position = message->position+4;
+ return 4;
+}
+
+int bfcp_build_attribute_REQUEST_STATUS(bfcp_message *message, bfcp_request_status *rs)
+{
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw; /* The 2-octets completing the Attribute */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "REQUEST_STATUS Status[%d/%s] Queue Position[%d]\n",
+ rs->rs,
+ get_bfcp_status(rs->rs),
+ rs->qp );
+ raw = (((raw & !(0xFF00)) | (rs->rs)) << 8) + /* First the Request Status (8 bits) */
+ ((raw & !(0x00FF)) | (rs->qp)); /* and then the Queue Position (8 bits) */
+ raw = htons(raw); /* We want all protocol values in network-byte-order */
+ memcpy(buffer, &raw, 2); /* We copy the RS and QP to the buffer */
+ bfcp_build_attribute_tlv(message, position, REQUEST_STATUS, 1, 4); /* Lenght is fixed (4 octets) */
+ message->length = message->length+4;
+ message->position = message->position+4;
+ return 4;
+}
+
+int bfcp_build_attribute_ERROR_CODE(bfcp_message *message, bfcp_error *error)
+{
+ if(!error) /* There's no Error Code, return wih a failure */
+ return -1;
+ bfcp_unknown_m_error_details *temp;
+ char ch; /* 8 bits */
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ char raw = ((raw & !(0xFF)) | (error->code)); /* The Error Code is 8 bits */
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR_CODE [%d/%s]\n", error->code, get_bfcp_error_type(error->code));
+
+ memcpy(buffer, &raw, 1); /* We copy the Error Code to the buffer */
+ buffer = buffer+1;
+ attrlen = 3;
+ switch(error->code) {
+ case BFCP_UNKNOWN_MANDATORY_ATTRIBUTE: /* For now, the only error that has more details is error 4 */
+ if(!(error->details))
+ return -1; /* There has to be AT LEAST one error detail, for error 4*/
+ temp = error->details;
+ while(temp) { /* Let's add a byte for each detail we find */
+ ch = (((ch & !(0xFE)) | (temp->unknown_type)) << 1) + /* Attribute: 7 bits */
+ ((ch & !(0x01)) | (temp->reserved)); /* Reserved: 1 bit */
+ attrlen++; /* We remember how many details we've written */
+ temp = temp->next;
+ }
+ if(((attrlen+2)%4) != 0) { /* We need padding */
+ padding = 4-((attrlen+2)%4);
+ memset(buffer+attrlen, 0, padding);
+ }
+ break;
+ default: /* All the others have none, so we add a byte of padding to the message */
+ padding++; /* We just need one byte: TLV+ErrorCode = 3 bytes */
+ memset(buffer, 0, padding);
+ break;
+ }
+ bfcp_build_attribute_tlv(message, position, ERROR_CODE, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
+
+int bfcp_build_attribute_ERROR_INFO(bfcp_message *message, char *eInfo)
+{
+ if(!eInfo) /* The string is empty, return with a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ int eLen = strlen(eInfo);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ERROR_INFO [%s]\n", eInfo? eInfo:"NULL" );
+
+ memcpy(buffer, eInfo, eLen);
+ buffer = buffer+eLen;
+ if(((eLen+2)%4) != 0) { /* We need padding */
+ padding = 4-((eLen+2)%4);
+ memset(buffer+eLen, 0, padding);
+ }
+ attrlen = attrlen+eLen;
+ bfcp_build_attribute_tlv(message, position, ERROR_INFO, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
+
+int bfcp_build_attribute_PARTICIPANT_PROVIDED_INFO(bfcp_message *message, char *pInfo)
+{
+ if(!pInfo) /* The string is empty, return with a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ int pLen = strlen(pInfo);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "PARTICIPANT_PROVIDED_INFO [%s]\n", pInfo? pInfo:"NULL" );
+
+ memcpy(buffer, pInfo, pLen);
+ buffer = buffer+pLen;
+ if(((pLen+2)%4) != 0) { /* We need padding */
+ padding = 4-((pLen+2)%4);
+ memset(buffer+pLen, 0, padding);
+ }
+ attrlen = attrlen+pLen;
+ bfcp_build_attribute_tlv(message, position, PARTICIPANT_PROVIDED_INFO, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
+
+int bfcp_build_attribute_STATUS_INFO(bfcp_message *message, char *sInfo)
+{
+ if(!sInfo) /* The string is empty, return with a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ int sLen = strlen(sInfo);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "STATUS_INFO [%s]\n", sInfo? sInfo:"NULL");
+
+ memcpy(buffer, sInfo, sLen);
+ buffer = buffer+sLen;
+ if(((sLen+2)%4) != 0) { /* We need padding */
+ padding = 4-((sLen+2)%4);
+ memset(buffer+sLen, 0, padding);
+ }
+ attrlen = attrlen+sLen;
+ bfcp_build_attribute_tlv(message, position, STATUS_INFO, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
+
+int bfcp_build_attribute_SUPPORTED_ATTRIBUTES(bfcp_message *message, bfcp_supported_list *attributes)
+{
+ if(!attributes) /* The supported attributes list is empty, return with a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int ch16; /* 16 bits */
+ bfcp_supported_list *temp = attributes;
+ while(temp && temp->element) { /* Fill all supported attributes */
+ ch16 = temp->element;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "SUPPORTED_ATTRIBUTES [%d/%s]\n",
+ temp->element,
+ get_bfcp_attribute(temp->element));
+
+ ch16 = ch16 << 1 ;
+ ch16 = ch16 & 0xFE ; //( BIT R )
+ memcpy(buffer, &ch16, 1);
+ buffer = buffer+1;
+ attrlen = attrlen+1;
+ temp = temp->next;
+ }
+ if((attrlen%4) != 0) { /* We need padding */
+ padding = 4-(attrlen%4);
+ memset(buffer, 0, padding);
+ }
+ bfcp_build_attribute_tlv(message, position, SUPPORTED_ATTRIBUTES, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
+
+int bfcp_build_attribute_SUPPORTED_PRIMITIVES(bfcp_message *message, bfcp_supported_list *primitives)
+{
+ if(!primitives) /* The supported attributes list is empty, return with a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int ch16; /* 16 bits */
+ bfcp_supported_list *temp = primitives;
+ while(temp) { /* Fill all supported primitives */
+ ch16 = temp->element;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "SUPPORTED_PRIMITIVES [%d/%s]\n",
+ temp->element,
+ get_bfcp_primitive(temp->element));
+
+ memcpy(buffer, &ch16, 1);
+ buffer = buffer+1;
+ attrlen = attrlen+1;
+ temp = temp->next;
+ }
+ if((attrlen%4) != 0) { /* We need padding */
+ padding = 4-(attrlen%4);
+ memset(buffer, 0, padding);
+ }
+ bfcp_build_attribute_tlv(message, position, SUPPORTED_PRIMITIVES, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
+
+int bfcp_build_attribute_USER_DISPLAY_NAME(bfcp_message *message, char *display)
+{
+ if(!display) /* The string is empty, return with a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ int dLen = strlen(display);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "USER_DISPLAY_NAME [%s]\n", display? display:"NULL");
+
+ memcpy(buffer, display, dLen);
+ buffer = buffer+dLen;
+ if(((dLen+2)%4) != 0) { /* We need padding */
+ padding = 4-((dLen+2)%4);
+ memset(buffer+dLen, 0, padding);
+ }
+ attrlen = attrlen+dLen;
+ bfcp_build_attribute_tlv(message, position, USER_DISPLAY_NAME, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
+
+int bfcp_build_attribute_USER_URI(bfcp_message *message, char *uri)
+{
+ if(!uri) /* The string is empty, return with a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ int uLen = strlen(uri);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "USER_URI [%s]\n", uri? uri:"NULL");
+
+ memcpy(buffer, uri, uLen);
+ buffer = buffer+uLen;
+ if(((uLen+2)%4) != 0) { /* We need padding */
+ padding = 4-((uLen+2)%4);
+ memset(buffer+uLen, 0, padding);
+ }
+ attrlen = attrlen+uLen;
+ bfcp_build_attribute_tlv(message, position, USER_URI, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
+
+int bfcp_build_attribute_BENEFICIARY_INFORMATION(bfcp_message *message, bfcp_user_information *beneficiary)
+{
+ if(!beneficiary) /* There's no Beneficiary User Information, return wih a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ int length = message->length; /* We keep track of the length before the attributes */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw = htons(beneficiary->ID); /* The 2-octets completing the Attribute Header */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "BENEFICIARY_INFORMATION Beneficiary ID[%d]\n", beneficiary->ID);
+
+ memcpy(buffer, &raw, 2); /* We copy the ID to the buffer */
+ attrlen = attrlen+2;
+ message->length = message->length+4;
+ message->position = message->position+4;
+ /* Here starts the ABNF (it's a grouped attribute) */
+ int err;
+ if(beneficiary->display) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_USER_DISPLAY_NAME(message, beneficiary->display);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ if(beneficiary->uri) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_USER_URI(message, beneficiary->uri);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ bfcp_build_attribute_tlv(message, position, BENEFICIARY_INFORMATION, 1, attrlen);
+ message->length = length+attrlen;
+ message->position = position+attrlen;
+ return attrlen;
+}
+
+/* 1*[FLOOR-REQUEST-STATUS] */
+int bfcp_build_attribute_FLOOR_REQUEST_INFORMATION(bfcp_message *message, bfcp_floor_request_information *frqInfo)
+{
+ if(!frqInfo) /* There's no Floor Request Information, return wih a failure */
+ return -1;
+ bfcp_floor_request_status *temp;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ int length = message->length; /* We keep track of the length before the attributes */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw = htons(frqInfo->frqID); /* The 2-octets completing the Attribute Header */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FLOOR_REQUEST_INFORMATION Floor request ID [%d]\n", frqInfo->frqID);
+ memcpy(buffer, &raw, 2); /* We copy the ID to the buffer */
+ attrlen = attrlen+2;
+ message->length = message->length+4;
+ message->position = message->position+4;
+ /* Here starts the ABNF (it's a grouped attribute) */
+ int err;
+ if(frqInfo->oRS) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_OVERALL_REQUEST_STATUS(message, frqInfo->oRS);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ if(!(frqInfo->fRS))
+ return -1; /* FLOOR-REQUEST-STATUS is 1*, there has to be AT LEAST one, return with a failure */
+ temp = frqInfo->fRS;
+ while(temp) { /* There can be more than one FLOOR-REQUEST-STATUS attribute */
+ err = bfcp_build_attribute_FLOOR_REQUEST_STATUS(message, temp);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ temp = temp->next;
+ }
+ if(frqInfo->beneficiary) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_BENEFICIARY_INFORMATION(message, frqInfo->beneficiary);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ if(frqInfo->requested_by) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_REQUESTED_BY_INFORMATION(message, frqInfo->requested_by);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ if(frqInfo->priority<5) { /* This attribute is not compulsory (must be between 0 and 4) */
+ err = bfcp_build_attribute_PRIORITY(message, frqInfo->priority);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ if(frqInfo->pInfo) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_PARTICIPANT_PROVIDED_INFO(message, frqInfo->pInfo);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ bfcp_build_attribute_tlv(message, position, FLOOR_REQUEST_INFORMATION, 1, attrlen);
+ message->length = length+attrlen;
+ message->position = position+attrlen;
+ return attrlen;
+}
+
+int bfcp_build_attribute_REQUESTED_BY_INFORMATION(bfcp_message *message, bfcp_user_information *requested_by)
+{
+ if(!requested_by) /* There's no RequestedBy User Information, return wih a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ int length = message->length; /* We keep track of the length before the attributes */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ attrlen = attrlen+2;
+ unsigned short int raw = htons(requested_by->ID); /* The 2-octets completing the Attribute Header */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "REQUESTED_BY_INFORMATION Requested by ID[%d]\n", requested_by->ID);
+
+ memcpy(buffer, &raw, 2); /* We copy the ID to the buffer */
+ message->length = message->length+4;
+ message->position = message->position+4;
+ /* Here starts the ABNF (it's a grouped attribute) */
+ int err;
+ if(requested_by->display) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_USER_DISPLAY_NAME(message, requested_by->display);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ if(requested_by->uri) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_USER_URI(message, requested_by->uri);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ bfcp_build_attribute_tlv(message, position, REQUESTED_BY_INFORMATION, 1, attrlen);
+ message->length = length+attrlen;
+ message->position = position+attrlen;
+ return attrlen;
+}
+
+int bfcp_build_attribute_FLOOR_REQUEST_STATUS(bfcp_message *message, bfcp_floor_request_status *fRS)
+{
+ if(!fRS) /* There's no Floor Request Status, return wih a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ int length = message->length; /* We keep track of the length before the attributes */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw = htons(fRS->fID); /* The 2-octets completing the Attribute Header */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FLOOR_REQUEST_STATUS floorId [%d]\n", fRS->fID);
+
+ memcpy(buffer, &raw, 2); /* We copy the ID to the buffer */
+ attrlen = attrlen+2;
+ message->length = message->length+4;
+ message->position = message->position+4;
+ /* Here starts the ABNF (it's a grouped attribute) */
+ int err;
+ if(fRS->rs) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_REQUEST_STATUS(message, fRS->rs);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ }
+ if(fRS->sInfo) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_STATUS_INFO(message, fRS->sInfo);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ bfcp_build_attribute_tlv(message, position, FLOOR_REQUEST_STATUS, 1, attrlen);
+ message->length = length+attrlen;
+ message->position = position+attrlen;
+ return attrlen;
+}
+
+int bfcp_build_attribute_OVERALL_REQUEST_STATUS(bfcp_message *message, bfcp_overall_request_status *oRS)
+{
+ if(!oRS) /* There's no Overall Request Status, return wih a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ int length = message->length; /* We keep track of the length before the attributes */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ unsigned short int raw = htons(oRS->frqID); /* The 2-octets completing the Attribute Header */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "OVERALL_REQUEST_STATUS FloorId[%d]\n", oRS->frqID);
+
+ memcpy(buffer, &raw, 2); /* We copy the ID to the buffer */
+ attrlen = attrlen+2;
+ message->length = message->length+4;
+ message->position = message->position+4;
+ /* Here starts the ABNF (it's a grouped attribute) */
+ int err;
+ if(oRS->rs) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_REQUEST_STATUS(message, oRS->rs);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ }
+ if(oRS->sInfo) { /* This attribute is not compulsory */
+ err = bfcp_build_attribute_STATUS_INFO(message, oRS->sInfo);
+ if(err == -1) /* We couldn't build this attribute, return with an error */
+ return -1;
+ attrlen = attrlen+err;
+ if((err%4) != 0) /* We need padding */
+ attrlen = attrlen+4-(err%4);
+ }
+ bfcp_build_attribute_tlv(message, position, OVERALL_REQUEST_STATUS, 1, attrlen);
+ message->length = length+attrlen;
+ message->position = position+attrlen;
+ return attrlen;
+}
+
+int bfcp_build_attribute_NONCE(bfcp_message *message, unsigned short int nonce)
+{
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "NONCE [%d]\n", nonce);
+ nonce = htons(nonce); /* We want all protocol values in network-byte-order */
+ memcpy(buffer, &nonce, 2); /* We copy the ID to the buffer */
+ bfcp_build_attribute_tlv(message, position, NONCE, 1, 4); /* Lenght is fixed (4 octets) */
+ message->length = message->length+4;
+ message->position = message->position+4;
+ return 4;
+}
+
+int bfcp_build_attribute_DIGEST(bfcp_message *message, bfcp_digest *digest)
+{
+ if(!digest) /* There's no Digest, return with a failure */
+ return -1;
+ int attrlen = 2; /* The Lenght of the attribute (starting from the TLV) */
+ int padding = 0; /* Number of bytes of padding */
+ int position = message->position; /* We keep track of where the TLV will have to be */
+ unsigned char *buffer = message->buffer+(message->position)+2; /* We skip the TLV bytes */
+ char raw = (raw & !(0xFF)) | (digest->algorithm); /* The Algorithm is 8 bits */
+ memcpy(buffer, &raw, 1); /* We copy the Algorithm to the buffer */
+ buffer = buffer+1;
+ int dLen = strlen(digest->text);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "DIGEST text [%s]\n", digest->text? digest->text:"NULL");
+
+ memcpy(buffer, digest->text, dLen);
+ buffer = buffer+dLen;
+ if(((dLen+3)%4) != 0) { /* We need padding */
+ padding = 4-((dLen+3)%4);
+ memset(buffer+dLen, 0, padding);
+ }
+ attrlen = attrlen+dLen+1;
+ bfcp_build_attribute_tlv(message, position, DIGEST, 1, attrlen);
+ message->length = message->length+attrlen+padding;
+ message->position = message->position+attrlen+padding;
+ return attrlen;
+}
diff --git a/libs/libbfcp/bfcpmsg/bfcp_messages_parse.c b/libs/libbfcp/bfcpmsg/bfcp_messages_parse.c
new file mode 100644
index 00000000000..f414f6d7cc9
--- /dev/null
+++ b/libs/libbfcp/bfcpmsg/bfcp_messages_parse.c
@@ -0,0 +1,1232 @@
+#include "bfcp_messages.h"
+#include "bfcp_strings.h"
+
+unsigned short int bfcp_get_length(bfcp_message *message)
+{
+ if(!message)
+ return 0;
+ unsigned long int ch32; /* 32 bits */
+ unsigned short int length; /* 16 bits */
+ unsigned char *buffer = message->buffer;
+ memcpy(&ch32, buffer, 4); /* We copy the first 4 octets of the header */
+ ch32 = ntohl(ch32);
+ length = (ch32 & 0x0000FFFF); /* We get the Lenght of the message */
+ return length;
+}
+
+int bfcp_get_primitive(bfcp_message *message)
+{
+ if(!message)
+ return 0;
+ unsigned long int ch32; /* 32 bits */
+ int primitive;
+ unsigned char *buffer = message->buffer;
+ memcpy(&ch32, buffer, 4); /* We copy the first 4 octets of the header */
+ ch32 = ntohl(ch32);
+ primitive = ((ch32 & 0x00FF0000) >> 16); /* We get the Primitive identifier */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Primitive[%d/0x%x][%s]\n",primitive,primitive,get_bfcp_primitive(primitive));
+ return primitive;
+}
+
+unsigned long int bfcp_get_conferenceID(bfcp_message *message)
+{
+ if(!message)
+ return 0;
+ unsigned long int ch32; /* 32 bits */
+ unsigned long int conferenceID; /* 32 bits */
+ unsigned char *buffer = message->buffer + 4;
+ memcpy(&ch32, buffer, 4); /* We skip the first 4 octets of the header and copy */
+ conferenceID = ntohl(ch32); /* We get the conferenceID of the message */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "conferenceID[%lu]\n",conferenceID);
+ return conferenceID;
+}
+
+unsigned short int bfcp_get_transactionID(bfcp_message *message)
+{
+ if(!message)
+ return 0;
+ unsigned long int ch16; /* 16 bits */
+ unsigned short int transactionID; /* 16 bits */
+ unsigned char *buffer = message->buffer + 8;
+ memcpy(&ch16, buffer, 2); /* We skip the first 8 octets of the header and copy */
+ transactionID = ntohs(ch16); /* We get the transactionID of the message */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "TransactionID[0x%x]",transactionID);
+ return transactionID;
+}
+
+unsigned short int bfcp_get_userID(bfcp_message *message)
+{
+ if(!message)
+ return 0;
+ unsigned long int ch16; /* 16 bits */
+ unsigned short int userID; /* 16 bits */
+ unsigned char *buffer = message->buffer + 10;
+ memcpy(&ch16, buffer, 2); /* We skip the first 10 octets of the header and copy */
+ userID = ntohs(ch16); /* We get the userID of the message */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "userID[0x%x]\n",userID);
+ return userID;
+}
+
+bfcp_received_message *bfcp_new_received_message(void)
+{
+ bfcp_received_message *recvM = calloc(1, sizeof(bfcp_received_message));
+ if(!recvM) /* We could not allocate the memory, return with a failure */
+ return NULL;
+ recvM->arguments = NULL;
+ recvM->version = 0;
+ recvM->reserved = 0;
+ recvM->length = 0;
+ recvM->primitive = 0;
+ recvM->entity = bfcp_new_entity(0, 0, 0);
+ recvM->first_attribute = NULL;
+ recvM->errors = NULL;
+ return recvM;
+}
+
+int bfcp_free_received_message(bfcp_received_message *recvM)
+{
+ int res = 0; /* We keep track here of the results of the sub-freeing methods*/
+ if(!recvM) /* There's nothing to free, return with a failure */
+ return -1;
+ if(recvM->arguments)
+ res += bfcp_free_arguments(recvM->arguments);
+ if(recvM->entity)
+ res += bfcp_free_entity(recvM->entity);
+ if(recvM->first_attribute)
+ res += bfcp_free_received_attribute(recvM->first_attribute);
+ if(recvM->errors)
+ res += bfcp_free_received_message_errors(recvM->errors);
+ free(recvM);
+ if(!res) /* No error occurred, succesfully freed the structure */
+ return 0;
+ else /* res was not 0, so some error occurred, return with a failure */
+ return -1;
+}
+
+bfcp_received_message_error *bfcp_received_message_add_error(bfcp_received_message_error *error, unsigned short int attribute, unsigned short int code)
+{
+ bfcp_received_message_error *temp, *previous;
+ if(!error) { /* The Error list doesn't exist yet, we create a new one */
+ error = calloc(1, sizeof(bfcp_received_message_error));
+ if(!error) /* We could not allocate the memory, return with a failure */
+ return NULL;
+ error->attribute = attribute;
+ error->code = code;
+ error->next = NULL;
+ return error;
+ } else {
+ previous = error;
+ temp = previous->next;
+ while(temp) { /* We search the last added error */
+ previous = temp;
+ temp = previous->next;
+ }
+ temp = calloc(1, sizeof(bfcp_received_message_error));
+ if(!temp) /* We could not allocate the memory, return with a failure */
+ return NULL;
+ temp->attribute = attribute;
+ temp->code = code;
+ temp->next = NULL;
+ previous->next = temp; /* Update the old last link in the list */
+ return error;
+ }
+}
+
+int bfcp_free_received_message_errors(bfcp_received_message_error *errors)
+{
+ if(!errors) /* There's nothing to free, return with a failure */
+ return -1;
+ bfcp_received_message_error *next = NULL, *temp = errors;
+ while(temp) {
+ next = temp->next;
+ free(temp);
+ temp = next;
+ }
+ return 0;
+}
+
+bfcp_received_attribute *bfcp_new_received_attribute(void)
+{
+ bfcp_received_attribute *recvA = calloc(1, sizeof(bfcp_received_attribute));
+ if(!recvA) /* We could not allocate the memory, return with a failure */
+ return NULL;
+ recvA->type = 0;
+ recvA->mandatory_bit = 0;
+ recvA->length = 0;
+ recvA->position = 0;
+ recvA->valid = 1; /* By default we mark the attribute as valid */
+ recvA->next = NULL;
+ return recvA;
+}
+
+int bfcp_free_received_attribute(bfcp_received_attribute *recvA)
+{
+ if(!recvA) /* There's nothing to free, return with a failure */
+ return -1;
+ bfcp_received_attribute *next = NULL, *temp = recvA;
+ while(temp) {
+ next = temp->next;
+ free(temp);
+ temp = next;
+ }
+ return 0;
+}
+
+bfcp_received_message *bfcp_parse_message(bfcp_message *message)
+{
+ bfcp_received_attribute *temp1 = NULL, *temp2 = NULL, *previous = NULL;
+ unsigned char *buffer;
+ unsigned short int ch16; /* 16 bits */
+ unsigned int ch32; /* 32 bits */
+ bfcp_received_message *recvM = bfcp_new_received_message();
+ if(!recvM) /* We could not allocate the memory, return with a failure */
+ return NULL;
+ /* First we read the Common Header and we parse it */
+ buffer = message->buffer;
+ memcpy(&ch32, buffer, 4); /* We copy the first 4 octets of the header */
+ ch32 = ntohl(ch32);
+ recvM->version = ((ch32 & 0xE0000000) >> 29); /* Version bits (must be 001) */
+ if((recvM->version) != 1) { /* Version is wrong, return with an error */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Unsupported protocol version %d\n", recvM->version);
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, 0, BFCP_WRONG_VERSION);
+ if(!(recvM->errors))
+ return NULL; /* An error occurred while recording the error, return with failure */
+ }
+ recvM->reserved = ((ch32 & 0x1F000000) >> 24); /* Reserved bits (they should be ignored but we check them anyway) */
+ if((recvM->reserved) != 0) { /* Reserved bits are not 0, return with an error */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, 0, BFCP_RESERVED_NOT_ZERO);
+ if(!(recvM->errors))
+ return NULL; /* An error occurred while recording the error, return with failure */
+ }
+ recvM->primitive = ((ch32 & 0x00FF0000) >> 16); /* Primitive identifier */
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Primitive(%d) - %s\n", recvM->primitive, get_bfcp_primitive(recvM->primitive));
+
+ recvM->length = (ch32 & 0x0000FFFF)*4 + 12; /* Payload length is in 4-byte units */
+ if(((recvM->length) != message->length) || ((recvM->length%4) != 0)) { /* The message length is wrong */
+ /* Either the length in the header is different from the length of the buffer... */
+ /* ...or the length is not a multiple of 4, meaning it's surely not aligned */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: payload length does not match data read from network.\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "We read %u bytes from network while message length calculated from mayload length is %u.\n",
+ message->length,
+ recvM->length);
+
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, 0, BFCP_WRONG_LENGTH);
+ if(!(recvM->errors))
+ return NULL; /* An error occurred while recording the error, return with failure */
+ }
+ if(recvM->errors) /* There are errors in the header, we won't proceed further */
+ return recvM;
+ buffer = buffer+4;
+ memcpy(&ch32, buffer, 4); /* Conference ID */
+ recvM->entity->conferenceID = ntohl(ch32);
+ buffer = buffer+4;
+ memcpy(&ch16, buffer, 2); /* Transaction ID */
+ recvM->entity->transactionID = ntohs(ch16);
+ buffer = buffer+2;
+ memcpy(&ch16, buffer, 2); /* User ID */
+ recvM->entity->userID = ntohs(ch16);
+ buffer = buffer+2;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "ConferenceID[%lu], UserID[%u], TransactionID[%u]\n",
+ recvM->entity->conferenceID,
+ recvM->entity->userID,
+ recvM->entity->transactionID);
+
+ message->position = 12; /* We've read the Common Header */
+ while(recvM->length>message->position) { /* We start parsing attributes too */
+ temp1 = bfcp_parse_attribute(message);
+ if(!temp1) /* We could not parse the attribute, return with a failure */
+ return NULL;
+ if(!(recvM->first_attribute)) { /* This is the first attribute we read */
+ recvM->first_attribute = temp1; /* Let's save it as first attribute */
+ recvM->first_attribute->next = NULL;
+ temp2 = temp1;
+ }
+ else { /* It's not the first attribute, let's manage the list */
+ temp2->next = temp1;
+ temp1->next = NULL;
+ previous = temp2;
+ temp2 = temp1;
+ }
+ if(temp1->length == 0) {
+ /* If the length of the attribute is 0 we have to stop, we'd fall in an eternal loop
+ We save this error regarding this attribute (temp1 -> Wrong Lenght)
+ and we save it for the attribute before (temp2) too, since it lead us here */
+ temp1->valid = 0; /* We mark the attribute as not valid */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp1->type, BFCP_WRONG_LENGTH);
+ if(!(recvM->errors))
+ return NULL; /* An error occurred while recording the error, return with failure */
+ if(previous) { /* Only add the error if there's an attribute before */
+ previous->valid = 0; /* We mark the attribute as not valid */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, previous->type, BFCP_WRONG_LENGTH);
+ if(!(recvM->errors))
+ return NULL; /* An error occurred while recording the error, return with failure */
+ }
+ message->position = recvM->length; /* We don't go on parsing, since we can't jump this attribute */
+ }
+ }
+ if(bfcp_parse_arguments(recvM, message) == -1) {/* We could not parse the arguments of the message */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to parse BFCP message arguments.\n");
+ return NULL;
+ } /* Return with a failure */
+ recvM->length = recvM->length-12; /* Before leaving, we remove the Common Header Lenght (12 bytes) */
+ /* from the Payload Lenght of the message */
+ return recvM;
+}
+
+bfcp_received_attribute *bfcp_parse_attribute(bfcp_message *message)
+{
+ int padding = 0;
+ unsigned char *buffer;
+ unsigned short int ch16; /* 16 bits */
+ bfcp_received_attribute *recvA = bfcp_new_received_attribute();
+ if(!recvA) /* We could not allocate the memory, return with a failure */
+ return NULL;
+ recvA->position = message->position; /* The position of the attribute in the buffer */
+ buffer = message->buffer+recvA->position;
+ memcpy(&ch16, buffer, 2); /* TLV: Attribute Header */
+ ch16 = ntohs(ch16);
+ recvA->type = ((ch16 & 0xFE00) >> 9); /* Type */
+ recvA->mandatory_bit = ((ch16 & 0x0100) >> 8); /* M */
+ recvA->length = (ch16 & 0x00FF); /* Lenght */
+ buffer = buffer+2;
+ if(((recvA->length)%4) != 0) /* There's padding stuff to jump too */
+ padding = 4-((recvA->length)%4);
+ message->position = message->position+recvA->length + /* There could be some padding */
+ padding; /* (which is not signed in length) */
+ return recvA;
+}
+
+int bfcp_parse_arguments(bfcp_received_message *recvM, bfcp_message *message)
+{
+ bfcp_received_attribute *temp = recvM->first_attribute;
+ if(!recvM) /* We could not allocate the memory, return with a failure */
+ return -1;
+ int floorID;
+ bfcp_floor_id_list *tempID = NULL; /* To manage the FLOOR-ID List */
+ bfcp_floor_request_information *tempInfo = NULL, *previousInfo = NULL;/* FLOOR-REQUEST-INFORMATION list */
+ recvM->arguments = bfcp_new_arguments();
+ recvM->arguments->primitive = recvM->primitive; /* Primitive */
+ recvM->arguments->entity = bfcp_new_entity(recvM->entity->conferenceID, /* Entity, we copy it not to */
+ recvM->entity->transactionID, recvM->entity->userID); /* to risk a double free() */
+ if(!(recvM->arguments)) /* We could not allocate the memory, return with a failure */
+ return -1;
+ while(temp) {
+ if(!(temp->valid)) { /* If the attribute is marked as not valid, we skip it... */
+ temp = temp->next;
+ continue;
+ } else switch(temp->type) { /* ...if it's valid, we parse it */
+ case BENEFICIARY_ID:
+ recvM->arguments->bID = bfcp_parse_attribute_BENEFICIARY_ID(message, temp);
+ if(!recvM->arguments->bID) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case FLOOR_ID:
+ if(!tempID) { /* Create a list, it's the first ID we add */
+ floorID = bfcp_parse_attribute_FLOOR_ID(message, temp);
+ if(!floorID) { /* An error occurred while parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ recvM->arguments->fID = bfcp_new_floor_id_list(floorID, 0);
+ tempID = recvM->arguments->fID;
+ if(!tempID) /* An error occurred in creating a new ID */
+ return -1;
+ break;
+ } else { /* We already have a list, add the new FloorID to it */
+ floorID = bfcp_parse_attribute_FLOOR_ID(message, temp);
+ if(!floorID) { /* An error occurred while parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ if(bfcp_add_floor_id_list(tempID, floorID, 0) == -1)
+ return -1;
+ break;
+ }
+ case FLOOR_REQUEST_ID:
+ recvM->arguments->frqID = bfcp_parse_attribute_FLOOR_REQUEST_ID(message, temp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FLOOR_REQUEST_ID[%d]\n",recvM->arguments->frqID);
+ break;
+ case PRIORITY:
+ recvM->arguments->priority = bfcp_parse_attribute_PRIORITY(message, temp);
+ if(recvM->arguments->priority>4) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case REQUEST_STATUS:
+ recvM->arguments->rs = bfcp_parse_attribute_REQUEST_STATUS(message, temp);
+ if(!(recvM->arguments->rs)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case ERROR_CODE:
+ recvM->arguments->error = bfcp_parse_attribute_ERROR_CODE(message, temp);
+ if(!(recvM->arguments->error)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case ERROR_INFO:
+ recvM->arguments->eInfo = bfcp_parse_attribute_ERROR_INFO(message, temp);
+ if(!(recvM->arguments->eInfo)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case PARTICIPANT_PROVIDED_INFO:
+ recvM->arguments->pInfo = bfcp_parse_attribute_PARTICIPANT_PROVIDED_INFO(message, temp);
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "PARTICIPANT_PROVIDED_INFO[%s]\n",
+ recvM->arguments->pInfo?recvM->arguments->pInfo:"");
+
+ if(!(recvM->arguments->pInfo)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case STATUS_INFO:
+ recvM->arguments->sInfo = bfcp_parse_attribute_STATUS_INFO(message, temp);
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "STATUS_INFO[%s]\n",
+ recvM->arguments->sInfo?recvM->arguments->sInfo:"");
+
+ if(!(recvM->arguments->sInfo)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case SUPPORTED_ATTRIBUTES:
+ recvM->arguments->attributes = bfcp_parse_attribute_SUPPORTED_ATTRIBUTES(message, temp);
+ if(!(recvM->arguments->attributes)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case SUPPORTED_PRIMITIVES:
+ recvM->arguments->primitives = bfcp_parse_attribute_SUPPORTED_PRIMITIVES(message, temp);
+ if(!(recvM->arguments->primitives)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case USER_DISPLAY_NAME:
+ return -1; /* We can't have this Attribute directly in a primitive */
+ case USER_URI:
+ return -1; /* We can't have this Attribute directly in a primitive */
+ case BENEFICIARY_INFORMATION:
+ recvM->arguments->beneficiary = bfcp_parse_attribute_BENEFICIARY_INFORMATION(message, temp);
+ if(!(recvM->arguments->beneficiary)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case FLOOR_REQUEST_INFORMATION:
+ if(!tempInfo) { /* Create a list, it's the first F.R.Info we add */
+ recvM->arguments->frqInfo = bfcp_parse_attribute_FLOOR_REQUEST_INFORMATION(message, temp);
+ if(!(recvM->arguments->frqInfo)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ tempInfo = previousInfo = recvM->arguments->frqInfo;
+ break;
+ } else {
+ tempInfo = bfcp_parse_attribute_FLOOR_REQUEST_INFORMATION(message, temp);
+ if(!tempInfo) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ tempInfo->next = NULL;
+ previousInfo->next = tempInfo;
+ previousInfo = tempInfo;
+ break;
+ }
+ break;
+ case REQUESTED_BY_INFORMATION:
+ return -1; /* We can't have this Attribute directly in a primitive */
+ case FLOOR_REQUEST_STATUS:
+ return -1; /* We can't have this Attribute directly in a primitive */
+ case OVERALL_REQUEST_STATUS:
+ return -1; /* We can't have this Attribute directly in a primitive */
+ case NONCE:
+ recvM->arguments->nonce = bfcp_parse_attribute_NONCE(message, temp);
+ if(!recvM->arguments->nonce) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ case DIGEST:
+ recvM->arguments->digest = bfcp_parse_attribute_DIGEST(message, temp);
+ if(!(recvM->arguments->digest)) { /* An error occurred in parsing this attribute */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_PARSING_ERROR);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ }
+ break;
+ default: /* An unrecognized attribute, remember it */
+ recvM->errors = bfcp_received_message_add_error(recvM->errors, temp->type, BFCP_UNKNOWN_ATTRIBUTE);
+ if(!(recvM->errors))
+ return -1; /* An error occurred while recording the error, return with failure */
+ temp->valid = 0; /* We mark the attribute as not valid */
+ break;
+ }
+ temp = temp->next;
+ }
+ return 0;
+}
+
+/* In parsing the attributes, we return 0 (or NULL) if something is WRONG, and return the value if all is ok */
+/* This is necessary since many arguments are unsigned, so cannot return -1 to notify that an error happened */
+/* In parsing the priority, an error is not 0, but a return value more than 4 (since priority is [0, 4]) */
+int bfcp_parse_attribute_BENEFICIARY_ID(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length != 4) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute BENEFICIARY_ID length [%d] is incorrect. Should be 4.\n",
+ recvA->length);
+ return 0;
+ }
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ ch16 = ntohs(ch16);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "BENEFICIARY_ID = [%d]\n", ch16);
+ return ch16;
+}
+
+int bfcp_parse_attribute_FLOOR_ID(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length != 4) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Wrong FLOOR_ID length [%d]. Should be 4.\n", recvA->length);
+ return 0;
+ }
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ ch16 = ntohs(ch16);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FLOOR_ID = [%d]\n", ch16);
+ return ch16;
+}
+
+int bfcp_parse_attribute_FLOOR_REQUEST_ID(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length != 4) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "parse attribute FLOOR_REQUEST_ID length [%d] is not correct. Should be 4.\n",
+ recvA->length);
+ return 0;
+ }
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ ch16 = ntohs(ch16);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FLOOR_REQUEST_ID = [%d]\n", ch16);
+ return ch16;
+}
+
+int bfcp_parse_attribute_PRIORITY(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length != 4) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Parse attribute PRIORITY length [%d] incorrect. Should be 4.\n",recvA->length );
+ return 0;
+ }
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ ch16 = ntohs(ch16);
+ if((ch16 & (0x1FFF)) != 0) /* The Reserved bits are not 0 */
+ return 0; /* Return with a failure */
+ return ((ch16 & (0xE000)) >> 13);
+}
+
+bfcp_request_status *bfcp_parse_attribute_REQUEST_STATUS(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length != 4) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute REQUEST_STATUS length [%d] is not correct. Should be 4.\n",
+ recvA->length);
+ return NULL;
+ }
+ bfcp_request_status *rs;
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ ch16 = ntohs(ch16);
+ rs = bfcp_new_request_status(
+ ((ch16 & (0xFF00)) >> 8), /* Request Status */
+ (ch16 & (0x00FF))); /* Queue Position */
+ if(!rs) /* An error occurred when creating the new Request Status */
+ return NULL; /* Return with a failure */
+
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "REQUEST_STATUS request Status [%s] Queue Position [%d]\n",
+ get_bfcp_status(rs->rs), rs->qp );
+ return rs;
+}
+
+bfcp_error *bfcp_parse_attribute_ERROR_CODE(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Parse attribute ERROR_CODE length [%d] is incorrect. Should be at lease 3.\n",
+ recvA->length );
+ return NULL;
+ }
+ bfcp_error *error = bfcp_new_error(0, NULL);
+ bfcp_unknown_m_error_details *first, *previous, *next;
+ if(!error) /* An error occurred when creating a new Error Code */
+ return NULL; /* Return with a failure */
+ char ch; /* 8 bits */
+ int i;
+ int number = 0; /* The number of specific details we might find */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch, buffer, 1);
+ error->code = (unsigned short int)ch; /* We get the Error Code*/
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"ERROR_CODE [%s] (%d)",get_bfcp_error_type(error->code), error->code);
+
+ switch(error->code) {
+ case BFCP_UNKNOWN_MANDATORY_ATTRIBUTE: /* For now, the only error that has more details is error 4 */
+ number = recvA->length-3; /* Each error detail takes 1 byte */
+ if(number == 0) {
+ /* There has to be AT LEAST one error detail, for error 4*/
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing error code detailed information.\n");
+ return NULL;
+ }
+
+ first = calloc(1, sizeof(bfcp_unknown_m_error_details));
+ if(!first) /* An error occurred in creating a new Details list */
+ return NULL;
+ buffer++; /* We skip the Error Code byte */
+ memcpy(&ch, buffer, 1);
+ first->unknown_type = ((ch & (0xFE)) >> 1); /* The Unknown Attribute, 7 bits */
+ first->reserved = (ch & (0x01)); /* The Reserved bit */
+ previous = first;
+ if(number>1) { /* Let's parse each other detail we find */
+ for(i = 1;iunknown_type = ((ch & (0xFE)) >> 1); /* The Unknown Attribute, 7 bits */
+ next->reserved = (ch & (0x01)); /* The Reserved bit */
+ previous->next = next;
+ previous = next;
+ }
+ }
+ error->details = first;
+ break;
+ default: /* All the others have none, so we can ignore it */
+ break;
+ }
+ return error;
+}
+
+char *bfcp_parse_attribute_ERROR_INFO(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute ERROR_INFO length [%d] is incorrect. Should be at least 3.\n",
+ recvA->length);
+ return NULL;
+ }
+
+ char ch = '\0';
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ char *eInfo = calloc(recvA->length-1, sizeof(char)); /* Lenght is TLV Header too */
+ memcpy(eInfo, buffer, recvA->length-2);
+ memcpy(eInfo+(recvA->length-2), &ch, 1); /* We add a terminator char to the string */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Parse attribute ERROR_INFO [%s]\n", eInfo?eInfo:"NULL");
+ return eInfo;
+}
+
+char *bfcp_parse_attribute_PARTICIPANT_PROVIDED_INFO(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute PARTICIPANT_PROVIDED_INFO length [%d] is incorrect. Should be at least 3.\n",
+ recvA->length);
+ return NULL;
+ }
+
+ char ch = '\0';
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ char *pInfo = calloc(recvA->length-1, sizeof(char)); /* Lenght is TLV Header too */
+ memcpy(pInfo, buffer, recvA->length-2);
+ memcpy(pInfo+(recvA->length-2), &ch, 1); /* We add a terminator char to the string */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Parse attribute PARTICIPANT_PROVIDED_INFO [%s].\n", pInfo? pInfo:"NULL");
+ return pInfo;
+}
+
+char *bfcp_parse_attribute_STATUS_INFO(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute STATUS_INFO length [%d] is incorrect. Should be at least 3.\n",
+ recvA->length);
+ return NULL;
+ }
+
+ char ch = '\0';
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ char *sInfo = calloc(recvA->length-1, sizeof(char)); /* Lenght is TLV Header too */
+ memcpy(sInfo, buffer, recvA->length-2);
+ memcpy(sInfo+(recvA->length-2), &ch, 1); /* We add a terminator char to the string */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "STATUS_INFO [%s]\n", sInfo? sInfo:"NULL");
+ return sInfo;
+}
+
+bfcp_supported_list *bfcp_parse_attribute_SUPPORTED_ATTRIBUTES(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute SUPPORTED_ATTRIBUTES length [%d] incorrect should be at lease 3",
+ recvA->length);
+ return NULL;
+ }
+
+ int i;
+ bfcp_supported_list *first, *previous, *next;
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ int number = (recvA->length-2)/2; /* Each supported attribute takes 2 bytes */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SUPPORTED_ATTRIBUTES number of attributes %d\n", number);
+ if(!number)
+ return NULL; /* No supported attributes? */
+ first = calloc(1, sizeof(bfcp_supported_list));
+ if(!first) /* An error occurred in creating a new Supported Attributes list */
+ return NULL;
+ memcpy(&ch16, buffer, 2);
+ first->element = ntohs(ch16);
+ previous = first;
+ if(number>1) { /* Let's parse each other supported attribute we find */
+ for(i = 1;ielement = ntohs(ch16);
+ previous->next = next;
+ previous = next;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "SUPPORTED_ATTRIBUTE: [%d-%s]\n",
+ next->element,
+ get_bfcp_attribute(next->element));
+ }
+ }
+ return first;
+}
+
+bfcp_supported_list *bfcp_parse_attribute_SUPPORTED_PRIMITIVES(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "parse attribute SUPPORTED_PRIMITIVES invalid length [%d]. Should be more than 3.\n",
+ recvA->length);
+ return NULL;
+ }
+
+ int i;
+ bfcp_supported_list *first, *previous, *next;
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ int number = (recvA->length-2)/2; /* Each supported primitive takes 2 bytes */
+ if(!number)
+ return NULL; /* No supported primitives? */
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Parse attribute SUPPORTED_PRIMITIVES number of primitives %d.\n", number);
+
+ first = calloc(1, sizeof(bfcp_supported_list));
+ if(!first) /* An error occurred in creating a new Supported Attributes list */
+ return NULL;
+ memcpy(&ch16, buffer, 2);
+ first->element = ntohs(ch16);
+ previous = first;
+ if(number>1) { /* Let's parse each other supported primitive we find */
+ for(i = 1;ielement = ntohs(ch16);
+ previous->next = next;
+ previous = next;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Parse attribute SUPPORTED_PRIMITIVES [%d-%s]\n",
+ next->element,
+ get_bfcp_primitive(next->element));
+ }
+ }
+ return first;
+}
+
+char *bfcp_parse_attribute_USER_DISPLAY_NAME(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute USER_DISPLAY_NAME invalid length [%d]. Should be more than 3.\n",
+ recvA->length);
+ return NULL;
+ }
+ char ch = '\0';
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ char *display = calloc(recvA->length-1, sizeof(char)); /* Lenght is TLV Header too */
+ memcpy(display, buffer, recvA->length-2);
+ memcpy(display+(recvA->length-2), &ch, 1); /* We add a terminator char to the string */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Parse attribute USER_DISPLAY_NAME [%s]\n", display? display:"NULL");
+ return display;
+}
+
+char *bfcp_parse_attribute_USER_URI(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute USER_URI invalid length [%d]. Should be more than 3.\n",
+ recvA->length);
+ return NULL;
+ }
+ char ch = '\0';
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ char *uri = calloc(recvA->length-1, sizeof(char)); /* Lenght is TLV Header too */
+ memcpy(uri, buffer, recvA->length-2);
+ memcpy(uri+(recvA->length-2), &ch, 1); /* We add a terminator char to the string */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "USER_URI [%s]\n", uri? uri:"NULL");
+ return uri;
+}
+
+bfcp_user_information *bfcp_parse_attribute_BENEFICIARY_INFORMATION(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute BENEFICIARY_INFORMATION invalid length [%d]. Should be more than 3.\n",
+ recvA->length);
+ return NULL;
+ }
+ int position;
+ bfcp_received_attribute *attribute = NULL;
+ bfcp_user_information *beneficiary = NULL;
+ unsigned short int ch16, bID; /* 16 bits */
+ char *display = NULL, *uri = NULL;
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ bID = ntohs(ch16); /* The first value, BeneficiaryID */
+ /* Display and URI are not compulsory, they might not be in the message, let's check it */
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "BENEFICIARY_INFORMATION(Beneficiary ID[%d])\n", bID);
+
+ message->position = recvA->position+4;
+ while(recvA->length>((message->position)-(recvA->position))) {
+ position = message->position; /* Remember where message was before attribute parsing */
+ attribute = bfcp_parse_attribute(message);
+ if(!attribute) /* An error occurred while parsing this attribute */
+ return NULL;
+ switch(attribute->type) {
+ case USER_DISPLAY_NAME:
+ display = bfcp_parse_attribute_USER_DISPLAY_NAME(message, attribute);
+ if(!display) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ case USER_URI:
+ uri = bfcp_parse_attribute_USER_URI(message, attribute);
+ if(!uri) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ default: /* There's an attribute that shouldn't be here... */
+ break;
+ }
+ message->position = position+attribute->length;
+ if(((attribute->length)%4) != 0)
+ message->position = message->position+4-((attribute->length)%4);
+ bfcp_free_received_attribute(attribute);
+ }
+ beneficiary = bfcp_new_user_information(bID, display, uri);
+ if(!beneficiary) /* An error occurred in creating a new Beneficiary User Information */
+ return NULL;
+ if(display)
+ free(display);
+ if(uri)
+ free(uri);
+ message->position = recvA->position+recvA->length;
+ if(((recvA->length)%4) != 0)
+ message->position = message->position+4-((recvA->length)%4);
+ return beneficiary;
+}
+
+bfcp_floor_request_information *bfcp_parse_attribute_FLOOR_REQUEST_INFORMATION(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute FLOOR_REQUEST_INFORMATION invalid length [%d]. Should be more than 3.\n",
+ recvA->length);
+ return NULL;
+ }
+ int position;
+ unsigned short int frqID, priority = 0;
+ bfcp_floor_request_information *frqInfo = NULL;
+ bfcp_received_attribute *attribute = NULL;
+ unsigned short int ch16; /* 16 bits */
+ bfcp_overall_request_status *oRS = NULL;
+ bfcp_floor_request_status *fRS = NULL, *tempRS = NULL;
+ bfcp_user_information *beneficiary = NULL, *requested_by = NULL;
+ char *pInfo = NULL;
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ frqID = ntohs(ch16); /* The first value, FloorRequestID */
+ /* Some attributes are not compulsory, they might not be in the message, let's check it */
+ /* FLOOR-REQUEST-STATUS has 1* multiplicity, there has to be AT LEAST one, */
+ /* So remember to check its presence outside, in server/client */
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FLOOR_REQUEST_INFORMATION(Floor request ID[%d])\n", frqID);
+
+ message->position = recvA->position+4;
+ while(recvA->length>((message->position)-(recvA->position))) {
+ position = message->position; /* Remember where message was before attribute parsing */
+ attribute = bfcp_parse_attribute(message);
+ if(!attribute) /* An error occurred while parsing this attribute */
+ return NULL;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Parse attribute FLOOR_REQUEST_INFORMATION Floor request ID[%d] Attribute type(%s)\n",
+ frqID,
+ get_bfcp_attribute(attribute->type));
+
+ switch(attribute->type) {
+ case OVERALL_REQUEST_STATUS:
+ oRS = bfcp_parse_attribute_OVERALL_REQUEST_STATUS(message, attribute);
+ if(!oRS) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ case FLOOR_REQUEST_STATUS:
+ if(!fRS) { /* Create a list, it's the first FLOOR-REQUEST-STATUS we add */
+ fRS = bfcp_parse_attribute_FLOOR_REQUEST_STATUS(message, attribute);
+ if(!fRS) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ } else { /* We already have a list, add the new FLOOR-REQUEST-STATUS to it */
+ tempRS = bfcp_parse_attribute_FLOOR_REQUEST_STATUS(message, attribute);
+ if(!tempRS) /* An error occurred while parsing this attribute */
+ return NULL;
+ if(bfcp_add_floor_request_status_list(fRS, tempRS, NULL) == -1)
+ return NULL;
+ break;
+ }
+ case BENEFICIARY_INFORMATION:
+ beneficiary = bfcp_parse_attribute_BENEFICIARY_INFORMATION(message, attribute);
+ if(!beneficiary) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ case REQUESTED_BY_INFORMATION:
+ requested_by = bfcp_parse_attribute_REQUESTED_BY_INFORMATION(message, attribute);
+ if(!requested_by) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ case PRIORITY:
+ priority = bfcp_parse_attribute_PRIORITY(message, attribute);
+ if(priority>4) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ case PARTICIPANT_PROVIDED_INFO:
+ pInfo = bfcp_parse_attribute_PARTICIPANT_PROVIDED_INFO(message, attribute);
+ if(!pInfo) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ default: /* There's an attribute that shouldn't be here... */
+ break;
+ }
+ message->position = position+attribute->length;
+ if(((attribute->length)%4) != 0)
+ message->position = message->position+4-((attribute->length)%4);
+ bfcp_free_received_attribute(attribute);
+ }
+ frqInfo = bfcp_new_floor_request_information(frqID, oRS, fRS, beneficiary, requested_by, priority, pInfo);
+ if(!frqInfo) /* An error occurred in creating a new Floor Request Information */
+ return NULL;
+ if(pInfo)
+ free(pInfo);
+ message->position = recvA->position+recvA->length;
+ if(((recvA->length)%4) != 0)
+ message->position = message->position+4-((recvA->length)%4);
+ return frqInfo;
+}
+
+bfcp_user_information *bfcp_parse_attribute_REQUESTED_BY_INFORMATION(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute REQUEST_BY_INFORMATION invalid length [%d]. Should be more than 3.\n",
+ recvA->length);
+ return NULL;
+ }
+
+ int position;
+ bfcp_received_attribute *attribute = NULL;
+ bfcp_user_information *requested_by = NULL;
+ unsigned short int ch16, rID; /* 16 bits */
+ char *display = NULL, *uri = NULL;
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ rID = ntohs(ch16); /* The first value, ReceivedByID */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Parse attribute REQUESTED_BY_INFORMATION Requested by ID[%d].\n", rID);
+ /* Display and URI are not compulsory, they might not be in the message, let's check it */
+ message->position = recvA->position+4;
+ while(recvA->length>((message->position)-(recvA->position))) {
+ position = message->position; /* Remember where message was before attribute parsing */
+ attribute = bfcp_parse_attribute(message);
+ if(!attribute) /* An error occurred while parsing this attribute */
+ return NULL;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Parse attribute REQUESTED_BY_INFORMATION request ID[%d] Attribute type(%s).\n",
+ rID,
+ get_bfcp_attribute(attribute->type));
+
+ switch(attribute->type) {
+ case USER_DISPLAY_NAME:
+ display = bfcp_parse_attribute_USER_DISPLAY_NAME(message, attribute);
+ if(!display) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ case USER_URI:
+ uri = bfcp_parse_attribute_USER_URI(message, attribute);
+ if(!uri) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ default: /* There's an attribute that shouldn't be here... */
+ break;
+ }
+ message->position = position+attribute->length;
+ if(((attribute->length)%4) != 0)
+ message->position = message->position+4-((attribute->length)%4);
+ bfcp_free_received_attribute(attribute);
+ }
+ requested_by = bfcp_new_user_information(rID, display, uri);
+ if(!requested_by) /* An error occurred in creating a new Beneficiary User Information */
+ return NULL;
+ if(display)
+ free(display);
+ if(uri)
+ free(uri);
+ message->position = recvA->position+recvA->length;
+ if(((recvA->length)%4) != 0)
+ message->position = message->position+4-((recvA->length)%4);
+ return requested_by;
+}
+
+bfcp_floor_request_status *bfcp_parse_attribute_FLOOR_REQUEST_STATUS(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute FLOOR_REQUEST_STATUS invalid length [%d]. Should be more than 3.\n",
+ recvA->length);
+ return NULL;
+ }
+ int position;
+ unsigned short int fID;
+ bfcp_received_attribute *attribute = NULL;
+ bfcp_floor_request_status *fRS = NULL;
+ unsigned short int ch16; /* 16 bits */
+ bfcp_request_status *rs = NULL;
+ char *sInfo = NULL;
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ fID = ntohs(ch16); /* The first value, FloorID */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FLOOR_REQUEST_STATUS floorId [%d]\n", fID);
+ /* Some attributes are not compulsory, they might not be in the message, let's check it */
+ message->position = recvA->position+4;
+ while(recvA->length>((message->position)-(recvA->position))) {
+ position = message->position; /* Remember where message was before attribute parsing */
+ attribute = bfcp_parse_attribute(message);
+ if(!attribute) /* An error occurred while parsing this attribute */
+ return NULL;
+ switch(attribute->type) {
+ case REQUEST_STATUS:
+ rs = bfcp_parse_attribute_REQUEST_STATUS(message, attribute);
+ if(!rs) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ case STATUS_INFO:
+ sInfo = bfcp_parse_attribute_STATUS_INFO(message, attribute);
+ if(!sInfo) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ default: /* There's an attribute that shouldn't be here... */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "FLOOR_REQUEST_STATUS - unexpected attribute type(%s)\n",
+ get_bfcp_attribute(attribute->type));
+ break;
+ }
+ message->position = position+attribute->length;
+ if(((attribute->length)%4) != 0)
+ message->position = message->position+4-((attribute->length)%4);
+ bfcp_free_received_attribute(attribute);
+ }
+ fRS = bfcp_new_floor_request_status(fID, rs->rs, rs->qp, sInfo);
+ if(!fRS) /* An error occurred in creating a new Floor Request Information */
+ return NULL;
+ if(rs)
+ bfcp_free_request_status(rs);
+ if(sInfo)
+ free(sInfo);
+ message->position = recvA->position+recvA->length;
+ if(((recvA->length)%4) != 0)
+ message->position = message->position+4-((recvA->length)%4);
+ return fRS;
+}
+
+bfcp_overall_request_status *bfcp_parse_attribute_OVERALL_REQUEST_STATUS(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<3) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Parse attribute OVERALL_REQUEST_STATUS invalid length [%d]. Should be more than 3.\n",
+ recvA->length);
+ return NULL;
+ }
+ int position;
+ unsigned short int frqID;
+ bfcp_received_attribute *attribute = NULL;
+ bfcp_overall_request_status *oRS = NULL;
+ unsigned short int ch16; /* 16 bits */
+ bfcp_request_status *rs = NULL;
+ char *sInfo = NULL;
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ frqID = ntohs(ch16); /* The first value, FloorID */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Parse attribute OVERALL_REQUEST_STATUS FloorRequestId[%d]\n", frqID);
+ /* Some attributes are not compulsory, they might not be in the message, let's check it */
+ message->position = recvA->position+4;
+ while(recvA->length>((message->position)-(recvA->position))) {
+ position = message->position; /* Remember where message was before attribute parsing */
+ attribute = bfcp_parse_attribute(message);
+ if(!attribute) /* An error occurred while parsing this attribute */
+ return NULL;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Parse attribute OVERALL_REQUEST_STATUS Requested by(%s).\n",
+ get_bfcp_attribute(attribute->type));
+
+ switch(attribute->type) {
+ case REQUEST_STATUS:
+ rs = bfcp_parse_attribute_REQUEST_STATUS(message, attribute);
+ if(!rs) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ case STATUS_INFO:
+ sInfo = bfcp_parse_attribute_STATUS_INFO(message, attribute);
+ if(!sInfo) /* An error occurred while parsing this attribute */
+ return NULL;
+ break;
+ default: /* There's an attribute that shouldn't be here... */
+ break;
+ }
+ message->position = position+attribute->length;
+ if(((attribute->length)%4) != 0)
+ message->position = message->position+4-((attribute->length)%4);
+ bfcp_free_received_attribute(attribute);
+ }
+ oRS = bfcp_new_overall_request_status(frqID, rs->rs, rs->qp, sInfo);
+ if(!oRS) /* An error occurred in creating a new Floor Request Information */
+ return NULL;
+ if(rs)
+ bfcp_free_request_status(rs);
+ if(sInfo)
+ free(sInfo);
+ message->position = recvA->position+recvA->length;
+ if(((recvA->length)%4) != 0)
+ message->position = message->position+4-((recvA->length)%4);
+ return oRS;
+}
+
+int bfcp_parse_attribute_NONCE(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length != 4) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse attribute NONCE length [%d]. Should be 4.\n", recvA->length);
+ return -1;
+ }
+ unsigned short int ch16; /* 16 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch16, buffer, 2);
+ ch16 = ntohs(ch16);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Parse attribute NONCE [%d]\n", ch16);
+ return ch16;
+}
+
+bfcp_digest *bfcp_parse_attribute_DIGEST(bfcp_message *message, bfcp_received_attribute *recvA)
+{
+ if(recvA->length<4) {/* The length of this attribute is wrong */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse attribute DIGEST length [%d]. Should be at least 4.\n", recvA->length);
+ return NULL;
+ }
+ char ch; /* 8 bits */
+ unsigned char *buffer = message->buffer+recvA->position+2; /* Skip the Header */
+ memcpy(&ch, buffer, 1);
+ bfcp_digest *digest = bfcp_new_digest((unsigned short int)ch); /* Algorithm */
+ buffer = buffer+1; /* Skip the Algorithm byte */
+ digest->text = calloc(recvA->length-2, sizeof(char)); /* Lenght is TLV + Algorithm byte too */
+ if(!digest) /* An error occurred in creating a new Digest */
+ return NULL;
+ memcpy(digest->text, buffer, recvA->length-3);
+ ch = '\0';
+ memcpy((digest->text)+(recvA->length-3), &ch, 1); /* We add a terminator char to the string */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Parse attribute DIGEST text[%s]\n", digest->text);
+ return digest;
+}
diff --git a/libs/libbfcp/bfcpmsg/bfcp_strings.c b/libs/libbfcp/bfcpmsg/bfcp_strings.c
new file mode 100644
index 00000000000..be2564f9245
--- /dev/null
+++ b/libs/libbfcp/bfcpmsg/bfcp_strings.c
@@ -0,0 +1,73 @@
+#include "bfcp_strings.h"
+
+/* Retrieve the string of BFCP primitive */
+const char* get_bfcp_primitive(int p)
+{
+ char *primitive = "Unknown Primitive";
+
+ if ( p > 0 || p <= 16 ) {
+ return bfcp_primitive[p-1].description ;
+ }
+
+ return primitive;
+}
+
+/* Retrieve the string of BFCP attribute */
+const char* get_bfcp_attribute(int a)
+{
+ char *attribute = "Unknown Attribute";
+
+ if ( a > 0 || a <= 20 ) {
+ return bfcp_attribute[a-1].description;
+ }
+
+ return attribute ;
+}
+
+/* Retrieve the string of BFCP status */
+const char* get_bfcp_status(int s)
+{
+ char *status = "Invalid";
+
+ if ( s > 0 || s <= 7 ) {
+ return bfcp_status[s-1].description;
+ }
+
+ return status;
+}
+
+/* Retrieve the string of BFCP priority */
+const char* get_bfcp_priority(unsigned short int p)
+{
+ char *priority = "Lowest";
+
+ if (p > 0 || p <= 4) {
+ return bfcp_priority[p-1].description;
+ }
+
+ return priority;
+}
+
+/* Retrieve the string of BFCP error type */
+const char* get_bfcp_error_type(int et)
+{
+ char *error_type = "Unknown Error Type";
+
+ if (et > 0 || et <= 12) {
+ return bfcp_error_type[et-1].description;
+ }
+
+ return error_type;
+}
+
+/* Retrieve the string of parsing error */
+const char* get_bfcp_parsing_errors(int e)
+{
+ char *error = "Unknown Parsing Error";
+
+ if (e > 0 || e <= 6) {
+ return bfcp_parsing_error[e - 1].description;
+ }
+
+ return error;
+}
diff --git a/libs/libbfcp/bfcpmsg/bfcp_strings.h b/libs/libbfcp/bfcpmsg/bfcp_strings.h
new file mode 100644
index 00000000000..60b5173a424
--- /dev/null
+++ b/libs/libbfcp/bfcpmsg/bfcp_strings.h
@@ -0,0 +1,150 @@
+/* String definitions for BFCP numeric values */
+
+
+#include "bfcp_messages.h"
+
+static const struct bfcp_primitives {
+ int primitive;
+ const char *description;
+} bfcp_primitive[] = {
+ { FloorRequest, "FloorRequest" },
+ { FloorRelease, "FloorRelease" },
+ { FloorRequestQuery, "FloorRequestQuery" },
+ { FloorRequestStatus, "FloorRequestStatus" },
+ { UserQuery, "UserQuery" },
+ { UserStatus, "UserStatus" },
+ { FloorQuery, "FloorQuery" },
+ { FloorStatus, "FloorStatus" },
+ { ChairAction, "ChairAction" },
+ { ChairActionAck, "ChairActionAck" },
+ { Hello, "Hello" },
+ { HelloAck, "HelloAck" },
+ { Error, "Error" },
+ { FloorRequestStatusAck, "FloorRequestStatusAck" },
+ { ErrorAck, "ErrorAck" },
+ { FloorStatusAck, "FloorStatusAck" },
+};
+
+static const struct bfcp_attributes {
+ int attribute;
+ const char *description;
+} bfcp_attribute[] = {
+ { BENEFICIARY_ID, "BENEFICIARY-ID" },
+ { FLOOR_ID, "FLOOR-ID" },
+ { FLOOR_REQUEST_ID, "FLOOR-REQUEST-ID" },
+ { PRIORITY, "PRIORITY" },
+ { REQUEST_STATUS, "REQUEST-STATUS" },
+ { ERROR_CODE, "ERROR-CODE" },
+ { ERROR_INFO, "ERROR-INFO" },
+ { PARTICIPANT_PROVIDED_INFO, "PARTICIPANT-PROVIDED-INFO" },
+ { STATUS_INFO, "STATUS-INFO" },
+ { SUPPORTED_ATTRIBUTES, "SUPPORTED-ATTRIBUTES" },
+ { SUPPORTED_PRIMITIVES, "SUPPORTED-PRIMITIVES" },
+ { USER_DISPLAY_NAME, "USER-DISPLAY-NAME" },
+ { USER_URI, "USER-URI" },
+ { BENEFICIARY_INFORMATION, "BENEFICIARY-INFORMATION" },
+ { FLOOR_REQUEST_INFORMATION, "FLOOR-REQUEST-INFORMATION" },
+ { REQUESTED_BY_INFORMATION, "REQUESTED-BY-INFORMATION" },
+ { FLOOR_REQUEST_STATUS, "FLOOR-REQUEST-STATUS" },
+ { OVERALL_REQUEST_STATUS, "OVERALL-REQUEST-STATUS" },
+ { NONCE, "NONCE" },
+ { DIGEST, "DIGEST" },
+};
+
+static const struct bfcp_statuses {
+ int status;
+ const char *description;
+} bfcp_status[] = {
+ { BFCP_PENDING, "Pending" },
+ { BFCP_ACCEPTED, "Accepted" },
+ { BFCP_GRANTED, "Granted" },
+ { BFCP_DENIED, "Denied" },
+ { BFCP_CANCELLED, "Cancelled" },
+ { BFCP_RELEASED, "Released" },
+ { BFCP_REVOKED, "Revoked" },
+};
+
+static const struct bfcp_priorities {
+ int priority;
+ const char *description;
+} bfcp_priority[] = {
+ { BFCP_LOWEST_PRIORITY, "Lowest" },
+ { BFCP_LOW_PRIORITY, "Low" },
+ { BFCP_NORMAL_PRIORITY, "Normal" },
+ { BFCP_HIGH_PRIORITY, "High" },
+ { BFCP_HIGHEST_PRIORITY, "Highest" },
+};
+
+static const struct bfcp_error_types {
+ int error;
+ const char *description;
+} bfcp_error_type[] = {
+ { BFCP_CONFERENCE_DOES_NOT_EXIST, "Conference does not Exist"},
+ { BFCP_USER_DOES_NOT_EXIST, "User does not Exist"},
+ { BFCP_UNKNOWN_PRIMITIVE, "Unknown Primitive"},
+ { BFCP_UNKNOWN_MANDATORY_ATTRIBUTE, "Unknown Mandatory Attribute"},
+ { BFCP_UNAUTHORIZED_OPERATION, "Unauthorized Operation"},
+ { BFCP_INVALID_FLOORID, "Invalid Floor ID"},
+ { BFCP_FLOORREQUEST_DOES_NOT_EXIST, "Floor Request ID Does Not Exist"},
+ { BFCP_MAX_FLOORREQUESTS_REACHED, "You have Already Reached the Maximum Number of Ongoing Floor Requests for this Floor"},
+ { BFCP_USE_TLS, "Use TLS"},
+ { BFCP_DIGEST_ATTRIBUTE_REQUIRED, "Digest Attribute Required"},
+ { BFCP_INVALID_NONCE, "Invalid Nonce"},
+ { BFCP_AUTHENTICATION_FAILED, "Authentication Failed"},
+};
+
+static const struct bfcp_parsing_errors {
+ int error;
+ const char *description;
+} bfcp_parsing_error[] = {
+ { BFCP_WRONG_VERSION, "Wrong Version Bit" },
+ { BFCP_RESERVED_NOT_ZERO, "Reserved bits not zeroed" },
+ { BFCP_UNKNOWN_PRIMITIVE, "Unknown Primitive" },
+ { BFCP_UNKNOWN_ATTRIBUTE, "Unknown Attribute" },
+ { BFCP_WRONG_LENGTH, "Wrong Length" },
+ { BFCP_PARSING_ERROR, "Parsing Error" },
+};
+
+
+/*!
+ \brief Retrieve the string for corresponding BFCP primitive value
+ \param p BFCP primitive value
+ \return BFCP primitive string
+ */
+const char* get_bfcp_primitive(int p);
+
+/*!
+ \brief Retrieve the string for corresponding BFCP attribute value
+ \param a BFCP attribute value
+ \return BFCP attribute string
+ */
+const char* get_bfcp_attribute(int a);
+
+/*!
+ \brief Retrieve the string for corresponding BFCP status value
+ \param s BFCP status value
+ \return BFCP status string
+ */
+const char* get_bfcp_status(int s);
+
+/*!
+ \brief Retrieve the string for corresponding BFCP priority
+ \param p BFCP priority value
+ \return BFCP priority string
+ */
+const char* get_bfcp_priority(unsigned short int p);
+
+/*!
+ \brief Retrieve the string for corresponding BFCP error_type
+ \param et BFCP error_type value
+ \return BFCP error_type string
+ */
+const char* get_bfcp_error_type(int et);
+
+/*!
+ \brief Retrieve the string for corresponding BFCP parsing_error
+ \param e BFCP parsing_error value
+ \return BFCP parsing_error string
+ */
+const char* get_bfcp_parsing_errors(int e);
+
diff --git a/libs/libbfcp/bfcpsrvclt/README.md b/libs/libbfcp/bfcpsrvclt/README.md
new file mode 100644
index 00000000000..dcbee4550d8
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/README.md
@@ -0,0 +1,43 @@
+BFCP server and client libraries
+================================
+
+This is a brief guide to the compilation of the BFCP (Binary Floor Control Protocol) libraries implementing the behavior layer for both servers and clients, according to the RFC specifications, and of the sample applications that have been made available to test the libraries.
+
+The main files that are both available for the BFCP participant and BFCP server are main.c, a small list of operations to test all the options of the BFCP libraries.
+
+## Compiling the libraries
+
+Before compiling these libraries, you'll need the BFCP messages library (`bfcpmsg`) installed. Besides, the libraries depend on pthread and OpenSSL, so be sure to install them before proceeding.
+
+Edit the `Makefile` according to your settings and compiler. By default gcc will be used, and each library installed to /usr as destination prefix (/usr/include, /usr/lib).
+
+There are several available targets to compile the code:
+
+* `make linux` will compile the testcode and the library, creating an executable file for Linux;
+* `make win32` will compile the testcode and the library, creating an executable file for Windows;
+* `make so` will only compile the library, creating a shared object for Linux;
+* `make dll` will only compile the library, creating a DLL for Windows.
+
+If you want to compile all the available targets, just use:
+
+ make all
+
+To install the compiled library (on Linux only), type, as root:
+
+ make install
+
+To install the libraries in a Windows environment you'll need to manually copy the headers file to your include folder, and copy the resulting DLL(s) where needed.
+
+## Testing the libraries
+
+You can execute the sample applications to test the just compiled libraries by typing:
+
+ ./bfcp_participant
+
+in the `bfcpclt` folder, and:
+
+ ./bfcp_server
+
+in the `bfcpsrv` folder. If you want to exploit the BFCP over TLS functionality, you'll need to create a certificate file and a private key for the server. By default the BFCP server will use `server.pem` as certificate filename and `server.key` as private key filename, and it will look for those file in the current folder. In case you want to use different files in the test application, edit the opportune line of code in `main.c` to meet your requirements and recompile. No certificates and keys are currently used for the participant side.
+
+A menu option has been made available in both the applications to test the libraries. Just play with it according to your needs to learn how the library works and to make tests on your own.
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpclt/Makefile b/libs/libbfcp/bfcpsrvclt/bfcpclt/Makefile
new file mode 100644
index 00000000000..66085930ccd
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpclt/Makefile
@@ -0,0 +1,47 @@
+PREFIX = /usr
+CC = gcc
+CC_W32 = i686-pc-mingw32-gcc
+OBJS = bfcp_participant.o
+OBJS_W32 = bfcp_participant.obj
+OPTS = -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -O2
+LIBS = -lbfcpmsg -lpthread -lssl -lcrypto
+LIBS_W32 = -lbfcpmsg -lws2_32 -lpthreadGC2 -lssleay32 -llibeay32 #-s
+DEPS_W32 = -L./
+WIN32 = -DWIN32
+
+so : $(OBJS)
+ $(CC) -ggdb -shared -Wl,-soname,libbfcpclt.so.0 -o libbfcpclt.so.0.0.7 $(OBJS) $(OPTS) $(LIBS)
+
+%.o: %.c
+ $(CC) -fPIC -ggdb -c $< -o $@ $(OPTS)
+
+dll : $(OBJS_W32)
+ $(CC_W32) $(WIN32) -ggdb -shared -o libbfcpclt.dll $(OBJS_W32) $(OPTS) $(DEPS_W32) $(LIBS_W32)
+
+%.obj: %.c
+ $(CC_W32) $(WIN32) -ggdb -c $< -o $@ $(OPTS)
+
+linux : main.o $(OBJS)
+ $(CC) -ggdb -o bfcp_participant main.o $(OBJS) $(OPTS) $(LIBS)
+
+win32 : dll main.obj
+ $(CC_W32) $(WIN32) -ggdb -o bfcp_participant.exe main.obj $(OPTS) $(DEPS_W32) -lbfcpclt $(LIBS_W32)
+
+clean :
+ rm -f *.o *.obj libbfcpclt* bfcp_participant bfcp_participant.exe
+
+all: clean so dll linux win32
+
+install:
+ @echo Installing BFCP client library to $(PREFIX)/lib/:
+ install -m 755 libbfcpclt.so.0.0.7 $(PREFIX)/lib/
+ ln -sf $(PREFIX)/lib/libbfcpclt.so.0.0.7 $(PREFIX)/lib/libbfcpclt.so.0
+ ln -sf $(PREFIX)/lib/libbfcpclt.so.0 $(PREFIX)/lib/libbfcpclt.so
+ @echo Installing BFCP client headers to $(PREFIX)/include/:
+ install -m 755 bfcp_participant.h $(PREFIX)/include/
+
+uninstall:
+ @echo Uninstalling BFCP client library from $(PREFIX)/lib/:
+ rm -f $(PREFIX)/lib/libbfcpclt*
+ @echo Uninstalling BFCP client headers from $(PREFIX)/include/:
+ rm -f $(PREFIX)/include/bfcp_participant.h
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpclt/bfcp_participant.c b/libs/libbfcp/bfcpsrvclt/bfcpclt/bfcp_participant.c
new file mode 100644
index 00000000000..7699bbd42c8
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpclt/bfcp_participant.c
@@ -0,0 +1,989 @@
+#include "bfcp_participant.h"
+
+/* Macro to check for errors after sending a BFCP message */
+#define BFCP_SEND_CHECK_ERRORS \
+ if(error <= 0) { \
+ if(arguments != NULL) \
+ bfcp_free_arguments(arguments); \
+ if(message != NULL) \
+ bfcp_free_message(message); \
+ close(server_sock); \
+ pthread_mutex_unlock(&count_mutex); \
+ return -1; \
+ } else { \
+ bfcp_free_arguments(arguments); \
+ bfcp_free_message(message); \
+ pthread_mutex_unlock(&count_mutex); \
+ }
+
+
+static unsigned short int base_transactionID = 1; /* TransactionID of the client */
+#ifndef WIN32
+static struct pollfd pollfds[1];
+#endif
+
+/* Thread- and mutex-related variables */
+static pthread_mutex_t count_mutex;
+static pthread_t thread;
+
+/* Socket-related variables */
+static int server_sock; /* File descriptor of the connection towards the FCS */
+static fd_set wset; /* Select-set for writing data to the FCS */
+
+/* TLS-related stuff */
+static int bfcp_transport; /* Wheter we use TCP/BFCP or TCP/TLS/BFCP */
+static SSL_CTX *context; /* SSL Context */
+static SSL_METHOD *method; /* SSL Method (TLSv1) */
+static SSL *session; /* SSL Session */
+
+
+/* Headers for private methods */
+int send_message_to_server(bfcp_message *message, int sockfd);
+bfcp_message *received_message_from_server(int sockfd, int *close_socket);
+void *recv_thread(void *func);
+
+
+/* Create a new Participant */
+struct bfcp_participant_information *bfcp_initialize_bfcp_participant(unsigned long int conferenceID, unsigned short int userID, char *IP_address_server, unsigned short int port_server, void( *received_msg)(bfcp_received_message *recv_msg), int transport)
+{
+ if(conferenceID == 0) {
+ printf("Invalid conference ID\n");
+ return NULL;
+ }
+ if(userID == 0) {
+ printf("Invalid userID\n");
+ return NULL;
+ }
+ if(port_server <= 1024) {
+ printf("Invalid port\n");
+ port_server = BFCP_FCS_DEFAULT_PORT;
+ }
+ if(IP_address_server == NULL) {
+ printf("Invalid IP\n");
+ return NULL;
+ }
+
+#ifdef WIN32
+ WSADATA wsaData;
+ WSAStartup(MAKEWORD(1, 1), &wsaData);
+#endif
+
+ if(transport < 1)
+ bfcp_transport = BFCP_OVER_TCP;
+ else
+ bfcp_transport = BFCP_OVER_TLS;
+
+ if(bfcp_transport == BFCP_OVER_TLS) {
+ /* Initialize TLS-related stuff */
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ method = (SSL_METHOD*)TLSv1_client_method();
+ if(!method)
+ return NULL;
+ context = SSL_CTX_new(method);
+ if(!context)
+ return NULL;
+ if(SSL_CTX_set_cipher_list(context, SSL_DEFAULT_CIPHER_LIST) < 0)
+ return NULL;
+ }
+
+ struct sockaddr_in server_addr;
+ conference_participant struct_participant;
+
+ /* Allocate and setup the new participant */
+ struct_participant = (conference_participant)calloc(1, sizeof(bfcp_participant_information));
+ if(struct_participant == NULL) {
+ printf("Couldn't allocate participant\n");
+ return NULL;
+ }
+
+ struct_participant->conferenceID = conferenceID;
+ struct_participant->userID = userID;
+ struct_participant->pfloors = NULL;
+
+ /* Initialize the mutex */
+ pthread_mutex_init(&count_mutex, NULL);
+ pthread_mutex_lock(&count_mutex);
+
+ /* Handle the socket-related operations */
+ server_sock = socket(AF_INET,SOCK_STREAM,0);
+ if(server_sock == -1) {
+ pthread_mutex_unlock(&count_mutex);
+ printf("Couldn't create socket\n");
+ return NULL;
+ }
+
+ /* Fill in the server information */
+ server_addr.sin_family = AF_INET;
+#ifndef WIN32
+ if((inet_aton(IP_address_server, &server_addr.sin_addr)) <= 0) { /* Not a numeric IP... */
+#else
+ server_addr.sin_addr.s_addr = inet_addr(IP_address_server);
+ if((inet_addr(IP_address_server)) <= 0) {
+#endif
+ struct hostent *host = gethostbyname(IP_address_server); /* ...resolve name */
+ if(!host) {
+ pthread_mutex_unlock(&count_mutex);
+ printf("Couldn't get host\n");
+ return NULL;
+ }
+ server_addr.sin_addr = *(struct in_addr *)host->h_addr_list;
+ }
+ server_addr.sin_port = htons(port_server);
+ memset(&(server_addr.sin_zero), '\0', 8);
+
+ /* Connect to the Floor Control Server */
+ if(connect(server_sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
+ pthread_mutex_unlock(&count_mutex);
+ printf("Couldn't connect (is the server up?)\n");
+ return NULL;
+ }
+
+ if(bfcp_transport == BFCP_OVER_TLS) {
+ /* Once the connection has been established, make the SSL Handshake */
+ session = SSL_new(context);
+ if(!session) {
+#ifndef WIN32
+ shutdown(server_sock, SHUT_RDWR);
+#else
+ shutdown(server_sock, SD_BOTH);
+#endif
+ close(server_sock);
+ pthread_mutex_unlock(&count_mutex);
+ return NULL;
+ }
+ if(SSL_set_fd(session, server_sock) < 1) {
+#ifndef WIN32
+ shutdown(server_sock, SHUT_RDWR);
+#else
+ shutdown(server_sock, SD_BOTH);
+#endif
+ close(server_sock);
+ pthread_mutex_unlock(&count_mutex);
+ return NULL;
+ }
+ if(SSL_connect(session) < 1) {
+#ifndef WIN32
+ shutdown(server_sock, SHUT_RDWR);
+#else
+ shutdown(server_sock, SD_BOTH);
+#endif
+ close(server_sock);
+ pthread_mutex_unlock(&count_mutex);
+ return NULL;
+ }
+ }
+
+ FD_ZERO(&wset);
+ FD_SET(server_sock, &wset);
+
+ /* Create the thread that will handle all incoming messages from the FCS */
+ if(pthread_create(&thread, NULL, recv_thread, (void *)received_msg) < 0) {
+ pthread_mutex_unlock(&count_mutex);
+ printf("Couldn't create thread\n");
+ return NULL;
+ }
+ pthread_detach(thread);
+ pthread_mutex_unlock(&count_mutex);
+
+ return struct_participant;
+}
+
+/* Destroy an existing Participant */
+int bfcp_destroy_bfcp_participant(bfcp_participant_information **participantp)
+{
+ if(participantp == NULL)
+ return -1;
+
+ bfcp_participant_information *participant = *participantp;
+
+ remove_floor_list_p(participant->pfloors);
+ free(participant);
+ participant = NULL;
+ *participantp = NULL;
+
+ /* Close the connection towards the FCS */
+#ifndef WIN32
+ shutdown(server_sock, SHUT_RDWR);
+#else
+ shutdown(server_sock, SD_BOTH);
+#endif
+ close(server_sock);
+
+ if(bfcp_transport == BFCP_OVER_TLS) {
+ /* Free TLS-related stuff */
+ SSL_free(session);
+ SSL_CTX_free(context);
+ }
+
+ /* Destroy the thread */
+ pthread_cancel(thread);
+
+ bfcp_transport = -1;
+
+ return 0;
+}
+
+/* Add a floor to the list of floors the participant will be aware of */
+int bfcp_insert_floor_participant(conference_participant participant, unsigned short int floorID)
+{
+ if(floorID <= 0)
+ return -1;
+ if(participant == NULL)
+ return -1;
+
+ participant->pfloors = insert_floor_list_p(participant->pfloors, floorID, NULL);
+
+ return 0;
+}
+
+/* Delete a floor from the list of floors the participant is aware of */
+int bfcp_delete_floor_participant(conference_participant participant, unsigned short int floorID)
+{
+ if(floorID <= 0)
+ return -1;
+ if(participant == NULL)
+ return -1;
+
+ floors_participant floor, temp_floor;
+ floor = participant->pfloors;
+
+ if(floor != NULL) {
+ if(floor->floorID == floorID) {
+ participant->pfloors = floor->next;
+ } else {
+ while((floor->next != NULL) && (floor->next->floorID != floorID))
+ floor = floor->next;
+ if(floor->next!=NULL) {
+ temp_floor = floor;
+ floor = floor->next;
+ temp_floor->next = floor->next;
+ }
+ }
+ }
+
+ if((floor == NULL) || (floor->floorID != floorID))
+ /* This floorID is not in the list */
+ return -1;
+
+ free(floor);
+ floor = NULL;
+
+ return 0;
+}
+
+
+/* BFCP Participant side Messages-related operations */
+
+/* Hello */
+int bfcp_hello_participant(conference_participant participant)
+{
+ if(participant == NULL)
+ return -1;
+
+ int error;
+ bfcp_arguments *arguments;
+ bfcp_message *message;
+
+ pthread_mutex_lock(&count_mutex);
+
+ /* Prepare a new 'Hello' message */
+ arguments = bfcp_new_arguments();
+ arguments->primitive = Hello;
+ arguments->entity = bfcp_new_entity(participant->conferenceID, base_transactionID, participant->userID);
+ message = bfcp_build_message(arguments);
+ if(!message) {
+ pthread_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&count_mutex);
+
+ /* Send the message to the FCS */
+ error = send_message_to_server(message, server_sock);
+ BFCP_SEND_CHECK_ERRORS;
+
+ return 0;
+}
+
+/* FloorRequest */
+int bfcp_floorRequest_participant(conference_participant participant, unsigned short int beneficiaryID, unsigned short int priority, bfcp_floors_participant *list_floors, char *participant_info)
+{
+ if(participant == NULL)
+ return -1;
+ if(priority > BFCP_HIGHEST_PRIORITY)
+ priority = BFCP_HIGHEST_PRIORITY;
+ if(list_floors == NULL)
+ return -1;
+
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message;
+ int error, dLen;
+ bfcp_floor_id_list *node = NULL;
+
+ bfcp_floors_participant *tempnode, *temp_list_floors, *floors_IDs;
+
+ /* Check if all the provided floors exist, otherwise give an error */
+ for(tempnode = list_floors; tempnode; tempnode = tempnode->next) {
+ temp_list_floors = participant->pfloors;
+ while(temp_list_floors && (temp_list_floors->floorID > tempnode->floorID))
+ temp_list_floors = temp_list_floors->next;
+ if((temp_list_floors == NULL) || (tempnode->floorID != temp_list_floors->floorID))
+ /* This floor is not in the list */
+ return -1;
+
+ }
+
+ pthread_mutex_lock(&count_mutex);
+
+ /* Prepare a new 'FloorRequest' message */
+ arguments = bfcp_new_arguments();
+ arguments->primitive = FloorRequest;
+ arguments->entity = bfcp_new_entity(participant->conferenceID, base_transactionID, participant->userID);
+
+ floors_IDs = list_floors;
+ if(floors_IDs != NULL)
+ node = bfcp_new_floor_id_list(floors_IDs->floorID, 0);
+ floors_IDs = floors_IDs->next;
+
+ while(floors_IDs != NULL){
+ bfcp_add_floor_id_list(node,floors_IDs->floorID, 0);
+ floors_IDs = floors_IDs->next;
+ }
+
+ arguments->fID = node;
+
+ if(beneficiaryID > 0)
+ arguments->bID = beneficiaryID;
+
+ if(participant_info != NULL) {
+ /* If there's Participant-provided Info text, add it */
+ dLen = strlen(participant_info);
+ if(dLen != 0) {
+ arguments->pInfo = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(arguments->pInfo == NULL)
+ return -1;
+ memcpy(arguments->pInfo, participant_info, dLen+1);
+ } else
+ arguments->pInfo = NULL;
+ }
+
+ arguments->priority = priority;
+
+ message = bfcp_build_message(arguments);
+ if(!message) {
+ pthread_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ remove_floor_list_p(list_floors);
+
+ pthread_mutex_unlock(&count_mutex);
+
+ /* Send the message to the FCS */
+ error = send_message_to_server(message, server_sock);
+ BFCP_SEND_CHECK_ERRORS;
+
+ return 0;
+}
+
+/* FloorRelease */
+int bfcp_floorRelease_participant(conference_participant participant, unsigned short int floorRequestID)
+{
+ if(participant == NULL)
+ return -1;
+ if(floorRequestID <= 0)
+ return -1;
+
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message;
+ int error;
+
+ pthread_mutex_lock(&count_mutex);
+
+ /* Prepare a new 'FloorRelease' message */
+ arguments = bfcp_new_arguments();
+ arguments->primitive = FloorRelease;
+ arguments->entity = bfcp_new_entity(participant->conferenceID, base_transactionID, participant->userID);
+
+ arguments->frqID = floorRequestID;
+
+ message = bfcp_build_message(arguments);
+ if(!message) {
+ pthread_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&count_mutex);
+
+ /* Send the message to the FCS */
+ error = send_message_to_server(message, server_sock);
+ BFCP_SEND_CHECK_ERRORS;
+
+ return 0;
+}
+
+/* FloorRequestQuery */
+int bfcp_floorRequestQuery_participant(conference_participant participant, unsigned short int floorRequestID)
+{
+ if(participant == NULL)
+ return -1;
+ if(floorRequestID <= 0)
+ return -1;
+
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message;
+ int error;
+
+ pthread_mutex_lock(&count_mutex);
+
+ /* Prepare a new 'FloorRequestQuery' message */
+ arguments = bfcp_new_arguments();
+ arguments->primitive = FloorRequestQuery;
+ arguments->entity = bfcp_new_entity(participant->conferenceID, base_transactionID, participant->userID);
+
+ arguments->frqID = floorRequestID;
+
+ message = bfcp_build_message(arguments);
+ if(!message) {
+ pthread_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&count_mutex);
+
+ /* Send the message to the FCS */
+ error = send_message_to_server(message, server_sock);
+ BFCP_SEND_CHECK_ERRORS;
+
+ return 0;
+}
+
+/* UserQuery */
+int bfcp_userQuery_participant(conference_participant participant, unsigned short int beneficiaryID)
+{
+ if(participant == NULL)
+ return -1;
+
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message;
+ int error;
+
+ pthread_mutex_lock(&count_mutex);
+
+ /* Prepare a new 'UserQuery' message */
+ arguments = bfcp_new_arguments();
+ arguments->primitive = UserQuery;
+ arguments->entity = bfcp_new_entity(participant->conferenceID, base_transactionID, participant->userID);
+
+ arguments->bID = beneficiaryID;
+
+ message = bfcp_build_message(arguments);
+ if(!message) {
+ pthread_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&count_mutex);
+
+ /* Send the message to the FCS */
+ error = send_message_to_server(message, server_sock);
+ BFCP_SEND_CHECK_ERRORS;
+
+ return 0;
+}
+
+/* UserQuery */
+int bfcp_floorQuery_participant(conference_participant participant, bfcp_floors_participant *list_floors)
+{
+ if(participant == NULL)
+ return -1;
+
+ bfcp_floors_participant *temp_list_floors, *tempnode;
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message;
+ bfcp_floors_participant *floors_IDs;
+ int error;
+
+ /* Check if all the provided floors exist, otherwise give an error */
+ for(tempnode = list_floors; tempnode; tempnode = tempnode->next) {
+ temp_list_floors = participant->pfloors;
+ while(temp_list_floors && (temp_list_floors->floorID > tempnode->floorID))
+ temp_list_floors = temp_list_floors->next;
+
+ if((temp_list_floors == NULL) || (tempnode->floorID != temp_list_floors->floorID))
+ /* This floor is not in the list */
+ return -1;
+ }
+
+ pthread_mutex_lock(&count_mutex);
+
+ /* Prepare a new 'FloorQuery' message */
+ arguments = bfcp_new_arguments();
+ arguments->primitive = FloorQuery;
+ arguments->entity = bfcp_new_entity(participant->conferenceID, base_transactionID, participant->userID);
+
+ floors_IDs = list_floors;
+ while(floors_IDs != NULL) {
+ if(arguments->fID)
+ bfcp_add_floor_id_list(arguments->fID, floors_IDs->floorID, 0);
+ else
+ arguments->fID = bfcp_new_floor_id_list(floors_IDs->floorID, 0);
+ floors_IDs = floors_IDs->next;
+ }
+
+ message = bfcp_build_message(arguments);
+ if(!message) {
+ pthread_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ remove_floor_list_p(list_floors);
+
+ pthread_mutex_unlock(&count_mutex);
+
+ /* Send the message to the FCS */
+ error = send_message_to_server(message, server_sock);
+ BFCP_SEND_CHECK_ERRORS;
+
+ return 0;
+}
+
+int bfcp_chairAction_participant(conference_participant participant, unsigned short int floorRequestID, char *statusInfo, unsigned short int status, bfcp_floors_participant *list_floors, unsigned short int queue_position)
+{
+ if(participant == NULL)
+ return -1;
+ if(list_floors == NULL)
+ return -1;
+ if(floorRequestID <= 0)
+ return -1;
+ if((status != BFCP_ACCEPTED) && (status != BFCP_DENIED) && (status != BFCP_REVOKED))
+ return -1;
+
+ bfcp_floors_participant *temp_list_floors, *tempnode;
+ bfcp_arguments *arguments;
+ bfcp_message *message;
+ bfcp_floors_participant *floors_IDs;
+ int error;
+ bfcp_floor_request_status *fRS = NULL, *fRS_temp;
+ bfcp_overall_request_status *oRS;
+
+ /* Check if all the floors in the request exist, otherwise give an error */
+ for(tempnode = list_floors; tempnode; tempnode = tempnode->next) {
+ temp_list_floors = participant->pfloors;
+ while(temp_list_floors && (temp_list_floors->floorID > tempnode->floorID))
+ temp_list_floors = temp_list_floors->next;
+ if((temp_list_floors == NULL) || (tempnode->floorID != temp_list_floors->floorID))
+ /* This floor is not in the list */
+ return -1;
+ }
+
+ pthread_mutex_lock(&count_mutex);
+
+ arguments = bfcp_new_arguments();
+ arguments->primitive = ChairAction;
+ arguments->entity = bfcp_new_entity(participant->conferenceID, base_transactionID, participant->userID);
+
+ if(status != BFCP_ACCEPTED)
+ queue_position = 0;
+
+ floors_IDs = list_floors;
+ if(floors_IDs != NULL)
+ fRS = bfcp_new_floor_request_status(floors_IDs->floorID, 0, 0, floors_IDs->sInfo);
+ if(fRS == NULL)
+ return -1;
+ floors_IDs = floors_IDs->next;
+ while(floors_IDs != NULL) {
+ fRS_temp = bfcp_new_floor_request_status(floors_IDs->floorID, 0, 0, floors_IDs->sInfo);
+ if(fRS_temp != NULL)
+ bfcp_list_floor_request_status(fRS, fRS_temp, NULL);
+ floors_IDs = floors_IDs->next;
+ }
+
+ oRS = bfcp_new_overall_request_status(floorRequestID, status, queue_position, statusInfo);
+
+ arguments->frqInfo = bfcp_new_floor_request_information(floorRequestID, oRS, fRS, NULL, NULL, 0, NULL);
+
+ message = bfcp_build_message(arguments);
+ if(!message) {
+ pthread_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ remove_floor_list_p(list_floors);
+
+ pthread_mutex_unlock(&count_mutex);
+
+ /* Send the message to the FCS */
+ error = send_message_to_server(message, server_sock);
+ BFCP_SEND_CHECK_ERRORS;
+
+ return 0;
+}
+
+
+/* Helper operations */
+
+/* Create a 'bfcp_floors_participant' element */
+bfcp_floors_participant *create_floor_list_p(unsigned short int floorID, char *status_info)
+{
+ bfcp_floors_participant *floor_list;
+ int dLen;
+
+ /* Allocate a new element */
+ floor_list = (bfcp_floors_participant *)calloc(1, sizeof(bfcp_floors_participant));
+ if(floor_list == NULL)
+ return NULL;
+
+ else {
+ /* Initialize the new element */
+ floor_list->floorID = floorID;
+ if(status_info != NULL) {
+ dLen = strlen(status_info);
+ if(dLen != 0) {
+ floor_list->sInfo = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(floor_list->sInfo == NULL)
+ return NULL;
+ memcpy(floor_list->sInfo, status_info, dLen+1);
+ }
+ } else
+ floor_list->sInfo = NULL;
+ floor_list->next = NULL;
+ }
+
+ return floor_list;
+}
+
+/* Create a 'bfcp_floors_participant' element and add it to an existing list */
+bfcp_floors_participant *insert_floor_list_p(floors_participant floor_list, unsigned short int floorID, char *status_info)
+{
+ if(floorID <= 0)
+ return NULL;
+
+ floors_participant floor, ini_floor_list;
+ int dLen;
+
+ /* First check if such a floor already exists */
+ ini_floor_list = floor_list;
+ while(ini_floor_list) {
+ if(ini_floor_list->floorID == floorID)
+ /* FloorID already exists */
+ return NULL;
+ ini_floor_list = ini_floor_list->next;
+ }
+ ini_floor_list = NULL;
+
+ /* Allocate a new element */
+ floor = (floors_participant)calloc(1, sizeof(bfcp_floors_participant));
+ if(floor == NULL)
+ return NULL;
+
+ if(floor_list == NULL) {
+ floor->floorID = floorID;
+ if(status_info != NULL) {
+ /* If there's Status Info text, add it */
+ dLen = strlen(status_info);
+ if(dLen != 0){
+ floor->sInfo = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(floor->sInfo == NULL)
+ return NULL;
+ memcpy(floor->sInfo, status_info, dLen+1);
+ }
+ } else
+ floor->sInfo = NULL;
+ floor->next = NULL;
+ floor_list =floor;
+ } else if(floor_list->floorID < floorID) {
+ floor->floorID = floorID;
+ if(status_info != NULL) {
+ /* If there's Status Info text, add it */
+ dLen = strlen(status_info);
+ if(dLen != 0){
+ floor->sInfo = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(floor->sInfo == NULL)
+ return NULL;
+ memcpy(floor->sInfo, status_info, dLen+1);
+ }
+ } else
+ floor->sInfo = NULL;
+ floor->next = floor_list;
+ floor_list = floor;
+ } else {
+ ini_floor_list = floor_list;
+ while(ini_floor_list->next && (ini_floor_list->next->floorID > floorID))
+ ini_floor_list = ini_floor_list->next;
+ floor->floorID = floorID;
+ if(status_info != NULL) {
+ /* If there's Status Info text, add it */
+ dLen = strlen(status_info);
+ if(dLen != 0){
+ floor->sInfo = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(floor->sInfo == NULL)
+ return NULL;
+ memcpy(floor->sInfo, status_info, dLen+1);
+ }
+ } else
+ floor->sInfo = NULL;
+
+ floor->next = ini_floor_list->next;
+ ini_floor_list->next = floor;
+ }
+
+ return floor_list;
+}
+
+/* Destroy a list of 'bfcp_floors_participant' elements */
+int remove_floor_list_p(floors_participant floor_list)
+{
+ floors_participant next;
+
+ /* Free all the elements from the floors list */
+ while(floor_list){
+ next = floor_list->next;
+ free(floor_list->sInfo);
+ floor_list->sInfo = NULL;
+ free(floor_list);
+ floor_list = NULL;
+ floor_list = next;
+ }
+
+ return 0;
+}
+
+
+/* Private methods */
+
+/* Send an already composed message (buffer) to the FCS */
+int send_message_to_server(bfcp_message *message, int sockfd)
+{
+ if(message == NULL)
+ return -1;
+
+ int error = 0;
+ int total = 0; /* How many bytes have been sent so far */
+ int bytesleft = 0; /* How many bytes still have to be sent */
+ bytesleft = message->length;
+
+ /* Wait up to ten seconds before timeout */
+ struct timeval tv;
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ while(total < message->length) {
+#ifdef WIN32
+ error = select(sockfd+1, NULL, &wset, NULL, &tv);
+ if(error < 0)
+ return -1; /* Select error */
+ if(error == 0)
+ return -1; /* Timeout */
+ if(FD_ISSET(sockfd, &wset)) {
+#endif
+ if(bfcp_transport == BFCP_OVER_TLS)
+ error = SSL_write(session, message->buffer+total, bytesleft);
+ else /* BFCP_OVER_TCP */
+ error = send(sockfd, (const char *)(message->buffer+total), bytesleft, 0);
+ if(error == -1) /* Error sending the message */
+ break;
+ total += error; /* Update the sent and to-be-sent bytes */
+ bytesleft -= error;
+#ifdef WIN32
+ }
+#endif
+ }
+
+ base_transactionID++;
+
+ return error;
+}
+
+/* Handle a just received message */
+bfcp_message *received_message_from_server(int sockfd, int *close_socket)
+{
+ int error, total = 0;
+ bfcp_message *message = NULL;
+ int in_length;
+
+ /* Reserve enough space for the common header (12 bytes) */
+ unsigned char *common_header = (unsigned char *)calloc(1, 12);
+
+ *close_socket = 0;
+ /* First look in the common header, since it will report the length of the whole message */
+ if(bfcp_transport == BFCP_OVER_TLS)
+ error = SSL_read(session, common_header, 12);
+ else /* BFCP_OVER_TCP */
+ error = recv(sockfd, (char *)(common_header), 12, 0);
+ if(error == 0) {
+ /* The FCS closed the connection */
+ printf("Server closed connection!\n");
+ free(common_header);
+ common_header = NULL;
+ *close_socket = 1;
+ close(sockfd);
+ return NULL;
+ }
+ if(error == -1) {
+ /* There was an error while receiving the message */
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+ message = bfcp_new_message(common_header, error);
+ /* Get the message length from the header of the message */
+ in_length = bfcp_get_length(message) + 12;
+ /* Strip the header length, since we already got it: we are interested in the rest, the payload */
+ total = in_length - 12;
+ if(total < 0) {
+ /* The reported length is corrupted */
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+ if(total == 0){
+ /* The whole message has already been received, there's no payload (e.g. ChairActionAck) */
+ free(common_header);
+ common_header = NULL;
+ return message;
+ }
+
+ /* Reserve enough space for the rest of the message */
+ unsigned char *buffer = (unsigned char *)calloc(1, total);
+
+ if(bfcp_transport == BFCP_OVER_TLS) { /* FIXME */
+ error = SSL_read(session, buffer, total);
+ } else { /* BFCP_OVER_TCP */
+ int missing = total;
+ while(1) {
+ if(missing <= 0)
+ break;
+ error = recv(sockfd, (char *)(buffer), total, 0);
+ if(error == 0) {
+ /* The FCS closed the connection */
+ printf("Server closed connection!\n");
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ close(sockfd);
+ return NULL;
+ }
+ if(error == -1) {
+ /* There was an error while receiving the message */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+ missing -= error;
+ }
+ }
+ if(error == 0) {
+ /* The FCS closed the connection */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ close(sockfd);
+ *close_socket = 1;
+ return NULL;
+ }
+ if(error == -1) {
+ /* There was an error while receiving the message */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+ if(in_length > BFCP_MAX_ALLOWED_SIZE) {
+ /* The message is bigger than BFCP_MAX_ALLOWED_SIZE (64K), discard it */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+ /* Remove the previously allocated message, which only contained the header */
+ if(message != NULL)
+ bfcp_free_message(message);
+
+ /* Extend the buffer to hold all the message */
+ common_header = (unsigned char *)realloc(common_header, in_length);
+
+ if(memcpy(common_header+12, buffer,total) == NULL) {
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+
+ /* Create a new BFCP message out of the whole received buffer */
+ message = bfcp_new_message(common_header, in_length);
+
+ /* Free the space reserved for the buffers */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return message;
+}
+
+/* Thread listening for incoming messages from the FCS */
+void *recv_thread(void *func)
+{
+ int(*received_msg)(bfcp_received_message *recv_msg) = func;
+
+ int error;
+ bfcp_message *message = NULL;
+ bfcp_received_message *recv_msg = NULL;
+ int close_socket;
+
+#ifdef WIN32
+ fd_set rset;
+ FD_ZERO(&rset);
+#endif
+ for(;;) {
+#ifdef WIN32
+ FD_SET(server_sock, &rset);
+ error = select(server_sock+1, &rset, NULL, NULL, NULL);
+#else
+ pollfds[0].fd = server_sock;
+ pollfds[0].events = POLLIN;
+ error = poll(pollfds, 1, -1);
+#endif
+ if(error < 0) {
+ close(server_sock);
+ if(bfcp_transport == BFCP_OVER_TLS)
+ SSL_free(session);
+ pthread_exit(0);
+ }
+#ifndef WIN32
+ if(pollfds[0].revents == POLLIN) {
+#endif
+ message = received_message_from_server(server_sock, &close_socket);
+ if(message != NULL) {
+ recv_msg = bfcp_parse_message(message);
+ if(recv_msg != NULL)
+ /* Trigger the application callback to notify about the new incoming message */
+ received_msg(recv_msg);
+ } else {
+ if(close_socket == 1)
+ pthread_exit(0);
+ }
+ if(message != NULL)
+ bfcp_free_message(message);
+#ifndef WIN32
+ } else if((pollfds[0].revents & POLLERR) ||
+ (pollfds[0].revents & POLLHUP) ||
+ (pollfds[0].revents & POLLNVAL)) {
+ printf("We got an error polling!!\n");
+ close(server_sock);
+ if(bfcp_transport == BFCP_OVER_TLS && session != NULL)
+ SSL_free(session);
+ pthread_exit(0);
+ }
+#endif
+ }
+}
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpclt/bfcp_participant.h b/libs/libbfcp/bfcpsrvclt/bfcpclt/bfcp_participant.h
new file mode 100644
index 00000000000..ef90a0b7ce0
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpclt/bfcp_participant.h
@@ -0,0 +1,98 @@
+#ifndef _BFCP_PARTICIPANT_H
+#define _BFCP_PARTICIPANT_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifndef WIN32
+#include
+#include
+#endif
+#include
+
+/* Needed for TCP/TLS/BFCP support */
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* The library supports both TCP/BFCP and TCP/TLS/BFCP */
+#define BFCP_OVER_TCP 0
+#define BFCP_OVER_TLS 1
+
+/* Library to build and parse BFCP messages */
+#include
+
+#define BFCP_FCS_DEFAULT_PORT 2345 /* By default the Floor Control Server will listen on this port */
+
+/* Participant-related Floor information */
+typedef struct bfcp_floors_participant {
+ unsigned short floorID; /* Floor Identifier */
+ char *sInfo; /* Status Info (text) */
+ struct bfcp_floors_participant *next;
+} bfcp_floors_participant;
+typedef bfcp_floors_participant *floors_participant;
+
+/* BFCP Participant */
+typedef struct bfcp_participant_information {
+ unsigned long int conferenceID; /* Conference Identifier */
+ unsigned short int userID; /* User Identifier (the participant) */
+ floors_participant pfloors; /* List of floors this user is aware of */
+} bfcp_participant_information;
+typedef bfcp_participant_information *conference_participant;
+
+
+#if defined __cplusplus
+ extern "C" {
+#endif
+
+/* BFCP Participant-related operations */
+
+/* Create a new Participant */
+struct bfcp_participant_information *bfcp_initialize_bfcp_participant(unsigned long int conferenceID, unsigned short int userID, char *IP_address_server, unsigned short int port_server, void( *received_msg)(bfcp_received_message *recv_msg), int transport);
+/* Destroy an existing Participant */
+int bfcp_destroy_bfcp_participant(bfcp_participant_information **participant);
+/* Add a floor to the list of floors the participant will be aware of */
+int bfcp_insert_floor_participant(conference_participant participant, unsigned short int floorID);
+/* Delete a floor from the list of floors the participant is aware of */
+int bfcp_delete_floor_participant(conference_participant participant, unsigned short int floorID);
+
+
+/* BFCP Participant side Messages-related operations */
+
+/* Hello */
+int bfcp_hello_participant(conference_participant participant);
+/* FloorRequest */
+int bfcp_floorRequest_participant(conference_participant participant, unsigned short int beneficiaryID, unsigned short int priority, bfcp_floors_participant *list_floors, char *participant_info);
+/* FloorRelease */
+int bfcp_floorRelease_participant(conference_participant participant, unsigned short int floorRequestID);
+/* FloorRequestQuery */
+int bfcp_floorRequestQuery_participant(conference_participant participant, unsigned short int floorRequestID);
+/* UserQuery */
+int bfcp_userQuery_participant(conference_participant participant, unsigned short int beneficiaryID);
+/* FloorQuery */
+int bfcp_floorQuery_participant(conference_participant participant, bfcp_floors_participant *list_floors);
+/* ChairAction */
+int bfcp_chairAction_participant(conference_participant participant, unsigned short int floorRequestID, char *statusInfo, unsigned short int status, bfcp_floors_participant *list_floors, unsigned short int queue_position);
+
+
+/* Helper operations */
+
+/* Create a 'bfcp_floors_participant' element */
+bfcp_floors_participant *create_floor_list_p(unsigned short int floorID, char *status_info);
+/* Create a 'bfcp_floors_participant' element and add it to an existing list */
+bfcp_floors_participant *insert_floor_list_p(floors_participant floor_list, unsigned short int floorID, char *status_info);
+/* Destroy a list of 'bfcp_floors_participant' elements */
+int remove_floor_list_p(floors_participant floor_list);
+
+#if defined __cplusplus
+ }
+#endif
+
+#endif
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpclt/main.c b/libs/libbfcp/bfcpsrvclt/bfcpclt/main.c
new file mode 100644
index 00000000000..aa9262c3ce5
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpclt/main.c
@@ -0,0 +1,502 @@
+#include "bfcp_participant.h"
+#include
+
+
+/* Helper Macros to check for errors */
+#define BFCP_CHECK_INTEGER \
+ if (error == 0) { \
+ printf("An integer is needed!\n"); \
+ break; \
+ }
+
+#define BFCP_CHECK_MESSAGE \
+ if(error == -1) \
+ printf("Error sending message...\n"); \
+ else \
+ printf("Message sent!\n");
+
+
+/* Headers */
+void menu(char *lineptr);
+void listen_server(bfcp_received_message *recv_msg);
+
+
+/* Callback to receive notifications from the underlying library about incoming BFCP messages */
+void listen_server(bfcp_received_message *recv_msg)
+{
+ int j, i;
+ bfcp_supported_list *info_primitives, *info_attributes;
+ bfcp_floor_request_information *tempInfo;
+ bfcp_floor_request_status *tempID;
+
+ if(!recv_msg) {
+ printf("Invalid message received...\n");
+ return;
+ }
+ if(!recv_msg->arguments) {
+ printf("Invalid arguments in the received message...\n");
+ bfcp_free_received_message(recv_msg);
+ return;
+ }
+ if(!recv_msg->entity) {
+ printf("Invalid IDs in the message header...\n");
+ bfcp_free_received_message(recv_msg);
+ return;
+ }
+ unsigned long int conferenceID = recv_msg->entity->conferenceID;
+ unsigned short int userID = recv_msg->entity->userID;
+ unsigned short int transactionID = recv_msg->entity->transactionID;
+
+ /* Output will be different according to the BFCP primitive in the message header */
+ switch(recv_msg->primitive) {
+ case Error:
+ printf("\nError:\n");
+ if(!recv_msg->arguments->error)
+ break;
+ printf("\tError n. %d\n", recv_msg->arguments->error->code);
+ printf("\tError info: %s\n", recv_msg->arguments->eInfo ? recv_msg->arguments->eInfo : "No info");
+ break;
+ case HelloAck:
+ printf("\nHelloAck:\n");
+ info_primitives = recv_msg->arguments->primitives;
+ printf("\tSupported Primitives:\n");
+ while(info_primitives != NULL) {
+ printf("\t\t%s\n", bfcp_primitive[info_primitives->element-1].description);
+ info_primitives = info_primitives->next;
+ }
+ info_attributes=recv_msg->arguments->attributes;
+ printf("\tSupported Attributes:\n");
+ while(info_attributes != NULL) {
+ printf("\t\t%s\n", bfcp_attribute[info_attributes->element-1].description);
+ info_attributes = info_attributes->next;
+ }
+ printf("\n");
+ break;
+ case ChairActionAck:
+ printf("ChairActionAck:\n");
+ printf("\tTransactionID: %d\n", transactionID);
+ printf("\tUserID %d\n", userID);
+ printf("\tConferenceID: %lu\n", conferenceID);
+ printf("\n");
+ break;
+ case FloorRequestStatus:
+ case FloorStatus:
+ if(recv_msg->primitive == FloorStatus)
+ printf("FloorStatus:\n");
+ else
+ printf("FloorRequestStatus:\n");
+ printf("\tTransactionID: %d\n", transactionID);
+ printf("\tUserID %d\n", userID);
+ printf("\tConferenceID: %lu\n", conferenceID);
+ if(recv_msg->arguments->fID != NULL)
+ printf("\tFloorID: %d\n", recv_msg->arguments->fID->ID);
+ if(recv_msg->arguments->frqInfo) {
+ tempInfo = recv_msg->arguments->frqInfo;
+ while(tempInfo) {
+ printf("FLOOR-REQUEST-INFORMATION:\n");
+ if(tempInfo->frqID)
+ printf(" Floor Request ID: %d\n", tempInfo->frqID);
+ if(tempInfo->oRS) {
+ printf(" OVERALL REQUEST STATUS:\n");
+ if(tempInfo->oRS->rs){
+ printf(" Queue Position %d\n", tempInfo->oRS->rs->qp);
+ printf(" RequestStatus %s\n", bfcp_status[tempInfo->oRS->rs->rs-1].description);
+ }
+ if(tempInfo->oRS->sInfo)
+ printf(" Status Info: %s\n", tempInfo->oRS->sInfo);
+ }
+ if(tempInfo->fRS) {
+ printf(" FLOOR REQUEST STATUS:\n");
+ tempID = tempInfo->fRS;
+ j = 0;
+ while(tempID) {
+ printf(" FLOOR IDs:\n");
+ j++;
+ printf(" (n.%d): %d\n", j, tempID->fID);
+ if(tempID->rs->rs)
+ printf(" RequestStatus %s\n", bfcp_status[tempID->rs->rs-1].description);
+ printf(" Status Info: %s\n", tempID->sInfo);
+ tempID = tempID->next;
+ }
+ }
+ if(tempInfo->beneficiary) {
+ printf(" BENEFICIARY-INFORMATION:\n");
+ if(tempInfo->beneficiary->ID)
+ printf(" Benefeciary ID: %d\n", tempInfo->beneficiary->ID);
+ if(tempInfo->beneficiary->display)
+ printf(" Display Name: %s\n", tempInfo->beneficiary->display);
+ if(tempInfo->beneficiary->uri)
+ printf(" User URI: %s\n", tempInfo->beneficiary->uri);
+ }
+ if(tempInfo->requested_by) {
+ printf(" REQUESTED BY INFORMATION:\n");
+ if(tempInfo->requested_by->ID)
+ printf(" Requested-by ID: %d\n", tempInfo->requested_by->ID);
+ if(tempInfo->requested_by->display)
+ printf(" Display Name: %s\n", tempInfo->requested_by->display);
+ if(tempInfo->requested_by->uri)
+ printf(" User URI: %s\n", tempInfo->requested_by->uri);
+ }
+ if(tempInfo->priority)
+ printf(" PRIORITY: %d\n", tempInfo->priority);
+ if(tempInfo->pInfo)
+ printf(" PARTICIPANT PROVIDED INFO: %s\n", tempInfo->pInfo);
+ printf("---\n");
+ tempInfo=tempInfo->next;
+ }
+ }
+ printf("\n");
+ break;
+ case UserStatus:
+ printf("UserStatus:\n");
+ printf("\tTransactionID: %d\n", transactionID);
+ printf("\tUserID %d\n", userID);
+ printf("\tConferenceID: %ld\n", conferenceID);
+ i = 0;
+ if(recv_msg->arguments->beneficiary)
+ printf("BeneficiaryInformation %d:\n", recv_msg->arguments->beneficiary->ID);
+ tempInfo=recv_msg->arguments->frqInfo;
+ while(tempInfo) {
+ i++;
+ printf("FLOOR-REQUEST-INFORMATION (%d):\n",i);
+ tempID = tempInfo->fRS;
+ j = 0;
+ while(tempID) {
+ printf(" FLOOR IDs:\n");
+ j++;
+ printf(" (n.%d): %d\n", j, tempID->fID);
+ if(tempID->rs->rs) printf(" RequestStatus %s\n", bfcp_status[tempID->rs->rs-1].description);
+ printf(" Status Info: %s\n", tempID->sInfo ? tempID->sInfo : "No info");
+ tempID = tempID->next;
+ }
+ printf(" FloorRequestID %d\n", tempInfo->frqID);
+ if(tempInfo->oRS) {
+ printf(" OVERALL REQUEST STATUS:\n");
+ if(tempInfo->oRS->rs){
+ printf(" Queue Position %d\n", tempInfo->oRS->rs->qp);
+ printf(" RequestStatus %s\n", bfcp_status[tempInfo->oRS->rs->rs-1].description);
+ }
+ if(tempInfo->oRS->sInfo)
+ printf(" Status Info: %s\n", tempInfo->oRS->sInfo ? tempInfo->oRS->sInfo : "No info");
+ }
+ if(tempInfo->beneficiary)
+ printf(" BeneficiaryID %d\n", tempInfo->beneficiary->ID);
+ if(tempInfo->requested_by)
+ printf(" Requested_byID %d\n", tempInfo->requested_by->ID);
+ printf(" Participant Provided info: %s\n", tempInfo->pInfo ? tempInfo->pInfo : "No info");
+ tempInfo = tempInfo->next;
+ }
+ printf("\n");
+ break;
+ default:
+ break;
+ }
+
+ if(recv_msg != NULL)
+ bfcp_free_received_message(recv_msg);
+}
+
+/* Menu to manipulate the Floor Control Server options and operations */
+void menu(char *lineptr)
+{
+ char line[80], *text = NULL, *text1 = NULL;
+ unsigned long int conferenceID = 0;
+ unsigned int userID = 0, floorID = 0, beneficiaryID = 0;
+ bfcp_participant_information *list = NULL;
+ bfcp_floors_participant *node = NULL, *list_floor = NULL;
+ floors_participant temp_floors = NULL;
+ int transport = -1, error = 0, status = 0, port_server = 0, priority = 0, queue_position = 0;
+ unsigned short int floorRequestID = 0;
+
+ list = NULL;
+
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "\n--------PARTICIPANT LIST-----------------------------\n",
+ " ? - Show the menu\n",
+ " c - Create the Participant\n",
+ " h - Destroy the Participant\n",
+ " i - Insert a new floor\n",
+ " d - Remove a floor\n",
+ " s - Show the information of the conference\n",
+ "BFCP Messages:\n",
+ " f - Hello\n",
+ " r - FloorRequest\n",
+ " l - FloorRelease\n",
+ " o - FloorRequestQuery\n",
+ " u - UserQuery\n",
+ " e - FloorQuery\n",
+ " a - ChairAction\n",
+ " q - quit \n",
+ "------------------------------------------------------\n\n");
+ while(fgets(line, 79, stdin) != NULL) {
+ lineptr = line;
+ while(*lineptr == ' ' || *lineptr == '\t')
+ ++lineptr;
+ switch(*lineptr) {
+ case '?':
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "\n--------PARTICIPANT LIST-----------------------------\n",
+ " ? - Show the menu\n",
+ " c - Create the Participant\n",
+ " h - Destroy the Participant\n",
+ " i - Insert a new floor\n",
+ " d - Remove a floor\n",
+ " s - Show all the participant information\n",
+ "BFCP Messages:\n",
+ " r - FloorRequest message\n",
+ " l - FloorRelease message\n",
+ " o - FloorRequestQuery message\n",
+ " u - UserQuery message\n",
+ " e - FloorQuery message\n",
+ " a - ChairAction message\n",
+ " f - Hello message\n",
+ " q - quit \n",
+ "------------------------------------------------------\n\n");
+ break;
+ case 'c':
+ ++lineptr;
+ printf("Enter the conferenceID of the conference:\n");
+ error = scanf ("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the userID of the participant:\n");
+ error = scanf ("%i", &userID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the IP address of the Floor Control Server: (e.g. 127.0.0.1)\n");
+ text1 = calloc(20, sizeof(char));
+ scanf ("%s", text1);
+ printf(" --> %s\n", text1 ? text1 : "??");
+ printf("Enter the listening port of the Floor Control Server: (e.g. 2345)\n");
+ error = scanf ("%i", &port_server);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the desired transport for the BFCP messages\n\t(0 for TCP/BFCP, 1 for TCP/TLS/BFCP):\n");
+ error = scanf ("%i", &transport);
+ BFCP_CHECK_INTEGER;
+ list = bfcp_initialize_bfcp_participant(conferenceID, userID, text1, port_server, listen_server, transport);
+ if(list == NULL)
+ printf("Couldn't create the new BFCP participant...\n");
+ else
+ printf("BFCP Participant created.\n");
+ free(text1);
+ break;
+ case 'i':
+ ++lineptr;
+ printf("Enter the FloorID:\n");
+ error = scanf ("%i", &floorID);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_insert_floor_participant(list, floorID) < 0)
+ printf("Couldn't add the new floor...\n");
+ else
+ printf("Floor added.\n");
+ break;
+ case 'd':
+ ++lineptr;
+ printf("Enter the FloorID:\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_delete_floor_participant(list, floorID) < 0)
+ printf("Couldn't remove the floor...\n");
+ else
+ printf("Floor removed.\n");
+ break;
+ case 'h':
+ ++lineptr;
+ if(bfcp_destroy_bfcp_participant(&list) < 0)
+ printf("Couldn't destroy the BFCP participant...\n");
+ else
+ printf("BFCP participant destroyed.\n");
+ break;
+ case 'r':
+ ++lineptr;
+ printf("Enter the BeneficiaryID of the new request (0 if it's not needed):\n");
+ error = scanf ("%u", &beneficiaryID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the priority for this request (0=lowest --> 4=highest):\n");
+ error = scanf ("%i", &priority);
+ BFCP_CHECK_INTEGER;
+#ifndef WIN32
+ printf("Enter some participant-provided information, if needed:\n");
+ scanf (" %a[^\n]", &text);
+#else
+ /* FIXME fix broken scanf in WIN32 */
+ text = calloc(20, sizeof(char));
+ sprintf(text, "Let me talk!");
+#endif
+ printf("Enter the FloorID:\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ node = create_floor_list_p(floorID, NULL);
+ printf("Enter another FloorID: (0 to stop inserting floors)\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ while (floorID != 0) {
+ node = insert_floor_list_p(node, floorID, NULL);
+ printf("Enter another FloorID: (0 to stop inserting floors)\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ }
+ error = bfcp_floorRequest_participant(list, beneficiaryID, priority, node, text);
+ if((error == -1) && (node != NULL)) {
+ /* Free the request */
+ printf("Error sending the message: do the floors in the request exist?\n");
+ remove_floor_list_p(node);
+ } else
+ printf("Message sent!\n");
+ free(text);
+ break;
+ case 'l':
+ ++lineptr;
+ printf("Enter the FloorRequestID of the request you want to release:\n");
+ error = scanf ("%hu", &floorRequestID);
+ BFCP_CHECK_INTEGER;
+ error = bfcp_floorRelease_participant(list, floorRequestID);
+ BFCP_CHECK_MESSAGE;
+ break;
+ case 'o':
+ ++lineptr;
+ printf("Enter the FloorRequestID of the request you're interested in:\n");
+ error = scanf ("%hu", &floorRequestID);
+ BFCP_CHECK_INTEGER;
+ error = bfcp_floorRequestQuery_participant(list, floorRequestID);
+ BFCP_CHECK_MESSAGE;
+ break;
+ case 'u':
+ ++lineptr;
+ printf("Enter the BeneficiaryID if you want information about a specific user (0 instead):\n");
+ error = scanf ("%u", &beneficiaryID);
+ BFCP_CHECK_INTEGER;
+ error = bfcp_userQuery_participant(list, beneficiaryID);
+ BFCP_CHECK_MESSAGE;
+ break;
+ case 'e':
+ ++lineptr;
+ printf("Enter the FloorID of the floor you're interested in: (0 to stop inserting floors):\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ if(floorID == 0)
+ node = NULL;
+ else {
+ node = create_floor_list_p(floorID, NULL);
+ printf("Enter the FloorID of the floor you're interested in: (0 to stop inserting floors)\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ while (floorID != 0){
+ node = insert_floor_list_p(node, floorID, NULL);
+ printf("Enter the FloorID of the floor you're interested in: (0 to stop inserting floors)\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ }
+ }
+ error = bfcp_floorQuery_participant(list, node);
+ if(error == -1)
+ remove_floor_list_p(node);
+ BFCP_CHECK_MESSAGE;
+ break;
+ case 'a':
+ ++lineptr;
+ printf("Enter the FloorRequestID:\n");
+ error = scanf ("%hu", &floorRequestID);
+ BFCP_CHECK_INTEGER;
+ printf("What to do with this request? (2=Accept / 4=Deny / 7=Revoke):\n");
+ error = scanf ("%u", &status);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the FloorID to act upon:\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+#ifndef WIN32
+ printf("Enter explanatory text about your decision concerning this floor:\n");
+ scanf (" %a[^\n]", &text);
+#else
+ /* FIXME fix broken scanf in WIN32 */
+ text = calloc(20, sizeof(char));
+ sprintf(text, "Nothing personal");
+#endif
+ list_floor = create_floor_list_p(floorID, text);
+ free(text);
+
+ printf("Enter another FloorID: (0 to stop inserting floors)\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ if(floorID != 0) {
+#ifndef WIN32
+ printf("Enter explanatory text about your decision concerning this floor:\n");
+ scanf (" %a[^\n]", &text);
+#else
+ /* FIXME fix broken scanf in WIN32 */
+ text = calloc(20, sizeof(char));
+ sprintf(text, "Nothing personal");
+#endif
+ }
+ while(floorID != 0) {
+ list_floor = insert_floor_list_p(list_floor, floorID, text);
+ free(text);
+ printf("Enter another FloorID: (0 to stop inserting floors)\n");
+ error = scanf ("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ if(floorID != 0) {
+#ifndef WIN32
+ printf("Enter explanatory text about your decision concerning this floor:\n");
+ scanf (" %a[^\n]", &text);
+#else
+ /* FIXME fix broken scanf in WIN32 */
+ text = calloc(20, sizeof(char));
+ sprintf(text, "Nothing personal");
+#endif
+ }
+ }
+#ifndef WIN32
+ printf("Enter explanatory text about your decision:\n");
+ scanf (" %a[^\n]", &text);
+#else
+ /* FIXME fix broken scanf in WIN32 */
+ text = calloc(20, sizeof(char));
+ sprintf(text, "Accept my decision");
+#endif
+ printf("Enter the desired position in queue for this request (0 if you are not interested in that):\n");
+ error = scanf ("%u", &queue_position);
+ BFCP_CHECK_INTEGER;
+ error = bfcp_chairAction_participant(list, floorRequestID, text, status, list_floor, queue_position);
+ free(text);
+ if(error == -1)
+ remove_floor_list_p(node);
+ BFCP_CHECK_MESSAGE;
+ break;
+ case 'f':
+ ++lineptr;
+ error = bfcp_hello_participant(list);
+ BFCP_CHECK_MESSAGE;
+ break;
+ case 's':
+ ++lineptr;
+ if(list == NULL)
+ break;
+ printf("conferenceID: %lu\n", list->conferenceID);
+ printf("userID: %u\n", list->userID);
+ temp_floors= list->pfloors;
+ while(temp_floors != NULL) {
+ printf("FloorID: %u ", temp_floors->floorID);
+ printf("\n");
+ temp_floors = temp_floors->next;
+ }
+ break;
+ case 'q':
+ status = 0;
+ return;
+ break;
+ case '\n':
+ break;
+ default:
+ printf("Invalid menu choice - try again\n");
+ break;
+ }
+ }
+}
+
+/* Main */
+int main (int argc, char *argv[])
+{
+ char *lineptr = NULL;
+ printf("\nBinary Floor Control Protocol (BFCP) Participant Tester\n\n");
+ menu(lineptr);
+
+ return 0;
+}
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/Makefile b/libs/libbfcp/bfcpsrvclt/bfcpsrv/Makefile
new file mode 100644
index 00000000000..45294d037ad
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/Makefile
@@ -0,0 +1,58 @@
+PREFIX = /usr
+CC = gcc
+CC_W32 = i686-mingw32-gcc
+OBJS = bfcp_server.o bfcp_link_list.o bfcp_floor_list.o bfcp_user_list.o
+OBJS_W32 = bfcp_server.obj bfcp_link_list.obj bfcp_floor_list.obj bfcp_user_list.obj
+OPTS = -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -O2
+LIBS = -lbfcpmsg -lpthread -lssl -lcrypto
+LIBS_W32 = -lbfcpmsg -lws2_32 -lpthreadGC2 -lssleay32 -llibeay32 #-s
+DEPS_W32 = -L./
+WIN32 = -DWIN32
+BASE = ../../../..
+INC = -I$(BASE)/src/include -I$(BASE)/libs/libteletone/src
+so : $(OBJS)
+ $(CC) -ggdb -shared -Wl,-soname,libbfcpsrv.so.0 -o libbfcpsrv.so.0.0.7 $(OBJS) $(OPTS) $(LIBS)
+%.o: %.c
+ $(CC) -fPIC -ggdb -c $(INC) $< -o $@ $(OPTS)
+
+dll : $(OBJS_W32)
+ $(CC_W32) $(WIN32) -ggdb -shared -o libbfcpsrv.dll $(OBJS_W32) $(OPTS) $(DEPS_W32) $(LIBS_W32)
+
+%.obj: %.c
+ $(CC_W32) $(WIN32) -ggdb -c $< -o $@ $(OPTS)
+
+linux : so main.o $(OBJS)
+ $(CC) -ggdb -o bfcp_server main.o $(OBJS) $(OPTS) $(LIBS) -lbfcpsrv
+
+stress : stress_server.o $(OBJS)
+ $(CC) -ggdb -o stress_server stress_server.o $(OBJS) $(OPTS) $(LIBS)
+
+win32 : main.obj $(OBJS_W32)
+ $(CC_W32) $(WIN32) -ggdb -o bfcp_server.exe main.obj $(OBJS_W32) $(OPTS) $(DEPS_W32) $(LIBS_W32)
+
+clean :
+ rm -f *.o *.obj libbfcpsrv* bfcp_server bfcp_server.exe
+
+all: clean so dll linux win32
+
+install:
+ @echo Installing BFCP server library to $(PREFIX)/lib/:
+ install -m 755 libbfcpsrv.so.0.0.7 $(PREFIX)/lib/
+ ln -sf $(PREFIX)/lib/libbfcpsrv.so.0.0.7 $(PREFIX)/lib/libbfcpsrv.so.0
+ ln -sf $(PREFIX)/lib/libbfcpsrv.so.0 $(PREFIX)/lib/libbfcpsrv.so
+ @echo Installing BFCP server headers to $(PREFIX)/include/:
+ install -m 755 bfcp_server.h $(PREFIX)/include/
+ install -m 755 bfcp_threads.h $(PREFIX)/include/
+ install -m 755 bfcp_user_list.h $(PREFIX)/include/
+ install -m 755 bfcp_link_list.h $(PREFIX)/include/
+ install -m 755 bfcp_floor_list.h $(PREFIX)/include/
+
+uninstall:
+ @echo Uninstalling BFCP server library from $(PREFIX)/lib/:
+ rm -f $(PREFIX)/lib/libbfcpsrv*
+ @echo Uninstalling BFCP server headers from $(PREFIX)/include/:
+ rm -f $(PREFIX)/include/bfcp_server.h
+ rm -f $(PREFIX)/include/bfcp_threads.h
+ rm -f $(PREFIX)/include/bfcp_user_list.h
+ rm -f $(PREFIX)/include/bfcp_link_list.h
+ rm -f $(PREFIX)/include/bfcp_floor_list.h
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_floor_list.c b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_floor_list.c
new file mode 100644
index 00000000000..cf3119afbf1
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_floor_list.c
@@ -0,0 +1,473 @@
+#include "bfcp_floor_list.h"
+
+/* Create a new linked list of floors */
+struct bfcp_list_floors *bfcp_create_floor_list(unsigned short int Max_Num)
+{
+ bfcp_list_floors * lfloors;
+ bfcp_floors *floors;
+
+ if(Max_Num == 0)
+ Max_Num = 1;
+
+ /* Allocate a new container for the list of floors */
+ lfloors = (bfcp_list_floors *)calloc(1, sizeof(bfcp_list_floors));
+ if(lfloors == NULL)
+ return NULL;
+
+ /* Allocate a new array of floors */
+ floors = (bfcp_floors *)calloc(Max_Num, sizeof(bfcp_floors));
+ if(floors == NULL) {
+ free(lfloors);
+ lfloors = NULL;
+ return NULL;
+ } else {
+ lfloors->number_floors = --Max_Num;
+ lfloors->actual_number_floors = 0;
+ lfloors->floors = floors;
+ }
+
+ return lfloors;
+}
+
+/* Add a floor (and its chair, if present) to a list of floors */
+int bfcp_insert_floor(bfcp_list_floors *lfloors, unsigned short int floorID, unsigned short int chairID)
+{
+ if(lfloors == NULL)
+ return -1;
+ if(floorID == 0)
+ return -1;
+
+ int number_floors, i = 0;
+
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID == floorID))
+ /* A floor with the same floorID already exists in this conference */
+ return -1;
+
+ number_floors = lfloors->number_floors;
+ if(lfloors->actual_number_floors > number_floors)
+ /* The maximum number of allowed floors has already been reached */
+ return -1;
+
+ /* Initialize the floor information */
+ lfloors->floors[lfloors->actual_number_floors].floorID = floorID;
+ lfloors->floors[lfloors->actual_number_floors].chairID = chairID;
+ lfloors->floors[lfloors->actual_number_floors].floorState = 0;
+ lfloors->floors[lfloors->actual_number_floors].limit_granted_floor = 2;
+ lfloors->floors[lfloors->actual_number_floors].floorquery = NULL;
+ lfloors->actual_number_floors= lfloors->actual_number_floors + 1;
+
+ return lfloors->actual_number_floors;
+}
+
+/* Get the number of currently available floors in a list */
+int bfcp_return_number_floors(bfcp_list_floors *lfloors)
+{
+ if(lfloors == NULL)
+ return -1;
+
+ return lfloors->number_floors;
+}
+
+/* Change the maximum number of allowed floors in a conference */
+int bfcp_change_number_floors(bfcp_list_floors *lfloors, unsigned short int Num)
+{
+ if(lfloors == NULL)
+ return -1;
+
+ if(Num == 0)
+ Num = 1;
+
+ bfcp_floors *floors = NULL;
+ floor_query *query = NULL;
+ floor_query *temp = NULL;
+ int i = 0;
+
+ if(lfloors->number_floors >= Num) {
+ for(i = Num;i <= lfloors->number_floors; i++) {
+ lfloors->floors[i].floorID = 0;
+ lfloors->floors[i].chairID = 0;
+ lfloors->floors[i].floorState = 0;
+ lfloors->floors[i].limit_granted_floor = 0;
+
+ /* Free the list of floor queries */
+ query = lfloors->floors[i].floorquery;
+ while(query) {
+ temp = query;
+ query = query->next;
+ free(temp);
+ temp = NULL;
+ }
+ }
+ }
+
+ floors = (bfcp_floors *)realloc(lfloors->floors, Num*sizeof(bfcp_floors));
+ if(floors == NULL)
+ return -1;
+
+ lfloors->floors = floors;
+
+ if(Num > lfloors->number_floors) {
+ for(i = lfloors->number_floors+1; i < Num; i++) {
+ lfloors->floors[i].floorID = 0;
+ lfloors->floors[i].chairID = 0;
+ lfloors->floors[i].floorState = 0;
+ lfloors->floors[i].limit_granted_floor = 0;
+
+ /* Free the list of floor queries*/
+ query = lfloors->floors[i].floorquery;
+ while(query) {
+ temp = query;
+ query = query->next;
+ free(temp);
+ temp = NULL;
+ }
+ }
+ }
+
+ if((lfloors->actual_number_floors) > Num)
+ lfloors->actual_number_floors = Num;
+
+ lfloors->number_floors = --Num;
+
+ return 0;
+}
+
+/* Check if a floor exists in a conference */
+int bfcp_exist_floor(bfcp_list_floors *lfloors, unsigned short int floorID)
+{
+ if(lfloors == NULL)
+ return -1;
+ if(floorID == 0)
+ return -1;
+
+ int i = 0;
+
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID == floorID))
+ /* The floor exists */
+ return 0;
+ else
+ /* The floor does NOT exist */
+ return -1;
+}
+
+/* Remove a floor from a floors list */
+int bfcp_delete_floor(bfcp_list_floors *lfloors, unsigned short int floorID)
+{
+ if(floorID == 0)
+ return -1;
+ if(lfloors == NULL)
+ return -1;
+
+ int i = 0;
+ floor_query *query = NULL;
+ floor_query *temp = NULL;
+
+ while(i < lfloors->actual_number_floors && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if(i >= lfloors->actual_number_floors)
+ /* This floor does not exist in this conference */
+ return -1;
+
+ i = i + 1;
+ while(i < lfloors->actual_number_floors) {
+ /* Reorder the whole list */
+ lfloors->floors[i-1].floorID = lfloors->floors[i].floorID;
+ lfloors->floors[i-1].chairID = lfloors->floors[i].chairID;
+ lfloors->floors[i-1].floorState = lfloors->floors[i].floorState;
+ lfloors->floors[i-1].limit_granted_floor = lfloors->floors[i].limit_granted_floor;
+ lfloors->floors[i-1].floorquery = lfloors->floors[i].floorquery;
+ i++;
+ }
+
+ lfloors->floors[i-1].floorID = 0;
+ lfloors->floors[i-1].chairID = 0;
+ lfloors->floors[i-1].floorState = 0;
+ lfloors->floors[i-1].limit_granted_floor = 0;
+
+ query = lfloors->floors[i-1].floorquery;
+ while(query) {
+ temp = query;
+ query = query->next;
+ free(temp);
+ temp = NULL;
+ }
+
+ lfloors->actual_number_floors = lfloors->actual_number_floors - 1;
+
+ return lfloors->actual_number_floors;
+}
+
+/* Change the chair's userID for a floor (setting chair to 0 removes it) */
+int bfcp_change_chair(bfcp_list_floors *lfloors, unsigned short int floorID, unsigned short int chairID)
+{
+ if(floorID == 0)
+ return -1;
+ if(lfloors == NULL)
+ return -1;
+
+ int i = 0;
+
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if(i >= lfloors->actual_number_floors)
+ /* A floor with this floorID does not exists in this conference */
+ return -1;
+
+ lfloors->floors[i].chairID = chairID;
+
+ return 0;
+}
+
+/* Get the maximum number of users that can be granted this floor at the same time */
+int bfcp_return_number_granted_floor(bfcp_list_floors *lfloors, unsigned short int floorID)
+{
+ if(lfloors == NULL)
+ return -1;
+ if(floorID == 0)
+ return -1;
+
+ int i = 0;
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if(i >= lfloors->actual_number_floors)
+ /* A floor with this floorID does not exists in this conference */
+ return -1;
+
+ return lfloors->floors[i].limit_granted_floor;
+}
+
+/* Change the maximum number of users that can be granted this floor at the same time */
+int bfcp_change_number_granted_floor(bfcp_list_floors *lfloors, unsigned short int floorID, unsigned short int limit_granted_floor)
+{
+ if(floorID == 0)
+ return -1;
+ if(lfloors == NULL)
+ return -1;
+
+ int i = 0;
+
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if(i >= lfloors->actual_number_floors)
+ /* A floor with this floorID does not exists in this conference */
+ return -1;
+
+ if(limit_granted_floor == 0)
+ lfloors->floors[i].limit_granted_floor = USHRT_MAX;
+ else
+ lfloors->floors[i].limit_granted_floor = (1 + limit_granted_floor);
+
+ return 0;
+}
+
+/* Change the current status of a floor */
+int bfcp_change_state_floor(bfcp_list_floors *lfloors, unsigned short int floorID, unsigned short int state)
+{
+ int i = 0;
+
+ if(floorID == 0)
+ return -1;
+ if(lfloors == NULL)
+ return -1;
+ if((state != BFCP_FLOOR_STATE_WAITING) && (state != BFCP_FLOOR_STATE_ACCEPTED))
+ return -1;
+
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if(i >= lfloors->actual_number_floors)
+ /* A floor with this floorID does not exists in this conference */
+ return -1;
+
+ if(state == BFCP_FLOOR_STATE_ACCEPTED) {
+ /* Decrease the state */
+ lfloors->floors[i].floorState = lfloors->floors[i].floorState - 1;
+ if(lfloors->floors[i].floorState == BFCP_FLOOR_STATE_ACCEPTED)
+ lfloors->floors[i].floorState = BFCP_FLOOR_STATE_WAITING;
+ } else {
+ /* Increase the state */
+ lfloors->floors[i].floorState = lfloors->floors[i].floorState + 1;
+ if(lfloors->floors[i].floorState == BFCP_FLOOR_STATE_ACCEPTED)
+ lfloors->floors[i].floorState = BFCP_FLOOR_STATE_GRANTED;
+ }
+
+ return 0;
+}
+
+/* Get the current status of a floor */
+int bfcp_return_state_floor(bfcp_list_floors *lfloors, unsigned short int floorID)
+{
+ int i = 0;
+
+ if(floorID == 0)
+ return -1;
+ if(lfloors == NULL)
+ return -1;
+ if(lfloors->floors == NULL)
+ return -1;
+
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if(i >= lfloors->actual_number_floors)
+ /* A floor with this floorID does not exists in this conference */
+ return -1;
+
+ return lfloors->floors[i].floorState;
+}
+
+/* Get the position of this floor in the list */
+int bfcp_return_position_floor(bfcp_list_floors *lfloors, unsigned short int floorID)
+{
+ if(floorID == 0)
+ return -1;
+ if(lfloors == NULL)
+ return -1;
+
+ int i = 0;
+
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if(i >= lfloors->actual_number_floors)
+ /* A floor with this floorID does not exists in this conference */
+ return -1;
+
+ return i;
+}
+
+/* Return the BFCP UserID of the chair of this floor */
+unsigned short int bfcp_return_chair_floor(bfcp_list_floors *lfloors, unsigned short int floorID)
+{
+ if(floorID == 0)
+ return 0;
+ if(lfloors == NULL)
+ return 0;
+
+ int i = 0;
+
+ while((i < lfloors->actual_number_floors) && (lfloors->floors[i].floorID != floorID))
+ i = i + 1;
+
+ if(i >= lfloors->actual_number_floors)
+ /* A floor with this floorID does not exists in this conference */
+ return 0;
+
+ return lfloors->floors[i].chairID;
+}
+
+/* Check if the chair's BFCP UserID exists (i.e. if it's valid) */
+int bfcp_exist_user_as_a_chair(bfcp_list_floors *lfloors, unsigned short int chairID)
+{
+ if(lfloors == NULL)
+ return -1;
+
+ int i;
+
+ for(i = 0; i < lfloors->actual_number_floors; i++) {
+ if(lfloors->floors[i].chairID == chairID)
+ return 0;
+ }
+
+ /* If we arrived so far, che chair is not valid user */
+ return -1;
+}
+
+/* Remove all floors from a list */
+int bfcp_clean_floor_list(bfcp_list_floors *lfloors)
+{
+ if(lfloors == NULL)
+ return -1;
+
+ floor_query *query = NULL;
+ floor_query *temp = NULL;;
+ int i;
+
+ for(i = 0; i < lfloors->actual_number_floors; i++) {
+ lfloors->floors[i].floorID = 0;
+ lfloors->floors[i].chairID = 0;
+ lfloors->floors[i].floorState = 0;
+ lfloors->floors[i].limit_granted_floor = 0;
+
+ query = lfloors->floors[i].floorquery;
+ while(query) {
+ temp = query;
+ query = query->next;
+ free(temp);
+ temp = NULL;
+ }
+ }
+
+ lfloors->actual_number_floors = 0;
+
+ return 0;
+}
+
+/* Free a linked list of floors */
+int bfcp_remove_floor_list(bfcp_list_floors **lfloorsp)
+{
+ if(lfloorsp == NULL)
+ return 0;
+
+ int error;
+
+ bfcp_list_floors *lfloors = *lfloorsp;
+
+ error = bfcp_clean_floor_list(lfloors);
+ if(error == 0) {
+ free(lfloors->floors);
+ lfloors->floors = NULL;
+ free(lfloors);
+ *lfloorsp = NULL;
+ } else
+ return -1;
+
+ return 0;
+}
+
+/* Remove a user from notifications related to floor events */
+int remove_request_from_the_floor(bfcp_floors *floors, unsigned short int userID)
+{
+ if(floors == NULL)
+ return 0;
+
+ floor_query *floorquery = NULL;
+ floor_query *newnode = NULL;
+
+ floorquery = floors->floorquery;
+ if(floorquery == NULL)
+ return 0;
+
+ if(floorquery->userID == userID) {
+ /* If this user exists in the request list, we remove it from the node */
+ floors->floorquery = floorquery->next;
+ floorquery->next = NULL;
+ free(floorquery);
+ floorquery = NULL;
+ return 0;
+ }
+
+ while(floorquery->next != NULL) {
+ if(floorquery->next->userID == userID) {
+ newnode= floorquery->next;
+ floorquery->next = newnode->next;
+ newnode->next = NULL;
+ free(newnode);
+ newnode = NULL;
+ return 0;
+ }
+ floorquery = floorquery->next;
+ }
+
+ return 0;
+}
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_floor_list.h b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_floor_list.h
new file mode 100644
index 00000000000..e040d082f3e
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_floor_list.h
@@ -0,0 +1,89 @@
+#ifndef _BFCP_FLOOR_LIST_H
+#define _BFCP_FLOOR_LIST_H
+
+#include
+#include
+#include
+#include
+
+
+#define BFCP_FLOOR_STATE_WAITING 0
+#define BFCP_FLOOR_STATE_ACCEPTED 1
+#define BFCP_FLOOR_STATE_GRANTED 2
+
+
+/* FloorQuery instance (to notify about floor events) */
+typedef struct floor_query {
+ unsigned short int userID; /* User to notify */
+ int fd; /* File descriptor of the user's connection */
+ struct sockaddr_in *client_addr; /* client's address required if server running over UDP */
+ struct floor_query *next; /* Next FloorQuery in the list */
+} floor_query;
+
+/* Floor */
+typedef struct bfcp_floors {
+ unsigned short int floorID; /* Floor ID */
+ unsigned short int chairID; /* UserID of the Chair for this floor */
+ unsigned short int floorState; /* Current state of the floor (free or not) */
+ unsigned short int limit_granted_floor; /* Number of users this floor can be granted to at the same time */
+ struct floor_query *floorquery; /* Users interested in events related to this floor (FloorQuery) */
+} bfcp_floors;
+/* Pointer to a Floor instance */
+typedef bfcp_floors *floors;
+
+/* Linked list of floors */
+typedef struct bfcp_list_floors {
+ unsigned short int number_floors; /* The maximum allowed number of floors in this conference */
+ unsigned short int actual_number_floors; /* The currently available floors in this conference */
+ struct bfcp_floors *floors; /* List of floors */
+} bfcp_list_floors;
+/* Pointer to a list of floors */
+typedef bfcp_list_floors *lfloors;
+
+
+/*************************/
+/* Floor-related methods */
+/*************************/
+
+/* Create a new linked list of floors */
+struct bfcp_list_floors *bfcp_create_floor_list(unsigned short int Max_Num);
+/* Add a floor (and its chair, if present) to a list of floors */
+int bfcp_insert_floor(bfcp_list_floors *lfloors, unsigned short int floorID, unsigned short int chairID);
+/* Get the number of currently available floors in a list */
+int bfcp_return_number_floors(bfcp_list_floors *lfloors);
+/* Change the maximum number of allowed floors in a conference */
+int bfcp_change_number_floors(bfcp_list_floors *lfloors, unsigned short int Num);
+/* Check if a floor exists in a conference */
+int bfcp_exist_floor(bfcp_list_floors *lfloors, unsigned short int floorID);
+/* Remove a floor from a floors list */
+int bfcp_delete_floor(bfcp_list_floors *lfloors, unsigned short int floorID);
+/* Change the chair's userID for a floor (setting chair to 0 removes it) */
+int bfcp_change_chair(bfcp_list_floors *lfloors, unsigned short int floorID, unsigned short int chairID);
+/* Get the maximum number of users that can be granted this floor at the same time */
+int bfcp_return_number_granted_floor(bfcp_list_floors *lfloors, unsigned short int floorID);
+/* Change the maximum number of users that can be granted this floor at the same time */
+int bfcp_change_number_granted_floor(bfcp_list_floors *lfloors, unsigned short int floorID, unsigned short int limit_granted_floor);
+/* Change the current status of a floor */
+int bfcp_change_state_floor(bfcp_list_floors *lfloors, unsigned short int floorID, unsigned short int state);
+/* Get the current status of a floor */
+int bfcp_return_state_floor(bfcp_list_floors *lfloors, unsigned short int floorID);
+/* Get the position of this floor in the list */
+int bfcp_return_position_floor(bfcp_list_floors *lfloors, unsigned short int floorID);
+/* Return the BFCP UserID of the chair of this floor */
+unsigned short int bfcp_return_chair_floor(bfcp_list_floors *lfloors, unsigned short int floorID);
+/* Check if the chair's BFCP UserID exists (i.e. if it's valid) */
+int bfcp_exist_user_as_a_chair(bfcp_list_floors *lfloors, unsigned short int chairID);
+/* Remove all floors from a list */
+int bfcp_clean_floor_list(bfcp_list_floors *lfloors);
+/* Free a linked list of floors */
+int bfcp_remove_floor_list(bfcp_list_floors **lfloorsp);
+
+
+/******************/
+/* Helper methods */
+/******************/
+
+/* Remove a user from notifications related to floor events */
+int remove_request_from_the_floor(bfcp_floors *floors, unsigned short int userID);
+
+#endif
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_link_list.c b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_link_list.c
new file mode 100644
index 00000000000..aa8315196d9
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_link_list.c
@@ -0,0 +1,1232 @@
+#include "bfcp_link_list.h"
+
+/* Create a new linked list of BFCP queues */
+struct bfcp_queue *bfcp_create_list(void)
+{
+ bfcp_queue *conference;
+
+ /* Create a new list of BFCP queues */
+ conference = (bfcp_queue *)calloc(1, sizeof(bfcp_queue));
+
+ /* Initialize the list */
+ if(conference == NULL)
+ return NULL;
+ else {
+ conference->head = NULL;
+ conference->tail = NULL;
+ }
+
+ return conference;
+}
+
+/* Initialize a new FloorRequest node */
+struct bfcp_node *bfcp_init_request(unsigned short int userID, unsigned short int beneficiaryID, int priority, char *participant_info, unsigned short int floorID)
+{
+ if(userID == 0)
+ return NULL;
+ if(floorID == 0)
+ return NULL;
+
+ pnode newnode;
+ pfloor floor_list;
+ int dLen;
+
+ /* Check if the priority argument is valid */
+ if(priority > BFCP_HIGHEST_PRIORITY)
+ priority = BFCP_HIGHEST_PRIORITY;
+
+ /* Create a new node */
+ newnode = (pnode)calloc(1, sizeof(bfcp_node));
+ if(!newnode)
+ return (NULL);
+
+ newnode->next = newnode->prev= NULL;
+
+ newnode->userID = userID;
+ newnode->beneficiaryID = beneficiaryID;
+ newnode->priority = priority;
+ newnode->queue_position = 0;
+ newnode->chair_info = NULL;
+ newnode->floorrequest = NULL;
+
+ /* Add participant-provided text, if present */
+ if(participant_info != NULL) {
+ dLen= strlen(participant_info);
+ if(dLen != 0) {
+ newnode->participant_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(newnode->participant_info == NULL)
+ return NULL;
+ memcpy(newnode->participant_info, participant_info, dLen+1);
+ }
+ } else
+ newnode->participant_info= NULL;
+
+ /* Create a new list of floors */
+ floor_list = (pfloor)calloc(1, sizeof(bfcp_floor));
+
+ /* Initialize the list */
+ if(floor_list == NULL)
+ return NULL;
+ else{
+ floor_list->floorID = floorID;
+ floor_list->status = BFCP_FLOOR_STATE_WAITING;
+ floor_list->chair_info = NULL;
+#ifndef WIN32
+ floor_list->pID = 0;
+#else
+ floor_list->pID.p = NULL;
+#endif
+ floor_list->next = NULL;
+ newnode->floor = floor_list;
+ }
+
+ return newnode;
+}
+
+/* Add a floor to an existing FloorRequest */
+int bfcp_add_floor_to_request(pnode newnode, unsigned short int floorID)
+{
+ if(newnode == NULL)
+ return -1;
+ if(floorID == 0)
+ return -1;
+
+ pfloor floor_list, ini_floor_list, floor;
+
+ /* Check if a floor with the same ID already exists in the list */
+ for(floor = newnode->floor; floor; floor = floor->next) {
+ if(floor->floorID == floorID)
+ /* This floor already exists in the list */
+ return -1;
+ }
+
+ /* Create a new list of floors */
+ floor_list = (pfloor)calloc(1, sizeof(bfcp_floor));
+
+ /* Initialize the list */
+ if(floor_list == NULL)
+ return -1;
+ else {
+ if(newnode->floor == NULL) {
+ floor_list->floorID = floorID;
+ floor_list->status = BFCP_FLOOR_STATE_WAITING;
+ floor_list->chair_info = NULL;
+#ifndef WIN32
+ floor_list->pID = 0;
+#else
+ floor_list->pID.p = NULL;
+#endif
+ floor_list->next= newnode->floor;
+ newnode->floor= floor_list;
+ } else if(newnode->floor->floorID < floorID) {
+ floor_list->floorID = floorID;
+ floor_list->status = BFCP_FLOOR_STATE_WAITING;
+ floor_list->chair_info = NULL;
+#ifndef WIN32
+ floor_list->pID = 0;
+#else
+ floor_list->pID.p = NULL;
+#endif
+ floor_list->next = newnode->floor;
+ newnode->floor = floor_list;
+ } else {
+ ini_floor_list = newnode->floor;
+ while((ini_floor_list->next) && (ini_floor_list->next->floorID > floorID))
+ ini_floor_list=ini_floor_list->next;
+ floor_list->floorID = floorID;
+ floor_list->status = BFCP_FLOOR_STATE_WAITING;
+ floor_list->chair_info = NULL;
+#ifndef WIN32
+ floor_list->pID = 0;
+#else
+ floor_list->pID.p=NULL;
+#endif
+ floor_list->next = ini_floor_list->next;
+ ini_floor_list->next = floor_list;
+ }
+ }
+
+ return 0;
+}
+
+/* Add an existing FloorRequest to a BFCP queue */
+int bfcp_insert_request(bfcp_queue *conference, pnode newnode, unsigned short int floorRequestID, char *chair_info)
+{
+ if(conference == NULL)
+ return -1;
+ if(newnode == NULL)
+ return -1;
+ if(floorRequestID == 0)
+ return -1;
+
+ pnode traverse;
+ int dLen, y = 1;
+
+ /* Add the floorRequestID to the node */
+ newnode->floorRequestID = floorRequestID;
+
+ if(chair_info != NULL) {
+ dLen = strlen(chair_info);
+ if(dLen != 0) {
+ if(newnode->chair_info != NULL) {
+ free(newnode->chair_info);
+ newnode->chair_info = NULL;
+ }
+ newnode->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(newnode->chair_info == NULL)
+ return -1;
+ memcpy(newnode->chair_info, chair_info, dLen+1);
+ }
+ } else
+ newnode->chair_info = NULL;
+
+ /* Insert the new node in the structure*/
+ traverse = conference->head;
+
+ /* If queue_position is not 0, we set the one the chair stated */
+ if((newnode->queue_position != 0) && (traverse != NULL)) {
+ /* Insert the new node in the structure*/
+ traverse = conference->tail;
+ while(traverse->prev) {
+ if(y < newnode->queue_position)
+ y = y + 1;
+ else
+ break;
+ traverse = traverse->prev;
+ }
+
+ if(y != newnode->queue_position) {
+ traverse = conference->head;
+ newnode->queue_position = 0;
+ }
+ newnode->priority = 0;
+ }
+
+ if(traverse == NULL) {
+ newnode->next = NULL;
+ newnode->prev = NULL;
+ conference->head = newnode;
+ conference->tail = newnode;
+ } else {
+ if((traverse->priority >= newnode->priority) && (newnode->queue_position == 0)) {
+ newnode->next = traverse;
+ newnode->prev = NULL;
+ conference->head = newnode;
+ if(traverse)
+ traverse->prev = newnode;
+ if(!conference->head)
+ conference->head = newnode;
+ if(!conference->tail)
+ conference->tail = newnode;
+ } else {
+ while(traverse->next && (traverse->next->priority < newnode->priority))
+ traverse=traverse->next;
+
+ newnode->next = traverse->next;
+ traverse->next = newnode;
+ newnode->prev = traverse;
+ if(newnode->next)
+ newnode->next->prev = newnode;
+ else
+ conference->tail = newnode;
+ }
+ }
+
+ return ++floorRequestID;
+}
+
+/* Return the UserID of the user who made the request */
+unsigned short int bfcp_give_user_of_request(bfcp_queue *conference, unsigned short int floorRequestID)
+{
+ if(conference == NULL)
+ return 0;
+ if(floorRequestID == 0)
+ return 0;
+
+ pnode traverse;
+ traverse = conference->head;
+
+ while(traverse && (traverse->floorRequestID != floorRequestID))
+ traverse = traverse->next;
+
+ if(!traverse || traverse->floorRequestID!= floorRequestID)
+ /* This node is not in the list */
+ return 0;
+ else {
+ if(traverse->beneficiaryID != 0)
+ return(traverse->beneficiaryID);
+ else
+ return(traverse->userID);
+ }
+}
+
+/* Return FoorRequestID, if user with userID exist in conference list,
+ this API is basically called when user sends FloorRelease message with FloorRequestID 0 */
+unsigned short int bfcp_get_floor_requestid(bfcp_queue *conference, unsigned short int userID)
+{
+ if (conference == NULL || userID == 0) {
+ return 0;
+ }
+
+ pnode traverse;
+
+ for (traverse = conference->head; traverse && (traverse->userID != userID); traverse = traverse->next);
+
+ if (traverse) {
+ return traverse->floorRequestID;
+ }
+
+ return 0;
+}
+
+/* Change status to a floor in a request */
+int bfcp_change_status(bfcp_queue *conference, unsigned short int floorID, unsigned short int floorRequestID, int status, char *floor_chair_info)
+{
+ if(conference == NULL)
+ return -1;
+ if(floorRequestID == 0)
+ return -1;
+ if((status < BFCP_FLOOR_STATE_WAITING) || (status > BFCP_FLOOR_STATE_GRANTED))
+ return -1;
+
+ pnode traverse;
+ pfloor floor;
+ int dLen;
+
+ traverse = conference->head;
+
+ while(traverse && (traverse->floorRequestID != floorRequestID))
+ traverse = traverse->next;
+
+ if(!traverse || (traverse->floorRequestID != floorRequestID))
+ /* This node is not in the list */
+ return -1;
+
+ floor = traverse->floor;
+ while(floor) {
+ if(floor->floorID == floorID) {
+ floor->status = status;
+ /* If there's chair-provided text, add it */
+ if(floor_chair_info != NULL) {
+ dLen = strlen(floor_chair_info);
+ if(dLen != 0) {
+ if(floor->chair_info != NULL) {
+ free(floor->chair_info);
+ floor->chair_info = NULL;
+ }
+ floor->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(floor->chair_info == NULL)
+ return -1;
+ memcpy(floor->chair_info, floor_chair_info, dLen+1);
+ }
+ } else
+ floor->chair_info = NULL;
+ return 0;
+ }
+ floor = floor->next;
+ }
+
+ /* If we arrived so far, some error happened */
+ return -1;
+
+}
+
+/* Check if the overall status is actually the status of every floor in the request (?) */
+int bfcp_all_floor_status(bfcp_queue *conference, unsigned short int floorRequestID, int status)
+{
+ if(conference == NULL)
+ return -1;
+ if(floorRequestID == 0)
+ return -1;
+ if((status < BFCP_FLOOR_STATE_WAITING) || (status > BFCP_FLOOR_STATE_GRANTED))
+ return -1;
+
+ pnode traverse;
+ pfloor floor;
+
+ traverse = conference->head;
+
+ while(traverse && (traverse->floorRequestID != floorRequestID))
+ traverse = traverse->next;
+
+ if(!traverse || (traverse->floorRequestID != floorRequestID))
+ /* This node is not in the list */
+ return -1;
+
+ floor = traverse->floor;
+ while(floor) {
+ if(floor->status != status)
+ return -1;
+ floor = floor->next;
+ }
+
+ return 0;
+}
+
+/* Check if the pthread identifier is valid (?) */
+int bfcp_all_floor_pID(pnode newnode)
+{
+ if(newnode == NULL)
+ return 0;
+
+ pfloor floor;
+
+ floor = newnode->floor;
+
+ while(floor) {
+#ifndef WIN32
+ if(floor->pID!=0)
+#else
+ if(floor->pID.p!=NULL)
+#endif
+ return -1;
+ floor=floor->next;
+ }
+
+ return 0;
+}
+
+/* Remove a floor from a floor request information (?) */
+int bfcp_delete_node_with_floorID(unsigned long int conferenceID, bfcp_queue *accepted, bfcp_queue *conference, unsigned short int floorID, bfcp_list_floors *lfloors, int type_list)
+{
+ if(conference == NULL)
+ return -1;
+ if(floorID == 0)
+ return -1;
+
+ pnode traverse, traverse_temp;
+ pfloor floor, temp, next;
+ floor_request_query *temp_request;
+ floor_request_query *next_request;
+ floor_request_query *floorrequest;
+ int delete_node = 0, i = 0;
+ unsigned short int userID;
+
+ traverse = conference->head;
+
+ while(traverse) {
+ floor = traverse->floor;
+ delete_node = 0;
+ while((floor != NULL) && (floor->floorID >= floorID)) {
+ if(floor->floorID == floorID) {
+ /* The head pointer points to the node we want to delete */
+ traverse_temp = traverse;
+
+ if(traverse_temp->beneficiaryID !=0)
+ userID = traverse_temp->beneficiaryID;
+ else
+ userID= traverse_temp->userID;
+
+ floorrequest = traverse_temp->floorrequest;
+
+ if(traverse_temp == conference->head) {
+ conference->head = traverse_temp->next;
+ traverse = conference->head;
+ if(traverse != NULL) {
+ traverse->prev = NULL;
+ if(traverse->next == NULL)
+ conference->tail = traverse;
+ } else
+ conference->tail = NULL;
+ } else {
+ if(traverse_temp->prev) {
+ /* It is not the first element */
+ traverse = traverse_temp->prev;
+ traverse_temp->prev->next = traverse_temp->next;
+ }
+ if(traverse_temp->next) {
+ /* It is not the last element */
+ traverse = traverse_temp->prev;
+ traverse_temp->next->prev = traverse_temp->prev;
+ } else {
+ traverse = NULL;
+ conference->tail = traverse_temp->prev;
+ }
+ }
+
+ /* Free all the elements from the floor list */
+ temp = traverse_temp->floor;
+ while(temp) {
+ /* Kill the threads */
+ if(type_list == 1) {
+#ifndef WIN32
+ if(temp->pID !=0) {
+ pthread_cancel(temp->pID);
+ temp->pID = 0;
+ }
+#else
+ if(temp->pID.p != NULL) {
+ pthread_cancel(temp->pID);
+ temp->pID.p = NULL;
+ }
+#endif
+ }
+
+ next = temp->next;
+ if(temp->status == BFCP_ACCEPTED) {
+ i = bfcp_return_position_floor(lfloors, temp->floorID);
+ if(i != -1) {
+ if(lfloors != NULL) {
+ if(lfloors->floors != NULL)
+ lfloors->floors[i].floorState = BFCP_FLOOR_STATE_WAITING;
+ }
+ }
+ }
+ free(temp->chair_info);
+ temp->chair_info = NULL;
+ free(temp);
+ temp = NULL;
+ temp = next;
+ }
+
+ /* Free all the elements from the request list */
+ temp_request = traverse_temp->floorrequest;
+ while(temp_request != NULL) {
+ next_request = temp_request->next;
+ free(temp_request);
+ temp_request = NULL;
+ temp_request = next_request;
+ }
+
+ free(traverse_temp->participant_info);
+ traverse_temp->participant_info = NULL;
+ free(traverse_temp->chair_info);
+ traverse_temp->chair_info = NULL;
+ free(traverse_temp);
+ traverse_temp = NULL;
+ floor = NULL;
+ delete_node = 1;
+ } else
+ floor = floor->next;
+ }
+ if((traverse != NULL) && (delete_node !=1))
+ traverse = traverse->next;
+ }
+
+ return 0;
+}
+
+/* Remove all elements related to an user from a floor request information (?) */
+int bfcp_delete_node_with_userID(bfcp_queue *conference, unsigned short int userID, bfcp_list_floors *lfloors)
+{
+ if(conference == NULL)
+ return 0;
+ if(userID == 0)
+ return -1;
+ if(lfloors == NULL)
+ return 0;
+ if(lfloors->floors == NULL)
+ return 0;
+
+ pnode traverse, traverse_temp;
+ pfloor temp, next;
+ floor_request_query *temp_request;
+ floor_request_query *next_request;
+ int i = 0;
+
+ traverse = conference->head;
+
+ while(traverse!=NULL) {
+ if((traverse->userID == userID) || (traverse->beneficiaryID == userID)) {
+ /* The head pointer points to the node we want to delete */
+ traverse_temp = traverse;
+ if(traverse_temp == conference->head) {
+ conference->head = traverse_temp->next;
+ traverse = conference->head;
+ if(traverse != NULL) {
+ traverse->prev = NULL;
+ if(traverse->next == NULL)
+ conference->tail = traverse;
+ } else
+ conference->tail = NULL;
+ } else {
+ if(traverse_temp->prev) {
+ /* It is not the first element */
+ traverse = traverse_temp->prev;
+ traverse_temp->prev->next = traverse_temp->next;
+ }
+ if(traverse_temp->next) {
+ /* It is not the last element */
+ traverse = traverse_temp->prev;
+ traverse_temp->next->prev = traverse_temp->prev;
+ }
+ else {
+ traverse = NULL;
+ conference->tail = traverse_temp->prev;
+ }
+ }
+ /* Free all the elements from the floor list */
+ temp = traverse_temp->floor;
+ while(temp != NULL) {
+ next = temp->next;
+ if(temp->status == 2) {
+ i = bfcp_return_position_floor(lfloors, temp->floorID);
+ if(i != -1)
+ lfloors->floors[i].floorState = BFCP_FLOOR_STATE_WAITING;
+ }
+ free(temp->chair_info);
+ temp->chair_info = NULL;
+ free(temp);
+ temp = NULL;
+ temp = next;
+ }
+ /* Free all the elements from the request list */
+ temp_request = traverse_temp->floorrequest;
+ while(temp_request != NULL) {
+ next_request = temp_request->next;
+ free(temp_request);
+ temp_request = NULL;
+ temp_request = next_request;
+ }
+
+ free(traverse_temp->participant_info);
+ traverse_temp->participant_info = NULL;
+ free(traverse_temp->chair_info);
+ traverse_temp->chair_info = NULL;
+ free(traverse_temp);
+ traverse_temp = NULL;
+ } else
+ traverse = traverse->next;
+ }
+
+ return 0;
+}
+
+/* Remove a FloorRequest from the BFCP queues */
+bfcp_floor *bfcp_delete_request(bfcp_queue *conference, unsigned short int floorRequestID, int type_queue)
+{
+ if(conference == NULL)
+ return NULL;
+ if(floorRequestID == 0)
+ return NULL;
+
+ pnode traverse;
+ pfloor temp, floor;
+
+ traverse = conference->head;
+
+ while(traverse && (traverse->floorRequestID != floorRequestID))
+ traverse = traverse->next;
+
+ if(!traverse || (traverse->floorRequestID != floorRequestID))
+ /* This node is not in the list */
+ return NULL;
+
+ /* Remove the thread if this node is in the pending queue*/
+ if(type_queue==2) {
+ floor = traverse->floor;
+ while(floor) {
+#ifndef WIN32
+ if(floor->pID != 0) {
+ pthread_cancel(floor->pID);
+ floor->pID = 0;
+ }
+#else
+ if(floor->pID.p != NULL) {
+ pthread_cancel(floor->pID);
+ floor->pID.p = NULL;
+ }
+#endif
+ floor = floor->next;
+ }
+ }
+
+ /* The head pointer points to the node we want to delete */
+ if(traverse == conference->head)
+ conference->head = traverse->next;
+ if(traverse->prev)
+ /* It is not the first element */
+ traverse->prev->next = traverse->next;
+ if(traverse->next)
+ /* It is not the last element */
+ traverse->next->prev = traverse->prev;
+ else
+ conference->tail = traverse->prev;
+
+ /* temp is the list with all the floors */
+ temp = traverse->floor;
+
+ /* Remove the list of requests */
+ remove_request_list_of_node(traverse->floorrequest);
+
+ free(traverse->participant_info);
+ traverse->participant_info = NULL;
+ free(traverse->chair_info);
+ traverse->chair_info = NULL;
+ free(traverse);
+ traverse = NULL;
+
+ return temp;
+}
+
+/* Get a FloorRequest from one of the BFCP queues */
+bfcp_node *bfcp_extract_request(bfcp_queue *conference, unsigned short int floorRequestID)
+{
+ if(conference == NULL)
+ return NULL;
+ if(floorRequestID == 0)
+ return NULL;
+
+ pnode traverse;
+ traverse = conference->head;
+
+ while(traverse && (traverse->floorRequestID != floorRequestID))
+ traverse = traverse->next;
+
+ if(!traverse || (traverse->floorRequestID != floorRequestID))
+ /* This node is not in the list */
+ return NULL;
+
+ /* The head pointer points to the node we want to retrieve */
+ if(traverse == conference->head)
+ conference->head = traverse->next;
+ if(traverse->prev)
+ /* It is not the first element */
+ traverse->prev->next = traverse->next;
+ if(traverse->next)
+ /* It is not the last element */
+ traverse->next->prev = traverse->prev;
+ else
+ conference->tail = traverse->prev;
+
+ return traverse;
+}
+
+/* Setup a FloorRequest so that it is to be sent in a BFCP message (?) */
+int bfcp_floor_request_query_server(bfcp_queue *conference, unsigned short int floorRequestID, unsigned short int userID, int sockfd)
+{
+ if(conference == NULL)
+ return -1;
+ if(floorRequestID == 0)
+ return -1;
+
+ pnode traverse;
+ traverse = conference->head;
+
+ while(traverse && (traverse->floorRequestID != floorRequestID))
+ traverse = traverse->next;
+
+ if(!traverse || (traverse->floorRequestID != floorRequestID))
+ /* This node is not in the list */
+ return -1;
+
+ return add_request_to_the_node(traverse, userID, sockfd);
+}
+
+/* Remove all requests from a list */
+int bfcp_clean_request_list(bfcp_queue *conference)
+{
+ if(conference == NULL)
+ return -1;
+
+ pnode traverse, node;
+ pfloor temp, next;
+ floor_request_query *temp_request;
+ floor_request_query *next_request;
+
+ traverse = conference->head;
+ while(traverse) {
+ node = traverse;
+ traverse = traverse->next;
+
+ /* Free all the elements of the floor list */
+ temp = node->floor;
+ while(temp) {
+ /* Free all the threads handling the request */
+#ifndef WIN32
+ if(temp->pID != 0) {
+ pthread_cancel(temp->pID);
+ temp->pID = 0;
+ }
+#else
+ if(temp->pID.p != NULL) {
+ pthread_cancel(temp->pID);
+ temp->pID.p = NULL;
+ }
+#endif
+ next = temp->next;
+ free(temp->chair_info);
+ temp->chair_info = NULL;
+ free(temp);
+ temp = NULL;
+ temp = next;
+ }
+ /* Free all the elements from the request list */
+ temp_request = node->floorrequest;
+ while(temp_request) {
+ next_request = temp_request->next;
+ free(temp_request);
+ temp_request = NULL;
+ temp_request = next_request;
+ }
+
+ free(node->participant_info);
+ node->participant_info = NULL;
+ free(node->chair_info);
+ node->chair_info = NULL;
+ free(node);
+ node = NULL;
+ }
+ conference->head = NULL;
+ conference->tail = NULL;
+
+ return 0;
+}
+
+/* Free a linked list of requests */
+int bfcp_remove_request_list(bfcp_queue **conference_p)
+{
+ if(conference_p == NULL)
+ return 0;
+
+ int error;
+ bfcp_queue *conference = *conference_p;
+
+ error = bfcp_clean_request_list(conference);
+ if(error==0) {
+ free(conference);
+ conference = NULL;
+ *conference_p = NULL;
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+/* Kill all the running threads handling a specific FloorRequest */
+int bfcp_kill_threads_request_with_FloorRequestID(bfcp_queue *conference, unsigned short int floorRequestID)
+{
+ if(conference == NULL)
+ return -1;
+ if(floorRequestID == 0)
+ return -1;
+
+ pnode traverse;
+ pfloor floor;
+
+ traverse = conference->head;
+
+ while(traverse && (traverse->floorRequestID != floorRequestID))
+ traverse = traverse->next;
+
+ if(!traverse || (traverse->floorRequestID != floorRequestID))
+ /* This node is not in the list */
+ return -1;
+
+ floor = traverse->floor;
+ while(floor) {
+#ifndef WIN32
+ if(floor->pID != 0) {
+ pthread_cancel(floor->pID);
+ floor->pID = 0;
+ }
+#else
+ if(floor->pID.p != NULL) {
+ pthread_cancel(floor->pID);
+ floor->pID.p = NULL;
+ }
+#endif
+ floor = floor->next;
+ }
+
+ return 0;
+}
+
+/* Convert a 'bfcp_node' info to 'bfcp_floor_request_information' (bfcp_messages.h) */
+bfcp_floor_request_information *bfcp_show_floorrequest_information(bfcp_queue *conference, lusers users, unsigned long int floorRequestID, int type_queue)
+{
+ if(conference == NULL)
+ return NULL;
+
+ pnode traverse;
+ pfloor floor;
+ bfcp_user_information *beneficiary_info, *user_info;
+ bfcp_floor_request_information *frqInfo;
+ bfcp_overall_request_status *oRS = NULL;
+ bfcp_floor_request_status *fRS_temp = NULL, *fRS = NULL;
+
+ traverse = conference->tail;
+
+ if(!traverse)
+ /* The list is empty */
+ return NULL;
+
+ while(traverse) {
+ if(traverse->floorRequestID == floorRequestID) {
+ if(type_queue == 0)
+ /* Granted */
+ oRS = bfcp_new_overall_request_status(traverse->floorRequestID, BFCP_GRANTED, 0, traverse->chair_info);
+ else if(type_queue==1)
+ /* Accepted */
+ oRS = bfcp_new_overall_request_status(traverse->floorRequestID, BFCP_ACCEPTED, traverse->queue_position, traverse->chair_info);
+ else if(type_queue==2)
+ /* Pending */
+ oRS = bfcp_new_overall_request_status(traverse->floorRequestID, BFCP_PENDING, traverse->priority, traverse->chair_info);
+ else
+ /* Revoke */
+ oRS = bfcp_new_overall_request_status(traverse->floorRequestID, BFCP_REVOKED, 0, traverse->chair_info);
+
+ floor = traverse->floor;
+ if(floor != NULL) {
+ fRS = bfcp_new_floor_request_status(floor->floorID, 0, 0, floor->chair_info);
+ floor = floor->next;
+ while(floor) {
+ fRS_temp = bfcp_new_floor_request_status(floor->floorID, 0, 0, floor->chair_info);
+ if(fRS_temp != NULL)
+ bfcp_list_floor_request_status(fRS, fRS_temp, NULL);
+ floor = floor->next;
+ }
+ }
+
+ if(traverse->beneficiaryID !=0) {
+ beneficiary_info = bfcp_show_user_information(users, traverse->beneficiaryID);
+ if(beneficiary_info == NULL) {
+ bfcp_free_user_information(beneficiary_info);
+ return NULL;
+ }
+ } else
+ beneficiary_info=NULL;
+
+ if(traverse->userID != 0) {
+ user_info = bfcp_show_user_information(users, traverse->userID);
+ if(user_info == NULL) {
+ bfcp_free_user_information(user_info);
+ return NULL;
+ }
+ } else
+ user_info = NULL;
+
+ frqInfo = bfcp_new_floor_request_information(traverse->floorRequestID, oRS, fRS, beneficiary_info, user_info, traverse->priority, traverse->participant_info);
+ return frqInfo;
+ }
+ traverse = traverse->prev;
+ }
+
+ /* If we arrived so far, something wrong happened */
+ return NULL;
+}
+
+/* Create a new linked list of floors */
+bfcp_floor *create_floor_list(unsigned short int floorID, int status, char *floor_chair_info)
+{
+ if(status > BFCP_GRANTED)
+ return NULL;
+
+ bfcp_floor *floor_list;
+ int dLen;
+
+ /* Create a new list of floors */
+ floor_list = (pfloor)calloc(1, sizeof(bfcp_floor));
+
+ /* Initialize the list*/
+ if(floor_list == NULL)
+ return NULL;
+ else {
+ floor_list->floorID = floorID;
+ floor_list->status = status;
+#ifndef WIN32
+ floor_list->pID = 0;
+#else
+ floor_list->pID.p = NULL;
+#endif
+ /* If there's chair-provided text, add it */
+ if(floor_chair_info != NULL) {
+ dLen= strlen(floor_chair_info);
+ if(dLen != 0) {
+ floor_list->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(floor_list->chair_info == NULL)
+ return NULL;
+ memcpy(floor_list->chair_info, floor_chair_info, dLen+1);
+ }
+ } else
+ floor_list->chair_info = NULL;
+
+ floor_list->next = NULL;
+ }
+
+ return floor_list;
+}
+
+/* Add floors to a list in order */
+bfcp_floor *add_floor_list(bfcp_floor *floor_list, unsigned short int floorID, int status, char *floor_chair_info)
+{
+ if((status < 0) || (status > BFCP_GRANTED))
+ return NULL;
+ if(floor_list == NULL)
+ return NULL;
+
+ pfloor ini_floor_list, floor;
+ int dLen;
+
+ /* Create a new floor instance */
+ floor = (pfloor)calloc(1, sizeof(bfcp_floor));
+
+ /* Initialize the floor */
+ if(floor == NULL)
+ return NULL;
+
+ if(floor_list->floorID < floorID) {
+ floor->floorID = floorID;
+ floor->status = status;
+#ifndef WIN32
+ floor->pID = 0;
+#else
+ floor->pID.p = NULL;
+#endif
+ /* If there's chair-provided text, add it */
+ if(floor_chair_info != NULL) {
+ dLen = strlen(floor_chair_info);
+ if(dLen != 0) {
+ floor->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(floor->chair_info == NULL)
+ return NULL;
+ memcpy(floor->chair_info, floor_chair_info, dLen+1);
+ }
+ } else
+ floor->chair_info = NULL;
+
+ floor->next = floor_list;
+ floor_list = floor;
+ } else if(floor_list->floorID > floorID) {
+ ini_floor_list = floor_list;
+ while(ini_floor_list->next && (ini_floor_list->next->floorID > floorID))
+ ini_floor_list = ini_floor_list->next;
+ floor->floorID = floorID;
+ floor->status = status;
+#ifndef WIN32
+ floor->pID = 0;
+#else
+ floor->pID.p = NULL;
+#endif
+ /* If there's chair-provided text, add it */
+ if(floor_chair_info != NULL) {
+ dLen = strlen(floor_chair_info);
+ if(dLen != 0) {
+ floor->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(floor->chair_info == NULL)
+ return NULL;
+ memcpy(floor->chair_info, floor_chair_info, dLen+1);
+ }
+ } else
+ floor->chair_info = NULL;
+
+ floor->next = ini_floor_list->next;
+ ini_floor_list->next = floor;
+ }
+
+ return(floor_list);
+}
+
+/* Free a linked list of requests */
+int remove_floor_list(bfcp_floor *floor_list)
+{
+ pfloor next;
+
+ /* Free all the elements from the floor list */
+ while(floor_list) {
+ next = floor_list->next;
+ free(floor_list->chair_info);
+ floor_list->chair_info = NULL;
+ free(floor_list);
+ floor_list = NULL;
+ floor_list = next;
+ }
+
+ return 0;
+}
+
+/* Remove the list of requests from a request node */
+int remove_request_list_of_node(floor_request_query *floorrequest)
+{
+ floor_request_query * next = NULL;
+
+ /* Free all the elements from the floor list */
+ while(floorrequest) {
+ next = floorrequest->next;
+ floorrequest->next = NULL;
+ free(floorrequest);
+ floorrequest = NULL;
+ floorrequest = next;
+ }
+
+ return 0;
+}
+
+/* Add a request to a request node */
+int add_request_to_the_node(pnode traverse, unsigned short int userID, int sockfd)
+{
+ if(traverse == NULL)
+ return -1;
+
+ int exist_query;
+ floor_request_query *floorrequest = NULL;
+ floor_request_query *newnode = NULL;
+
+ floorrequest=traverse->floorrequest;
+
+ /* If the request already exists in the list, we don't add it again */
+ exist_query = 0;
+ while(floorrequest != NULL) {
+ if(floorrequest->userID == userID) {
+ exist_query = 1;
+ break;
+ }
+ floorrequest = floorrequest->next;
+ }
+
+ if(exist_query == 0) {
+ /* Create the new node */
+ newnode = (floor_request_query *)calloc(1, sizeof(floor_request_query));
+ if(newnode == NULL)
+ return -1;
+
+ floorrequest = traverse->floorrequest;
+
+ /* Add the request to the listto the list */
+ newnode->userID = userID;
+ newnode->fd = sockfd;
+ newnode->next = floorrequest;
+ traverse->floorrequest = newnode;
+ }
+
+ return 0;
+}
+
+/* Request a request from a request node */
+int remove_request_from_the_node(pnode traverse, unsigned short int userID)
+{
+ if(traverse == NULL)
+ return 0;
+
+ floor_request_query *floorrequest = NULL;
+ floor_request_query *newnode = NULL;
+
+ floorrequest = traverse->floorrequest;
+ if(floorrequest == NULL)
+ return 0;
+
+ /* If the request exists in the list, we remove it from the node */
+ if(floorrequest->userID == userID) {
+ traverse->floorrequest = floorrequest->next;
+ floorrequest->next = NULL;
+ free(floorrequest);
+ floorrequest = NULL;
+ return 0;
+ }
+
+ while(floorrequest->next != NULL) {
+ if(floorrequest->next->userID == userID) {
+ newnode = floorrequest->next;
+ floorrequest->next = newnode->next;
+ free(newnode);
+ newnode = NULL;
+ return 0;
+ }
+ floorrequest = floorrequest->next;
+ }
+
+ return 0;
+}
+
+/* ?? */
+int bfcp_accepted_pending_node_with_floorID(unsigned long int conferenceID, bfcp_queue *accepted, bfcp_queue *conference, unsigned short int floorID, bfcp_list_floors *lfloors, int type_list)
+{
+ if(conference == NULL)
+ return -1;
+ if(floorID == 0)
+ return -1;
+
+ pnode traverse, traverse_temp;
+ floor_request_query *floorrequest;
+ int delete_node = 0, error = 0;
+ unsigned short int userID;
+ bfcp_node *newnode = NULL;
+ pfloor floor;
+
+ traverse = conference->head;
+
+ while(traverse) {
+ floor = traverse->floor;
+ delete_node = 0;
+ while((floor != NULL) && (floor->floorID >= floorID)) {
+ if(floor->floorID == floorID) {
+ floor->status = 1;
+ floor->chair_info = NULL;
+ }
+
+ /* If all the floors in the request have been accepted... */
+ if(bfcp_all_floor_status(conference, traverse->floorRequestID, 1) == 0) {
+ traverse_temp = traverse->next;
+ /* ...extract the node request from the Pending list... */
+ newnode = bfcp_extract_request(conference, traverse->floorRequestID);
+
+ /* ...and remove the threads for this node */
+ floor = newnode->floor;
+ while(floor) {
+#ifndef WIN32
+ if(floor->pID != 0) {
+ pthread_cancel(floor->pID);
+ floor->pID = 0;
+ }
+#else
+ if(floor->pID.p != NULL) {
+ pthread_cancel(floor->pID);
+ floor->pID.p = NULL;
+ }
+#endif
+ floor = floor->next;
+ }
+
+ /* Put the node in the Accepted list */
+ /* Change the priority of the node to the lowest one */
+ newnode->priority = BFCP_LOWEST_PRIORITY;
+
+ error = bfcp_insert_request(accepted, newnode, traverse->floorRequestID, NULL);
+ if(error == -1)
+ return (-1);
+
+ /* Add the floor request information to the floor nodes */
+ if(newnode->beneficiaryID != 0)
+ userID = newnode->beneficiaryID;
+ else
+ userID = newnode->userID;
+
+ floorrequest = newnode->floorrequest;
+
+ delete_node = 1;
+ traverse = traverse_temp;
+ } else
+ floor = floor->next;
+ }
+ if((traverse != NULL) && (delete_node != 1))
+ traverse = traverse->next;
+ }
+
+ return 0;
+}
+
+/* Change position in queue to a FloorRequest */
+int bfcp_change_queue_position(bfcp_queue *conference, unsigned short int floorRequestID, int queue_position)
+{
+ if(conference == NULL)
+ return 0;
+ if(queue_position <0)
+ return 0;
+
+ pnode traverse;
+ traverse = conference->head;
+
+ while(traverse && (traverse->floorRequestID != floorRequestID))
+ traverse = traverse->next;
+
+ if(!traverse || (traverse->floorRequestID != floorRequestID))
+ /* This node is not in the list */
+ return 0;
+ else {
+ if(queue_position > traverse->queue_position)
+ traverse->queue_position = queue_position;
+ }
+
+ return 0;
+}
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_link_list.h b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_link_list.h
new file mode 100644
index 00000000000..364f71b0051
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_link_list.h
@@ -0,0 +1,136 @@
+#ifndef _BFCP_LINK_LIST_H
+#define _BFCP_LINK_LIST_H
+
+#include
+#include
+#include
+
+/* Definition for threads (Asterisk redefines pthreads) */
+#include "bfcp_threads.h"
+
+#include "bfcp_floor_list.h"
+#include "bfcp_user_list.h"
+
+/* The BFCP messages building/parsing library */
+#include
+
+/* FloorRequestQuery instance (to notify about request events) */
+typedef struct floor_request_query {
+ unsigned short int userID; /* User to notify */
+ int fd; /* File descriptor of the user's connection */
+ struct floor_request_query *next; /* Next FloorRequestQuery in the list */
+} floor_request_query;
+
+/* Floor information */
+typedef struct bfcp_floor {
+ unsigned short int floorID; /* FloorID in this request */
+ int status; /* Floor state as defined in bfcp_floor_list.h */
+ char *chair_info; /* Chair-provided text about ChairActions */
+ pthread_t pID; /* Thread handling this request */
+ struct bfcp_floor *next; /* Next Floor in the list */
+} bfcp_floor;
+/* Pointer to a specific instance */
+typedef bfcp_floor *pfloor;
+
+/* FloorRequest information */
+typedef struct bfcp_node {
+ unsigned short int floorRequestID;
+ unsigned short int userID;
+ unsigned short int beneficiaryID;
+ int priority; /* Priority in the Pending queue */
+ int queue_position; /* Queue Position in the Accepted list */
+ char *participant_info; /* Participant-provided text */
+ char *chair_info; /* Chair-provided text about ChairActions */
+ struct floor_request_query *floorrequest; /* Array of queries for this request */
+ struct bfcp_floor *floor; /* List of floors in this request */
+ struct bfcp_node *next, *prev; /* This is a double-linked list */
+} bfcp_node;
+/* Pointer to a specific instance */
+typedef bfcp_node *pnode;
+
+
+/*
+A BFCP queue is structured as follows:
+
+ NULL <----------- prev <----------- prev
+ head ---> object1 object2 object3 <--- tail
+ (struct bfcp_node) (struct bfcp_node) (struct bfcp_node)
+ next ------------> next ------------> NULL
+*/
+typedef struct bfcp_queue {
+ pnode head; /* The first element in the list */
+ pnode tail; /* The last element in the list */
+} bfcp_queue;
+
+
+/************************/
+/* List-related methods */
+/************************/
+
+/* Create a new linked list of BFCP queues */
+struct bfcp_queue *bfcp_create_list(void);
+/* Initialize a new FloorRequest node */
+struct bfcp_node *bfcp_init_request(unsigned short int userID, unsigned short int beneficiaryID, int priority, char *text, unsigned short int floorID);
+/* Add a floor to an existing FloorRequest */
+int bfcp_add_floor_to_request(pnode newnode, unsigned short int floorID);
+/* Add an existing FloorRequest to a BFCP queue */
+int bfcp_insert_request(bfcp_queue *conference, pnode newnode, unsigned short int floorRequestID, char *chair_info);
+/* Return the UserID of the user who made the request */
+unsigned short int bfcp_give_user_of_request(bfcp_queue *conference, unsigned short int floorRequestID);
+
+/*!
+ \brief Retrieve FloorRequestID, if user with userID exist in conference list
+ \param conference The linked list of currently managed conferences
+ \param userID user_id of user whose FloorRequestID is needed
+ \return FloorRequestID If user exist in conference list, else return 0
+ */
+unsigned short int bfcp_get_floor_requestid(bfcp_queue *conference, unsigned short int userID);
+
+/* Change status to a floor in a request */
+int bfcp_change_status(bfcp_queue *conference, unsigned short int floorID, unsigned short int floorRequestID, int status, char *floor_chair_info);
+/* Check if the overall status is actually the status of every floor in the request (?) */
+int bfcp_all_floor_status(bfcp_queue *conference, unsigned short int floorRequestID, int status);
+/* Check if the pthread identifier is valid (?) */
+int bfcp_all_floor_pID(pnode newnode);
+/* Remove a floor from a floor request information (?) */
+int bfcp_delete_node_with_floorID(unsigned long int conferenceID, bfcp_queue *accepted, bfcp_queue *conference, unsigned short int floorID, bfcp_list_floors *lfloors, int type_list);
+/* Remove all elements related to an user from a floor request information (?) */
+int bfcp_delete_node_with_userID(bfcp_queue *conference, unsigned short int userID, bfcp_list_floors *lfloors);
+/* Remove a FloorRequest from the BFCP queues */
+bfcp_floor *bfcp_delete_request(bfcp_queue *conference, unsigned short int floorRequestID, int type_queue);
+/* Get a FloorRequest from one of the BFCP queues */
+bfcp_node *bfcp_extract_request(bfcp_queue *conference, unsigned short int floorRequestID);
+/* Setup a FloorRequest so that it is to be sent in a BFCP message (?) */
+int bfcp_floor_request_query_server(bfcp_queue *conference, unsigned short int floorRequestID, unsigned short int userID, int sockfd);
+/* Remove all requests from a list */
+int bfcp_clean_request_list(bfcp_queue *conference);
+/* Free a linked list of requests */
+int bfcp_remove_request_list(bfcp_queue **conference);
+/* Kill all the running threads handling a specific FloorRequest */
+int bfcp_kill_threads_request_with_FloorRequestID(bfcp_queue *conference, unsigned short int floorRequestID);
+/* Convert a 'bfcp_node' info to 'bfcp_floor_request_information' (bfcp_messages.h) */
+bfcp_floor_request_information *bfcp_show_floorrequest_information(bfcp_queue *conference, lusers users, unsigned long int FloorRequestID, int type_queue);
+
+
+/******************/
+/* Helper methods */
+/******************/
+
+/* Create a new linked list of floors */
+bfcp_floor *create_floor_list(unsigned short int floorID, int status, char *floor_chair_info);
+/* Add floors to a list in order */
+bfcp_floor *add_floor_list(bfcp_floor *floor_list, unsigned short int floorID, int status, char *floor_chair_info);
+/* Free a linked list of requests */
+int remove_floor_list(bfcp_floor *floor_list);
+/* Remove the list of requests from a request node */
+int remove_request_list_of_node(floor_request_query *floorrequest);
+/* Add a request to a request node */
+int add_request_to_the_node(pnode traverse, unsigned short int userID, int sockfd);
+/* Request a request from a request node */
+int remove_request_from_the_node(pnode traverse, unsigned short int userID);
+/* ?? */
+int bfcp_accepted_pending_node_with_floorID(unsigned long int conferenceID, bfcp_queue *accepted, bfcp_queue *conference, unsigned short int floorID, bfcp_list_floors *lfloors, int type_list);
+/* Change position in queue to a FloorRequest */
+int bfcp_change_queue_position(bfcp_queue *conference, unsigned short int floorRequestID, int queue_position);
+
+#endif
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_server.c b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_server.c
new file mode 100644
index 00000000000..8f0ac53e72c
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_server.c
@@ -0,0 +1,4174 @@
+#include "bfcp_server.h"
+
+/* Macro to check for errors after sending a BFCP message */
+#ifdef WIN32
+#define BFCP_SEND_CHECK_ERRORS(fds) \
+ if(error < 0) { \
+ if(arguments != NULL) \
+ bfcp_free_arguments(arguments); \
+ if(message != NULL) \
+ bfcp_free_message(message); \
+ return 0; \
+ } else if(error == 0) { \
+ if(arguments != NULL) \
+ bfcp_free_arguments(arguments); \
+ if(message != NULL) \
+ bfcp_free_message(message); \
+ close(fds); \
+ FD_CLR(fds, &allset); \
+ for(i = 0; i < BFCP_MAX_CONNECTIONS; i++) { \
+ if(client[i] == fds) { \
+ client[i] = -1; \
+ /* Free TLS Session as well */ \
+ if(session[i]) { \
+ SSL_free(session[i]); \
+ session[i] = NULL; \
+ } \
+ break; \
+ } \
+ } \
+ return -1; \
+ } \
+ if(arguments != NULL) \
+ bfcp_free_arguments(arguments); \
+ if(message != NULL) \
+ bfcp_free_message(message);
+#else
+#define BFCP_SEND_CHECK_ERRORS(fds) \
+ if(error < 0) { \
+ if(arguments != NULL) \
+ bfcp_free_arguments(arguments); \
+ if(message != NULL) \
+ bfcp_free_message(message); \
+ return 0; \
+ } else if(error == 0) { \
+ if(arguments != NULL) \
+ bfcp_free_arguments(arguments); \
+ if(message != NULL) \
+ bfcp_free_message(message); \
+ close(fds); \
+ for(i = 0; i < BFCP_MAX_CONNECTIONS; i++) { \
+ if(client[i] == fds) { \
+ client[i] = -1; \
+ int j=0; \
+ for(j = 0; j < fds_no; j++) { \
+ if(pollfds[j].fd == fds) { \
+ pollfds[j].fd = pollfds[fds_no-1].fd; \
+ pollfds[j].events = pollfds[fds_no-1].events; \
+ pollfds[j].revents = pollfds[fds_no-1].revents; \
+ fds_no--; \
+ break; \
+ } \
+ } \
+ /* Free TLS Session as well */ \
+ if(session[i]) { \
+ SSL_free(session[i]); \
+ session[i] = NULL; \
+ } \
+ break; \
+ } \
+ } \
+ return -1; \
+ } \
+ if(arguments != NULL) \
+ bfcp_free_arguments(arguments); \
+ if(message != NULL) \
+ bfcp_free_message(message);
+#endif
+
+/* Callbacks to notify the Application Server about BFCP events:
+ - 'arguments' has all the arguments of the BFCP message;
+ - 'outgoing_msg' is
+ 1 when the message has been SENT BY the FCS,
+ 0 when the message has been SENT TO the FCS.
+ */
+static int(*callback_func)(bfcp_arguments *arguments, int outgoing_msg);
+static int(*notify_to_server_app)(bfcp_arguments *arguments, int outgoing_msg);
+
+
+/* Headers for private methods */
+static void *recv_thread(void *st_server);
+
+
+/* Create a new Floor Control Server */
+struct bfcp_server *bfcp_initialize_bfcp_server(unsigned short int Max_conf, unsigned short int port_server, int(*notify_to_server_app)(bfcp_arguments *arguments, int outgoing_msg), int transport, char *certificate, char *privatekey, char *restricted)
+{
+#ifdef WIN32
+ WSADATA wsaData;
+ WSAStartup(MAKEWORD(1, 1), &wsaData);
+#endif
+
+ bfcp struct_server;
+ conference lconferences;
+ struct sockaddr_in server_addr;
+ int i = 0;
+ int server_sock;
+
+ if(Max_conf == 0)
+ Max_conf = 1;
+ if(port_server <= 1024)
+ port_server = BFCP_FCS_DEFAULT_PORT;
+
+ /* Create the new Floor Control Server */
+ struct_server = (bfcp)calloc(1, sizeof(bfcp_server));
+ if(struct_server == NULL)
+ return NULL;
+
+ /* Initialize and lock the mutex */
+ bfcp_mutex_init(&count_mutex, NULL);
+ bfcp_mutex_lock(&count_mutex);
+
+ lconferences = (conference)calloc(Max_conf, sizeof(bfcp_conference));
+ if(lconferences == NULL) {
+ bfcp_mutex_unlock(&count_mutex);
+ free(struct_server);
+ struct_server = NULL;
+ return NULL;
+ }
+
+ struct_server->list_conferences = lconferences;
+ struct_server->Actual_number_conference = 0;
+ struct_server->Max_number_conference = --Max_conf;
+
+ if(!restricted)
+ struct_server->restricted[0] = struct_server->restricted[1] = struct_server->restricted[2] = struct_server->restricted[3] = 0;
+ else {
+ if(sscanf(restricted, "%hu.%hu.%hu.%hu", &struct_server->restricted[0], &struct_server->restricted[1], &struct_server->restricted[2], &struct_server->restricted[3]) < 4)
+ struct_server->restricted[0] = struct_server->restricted[1] = struct_server->restricted[2] = struct_server->restricted[3] = 0;
+ if(struct_server->restricted[0] > 254)
+ struct_server->restricted[0] = struct_server->restricted[1] = struct_server->restricted[2] = struct_server->restricted[3] = 0;
+ if(struct_server->restricted[1] > 254)
+ struct_server->restricted[0] = struct_server->restricted[1] = struct_server->restricted[2] = struct_server->restricted[3] = 0;
+ if(struct_server->restricted[2] > 254)
+ struct_server->restricted[0] = struct_server->restricted[1] = struct_server->restricted[2] = struct_server->restricted[3] = 0;
+ if(struct_server->restricted[3] > 254)
+ struct_server->restricted[0] = struct_server->restricted[1] = struct_server->restricted[2] = struct_server->restricted[3] = 0;
+ }
+
+ callback_func = notify_to_server_app;
+
+ if (transport < 1) {
+ struct_server->bfcp_transport = BFCP_OVER_TCP;
+ } else if (transport == 1) {
+ struct_server->bfcp_transport = BFCP_OVER_TLS;
+ } else {
+ struct_server->bfcp_transport = BFCP_OVER_UDP;
+ }
+
+ if(struct_server->bfcp_transport == BFCP_OVER_TLS) {
+ /* Initialize TLS-related stuff */
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ /* The BFCP specification requires TLS */
+ method = (SSL_METHOD *)TLSv1_server_method();
+ if(!method)
+ return NULL;
+ /* Create and setup a new context that all sessions will inheritate */
+ context = SSL_CTX_new(method);
+ if(!context)
+ return NULL;
+ if(SSL_CTX_use_certificate_file(context, certificate, SSL_FILETYPE_PEM) < 1)
+ return NULL;
+ if(SSL_CTX_use_PrivateKey_file(context, privatekey, SSL_FILETYPE_PEM) < 1)
+ return NULL;
+ if(!SSL_CTX_check_private_key(context))
+ return NULL;
+ if(SSL_CTX_set_cipher_list(context, SSL_DEFAULT_CIPHER_LIST) < 0)
+ return NULL;
+ }
+
+ /* Setup the socket-related stuff */
+ if (transport <= 1) {
+ server_sock = socket(AF_INET, SOCK_STREAM, 0);
+ } else {
+ server_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ }
+
+ if(server_sock == -1)
+ return NULL;
+
+ if (transport == BFCP_OVER_UDP) {
+ server_sock_udp = server_sock;
+ } else {
+ server_sock_tcp = server_sock;
+ }
+
+ int yes = 1;
+#ifndef WIN32
+ if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0)
+#else
+ if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(int)) < 0)
+#endif
+ return NULL;
+
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(port_server);
+ server_addr.sin_addr.s_addr = INADDR_ANY;
+
+ /* Bind the server to the chosen listening port */
+ if(bind(server_sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0) {
+ /* Bind at the port failed... */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bind at the port failed...\n");
+ return NULL;
+ }
+
+ /* Listen */
+ if (transport != BFCP_OVER_UDP) {
+ if (listen(server_sock, BFCP_BACKLOG) == -1) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Listen failed...\n");
+ return NULL;
+ }
+
+ maxfd = server_sock;
+ maxi = -1;
+
+ for (i = 0; i < BFCP_MAX_CONNECTIONS; i++) {
+ client[i] = -1;
+#if 0
+ pollfds[i+1].fd = -1;
+ pollfds[i+1].events = 0;
+#endif
+ }
+ }
+
+#ifndef WIN32
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Going to poll fd=%d\n", server_sock);
+
+ if (transport == BFCP_OVER_UDP) {
+ poll_fd_udp[0].fd = server_sock;
+ poll_fd_udp[0].events = POLLIN;
+ close_udp_conn = 0;
+ } else {
+ pollfds[0].fd = server_sock;
+ pollfds[0].events = POLLIN;
+ fds_no = 1;
+ }
+#else
+ if (transport != BFCP_OVER_UDP) {
+ FD_ZERO(&wset);
+ FD_SET(server_sock, &wset);
+ }
+#endif
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ /* Create the thread that will handle incoming connections and messages */
+ if (transport == BFCP_OVER_UDP) {
+ if (pthread_create(&thread_udp, NULL, recv_thread, struct_server) < 0) {
+ /* Couldn't start the receiving thread */
+ return NULL;
+ }
+
+ pthread_detach(thread_udp);
+ } else {
+ if (pthread_create(&thread_tcp, NULL, recv_thread, struct_server) < 0) {
+ /* Couldn't start the receiving thread */
+ return NULL;
+ }
+
+ pthread_detach(thread_tcp);
+ }
+
+ return struct_server;
+}
+
+/* Destroy a currently running Floor Control Server */
+int bfcp_destroy_bfcp_server(bfcp_server **serverp)
+{
+ if(serverp == NULL)
+ return -1;
+
+ int error = 0, i, max_conference;
+ int server_sock;
+ int transport;
+
+ bfcp_server *server = *serverp;
+ max_conference = server->Actual_number_conference - 1;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ if (server->bfcp_transport == BFCP_OVER_UDP) {
+ server_sock = server_sock_udp;
+ } else {
+ server_sock = server_sock_tcp;
+ }
+
+ transport = server->bfcp_transport;
+
+ for(i = 0; i <= max_conference; i++) {
+ /* Free all the handled information (floors, users, etc) */
+ error = bfcp_remove_request_list(&(server->list_conferences[i].pending));
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ error = bfcp_remove_request_list(&(server->list_conferences[i].accepted));
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ error = bfcp_remove_request_list(&(server->list_conferences[i].granted));
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ error = bfcp_remove_floor_list(&(server->list_conferences[i].floor));
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ error = bfcp_remove_user_list(&(server->list_conferences[i].user));
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ server->list_conferences[i].conferenceID = 0;
+ server->list_conferences[i].chair_wait_request = 0;
+ server->list_conferences[i].automatic_accepted_deny_policy = 0;
+ }
+
+ /* Free the list of active conferences */
+ free(server->list_conferences);
+ server->list_conferences = NULL;
+
+ if(server->bfcp_transport == BFCP_OVER_TLS)
+ /* Free the TLS-related stuff */
+ SSL_CTX_free(context);
+
+ /* Free the FCS stuff */
+ if(error == 0) {
+ free(server);
+ server = NULL;
+ *serverp = NULL;
+ } else {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Destroy the mutex */
+ bfcp_mutex_unlock(&count_mutex);
+ bfcp_mutex_destroy(&count_mutex);
+
+ /* Destroy the thread */
+ if (transport == BFCP_OVER_UDP) {
+ // pthread_cancel(thread_udp);
+ close_udp_conn = 1;
+ } else {
+ pthread_cancel(thread_tcp);
+ }
+
+ /* Close the listening socket */
+#ifndef WIN32
+ shutdown(server_sock, SHUT_RDWR);
+#else
+ shutdown(server_sock, SD_BOTH);
+#endif
+ close(server_sock);
+
+ return 0;
+}
+
+/* Create a new BFCP Conference and add it to the FCS */
+int bfcp_initialize_conference_server(bfcp_server *conference_server, unsigned long int conferenceID, unsigned short int Max_Num_floors, unsigned short int Max_Number_Floor_Request, int automatic_accepted_deny_policy, unsigned long int chair_wait_request)
+{
+ if(conference_server == NULL)
+ return -1;
+ if(conference_server->list_conferences == NULL)
+ return -1;
+ if(conferenceID == 0)
+ return -1;
+
+ int i = 0, actual_conference;
+
+ if(Max_Number_Floor_Request <= 0)
+ Max_Number_Floor_Request = 1;
+ if(Max_Num_floors <= 0)
+ Max_Num_floors = 1;
+ if((automatic_accepted_deny_policy != 0) && (automatic_accepted_deny_policy != 1))
+ automatic_accepted_deny_policy = 0;
+ if(chair_wait_request <= 0)
+ chair_wait_request = 300; /* By default the FCS will wait 5 minutes for ChairActions */
+
+ /* Initialization the conference */
+ i = conference_server->Actual_number_conference;
+ if(i > conference_server->Max_number_conference)
+ /* The maximum allowed number of active conferences has already been reached */
+ return -1;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = conference_server->Actual_number_conference;
+ for(i = 0; ilist_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ if(conference_server->list_conferences[i].conferenceID == conferenceID) {
+ /* A conference with this conferenceID already exists */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Create a list for Pending request */
+ conference_server->list_conferences[i].pending = bfcp_create_list();
+ if(!conference_server->list_conferences[i].pending) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Create a list for Accepted request */
+ conference_server->list_conferences[i].accepted = bfcp_create_list();
+ if(!conference_server->list_conferences[i].accepted) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Create a list for Granted request */
+ conference_server->list_conferences[i].granted = bfcp_create_list();
+ if(!conference_server->list_conferences[i].granted) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ conference_server->list_conferences[i].conferenceID = conferenceID;
+
+ /* Create a list for users */
+ conference_server->list_conferences[i].user = bfcp_create_user_list(Max_Number_Floor_Request, Max_Num_floors);
+ if(!conference_server->list_conferences[i].user) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Create a list for floors */
+ conference_server->list_conferences[i].floor = bfcp_create_floor_list(Max_Num_floors);
+ if(!conference_server->list_conferences[i].floor) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ conference_server->list_conferences[i].chair_wait_request = chair_wait_request;
+ conference_server->list_conferences[i].automatic_accepted_deny_policy = automatic_accepted_deny_policy;
+ conference_server->list_conferences[i].floorRequestID = 1;
+
+ /* Both the conference and its list of users inheritate the transport property from the FCS */
+ conference_server->list_conferences[i].bfcp_transport = conference_server->bfcp_transport;
+ conference_server->list_conferences[i].user->bfcp_transport = conference_server->bfcp_transport;
+
+ conference_server->Actual_number_conference = ++i;
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Destroy a currently managed BFCP Conference and remove it from the FCS */
+int bfcp_destroy_conference_server(bfcp_server *conference_server, unsigned long int conferenceID)
+{
+ if(conferenceID <= 0)
+ return -1;
+ if(conference_server == NULL)
+ return -1;
+
+ int error = 0, i, actual_conference;
+ conference remove_conference, last_conference;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = conference_server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(conference_server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ if(conference_server->list_conferences[i].conferenceID == conferenceID) {
+ remove_conference = &conference_server->list_conferences[i];
+ last_conference = &conference_server->list_conferences[actual_conference];
+
+ /* We free the list of Pending requests */
+ error = bfcp_clean_request_list(remove_conference->pending);
+ if(error == 0) {
+ free(remove_conference->pending);
+ remove_conference->pending = NULL;
+ } else {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* We free the list of Accepted requests */
+ error = bfcp_clean_request_list(remove_conference->accepted);
+ if(error == 0) {
+ free(remove_conference->accepted);
+ remove_conference->accepted = NULL;
+ } else {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* We free the list of Granted requests */
+ error = bfcp_clean_request_list(remove_conference->granted);
+ if(error == 0) {
+ free(remove_conference->granted);
+ remove_conference->granted = NULL;
+ } else {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* We free the list of floors */
+ error = bfcp_remove_floor_list(&(remove_conference->floor));
+ if(error == 0) {
+ free(remove_conference->floor);
+ remove_conference->floor = NULL;
+ }
+ /* We free the list of users */
+ error = bfcp_remove_user_list(&(remove_conference->user));
+ if(error == 0) {
+ free(remove_conference->user);
+ remove_conference->user = NULL;
+ }
+
+ remove_conference->conferenceID = 0;
+ remove_conference->chair_wait_request = 0;
+ remove_conference->automatic_accepted_deny_policy = 0;
+
+ if(i != actual_conference) {
+ /* Swap the last element in queue and the one to delete (reorder) */
+ remove_conference->pending = last_conference->pending;
+ remove_conference->accepted = last_conference->accepted;
+ remove_conference->granted = last_conference->granted;
+ remove_conference->conferenceID = last_conference->conferenceID;
+ remove_conference->user = last_conference->user;
+ remove_conference->floor = last_conference->floor;
+ remove_conference->chair_wait_request = last_conference->chair_wait_request;
+ remove_conference->automatic_accepted_deny_policy = last_conference->automatic_accepted_deny_policy;
+
+ /* Remove the last element of the queue, which now is the one to delete */
+ last_conference->pending = NULL;
+ last_conference->accepted = NULL;
+ last_conference->granted = NULL;
+ last_conference->user = NULL;
+ last_conference->floor = NULL;
+ last_conference->conferenceID = 0;
+ last_conference->chair_wait_request = 0;
+ last_conference->automatic_accepted_deny_policy = 0;
+ }
+ } else {
+ /* A conference with this conferenceID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ conference_server->Actual_number_conference = actual_conference;
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Change the maximum number of allowed conferences in the FCS */
+int bfcp_change_number_bfcp_conferences_server(bfcp_server *server, unsigned short int Num)
+{
+ if(server == NULL)
+ return -1;
+ if(Num == 0)
+ Num = 1;
+
+ conference lconference;
+ int i = 0;
+
+ if((server->Actual_number_conference) > Num) {
+ for(i = Num; i < server->Actual_number_conference; i++)
+ bfcp_destroy_conference_server(server, server->list_conferences[i].conferenceID);
+ }
+
+ lconference = (conference)realloc(server->list_conferences, Num*sizeof(bfcp_conference));
+ if(lconference == NULL)
+ return -1;
+
+ server->list_conferences = lconference;
+
+ if((server->Actual_number_conference) > Num)
+ server->Actual_number_conference = Num;
+
+ server->Max_number_conference = --Num;
+
+ return 0;
+}
+
+/* Change the maximum number of users that can be granted this floor at the same time */
+int bfcp_change_number_granted_floor_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int floorID, unsigned short int limit_granted_floor)
+{
+ if(server == NULL)
+ return -1;
+ if(floorID <= 0)
+ return -1;
+ if(limit_granted_floor <= 0)
+ return -1;
+
+ int actual_conference = 0, value = 0;
+ int i = 0;
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ if(server->list_conferences[i].conferenceID == conferenceID) {
+ value = bfcp_change_number_granted_floor(server->list_conferences[i].floor, floorID, limit_granted_floor);
+ if(value == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Change the allowed number of per-floor requests for this list */
+int bfcp_change_user_req_floors_server(bfcp_server *server, unsigned short int Max_Number_Floor_Request)
+{
+ if(server == NULL)
+ return -1;
+ if(Max_Number_Floor_Request == 0)
+ Max_Number_Floor_Request = 1;
+
+ int i = 0, value = 0;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ for(i = 0; i < server->Actual_number_conference; i++) {
+ value = bfcp_change_user_req_floors(server->list_conferences[i].user, Max_Number_Floor_Request);
+ if(value == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Change the automated policy for requests related to floors that have no chair */
+int bfcp_change_chair_policy(bfcp_server *conference_server, unsigned long int conferenceID, int automatic_accepted_deny_policy, unsigned long int chair_wait_request)
+{
+ if(conference_server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+ if((automatic_accepted_deny_policy < 0) || (automatic_accepted_deny_policy > 1))
+ automatic_accepted_deny_policy = 0;
+
+ int i, actual_conference = 0;
+
+ actual_conference = conference_server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(conference_server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ if(conference_server->list_conferences[i].conferenceID == conferenceID) {
+ if(chair_wait_request != 0)
+ conference_server->list_conferences[i].chair_wait_request = chair_wait_request;
+ conference_server->list_conferences[i].automatic_accepted_deny_policy = automatic_accepted_deny_policy;
+ } else {
+ /* A conference with this conferenceID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Add a floor to an existing conference */
+int bfcp_add_floor_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int floorID, unsigned short int ChairID, int limit_granted_floor)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+ if(limit_granted_floor < 0)
+ return -1;
+
+ int actual_conference = 0, error, i;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ if(server->list_conferences[i].conferenceID == conferenceID) {
+ /* Check if the chair of the floor is a valid user */
+ if((bfcp_existence_user(server->list_conferences[i].user, ChairID) == 0) || (ChairID == 0)) {
+ error = bfcp_insert_floor(server->list_conferences[i].floor, floorID, ChairID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ error = bfcp_change_number_granted_floor(server->list_conferences[i].floor, floorID, limit_granted_floor);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ } else {
+ /* A conference with this conferenceID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Remove a floor from an existing conference */
+int bfcp_delete_floor_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int floorID)
+{
+ int actual_conference=0, value=0, error, i;
+ bfcp_queue *laccepted;
+
+ if(server == NULL) return -1;
+ if(conferenceID <= 0) return -1;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ if(server->list_conferences[i].conferenceID == conferenceID) {
+ /* Find the position of this floor in the floor list */
+ value = bfcp_return_position_floor(server->list_conferences[i].floor, floorID);
+
+ /* Remove the floor from the FloorRequests sublist of the user list */
+ error = bfcp_delete_a_floor_from_user_list(server->list_conferences[i].user, value);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Remove the floor from the Pending list */
+ error = bfcp_delete_node_with_floorID(server->list_conferences[i].conferenceID, server->list_conferences[i].accepted, server->list_conferences[i].pending, floorID, server->list_conferences[i].floor, 1);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Remove the floor from the Accepted list */
+ error = bfcp_delete_node_with_floorID(server->list_conferences[i].conferenceID, server->list_conferences[i].accepted, server->list_conferences[i].accepted, floorID, server->list_conferences[i].floor,0);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Remove the floor from the Granted list */
+ error = bfcp_delete_node_with_floorID(server->list_conferences[i].conferenceID, server->list_conferences[i].accepted, server->list_conferences[i].granted, floorID, server->list_conferences[i].floor,0);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if other requests that need this floor are in the Accepted list */
+ laccepted = server->list_conferences[i].accepted;
+ if(give_free_floors_to_the_accepted_nodes(server->list_conferences+i, laccepted, server->list_conferences[i].floor, NULL)== -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Remove the floor from the floor list */
+ error = bfcp_delete_floor(server->list_conferences[i].floor, floorID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ /* A conference with this conferenceID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Set a participant as chair of a floor */
+int bfcp_add_chair_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int floorID, unsigned short int ChairID)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+
+ int error, i, actual_conference = 0;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ if(server->list_conferences[i].conferenceID == conferenceID) {
+ /* Check if this is a valid user of the conference */
+ if(bfcp_existence_user(server->list_conferences[i].user, ChairID) == 0) {
+ /* Add the ChairID to the floor list */
+ error = bfcp_change_chair(server->list_conferences[i].floor, floorID, ChairID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ /* A user with this userID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ /* A conference with this conferenceID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Set no participant as chair for a floor */
+int bfcp_delete_chair_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int floorID)
+{
+ if(server == NULL)
+ return -1;
+ if(server->list_conferences == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+
+ int error, i, actual_conference = 0, position_floor = 0;
+ bfcp_floor *floor;
+ floor_request_query *newrequest;
+ pnode traverse;
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ if(server->list_conferences[i].conferenceID != conferenceID)
+ /* A conference with this conferenceID does NOT exist */
+ return -1;
+
+ if(server->list_conferences[i].floor != NULL) {
+ position_floor = bfcp_return_position_floor(server->list_conferences[i].floor, floorID);
+ if(position_floor == -1)
+ return -1;
+ } else
+ return -1;
+
+ /* Check if the chair of the floor is a valid user */
+ if(server->list_conferences[i].floor->floors[position_floor].chairID != 0) {
+ if(bfcp_existence_user(server->list_conferences[i].user, server->list_conferences[i].floor->floors[position_floor].chairID) == 0) {
+ /* Check if the automated response policy is to deny requests */
+ if(server->list_conferences[i].automatic_accepted_deny_policy == 1) {
+ /* Notify all interested users before cancelling the requests */
+ if((server->list_conferences[i].pending!=NULL) && (server->list_conferences[i].pending->head!=NULL)) {
+ traverse = server->list_conferences[i].pending->head;
+ while(traverse != NULL) {
+ floor = traverse->floor;
+ while(floor != NULL) {
+ if(floor->floorID == floorID) {
+ newrequest = traverse->floorrequest;
+ while(newrequest != NULL) {
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, conferenceID, newrequest->userID, 0, traverse, BFCP_CANCELLED, newrequest->fd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ newrequest = newrequest->next;
+ }
+ }
+ floor = floor->next;
+ }
+ traverse = traverse->next;
+ }
+ }
+ /* Remove the floor from the Pending list */
+ error = bfcp_delete_node_with_floorID(server->list_conferences[i].conferenceID, server->list_conferences[i].accepted, server->list_conferences[i].pending, floorID, server->list_conferences[i].floor,0);
+ if(error == -1)
+ return -1;
+ }
+ if(server->list_conferences[i].automatic_accepted_deny_policy == 0) {
+ error = bfcp_accepted_pending_node_with_floorID(server->list_conferences[i].conferenceID, server->list_conferences[i].accepted, server->list_conferences[i].pending, floorID, server->list_conferences[i].floor, 0);
+ if(error == -1)
+ return -1;
+
+ /* Notify all interested users before accepting the requests */
+ if((server->list_conferences[i].accepted != NULL) && (server->list_conferences[i].accepted->head != NULL)) {
+ traverse = server->list_conferences[i].accepted->head;
+ while(traverse != NULL) {
+ floor = traverse->floor;
+ while(floor != NULL) {
+ if(floor->floorID == floorID) {
+ newrequest = traverse->floorrequest;
+
+ while(newrequest != NULL) {
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, conferenceID, newrequest->userID, 0, traverse, BFCP_ACCEPTED, newrequest->fd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ newrequest = newrequest->next;
+ }
+ }
+ floor = floor->next;
+ }
+ traverse = traverse->next;
+ }
+ }
+ /* Check if the node should be in the Granted queue */
+ if(give_free_floors_to_the_accepted_nodes(server->list_conferences+i, server->list_conferences[i].accepted, server->list_conferences[i].floor, NULL) == -1)
+ return -1;
+ else {
+ /*send floor information after accepted all the floors*/
+ if((server->list_conferences[i].granted != NULL) && (server->list_conferences[i].granted->head != NULL)) {
+ traverse = server->list_conferences[i].granted->head;
+ while(traverse != NULL) {
+ floor = traverse->floor;
+ while(floor != NULL) {
+ if(floor->floorID == floorID) {
+ newrequest = traverse->floorrequest;
+ while(newrequest != NULL) {
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, conferenceID, newrequest->userID, 0, traverse, BFCP_GRANTED, newrequest->fd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ newrequest = newrequest->next;
+ }
+ }
+ floor = floor->next;
+ }
+ traverse = traverse->next;
+ }
+ }
+ }
+ }
+ /* Remove the ChairID from the floor list */
+ error = bfcp_change_chair(server->list_conferences[i].floor, floorID, 0);
+ if(error == -1)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Add a participant to the list of users of a BFCP Conference */
+int bfcp_add_user_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int userID, char *user_URI, char *user_display_name)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+
+ int error, i, actual_conference = 0;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ if(server->list_conferences[i].conferenceID == conferenceID) {
+ /* Add a new user to the conference */
+ error = bfcp_add_user(server->list_conferences[i].user, userID, user_URI, user_display_name);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ /* A conference with this conferenceID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Set address of a user in bfcp_list_users of a BFCP conference */
+int bfcp_set_user_address_server(bfcp_server *server,
+ unsigned long int conferenceID,
+ unsigned short int userID,
+ char *client_address,
+ unsigned short int client_port)
+{
+ if (server == NULL || conferenceID <= 0) {
+ return -1;
+ }
+
+ int error, i, actual_conference = 0;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference;
+
+ for (i = 0; i < actual_conference && (server->list_conferences[i].conferenceID != conferenceID); i++);
+
+ if (i < actual_conference) {
+ /* Set address of user in the conference */
+ error = bfcp_set_user_address(server->list_conferences[i].user, userID, client_address, client_port);
+
+ if (error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ /* A conference with this conferenceID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Retrieve participant address from user list of a BFCP conference */
+struct sockaddr_in *bfcp_get_user_address_server(bfcp_server *server,
+ unsigned long int conferenceID,
+ unsigned short int userID)
+{
+ if (server == NULL || conferenceID <= 0 || userID <= 0) {
+ return NULL;
+ }
+
+ int i, actual_conference = 0;
+ struct sockaddr_in *client_address = NULL;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference;
+
+ for (i = 0; i < actual_conference && (server->list_conferences[i].conferenceID != conferenceID); i++);
+
+ if (i < actual_conference) {
+ /* Check if this is a valid user in the conference */
+ if (bfcp_existence_user(server->list_conferences[i].user, userID) == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return NULL;
+ }
+
+ /* Get address of user */
+ client_address = bfcp_get_user_address(server->list_conferences[i].user, userID);
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return client_address;
+}
+
+/* Remove a participant from the list of users of a BFCP Conference */
+int bfcp_delete_user_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int userID)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+ if(userID <= 0)
+ return -1;
+
+ int error, i, y, actual_conference = 0;
+ bfcp_queue *laccepted;
+ bfcp_list_floors *lfloors;
+ pnode traverse;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ if(server->list_conferences[i].conferenceID == conferenceID) {
+ /* Check if this is a valid user in the conference */
+ if(bfcp_existence_user(server->list_conferences[i].user, userID) == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Remove the user from the FloorRequest list of every node */
+ error = bfcp_remove_floorrequest_from_all_nodes(server->list_conferences+i, userID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Remove the user from the FloorQuery list */
+ error = bfcp_remove_floorquery_from_all_nodes(server->list_conferences[i].floor, userID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Checks if the user is chair of any floors */
+ if(bfcp_exist_user_as_a_chair(server->list_conferences[i].floor, userID) == 0) {
+ /* This user is chair of at least one floor */
+ lfloors = server->list_conferences[i].floor;
+ for(y = 0; y < lfloors->actual_number_floors; y++) {
+ if(lfloors->floors[y].chairID == userID) {
+ error = bfcp_delete_chair_server(server, conferenceID, lfloors->floors[y].floorID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ }
+ }
+
+ /* Notify all interested users before cancelling the Pending requests */
+ if((server->list_conferences[i].pending != NULL) && (server->list_conferences[i].pending->head != NULL)) {
+ traverse = server->list_conferences[i].pending->head;
+ while(traverse != NULL) {
+ if((traverse->userID == userID) || (traverse->beneficiaryID == userID)) {
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, traverse, BFCP_CANCELLED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ traverse = traverse->next;
+ }
+ }
+
+ /* Notify all interested users before cancelling the Accepted requests */
+ if((server->list_conferences[i].accepted != NULL) && (server->list_conferences[i].accepted->head != NULL)) {
+ traverse = server->list_conferences[i].accepted->head;
+ while(traverse != NULL) {
+ if((traverse->userID == userID) || (traverse->beneficiaryID == userID)) {
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, traverse, BFCP_CANCELLED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ traverse = traverse->next;
+ }
+ }
+
+ /* Notify all interested users before cancelling the Granted requests */
+ if((server->list_conferences[i].granted != NULL) && (server->list_conferences[i].granted->head != NULL)) {
+ traverse = server->list_conferences[i].granted->head;
+ while(traverse != NULL) {
+ if((traverse->userID == userID) || (traverse->beneficiaryID == userID)) {
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, traverse, BFCP_CANCELLED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ traverse = traverse->next;
+ }
+ }
+
+ /* Remove the user from the Pending requests list */
+ error = bfcp_delete_node_with_userID(server->list_conferences[i].pending, userID, server->list_conferences[i].floor);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Remove the user from the Accepted requests list */
+ error = bfcp_delete_node_with_userID(server->list_conferences[i].accepted, userID, server->list_conferences[i].floor);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Remove the user from the Granted requests list */
+ error = bfcp_delete_node_with_userID(server->list_conferences[i].granted, userID, server->list_conferences[i].floor);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Finally remove the user from the conference */
+ error = bfcp_delete_user(server->list_conferences[i].user, userID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if other requests that need the floors freed by the leaving user are in the Accepted list */
+ laccepted = server->list_conferences[i].accepted;
+ if(give_free_floors_to_the_accepted_nodes(server->list_conferences+i, laccepted, server->list_conferences[i].floor, NULL) == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ /* A conference with this conferenceID does NOT exist */
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Create a new 'bfcp_floor_request_information' (bfcp_messages.h) out of a 'pnode' */
+bfcp_floor_request_information *create_floor_request_userID(pnode traverse,lusers users, unsigned short int userID, unsigned short int request_status, int i)
+{
+ if(traverse == NULL)
+ return NULL;
+ if(users == NULL)
+ return NULL;
+
+ bfcp_user_information *user_info;
+ bfcp_user_information *beneficiary_info;
+ bfcp_floor *node;
+ bfcp_floor_request_information *frqInfo = NULL;
+ bfcp_overall_request_status *oRS = NULL;
+ bfcp_floor_request_status *fRS_temp = NULL, *fRS = NULL;
+
+ /* If there's a beneficiary, add its information */
+ if(traverse->beneficiaryID != 0) {
+ beneficiary_info = bfcp_show_user_information(users, traverse->beneficiaryID);
+ if(beneficiary_info == NULL) {
+ bfcp_free_user_information(beneficiary_info);
+ return NULL;
+ }
+ } else
+ beneficiary_info = NULL;
+ /* If there's user information, add it */
+ if(traverse->userID != 0) {
+ user_info = bfcp_show_user_information(users, traverse->userID);
+ if(user_info == NULL) {
+ bfcp_free_user_information(user_info);
+ return NULL;
+ }
+ } else
+ user_info = NULL;
+
+ node = traverse->floor;
+ if(node != NULL) {
+ /* Passing request status as argument and neglect the case of invalid primitive in BFCP message */
+ fRS = bfcp_new_floor_request_status(node->floorID, request_status, 0, node->chair_info);
+ if(fRS == NULL) return NULL;
+ node = node->next;
+ while(node != NULL) {
+ /* Passing request status as argument and neglect the case of invalid primitive in BFCP message */
+ fRS_temp = bfcp_new_floor_request_status(node->floorID, request_status, 0, node->chair_info);
+ if(fRS_temp != NULL)
+ bfcp_list_floor_request_status(fRS, fRS_temp, NULL);
+ node=node->next;
+ }
+ } else
+ return NULL;
+
+ oRS = bfcp_new_overall_request_status(traverse->floorRequestID, request_status, i , traverse->chair_info);
+
+ frqInfo = bfcp_new_floor_request_information(traverse->floorRequestID, oRS, fRS, beneficiary_info, user_info, traverse->priority ,traverse->participant_info);
+
+ return frqInfo;
+}
+
+/* Create a new 'bfcp_floor_request_information' (bfcp_messages.h) out of a floor */
+bfcp_floor_request_information *create_floor_message(unsigned short int floorID, pnode traverse, lusers users, unsigned short int request_status, int i)
+{
+ if(traverse == NULL)
+ return NULL;
+ if(users == NULL)
+ return NULL;
+
+ bfcp_user_information *user_info;
+ bfcp_user_information *beneficiary_info;
+ bfcp_floor_request_information *frqInfo = NULL;
+ bfcp_floor_request_status *fRS = NULL;
+ bfcp_overall_request_status *oRS = NULL;
+
+ /* If there's a beneficiary, add its information */
+ if(traverse->beneficiaryID != 0) {
+ beneficiary_info = bfcp_show_user_information(users, traverse->beneficiaryID);
+ if(beneficiary_info == NULL) {
+ bfcp_free_user_information(beneficiary_info);
+ return NULL;
+ }
+ } else
+ beneficiary_info = NULL;
+
+ /* If there's user information, add its information */
+ if(traverse->userID != 0) {
+ user_info = bfcp_show_user_information(users, traverse->userID);
+ if(user_info == NULL) {
+ bfcp_free_user_information(user_info);
+ return NULL;
+ }
+ } else
+ user_info = NULL;
+
+ /* Setup the Floor Request Information by preparing its sub-attributes */
+ fRS = bfcp_new_floor_request_status(floorID, request_status, 0, NULL);
+ oRS = bfcp_new_overall_request_status(traverse->floorRequestID, request_status, i , traverse->chair_info);
+ frqInfo = bfcp_new_floor_request_information(traverse->floorRequestID, oRS, fRS, beneficiary_info, user_info, traverse->priority ,traverse->participant_info);
+
+ return frqInfo;
+}
+
+/* Setup and send a floorstatus BFCP message */
+int bfcp_show_floor_information(unsigned long int conferenceID, unsigned short int TransactionID, unsigned short int userID, bfcp_conference *conference, unsigned short int floorID, int sockid, fd_set allset, int *client, pnode newnode, unsigned short int status)
+{
+ if(conference == NULL)
+ return 0;
+
+ int error, i;
+ pnode traverse;
+ pfloor floor;
+ bfcp_message *message = NULL;
+ bfcp_arguments *arguments = NULL;
+ bfcp_floor_request_information *frqInfo = NULL, *list_frqInfo = NULL;
+ bfcp_floor_id_list *fID;
+
+ arguments = bfcp_new_arguments();
+ if(!arguments)
+ return -1;
+
+ arguments->entity = bfcp_new_entity(conferenceID, TransactionID, userID);
+ arguments->primitive = FloorStatus;
+ if(floorID != 0)
+ fID = bfcp_new_floor_id_list(floorID, 0);
+ else fID = NULL;
+
+ arguments->fID = fID;
+
+ if((status > BFCP_GRANTED) && (newnode != NULL)) {
+ frqInfo = create_floor_message(floorID, newnode, conference->user, status, 0);
+ if((frqInfo != NULL) && (list_frqInfo != NULL))
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else if(list_frqInfo == NULL)
+ list_frqInfo = frqInfo;
+ }
+
+ if(conference->granted != NULL) {
+ /* This is the Granted queue */
+ traverse = conference->granted->tail;
+ while(traverse) {
+ if((newnode == NULL) || (status <= BFCP_GRANTED) || ((newnode != NULL) && (newnode->floorRequestID != traverse->floorRequestID))) {
+ floor = traverse->floor;
+ while(floor) {
+ if(floor->floorID == floorID) {
+ frqInfo = create_floor_message(floorID, traverse, conference->user, 3, 0);
+ if((frqInfo != NULL) && (list_frqInfo != NULL))
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else if(list_frqInfo == NULL)
+ list_frqInfo = frqInfo;
+ }
+ floor = floor->next;
+ }
+ }
+ traverse = traverse->prev;
+ }
+ }
+
+ if(conference->accepted != NULL) {
+ /* This is the Accepted queue */
+ traverse = conference->accepted->tail;
+ i = 1;
+ while(traverse) {
+ if((newnode == NULL) || (status <= BFCP_GRANTED) || ((newnode != NULL) && (newnode->floorRequestID != traverse->floorRequestID))) {
+ floor = traverse->floor;
+ while(floor) {
+ if(floor->floorID == floorID) {
+ frqInfo = create_floor_message(floorID, traverse, conference->user, 2, i);
+ if((frqInfo != NULL) && (list_frqInfo != NULL))
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else if(list_frqInfo == NULL)
+ list_frqInfo = frqInfo;
+ }
+ floor = floor->next;
+ }
+ }
+ i = i + 1;
+ traverse = traverse->prev;
+ }
+ }
+
+ if(conference->pending != NULL) {
+ /* This is the Accepted queue */
+ traverse = conference->pending->tail;
+ while(traverse) {
+ if((newnode == NULL) || (status <= BFCP_GRANTED) || ((newnode != NULL) && (newnode->floorRequestID != traverse->floorRequestID))) {
+ floor = traverse->floor;
+ while(floor) {
+ if(floor->floorID == floorID) {
+ frqInfo = create_floor_message(floorID, traverse, conference->user, 1, 0);
+ if((frqInfo != NULL) && (list_frqInfo != NULL))
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else if(list_frqInfo == NULL)
+ list_frqInfo = frqInfo;
+ }
+ floor = floor->next;
+ }
+ }
+ traverse = traverse->prev;
+ }
+ }
+
+ arguments->frqInfo = list_frqInfo;
+
+ if (conference->bfcp_transport == BFCP_OVER_UDP) {
+ struct sockaddr_in *client_address = bfcp_get_user_address(conference->user, userID);
+ error = send_message_to_client_over_udp(arguments, sockid, notify_to_server_app, client_address);
+ } else {
+ error = send_message_to_client(arguments, sockid, notify_to_server_app,
+ conference->bfcp_transport);
+ }
+
+ BFCP_SEND_CHECK_ERRORS(sockid);
+
+ return 0;
+}
+
+/* Prepare the needed arguments for a FloorRequestStatus BFCP message */
+int bfcp_print_information_floor(bfcp_conference *conference, unsigned short int userID, unsigned short int TransactionID, pnode newnode, unsigned short int status)
+{
+ if(conference == NULL)
+ return 0;
+ if(conference->floor == NULL)
+ return 0;
+ if(conference->floor->floors == NULL)
+ return 0;
+ if(status <= 0)
+ return -1;
+ if(newnode == NULL)
+ return 0;
+
+ int error, position;
+ users user;
+ pfloor floor;
+ floor_request_query *newrequest;
+
+ /* Prepare all floor information needed by interested users */
+ floor = newnode->floor;
+ while(floor) {
+ position = bfcp_return_position_floor(conference->floor, floor->floorID);
+ if(position >= 0) {
+ if(conference->floor->floors != NULL) {
+ user = conference->user->users;
+ while (user) {
+ if (status == BFCP_GRANTED && (user->userID != newnode->userID)) {
+ /* Sending FloorStatus to all participants in conference except participant who was granted floor */
+ error = bfcp_show_floor_information(conference->conferenceID,
+ TransactionID, user->userID, conference, floor->floorID,
+ user->fd, allset, client, newnode, status);
+ if (error == -1) {
+ return -1;
+ }
+ } else if (status == BFCP_RELEASED) {
+ /* Sending FloorStatus to all participants in conference */
+ error = bfcp_show_floor_information(conference->conferenceID,
+ TransactionID, user->userID, conference, floor->floorID,
+ user->fd, allset, client, newnode, status);
+ if (error == -1) {
+ return -1;
+ }
+ }
+
+ user = user->next;
+ }
+ }
+ }
+ floor = floor->next;
+ }
+
+ newrequest = newnode->floorrequest;
+
+ while(newrequest != NULL) {
+ error = bfcp_show_requestfloor_information(conference->user, conference->accepted, conference->conferenceID, newrequest->userID, 0, newnode, status, newrequest->fd);
+ if(error == -1)
+ return -1;
+ newrequest = newrequest->next;
+ }
+
+ return 0;
+}
+
+/* Setup and send a FloorRequestStatus BFCP message */
+int bfcp_show_requestfloor_information(bfcp_list_users *list_users, bfcp_queue *accepted_queue, unsigned long int conferenceID, unsigned short int userID, unsigned short int TransactionID, pnode newnode, unsigned short int status, int socket)
+{
+ if(newnode == NULL)
+ return 0;
+ if(status <= 0)
+ return 0;
+ if(list_users == NULL)
+ return 0;
+
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message = NULL;
+ bfcp_floor *floorID;
+ bfcp_user_information *beneficiary_info, *user_info;
+ pnode traverse=NULL;
+ bfcp_overall_request_status *oRS = NULL;
+ bfcp_floor_request_status *fRS_temp = NULL, *fRS = NULL;
+ int i = 0, error = 0;
+
+ arguments = bfcp_new_arguments();
+ if(!arguments)
+ return -1;
+
+ arguments->entity = bfcp_new_entity(conferenceID, TransactionID, userID);
+ arguments->primitive = FloorRequestStatus;
+
+ if(newnode->beneficiaryID != 0) {
+ beneficiary_info = bfcp_new_user_information(newnode->beneficiaryID, (char *)bfcp_obtain_user_display_name(list_users, newnode->beneficiaryID), (char *)bfcp_obtain_userURI(list_users, newnode->beneficiaryID));
+ if(beneficiary_info == NULL) {
+ bfcp_free_user_information(beneficiary_info);
+ return -1;
+ }
+ } else
+ beneficiary_info = NULL;
+
+ if(newnode->userID != 0) {
+ user_info = bfcp_new_user_information(newnode->userID, (char *)bfcp_obtain_user_display_name(list_users, newnode->userID), (char *)bfcp_obtain_userURI(list_users, newnode->userID));
+ if(user_info == NULL) {
+ bfcp_free_user_information(user_info);
+ return -1;
+ }
+ } else
+ user_info = NULL;
+
+ floorID = newnode->floor;
+ if(floorID != NULL) {
+ /* Passing request status as argument and neglect the case of invalid primitive in BFCP message */
+ fRS = bfcp_new_floor_request_status(floorID->floorID, status, 0, floorID->chair_info);
+ }
+ if(fRS == NULL)
+ return -1;
+ floorID = floorID->next;
+ while(floorID != NULL) {
+ /* Passing request status as argument and neglect the case of invalid primitive in BFCP message */
+ fRS_temp = bfcp_new_floor_request_status(floorID->floorID, status, 0, floorID->chair_info);
+ if(fRS_temp != NULL) bfcp_list_floor_request_status(fRS, fRS_temp, NULL);
+ floorID = floorID->next;
+ }
+
+ switch(status) {
+ case BFCP_PENDING:
+ /* Pending request */
+ oRS = bfcp_new_overall_request_status(newnode->floorRequestID, status, newnode->priority, newnode->chair_info);
+ break;
+ case BFCP_ACCEPTED:
+ /* Accepted request */
+ oRS = bfcp_new_overall_request_status(newnode->floorRequestID, status, 0, newnode->chair_info);
+ if(accepted_queue != NULL) {
+ traverse = accepted_queue->tail;
+ i = 1;
+ while(traverse != NULL) {
+ if(traverse->floorRequestID == newnode->floorRequestID) {
+ oRS = bfcp_new_overall_request_status(traverse->floorRequestID, status, i , traverse->chair_info);
+ break;
+ } else
+ i = i + 1;
+ traverse = traverse->prev;
+ }
+ }
+ break;
+ default:
+ oRS = bfcp_new_overall_request_status(newnode->floorRequestID, status, 0, newnode->chair_info);
+ break;
+ }
+
+ arguments->frqInfo = bfcp_new_floor_request_information(newnode->floorRequestID, oRS, fRS, beneficiary_info, user_info, 0,newnode->participant_info);
+ if (list_users->bfcp_transport == BFCP_OVER_UDP) {
+ struct sockaddr_in *client_address = bfcp_get_user_address(list_users, userID);
+ error = send_message_to_client_over_udp(arguments, socket, notify_to_server_app, client_address);
+ } else {
+ error = send_message_to_client(arguments, socket, notify_to_server_app,
+ list_users->bfcp_transport);
+ }
+
+ BFCP_SEND_CHECK_ERRORS(socket);
+
+ return 0;
+}
+
+/* Handle a BFCP message a client sent to the FCS */
+bfcp_message *received_message_from_client(int sockfd, int i, int transport)
+{
+ int error = 0, total = 0;
+ bfcp_message *message = NULL;
+ int in_length;
+
+ /* Reserve enough space for the common header (12 bytes) */
+ unsigned char *common_header = (unsigned char *)calloc(1, 12);
+ if(common_header == NULL)
+ return NULL;
+
+ if(transport == BFCP_OVER_TLS) {
+ if(session[i])
+ error = SSL_read(session[i], common_header, 12);
+ } else /* BFCP_OVER_TCP */
+ error = recv(sockfd, common_header, 12, 0);
+ if(error == 0) {
+ /* The client closed the connection */
+ free(common_header);
+ common_header = NULL;
+ close(sockfd);
+ client[i] = -1;
+#ifdef WIN32
+ FD_CLR(sockfd, &allset);
+#else
+ int j=0;
+ for(j = 0; j < fds_no; j++) {
+ if(pollfds[j].fd == sockfd) {
+ pollfds[j].fd = pollfds[fds_no-1].fd;
+ pollfds[j].events = pollfds[fds_no-1].events;
+ pollfds[j].revents = pollfds[fds_no-1].revents;
+ fds_no--;
+ }
+ }
+/* pollfds[i+1].fd = -1;
+ pollfds[i+1].events = 0;*/
+#endif
+ return NULL;
+ }
+ if(error == -1) {
+ /* There was an error while receiving the message */
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+
+ message = bfcp_new_message(common_header, error);
+ /* Get the message length from the header of the message and multiplying by 4 to get actual payload length, default it is in 4-byte units */
+ in_length = bfcp_get_length(message)*4 + 12;
+ /* Strip the header length, since we already got it: we are interested in the rest, the payload */
+ total = in_length - 12;
+ if(total < 0) {
+ /* The reported length is corrupted */
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+ if(total == 0) {
+ /* The whole message has already been received, there's no payload (e.g. ChairActionAck) */
+ free(common_header);
+ common_header = NULL;
+ return message;
+ }
+
+ /* Reserve enough space for the rest of the message */
+ unsigned char *buffer = (unsigned char *)calloc(1, total);
+ if(buffer == NULL)
+ return NULL;
+
+ int missing = total;
+ int bytes_read = 0;
+ while(1) {
+ if(missing <= 0)
+ break;
+ if(transport == BFCP_OVER_TLS) { /* FIXME */
+ if(session[i])
+ error = SSL_read(session[i], buffer + bytes_read, total);
+ } else /* BFCP_OVER_TCP */
+ error = recv(sockfd, buffer + bytes_read, total, 0);
+ if(error == 0) {
+ /* The FCS closed the connection */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ close(sockfd);
+ return NULL;
+ }
+ if(error == -1) {
+ /* There was an error while receiving the message */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+ missing -= error;
+ bytes_read += error;
+ }
+ if(in_length > BFCP_MAX_ALLOWED_SIZE) {
+ /* The message is bigger than BFCP_MAX_ALLOWED_SIZE (64K), discard it */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+ /* Remove the previously allocated message, which only contained the header */
+ if(message != NULL)
+ bfcp_free_message(message);
+
+ /* Extend the buffer to hold all the message */
+ common_header = (unsigned char *)realloc(common_header, in_length);
+
+ if(memcpy(common_header+12, buffer,total) == NULL) {
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return NULL;
+ }
+
+ /* Create a new BFCP message out of the whole received buffer */
+ message = bfcp_new_message(common_header, in_length);
+
+ /* Free the space reserved for the buffers */
+ free(buffer);
+ buffer = NULL;
+ free(common_header);
+ common_header = NULL;
+ return message;
+}
+
+/* Remove all floor requests made by a user from all existing nodes */
+int bfcp_remove_floorrequest_from_all_nodes(bfcp_conference *server, unsigned short int userID)
+{
+ int error;
+
+ if(server == NULL)
+ return -1;
+
+ error = bfcp_remove_floorrequest_from_a_queue(server->pending, userID);
+ if(error == -1)
+ return -1;
+
+ error = bfcp_remove_floorrequest_from_a_queue(server->accepted, userID);
+ if(error == -1)
+ return -1;
+
+ error = bfcp_remove_floorrequest_from_a_queue(server->granted, userID);
+ if(error == -1)
+ return -1;
+
+ return 0;
+}
+
+ /* Handle a BFCP message a client sent to the FCS (UDP) */
+bfcp_message *received_message_from_client_over_udp(int sockfd)
+{
+ int message_length = 0;
+ bfcp_message *message = NULL;
+
+ /* Reserve enough space for the common header (12 bytes) */
+ unsigned char *message_read = (unsigned char *)calloc(1, BFCP_MAX_ALLOWED_SIZE);
+
+ if (message_read == NULL) {
+ return NULL;
+ }
+
+ memset(&cliaddr, 0, sizeof(cliaddr));
+
+ message_length = recvfrom(sockfd, message_read, BFCP_MAX_ALLOWED_SIZE, 0, ( struct sockaddr *) &cliaddr, &m_addrlen);
+
+ if (message_length == 0 || message_length == -1) {
+ /* Message length was 0 or there was an error while receiving message */
+ free(message_read);
+ message_read = NULL;
+ return NULL;
+ }
+
+ message = bfcp_new_message(message_read, message_length);
+
+ free(message_read);
+ message_read = NULL;
+ return message;
+}
+
+/* Remove all floor requests made by a user from a queue */
+int bfcp_remove_floorrequest_from_a_queue(bfcp_queue *conference, unsigned short int userID)
+{
+ if(conference == NULL)
+ return -1;
+ if(userID <= 0)
+ return -1;
+
+ pnode traverse;
+ int error;
+
+ traverse = conference->head;
+
+ while(traverse) {
+ error = remove_request_from_the_node(traverse, userID);
+ if(error == -1)
+ return -1;
+
+ traverse = traverse->next;
+ }
+
+ return 0;
+}
+
+/* Disable and remove all floor events notifications to an user */
+int bfcp_remove_floorquery_from_all_nodes(bfcp_list_floors *lfloors, unsigned short int userID)
+{
+ if(lfloors == NULL)
+ return 0;
+ if(lfloors->floors == NULL)
+ return 0;
+ if(userID <= 0)
+ return -1;
+
+ int i = 0, error = 0;
+
+ for(i = 0; i < lfloors->actual_number_floors; i++) {
+ error = remove_request_from_the_floor(lfloors->floors+i, userID);
+ if(error == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* A controller to check timeouts when waiting for a ChairAction */
+void *watchdog(void *st_thread)
+{
+ bfcp_mutex_lock(&count_mutex);
+
+ bfcp_thread *thread = (bfcp_thread *)st_thread;
+ bfcp_conference *server;
+ pfloor list_floors;
+ unsigned long int chair_wait_request;
+ unsigned long int floorRequestID;
+ pnode traverse;
+
+ server = thread->conf;
+ floorRequestID = thread->floorRequestID;
+ chair_wait_request = thread->chair_wait_request;
+
+ /* Free the thread */
+ free(thread);
+ thread = NULL;
+
+ bfcp_mutex_unlock(&count_mutex);
+
+#ifndef WIN32
+ sleep(chair_wait_request);
+#else
+ Sleep(chair_wait_request*1000);
+#endif
+
+ /*if the queue is a pending queue*/
+ if((server != NULL) && (server->pending != NULL)) {
+ traverse = server->pending->tail;
+ while(traverse) {
+ if((traverse->floorRequestID) == floorRequestID) {
+ bfcp_print_information_floor(server, 0, 0, traverse, BFCP_CANCELLED);
+ int beneficiary = traverse->beneficiaryID;
+ if(beneficiary == 0)
+ beneficiary = traverse->userID;
+ list_floors = traverse->floor;
+ while(list_floors != NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(WATCHDOG) cancel: floor info is (tot %d) %d\n", server->floor->actual_number_floors, list_floors->floorID);
+ int position_floor = bfcp_return_position_floor(server->floor, list_floors->floorID);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(WATCHDOG) cancel: position_floor=%d\n", position_floor);
+ if(position_floor != -1) {
+ int error = bfcp_deleted_user_request(server->user, beneficiary, position_floor);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(WATCHDOG) -- bfcp_deleted_user_request (user %hu) --> %d\n", beneficiary, error);
+ //~ if(error == -1) {
+ //~ bfcp_mutex_unlock(&count_mutex);
+ //~ return -1;
+ //~ }
+ }
+ list_floors = list_floors->next;
+ }
+
+ }
+ traverse = traverse->prev;
+ }
+ }
+
+ /* If the request is from the Pending list, remove it */
+ list_floors = bfcp_delete_request(server->pending, floorRequestID, 0);
+
+ /* Free all the elements from the floors list */
+ remove_floor_list(list_floors);
+
+ pthread_exit((void *)0);
+ return NULL;
+}
+
+/* Handle an incoming FloorRequest message */
+int bfcp_FloorRequest_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int TransactionID, pnode newnode, int sockfd, int y)
+{
+ if(server == NULL)
+ return -1;
+ if(newnode == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+
+ int actual_conference = 0, i, position_floor, error;
+ unsigned short int chairID;
+ pfloor tempnode, floor;
+ pthread_t wid; /* The thread identifier */
+ struct_thread st_thread;
+ unsigned long int floorRequestID;
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ if(server->list_conferences[i].floorRequestID <= 0)
+ server->list_conferences[i].floorRequestID = 1;
+ floorRequestID = server->list_conferences[i].floorRequestID;
+
+ newnode->floorRequestID = floorRequestID;
+
+ /* A buffer to compose error text messages when needed */
+ char errortext[200];
+
+ /* Check if this conference exists */
+ if(server->list_conferences[i].conferenceID != conferenceID) {
+ sprintf(errortext, "Conference %lu does not exist", conferenceID);
+ bfcp_error_code(conferenceID, newnode->userID, TransactionID, BFCP_CONFERENCE_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if this user exists */
+ if(bfcp_existence_user(server->list_conferences[i].user, newnode->userID) != 0) {
+ sprintf(errortext, "User %hu does not exist in Conference %lu", newnode->userID, conferenceID);
+ bfcp_error_code(conferenceID, newnode->userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* If this FloorRequest has a beneficiaryID, check if the user is allowed to do this operation */
+ if((newnode->beneficiaryID != 0) && (bfcp_exist_user_as_a_chair(server->list_conferences[i].floor, newnode->userID) != 0)) {
+ sprintf(errortext, "Third-party FloorRequests only allowed for chairs (User %hu is not chair of any floor)", newnode->userID);
+ bfcp_error_code(conferenceID, newnode->userID, TransactionID, BFCP_UNAUTHORIZED_OPERATION, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Checks if the beneficiary user exists in the conference */
+ if((newnode->beneficiaryID != 0) && (bfcp_existence_user(server->list_conferences[i].user, newnode->beneficiaryID) != 0)) {
+ sprintf(errortext, "User %hu (beneficiary of the request) does not exist in Conference %lu", newnode->beneficiaryID, conferenceID);
+ bfcp_error_code(conferenceID, newnode->userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if all the floors exist in the conference, otherwise send an error */
+ if((newnode->floor) != NULL) {
+ for(tempnode = newnode->floor; tempnode; tempnode = tempnode->next) {
+ position_floor = bfcp_return_position_floor(server->list_conferences[i].floor, tempnode->floorID);
+ if(position_floor == -1) {
+ sprintf(errortext, "Floor %hu does not exist in Conference %lu", tempnode->floorID, conferenceID);
+ bfcp_error_code(conferenceID, newnode->userID, TransactionID, BFCP_INVALID_FLOORID, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* If no chair is present and the policy is to autodeny requests, remove the request node */
+ if((server->list_conferences[i].automatic_accepted_deny_policy == 1) && (bfcp_return_chair_floor(server->list_conferences[i].floor, tempnode->floorID) == 0)) {
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, server->list_conferences[i].conferenceID, newnode->userID, TransactionID, newnode, BFCP_DENIED, sockfd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Remove the request node */
+ remove_floor_list(newnode->floor);
+ remove_request_list_of_node(newnode->floorrequest);
+ free(newnode->participant_info);
+ newnode->participant_info = NULL;
+ free(newnode->chair_info);
+ newnode->chair_info = NULL;
+ free(newnode);
+ newnode = NULL;
+ bfcp_mutex_unlock(&count_mutex);
+ return 0;
+ }
+
+ /* Check if this user has already reached the maximum number of ongoing requests for the same floor */
+ if(bfcp_is_floor_request_full(conferenceID, TransactionID, server->list_conferences[i].user, newnode->beneficiaryID ? newnode->beneficiaryID : newnode->userID, position_floor, sockfd, y) == -1) {
+ /* Remove the request node */
+ remove_floor_list(newnode->floor);
+ remove_request_list_of_node(newnode->floorrequest);
+ free(newnode->participant_info);
+ newnode->participant_info = NULL;
+ free(newnode->chair_info);
+ newnode->chair_info = NULL;
+ free(newnode);
+ newnode = NULL;
+ bfcp_mutex_unlock(&count_mutex);
+ return 0;
+ }
+ }
+ } else {
+ sprintf(errortext, "There are no floors in Conference %lu", conferenceID);
+ bfcp_error_code(conferenceID, newnode->userID, TransactionID, BFCP_INVALID_FLOORID, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Checks in which position each floor is, and add the request to the user's list */
+ position_floor = 0;
+ for(tempnode = newnode->floor; tempnode; tempnode = tempnode->next) {
+ position_floor = bfcp_return_position_floor(server->list_conferences[i].floor, tempnode->floorID);
+ if(position_floor != -1) {
+ /* If the floor(s) is/are for a beneficiary, add the request to the beneficiary's list */
+ if(newnode->beneficiaryID != 0)
+ error = bfcp_add_user_request(conferenceID, TransactionID, server->list_conferences[i].user, newnode->beneficiaryID, position_floor, sockfd, y);
+ else
+ error = bfcp_add_user_request(conferenceID, TransactionID, server->list_conferences[i].user, newnode->userID, position_floor, sockfd, y);
+ if(error == -1) {
+ /* Remove the node */
+ remove_floor_list(newnode->floor);
+ remove_request_list_of_node(newnode->floorrequest);
+ free(newnode->participant_info);
+ newnode->participant_info = NULL;
+ free(newnode->chair_info);
+ newnode->chair_info = NULL;
+ free(newnode);
+ newnode = NULL;
+ bfcp_mutex_unlock(&count_mutex);
+ return 0;
+ }
+ } else {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ /* Handle the Chair part */
+
+ /* For each floor in the request, accept/deny it or ask for the chair's approval */
+ if((newnode->floor) != NULL) {
+ for(tempnode = newnode->floor; tempnode; tempnode = tempnode->next) {
+ /*checks if this floor has a chair*/
+ chairID= bfcp_return_chair_floor(server->list_conferences[i].floor, tempnode->floorID);
+ /*if it has a chair*/
+ if(chairID != 0) {
+ /* Allocate a new thread handler */
+ st_thread = (struct_thread)calloc(1, sizeof(bfcp_thread));
+ if(st_thread == NULL) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Initialize the structure the thread will handle */
+ st_thread->conf = server->list_conferences + i;
+ st_thread->chair_wait_request = server->list_conferences[i].chair_wait_request;
+ st_thread->floorRequestID = floorRequestID;
+
+ /* Create the thread */
+ if( pthread_create(&wid, NULL, watchdog, st_thread) < 0) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ pthread_detach(wid);
+
+ /*put the pID in the node*/
+ tempnode->pID = wid;
+ } else
+ /* Change status of the floor to Accepted */
+ tempnode->status = 1;
+ }
+ }
+
+ /* Check if the floors are FREE (TODO check state) */
+ floor = newnode->floor;
+ while(floor != NULL) {
+ if(floor->status == 1)
+ floor = floor->next;
+ else
+ break;
+ }
+
+ if(floor == NULL) {
+ /*put the node in the accept list*/
+ /*change the priority of the node to the lowest one*/
+ newnode->priority = 0;
+
+ /* Remove the threads handling this node */
+ floor = newnode->floor;
+ while(floor) {
+#ifndef WIN32
+ if(floor->pID != 0) {
+#else
+ if(floor->pID.p != NULL) {
+#endif
+ pthread_cancel(floor->pID);
+#ifndef WIN32
+ floor->pID = 0;
+#else
+ floor->pID.p = NULL;
+#endif
+ }
+ floor = floor->next;
+ }
+
+ error = bfcp_insert_request(server->list_conferences[i].accepted, newnode, floorRequestID, NULL);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Prepare all floor information needed by interested users */
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, newnode, BFCP_ACCEPTED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Notify the requester about all the most important information about his request */
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, server->list_conferences[i].conferenceID, newnode->userID, TransactionID, newnode, BFCP_ACCEPTED, sockfd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if the node should be moved to the Granted queue */
+ if(server->list_conferences[i].floor != NULL) {
+ if(server->list_conferences[i].floor->floors != NULL) {
+ for (y = (server->list_conferences[i].floor->actual_number_floors-1); 0 <= y; y--) {
+ if(bfcp_return_state_floor(server->list_conferences[i].floor, server->list_conferences[i].floor->floors[y].floorID)list_conferences[i].floor, server->list_conferences[i].floor->floors[y].floorID)) {
+ if(check_accepted_node(server->list_conferences+i, newnode, server->list_conferences[i].floor->floors[y].floorID, NULL) == 0) {
+ /* Notify the requester about all the most important information about his request */
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, server->list_conferences[i].conferenceID, newnode->userID, TransactionID, newnode, BFCP_GRANTED, sockfd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ /*put the node in the pending list*/
+ error = bfcp_insert_request(server->list_conferences[i].pending, newnode, floorRequestID, NULL);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Prepare all floor information needed by interested users */
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, newnode, BFCP_PENDING);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Notify the requester about all the most important information about his request */
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, server->list_conferences[i].conferenceID, newnode->userID, TransactionID, newnode, BFCP_PENDING, sockfd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ server->list_conferences[i].floorRequestID = server->list_conferences[i].floorRequestID + 1;
+
+ /* The requester will constantly be notified about updates concerning his request */
+ error = add_request_to_the_node(newnode, newnode->userID, sockfd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Handle an incoming FloorRelease message */
+/*RequestStatus ->Cancelled if the floor had not been previous granted- Released if the floor had been previous granted*/
+int bfcp_FloorRelease_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int TransactionID, unsigned short int userID, unsigned long int floorRequestID, int sockfd, int y)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+
+ int i, position_floor, actual_conference = 0, error, status_floor = 0;
+ pfloor temp, list_floors = NULL, floor;
+ pnode newnode = NULL;
+ bfcp_queue *laccepted;
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ /* A buffer to compose error text messages when needed */
+ char errortext[200];
+
+ /* Check if this conference exists */
+ if(server->list_conferences[i].conferenceID != conferenceID) {
+ sprintf(errortext, "Conference %lu does not exist", conferenceID);
+ bfcp_error_code(conferenceID, newnode->userID, TransactionID, BFCP_CONFERENCE_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if this user exists */
+ if(bfcp_existence_user(server->list_conferences[i].user, userID) != 0) {
+ sprintf(errortext, "User %hu does not exist in Conference %lu", userID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* If floorRequestID is 0 then fetching floorRequestID from accepeted/pending/granted
+ floor list mapped with userID, if not found then generating error */
+ if (floorRequestID <= 0 &&
+ !(floorRequestID = bfcp_get_floor_requestid(server->list_conferences[i].accepted, userID)) &&
+ !(floorRequestID = bfcp_get_floor_requestid(server->list_conferences[i].pending, userID)) &&
+ !(floorRequestID = bfcp_get_floor_requestid(server->list_conferences[i].granted, userID))) {
+ sprintf(errortext, "FloorRequest for user %hu does not exist in Conference %lu", userID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_FLOORREQUEST_DOES_NOT_EXIST, errortext,
+ NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if this request node is in the Accepted list */
+ if(bfcp_give_user_of_request(server->list_conferences[i].accepted, floorRequestID) == userID) {
+ newnode = bfcp_extract_request(server->list_conferences[i].accepted, floorRequestID);
+ status_floor = BFCP_FLOOR_STATE_ACCEPTED;
+ }
+
+ if(newnode == NULL) {
+ /* First check if the request node is in the Pending list */
+ if(bfcp_give_user_of_request(server->list_conferences[i].pending, floorRequestID) == userID) {
+ bfcp_kill_threads_request_with_FloorRequestID(server->list_conferences[i].pending, floorRequestID);
+ newnode = bfcp_extract_request(server->list_conferences[i].pending, floorRequestID);
+ status_floor = BFCP_FLOOR_STATE_ACCEPTED;
+ }
+ if(newnode == NULL) {
+ /* Then check if the request node is in the Granted list */
+ if(bfcp_give_user_of_request(server->list_conferences[i].granted, floorRequestID) == userID) {
+ newnode = bfcp_extract_request(server->list_conferences[i].granted, floorRequestID);
+ status_floor = BFCP_FLOOR_STATE_GRANTED;
+ }
+ if(newnode == NULL) {
+ sprintf(errortext, "FloorRequest %lu does not exist in Conference %lu", floorRequestID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_FLOORREQUEST_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ /* Remove the thread if this request node is in the Pending list */
+ floor = newnode->floor;
+ while(floor) {
+#ifndef WIN32
+ if(floor->pID != 0) {
+#else
+ if(floor->pID.p != NULL) {
+#endif
+ pthread_cancel(floor->pID);
+#ifndef WIN32
+ floor->pID = 0;
+#else
+ floor->pID.p = NULL;
+#endif
+ }
+ floor = floor->next;
+ }
+ }
+ }
+
+ /* Notify the releaser about the floor request information of the released request */
+ if(status_floor == BFCP_FLOOR_STATE_ACCEPTED)
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, server->list_conferences[i].conferenceID, userID, TransactionID, newnode, BFCP_CANCELLED, sockfd);
+ else
+ error = bfcp_show_requestfloor_information(server->list_conferences[i].user, server->list_conferences[i].accepted, server->list_conferences[i].conferenceID, userID, TransactionID, newnode, BFCP_RELEASED, sockfd);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ error = remove_request_from_the_node(newnode, userID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Prepare all floor information needed by interested users */
+
+ if(status_floor == BFCP_FLOOR_STATE_ACCEPTED)
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, newnode, BFCP_CANCELLED);
+ else
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, newnode, BFCP_RELEASED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ list_floors = newnode->floor;
+
+ /* Remove the list of requests */
+ remove_request_list_of_node(newnode->floorrequest);
+
+ free(newnode->participant_info);
+ newnode->participant_info = NULL;
+ free(newnode->chair_info);
+ newnode->chair_info = NULL;
+ free(newnode);
+ newnode = NULL;
+
+ while(list_floors != NULL) {
+ position_floor = bfcp_return_position_floor(server->list_conferences[i].floor, list_floors->floorID);
+
+ if(position_floor != -1) {
+ if((bfcp_return_state_floor(server->list_conferences[i].floor, server->list_conferences[i].floor->floors[position_floor].floorID) >= 2) && (list_floors->status == 2))
+ /* Change state of the floor to available (FREE) */
+ bfcp_change_state_floor(server->list_conferences[i].floor, list_floors->floorID, 1);
+
+ error = bfcp_deleted_user_request(server->list_conferences[i].user, userID, position_floor);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ /* Check if other requests that need this floor are in the Accepted list */
+ laccepted = server->list_conferences[i].accepted;
+
+ if(give_free_floors_to_the_accepted_nodes(server->list_conferences+i, laccepted, server->list_conferences[i].floor, NULL) == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Destroy the floors list */
+ temp = list_floors;
+ list_floors = list_floors->next;
+ free(temp->chair_info);
+ temp->chair_info = NULL;
+ free(temp);
+ temp = NULL;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Handle an incoming ChairAction message */
+int bfcp_ChairAction_server(bfcp_server *server, unsigned long int conferenceID, bfcp_floor *list_floors, unsigned short int userID, unsigned long int floorRequestID, int RequestStatus, char *chair_info, int queue_position, unsigned short int TransactionID, int sockfd, int y)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+ if(list_floors == NULL)
+ return -1;
+ if(userID <= 0)
+ return -1;
+ if(floorRequestID <= 0)
+ return -1;
+ if((RequestStatus != BFCP_ACCEPTED) && (RequestStatus != BFCP_DENIED) && (RequestStatus != BFCP_REVOKED))
+ return -1;
+ if(queue_position < 0)
+ return -1;
+ if(TransactionID <= 0)
+ return -1;
+
+ int actual_conference = 0, i, error, position_floor;
+ pfloor floor, next, next_floors, tempnode, free_floors, tempfloors = NULL;
+ bfcp_node *newnode = NULL;
+ bfcp_floor *node = NULL;
+ bfcp_queue *laccepted;
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message = NULL;
+ int dLen;
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ /* A buffer to compose error text messages when needed */
+ char errortext[200];
+
+ /* Check if this conference exists */
+ if(server->list_conferences[i].conferenceID != conferenceID) {
+ sprintf(errortext, "Conference %lu does not exist", conferenceID);
+ bfcp_error_code(conferenceID, newnode->userID, TransactionID, BFCP_CONFERENCE_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if this user exists */
+ if(bfcp_existence_user(server->list_conferences[i].user, userID) != 0) {
+ sprintf(errortext, "User %hu does not exist in Conference %lu", userID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if all the floors exist in the conference, otherwise send an error */
+ for(tempnode = list_floors; tempnode; tempnode = tempnode->next) {
+ position_floor = bfcp_return_position_floor(server->list_conferences[i].floor, tempnode->floorID);
+ if(position_floor == -1) {
+ sprintf(errortext, "Floor %hu does not exist in Conference %lu", tempnode->floorID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_INVALID_FLOORID, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if the user is allowed to do this operation */
+ if(bfcp_return_chair_floor(server->list_conferences[i].floor, tempnode->floorID) != userID) {
+ sprintf(errortext, "User %hu is not chair of Floor %hu in Conference %lu", userID, tempnode->floorID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_UNAUTHORIZED_OPERATION, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ if(RequestStatus == BFCP_ACCEPTED) {
+ /* The chair accepted a request */
+
+ /* First check if the request node is in the Pending list */
+ if(bfcp_give_user_of_request(server->list_conferences[i].pending, floorRequestID) == 0) {
+ sprintf(errortext, "Pending FloorRequest %lu does not exist in Conference %lu", floorRequestID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_FLOORREQUEST_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ /* Check if the floors involved in the accepted request exist */
+ for(tempnode = list_floors; tempnode != NULL; tempnode = tempnode->next) {
+ if(bfcp_change_status(server->list_conferences[i].pending, tempnode->floorID, floorRequestID, BFCP_FLOOR_STATE_ACCEPTED, tempnode->chair_info) != 0) {
+ sprintf(errortext, "Floor %hu does not exist in Conference %lu", tempnode->floorID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_INVALID_FLOORID, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ /* Set the queue_position value if it is needed */
+ bfcp_change_queue_position(server->list_conferences[i].pending, floorRequestID, queue_position);
+
+ /* If all the floors in the request have been accepted... */
+ if(bfcp_all_floor_status(server->list_conferences[i].pending, floorRequestID, BFCP_FLOOR_STATE_ACCEPTED) == 0) {
+ /* Extract the request node from the Pending list */
+ newnode = bfcp_extract_request(server->list_conferences[i].pending, floorRequestID);
+
+ /* Remove the threads handling this node */
+ floor = newnode->floor;
+ while(floor) {
+#ifndef WIN32
+ if(floor->pID != 0) {
+#else
+ if(floor->pID.p != NULL) {
+#endif
+ pthread_cancel(floor->pID);
+#ifndef WIN32
+ floor->pID = 0;
+#else
+ floor->pID.p = NULL;
+#endif
+ }
+ floor = floor->next;
+ }
+
+ /* Move the node to the Accepted list */
+
+ newnode->priority = BFCP_LOWEST_PRIORITY;
+
+ error = bfcp_insert_request(server->list_conferences[i].accepted, newnode, floorRequestID, chair_info);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Prepare all floor information needed by interested users */
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, newnode, BFCP_ACCEPTED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if the node should be in the Granted queue */
+ laccepted = server->list_conferences[i].accepted;
+ if(give_free_floors_to_the_accepted_nodes(server->list_conferences+i, laccepted, server->list_conferences[i].floor, chair_info) == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ } else if(RequestStatus == BFCP_DENIED) {
+ /* The chair denied a pending request */
+
+ /* Extract the request node from the Pending list */
+ newnode = bfcp_extract_request(server->list_conferences[i].pending, floorRequestID);
+ if(newnode == NULL) {
+ newnode = bfcp_extract_request(server->list_conferences[i].accepted, floorRequestID);
+ if(newnode == NULL) {
+ sprintf(errortext, "FloorRequest %lu does not exist in Conference %lu, neither Pending or Accepted", floorRequestID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_FLOORREQUEST_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ unsigned short int beneficiary = newnode->beneficiaryID;
+ if(beneficiary == 0)
+ beneficiary = newnode->floorrequest->userID;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Denying floor to beneficiary %hu\n", beneficiary);
+
+ /* If there's chair-provided text information, add it to the request node */
+ if(chair_info != NULL) {
+ dLen = strlen(chair_info);
+ if(dLen != 0) {
+ if(newnode->chair_info != NULL) {
+ free(newnode->chair_info);
+ newnode->chair_info = NULL;
+ }
+ newnode->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ memcpy(newnode->chair_info, chair_info, dLen+1);
+ }
+ }
+
+ /* Remove the threads handling this node */
+ floor = newnode->floor;
+ while(floor != NULL) {
+#ifndef WIN32
+ if(floor->pID != 0) {
+#else
+ if(floor->pID.p != NULL) {
+#endif
+ pthread_cancel(floor->pID);
+#ifndef WIN32
+ floor->pID = 0;
+#else
+ floor->pID.p = NULL;
+#endif
+ }
+ floor = floor->next;
+ }
+
+ /* Add the chair-provided information to each floor */
+ for(tempnode = list_floors; tempnode != NULL; tempnode = tempnode->next) {
+ for(node = newnode->floor; node != NULL; node = node->next) {
+ if(node->floorID == tempnode->floorID) {
+ /* If there's chair-provided text for this floor, add it */
+ if(tempnode->chair_info != NULL) {
+ dLen = strlen(tempnode->chair_info);
+ if(dLen != 0) {
+ if(node->chair_info != NULL) {
+ free(node->chair_info);
+ node->chair_info = NULL;
+ }
+ node->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ memcpy(node->chair_info, tempnode->chair_info, dLen+1);
+ }
+ } else
+ node->chair_info = NULL;
+ }
+ }
+ }
+ /* Prepare all floor information needed by interested users */
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, newnode, BFCP_DENIED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Decrease requests counter */
+ free_floors = newnode->floor;
+ while(free_floors != NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "deny: floor info is (tot %d) %d\n", server->list_conferences[i].floor->actual_number_floors, free_floors->floorID);
+ int position_floor = bfcp_return_position_floor(server->list_conferences[i].floor, free_floors->floorID);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "deny: position_floor=%d\n", position_floor);
+ if(position_floor != -1) {
+ error = bfcp_deleted_user_request(server->list_conferences[i].user, beneficiary, position_floor);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " -- bfcp_deleted_user_request (user %hu) --> %d\n", beneficiary, error);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ free_floors = free_floors->next;
+ }
+
+ /* Remove the request node from the Pending list */
+ if(newnode != NULL) {
+ tempfloors = newnode->floor;
+ remove_floor_list(newnode->floor);
+ remove_request_list_of_node(newnode->floorrequest);
+ free(newnode->participant_info);
+ newnode->participant_info = NULL;
+ free(newnode->chair_info);
+ newnode->chair_info = NULL;
+ free(newnode);
+ newnode = NULL;
+ }
+
+ } else if(RequestStatus == BFCP_REVOKED) {
+ /* The chair revoked a previously granted request */
+
+ /* Extract the request node from the Granted list */
+ newnode = bfcp_extract_request(server->list_conferences[i].granted, floorRequestID);
+ if(newnode == NULL) {
+ sprintf(errortext, "Granted FloorRequest %lu does not exist in Conference %lu", floorRequestID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_FLOORREQUEST_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ unsigned short int beneficiary = newnode->beneficiaryID;
+ if(beneficiary == 0)
+ beneficiary = newnode->floorrequest->userID;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Revoking floor to beneficiary %hu\n", beneficiary);
+
+ /* If there's chair-provided text information, add it to the request node */
+ if(chair_info != NULL) {
+ dLen = strlen(chair_info);
+ if(dLen != 0) {
+ if(newnode->chair_info != NULL)
+ free(newnode->chair_info);
+ newnode->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ memcpy(newnode->chair_info, chair_info, dLen+1);
+ }
+ }
+
+ /* Add the chair-provided information to each floor */
+ for(tempnode = list_floors; tempnode != NULL; tempnode = tempnode->next) {
+ for(node = newnode->floor; node != NULL; node = node->next) {
+ if(node->floorID == tempnode->floorID) {
+ /* If there's chair-provided text for this floor, add it */
+ if(tempnode->chair_info != NULL) {
+ dLen = strlen(tempnode->chair_info);
+ if(dLen != 0) {
+ if(node->chair_info != NULL) {
+ free(node->chair_info);
+ node->chair_info = NULL;
+ }
+ node->chair_info = (char *)calloc(1, dLen*sizeof(char)+1);
+ memcpy(node->chair_info, tempnode->chair_info, dLen+1);
+ }
+ } else
+ node->chair_info = NULL;
+ }
+ }
+ }
+
+ /* Prepare all floor information needed by interested users */
+ error = bfcp_print_information_floor(server->list_conferences+i, 0, 0, newnode, BFCP_REVOKED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Remove the request node from the Granted list */
+ if(newnode != NULL) {
+ tempfloors = newnode->floor;
+ remove_request_list_of_node(newnode->floorrequest);
+ free(newnode->participant_info);
+ newnode->participant_info = NULL;
+ free(newnode->chair_info);
+ newnode->chair_info = NULL;
+ free(newnode);
+ newnode = NULL;
+ }
+
+ /* Set the state of the floors to FREE */
+ free_floors = tempfloors;
+ while(free_floors != NULL) {
+ int position_floor = bfcp_return_position_floor(server->list_conferences[i].floor, free_floors->floorID);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "revoke: position_floor=%d\n", position_floor);
+ if(position_floor != -1) {
+ error = bfcp_change_state_floor(server->list_conferences[i].floor, free_floors->floorID, 1);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " -- bfcp_change_state_floor --> %d\n", error);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ error = bfcp_deleted_user_request(server->list_conferences[i].user, beneficiary, position_floor);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " -- bfcp_deleted_user_request (user %hu) --> %d\n", beneficiary, error);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ next = free_floors->next;
+ free(free_floors->chair_info);
+ free_floors->chair_info = NULL;
+ free(free_floors);
+ free_floors = NULL;
+ free_floors = next;
+ }
+
+ laccepted = server->list_conferences[i].accepted;
+ if(give_free_floors_to_the_accepted_nodes(server->list_conferences+i, laccepted, server->list_conferences[i].floor, chair_info) == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Free the floors list */
+ while(list_floors) {
+ next_floors = list_floors->next;
+ free(list_floors->chair_info);
+ list_floors->chair_info = NULL;
+ free(list_floors);
+ list_floors = NULL;
+ list_floors = next_floors;
+ }
+
+ /* Send the ChairActionAck to the client */
+ arguments = bfcp_new_arguments();
+ if(!arguments) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ arguments->entity = bfcp_new_entity(conferenceID,TransactionID,userID);
+ arguments->primitive = ChairActionAck;
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ if (server->bfcp_transport == BFCP_OVER_UDP) {
+ struct sockaddr_in *client_address = bfcp_get_user_address_server(server, conferenceID, userID);
+ error = send_message_to_client_over_udp(arguments, sockfd, notify_to_server_app, client_address);
+ } else {
+ error = send_message_to_client(arguments, sockfd, notify_to_server_app, server->bfcp_transport);
+ }
+
+ BFCP_SEND_CHECK_ERRORS(sockfd);
+
+ return 0;
+}
+
+/* Handle an incoming Hello message */
+int bfcp_hello_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int userID, unsigned short int TransactionID, int sockfd, int y)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+ if(userID <= 0)
+ return -1;
+ if(TransactionID <= 0)
+ return -1;
+
+ int actual_conference = 0, i, error;
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message = NULL;
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ /* A buffer to compose error text messages when needed */
+ char errortext[200];
+
+ /* Check if this conference exists */
+ if(server->list_conferences[i].conferenceID != conferenceID) {
+ sprintf(errortext, "Conference %lu does not exist", conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_CONFERENCE_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if this user exists */
+ if(bfcp_existence_user(server->list_conferences[i].user, userID) != 0) {
+ sprintf(errortext, "User %hu does not exist in Conference %lu", userID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Set sockfd with userID in user list */
+ if (bfcp_set_user_sockfd(server->list_conferences[i].user, userID, sockfd) != 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to set socket file descriptor in the user list!\n");
+ }
+
+ arguments = bfcp_new_arguments();
+ if(!arguments) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ arguments->entity = bfcp_new_entity(conferenceID,TransactionID,userID);
+ arguments->primitive = HelloAck;
+
+ /* Create a list of all the primitives the FCS supports */
+ arguments->primitives= bfcp_new_supported_list(FloorRequest,
+ FloorRelease,
+ FloorRequestQuery,
+ FloorRequestStatus,
+ UserQuery,
+ UserStatus,
+ FloorQuery,
+ FloorStatus,
+ ChairAction,
+ ChairActionAck,
+ Hello,
+ HelloAck,
+ Error, 0);
+ /* Create a list of all the attributes the FCS supports */
+ arguments->attributes= bfcp_new_supported_list(BENEFICIARY_ID,
+ FLOOR_ID,
+ FLOOR_REQUEST_ID,
+ PRIORITY,
+ REQUEST_STATUS,
+ ERROR_CODE,
+ ERROR_INFO,
+ PARTICIPANT_PROVIDED_INFO,
+ STATUS_INFO,
+ SUPPORTED_ATTRIBUTES,
+ SUPPORTED_PRIMITIVES,
+ USER_DISPLAY_NAME,
+ USER_URI,
+ BENEFICIARY_INFORMATION,
+ FLOOR_REQUEST_INFORMATION,
+ REQUESTED_BY_INFORMATION,
+ FLOOR_REQUEST_STATUS,
+ OVERALL_REQUEST_STATUS,
+ NONCE,
+ DIGEST, 0);
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ if (server->bfcp_transport == BFCP_OVER_UDP) {
+ struct sockaddr_in *client_address = bfcp_get_user_address_server(server, conferenceID, userID);
+ error = send_message_to_client_over_udp(arguments, sockfd, notify_to_server_app, client_address);
+ } else {
+ error = send_message_to_client(arguments, sockfd, notify_to_server_app, server->bfcp_transport);
+ }
+
+ BFCP_SEND_CHECK_ERRORS(sockfd);
+
+ return 0;
+}
+
+/* Handle an incoming UserQuery message */
+int bfcp_userquery_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int userID, unsigned short int TransactionID, unsigned short int beneficiaryID, int sockfd, int y)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+ if(userID <= 0)
+ return -1;
+
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message = NULL;
+ bfcp_user_information *beneficiary_info;
+ int error, actual_conference = 0, i, j;
+ bfcp_floor_request_information *frqInfo = NULL, *list_frqInfo = NULL;
+ pnode traverse;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ /* A buffer to compose error text messages when needed */
+ char errortext[200];
+
+ /* Check if this conference exists */
+ if(server->list_conferences[i].conferenceID != conferenceID) {
+ sprintf(errortext, "Conference %lu does not exist", conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_CONFERENCE_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if this user exists */
+ if(bfcp_existence_user(server->list_conferences[i].user, userID) != 0) {
+ sprintf(errortext, "User %hu does not exist in Conference %lu", userID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ if(beneficiaryID != 0) {
+ /* The user requested information about another user, the Beneficiary: */
+ /* check if this beneficiary exists in the conference */
+ if(bfcp_existence_user(server->list_conferences[i].user, beneficiaryID) != 0) {
+ sprintf(errortext, "User %hu (beneficiary of the query) does not exist in Conference %lu", beneficiaryID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ /* Prepare an UserStatus message */
+ arguments = bfcp_new_arguments();
+ if(!arguments) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ arguments->entity = bfcp_new_entity(conferenceID,TransactionID,userID);
+ arguments->primitive = UserStatus;
+
+ /* Add the Beneficiary information, if needed */
+ if(beneficiaryID != 0) {
+ beneficiary_info = bfcp_show_user_information(server->list_conferences[i].user, beneficiaryID);
+ if(beneficiary_info == NULL) {
+ bfcp_free_user_information(beneficiary_info);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ userID= beneficiaryID;
+ } else
+ beneficiary_info = NULL;
+
+ arguments->beneficiary = beneficiary_info;
+
+ /*if the queue is a granted queue*/
+ if(server->list_conferences[i].granted != NULL) {
+ traverse = server->list_conferences[i].granted->tail;
+ while(traverse) {
+ if((traverse->userID == userID) || (traverse->beneficiaryID == userID)) {
+ frqInfo = create_floor_request_userID(traverse,server->list_conferences[i].user, userID, 3, 0);
+ if((frqInfo != NULL) && (list_frqInfo != NULL))
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else if(list_frqInfo == NULL)
+ list_frqInfo = frqInfo;
+ }
+ traverse = traverse->prev;
+ }
+ }
+
+ /* Accepted queue */
+ if(server->list_conferences[i].accepted != NULL) {
+ traverse = server->list_conferences[i].accepted->tail;
+ j = 1;
+ while(traverse) {
+ if((traverse->userID == userID) || (traverse->beneficiaryID == userID)) {
+ frqInfo = create_floor_request_userID(traverse,server->list_conferences[i].user, userID, 2, j);
+ if((frqInfo != NULL) && (list_frqInfo != NULL))
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else if(list_frqInfo == NULL)
+ list_frqInfo = frqInfo;
+ }
+ j = j + 1;
+ traverse = traverse->prev;
+ }
+ }
+
+ /* Pending queue */
+ if(server->list_conferences[i].pending != NULL) {
+ traverse = server->list_conferences[i].pending->tail;
+ while(traverse) {
+ if((traverse->userID == userID) || (traverse->beneficiaryID == userID)) {
+ frqInfo = create_floor_request_userID(traverse,server->list_conferences[i].user, userID, 1, 0);
+ if((frqInfo != NULL) && (list_frqInfo != NULL))
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else if(list_frqInfo == NULL)
+ list_frqInfo = frqInfo;
+ }
+ traverse = traverse->prev;
+ }
+ }
+
+ arguments->frqInfo = list_frqInfo;
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ if (server->bfcp_transport == BFCP_OVER_UDP) {
+ struct sockaddr_in *client_address = bfcp_get_user_address_server(server, conferenceID, userID);
+ error = send_message_to_client_over_udp(arguments, sockfd, notify_to_server_app, client_address);
+ } else {
+ error = send_message_to_client(arguments, sockfd, notify_to_server_app, server->bfcp_transport);
+ }
+
+ BFCP_SEND_CHECK_ERRORS(sockfd);
+
+ return 0;
+}
+
+/* Handle an incoming FloorQuery message */
+int bfcp_floorquery_server(bfcp_server *server, unsigned long int conferenceID, bfcp_floor *list_floors, unsigned short int userID, unsigned short int TransactionID, int sockfd, int y)
+{
+ if(server == NULL)
+ return -1;
+ if(server->list_conferences == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+ if(TransactionID <= 0)
+ return -1;
+
+ int error, i, actual_conference, position;
+ bfcp_floor *next_floors, *tempnode;
+ floor_query *query;
+ int position_floor;
+
+ bfcp_mutex_lock(&count_mutex);
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ /* A buffer to compose error text messages when needed */
+ char errortext[200];
+
+ /* Check if this conference exists */
+ if(server->list_conferences[i].conferenceID == conferenceID) {
+ /* Check if the user exists */
+ if(bfcp_existence_user(server->list_conferences[i].user, userID) != 0) {
+ sprintf(errortext, "User %hu does not exist in Conference %lu", userID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ if (server->bfcp_transport == BFCP_OVER_UDP) {
+ /* Fetching address of client so we can send FloorStatus message and that address */
+ struct sockaddr_in *client_addr = bfcp_get_user_address(server->list_conferences[i].user, userID);
+ error = bfcp_floor_query_server_over_udp(server->list_conferences[i].floor,
+ list_floors, userID, client_addr, sockfd);
+ } else {
+ error = bfcp_floor_query_server(server->list_conferences[i].floor, list_floors,
+ userID, sockfd);
+ }
+
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ } else {
+ sprintf(errortext, "Conference %lu does not exist", conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_CONFERENCE_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if all the floors exist in the conference, otherwise send an error */
+ if(list_floors != NULL) {
+ for(tempnode = list_floors; tempnode; tempnode = tempnode->next) {
+ position_floor = bfcp_return_position_floor(server->list_conferences[i].floor, tempnode->floorID);
+ if(position_floor == -1) {
+ sprintf(errortext, "Floor %hu does not exist in Conference %lu", tempnode->floorID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_INVALID_FLOORID, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ }
+
+ if(list_floors == NULL) {
+ /* Remove the user from the list of FloorQueries */
+ error = bfcp_remove_floorquery_from_all_nodes(server->list_conferences[i].floor, userID);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ error = bfcp_show_floor_information(conferenceID, TransactionID, userID, server->list_conferences+i, 0, sockfd, allset, client, NULL, 0);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+
+ while(list_floors) {
+ position = bfcp_return_position_floor(server->list_conferences[i].floor, list_floors->floorID);
+ if(position >= 0) {
+ if(server->list_conferences[i].floor->floors != NULL) {
+ query = server->list_conferences[i].floor->floors[position].floorquery;
+ while(query != NULL) {
+ if(query->userID == userID) {
+ error = bfcp_show_floor_information(conferenceID, TransactionID, query->userID, server->list_conferences+i, list_floors->floorID, query->fd, allset, client, NULL, 0);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ }
+ query = query->next;
+ }
+ }
+ }
+
+ /* Remove the floor from the list */
+ next_floors = list_floors->next;
+ free(list_floors->chair_info);
+ list_floors->chair_info = NULL;
+ free(list_floors);
+ list_floors = NULL;
+ list_floors = next_floors;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+
+ return 0;
+}
+
+/* Handle an incoming FloorQuery message for UDP and also set client
+ address in query list corrosponding to userID */
+int bfcp_floor_query_server_over_udp(bfcp_list_floors *lfloors,
+ bfcp_floor *list_floors,
+ unsigned short int userID,
+ struct sockaddr_in *client_addr,
+ int sockfd)
+{
+ if (lfloors == NULL)
+ return 0;
+ if (userID <= 0)
+ return -1;
+
+ floor_query *query = NULL;
+ floor_query *query_temp = NULL;
+ floor_query *newnode = NULL;
+ int i = 0, exist_user;
+
+ i = lfloors->actual_number_floors-1;
+ while (i >= 0) {
+ if ((list_floors == NULL) || (lfloors->floors[i].floorID != list_floors->floorID)) {
+ query = lfloors->floors[i].floorquery;
+ if (query) {
+ if (query->userID == userID) {
+ lfloors->floors[i].floorquery = query->next;
+ query->next = NULL;
+ free(query);
+ query = NULL;
+ } else {
+ while (query->next) {
+ if (query->next->userID == userID) {
+ /* Remove the query */
+ query_temp= query->next;
+ query->next = query_temp->next;
+ query_temp->next = NULL;
+ free(query_temp);
+ query_temp = NULL;
+ break;
+ } else {
+ query = query->next;
+ }
+ }
+ }
+ }
+
+ if (list_floors == NULL) {
+ i--;
+ } else {
+ if (lfloors->floors[i].floorID > list_floors->floorID) {
+ i--;
+ } else {
+ list_floors = list_floors->next;
+ }
+ }
+ } else {
+ query = lfloors->floors[i].floorquery;
+ /* If the query already exists, don't add it again */
+ exist_user = 0;
+
+ while (query) {
+ if (query->userID == userID) {
+ exist_user = 1;
+ break;
+ }
+ query = query->next;
+ }
+
+ if (exist_user == 0) {
+ /* Allocate a new node */
+ newnode = (floor_query *)calloc(1, sizeof(floor_query));
+
+ if (newnode == NULL) {
+ return -1;
+ }
+
+ query = lfloors->floors[i].floorquery;
+ /* Add the new query to the list of requests */
+ newnode->userID = userID;
+ newnode->fd = sockfd;
+ newnode->client_addr = client_addr;
+ newnode->next = query;
+ lfloors->floors[i].floorquery = newnode;
+ }
+
+ i--;
+ list_floors = list_floors->next;
+ }
+ }
+
+ return 0;
+}
+
+/* (??) */
+int bfcp_floor_query_server(bfcp_list_floors *lfloors, bfcp_floor *list_floors, unsigned short int userID, int sockfd)
+{
+ if(lfloors == NULL)
+ return 0;
+ if(userID <= 0)
+ return -1;
+
+ floor_query *query = NULL;
+ floor_query *query_temp = NULL;
+ floor_query *newnode = NULL;
+ int i = 0, exist_user;
+
+ i = lfloors->actual_number_floors-1;
+ while(0 <= i) {
+ if((list_floors == NULL) || (lfloors->floors[i].floorID != list_floors->floorID)) {
+ query = lfloors->floors[i].floorquery;
+ if(query != NULL) {
+ if(query->userID == userID) {
+ lfloors->floors[i].floorquery = query->next;
+ query->next = NULL;
+ free(query);
+ query = NULL;
+ } else {
+ while(query->next) {
+ if(query->next->userID == userID) {
+ /* Remove the query */
+ query_temp= query->next;
+ query->next = query_temp->next;
+ query_temp->next = NULL;
+ free(query_temp);
+ query_temp = NULL;
+ break;
+ } else
+ query = query->next;
+ }
+ }
+ }
+
+ if(list_floors == NULL)
+ i = i - 1;
+ else {
+ if(lfloors->floors[i].floorID > list_floors->floorID)
+ i = i - 1;
+ else
+ list_floors = list_floors->next;
+ }
+ } else {
+ query = lfloors->floors[i].floorquery;
+ /* If the query already exists, don't add it again */
+ exist_user = 0;
+ while(query) {
+ if(query->userID == userID) {
+ exist_user = 1;
+ break;
+ }
+ query = query->next;
+ }
+ if(exist_user == 0) {
+ /* Allocate a new node */
+ newnode = (floor_query *)calloc(1, sizeof(floor_query));
+ if(newnode == NULL)
+ return -1;
+
+ query = lfloors->floors[i].floorquery;
+ /* Add the new query to the list of requests */
+ newnode->userID = userID;
+ newnode->fd = sockfd;
+ newnode->next = query;
+ lfloors->floors[i].floorquery = newnode;
+ }
+
+ i = i - 1;
+ list_floors = list_floors->next;
+ }
+ }
+
+ return 0;
+}
+
+/* Handle an incoming FloorRequestQuery message */
+int bfcp_floorrequestquery_server(bfcp_server *server, unsigned long int conferenceID, unsigned short int TransactionID, unsigned long int floorRequestID, unsigned short int userID, int sockfd, int y)
+{
+ if(server == NULL)
+ return -1;
+ if(conferenceID <= 0)
+ return -1;
+ if(userID <= 0)
+ return -1;
+
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message = NULL;
+ bfcp_floor_request_information *frqInfo, *list_frqInfo = NULL;
+ int actual_conference, i, error;
+
+ actual_conference = server->Actual_number_conference - 1;
+ for(i = 0; i < actual_conference; i++) {
+ if(server->list_conferences[i].conferenceID == conferenceID)
+ break;
+ }
+
+ /* A buffer to compose error text messages when needed */
+ char errortext[200];
+
+ /* Check if this conference exists */
+ if(server->list_conferences[i].conferenceID != conferenceID) {
+ sprintf(errortext, "Conference %lu does not exist", conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_CONFERENCE_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if this user exists */
+ if(bfcp_existence_user(server->list_conferences[i].user, userID) != 0) {
+ sprintf(errortext, "User %hu does not exist in Conference %lu", userID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_USER_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Check if the request is in the Pending list */
+ if(bfcp_floor_request_query_server(server->list_conferences[i].pending, floorRequestID, userID, sockfd) != 0) {
+ /* Check if the request is in the Accepted list */
+ if(bfcp_floor_request_query_server(server->list_conferences[i].accepted, floorRequestID, userID, sockfd) != 0) {
+ /* Check if the request is in the Granted list */
+ if(bfcp_floor_request_query_server(server->list_conferences[i].granted, floorRequestID, userID, sockfd) != 0) {
+ sprintf(errortext, "FloorRequest %lu does not exist in Conference %lu", floorRequestID, conferenceID);
+ bfcp_error_code(conferenceID, userID, TransactionID, BFCP_FLOORREQUEST_DOES_NOT_EXIST, errortext, NULL, sockfd, y, server->bfcp_transport);
+ return -1;
+ }
+ }
+ }
+
+ /* Prepare the FloorRequestStatus message */
+ arguments = bfcp_new_arguments();
+ if(!arguments) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+ arguments->entity = bfcp_new_entity(conferenceID,TransactionID,userID);
+ arguments->primitive = FloorRequestStatus;
+
+ /* Granted list*/
+ frqInfo = bfcp_show_floorrequest_information(server->list_conferences[i].granted, server->list_conferences[i].user, floorRequestID, 0);
+ if(frqInfo != NULL) {
+ if(list_frqInfo != NULL)
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else
+ list_frqInfo = frqInfo;
+ }
+
+ /* Accepted list*/
+ frqInfo = bfcp_show_floorrequest_information(server->list_conferences[i].accepted, server->list_conferences[i].user, floorRequestID, 1);
+ if(frqInfo != NULL) {
+ if(list_frqInfo != NULL)
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else
+ list_frqInfo = frqInfo;
+ }
+
+ /* Pending list*/
+ frqInfo = bfcp_show_floorrequest_information(server->list_conferences[i].pending, server->list_conferences[i].user, floorRequestID, 2);
+ if(frqInfo != NULL) {
+ if(list_frqInfo != NULL)
+ bfcp_add_floor_request_information_list(list_frqInfo, frqInfo, NULL);
+ else
+ list_frqInfo = frqInfo;
+ }
+
+ arguments->frqInfo = list_frqInfo;
+
+ if (server->bfcp_transport == BFCP_OVER_UDP) {
+ struct sockaddr_in *client_address = bfcp_get_user_address_server(server, conferenceID, userID);
+ error = send_message_to_client_over_udp(arguments, sockfd, notify_to_server_app, client_address);
+ } else {
+ error = send_message_to_client(arguments, sockfd, notify_to_server_app, server->bfcp_transport);
+ }
+
+ BFCP_SEND_CHECK_ERRORS(sockfd);
+
+ return 0;
+}
+
+/* Check if it's fine to grant a floor to an accepted request */
+int check_accepted_node(bfcp_conference *conference, pnode queue_accepted, unsigned short int floorID, char *chair_info)
+{
+ pfloor revoke_floor;
+ pnode newnode;
+ int error;
+
+ revoke_floor = queue_accepted->floor;
+ while(revoke_floor) {
+ if((floorID == revoke_floor->floorID) && ((revoke_floor->status == BFCP_FLOOR_STATE_WAITING) || (revoke_floor->status == BFCP_FLOOR_STATE_ACCEPTED))) {
+ /* Change state to the floor again */
+ bfcp_change_state_floor(conference->floor, revoke_floor->floorID, 0);
+ /* Set it as Granted */
+ revoke_floor->status = BFCP_FLOOR_STATE_GRANTED;
+ revoke_floor = revoke_floor->next;
+ break;
+ } else if((floorID < revoke_floor->floorID) && (revoke_floor->status == BFCP_FLOOR_STATE_GRANTED))
+ revoke_floor = revoke_floor->next;
+ else
+ break;
+ }
+
+ if((revoke_floor == NULL) && (bfcp_all_floor_status(conference->accepted, queue_accepted->floorRequestID, 2) == 0)) {
+ /* Extract the request node from the Accepted list */
+ newnode = bfcp_extract_request(conference->accepted, queue_accepted->floorRequestID);
+ if(newnode == NULL) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Now prepare to move the node to the Granted list */
+
+ /* Change the priority of the request node to the lowest one */
+ newnode->priority = BFCP_LOWEST_PRIORITY;
+ /* Change the queue_position of the request node to the lowest one */
+ newnode->queue_position = 0;
+ /* Move the node to the Granted list */
+ error = bfcp_insert_request(conference->granted, newnode, newnode->floorRequestID, chair_info);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ /* Prepare all floor information needed by interested users */
+ error = bfcp_print_information_floor(conference, 0, 0, newnode, BFCP_GRANTED);
+ if(error == -1) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ return 0;
+ } else
+ return 1;
+}
+
+/* Check if it's fine to grant a floor to an accepted request (??) */
+int give_free_floors_to_the_accepted_nodes(bfcp_conference *conference, bfcp_queue *laccepted, bfcp_list_floors *lfloors, char *chair_info)
+{
+ if(lfloors == NULL)
+ return 0;
+ if(lfloors->floors == NULL)
+ return 0;
+ if(laccepted == NULL)
+ return 0;
+
+ int i;
+ pnode queue_accepted;
+
+ for (i = (lfloors->actual_number_floors - 1); 0 <= i; i--) {
+ if(bfcp_return_state_floor(lfloors, lfloors->floors[i].floorID) < bfcp_return_number_granted_floor(lfloors, lfloors->floors[i].floorID)) {
+ queue_accepted = laccepted->tail;
+ while(queue_accepted) {
+ if(check_accepted_node(conference, queue_accepted, lfloors->floors[i].floorID, chair_info) == 1)
+ queue_accepted = queue_accepted->prev;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Setup and send an Error reply to a participant */
+int bfcp_error_code(unsigned long int conferenceID, unsigned short int userID, unsigned short int TransactionID, int code, char *error_info, bfcp_unknown_m_error_details *details, int sockfd, int i, int transport)
+{
+ int error, dLen;
+ bfcp_arguments *arguments = NULL;
+ bfcp_message *message = NULL;
+
+ arguments = bfcp_new_arguments();
+ if(!arguments)
+ return -1;
+
+ arguments->entity = bfcp_new_entity(conferenceID, TransactionID, userID);
+ arguments->primitive = Error;
+
+ arguments->error = bfcp_new_error(code, NULL);
+ if(!arguments->error) {
+ /* An error occurred when creating a new Error Code */
+ bfcp_free_error(arguments->error);
+ return -1;
+ }
+
+ if(error_info != NULL) { /* If there's error text, add it */
+ dLen = strlen(error_info);
+ if(dLen != 0) {
+ arguments->eInfo = (char *)calloc(1, dLen*sizeof(char)+1);
+ memcpy(arguments->eInfo, error_info, dLen+1);
+ } else
+ arguments->eInfo = NULL;
+ } else
+ arguments->eInfo = NULL;
+
+ if (transport == BFCP_OVER_UDP) {
+ error = send_message_to_client_over_udp(arguments, sockfd, notify_to_server_app, NULL);
+ } else {
+ error = send_message_to_client(arguments, sockfd, notify_to_server_app, transport);
+ }
+
+ BFCP_SEND_CHECK_ERRORS(sockfd);
+
+ return 0;
+}
+
+/* Send a BFCP message to a participant */
+int send_message_to_client(bfcp_arguments *arguments, int sockfd, int(*notify_to_server_app)(bfcp_arguments *arguments, int outgoing_msg), int transport)
+{
+ if(arguments == NULL)
+ return -1;
+
+ int error = 0;
+ int total = 0; /* How many bytes have been sent */
+ int bytesleft = 0; /* How many bytes still have to be sent */
+ struct timeval tv;
+
+ bfcp_message *message = bfcp_build_message(arguments);
+ if(!message) {
+ if(arguments != NULL)
+ bfcp_free_arguments(arguments);
+ return -1;
+ }
+
+ callback_func(arguments, 1); /* Notify OUTGOING (1) message */
+
+ bytesleft = message->length;
+
+ /* Wait up to five seconds. */
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+#ifdef WIN32
+ FD_ZERO(&wset);
+ FD_SET(sockfd, &wset);
+#endif
+ /* Look for the TLS session associated with this file descriptor */
+ int i;
+ for(i = 0; i < BFCP_MAX_CONNECTIONS; i++) {
+ if(client[i] == sockfd)
+ break;
+ }
+ if(i == BFCP_MAX_CONNECTIONS)
+ return -1;
+
+ while(total < (message->length)) {
+#ifdef WIN32
+ error = select(sockfd+1, NULL, &wset, NULL, &tv);
+ if(error == -1)
+ return -1; /* Error in the select */
+ if(error == 0)
+ return 0; /* Timeout in the select */
+ if(FD_ISSET(sockfd, &wset)) {
+#endif
+ if(transport == BFCP_OVER_TLS) {
+ if(session[i])
+ error = SSL_write(session[i], message->buffer + total, bytesleft);
+ } else /* BFCP_OVER_TCP */
+ error = send(sockfd, message->buffer + total, bytesleft, 0);
+ if(error == -1) /* Error sending the message */
+ break;
+ total += error;
+ bytesleft -= error;
+#ifdef WIN32
+ }
+#endif
+ }
+
+ return error;
+}
+
+/* Send a BFCP message to a participant (UDP) */
+int send_message_to_client_over_udp(bfcp_arguments *arguments,
+ int sockfd,
+ int(*notify_to_server_app)(bfcp_arguments *arguments, int outgoing_msg),
+ struct sockaddr_in *client_address)
+{
+ if (arguments == NULL) {
+ return -1;
+ }
+
+ int bytes_send = 0;
+ int total = 0; /* How many bytes have been sent */
+ int bytesleft = 0; /* How many bytes still have to be sent */
+
+ bfcp_message *message = bfcp_build_message(arguments);
+
+ if (!message) {
+ if (arguments) {
+ bfcp_free_arguments(arguments);
+ }
+
+ return -1;
+ }
+
+ callback_func(arguments, 1); /* Notify OUTGOING (1) message */
+
+ bytesleft = message->length;
+
+ if (!client_address) {
+ client_address = &cliaddr;
+ }
+
+ while (total < (message->length)) {
+ bytes_send = sendto(sockfd, message->buffer + total, bytesleft, 0,
+ (struct sockaddr *) client_address, sizeof(struct sockaddr_in));
+
+ if (bytes_send == -1) /* Error sending the message */ {
+ break;
+ }
+
+ total += bytes_send;
+ bytesleft -= bytes_send;
+ }
+
+ return bytes_send;
+}
+
+/* Thread handling incoming connections and messages */
+static void *recv_thread(void *st_server)
+{
+ int error = 0, nready, i = 0, sockfd, client_sock;
+ bfcp_message *message = NULL;
+ bfcp_received_message *recvM = NULL;
+ bfcp_server *server = (bfcp_server *)st_server;
+ unsigned int addrlen;
+ struct sockaddr_in client_addr;
+ pfloor list_floor;
+ bfcp_floor_id_list *parse_floor;
+ bfcp_floor_request_status *parse_floor_id;
+ pnode node;
+ bfcp_received_message_error *errors;
+ bfcp_unknown_m_error_details *error_detail_list;
+
+ /* A buffer to compose error text messages when needed */
+ char errortext[200];
+
+ if (server->bfcp_transport != BFCP_OVER_UDP) {
+
+#ifdef WIN32
+ FD_ZERO(&allset);
+ FD_SET(server_sock_tcp, &allset); /* For TCP socket (server_sock_tcp) */
+#else
+ struct pollfd tmppollfds[BFCP_MAX_CONNECTIONS+1];
+ int tmpfds_no = 0;
+#endif
+
+ while(1) {
+#ifdef WIN32
+ rset = allset;
+
+ nready = select(maxfd+1, &rset, NULL, NULL, NULL);
+
+ if(nready < 0) {
+ close(server_sock_tcp);
+ pthread_exit(0);
+ }
+ if(FD_ISSET(server_sock_tcp,&rset)) { /* For TCP socket (server_sock_tcp) */
+#else
+ memcpy(&tmppollfds, &pollfds, sizeof(struct pollfd)*(BFCP_MAX_CONNECTIONS+1));
+ tmpfds_no = fds_no;
+ while((nready = poll(tmppollfds, tmpfds_no, -1) < 0) && (errno == EINTR));
+ if(nready < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error polling, closing connection\n");
+ switch(errno) {
+ case EAGAIN:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tEAGAIN\n");
+ break;
+ case EFAULT:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tEFAULT\n");
+ break;
+ case EINTR:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tEINTR\n");
+ break;
+ case EINVAL:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tEINVAL\n");
+ break;
+ default:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tboh\n");
+ break;
+ }
+ close(server_sock_tcp); /* For TCP socket (server_sock_tcp) */
+ pthread_exit(0);
+ }
+ if(tmppollfds[0].revents == POLLIN) {
+#endif
+ addrlen = sizeof(client_addr);
+ client_sock = accept(server_sock_tcp, (struct sockaddr *)&client_addr, &addrlen); /* For TCP socket (server_sock_tcp) */
+
+ /* Check if there is any IP_based restriction */
+ unsigned short int ip[4];
+ sscanf(inet_ntoa(client_addr.sin_addr), "%hu.%hu.%hu.%hu", &ip[0], &ip[1], &ip[2], &ip[3]);
+ int ok = 0;
+ if((server->restricted[0] == 0) || (ip[0] == server->restricted[0]))
+ ok++;
+ if((server->restricted[1] == 0) || (ip[1] == server->restricted[1]))
+ ok++;
+ if((server->restricted[2] == 0) || (ip[2] == server->restricted[2]))
+ ok++;
+ if((server->restricted[3] == 0) || (ip[3] == server->restricted[3]))
+ ok++;
+ if(ok < 4) { /* Didn't pass restriction test */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Client didn't pass restriction\n");
+#ifndef WIN32
+ shutdown(client_sock, SHUT_RDWR);
+#else
+ shutdown(client_sock, SD_BOTH);
+#endif
+ close(client_sock);
+ continue;
+ }
+
+ for(i = 0; i < BFCP_MAX_CONNECTIONS; i++) {
+ if(client[i] < 0) {
+ client[i] = client_sock;
+ if(server->bfcp_transport == BFCP_OVER_TLS) {
+ /* Setup a TLS session for this new connection:
+ TODO: better management of TLS-related errors
+ if(session[i]) {
+ SSL_free(session[i]);
+ session[i] = NULL;
+ } */
+ session[i] = SSL_new(context);
+ if(!session[i])
+ break;
+ if(SSL_set_fd(session[i], client_sock) < 1)
+ break;
+ if(SSL_accept(session[i]) < 1)
+ break;
+ }
+ break;
+ }
+ }
+
+ if(i == BFCP_MAX_CONNECTIONS) {
+ /* Too many clients connected */
+#ifndef WIN32
+ shutdown(client_sock, SHUT_RDWR);
+#else
+ shutdown(client_sock, SD_BOTH);
+#endif
+ close(client_sock);
+ continue;
+ }
+
+#ifdef WIN32
+ FD_SET(client_sock, &allset);
+#else
+// pollfds[i+1].fd = client[i];
+// pollfds[i+1].events = POLLIN;
+ pollfds[fds_no].fd = client[i];
+ pollfds[fds_no].events = POLLIN;
+ fds_no++;
+#endif
+
+ if(client_sock > maxfd)
+ maxfd = client_sock;
+
+ if(i > maxi)
+ maxi = i;
+
+ if(--nready <= 0)
+ continue;
+
+#ifndef WIN32
+ error = fcntl(client_sock, O_NONBLOCK, 1);
+#endif
+ }
+
+#ifdef WIN32
+ for(i = 0; i <= maxi; i++) {
+ if((sockfd = client[i]) < 0)
+ continue;
+#else
+ int j=0;
+ for(j = 1; j < tmpfds_no; j++) {
+#endif
+#ifdef WIN32
+ if(FD_ISSET(sockfd, &rset)) {
+#else
+ if(tmppollfds[j].revents == POLLIN) {
+ for(i = 0; i <= maxi; i++) {
+ if(client[i] == tmppollfds[j].fd)
+ break;
+ }
+ if(i > maxi)
+ continue;
+ if((sockfd = client[i]) < 0)
+ continue;
+#endif
+ message = received_message_from_client(sockfd, i, server->bfcp_transport);
+ if(message != NULL) {
+ recvM = bfcp_parse_message(message);
+ if(recvM != NULL) {
+ /* Notify the application about the incoming message through the callback */
+ callback_func(recvM->arguments, 0);
+ if(recvM->errors != NULL) {
+ errors = recvM->errors;
+ switch(errors->code) {
+ case BFCP_UNKNOWN_PRIMITIVE:
+ sprintf(errortext, "Unknown primitive %i", recvM->primitive);
+ bfcp_error_code(recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, BFCP_UNKNOWN_PRIMITIVE, errortext, NULL, sockfd, i, server->bfcp_transport);
+ break;
+ case BFCP_UNKNOWN_MANDATORY_ATTRIBUTE:
+ error_detail_list = bfcp_new_unknown_m_error_details_list(errors->attribute, 0);
+ errors = errors->next;
+ while(errors) {
+ if(errors->code == BFCP_UNKNOWN_MANDATORY_ATTRIBUTE)
+ error = bfcp_add_unknown_m_error_details_list(error_detail_list, errors->attribute, 0);
+ if(error == -1)
+ break;
+ errors = errors->next;
+ }
+ if(error != -1)
+ bfcp_error_code(recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, BFCP_UNKNOWN_MANDATORY_ATTRIBUTE, "Unknown Mandatory Attributes in the header", error_detail_list, sockfd, i, server->bfcp_transport);
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* Check the primitive in the message and do what's needed */
+ switch(recvM->primitive) {
+ case Hello:
+ if(recvM->entity != NULL)
+ bfcp_hello_server(server, recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, sockfd, i);
+ break;
+ case ChairAction:
+ if(recvM->entity != NULL) {
+ if(recvM->arguments != NULL) {
+ if(recvM->arguments->frqInfo != NULL) {
+ if(recvM->arguments->frqInfo->oRS != NULL) {
+ if(recvM->arguments->frqInfo->fRS != NULL) {
+ parse_floor_id=recvM->arguments->frqInfo->fRS;
+ if(parse_floor_id != NULL) {
+ list_floor = create_floor_list(parse_floor_id->fID, 0, parse_floor_id->sInfo);
+ parse_floor_id = parse_floor_id->next;
+ while(parse_floor_id != NULL) {
+ list_floor = add_floor_list(list_floor, parse_floor_id->fID, 0, parse_floor_id->sInfo);
+ parse_floor_id = parse_floor_id->next;
+ }
+ error = bfcp_ChairAction_server(server, recvM->entity->conferenceID, list_floor, recvM->entity->userID, recvM->arguments->frqInfo->frqID, recvM->arguments->frqInfo->oRS->rs->rs, recvM->arguments->frqInfo->oRS->sInfo, 0,recvM->entity->transactionID, sockfd, i);
+ if(error == -1) {
+ remove_floor_list(list_floor);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case FloorQuery:
+ if(recvM->entity != NULL) {
+ if(recvM->arguments != NULL) {
+ if(recvM->arguments->fID != NULL) {
+ parse_floor =recvM->arguments->fID;
+ if(parse_floor != NULL) {
+ list_floor = create_floor_list(parse_floor->ID, 0, NULL);
+ parse_floor = parse_floor->next;
+ while(parse_floor != NULL) {
+ list_floor = add_floor_list(list_floor, parse_floor->ID, 0, NULL);
+ parse_floor = parse_floor->next;
+ }
+ }
+ }
+ else
+ list_floor = NULL;
+ error = bfcp_floorquery_server(server, recvM->entity->conferenceID, list_floor, recvM->entity->userID, recvM->entity->transactionID, sockfd, i);
+ if(error == -1)
+ remove_floor_list(list_floor);
+ }
+ }
+ break;
+ case UserQuery:
+ if(recvM->entity != NULL) {
+ if(recvM->arguments != NULL)
+ error = bfcp_userquery_server(server, recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, recvM->arguments->bID, sockfd, i);
+ }
+ break;
+ case FloorRequestQuery:
+ if(recvM->entity != NULL) {
+ if(recvM->arguments != NULL) {
+ if(recvM->arguments->frqID != 0)
+ error = bfcp_floorrequestquery_server(server, recvM->entity->conferenceID, recvM->entity->transactionID, recvM->arguments->frqID, recvM->entity->userID, sockfd, i);
+ }
+ }
+ break;
+ case FloorRelease:
+ if(recvM->entity != NULL) {
+ if(recvM->arguments != NULL) {
+ error = bfcp_FloorRelease_server(server, recvM->entity->conferenceID, recvM->entity->transactionID, recvM->entity->userID, recvM->arguments->frqID, sockfd, i);
+ }
+ }
+ break;
+ case FloorRequest:
+ if(recvM->entity != NULL) {
+ if(recvM->arguments != NULL) {
+ if(recvM->arguments->fID != NULL) {
+ parse_floor = recvM->arguments->fID;
+ if(parse_floor != NULL) {
+ node = bfcp_init_request(recvM->entity->userID, recvM->arguments->bID, recvM->arguments->priority, recvM->arguments->pInfo, parse_floor->ID);
+ parse_floor = parse_floor->next;
+ while(parse_floor != NULL) {
+ error = bfcp_add_floor_to_request(node, parse_floor->ID);
+ if(error != 0)
+ break;
+ parse_floor = parse_floor->next;
+ }
+ error = bfcp_FloorRequest_server(server, recvM->entity->conferenceID, recvM->entity->transactionID, node, sockfd, i);
+ }
+ }
+ }
+ }
+ break;
+ case FloorRequestStatusAck:
+ case ErrorAck:
+ case FloorStatusAck:
+ break;
+ default:
+ sprintf(errortext, "Unknown primitive %i", recvM->primitive);
+ bfcp_error_code(recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, BFCP_UNKNOWN_PRIMITIVE, errortext, NULL, sockfd, i, server->bfcp_transport);
+ break;
+ }
+ }
+ }
+ if(message != NULL)
+ bfcp_free_message(message);
+ if(recvM != NULL)
+ bfcp_free_received_message(recvM);
+ }
+ if(--nready <= 0)
+ break;
+ }
+ }
+ }
+ } else { /* recv_thread() part for server of UDP transport socket */
+#ifdef WIN32
+ fd_set rset;
+ FD_ZERO(&rset);
+#endif
+ while (1) {
+#ifdef WIN32
+ FD_SET(server_sock_udp, &rset);
+ nready = select(server_sock_udp+1, &rset, NULL, NULL, NULL);
+#else
+ while((nready = poll(poll_fd_udp, 1, -1) < 0) && (errno == EINTR));
+#endif
+ if (nready < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error polling, closing connection\n");
+ switch(errno) {
+ case EAGAIN:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tEAGAIN\n");
+ break;
+ case EFAULT:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tEFAULT\n");
+ break;
+ case EINTR:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tEINTR\n");
+ break;
+ case EINVAL:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tEINVAL\n");
+ break;
+ default:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tboh\n");
+ break;
+ }
+ close(server_sock_udp);
+ pthread_exit(0);
+ }
+
+ if (close_udp_conn) {
+ close(server_sock_udp);
+ pthread_exit(0);
+ }
+
+#ifdef WIN32
+ if (FD_ISSET(server_sock_udp, &rset)) {
+#else
+ if (poll_fd_udp[0].revents == POLLIN) {
+#endif
+ message = received_message_from_client_over_udp(server_sock_udp);
+
+ if(message) {
+ recvM = bfcp_parse_message(message);
+
+ if (recvM) {
+ /* Notify the application about the incoming message (0) through the callback */
+ callback_func(recvM->arguments, 0);
+
+ if (recvM->errors) {
+ errors = recvM->errors;
+
+ switch (errors->code) {
+ case BFCP_UNKNOWN_PRIMITIVE:
+ sprintf(errortext, "Unknown primitive %i", recvM->primitive);
+ bfcp_error_code(recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, BFCP_UNKNOWN_PRIMITIVE, errortext, NULL, server_sock_udp, i, server->bfcp_transport);
+ break;
+ case BFCP_UNKNOWN_MANDATORY_ATTRIBUTE:
+ error_detail_list = bfcp_new_unknown_m_error_details_list(errors->attribute, 0);
+ errors = errors->next;
+
+ while (errors) {
+ if (errors->code == BFCP_UNKNOWN_MANDATORY_ATTRIBUTE) {
+ error = bfcp_add_unknown_m_error_details_list(error_detail_list, errors->attribute, 0);
+ }
+ if (error == -1) {
+ break;
+ }
+
+ errors = errors->next;
+ }
+ if (error != -1) {
+ bfcp_error_code(recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, BFCP_UNKNOWN_MANDATORY_ATTRIBUTE, "Unknown Mandatory Attributes in the header", error_detail_list, server_sock_udp, i, server->bfcp_transport);
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* Check the primitive in the message and do what's needed */
+ switch (recvM->primitive) {
+ case Hello:
+ if (recvM->entity) {
+ bfcp_hello_server(server, recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, server_sock_udp, i);
+ }
+ break;
+ case ChairAction:
+ if ((recvM->entity) &&
+ (recvM->arguments) &&
+ (recvM->arguments->frqInfo) &&
+ (recvM->arguments->frqInfo->oRS) &&
+ (recvM->arguments->frqInfo->fRS) &&
+ (parse_floor_id = recvM->arguments->frqInfo->fRS)) {
+ list_floor = create_floor_list(parse_floor_id->fID, 0, parse_floor_id->sInfo);
+ parse_floor_id = parse_floor_id->next;
+
+ while (parse_floor_id) {
+ list_floor = add_floor_list(list_floor, parse_floor_id->fID, 0, parse_floor_id->sInfo);
+ parse_floor_id = parse_floor_id->next;
+ }
+
+ error = bfcp_ChairAction_server(server, recvM->entity->conferenceID, list_floor, recvM->entity->userID, recvM->arguments->frqInfo->frqID, recvM->arguments->frqInfo->oRS->rs->rs, recvM->arguments->frqInfo->oRS->sInfo, 0,recvM->entity->transactionID, server_sock_udp, i);
+
+ if (error == -1) {
+ remove_floor_list(list_floor);
+ break;
+ }
+ }
+ break;
+ case FloorQuery:
+ if ((recvM->entity) &&
+ (recvM->arguments)) {
+ if (recvM->arguments->fID) {
+ parse_floor =recvM->arguments->fID;
+ if (parse_floor) {
+ list_floor = create_floor_list(parse_floor->ID, 0, NULL);
+ parse_floor = parse_floor->next;
+
+ while (parse_floor) {
+ list_floor = add_floor_list(list_floor, parse_floor->ID, 0, NULL);
+ parse_floor = parse_floor->next;
+ }
+ }
+ } else {
+ list_floor = NULL;
+ }
+ error = bfcp_floorquery_server(server, recvM->entity->conferenceID, list_floor, recvM->entity->userID, recvM->entity->transactionID, server_sock_udp, i);
+
+ if (error == -1) {
+ remove_floor_list(list_floor);
+ }
+ }
+ break;
+ case UserQuery:
+ if ((recvM->entity) &&
+ (recvM->arguments)) {
+ error = bfcp_userquery_server(server, recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, recvM->arguments->bID, server_sock_udp, i);
+ }
+ break;
+ case FloorRequestQuery:
+ if ((recvM->entity) &&
+ (recvM->arguments) &&
+ (recvM->arguments->frqID != 0)) {
+ error = bfcp_floorrequestquery_server(server, recvM->entity->conferenceID, recvM->entity->transactionID, recvM->arguments->frqID, recvM->entity->userID, server_sock_udp, i);
+ }
+ break;
+ case FloorRelease:
+ if ((recvM->entity) &&
+ (recvM->arguments)) {
+ error = bfcp_FloorRelease_server(server, recvM->entity->conferenceID, recvM->entity->transactionID, recvM->entity->userID, recvM->arguments->frqID, server_sock_udp, i);
+ }
+ break;
+ case FloorRequest:
+ if ((recvM->entity) &&
+ (recvM->arguments) &&
+ (recvM->arguments->fID) &&
+ (parse_floor = recvM->arguments->fID)) {
+ node = bfcp_init_request(recvM->entity->userID, recvM->arguments->bID, recvM->arguments->priority, recvM->arguments->pInfo, parse_floor->ID);
+ parse_floor = parse_floor->next;
+
+ while (parse_floor) {
+ error = bfcp_add_floor_to_request(node, parse_floor->ID);
+
+ if (error) {
+ break;
+ }
+
+ parse_floor = parse_floor->next;
+ }
+
+ error = bfcp_FloorRequest_server(server, recvM->entity->conferenceID, recvM->entity->transactionID, node, server_sock_udp, i);
+ }
+ break;
+ case FloorRequestStatusAck:
+ case ErrorAck:
+ case FloorStatusAck:
+ break;
+ default:
+ sprintf(errortext, "Unknown primitive %i", recvM->primitive);
+ bfcp_error_code(recvM->entity->conferenceID, recvM->entity->userID, recvM->entity->transactionID, BFCP_UNKNOWN_PRIMITIVE, errortext, NULL, server_sock_udp, i, server->bfcp_transport);
+ break;
+ }
+ }
+ }
+ if (message) {
+ bfcp_free_message(message);
+ }
+ if (recvM) {
+ bfcp_free_received_message(recvM);
+ }
+ }
+#ifdef WIN32
+ }
+#else
+ } else if((poll_fd_udp[0].revents & POLLERR) ||
+ (poll_fd_udp[0].revents & POLLHUP) ||
+ (poll_fd_udp[0].revents & POLLNVAL)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "We got an error polling!!\n");
+ close(server_sock_udp);
+ pthread_exit(0);
+
+ }
+#endif
+ }
+ }
+
+}
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_server.h b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_server.h
new file mode 100644
index 00000000000..e46449aaf2c
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_server.h
@@ -0,0 +1,240 @@
+#ifndef _BFCP_SERVER_H
+#define _BFCP_SERVER_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef WIN32
+#include
+#endif
+
+#include "bfcp_link_list.h"
+
+/* The BFCP messages building/parsing library */
+#include
+
+/* Definition for threads (Asterisk redefines pthreads) */
+#include "bfcp_threads.h"
+#include "switch.h"
+
+#define BFCP_FCS_DEFAULT_PORT 2345 /* The default port the Floor Control Server will bind to */
+#define BFCP_BACKLOG 10 /* The default value for the pending connections queue */
+#define BFCP_MAX_CONNECTIONS 1000 /* The default value for how many connections the server can hold at the same time */
+
+/* The library supports TCP/BFCP, TCP/TLS/BFCP and UDP/BFCP */
+#define BFCP_OVER_TCP 0
+#define BFCP_OVER_TLS 1
+#define BFCP_OVER_UDP 2
+
+struct sockaddr_in cliaddr; /* Stores client address of current message read and later may be used to send response to client */
+socklen_t m_addrlen; /* Stores length of client address */
+
+/* BFCP Conference instance */
+typedef struct bfcp_conference {
+ int bfcp_transport; /* BFCP/TCP (0) or BFCP/TLS (1) or BFCP/UDP (2) */
+ bfcp_queue *pending; /* The Pending list */
+ bfcp_queue *accepted; /* The Accepted list */
+ bfcp_queue *granted; /* The Granted list */
+ unsigned long int conferenceID; /* The BFCP ConferenceID */
+ unsigned short int floorRequestID; /* The base FloorRequestID to increment at each new request */
+ bfcp_list_users *user; /* The Users list */
+ bfcp_list_floors *floor; /* The Floors list */
+ unsigned long int chair_wait_request; /* Time in miliseconds that the system will wait for a ChairAction */
+ int automatic_accepted_deny_policy; /* Policy for automated responses when a chair is missing (0 = accept request, 1 = reject request) */
+} bfcp_conference;
+/* Pointer to a BFCP Conference */
+typedef bfcp_conference *conference;
+
+/* Floor Control Server (FCS) */
+typedef struct bfcp_server {
+ int bfcp_transport; /* BFCP/TCP (0) or BFCP/TLS (1) or BFCP/UDP (2) */
+ unsigned short int Actual_number_conference; /* The current number of managed conferences */
+ unsigned short int Max_number_conference; /* The maximum number of allowed conferences */
+ bfcp_conference *list_conferences; /* The linked list of currently managed conferences */
+ unsigned short int restricted[4];
+ /* Callback to notify the Application Server about BFCP events */
+ int( *callback_func)(bfcp_arguments *arguments, int outgoing_msg);
+} bfcp_server;
+/* Pointer to a FCS instance */
+typedef bfcp_server *bfcp;
+
+/* Thread handling a specific FloorRequest instance */
+typedef struct bfcp_thread {
+ bfcp_conference *conf; /* BFCP Conference this thread is related to */
+ unsigned long int chair_wait_request; /* Time in milisecons that the thread will wait for a ChairAction */
+ unsigned short int floorRequestID; /* Identifier of the FloorRequest this thread is handling */
+} bfcp_thread;
+/* Pointer to a thread */
+typedef bfcp_thread *struct_thread;
+
+/* Thread- and mutex-related variables */
+bfcp_mutex_t count_mutex;
+pthread_t thread_tcp, thread_udp;
+
+/* Socket-related variables (File descriptors and sets) */
+int maxfd, server_sock_tcp, server_sock_udp, maxi, fds_no;
+int close_udp_conn; /* Flag used to exit from thread running for UDP socket */
+int client[BFCP_MAX_CONNECTIONS];
+fd_set rset, wset, allset;
+#ifndef WIN32
+struct pollfd pollfds[BFCP_MAX_CONNECTIONS+1];
+struct pollfd poll_fd_udp[1]; /* For UDP socket */
+#endif
+
+/* TLS-related stuff: an array of sessions is needed to pair up with client[i] */
+SSL_CTX *context;
+SSL_METHOD *method;
+SSL *session[BFCP_MAX_CONNECTIONS];
+
+
+/**************************/
+/* Server-related methods */
+/**************************/
+
+/* Create a new Floor Control Server */
+struct bfcp_server *bfcp_initialize_bfcp_server(unsigned short int Max_conf, unsigned short int port_server, int(*notify_to_server_app)(bfcp_arguments *arguments, int outgoing_msg), int transport, char *certificate, char *privatekey, char *restrict);
+/* Destroy a currently running Floor Control Server */
+int bfcp_destroy_bfcp_server(bfcp_server **serverp);
+/* Create a new BFCP Conference and add it to the FCS */
+int bfcp_initialize_conference_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int Max_Num_Floors, unsigned short int Max_Number_Floor_Request, int automatic_accepted_deny_policy, unsigned long int chair_wait_request);
+/* Destroy a currently managed BFCP Conference and remove it from the FCS */
+int bfcp_destroy_conference_server(bfcp_server *server, unsigned long int ConferenceID);
+/* Change the maximum number of allowed conferences in the FCS */
+int bfcp_change_number_bfcp_conferences_server(bfcp_server *server, unsigned short int Num);
+/* Change the maximum number of users that can be granted this floor at the same time */
+int bfcp_change_number_granted_floor_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int FloorID, unsigned short int limit_granted_floor);
+/* Change the allowed number of per-floor requests for this list */
+int bfcp_change_user_req_floors_server(bfcp_server *server, unsigned short int Max_Number_Floor_Request);
+/* Change the automated policy for requests related to floors that have no chair */
+int bfcp_change_chair_policy(bfcp_server *server, unsigned long int ConferenceID, int automatic_accepted_deny_policy, unsigned long int chair_wait_request);
+/* Add a floor to an existing conference */
+int bfcp_add_floor_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int FloorID, unsigned short int ChairID, int limit_granted_floor);
+/* Remove a floor from an existing conference */
+int bfcp_delete_floor_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int FloorID);
+/* Set a participant as chair of a floor */
+int bfcp_add_chair_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int FloorID, unsigned short int ChairID);
+/* Set no participant as chair for a floor */
+int bfcp_delete_chair_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int FloorID);
+/* Add a participant to the list of users of a BFCP Conference */
+int bfcp_add_user_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int userID, char *user_URI, char *user_display_name);
+/* Remove a participant from the list of users of a BFCP Conference */
+int bfcp_delete_user_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int userID);
+
+/*!
+ \brief Set user address of participant with userID in the user_list
+ \param server Pointer to Floor Control Server instance
+ \param conferenceID BFCP conferenceID
+ \param userID BFCP userID
+ \param client_address char pointer pointing to IP address of client
+ \param client_port Port at which client is listening
+ \return 0, If address successfully set else return -1
+ */
+int bfcp_set_user_address_server(bfcp_server *server,
+ unsigned long int conferenceID,
+ unsigned short int userID,
+ char *client_address,
+ unsigned short int client_port);
+
+/*!
+ \brief Retrieve user address of participant with userID in the user_list
+ \param server Pointer to Floor Control Server instance
+ \param conferenceID BFCP conferenceID
+ \param userID BFCP userID
+ \return Pointer to client's socket address of type struct sockaddr_in
+ */
+struct sockaddr_in *bfcp_get_user_address_server(bfcp_server *server,
+ unsigned long int conferenceID,
+ unsigned short int userID);
+
+/******************/
+/* Helper methods */
+/******************/
+
+/* Create a new 'bfcp_floor_request_information' (bfcp_messages.h) out of a 'pnode' */
+bfcp_floor_request_information *create_floor_request_userID(pnode traverse, lusers users, unsigned short int userID, unsigned short int request_status, int i);
+/* Create a new 'bfcp_floor_request_information' (bfcp_messages.h) out of a floor */
+bfcp_floor_request_information *create_floor_message(unsigned short int floorID, pnode traverse, lusers users, unsigned short int request_status, int i);
+/* Setup and send a FloorStatus BFCP message */
+int bfcp_show_floor_information(unsigned long int ConferenceID, unsigned short int TransactionID, unsigned short int userID, bfcp_conference *conference, unsigned short int floorID, int sockid, fd_set allset, int *client, pnode newnode, unsigned short int status);
+/* Prepare the needed arguments for a FloorRequestStatus BFCP message */
+int bfcp_print_information_floor(bfcp_conference *conference, unsigned short int userID, unsigned short int TransactionID, pnode newnode, unsigned short int status);
+/* Setup and send a FloorRequestStatus BFCP message */
+int bfcp_show_requestfloor_information(bfcp_list_users *list_users, bfcp_queue *accepted_queue, unsigned long int ConferenceID, unsigned short int userID, unsigned short int TransactionID, pnode newnode, unsigned short int status, int socket);
+/* Handle a BFCP message a client sent to the FCS */
+bfcp_message *received_message_from_client(int sockfd, int i, int transport);
+
+/*!
+ \brief Handle a BFCP message a client sent to the FCS (UDP)
+ \param sockfd File descriptor of UDP socket of server
+ \return Pointer to bfcp_message
+ */
+bfcp_message *received_message_from_client_over_udp(int sockfd);
+
+/* Remove all floor requests made by a user from all existing nodes */
+int bfcp_remove_floorrequest_from_all_nodes(bfcp_conference *server, unsigned short int userID);
+/* Remove all floor requests made by a user from a queue */
+int bfcp_remove_floorrequest_from_a_queue(bfcp_queue *conference, unsigned short int userID);
+/* Disable and remove all floor events notifications to an user */
+int bfcp_remove_floorquery_from_all_nodes(bfcp_list_floors *lfloors, unsigned short int userID);
+/* A controller to check timeouts when waiting for a ChairAction */
+void *watchdog(void *st_thread);
+/* Handle an incoming FloorRequest message */
+int bfcp_FloorRequest_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int TransactionID, pnode newnode, int sockfd, int y);
+/* Handle an incoming FloorRelease message */
+int bfcp_FloorRelease_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int TransactionID, unsigned short int userID, unsigned long int FloorRequestID, int sockfd, int y);
+/* Handle an incoming ChairAction message */
+int bfcp_ChairAction_server(bfcp_server *server, unsigned long int ConferenceID, bfcp_floor *list_floors, unsigned short int userID, unsigned long int FloorRequestID, int RequestStatus, char *chair_info, int queue_position, unsigned short int TransactionID, int sockfd, int y);
+/* Handle an incoming Hello message */
+int bfcp_hello_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int userID, unsigned short int TransactionID, int sockfd, int y);
+/* Handle an incoming UserQuery message */
+int bfcp_userquery_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int userID, unsigned short int TransactionID, unsigned short int beneficiaryID, int sockfd, int y);
+/* Handle an incoming FloorQuery message */
+int bfcp_floorquery_server(bfcp_server *server, unsigned long int ConferenceID, bfcp_floor *list_floors, unsigned short int userID, unsigned short int TransactionID, int sockfd, int y);
+/* (??) */
+int bfcp_floor_query_server(bfcp_list_floors *lfloors, bfcp_floor *list_floors, unsigned short int userID, int sockfd);
+
+/*!
+ \brief Add new floor query for a floor in query list, if not exit for user with userID
+ and also set client address corrospoding to participant, is specific for UDP socket
+ \param lfloors Pointer to a list of floors
+ \param list_floors Pointer to a specific instance of Floor Information
+ \param userID BFCP userID
+ \param client_addr BFCP particiapnt addrss
+ \param sockfd file descriptor of UDP socket of server
+ \return 0, if floor query added or already present else -1
+ */
+int bfcp_floor_query_server_over_udp(bfcp_list_floors *lfloors,
+ bfcp_floor *list_floors,
+ unsigned short int userID,
+ struct sockaddr_in *client_addr,
+ int sockfd);
+
+/* Handle an incoming FloorRequestQuery message */
+int bfcp_floorrequestquery_server(bfcp_server *server, unsigned long int ConferenceID, unsigned short int TransactionID, unsigned long int FloorRequestID, unsigned short int userID, int sockfd, int y);
+/* Check if it's fine to grant a floor to an accepted request */
+int check_accepted_node(bfcp_conference *conference, pnode queue_accepted, unsigned short int floorID, char *chair_info);
+/* Check if it's fine to grant a floor to an accepted request (??) */
+int give_free_floors_to_the_accepted_nodes(bfcp_conference *conference, bfcp_queue *laccepted, bfcp_list_floors *lfloors, char *chair_info);
+/* Setup and send an Error reply to a participant */
+int bfcp_error_code(unsigned long int ConferenceID, unsigned short int userID, unsigned short int TransactionID, int code, char *error_info, bfcp_unknown_m_error_details *details, int sockfd, int i, int transport);
+/* Send a BFCP message to a participant */
+int send_message_to_client(bfcp_arguments *arguments, int sockfd, int(*notify_to_server_app)(bfcp_arguments *arguments, int outgoing_msg), int transport);
+
+/*!
+ \brief Send a BFCP message to a participant (UDP)
+ \param arguments Pointer of bfcp_arguments
+ \param sockfd File descriptor to participant address
+ \param notify_to_server_app Notify the Application Server about BFCP events
+ \param client_address Socket address of particiapnt
+ \return Number of bytes send, if any error occur then return -1;
+ */
+int send_message_to_client_over_udp(bfcp_arguments *arguments,
+ int sockfd,
+ int(*notify_to_server_app)(bfcp_arguments *arguments, int outgoing_msg),
+ struct sockaddr_in *client_address);
+
+#endif
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_threads.h b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_threads.h
new file mode 100644
index 00000000000..44ab292693d
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_threads.h
@@ -0,0 +1,13 @@
+#ifndef _BFCP_THREADS_
+#define _BFCP_THREADS_
+
+#include
+typedef pthread_mutex_t bfcp_mutex_t;
+#define bfcp_mutex_init(a,b) pthread_mutex_init(a,b)
+#define bfcp_mutex_destroy(a) pthread_mutex_destroy(a)
+#define bfcp_mutex_lock(a) \
+ pthread_mutex_lock(a);
+#define bfcp_mutex_unlock(a) \
+ pthread_mutex_unlock(a);
+
+#endif
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_user_list.c b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_user_list.c
new file mode 100644
index 00000000000..5c7d3e9ac1b
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_user_list.c
@@ -0,0 +1,569 @@
+#include "bfcp_user_list.h"
+
+/* From 'bfcp_server.h': Setup and send an Error reply to a participant */
+extern int bfcp_error_code(unsigned long int ConferenceID, unsigned short int userID, unsigned short int TransactionID, int code, char *error_info, bfcp_unknown_m_error_details *details, int sockfd, int i, int transport);
+
+
+/* Create a new linked list of users */
+struct bfcp_list_users *bfcp_create_user_list (unsigned short int Max_Number_Floor_Request, unsigned short int Num_floors)
+{
+ bfcp_list_users *lusers;
+
+ if(Max_Number_Floor_Request <= 0)
+ Max_Number_Floor_Request = 1;
+ if(Num_floors <= 0)
+ Num_floors = 1;
+
+ /* Allocate a new list of users */
+ lusers = (bfcp_list_users *)calloc(1, sizeof(bfcp_list_users));
+
+ /* Initialize the list */
+ if(lusers == NULL)
+ return(NULL);
+ else {
+ lusers->max_number_floor_request = Max_Number_Floor_Request;
+ lusers->maxnumberfloors = --Num_floors;
+ lusers->users = NULL;
+ }
+
+ return(lusers);
+}
+
+/* Check ifparticipant with such userID exists in this list */
+int bfcp_existence_user(lusers list_users, unsigned short int userID)
+{
+ users temp_list_users;
+
+ if(list_users == NULL)
+ return -1;
+ if(userID <= 0)
+ return -1;
+
+ temp_list_users= list_users->users;
+
+ while(temp_list_users && (temp_list_users->userID != userID))
+ temp_list_users = temp_list_users->next;
+
+ if(temp_list_users && (temp_list_users->userID == userID))
+ /* This user is in the list */
+ return 0;
+ else
+ /* This user is NOT in the list */
+ return -1;
+}
+
+/* Change the allowed number of per-floor requests for this list */
+int bfcp_change_user_req_floors(lusers list_users, unsigned short int Max_Number_Floor_Request)
+{
+ if(list_users == NULL)
+ return -1;
+
+ list_users->max_number_floor_request = Max_Number_Floor_Request;
+
+ return 0;
+}
+
+/* Change the allowed number of floors in the conference for this list */
+int bfcp_change_number_users_floors(lusers list_users, unsigned short int Num_floors)
+{
+ if(list_users == NULL)
+ return -1;
+ if(Num_floors <= 0)
+ return -1;
+
+ users user = NULL;
+ int *list_floors = NULL, i = 0;
+
+ for(user = list_users->users; user; user= user->next) {
+ if(list_users->maxnumberfloors >= Num_floors) {
+ for(i = Num_floors; i <= list_users->maxnumberfloors; i++)
+ user->numberfloorrequest[i] = 0;
+ }
+
+ list_floors = (int *)realloc(user->numberfloorrequest, (Num_floors)*sizeof(int));
+ if(list_floors == NULL)
+ return -1;
+
+ user->numberfloorrequest= list_floors;
+
+ if(Num_floors > list_users->maxnumberfloors) {
+ for(i = list_users->maxnumberfloors+1; i < Num_floors; i++)
+ user->numberfloorrequest[i]=0;
+ }
+ }
+
+ list_users->maxnumberfloors = --Num_floors;
+
+ return 0;
+}
+
+/* Add a new user to this list */
+int bfcp_add_user(lusers list_users, unsigned short int userID, char *user_URI, char *user_display_name)
+{
+ if(list_users == NULL)
+ return -1;
+ if(userID <= 0)
+ return -1;
+
+ users ini_user_list = NULL, user = NULL, node_user = NULL;
+ int dLen = 0;
+
+ /* First we check if a user with the same ID already exists in the list */
+ for(user = list_users->users; user; user = user->next) {
+ if(user->userID == userID)
+ /* This user already exists in the list */
+ return -1;
+ }
+
+ /* Create a new user instance */
+ node_user = (bfcp_user *)calloc(1, sizeof(bfcp_user));
+
+ /* Initialize the new user */
+ if(node_user == NULL)
+ return -1;
+ else {
+ node_user->userID = userID;
+ /* Add the CSP URI text */
+ if(user_URI != NULL) {
+ dLen = strlen(user_URI);
+ if(dLen != 0) {
+ node_user->user_URI = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(node_user->user_URI == NULL)
+ return -1;
+ memcpy(node_user->user_URI, user_URI, dLen+1);
+ }
+ } else /* No CSP URI for this user */
+ node_user->user_URI = NULL;
+
+ /* Add the Display Name text */
+ if(user_display_name != NULL) {
+ dLen = strlen(user_display_name);
+ if(dLen != 0) {
+ node_user->user_display_name = (char *)calloc(1, dLen*sizeof(char)+1);
+ if(node_user->user_display_name == NULL)
+ return -1;
+ memcpy(node_user->user_display_name, user_display_name, dLen+1);
+ }
+ } else /* No Display Name for this user */
+ node_user->user_display_name = NULL;
+
+ /* Create a list for floor requests by this user */
+ node_user->numberfloorrequest = (int *)calloc(list_users->maxnumberfloors + 1, sizeof(int));
+ if(node_user->numberfloorrequest == NULL)
+ return -1;
+
+ node_user->client_addr = NULL;
+ node_user->fd = 0;
+
+ if(list_users->users == NULL) {
+ node_user->next = list_users->users;
+ list_users->users = node_user;
+ } else if(list_users->users->userID < userID) {
+ node_user->next = list_users->users;
+ list_users->users = node_user;
+ } else {
+ ini_user_list = list_users->users;
+ while(ini_user_list->next && (ini_user_list->next->userID > userID)) {
+ ini_user_list = ini_user_list->next;
+ }
+ node_user->next = ini_user_list->next;
+ ini_user_list->next = node_user;
+ }
+ }
+
+ return(0);
+}
+
+/* Delete an existing user from this list */
+int bfcp_delete_user(lusers list_users, unsigned short int userID)
+{
+ if(list_users == NULL)
+ return 0;
+ if(userID <= 0)
+ return -1;
+
+ users temp_list_users, temp_node_user;
+
+ temp_list_users = list_users->users;
+ if(temp_list_users == NULL)
+ /* The users' list is empty */
+ return 0;
+ else {
+ if(temp_list_users->userID == userID)
+ list_users->users = temp_list_users->next;
+ else {
+ while((temp_list_users->next != NULL) && (temp_list_users->next->userID != userID))
+ temp_list_users = temp_list_users->next;
+ if(temp_list_users->next!=NULL) {
+ temp_node_user = temp_list_users;
+ temp_list_users = temp_list_users->next;
+ temp_node_user->next = temp_list_users->next;
+ }
+ }
+ }
+
+ /* This node is not in the list */
+ if((temp_list_users == NULL) || (temp_list_users->userID != userID))
+ /* This user does not exist in the conference */
+ return 0;
+
+ /* Free the user node */
+ free(temp_list_users->user_URI);
+ temp_list_users->user_URI = NULL;
+ free(temp_list_users->user_display_name);
+ temp_list_users->user_display_name = NULL;
+ free(temp_list_users->numberfloorrequest);
+ temp_list_users->numberfloorrequest = NULL;
+ free(temp_list_users->client_addr);
+ temp_list_users->client_addr = NULL;
+ free(temp_list_users);
+ temp_list_users = NULL;
+
+ return(0);
+}
+
+/* Set address of user in this list */
+int bfcp_set_user_address(lusers list_users, unsigned short int userID, char *client_address, unsigned short int client_port)
+{
+ if (list_users == NULL || userID <= 0) {
+ return -1;
+ }
+
+ users user;
+
+ /* Need to find user node with same userID */
+ for (user = list_users->users; user && (user->userID != userID); user = user->next);
+
+ if (!user) {
+ /* user does not present in userlist */
+ return -1;
+ }
+
+ if (!user->client_addr) {
+ user->client_addr = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in));
+ }
+
+ user->client_addr->sin_addr.s_addr = inet_addr(client_address);
+ user->client_addr->sin_port = htons(client_port);
+ user->client_addr->sin_family = AF_INET;
+ memset(&(user->client_addr->sin_zero), '\0', 8);
+ return 0;
+
+}
+
+/* Retrieve address of user from the list */
+struct sockaddr_in *bfcp_get_user_address(lusers list_users, unsigned short int userID)
+{
+ if (list_users == NULL || userID <= 0) {
+ return NULL;
+ }
+
+ users user;
+
+ /* Need to find user node with same userID */
+ for (user = list_users->users; user && (user->userID != userID); user = user->next);
+
+ if (user) {
+ /* user present in userlist */
+ return user->client_addr;
+ }
+
+ return NULL;
+}
+
+
+/* Set socket file descriptor of specific user in the list */
+int bfcp_set_user_sockfd(lusers list_users, unsigned short int userID, int sockfd)
+{
+ if (list_users == NULL || userID <= 0) {
+ return -1;
+ }
+
+ users user;
+
+ /* Need to find user node with userID */
+ for (user = list_users->users; user && (user->userID != userID); user = user->next);
+
+ if (user) {
+ user->fd = sockfd; /* sockfd is required later for sending FloorStatus to
+ user if floor status changes to granted or released */
+ return 0;
+ }
+
+ /* user not present in list */
+ return -1;
+}
+
+/* Add a new FloorRequest to the list of requests made by this user */
+int bfcp_add_user_request(unsigned long int ConferenceID, unsigned short int TransactionID, lusers list_users, unsigned short int userID, int position_floor, int sockfd, int y)
+{
+ if(userID <= 0)
+ return -1;
+ if(position_floor < 0)
+ return -1;
+ if(list_users == NULL)
+ return -1;
+
+ users temp_list_users;
+
+ if(position_floor >list_users->maxnumberfloors)
+ /* This floor is not in the conference */
+ return -1;
+
+ temp_list_users= list_users->users;
+ while((temp_list_users != NULL) && (temp_list_users->userID != userID))
+ temp_list_users = temp_list_users->next;
+
+ /* ifthe node is in the list, print it */
+ if((temp_list_users != NULL) && (temp_list_users->userID == userID)) {
+ if((temp_list_users->numberfloorrequest[position_floor]) >= list_users->max_number_floor_request) {
+ char errortext[200];
+ sprintf(errortext, "User %hu has already reached the maximum allowed number of requests (%i) for the same floor in Conference %lu", userID, list_users->max_number_floor_request, ConferenceID);
+ bfcp_error_code(ConferenceID, userID, TransactionID, BFCP_MAX_FLOORREQUESTS_REACHED, errortext, NULL, sockfd, y, list_users->bfcp_transport);
+ return -1;
+ } else
+ temp_list_users->numberfloorrequest[position_floor] = temp_list_users->numberfloorrequest[position_floor]+1;
+ } else
+ /* This user is not in the list */
+ return -1;
+
+ return 0;
+}
+
+/* Check ifthis user has already reached the max number of requests that can be made for this floor */
+int bfcp_is_floor_request_full(unsigned long int ConferenceID, unsigned short int TransactionID, lusers list_users, unsigned short int userID, int position_floor, int sockfd, int y)
+{
+ if(userID <= 0)
+ return -1;
+ if(position_floor < 0)
+ return -1;
+ if(list_users == NULL)
+ return -1;
+
+ users temp_list_users;
+
+ if(position_floor > list_users->maxnumberfloors)
+ /* This floor is not in the conference */
+ return -1;
+
+ temp_list_users = list_users->users;
+ if(temp_list_users==NULL)
+ return -1;
+
+ while((temp_list_users != NULL) && (temp_list_users->userID != userID))
+ temp_list_users = temp_list_users->next;
+
+ /* ifthe node is in the list, print it */
+ if((temp_list_users != NULL) && (temp_list_users->userID == userID)) {
+ if(temp_list_users->numberfloorrequest[position_floor] >= list_users->max_number_floor_request) {
+ char errortext[200];
+ sprintf(errortext, "User %hu has already reached the maximum allowed number of requests (%i) for the same floor in Conference %lu", userID, list_users->max_number_floor_request, ConferenceID);
+ bfcp_error_code(ConferenceID, userID, TransactionID, BFCP_MAX_FLOORREQUESTS_REACHED, errortext, NULL, sockfd, y, list_users->bfcp_transport);
+ return -1;
+ }
+ }
+
+ return(0);
+}
+
+/* Clean all requests made by all users of this list regarding a specific floor */
+int bfcp_clean_all_users_request_of_a_floor(lusers list_users, unsigned short int floorID)
+{
+ if(list_users == NULL)
+ return -1;
+ if(floorID <= 0)
+ return -1;
+
+ users temp_list_users;
+
+ if(floorID > list_users->maxnumberfloors+1)
+ /* This floor is not in the conference */
+ return -1;
+
+ temp_list_users = list_users->users;
+
+ for(temp_list_users = list_users->users; temp_list_users; temp_list_users = temp_list_users->next)
+ temp_list_users->numberfloorrequest[floorID-1] = 0;
+
+ return(0);
+}
+
+/* Stop handling a specific floor in this list and remove it */
+int bfcp_delete_a_floor_from_user_list(lusers list_users, unsigned short int floorID)
+{
+ if(list_users == NULL)
+ return -1;
+
+ users temp_list_users;
+ int i;
+ int *list_floors;
+
+ if(floorID>list_users->maxnumberfloors+1)
+ /* This floor is not in the conference */
+ return -1;
+
+ temp_list_users = list_users->users;
+
+ for(temp_list_users = list_users->users; temp_list_users; temp_list_users = temp_list_users->next) {
+ for(i = floorID + 1; i < list_users->maxnumberfloors; i++)
+ temp_list_users->numberfloorrequest[i-1] = temp_list_users->numberfloorrequest[i];
+ temp_list_users->numberfloorrequest[i-1] = 0;
+
+ list_floors = (int *)realloc(temp_list_users->numberfloorrequest, (list_users->maxnumberfloors+1)*sizeof(int));
+ if(list_floors == NULL)
+ return -1;
+ }
+
+ list_users->maxnumberfloors = list_users->maxnumberfloors - 1;
+
+ return(0);
+}
+
+/* Decrease the number of requests made by a user for a floor */
+int bfcp_deleted_user_request(lusers list_users, unsigned short int userID, int position_floor)
+{
+ if(list_users == NULL)
+ return -1;
+ if(userID <= 0)
+ return -1;
+ if(position_floor < 0)
+ return -1;
+
+ users temp_list_users;
+
+ if(position_floor>list_users->maxnumberfloors)
+ /* This floor is not in this list */
+ return -1;
+
+ temp_list_users = list_users->users;
+
+ while(temp_list_users && (temp_list_users->userID != userID))
+ temp_list_users = temp_list_users->next;
+
+ if(temp_list_users && (temp_list_users->userID == userID)) {
+ if(temp_list_users->numberfloorrequest[position_floor] > 0)
+ temp_list_users->numberfloorrequest[position_floor] = temp_list_users->numberfloorrequest[position_floor] -1;
+ } else
+ /* This user is not in the list */
+ return -1;
+
+ return(0);
+}
+
+/* Remove all users from a list */
+int bfcp_clean_user_list(lusers list_users)
+{
+ if(list_users == NULL)
+ return -1;
+
+ users temp_list_users, temp;
+
+ temp_list_users= list_users->users;
+ if(temp_list_users == NULL)
+ return 0;
+
+ while(temp_list_users) {
+ temp = temp_list_users;
+ temp_list_users = temp_list_users->next;
+ free(temp->user_URI);
+ temp->user_URI = NULL;
+ free(temp->user_display_name);
+ temp->user_display_name = NULL;
+ free(temp->numberfloorrequest);
+ temp->numberfloorrequest = NULL;
+ free(temp);
+ temp = NULL;
+ }
+
+ list_users->users=NULL;
+ return(0);
+}
+
+/* Free a linked list of users */
+int bfcp_remove_user_list(bfcp_list_users **lusers_p)
+{
+ if(lusers_p == NULL)
+ return 0;
+
+ int error;
+ bfcp_list_users *lusers = *lusers_p;
+
+ error = bfcp_clean_user_list(lusers);
+
+ if(error == 0) {
+ free(lusers);
+ lusers = NULL;
+ *lusers_p = NULL;
+ } else
+ return -1;
+
+ return(0);
+
+}
+
+/* Convert a 'bfcp_user' info to 'bfcp_user_information' (bfcp_messages.h) */
+bfcp_user_information *bfcp_show_user_information(lusers list_users, unsigned short int userID)
+{
+ if(list_users == NULL)
+ return NULL;
+ if(userID <= 0)
+ return NULL;
+
+ users temp_list_users;
+ bfcp_user_information *user_info;
+
+ temp_list_users = list_users->users;
+
+ while(temp_list_users && temp_list_users->userID!= userID)
+ temp_list_users = temp_list_users->next;
+
+ /* ifthe node is in the list, convert it to a 'bfcp_user_information' */
+ if(temp_list_users && (temp_list_users->userID == userID))
+ user_info = bfcp_new_user_information(temp_list_users->userID, temp_list_users->user_display_name, temp_list_users->user_URI);
+ else
+ /* This user is not in the list */
+ return NULL;
+
+ return user_info;
+}
+
+/* Get the CSP URI for this BFCP UserID */
+char *bfcp_obtain_userURI(lusers list_users, unsigned short int userID)
+{
+ if(userID <= 0)
+ return NULL;
+ if(list_users == NULL)
+ return NULL;
+
+ users temp_list_users;
+
+ temp_list_users= list_users->users;
+ while((temp_list_users != NULL) && (temp_list_users->userID != userID))
+ temp_list_users = temp_list_users->next;
+
+ /* ifthe node is in the list, return the URI information */
+ if((temp_list_users != NULL) && (temp_list_users->userID == userID))
+ return temp_list_users->user_URI;
+ else
+ return NULL;
+}
+
+/* Get the Display Name for this BFCP UserID */
+char *bfcp_obtain_user_display_name(lusers list_users, unsigned short int userID)
+{
+ if(userID <= 0)
+ return NULL;
+ if(list_users == NULL)
+ return NULL;
+
+ users temp_list_users;
+
+ temp_list_users= list_users->users;
+ while((temp_list_users != NULL) && (temp_list_users->userID != userID))
+ temp_list_users = temp_list_users->next;
+
+ if((temp_list_users != NULL) && (temp_list_users->userID == userID))
+ return temp_list_users->user_display_name;
+ else
+ return NULL;
+}
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_user_list.h b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_user_list.h
new file mode 100644
index 00000000000..ba8caff442d
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/bfcp_user_list.h
@@ -0,0 +1,116 @@
+#ifndef _BFCP_USER_LIST_H
+#define _BFCP_USER_LIST_H
+
+#include
+#include
+#include
+
+/* Needed for TCP/TLS/BFCP support */
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* The BFCP messages building/parsing library */
+#include
+
+enum chair_type {NO_CHAIR = 0, CHAIR};
+
+/* BFCP Participant (User) */
+typedef struct bfcp_user {
+ unsigned short int userID; /* UserID */
+ char *user_URI; /* Call Signaling Protocol URI */
+ char *user_display_name; /* User-friendly Display Name */
+ int *numberfloorrequest; /* Number of floor requests made by this user for each floor in the conference */
+ struct sockaddr_in *client_addr;/* Socket address of participant, used in case of UDP socket*/
+ int fd; /* socket fd of client*/
+ struct bfcp_user *next; /* Next user in the list */
+} bfcp_user;
+/* Pointer to a specific user */
+typedef bfcp_user *users;
+
+/* List of participants to the conference */
+typedef struct bfcp_list_users {
+ int bfcp_transport; /* BFCP/TCP (0) or BFCP/TLS (1) */
+ unsigned short int max_number_floor_request; /* Policy regarding the max allowed number of requests each user can make for a specific floor */
+ unsigned short int maxnumberfloors; /* The max number of allowed floors in this conference */
+ struct bfcp_user *users; /* The linked list of all users in the conference */
+} bfcp_list_users;
+/* Pointer to a specific list of users */
+typedef bfcp_list_users *lusers;
+
+
+/************************/
+/* User-related methods */
+/************************/
+
+/* Create a new linked list of users */
+struct bfcp_list_users *bfcp_create_user_list (unsigned short int Max_Number_Floor_Request, unsigned short int Num_floors);
+/* Check if participant with such userID exists in this list */
+int bfcp_existence_user(lusers list_users, unsigned short int userID);
+/* Change the allowed number of per-floor requests for this list */
+int bfcp_change_user_req_floors(lusers list_users, unsigned short int Max_Number_Floor_Request);
+/* Change the allowed number of floors in the conference for this list */
+int bfcp_change_number_users_floors(lusers list_users, unsigned short int Num_floors);
+/* Add a new user to this list */
+int bfcp_add_user(lusers list_users, unsigned short int userID, char *user_URI, char *user_display_name);
+
+/*!
+ \brief Set address of user in this list
+ \param list_users Pointer to a specific list of users
+ \param userID BFCP userID
+ \param client_address char pointer to IP addrss of user
+ \param client_port Port at which user is listening
+ \return 0, If client_address successfully set else return -1
+ */
+int bfcp_set_user_address(lusers list_users, unsigned short int userID, char *client_address, unsigned short int client_port);
+
+/*!
+ \brief Retrieve address of user
+ \param list_users Pointer to a specific list of users
+ \param userID BFCP userID
+ \return Socket address of user of type struct sockaddr_in*
+ */
+struct sockaddr_in *bfcp_get_user_address(lusers list_users, unsigned short int userID);
+
+/*!
+ \brief Set socket file descriptor to user list
+ \param list_users Pointer to a specific list of users
+ \param userID BFCP userID
+ \param sockfd File descriptor of user
+ \return 0, If successfully set else return -1
+ */
+int bfcp_set_user_sockfd(lusers list_users, unsigned short int userID, int sockfd);
+
+/* Delete an existing user from this list */
+int bfcp_delete_user(lusers list_users, unsigned short int userID);
+/* Add a new FloorRequest to the list of requests made by this user */
+int bfcp_add_user_request(unsigned long int ConferenceID, unsigned short int TransactionID, lusers list_users, unsigned short int userID, int position_floor, int sockfd, int y);
+/* Check if this user has already reached the max number of requests that can be made for this floor */
+int bfcp_is_floor_request_full(unsigned long int ConferenceID, unsigned short int TransactionID, lusers list_users, unsigned short int userID, int position_floor, int sockfd, int y);
+/* Clean all requests made by all users of this list regarding a specific floor */
+int bfcp_clean_all_users_request_of_a_floor(lusers list_users, unsigned short int floorID);
+/* Stop handling a specific floor in this list and remove it */
+int bfcp_delete_a_floor_from_user_list(lusers list_users, unsigned short int floorID);
+/* Decrease the number of requests made by a user for a floor */
+int bfcp_deleted_user_request(lusers list_users, unsigned short int userID, int position_floor);
+/* Remove all users from a list */
+int bfcp_clean_user_list(lusers list_users);
+/* Free a linked list of users */
+int bfcp_remove_user_list(bfcp_list_users **lusers_p);
+/* Convert a 'bfcp_user' info to 'bfcp_user_information' (bfcp_messages.h) */
+bfcp_user_information *bfcp_show_user_information(lusers list_users, unsigned short int userID);
+
+
+/******************/
+/* Helper methods */
+/******************/
+
+/* Get the CSP URI for this BFCP UserID */
+char *bfcp_obtain_userURI(lusers list_users, unsigned short int userID);
+/* Get the Display Name for this BFCP UserID */
+char *bfcp_obtain_user_display_name(lusers list_users, unsigned short int userID);
+
+#endif
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/main.c b/libs/libbfcp/bfcpsrvclt/bfcpsrv/main.c
new file mode 100644
index 00000000000..5b0c4dbc601
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/main.c
@@ -0,0 +1,477 @@
+#include "bfcp_server.h"
+#include
+
+
+/* Helper Macro to check for integer errors */
+#define BFCP_CHECK_INTEGER \
+ if(error == 0) { \
+ printf("An integer is needed!\n"); \
+ break; \
+ }
+
+
+/* Headers */
+void menu(char *lineptr);
+int received_msg(bfcp_arguments *arguments, int outgoing);
+void print_requests_list(bfcp server, int index, int status);
+
+
+/* Callback to receive notifications from the underlying library about incoming BFCP messages */
+int received_msg(bfcp_arguments *arguments, int outgoing)
+{
+ if(!arguments) {
+ printf("Invalid arguments in the received message...\n");
+ return -1;
+ }
+ if(!arguments->entity) {
+ printf("Invalid IDs in the message header...\n");
+ bfcp_free_arguments(arguments);
+ return -1;
+ }
+ unsigned long int conferenceID = arguments->entity->conferenceID;
+ unsigned short int userID = arguments->entity->userID;
+ unsigned short int transactionID = arguments->entity->transactionID;
+
+ if (arguments->primitive <= 13) {
+ printf("(%lu/%d/%d) %s %s\n", conferenceID, transactionID, userID, outgoing ? "--->" :"<---", bfcp_primitive[arguments->primitive-1].description);
+ } else {
+ printf("(%lu/%d/%d) %s %s\n", conferenceID, transactionID, userID, outgoing ? "--->" :"<---", "UNKNOWN PRIMITIVE");
+ }
+
+ return 0;
+}
+
+
+/* Menu to manipulate the Floor Control Server options and operations */
+void menu(char *lineptr)
+{
+ char line[80];
+ unsigned long int conferenceID = 0;
+ bfcp list = NULL, server = NULL;
+ int transport = 0, error = 0, max_num = 0, port = 0, Max_Num_Floors = 0,
+ Max_Number_Floor_Request = 0, chair_automatic_accepted_policy = 0,
+ chair_wait_request = 0, status = 0, limit_granted_floor = 0, i = 0, j = 0;
+ unsigned int floorID = 0, chairID = 0, userID = 0;
+ bfcp_conference *lconferences = NULL;
+ bfcp_list_floors *list_floor = NULL;
+ bfcp_list_users *list_user = NULL;
+ bfcp_user *user = NULL;
+ floor_query *query = NULL;
+ char *text = NULL, *text1 = NULL;
+
+ list = NULL;
+
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "\n--------CONFERENCE SERVER-----------------------------------\n",
+ " ? - Show the menu\n",
+ " c - Create the FCS\n",
+ " y - Destroy the FCS\n",
+ " i - Insert a new conference\n",
+ " d - Delete a conference\n",
+ " a - Add a new floor\n",
+ " f - Delete a floor\n",
+ " r - Add a floor chair\n",
+ " g - Delete a floor chair\n",
+ " j - Add a new user\n",
+ " k - Delete a user\n",
+ " h - Change the max number of conferences\n",
+ " w - Change number of users that can be granted the same floor at the same time\n"
+ " b - Change the chair policy\n",
+ " u - Change maximum number of requests a user can make for the same floor\n",
+ " s - Show the conferences in the BFCP server\n",
+ " q - Quit\n",
+ "------------------------------------------------------------------\n\n");
+ while(fgets(line, 79, stdin) != NULL) {
+ lineptr = line;
+ while(*lineptr == ' ' || *lineptr == '\t')
+ ++lineptr;
+ switch(*lineptr) {
+ case '?':
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "\n--------CONFERENCE SERVER-----------------------------------\n",
+ " ? - Show the menu\n",
+ " c - Create the FCS\n",
+ " y - Destroy the FCS\n",
+ " i - Insert a new conference\n",
+ " d - Delete a conference\n",
+ " a - Add a new floor\n",
+ " f - Delete a floor\n",
+ " r - Add a floor chair\n",
+ " g - Delete a floor chair\n",
+ " j - Add a new user\n",
+ " k - Delete a user\n",
+ " h - Change the max number of conferences\n",
+ " w - Change number of users that can be granted the same floor at the same time\n"
+ " b - Change the chair policy\n",
+ " u - Change maximum number of requests a user can make for the same floor\n",
+ " s - Show the conferences in the BFCP server\n",
+ " q - Quit\n",
+ "--------------------------------------------------------------\n\n");
+ break;
+ case 'c':
+ ++lineptr;
+ printf("Enter the maximum number of allowed concurrent conferences in the system:\n");
+ error = scanf("%i", &max_num);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the listening port for the FCS:\n");
+ error = scanf("%i", &port);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the desired transport for the BFCP messages\n\t(0 for TCP/BFCP, 1 for TCP/TLS/BFCP, 2 for UDP/BFCP):\n");
+ error = scanf ("%i", &transport);
+ BFCP_CHECK_INTEGER;
+ list = bfcp_initialize_bfcp_server(max_num, port, received_msg, transport, "server.pem", "server.key", "0.0.0.0");
+ if(list == NULL)
+ printf("Couldn't create the FCS (is the port already taken?)...\n");
+ else
+ printf("FCS created.\n");
+ break;
+ case 'i':
+ ++lineptr;
+ printf("Enter the desired ConferenceID for the conference:\n");
+ error = scanf("%li", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the maximum number of floors you want in this conference:\n");
+ error = scanf("%i", &Max_Num_Floors);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the maximum number of requests a user can make for the same floor:\n");
+ error = scanf("%i", &Max_Number_Floor_Request);
+ BFCP_CHECK_INTEGER;
+ printf("Automated policy when chair is missing:\n\t0 = accept the request / 1 = don't\n");
+ error = scanf("%u", &chair_automatic_accepted_policy);
+ BFCP_CHECK_INTEGER;
+ printf("Time in seconds the system will wait for a ChairAction: (0 for default number)\n");
+ error = scanf("%i", &chair_wait_request);
+ BFCP_CHECK_INTEGER;
+
+ if(bfcp_initialize_conference_server(list, conferenceID, Max_Num_Floors, Max_Number_Floor_Request, chair_automatic_accepted_policy, chair_wait_request) < 0)
+ printf("Couldn't add the conference %lu to the FCS...\n", conferenceID);
+ else
+ printf("Conference added.\n");
+ break;
+ case 'd':
+ ++lineptr;
+ printf("Enter the conference you want to remove:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_destroy_conference_server(list, conferenceID) < 0)
+ printf("Couldn't remove the conference %lu from the FCS...\n", conferenceID);
+ else
+ printf("Conference removed.\n");
+ break;
+ case 'h':
+ ++lineptr;
+ printf("Enter the maximum allowed number of concurrent conferences you want to have:\n");
+ error = scanf("%i", &max_num);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_change_number_bfcp_conferences_server(list, max_num) < 0)
+ printf("Couldn't change the maximum allowed number of concurrent conferences...\n");
+ else
+ printf("Setting changed.\n");
+ break;
+ case 'u':
+ ++lineptr;
+ printf("Enter the maximum number of requests a user can make for the same floor:\n");
+ error = scanf("%i", &max_num);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_change_user_req_floors_server(list, max_num) < 0)
+ printf("Couldn't the maximum number of requests a user can make for the same floor:\n");
+ else
+ printf("Setting changed.\n");
+ break;
+ case 'y':
+ ++lineptr;
+ error = bfcp_destroy_bfcp_server(&list);
+ if(error < 0)
+ printf("Couldn't destroy the FCS...\n");
+ else
+ printf("FCS destroyed.\n");
+ break;
+ case 's':
+ ++lineptr;
+ server = list;
+ if(server == NULL) {
+ printf("The Floor Control Server is not up\n");
+ break;
+ }
+ lconferences = server->list_conferences;
+ if(lconferences == NULL) {
+ printf("There are no conferences in the FCS\n");
+ break;
+ }
+
+ if(server->Actual_number_conference == 0) {
+ printf("There are no conferences in the FCS\n");
+ break;
+ }
+
+ for(i = 0; i < server->Actual_number_conference; i++) {
+ printf("CONFERENCE:\n");
+ printf("ConferenceID: %lu\n", server->list_conferences[i].conferenceID);
+ printf("\n");
+ /* Print the list of floors */
+ list_floor = server->list_conferences[i].floor;
+ if(list_floor != NULL) {
+ printf("Maximum number of floors in the conference: %i\n", list_floor->number_floors + 1);
+ printf("FLOORS\n");
+ for(j = 0; j < list_floor->actual_number_floors; j++) {
+ printf("FloorID: %u, ", list_floor->floors[j].floorID);
+ printf("ChairID: %u", list_floor->floors[j].chairID);
+ if(list_floor->floors[j].floorState == BFCP_FLOOR_STATE_WAITING)
+ printf(" state: FREE\n");
+ else if(list_floor->floors[j].floorState == BFCP_FLOOR_STATE_ACCEPTED)
+ printf(" state: ACCEPTED\n");
+ else if(list_floor->floors[j].floorState >= BFCP_FLOOR_STATE_GRANTED)
+ printf(" state: GRANTED\n");
+ else
+ printf(" state: error!\n");
+ printf("Number of simultaneous granted users:% i\n", list_floor->floors[j].limit_granted_floor-1);
+ query = list_floor->floors[j].floorquery;
+ if(query != NULL)
+ printf("QUERY LIST\n");
+ while(query) {
+ printf("User: %hu\n",query->userID);
+ query = query->next;
+ }
+ }
+ }
+ /* Print the list of users */
+ list_user = server->list_conferences[i].user;
+ if(list_user != NULL) {
+ user = list_user->users;
+ printf("Maximum number of request per floors in the conference: %i\n", list_user->max_number_floor_request);
+ printf("USERS\n");
+ while(user) {
+ printf("UserID: %hu\n", user->userID);
+ user = user->next;
+ }
+ }
+ /* Print the list of Pending requests */
+ print_requests_list(server, i, BFCP_PENDING);
+ /* Print the list of Accepted requests */
+ print_requests_list(server, i, BFCP_ACCEPTED);
+ /* Print the list of Granted requests */
+ print_requests_list(server, i, BFCP_GRANTED);
+ }
+ printf("\n");
+ break;
+ case 'a':
+ ++lineptr;
+ printf("Enter the conference you want to add a new floor to:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the desired FloorID:\n");
+ error = scanf("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ printf("If a chair will manage this floor, enter its UserID\n\t(ChairID, 0 if no chair):\n");
+ error = scanf("%u", &chairID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the maximum number of users that can be granted this floor at the same time\n\t(0 for unlimited users):\n");
+ error = scanf("%u", &limit_granted_floor);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_add_floor_server(list, conferenceID, floorID, chairID, limit_granted_floor) < 0)
+ printf("Coudln't add the new floor...\n");
+ else
+ printf("Floor added.\n");
+ break;
+ case 'f':
+ ++lineptr;
+ printf("Enter the conference you want to remove the floor from:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the FloorID you want to remove:\n");
+ error = scanf("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_delete_floor_server(list, conferenceID, floorID) < 0)
+ printf("Coudln't remove the floor...\n");
+ else
+ printf("Floor removed.\n");
+ break;
+ case 'r':
+ ++lineptr;
+ printf("Enter the conference you want to add a new chair to:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the FloorID this new chair will manage:\n");
+ error = scanf("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the UserID of the chair (ChairID):\n");
+ error = scanf("%u", &chairID);
+ BFCP_CHECK_INTEGER;
+ error = bfcp_add_chair_server(list, conferenceID, floorID, chairID);
+ if(error == 0)
+ printf("Chair successfully added\n");
+ else if(error == -1)
+ printf("Couldn't setup the new chair...\n");
+ break;
+ case 'g':
+ ++lineptr;
+ printf("Enter the conference you want to remove a chair from:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the FloorID the chair is currently handling:\n");
+ error = scanf("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ error = bfcp_delete_chair_server(list, conferenceID, floorID);
+ if(error == 0)
+ printf("Chair successfully removed\n");
+ else if(error == -1)
+ printf("Couldn't remove the chair...\n");
+ break;
+ case 'j':
+ ++lineptr;
+ printf("Enter the conference you want to add a new user to:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the UserID:\n");
+ error = scanf("%u", &userID);
+ BFCP_CHECK_INTEGER;
+#ifndef WIN32
+ printf("Enter the user's URI (e.g. bob@example.com):\n");
+ scanf(" %a[^\n]", &text);
+ printf("Enter the user's display name (e.g. Bob Hoskins):\n");
+ scanf(" %a[^\n]", &text1);
+#else
+ /* FIXME fix broken scanf in WIN32 */
+ text = calloc(10, sizeof(char));
+ sprintf(text, "User %u", userID);
+ text1 = calloc(20, sizeof(char));
+ sprintf(text1, "user%u@localhost", userID);
+ printf("Defaulting URI and Display to '%s':'%s'...\n", text, text1);
+#endif
+ if(bfcp_add_user_server(list, conferenceID, userID, text, text1) < 0)
+ printf("Couldn't add the new user...\n");
+ else
+ printf("User added.\n");
+ free(text);
+ free(text1);
+ break;
+ case 'k':
+ ++lineptr;
+ printf("Enter the conference you want to remove the user from:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the UserID:\n");
+ error = scanf("%u", &userID);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_delete_user_server(list, conferenceID, userID) < 0)
+ printf("Couldn't remove the user...\n");
+ else
+ printf("User removed.\n");
+ break;
+ case 'w':
+ ++lineptr;
+ printf("Enter the conference for which you want to change the maximum number of users that can be granted the same floor at the same time:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the FloorID:\n");
+ error = scanf("%u", &floorID);
+ BFCP_CHECK_INTEGER;
+ printf("Enter the maximum number of users that can be granted this floor at the same time:\n");
+ error = scanf("%u", &limit_granted_floor);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_change_number_granted_floor_server(list, conferenceID, floorID, limit_granted_floor) < 0)
+ printf("Couldn't change the settings for this conference...\n");
+ else
+ printf("Setting changed.\n");
+ break;
+ case 'b':
+ ++lineptr;
+ printf("Enter conference for which you want to change the automated accept policy:\n");
+ error = scanf("%lu", &conferenceID);
+ BFCP_CHECK_INTEGER;
+ printf("Automated policy when chair is missing:\n\t0 = accept the request / 1 = don't\n");
+ error = scanf("%u", &chair_automatic_accepted_policy);
+ BFCP_CHECK_INTEGER;
+ printf("Time in seconds the system will wait for a ChairAction: (0 for default number)\n");
+ error = scanf("%i", &chair_wait_request);
+ BFCP_CHECK_INTEGER;
+ if(bfcp_change_chair_policy(list, conferenceID, chair_automatic_accepted_policy, chair_wait_request) < 0)
+ printf("Couldn't change the settings for this conference...\n");
+ else
+ printf("Setting changed.\n");
+ break;
+ case 'q':
+ status = 0;
+ return;
+ break;
+ case '\n':
+ break;
+ default:
+ printf("Invalid menu choice - try again\n");
+ break;
+ }
+ }
+}
+
+
+/* Helper method to print the list of requests */
+void print_requests_list(bfcp server, int index, int status)
+{
+ if(!server)
+ return;
+
+ bfcp_queue *list = NULL;
+ bfcp_node *node = NULL;
+ floor_request_query *query_floorrequest = NULL;
+
+ switch(status) {
+ case BFCP_PENDING:
+ list = server->list_conferences[index].pending;
+ break;
+ case BFCP_ACCEPTED:
+ list = server->list_conferences[index].accepted;
+ break;
+ case BFCP_GRANTED:
+ list = server->list_conferences[index].granted;
+ break;
+ default:
+ break;
+ }
+
+ bfcp_floor *FloorID = NULL;
+
+ if(list != NULL) {
+ node = list->head;
+ if(node)
+ printf("%s LIST\n", bfcp_status[status-1].description);
+ while(node != NULL) {
+ printf("FloorRequestID: %hu\n\tUserID: %hu Priority: %i Queue_position: %hu ", node->floorRequestID, node->userID, node->priority, node->queue_position);
+ if(node->beneficiaryID != 0)
+ printf("BeneficiaryID: %hu", node->beneficiaryID);
+ printf("\n");
+ FloorID = node->floor;
+ while(FloorID) {
+ printf("FloorID: %hu ", FloorID->floorID);
+ if(FloorID->chair_info != NULL)
+ printf("Chair-provided information: %s ", FloorID->chair_info);
+ if(FloorID->status == BFCP_FLOOR_STATE_WAITING)
+ printf(" state: FREE\n");
+ else if(FloorID->status == BFCP_FLOOR_STATE_ACCEPTED)
+ printf(" state: ACCEPTED\n");
+ else if(FloorID->status >= BFCP_FLOOR_STATE_GRANTED)
+ printf(" state: GRANTED\n");
+ else
+ printf(" state: error!\n");
+ FloorID = FloorID->next;
+ }
+ query_floorrequest = node->floorrequest;
+ while(query_floorrequest) {
+ printf("FloorRequest query: %hu\n", query_floorrequest->userID);
+ query_floorrequest = query_floorrequest->next;
+ }
+ node = node->next;
+ printf("-----------------\n");
+ }
+ }
+}
+
+
+/* Main */
+int main (int argc, char *argv[])
+{
+ char *lineptr = NULL;
+ printf("\nBinary Floor Control Protocol (BFCP) Floor Control Server (FCS) Tester\n\n");
+ menu(lineptr);
+
+ return 0;
+}
diff --git a/libs/libbfcp/bfcpsrvclt/bfcpsrv/stress_server.c b/libs/libbfcp/bfcpsrvclt/bfcpsrv/stress_server.c
new file mode 100644
index 00000000000..6ecd8d56155
--- /dev/null
+++ b/libs/libbfcp/bfcpsrvclt/bfcpsrv/stress_server.c
@@ -0,0 +1,97 @@
+#include "bfcp_server.h"
+#include
+
+
+/* Helper Macro to check for integer errors */
+#define BFCP_CHECK_INTEGER \
+ if(error == 0) { \
+ printf("An integer is needed!\n"); \
+ break; \
+ }
+
+
+/* Headers */
+void menu(char *lineptr);
+int received_msg(bfcp_arguments *arguments, int outgoing);
+
+
+/* Callback to receive notifications from the underlying library about incoming BFCP messages */
+int received_msg(bfcp_arguments *arguments, int outgoing)
+{
+ if(!arguments) {
+ printf("Invalid arguments in the received message...\n");
+ return -1;
+ }
+ if(!arguments->entity) {
+ printf("Invalid IDs in the message header...\n");
+ bfcp_free_arguments(arguments);
+ return -1;
+ }
+ unsigned long int conferenceID = arguments->entity->conferenceID;
+ unsigned short int userID = arguments->entity->userID;
+ unsigned short int transactionID = arguments->entity->transactionID;
+
+ if(arguments != NULL)
+ printf("(%lu/%d/%d) %s %s\n", conferenceID, transactionID, userID, outgoing ? "--->" :"<---", bfcp_primitive[arguments->primitive-1].description);
+
+ return 0;
+}
+
+
+/* Menu to manipulate the Floor Control Server options and operations */
+void menu(char *lineptr)
+{
+ unsigned long int conferenceID = 0;
+ bfcp list = NULL;
+ int i = 0;
+ unsigned int userID = 0;
+ char *text = NULL, *text1 = NULL;
+
+ list = bfcp_initialize_bfcp_server(1, 2345, received_msg, 0, "server.pem", "server.key");
+ if(list == NULL) {
+ printf("Couldn't create the FCS (is the port already taken?)...\n");
+ return;
+ } else
+ printf("FCS created.\n");
+
+ conferenceID = 8771000;
+ if(bfcp_initialize_conference_server(list, conferenceID, 2, 1, 0, 0) < 0) {
+ printf("Couldn't add the conference %lu to the FCS...\n", conferenceID);
+ return;
+ } else
+ printf("Conference added.\n");
+
+ if(bfcp_add_floor_server(list, conferenceID, 11, 0, 0) < 0) {
+ printf("Coudln't add the new floor...\n");
+ return;
+ } else
+ printf("Floor added.\n");
+
+ for(i=0; i < 190; i++) {
+ userID = i+1;
+ text = calloc(10, sizeof(char));
+ sprintf(text, "User %u", userID);
+ text1 = calloc(20, sizeof(char));
+ sprintf(text1, "user%u@localhost", userID);
+ if(bfcp_add_user_server(list, conferenceID, userID, text, text1) < 0)
+ printf("Couldn't add the new user...\n");
+ else
+ printf("User %hu added.\n", userID);
+ free(text);
+ free(text1);
+ }
+
+ while(1)
+ sleep(1);
+}
+
+
+/* Main */
+int main (int argc, char *argv[])
+{
+ char *lineptr = NULL;
+ printf("\nBinary Floor Control Protocol (BFCP) Floor Control Server (FCS) Tester\n\n");
+ menu(lineptr);
+
+ return 0;
+}
diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
index bb9221f1099..a4c3ece4bc8 100644
--- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
+++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
@@ -1344,6 +1344,19 @@ static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result)
return;
}
+ if (sdp_media_has_bfcp(m)) {
+ if (*r) {
+ r += strspn(r, SPACE TAB);
+ if (!su_casematch(r, "*")) {
+ parsing_error(p, "m= invalid format for BFCP protocol, payload_code can only be an *");
+ return;
+ }
+ } else {
+ parsing_error(p, "m= invalid format for BFCP protocol, payload code * missing");
+ return;
+ }
+ }
+
/* "normal" format list */
if (*r) {
sdp_list_t **fmt = &m->m_format;
@@ -1422,6 +1435,12 @@ void sdp_media_transport(sdp_media_t *m, char const *s)
m->m_proto = sdp_proto_tcp, m->m_proto_name = "TCP";
else if (su_casematch(s, "TLS"))
m->m_proto = sdp_proto_tls, m->m_proto_name = "TLS";
+ else if (su_casematch(s, "UDP/BFCP"))
+ m->m_proto = sdp_proto_udp_bfcp, m->m_proto_name = "UDP/BFCP";
+ else if (su_casematch(s, "TCP/BFCP"))
+ m->m_proto = sdp_proto_tcp_bfcp, m->m_proto_name = "TCP/BFCP";
+ else if (su_casematch(s, "TCP/TLS/BFCP"))
+ m->m_proto = sdp_proto_tcp_tls_bfcp, m->m_proto_name = "TCP/TLS/BFCP";
else
m->m_proto = sdp_proto_x, m->m_proto_name = s;
}
@@ -1432,6 +1451,12 @@ int sdp_media_has_rtp(sdp_media_t const *m)
return m && (m->m_proto == sdp_proto_rtp || m->m_proto == sdp_proto_srtp || m->m_proto == sdp_proto_extended_srtp || m->m_proto == sdp_proto_extended_rtp);
}
+/** Check if media uses BFCP as its transport protocol. */
+int sdp_media_has_bfcp(sdp_media_t const *m)
+{
+ return m && (m->m_proto == sdp_proto_udp_bfcp || m->m_proto == sdp_proto_tcp_bfcp || m->m_proto == sdp_proto_tcp_tls_bfcp);
+}
+
#define RTPMAP(pt, encoding, rate, params) \
{ sizeof(sdp_rtpmap_t), NULL, encoding, rate, (char *)params, NULL, 1, pt, 0 }
diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h b/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
index bf0741e0449..03668141f0e 100644
--- a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
+++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
@@ -250,7 +250,10 @@ typedef enum
sdp_proto_extended_srtp = 261, /** WEBRTC SAVPF */
sdp_proto_extended_rtp = 262, /** WEBRTC AVPF */
sdp_proto_tls = 511, /**< TLS over TCP */
- sdp_proto_any = 512 /**< * wildcard */
+ sdp_proto_any = 512, /**< * wildcard */
+ sdp_proto_tcp_bfcp = 514, /* SDP transport id for TCP/BFCP */
+ sdp_proto_tcp_tls_bfcp = 515, /* SDP transport id for TCP/TLS/BFCP */
+ sdp_proto_udp_bfcp = 516 /* SDP transport id for UDP/BFCP */
} sdp_proto_e;
/** Session mode. @note Identical to rtp_mode_t. */
@@ -432,6 +435,9 @@ SOFIAPUBFUN sdp_connection_t *sdp_media_connections(sdp_media_t const *m);
/** Check if media uses RTP as its transport protocol */
SOFIAPUBFUN int sdp_media_has_rtp(sdp_media_t const *m);
+/** Check if media uses BFCP as its transport protocol. */
+SOFIAPUBFUN int sdp_media_has_bfcp(sdp_media_t const *m);
+
/** Set media type */
SOFIAPUBFUN void sdp_media_type(sdp_media_t *m, char const *s);
diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h
index cb454c49836..e1f99b99869 100644
--- a/src/include/switch_core_media.h
+++ b/src/include/switch_core_media.h
@@ -90,6 +90,14 @@ typedef enum {
VAD_OUT = (1 << 1)
} switch_core_media_vflag_t;
+
+typedef struct media_attribute_s {
+ int a_size;
+ struct media_attribute_s *a_next;
+ char *a_name;
+ char *a_value;
+} media_attribute_t;
+
typedef struct switch_core_media_params_s {
uint32_t rtp_timeout_sec;
uint32_t rtp_hold_timeout_sec;
@@ -311,6 +319,7 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se
uint32_t channels,
uint8_t negotiated);
+SWITCH_DECLARE(void) switch_core_media_set_media_attribute(switch_core_session_t *session, media_attribute_t *media_attribute, switch_media_type_t type);
SWITCH_DECLARE(switch_status_t) switch_core_media_check_autoadj(switch_core_session_t *session);
SWITCH_DECLARE(switch_rtp_crypto_key_type_t) switch_core_media_crypto_str2type(const char *str);
SWITCH_DECLARE(const char *) switch_core_media_crypto_type2str(switch_rtp_crypto_key_type_t type);
@@ -318,7 +327,9 @@ SWITCH_DECLARE(int) switch_core_media_crypto_keysalt_len(switch_rtp_crypto_key_t
SWITCH_DECLARE(int) switch_core_media_crypto_salt_len(switch_rtp_crypto_key_type_t type);
SWITCH_DECLARE(char *) switch_core_media_filter_sdp(const char *sdp, const char *cmd, const char *arg);
SWITCH_DECLARE(char *) switch_core_media_process_sdp_filter(const char *sdp, const char *cmd_buf, switch_core_session_t *session);
-
+SWITCH_DECLARE(media_attribute_t *) switch_core_media_get_media_attribute(switch_core_session_t *session, switch_media_type_t type);
+SWITCH_DECLARE(payload_map_t *) switch_core_media_get_payload_map(switch_core_session_t *session, switch_media_type_t type);
+SWITCH_DECLARE(media_proto_name_t *) switch_core_media_get_media_protocol(switch_core_session_t *session, switch_media_type_t type);
SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_session_t *session,
switch_media_type_t mtype,
@@ -388,6 +399,22 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_print(switch_core_session_t
SWITCH_DECLARE(switch_status_t) switch_core_session_printf(switch_core_session_t *session, const char *fmt, ...);
SWITCH_DECLARE(switch_msrp_session_t *) switch_core_media_get_msrp_session(switch_core_session_t *session);
+
+/*!
+ \brief Retrieve the video_read codec from rtp_engine of current video
+ \param session session to retrieve from
+ \return a pointer to the codec
+*/
+SWITCH_DECLARE(switch_codec_t *) switch_core_media_get_video_read_codec(switch_core_session_t *session);
+
+/*!
+ \brief Retrieve the video_write codec from rtp_engine of current video
+ \param session session to retrieve from
+ \return a pointer to the codec
+*/
+SWITCH_DECLARE(switch_codec_t *) switch_core_media_get_video_write_codec(switch_core_session_t *session, int flag);
+
+
SWITCH_DECLARE(void) switch_core_media_set_smode(switch_core_session_t *session, switch_media_type_t type, switch_media_flow_t smode, switch_sdp_type_t sdp_type);
SWITCH_END_EXTERN_C
diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h
index 77e7b20e236..29314f6603c 100644
--- a/src/include/switch_loadable_module.h
+++ b/src/include/switch_loadable_module.h
@@ -292,6 +292,19 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs(const switch_codec_impleme
*/
SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_implementation_t **array, char fmtp_array[SWITCH_MAX_CODECS][MAX_FMTP_LEN], int arraylen, char **prefs, int preflen);
+
+/*!
+ \brief Retrieve the list of loaded codecs into an array based on another array showing the sorted order
+ \param array the array to populate
+ \param arraylen the max size in elements of the array
+ \param prefs the array of preferred codec names
+ \param preflen the size in elements of the
+ \param video_pt_count the pointer to array containing count of video payload count of each video media.
+ \return the number of elements added to the array
+ \note this function only considers codecs that are listed in the "prefs" array and ignores the rest.
+*/
+SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted2(const switch_codec_implementation_t **array, char fmtp_array[SWITCH_MAX_CODECS][MAX_FMTP_LEN], int arraylen, char **prefs, int preflen, int *video_pt_count);
+
/*!
\brief Execute a registered API command
\param cmd the name of the API command to execute
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 133422764b7..c79001289b2 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -213,10 +213,16 @@ SWITCH_BEGIN_EXTERN_C
#define SWITCH_REMOTE_MEDIA_PORT_VARIABLE "remote_media_port"
#define SWITCH_REMOTE_VIDEO_IP_VARIABLE "remote_video_ip"
#define SWITCH_REMOTE_VIDEO_PORT_VARIABLE "remote_video_port"
+#define SWITCH_REMOTE_PRESENTATION_IP_VARIABLE "remote_presentation_ip"
+#define SWITCH_REMOTE_PRESENTATION_PORT_VARIABLE "remote_presentation_port"
#define SWITCH_LOCAL_VIDEO_IP_VARIABLE "local_video_ip"
#define SWITCH_LOCAL_VIDEO_PORT_VARIABLE "local_video_port"
+#define SWITCH_LOCAL_PRESENTATION_IP_VARIABLE "local_presentation_ip"
+#define SWITCH_LOCAL_PRESENTATION_PORT_VARIABLE "local_presentation_port"
#define SWITCH_LOCAL_TEXT_IP_VARIABLE "local_text_ip"
#define SWITCH_LOCAL_TEXT_PORT_VARIABLE "local_text_port"
+#define SWITCH_LOCAL_APPLICATION_IP_VARIABLE "local_application_ip"
+#define SWITCH_LOCAL_APPLICATION_PORT_VARIABLE "local_application_port"
#define SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE "hangup_after_bridge"
#define SWITCH_PARK_AFTER_BRIDGE_VARIABLE "park_after_bridge"
#define SWITCH_PARK_AFTER_EARLY_BRIDGE_VARIABLE "park_after_early_bridge"
@@ -237,7 +243,7 @@ SWITCH_BEGIN_EXTERN_C
#define SWITCH_DEFAULT_FILE_BUFFER_LEN 65536
#define SWITCH_DTMF_LOG_LEN 1000
#define SWITCH_MAX_TRANS 2000
-#define SWITCH_CORE_SESSION_MAX_PRIVATES 2
+#define SWITCH_CORE_SESSION_MAX_PRIVATES 3
#define SWITCH_DEFAULT_VIDEO_SIZE 1200
#define SWITCH_RTCP_AUDIO_INTERVAL_MSEC "1000"
#define SWITCH_RTCP_VIDEO_INTERVAL_MSEC "1000"
@@ -245,6 +251,13 @@ SWITCH_BEGIN_EXTERN_C
#define TEXT_UNICODE_LINEFEED {0xe2, 0x80, 0xa8}
#define MAX_FMTP_LEN 256
+/* BFCP */
+/* Channel variable to store local sdp of BFCP media */
+#define SWITCH_BFCP_LOCAL_SDP "bfcp_local_sdp"
+/* channel variable to store local sdp of BFCP media of peer_session */
+#define SWITCH_PEER_BFCP_LOCAL_SDP "peer_bfcp_local_sdp"
+#define SWITCH_PEER_BFCP_USERID "peer_bfcp_userid"
+#define BFCP "bfcp"
/* Jitter */
#define JITTER_VARIANCE_THRESHOLD 400.0
/* IPDV */
@@ -258,7 +271,8 @@ typedef uint8_t switch_byte_t;
typedef enum {
SWITCH_PVT_PRIMARY = 0,
- SWITCH_PVT_SECONDARY
+ SWITCH_PVT_SECONDARY,
+ SWITCH_PVT_TERTIARY
} switch_pvt_class_t;
@@ -592,6 +606,7 @@ SWITCH_DECLARE_DATA extern switch_filenames SWITCH_GLOBAL_filenames;
#define SWITCH_MAX_STATE_HANDLERS 30
#define SWITCH_CORE_QUEUE_LEN 100000
#define SWITCH_MAX_MANAGEMENT_BUFFER_LEN 1024 * 8
+#define SWITCH_MAX_VIDEO_MEDIA 2 /*Maximum video media can be handled*/
#define SWITCH_ACCEPTABLE_INTERVAL(_i) (_i && _i <= SWITCH_MAX_INTERVAL && (_i % 10) == 0)
@@ -1618,6 +1633,14 @@ typedef enum {
CF_STREAM_CHANGED,
CF_ARRANGED_BRIDGE,
CF_STATE_REPEAT,
+ /* channel leg contains BFCP media */
+ CF_BFCP,
+ /* channel flag for early media BFCP */
+ CF_EARLY_MEDIA_BFCP,
+ /* Work for signaling that other leg contains BFCP media */
+ CF_PEER_BFCP,
+ /* Stream change due to change in BFCP protocol */
+ CF_BFCP_STREAM_CHANGE,
CF_WANT_DTLSv1_2,
CF_RFC7329_COMPAT,
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
@@ -1834,9 +1857,10 @@ typedef enum {
typedef enum {
SWITCH_MEDIA_TYPE_AUDIO,
SWITCH_MEDIA_TYPE_VIDEO,
- SWITCH_MEDIA_TYPE_TEXT
+ SWITCH_MEDIA_TYPE_TEXT,
+ SWITCH_MEDIA_TYPE_APPLICATION
} switch_media_type_t;
-#define SWITCH_MEDIA_TYPE_TOTAL 3
+#define SWITCH_MEDIA_TYPE_TOTAL 4
/*!
@@ -2661,6 +2685,8 @@ typedef enum {
CRYPTO_KEY_PARAM_METHOD_INVALID
} switch_rtp_crypto_key_param_method_type_t;
+typedef char const media_proto_name_t;
+
typedef struct payload_map_s {
switch_media_type_t type;
switch_sdp_type_t sdp_type;
@@ -2693,7 +2719,6 @@ typedef struct payload_map_s {
int adv_channels;
struct payload_map_s *next;
-
} payload_map_t;
typedef enum {
diff --git a/src/mod/applications/mod_bfcp/Makefile.am b/src/mod/applications/mod_bfcp/Makefile.am
new file mode 100644
index 00000000000..d92cbd4dd26
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/Makefile.am
@@ -0,0 +1,15 @@
+include $(top_srcdir)/build/modmake.rulesam
+MODNAME = mod_bfcp
+
+BFCP_CFLAGS = -I$(switch_srcdir)/libs/libbfcp/bfcpmsg -I$(switch_srcdir)/libs/libbfcp/bfcpsrvclt/bfcpsrv -I$(switch_srcdir)/libs/libbfcp/bfcpsrvclt/bfcpclt -I$(switch_srcdir)/src/mod/applications/mod_bfcp -I$(switch_srcdir)/src/include -I$(switch_srcdir)/libs/libbfcp -lbfcpmsg -I$(switch_srcdir)/libs/libbfcp -lbfcpsrv -I$(switch_srcdir)/libs/libbfcp -lbfcpclt
+BFCP_LDFLAGS = -L$(switch_srcdir)/libs/libbfcp/bfcpmsg -L$(switch_srcdir)/libs/libbfcp/bfcpsrvclt/bfcpsrv -L$(switch_srcdir)/libs/libbfcp/bfcpsrvclt/bfcpclt
+
+mod_LTLIBRARIES = mod_bfcp.la
+
+mod_bfcp_la_SOURCES = mod_bfcp.c mod_bfcp.h bfcp_interface.c bfcp_interface.h bfcp_media.c bfcp_thread.h
+mod_bfcp_la_CFLAGS = $(AM_CFLAGS) $(BFCP_CFLAGS)
+mod_bfcp_la_LIBADD = $(switch_builddir)/libfreeswitch.la $(BFCP_LDFLAGS)
+mod_bfcp_la_LDFLAGS = -avoid-version -module -no-undefined -shared -bfcprel
+
+
+
diff --git a/src/mod/applications/mod_bfcp/bfcp_interface.c b/src/mod/applications/mod_bfcp/bfcp_interface.c
new file mode 100644
index 00000000000..786c2c4f79c
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/bfcp_interface.c
@@ -0,0 +1,677 @@
+/*!
+ * MODULE : mod_bfcp
+ *
+ * Owners : GSLab Pvt Ltd
+ * : www.gslab.com
+ * : © Copyright 2020 Great Software Laboratory. All rights reserved.
+ *
+ * The Original Code is mod_bfcp for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * Contributor(s):
+ *
+ * Aman Thakral
+ * Vishal Abhishek
+ *
+ * Reviewer(s):
+ *
+ * Sagar Joshi
+ * Prashanth Regalla
+ *
+ * bfcp_interface.c -- LIBBFCP ENDPOINT CODE (code to tie libbfcp with freeswitch)
+ *
+ */
+#include "mod_bfcp.h"
+
+/* Callback to receive notifications from the underlying library about incoming BFCP messages */
+int received_msg(bfcp_arguments *arguments,
+ int is_outgoing)
+{
+ uint64_t conference_id;
+ uint16_t user_id, transaction_id;
+
+ if (!arguments) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid arguments in the received message!\n");
+ return -1;
+ }
+
+ if (!arguments->entity) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Invalid IDs in the message header!\n");
+ bfcp_free_arguments(arguments);
+ return -1;
+ }
+
+ conference_id = arguments->entity->conferenceID;
+ user_id = arguments->entity->userID;
+ transaction_id = arguments->entity->transactionID;
+
+ if (arguments->primitive <= 16) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%lu/%d/%d) %s %s\n", conference_id, transaction_id, user_id, is_outgoing ? "--->" :"<---", bfcp_primitive[arguments->primitive-1].description);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%lu/%d/%d) %s %s\n", conference_id, transaction_id, user_id, is_outgoing ? "--->" :"<---", "UNKNOWN PRIMITIVE");
+ }
+
+ return 0;
+}
+
+/* To print the Floor State of BFCP */
+ switch_status_t print_requests_list(bfcp server,
+ int index,
+ int status,
+ switch_stream_handle_t *stream)
+{
+ bfcp_queue *list = NULL;
+ bfcp_node *node = NULL;
+ floor_request_query *query_floorrequest = NULL;
+ bfcp_floor *floor = NULL;
+
+ if (!server) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "BFCP Server is not up");
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ switch (status) {
+ case BFCP_PENDING:
+ list = server->list_conferences[index].pending;
+ break;
+ case BFCP_ACCEPTED:
+ list = server->list_conferences[index].accepted;
+ break;
+ case BFCP_GRANTED:
+ list = server->list_conferences[index].granted;
+ break;
+ default:
+ break;
+ }
+
+ if (list) {
+ node = list->head;
+
+ if (node) {
+ stream->write_function(stream, "%s LIST\n", bfcp_status[status-1].description);
+ }
+
+ while (node) {
+ stream->write_function(stream, "FloorRequestID: %u\n\tUserID: %u Priority: %i Queue_position: %u ", node->floorRequestID, node->userID, node->priority, node->queue_position);
+
+ if (node->beneficiaryID) {
+ stream->write_function(stream, "BeneficiaryID: %u", node->beneficiaryID);
+ }
+
+ stream->write_function(stream, "\n");
+ floor = node->floor;
+
+ while (floor) {
+ stream->write_function(stream, "FloorID: %u ", floor->floorID);
+
+ if (floor->chair_info) {
+ stream->write_function(stream, "Chair-provided information: %s ", floor->chair_info);
+ }
+
+ if (floor->status == BFCP_FLOOR_STATE_WAITING) {
+ stream->write_function(stream, " state: FREE\n");
+ } else if (floor->status == BFCP_FLOOR_STATE_ACCEPTED) {
+ stream->write_function(stream, " state: ACCEPTED\n");
+ } else if (floor->status >= BFCP_FLOOR_STATE_GRANTED) {
+ stream->write_function(stream, " state: GRANTED\n");
+ } else {
+ stream->write_function(stream, " state: ERROR!\n");
+ }
+
+ floor = floor->next;
+ }
+
+ query_floorrequest = node->floorrequest;
+
+ while (query_floorrequest) {
+ stream->write_function(stream, "FloorRequest query: %u\n", query_floorrequest->userID);
+ query_floorrequest = query_floorrequest->next;
+ }
+
+ node = node->next;
+ stream->write_function(stream, "-----------------\n");
+ }
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Get new Conference ID */
+uint64_t bfcp_get_conf_id()
+{
+ uint64_t conference_id = (++conference_id_counter) % get_max_val(sizeof(conference_id_counter));
+
+ if (!conference_id) {
+ conference_id_counter = 1;
+ }
+
+ return conference_id ? conference_id : conference_id_counter;
+}
+
+/* Get new User ID */
+uint16_t bfcp_get_user_id()
+{
+ uint16_t user_id = (++user_id_counter) % get_max_val(sizeof(user_id_counter));
+
+ if (!user_id) {
+ user_id_counter = 1;
+ }
+
+ return (user_id) ? user_id : user_id_counter;
+}
+
+/* Create a new BFCP Interface */
+bfcp_interface create_bfcp_interface(char *p_uuid)
+{
+ bfcp_interface bfcp_interface_object;
+
+ if (!p_uuid) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Invalid UUID!\n");
+ return NULL;
+ }
+
+ /* Allocate and setup the new participant */
+ bfcp_interface_object = (bfcp_interface) calloc(1, sizeof(bfcp_object_t));
+
+ if (!bfcp_interface_object) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Could not allocate memory to interface object!\n");
+ return NULL;
+ }
+
+ mod_bfcp_mutex_init(&(bfcp_interface_object->bfcp_count_mutex), NULL);
+ mod_bfcp_mutex_lock(&(bfcp_interface_object->bfcp_count_mutex));
+
+ /* Assigning dummy values */
+ bfcp_interface_object->m_efloorctrl_mode = FLOOCTRL_MODE_CLIENT;
+ bfcp_interface_object->m_uuid = strdup((char *) p_uuid);
+ bfcp_interface_object->m_user_id = 0;
+ bfcp_interface_object->m_conf_id = 0;
+ bfcp_interface_object->m_is_passive = false;
+ bfcp_interface_object->m_floor_stream_map = NULL;
+ bfcp_interface_object->m_floor_stream_count = 0;
+
+ mod_bfcp_mutex_unlock(&(bfcp_interface_object->bfcp_count_mutex));
+
+ return bfcp_interface_object;
+}
+
+/* Add Conference and other details into FCS */
+void bfcp_interface_add_conference_to_server(bfcp_interface interface)
+{
+ uint32_t max_num_floors, max_number_floor_request, chair_wait_request;
+ uint16_t floor_id, user_id;
+ uint64_t conference_id;
+ struct bfcp_server *bfcp_srv;
+ floor_stream_mapping_t *floor_stream_map;
+
+ conference_id = bfcp_interface_get_conf_id(interface);
+ user_id = bfcp_interface_get_user_id(interface);
+ max_num_floors = bfcp_conf_globals.max_floor_per_conf;
+ chair_wait_request = bfcp_conf_globals.wait_time_chair_action;
+
+ if (interface->m_transport == BFCP_OVER_UDP) {
+ bfcp_srv = bfcp_srv_udp;
+ max_number_floor_request = bfcp_conf_globals.max_floor_request_per_floor[1];
+ } else {
+ bfcp_srv = bfcp_srv_tcp;
+ max_number_floor_request = bfcp_conf_globals.max_floor_request_per_floor[0];
+ }
+
+ if (bfcp_initialize_conference_server(bfcp_srv, conference_id, max_num_floors, max_number_floor_request, BFCP_AUTOMATED_CHAIR_POLICY, chair_wait_request) < 0) {
+ if (bfcp_interface_check_conference_existance(conference_id, interface->m_transport) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Couldn't add the conference %lu to the FCS!\n", conference_id);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Conference %lu Already Added in FCS!\n", conference_id);
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Conference %lu added successfully.\n", conference_id);
+ }
+
+
+ for (floor_stream_map = bfcp_interface_get_floor_stream_mapping(interface); floor_stream_map; floor_stream_map = floor_stream_map->next) {
+
+ floor_id = floor_stream_map->m_floor_id;
+
+ if (bfcp_add_floor_server(bfcp_srv, conference_id, floor_id, BFCP_CHAIR_MANAGE_FLOOR, BFCP_MAX_FLOOR_GRANT_AT_A_TIME) < 0) {
+ if (bfcp_interface_check_floor_existance(conference_id, floor_id, interface->m_transport) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Coudln't add the new floor!\n");
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Floor %u already Added!\n", floor_id);
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Floor %d added.\n", floor_id);
+ }
+ }
+
+ if (bfcp_add_user_server(bfcp_srv, conference_id, user_id, NULL, NULL) < 0) {
+ if (bfcp_interface_check_user_existance(conference_id, user_id, interface->m_transport) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Couldn't add the new user!\n");
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "User %u Already Added!\n", user_id);
+ if (bfcp_srv->bfcp_transport == BFCP_OVER_UDP) {
+ if (bfcp_set_user_address_server(bfcp_srv, conference_id, user_id, interface->m_client_address, interface->m_client_port) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Unable to add client address!\n");
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Client address %s::%d mapped with userID %d!\n", interface->m_client_address, interface->m_client_port, user_id);
+ }
+ }
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "User %d added.\n", user_id);
+ if (bfcp_srv->bfcp_transport == BFCP_OVER_UDP) {
+ if (bfcp_set_user_address_server(bfcp_srv, conference_id, user_id, interface->m_client_address, interface->m_client_port) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Unable to add client address!\n");
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Client address %s::%d mapped with userID %d!\n", interface->m_client_address, interface->m_client_port, user_id);
+ }
+ }
+ }
+}
+
+/* Destroying BFCP Interface */
+void bfcp_interface_destroy_interface(bfcp_interface interface)
+{
+ struct bfcp_server *bfcp_srv;
+ char *uuid = bfcp_interface_get_uuid(interface);
+ char *media_stream_str = bfcp_interface_get_media_stream_str(interface);
+ char *client_address = bfcp_interface_get_client_address(interface);
+ int i = 0, conf_count = 0;
+ uint64_t conf_id = bfcp_interface_get_conf_id(interface);
+ uint16_t user_id = bfcp_interface_get_user_id(interface);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Destroy Interface called for user %u\n", user_id);
+
+ if (interface->m_transport == BFCP_OVER_UDP) {
+ bfcp_srv = bfcp_srv_udp;
+ } else {
+ bfcp_srv = bfcp_srv_tcp;
+ }
+
+ conf_count = bfcp_srv->Actual_number_conference;
+
+ for (i = 0; i < conf_count && (bfcp_srv->list_conferences[i].conferenceID != conf_id); i++);
+
+ if (i < conf_count) {
+ if (bfcp_delete_user_server(bfcp_srv, conf_id, user_id) == 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Removed user %u\n", bfcp_interface_get_user_id(interface));
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Couldn't remove the user %u from the FCS!\n", user_id);
+ }
+
+ /* Removing the conference, no user present in the conference */
+ if (!bfcp_srv->list_conferences[i].user->users) {
+ if (bfcp_destroy_conference_server(bfcp_srv, bfcp_interface_get_conf_id(interface)) < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Couldn't remove the conference %lu from the FCS!\n", conf_id);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Conference %lu removed.\n", conf_id);
+ }
+ }
+
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Conference %lu not present or already removed\n", conf_id);
+ }
+
+ mod_bfcp_mutex_lock(&(interface->bfcp_count_mutex));
+
+ /* Dealocating the memories */
+ free(uuid);
+ uuid = NULL;
+ free(media_stream_str);
+ media_stream_str = NULL;
+ free(client_address);
+ client_address = NULL;
+
+ bfcp_interface_destroy_floor_stream_mapping(bfcp_interface_get_floor_stream_mapping(interface));
+
+ mod_bfcp_mutex_unlock(&(interface->bfcp_count_mutex));
+ mod_bfcp_mutex_destroy(&(interface->bfcp_count_mutex));
+
+ free(interface);
+ interface = NULL;
+}
+
+/* Destroys Floor Stream Map */
+void bfcp_interface_destroy_floor_stream_mapping(floor_stream_mapping_t *floor_stream_map)
+{
+ floor_stream_mapping_t *temp;
+
+ while(floor_stream_map) {
+ temp = floor_stream_map;
+ floor_stream_map = floor_stream_map->next;
+ free(temp);
+ }
+}
+
+/* Check whether conferenceID exist in conference list or not */
+int bfcp_interface_check_conference_existance(uint64_t conf_id,
+ uint16_t transport)
+{
+ int conf_count = 0, i;
+
+ struct bfcp_server *bfcp_srv;
+
+ if (transport == BFCP_OVER_UDP) {
+ bfcp_srv = bfcp_srv_udp;
+ } else {
+ bfcp_srv = bfcp_srv_tcp;
+ }
+
+ if (bfcp_srv == NULL || conf_id <= 0) {
+ return -1;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ conf_count = bfcp_srv->Actual_number_conference;
+
+ for (i = 0; i < conf_count && (bfcp_srv->list_conferences[i].conferenceID != conf_id); i++);
+
+ if (i < conf_count) {
+ bfcp_mutex_unlock(&count_mutex);
+ return 0;
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+ return -2;
+}
+
+/* Check whether floorID exist in floor list of particular conference or not */
+int bfcp_interface_check_floor_existance(uint64_t conf_id,
+ uint16_t floor_id,
+ uint16_t transport)
+{
+ int conf_count = 0, i = 0, j = 0;
+
+ struct bfcp_server *bfcp_srv;
+
+ if (transport == BFCP_OVER_UDP) {
+ bfcp_srv = bfcp_srv_udp;
+ } else {
+ bfcp_srv = bfcp_srv_tcp;
+ }
+
+ if (bfcp_srv == NULL || conf_id <= 0 || floor_id <= 0) {
+ return -1;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ conf_count = bfcp_srv->Actual_number_conference;
+
+ for (i = 0; i < conf_count && (bfcp_srv->list_conferences[i].conferenceID != conf_id); i++);
+
+ if (i < conf_count) {
+ bfcp_list_floors *list_floors;
+
+ list_floors = bfcp_srv->list_conferences[i].floor;
+
+ if (!list_floors) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ for (j = 0; j < list_floors->actual_number_floors && (list_floors->floors[j].floorID != floor_id); j++);
+
+ if (j < list_floors->actual_number_floors) {
+ /* A floor with the same floorID already exists in this conference */
+ bfcp_mutex_unlock(&count_mutex);
+ return 0;
+ }
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+}
+
+/* Check whether userID exist in user list of particular conference or not */
+int bfcp_interface_check_user_existance(uint64_t conf_id,
+ uint16_t user_id,
+ uint16_t transport)
+{
+ int i, conf_count = 0;
+ struct bfcp_server *bfcp_srv;
+
+ if (transport == BFCP_OVER_UDP) {
+ bfcp_srv = bfcp_srv_udp;
+ } else {
+ bfcp_srv = bfcp_srv_tcp;
+ }
+
+ if (bfcp_srv == NULL || conf_id <= 0 || user_id <= 0) {
+ return -1;
+ }
+
+ bfcp_mutex_lock(&count_mutex);
+
+ conf_count = bfcp_srv->Actual_number_conference;
+
+ for (i = 0; i < conf_count && (bfcp_srv->list_conferences[i].conferenceID != conf_id); i++);
+
+ if (i < conf_count) {
+ users user = NULL;
+ lusers list_users;
+
+ list_users = bfcp_srv->list_conferences[i].user;
+
+ if (list_users == NULL) {
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+ }
+
+ for (user = list_users->users; user && user->userID != user_id; user = user->next);
+
+ if (user) {
+ /* This user already exists in the list */
+ bfcp_mutex_unlock(&count_mutex);
+ return 0;
+ }
+ }
+
+ bfcp_mutex_unlock(&count_mutex);
+ return -1;
+}
+
+void bfcp_interface_set_user_id(bfcp_interface interface,
+ uint16_t user_id)
+{
+ interface->m_user_id = user_id;
+}
+
+void bfcp_interface_set_conf_id(bfcp_interface interface,
+ uint64_t conf_id)
+{
+ interface->m_conf_id = conf_id;
+}
+
+void bfcp_interface_set_floorctrl_mode(bfcp_interface interface,
+ e_floorctrl_mode floorctrl_mode)
+{
+ interface->m_efloorctrl_mode = floorctrl_mode;
+}
+
+void bfcp_interface_set_is_passive(bfcp_interface interface ,
+ bool is_passive)
+{
+ interface->m_is_passive = is_passive;
+}
+
+void bfcp_interface_set_media_stream_str(bfcp_interface interface,
+ char *media_stream_str)
+{
+ interface->m_media_stream_str = strdup((char *) media_stream_str);
+}
+
+void bfcp_interface_set_floor_stream_mapping(bfcp_interface interface,
+ uint16_t floor_id,
+ uint16_t stream_id)
+{
+ floor_stream_mapping_t *head = interface->m_floor_stream_map, *temp , *new_node;
+
+ if (bfcp_conf_globals.max_floor_per_conf < interface->m_floor_stream_count) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Maximum number of floor has been assigned into list for a conference! No more floor is allowed \n");
+ return;
+ }
+
+ for (temp = head; temp; temp = (temp->next)) {
+ if (temp->m_floor_id == floor_id) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Floor ID %d already present in the list\n", floor_id);
+ return;
+ }
+
+ if (!temp->next) {
+ break;
+ }
+ }
+
+ new_node = (floor_stream_mapping_t*)malloc(sizeof(floor_stream_mapping_t));
+
+ new_node->m_floor_id = floor_id;
+ new_node->m_stream_id = stream_id;
+ new_node->next = NULL;
+
+ if(!temp) {
+ interface->m_floor_stream_map = new_node;
+ } else {
+ temp->next = new_node;
+ }
+
+ interface->m_floor_stream_count++;
+}
+
+uint16_t bfcp_interface_get_user_id(bfcp_interface interface)
+{
+ return interface->m_user_id;
+}
+
+uint16_t bfcp_interface_floor_stream_count(bfcp_interface interface)
+{
+ return interface->m_floor_stream_count;
+}
+
+uint64_t bfcp_interface_get_conf_id(bfcp_interface interface)
+{
+ return interface->m_conf_id;
+}
+
+uint16_t bfcp_interface_get_client_port(bfcp_interface interface)
+{
+ return interface->m_client_port;
+}
+
+floor_stream_mapping_t *bfcp_interface_get_floor_stream_mapping(bfcp_interface interface)
+{
+ return interface->m_floor_stream_map;
+}
+
+e_floorctrl_mode bfcp_interface_get_floorctrl_mode(bfcp_interface interface)
+{
+ return interface->m_efloorctrl_mode;
+}
+
+bool bfcp_interface_get_is_passive(bfcp_interface interface)
+{
+ return interface->m_is_passive;
+}
+
+char *bfcp_interface_get_uuid(bfcp_interface interface)
+{
+ return interface->m_uuid;
+}
+
+char *bfcp_interface_get_media_stream_str(bfcp_interface interface)
+{
+ return interface->m_media_stream_str;
+}
+
+char *bfcp_interface_get_client_address(bfcp_interface interface)
+{
+ return interface->m_client_address;
+}
+
+
+/* Start BFCP server instance on parameters taken from configuration file of mod_bfcp */
+switch_status_t start_bfcp_server()
+{
+ /* bfcp_conf_globals.bfcp_transport_tcp == 0 , start BFCP server over TCP socket
+ bfcp_conf_globals.bfcp_transport_tcp == 1, start BFCP server over TCP/TLS socket */
+ if (bfcp_conf_globals.bfcp_transport_tcp == 0 || bfcp_conf_globals.bfcp_transport_tcp == 1) {
+ bfcp_srv_tcp = bfcp_initialize_bfcp_server(bfcp_conf_globals.max_conf_per_server[0],
+ bfcp_conf_globals.bfcp_port,
+ received_msg,
+ bfcp_conf_globals.bfcp_transport_tcp,
+ NULL,
+ NULL,
+ "0.0.0.0");
+
+ if (bfcp_srv_tcp) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"%s FCS created.\n", (bfcp_conf_globals.bfcp_transport_tcp) ? "TCP/TLS/BFCP" : "TCP/BFCP");
+ tcp_server = 1;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,"Couldn't create the FCS over TCP, is the port already taken?\n");
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"TCP/BFCP and TCP/TLS/BFCP FCS are down.\n");
+ }
+
+ if (bfcp_conf_globals.bfcp_transport_udp) {
+ bfcp_srv_udp = bfcp_initialize_bfcp_server(bfcp_conf_globals.max_conf_per_server[1],
+ bfcp_conf_globals.bfcp_port,
+ received_msg,
+ BFCP_OVER_UDP,
+ NULL,
+ NULL,
+ "0.0.0.0");
+
+ if (bfcp_srv_udp) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"UDP/BFCP FCS created.\n");
+ udp_server = 1;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,"Couldn't create the FCS over UDP, is the port already taken?\n");
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"UDP FCS server is down.\n");
+ }
+
+ if (!bfcp_srv_udp && !bfcp_srv_tcp) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to open socket for UDP and TCP\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Destroy BFCP server instance */
+void stop_bfcp_server()
+{
+ int error;
+
+ if (bfcp_srv_tcp) {
+ error = bfcp_destroy_bfcp_server(&bfcp_srv_tcp);
+
+ if (error >= 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"TCP FCS Stopped.\n");
+ tcp_server = 0;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"Couldn't destroy TCP FCS!\n");
+ }
+ }
+
+ if (bfcp_srv_udp) {
+ error = bfcp_destroy_bfcp_server(&bfcp_srv_udp);
+
+ if (error >= 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"UDP FCS Stopped.\n");
+ udp_server = 0;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"Couldn't destroy UDP FCS !\n");
+ }
+ }
+}
+
+/* To calculate maximum value for confID & userID*/
+uint64_t get_max_val(uint32_t bytes)
+{
+ int bits = 8 * bytes;
+
+ uint64_t max = (1LU << (bits - 1)) + ((1LU << (bits - 1)) - 1);
+
+ return max;
+}
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/bfcp_interface.h b/src/mod/applications/mod_bfcp/bfcp_interface.h
new file mode 100644
index 00000000000..b06af6822cf
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/bfcp_interface.h
@@ -0,0 +1,209 @@
+/*!
+ * MODULE : mod_bfcp
+ *
+ * Owners : GSLab Pvt Ltd
+ * : www.gslab.com
+ * : © Copyright 2020 Great Software Laboratory. All rights reserved.
+ *
+ * The Original Code is mod_bfcp for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * Contributor(s):
+ *
+ * Aman Thakral
+ * Vishal Abhishek
+ *
+ * Reviewer(s):
+ *
+ * Sagar Joshi
+ * Prashanth Regalla
+ *
+ * bfcp_interface.h -- LIBBFCP ENDPOINT CODE (code to tie libbfcp with freeswitch)
+ *
+ */
+
+/* Library for server of libbfcp */
+#include "bfcp_server.h"
+#include "bfcp_messages.h"
+#include
+#include
+
+/* Library for thread of mod_bfcp */
+#include "bfcp_thread.h"
+
+#define CLIENT_CONF_ID 1
+#define CLIENT_FLOOR_ID 1
+#define STREAM_ID 3
+
+#define REMOTE_CLIENT_USER_ID 2
+#define LOCAL_CLIENT_USER_ID 3
+
+#define USER_BUF_SIZE 6
+#define BFCP_VERSION 1
+
+/*! \brief BFCP server related parameters whose place need to be constant, please don't modify */
+#define BFCP_AUTOMATED_CHAIR_POLICY 0 /* Accepting request when chair is missing (0 Accepting request, 1 don't */
+#define BFCP_MAX_FLOOR_GRANT_AT_A_TIME 1 /* Number of users that can be granted same floor at a time */
+#define BFCP_CHAIR_MANAGE_FLOOR 0 /* userid of chair who will manage particular floor, if no chair then 0 */
+#define BFCP_MAX_CONF 64 /* Maximum number of allowed concurrent conferences in a server */
+#define BFCP_MAX_FLOOR_PER_CONF 64 /* Maximum number of allowed concurrent conferences in a conference */
+#define BFCP_MAX_FLOORREQUESTS_PER_FLOOR 64 /* Maximum number of FloorRequests for a floor from a user */
+#define BFCP_CHAIR_WAIT_REQUEST 300 /* Default chair wait time */
+
+uint16_t user_id_counter; /* Maintains userID value to assign to new BFCP participant */
+uint64_t conference_id_counter; /* Maintains confID value to assign to new BFCP conference */
+
+uint16_t tcp_server, udp_server; /* Maintains server type while creating and destroying BFCP server */
+
+/*! \brief Enumration for BFCP Floor Control mode */
+typedef enum {
+ FLOOCTRL_MODE_CLIENT = 0 ,
+ FLOOCTRL_MODE_SERVER ,
+ FLOOCTRL_MODE_CLIENT_AND_SERVER
+}e_floorctrl_mode ;
+
+/*! \brief Floor Stream Mapping */
+struct floor_stream_mapping_s {
+ uint16_t m_floor_id;
+ uint16_t m_stream_id;
+ struct floor_stream_mapping_s *next;
+};
+
+typedef struct floor_stream_mapping_s floor_stream_mapping_t;
+
+/*! \brief BFCP interface */
+typedef struct bfcp_object_s {
+ e_floorctrl_mode m_efloorctrl_mode;
+ char* m_uuid;
+ char* m_media_stream_str;
+ char* m_client_address;
+ uint16_t m_client_port;
+ uint64_t m_conf_id;
+ uint16_t m_user_id;
+ uint16_t m_floor_stream_count;
+ uint16_t m_transport;
+ floor_stream_mapping_t *m_floor_stream_map;
+ bool m_is_passive;
+ mod_bfcp_mutex_t bfcp_count_mutex;
+} bfcp_object_t;
+
+typedef bfcp_object_t *bfcp_interface;
+
+/*!
+ \brief Receive notifications from the underlying library about incoming BFCP messages
+ \param arguments BFCP arguments
+ \param is_outgoing Direction of message flow (incoming or outgoing)
+ \return 0 : After successful completion
+ -1 : Otherwise
+ */
+int received_msg(bfcp_arguments *arguments,
+ int is_outgoing);
+
+/*!
+ \brief Print floor state of BFCP
+ \param server Pointer to FCS instance
+ \param index Variable for list_conference index
+ \param status BFCP floor request status
+ \param stream Pointer of switch_stream_handle
+ \return SWITCH_STATUS_SUCCESS
+ */
+switch_status_t print_requests_list(bfcp server,
+ int index,
+ int status,
+ switch_stream_handle_t *stream);
+
+/* BFCP Server-related Operation */
+
+/*! \brief Start BFCP server instance on parameter taken from configuration file of mod_bfcp */
+switch_status_t start_bfcp_server();
+
+/*! \brief Destroy BFCP server instance */
+void stop_bfcp_server();
+
+/* BFCP Interface-related operations */
+
+/* Create a new BFCP Interface */
+bfcp_interface create_bfcp_interface(char *p_uuid);
+
+/*! \brief Interface API to add conference to BFCP server */
+void bfcp_interface_add_conference_to_server(bfcp_interface interface);
+
+/*! \brief API to destroy BFCP interface. Memory pools are returned to the core and utilized memory from the channel is freed*/
+void bfcp_interface_destroy_interface(bfcp_interface interface);
+
+/*! \brief Destroying Floor Stream Mapping */
+void bfcp_interface_destroy_floor_stream_mapping(floor_stream_mapping_t *floor_stream_map);
+
+/*!
+ \brief Check if ConferenceId exists in conference list
+ \param conf_id BFCP ConferenceID
+ \param tansport server type (UDP or TCP)
+ \return 0 : If ConferenceID exists in the conference list
+ -1 : If Server or ConferenceID is invalid
+ -2 : If conferenceID doesn't exist in the conference list
+ */
+int bfcp_interface_check_conference_existance(uint64_t conf_id,
+ uint16_t transport);
+
+/*!
+ \brief Check if FloorId exists in floor list of particular conference or not
+ \param conf_id BFCP ConferenceID
+ \param floor_id BFCP FloorID
+ \param tansport server type (UDP or TCP)
+ \return 0 : If FloorID exists in the floor list
+ -1 : Otherwise
+ */
+int bfcp_interface_check_floor_existance(uint64_t conf_id,
+ uint16_t floor_id,
+ uint16_t transport);
+
+/*!
+ \brief Check if UserId exists in user list of particular conference or not
+ \param conf_id BFCP ConferenceID
+ \param user_id BFCP UserID
+ \param tansport server type (UDP or TCP)
+ \return 0 : If UserID exists in the user list
+ -1 : Otherwise
+ */
+int bfcp_interface_check_user_existance(uint64_t conf_id,
+ uint16_t user_id,
+ uint16_t transport);
+
+/*! \brief Setter API for interface data member */
+void bfcp_interface_set_user_id(bfcp_interface interface,
+ uint16_t user_id);
+
+void bfcp_interface_set_conf_id(bfcp_interface interface,
+ uint64_t conf_id);
+
+void bfcp_interface_set_floor_stream_mapping(bfcp_interface interface,
+ uint16_t foor_id,
+ uint16_t stream_id);
+
+void bfcp_interface_set_floorctrl_mode(bfcp_interface interface,
+ e_floorctrl_mode floorctrl_mode);
+
+void bfcp_interface_set_is_passive(bfcp_interface interface,
+ bool is_passive);
+
+void bfcp_interface_set_media_stream_str(bfcp_interface interface,
+ char* media_stream_str);
+
+/*! \brief Getter API for interface member */
+uint16_t bfcp_interface_get_user_id(bfcp_interface interface);
+uint16_t bfcp_interface_get_floor_stream_count(bfcp_interface interface);
+uint16_t bfcp_interface_get_client_port(bfcp_interface interface);
+uint64_t bfcp_interface_get_conf_id(bfcp_interface interface);
+floor_stream_mapping_t *bfcp_interface_get_floor_stream_mapping(bfcp_interface interface);
+e_floorctrl_mode bfcp_interface_get_floorctrl_mode(bfcp_interface interface);
+bool bfcp_interface_get_is_passive(bfcp_interface interface);
+char *bfcp_interface_get_uuid(bfcp_interface interface);
+char *bfcp_interface_get_media_stream_str(bfcp_interface interface);
+char *bfcp_interface_get_client_address(bfcp_interface interface);
+
+
+/*! \brief API to assign confID and userID */
+uint16_t bfcp_get_user_id();
+uint64_t bfcp_get_conf_id();
+
+/*! \brief API to get maximum value for any data type */
+uint64_t get_max_val(uint32_t);
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/bfcp_media.c b/src/mod/applications/mod_bfcp/bfcp_media.c
new file mode 100644
index 00000000000..302f40bc1e4
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/bfcp_media.c
@@ -0,0 +1,552 @@
+/*!
+ * MODULE : mod_bfcp
+ *
+ * Owners : GSLab Pvt Ltd
+ * : www.gslab.com
+ * : © Copyright 2020 Great Software Laboratory. All rights reserved.
+ *
+ * The Original Code is mod_bfcp for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * Contributor(s):
+ *
+ * Aman Thakral
+ * Vishal Abhishek
+ *
+ * Reviewer(s):
+ *
+ * Sagar Joshi
+ * Prashanth Regalla
+ *
+ * bfcp_media.c -- LIBBFCP ENDPOINT CODE (bfcp code)
+ *
+ */
+#include "mod_bfcp.h"
+
+/*!
+ \brief Retrieve media atrributes of BFCP
+ \param session Pointer to session of current leg
+ \return media attributes of BFCP
+ */
+static media_attribute_t* bfcp_get_bfcp_attribute(switch_core_session_t *session);
+
+/*!
+ \brief Check if all mandatory attributes are present in remote SDP or not
+ \param session Pointer to session of current leg
+ \param bfcp_media_attributes Pointer of media attributes of BFCP
+ \return SWITCH_STATUS_SUCCESS : If all mandatory attributes are present in remote SDP,
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+static switch_status_t bfcp_check_mandatory_attribute(switch_core_session_t *session,
+ media_attribute_t *bfcp_media_attribute);
+
+/*!
+ \brief Validate BFCP attributes and maintain object of BFCP for current leg
+ \param session Pointer to session of current leg
+ \param bfcp_media_attribute Pointer to media attributes of BFCP
+ \param bfcp_interface_object Pointer to object where we maintain BFCP related data for current leg
+ \return SWITCH_STATUS_SUCCESS : If validation of BFCP attributes is successful
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+static switch_status_t bfcp_validate_sdp(switch_core_session_t *session,
+ media_attribute_t *bfcp_media_attribute,
+ bfcp_interface bfcp_interface_obj);
+
+/*!
+ \brief To validate userID of BFCP and store it in BFCP object
+ \param user_id Pointer to BFCP userID buffer
+ \return SWITCH_STATUS_SUCCESS : If BFCP userID validated successfully
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+static switch_status_t bfcp_validate_userid(char *user_id);
+
+/*!
+ \brief To validate conferenceID of BFCP and store it in BFCP object
+ \param conf_id Pointer to BFCP confID buffer
+ \return SWITCH_STATUS_SUCCESS : If BFCP conferenceID validated successfully
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+static switch_status_t bfcp_validate_confid(char *conf_id);
+
+/*!
+ \brief To validate BFCP floor control and store it in BFCP object
+ \param floor_ctrl Pointer to BFCP Floor Control buffer
+ \param bfcp_interface_object Pointer to object where we maintain BFCP related data for current leg
+ \return SWITCH_STATUS_SUCCESS : If floor control is of type C-only or C-S
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+static switch_status_t bfcp_validate_floorctrl(char *floor_ctrl,
+ bfcp_interface bfcp_interface_object);
+
+/*!
+ \brief To validate BFCP floorID & Storing it in BFCP object
+ \param floor_id Pointer to BFCP floorID buffer
+ \param bfcp_interface_object Pointer to object where we maintain BFCP related data for current leg
+ \return SWITCH_STATUS_SUCCESS : If floorID validated successfully
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+static switch_status_t bfcp_validate_floorid(char *floor_id,
+ bfcp_interface bfcp_interface_object);
+
+/*!
+ \brief To validate BFCP setup and storing it in BFCP Object
+ \param setup Pointer to BFCP setup buffer
+ \param bfcp_interface_object Pointer to object where we maintain BFCP related data for current leg
+ \return SWITCH_STATUS_SUCCESS : If setup is active or actpass
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+static switch_status_t bfcp_validate_setup(char *setup,
+ bfcp_interface bfcp_interface_object);
+
+/*!
+ \brief To validate BFCP connection and storing it in BFCP Object
+ \param connection Pointer to BFCP connection buffer
+ \return SWITCH_STATUS_SUCCESS : If connection is new or existing
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+static switch_status_t bfcp_validate_connection(char *connection);
+
+/* Parsing tokens */
+#define SPACE " "
+#define TAB "\011"
+#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define DIGIT "0123456789"
+#define TOKEN ALPHA "-!#$%&'*+.^_`{|}~"
+
+static char *token(char **message,
+ const char *sep,
+ const char *legal,
+ const char *strip)
+{
+ size_t n;
+ char *retval = *message;
+
+ if (strip) {
+ retval += strspn(retval, strip);
+ }
+
+ if (legal) {
+ n = strspn(retval, legal);
+ } else {
+ n = strcspn(retval, sep);
+ }
+
+ if (n == 0) {
+ return NULL;
+ }
+
+ if (retval[n]) {
+ retval[n++] = '\0';
+ n += strspn(retval + n, sep);
+ }
+
+ *message = retval + n;
+ if (*retval == '\0') {
+ return NULL;
+ }
+
+ return retval;
+}
+
+/* To get media attributes of BFCP */
+static media_attribute_t* bfcp_get_bfcp_attribute(switch_core_session_t *session)
+{
+ return switch_core_media_get_media_attribute(session, SWITCH_MEDIA_TYPE_APPLICATION);
+}
+
+/* To parse and validate BFCP attributes */
+switch_status_t bfcp_parse(switch_core_session_t *session)
+{
+ switch_channel_t *channel;
+ media_attribute_t *bfcp_media_attribute;
+ bfcp_interface bfcp_interface_obj;
+ media_proto_name_t *media_proto;
+
+ channel = switch_core_session_get_channel(session);
+
+ media_proto = switch_core_media_get_media_protocol(session, SWITCH_MEDIA_TYPE_APPLICATION);
+
+ if ((!strcmp(media_proto, "UDP/BFCP"))) {
+ if (!udp_server) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Sorry UDP socket for BFCP not up!\n");
+ switch_channel_clear_flag(channel, CF_BFCP);
+ return SWITCH_STATUS_FALSE;
+ }
+ } else if (!strcmp(media_proto, "TCP/BFCP")) {
+ if (!tcp_server || bfcp_conf_globals.bfcp_transport_tcp != BFCP_OVER_TCP) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Sorry TCP socket for BFCP not up!\n");
+ switch_channel_clear_flag(channel, CF_BFCP);
+ return SWITCH_STATUS_FALSE;
+ }
+ } else if (!strcmp(media_proto, "TCP/TLS/BFCP")) {
+ if (!tcp_server || bfcp_conf_globals.bfcp_transport_tcp != BFCP_OVER_TLS) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Sorry TCP/TLS socket for BFCP not up!\n");
+ switch_channel_clear_flag(channel, CF_BFCP);
+ return SWITCH_STATUS_FALSE;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Not a BFCP media protocol!\n");
+ switch_channel_clear_flag(channel, CF_BFCP);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!(bfcp_interface_obj = (bfcp_interface ) switch_core_session_get_private_class(session, SWITCH_PVT_TERTIARY)) &&
+ !(bfcp_interface_obj = create_bfcp_interface(switch_core_session_get_uuid(session)))) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ mod_bfcp_mutex_lock(&(bfcp_interface_obj->bfcp_count_mutex));
+
+ bfcp_media_attribute = bfcp_get_bfcp_attribute(session);
+
+ if (bfcp_validate_sdp(session, bfcp_media_attribute, bfcp_interface_obj) != SWITCH_STATUS_SUCCESS) {
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "One or more BFCP attributes are not in proper format.\n");
+
+ if (switch_channel_test_flag(channel, CF_BFCP)) {
+ switch_channel_clear_flag(channel, CF_BFCP);
+ }
+
+ mod_bfcp_mutex_unlock(&(bfcp_interface_obj->bfcp_count_mutex));
+ bfcp_interface_destroy_interface(bfcp_interface_obj);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (bfcp_check_mandatory_attribute(session, bfcp_media_attribute) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "All mandatory attributes of BFCP are not present in SDP.\n");
+ }
+
+ mod_bfcp_mutex_unlock(&(bfcp_interface_obj->bfcp_count_mutex));
+ switch_core_session_set_private_class(session, bfcp_interface_obj, SWITCH_PVT_TERTIARY);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Validates the SDP parametrs of BFCP and stores atrribute values in BFCPInterface Object */
+static switch_status_t bfcp_validate_sdp(switch_core_session_t *session,
+ media_attribute_t *bfcp_media_attribute,
+ bfcp_interface bfcp_interface_object)
+{
+ media_attribute_t *bfcp_attribute = bfcp_media_attribute;
+ switch_core_session_t *peer_session;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+ while (bfcp_attribute) {
+ if (!strcmp(bfcp_attribute->a_name, "userid")) {
+ status = bfcp_validate_userid(bfcp_attribute->a_value);
+
+ } else if (!strcmp(bfcp_attribute->a_name, "confid")) {
+ status = bfcp_validate_confid(bfcp_attribute->a_value);
+
+ } else if (!strcmp(bfcp_attribute->a_name, "floorctrl")) {
+ status = bfcp_validate_floorctrl(bfcp_attribute->a_value, bfcp_interface_object);
+
+ } else if (!strcmp(bfcp_attribute->a_name, "floorid")) {
+ status = bfcp_validate_floorid(bfcp_attribute->a_value, bfcp_interface_object);
+
+ } else if (!strcmp(bfcp_attribute->a_name, "setup")) {
+ status = bfcp_validate_setup(bfcp_attribute->a_value, bfcp_interface_object);
+
+ } else if (!strcmp(bfcp_attribute->a_name, "connection")) {
+ status = bfcp_validate_connection(bfcp_attribute->a_value);
+ }
+
+ if (status != SWITCH_STATUS_SUCCESS)
+ return status;
+
+ bfcp_attribute = bfcp_attribute->a_next;
+ }
+
+ if (bfcp_interface_get_floor_stream_mapping(bfcp_interface_object) == NULL) {
+ bfcp_interface_set_floor_stream_mapping(bfcp_interface_object, CLIENT_FLOOR_ID, STREAM_ID);
+ bfcp_interface_set_media_stream_str(bfcp_interface_object, "mstrm");
+ }
+
+ if ((bfcp_interface_get_conf_id(bfcp_interface_object) == 0) || (bfcp_interface_get_user_id(bfcp_interface_object) == 0)) {
+ switch_core_session_get_partner(session, &peer_session);
+
+ if (peer_session) {
+ switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session);
+
+ if (bfcp_interface_get_user_id(bfcp_interface_object) == 0) {
+ if (switch_channel_get_variable(peer_channel, SWITCH_PEER_BFCP_USERID)) {
+ bfcp_interface_set_user_id(bfcp_interface_object, atoi(switch_channel_get_variable(peer_channel, SWITCH_PEER_BFCP_USERID)));
+ switch_channel_set_variable(peer_channel, SWITCH_PEER_BFCP_USERID, NULL);
+ } else {
+ bfcp_interface_set_user_id(bfcp_interface_object, bfcp_get_user_id());
+ }
+ }
+
+ if (bfcp_interface_get_conf_id(bfcp_interface_object) == 0) {
+ bfcp_interface peer_bfcp_object = switch_core_session_get_private_class(peer_session, SWITCH_PVT_TERTIARY);
+
+ if (peer_bfcp_object) {
+ bfcp_interface_set_conf_id(bfcp_interface_object, bfcp_interface_get_conf_id(peer_bfcp_object));
+ } else {
+ bfcp_interface_set_conf_id(bfcp_interface_object, bfcp_get_conf_id());
+ }
+ }
+
+ switch_core_session_rwunlock(peer_session);
+ } else {
+ if (bfcp_interface_get_user_id(bfcp_interface_object) == 0) {
+ bfcp_interface_set_user_id(bfcp_interface_object, bfcp_get_user_id());
+ }
+
+ if (bfcp_interface_get_conf_id(bfcp_interface_object) == 0) {
+ bfcp_interface_set_conf_id(bfcp_interface_object, bfcp_get_conf_id());
+ }
+ }
+ }
+
+ return status;
+}
+
+/* Check if all mandatory attributes are present or not */
+static switch_status_t bfcp_check_mandatory_attribute(switch_core_session_t *session,
+ media_attribute_t *bfcp_media_attribute)
+{
+ uint16_t is_attribute[6] = {0};
+ media_attribute_t *bfcp_attribute = bfcp_media_attribute;
+
+ while (bfcp_attribute) {
+ if (!strcmp(bfcp_attribute->a_name, "userid")) {
+ is_attribute[0]++;
+ } else if (!strcmp(bfcp_attribute->a_name, "confid")) {
+ is_attribute[1]++;
+ } else if (!strcmp(bfcp_attribute->a_name, "floorctrl")) {
+ is_attribute[2]++;
+ } else if (!strcmp(bfcp_attribute->a_name, "floorid")) {
+ is_attribute[3]++;
+ } else if (!strcmp(bfcp_attribute->a_name, "setup")) {
+ is_attribute[4]++;
+ } else if (!strcmp(bfcp_attribute->a_name, "connection")) {
+ is_attribute[5]++;
+ }
+
+ bfcp_attribute = bfcp_attribute->a_next;
+ }
+
+ if (!is_attribute[2]) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Attribute 'floorctrl' missing, then by default offerer act as client\n");
+
+ bfcp_attribute = (media_attribute_t*) malloc(sizeof(media_attribute_t));
+
+ if (!bfcp_attribute) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ bfcp_attribute->a_size = sizeof (media_attribute_t);
+ bfcp_attribute->a_name = "floorctrl";
+ bfcp_attribute->a_value = "c-only";
+ bfcp_attribute->a_next = bfcp_media_attribute;
+ bfcp_media_attribute = bfcp_attribute;
+ is_attribute[2]++;
+
+ switch_core_media_set_media_attribute(session, bfcp_media_attribute, SWITCH_MEDIA_TYPE_APPLICATION);
+ }
+
+ for (uint16_t check_attribute = 0; check_attribute < 6; check_attribute++) {
+ if (!is_attribute[check_attribute]) {
+ return SWITCH_STATUS_FALSE;
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Generates LOCAL SDP for BFCP media which is sent to current/peer leg */
+SWITCH_DECLARE(void) bfcp_media_gen_local_sdp(switch_core_session_t *session,
+ switch_sdp_type_t sdp_type)
+{
+ switch_core_session_t *peer_session;
+ switch_channel_t *channel, *peer_channel;
+ payload_map_t *pmap;
+ char *buf;
+ bfcp_interface bfcp_interface_object;
+ media_proto_name_t *media_proto;
+
+ channel = switch_core_session_get_channel(session);
+ pmap = switch_core_media_get_payload_map(session, SWITCH_MEDIA_TYPE_APPLICATION);
+ media_proto = switch_core_media_get_media_protocol(session, SWITCH_MEDIA_TYPE_APPLICATION);
+
+ switch_zmalloc(buf, BFCPBUFLEN);
+
+ switch_core_session_get_partner(session, &peer_session);
+
+ bfcp_interface_object = (bfcp_interface) switch_core_session_get_private_class(session, SWITCH_PVT_TERTIARY);
+
+ mod_bfcp_mutex_lock(&(bfcp_interface_object->bfcp_count_mutex));
+
+ bfcp_interface_object->m_client_port = pmap->remote_sdp_port;
+ bfcp_interface_object->m_client_address = strdup((char*) pmap->remote_sdp_ip);
+
+ if (!strcmp(media_proto, "UDP/BFCP")) {
+ bfcp_interface_object->m_transport = 2;
+ } else if (!strcmp(media_proto, "TCP/BFCP")) {
+ bfcp_interface_object->m_transport = 1;
+ } else {
+ bfcp_interface_object->m_transport = 0;
+ }
+
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "m=application %d %s *\r\n", bfcp_conf_globals.bfcp_port, media_proto);
+
+ /* LOCAL SDP generation for BFCP media */
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=floorctrl:s-only\r\n");
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=confid:%d\r\n", bfcp_interface_get_conf_id(bfcp_interface_object));
+
+ /* For userid to be set in LOCAL SDP of BFCP as per request/response to be send */
+ if (!switch_channel_test_flag(channel, CF_EARLY_MEDIA_BFCP)) {
+ if (peer_session) {
+ bfcp_interface peer_bfcp_interface = (bfcp_interface) switch_core_session_get_private_class(peer_session, SWITCH_PVT_TERTIARY);
+
+ if (peer_bfcp_interface) {
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=userid:%d\r\n", bfcp_interface_get_user_id(peer_bfcp_interface));
+ } else {
+ char userid_buf[USER_BUF_SIZE];
+ uint16_t user_id = bfcp_get_user_id();
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=userid:%d\r\n", user_id);
+ sprintf(userid_buf, "%d", user_id);
+ switch_channel_set_variable(channel, SWITCH_PEER_BFCP_USERID, userid_buf);
+ }
+ } else {
+ char userid_buf[USER_BUF_SIZE];
+ uint16_t user_id = bfcp_get_user_id();
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=userid:%d\r\n", user_id);
+ sprintf(userid_buf, "%d", user_id);
+ switch_channel_set_variable(channel, SWITCH_PEER_BFCP_USERID, userid_buf);
+ }
+ } else {
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=userid:%d\r\n", bfcp_interface_get_user_id(bfcp_interface_object));
+ }
+
+ for (floor_stream_mapping_t *floor_stream_map = bfcp_interface_get_floor_stream_mapping(bfcp_interface_object);
+ floor_stream_map;
+ floor_stream_map = floor_stream_map->next) {
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=floorid:%d %s:%d\r\n", floor_stream_map->m_floor_id, bfcp_interface_get_media_stream_str(bfcp_interface_object), floor_stream_map->m_stream_id);
+ }
+
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=setup:passive\r\n");
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=connection:new\r\n");
+ switch_snprintf(buf + strlen(buf), BFCPBUFLEN - strlen(buf), "a=bfcpver:%d\r\n", BFCP_VERSION);
+
+ switch_channel_set_variable(channel, SWITCH_BFCP_LOCAL_SDP, buf);
+
+ if (peer_session) {
+ peer_channel = switch_core_session_get_channel(peer_session);
+
+ if (sdp_type == SDP_TYPE_REQUEST) {
+ switch_channel_set_flag(peer_channel, CF_PEER_BFCP);
+ switch_channel_set_variable(peer_channel, SWITCH_PEER_BFCP_LOCAL_SDP, buf);
+ }
+
+ /* Set channel flag and variable in peer_channel only if peer_channel supports BFCP media */
+ if (switch_channel_test_flag(channel, CF_PEER_BFCP)) {
+ switch_channel_set_flag(peer_channel, CF_PEER_BFCP);
+ switch_channel_set_variable(peer_channel, SWITCH_PEER_BFCP_LOCAL_SDP, buf);
+ }
+
+ switch_core_session_rwunlock(peer_session);
+ }
+
+ mod_bfcp_mutex_unlock(&(bfcp_interface_object->bfcp_count_mutex));
+
+ switch_safe_free(buf);
+}
+
+/* To validate userID of BFCP */
+static switch_status_t bfcp_validate_userid(char *user_id)
+{
+ unsigned long user;
+ char *value;
+
+ user = strtoul(user_id, &value, 10);
+ if (!user || strcmp(value, "")) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* To validate conferenceID of BFCP */
+static switch_status_t bfcp_validate_confid(char *conf_id)
+{
+ unsigned long conference;
+ char *value;
+
+ conference = strtoul(conf_id, &value, 10);
+ if (!conference || strcmp(value, "")) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* To validate BFCP floor control */
+static switch_status_t bfcp_validate_floorctrl(char *floor_ctrl,
+ bfcp_interface bfcp_interface_object)
+{
+ if (!strcmp(floor_ctrl, "c-only")) {
+ bfcp_interface_set_floorctrl_mode(bfcp_interface_object, FLOOCTRL_MODE_CLIENT);
+ } else if (!strcmp(floor_ctrl, "c-s")) {
+ bfcp_interface_set_floorctrl_mode(bfcp_interface_object, FLOOCTRL_MODE_CLIENT_AND_SERVER);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " %s : Invalid value of Floor_ctrl\n", floor_ctrl);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* To validate BFCP floorID */
+static switch_status_t bfcp_validate_floorid(char *floor_id,
+ bfcp_interface bfcp_interface_object)
+{
+ unsigned long floor, stream_id;
+ char *value, *mstrm;
+
+ floor = strtoul(floor_id, &value, 10);
+ if (!floor) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ value++;
+
+ mstrm = token(&value, SPACE, TOKEN, ":");
+ if (!mstrm && strcmp(mstrm, "m-stream") && strcmp(mstrm, "mstrm")) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ stream_id = strtoul(value, &value, 10);
+ if (!stream_id || strcmp(value, "")) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ bfcp_interface_set_floor_stream_mapping(bfcp_interface_object, floor, stream_id);
+ bfcp_interface_set_media_stream_str(bfcp_interface_object, mstrm);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* To validate BFCP setup */
+static switch_status_t bfcp_validate_setup(char *setup,
+ bfcp_interface bfcp_interface_object)
+{
+ if (!strcmp(setup, "active") || !strcmp(setup, "actpass")) {
+ bfcp_interface_set_is_passive(bfcp_interface_object, false);
+ return SWITCH_STATUS_SUCCESS;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Invalid setup mode.\n");
+ return SWITCH_STATUS_FALSE;
+ }
+}
+
+/* To validate BFCP connection */
+static switch_status_t bfcp_validate_connection(char *connection)
+{
+ if (strcmp(connection, "new") && strcmp(connection, "existing")) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/bfcp_thread.h b/src/mod/applications/mod_bfcp/bfcp_thread.h
new file mode 100644
index 00000000000..3a77d94e7eb
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/bfcp_thread.h
@@ -0,0 +1,29 @@
+/*!
+ * MODULE : mod_bfcp
+ *
+ * \Owners : GSLab Pvt Ltd
+ * : www.gslab.com
+ * : © Copyright 2020 Great Software Laboratory. All rights reserved.
+ *
+ * The Original Code is mod_bfcp for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * Contributor(s):
+ *
+ * Aman Thakral
+ * Vishal Abhishek
+ *
+ * Reviewer(s):
+ *
+ * Sagar Joshi
+ * Prashanth Regalla
+ *
+ * bfcp_thread.h -- LIBBFCP ENDPOINT CODE
+ *
+ */
+#include
+
+typedef pthread_mutex_t mod_bfcp_mutex_t;
+#define mod_bfcp_mutex_init(a,b) pthread_mutex_init(a,b)
+#define mod_bfcp_mutex_destroy(a) pthread_mutex_destroy(a)
+#define mod_bfcp_mutex_lock(a) pthread_mutex_lock(a);
+#define mod_bfcp_mutex_unlock(a) pthread_mutex_unlock(a);
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/conf/bfcp.conf.xml b/src/mod/applications/mod_bfcp/conf/bfcp.conf.xml
new file mode 100644
index 00000000000..b76b4fb0d5b
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/conf/bfcp.conf.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/mod_bfcp.c b/src/mod/applications/mod_bfcp/mod_bfcp.c
new file mode 100644
index 00000000000..2d5212346db
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/mod_bfcp.c
@@ -0,0 +1,654 @@
+/*!
+ * MODULE : mod_bfcp
+ *
+ * Owners : GSLab Pvt Ltd
+ * : www.gslab.com
+ * : © Copyright 2020 Great Software Laboratory. All rights reserved.
+ *
+ * The Original Code is mod_bfcp for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * Contributor(s):
+ *
+ * Aman Thakral
+ * Vaibhav Sathe
+ * Pushp Raj
+ * Vishal Abhishek
+ *
+ * Reviewer(s):
+ *
+ * Sagar Joshi
+ * Prashanth Regalla
+ *
+ * mod_bfcp.c -- LIBBFCP ENDPOINT CODE
+ *
+ */
+#include "mod_bfcp.h"
+
+struct bfcp_conf_globals bfcp_conf_globals;
+
+/* Prototypes */
+SWITCH_MODULE_LOAD_FUNCTION(mod_bfcp_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_bfcp_shutdown);
+SWITCH_MODULE_DEFINITION(mod_bfcp, mod_bfcp_load, mod_bfcp_shutdown, NULL);
+
+/* Declaration of endpoint_interface of bfcp which will store function details and help to call from switch core */
+switch_endpoint_interface_t *bfcp_endpoint_interface;
+
+static switch_status_t bfcp_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg);
+
+/* State Handler API's called on different channel states to work on BFCP */
+static switch_status_t bfcp_on_execute(switch_core_session_t *session);
+static switch_status_t bfcp_on_exchange_media(switch_core_session_t *session);
+static switch_status_t bfcp_on_consume_media(switch_core_session_t *session);
+static switch_status_t bfcp_on_destroy(switch_core_session_t *session);
+
+/*! \brief A table of i/o routines that an endpoint interface of mod_bfcp can implement */
+switch_io_routines_t bfcp_io_routines = {
+ /*.outgoing_channel */ NULL,
+ /*.read_frame */ NULL,
+ /*.write_frame */ NULL,
+ /*.kill_channel */ NULL,
+ /*.send_dtmf */ NULL,
+ /*.receive_message */ bfcp_receive_message,
+ /*.receive_event */ NULL,
+ /*.state_change */ NULL,
+ /*.read_video_frame */ NULL,
+ /*.write_video_frame */ NULL,
+ /*.read_text_frame */ NULL,
+ /*.write_text_frame */ NULL,
+ /*.state_run*/ NULL,
+ /*.get_jb*/ NULL
+};
+
+/*! \brief A table of state handlers that an endpoint interface of mod_bfcp can implement */
+switch_state_handler_table_t bfcp_event_handlers = {
+ /*.on_init */ NULL,
+ /*.on_routing */ NULL,
+ /*.on_execute */ bfcp_on_execute,
+ /*.on_hangup */ NULL,
+ /*.on_exchange_media */ bfcp_on_exchange_media,
+ /*.on_soft_execute */ NULL,
+ /*.on_consume_media */ bfcp_on_consume_media,
+ /*.on_hibernate */ NULL,
+ /*.on_reset */ NULL,
+ /*.on_park */ NULL,
+ /*.on_reporting */ NULL,
+ /*.on_destroy */ bfcp_on_destroy
+};
+
+static switch_status_t bfcp_receive_message(switch_core_session_t *session,
+ switch_core_session_message_t *msg)
+{
+ bfcp_interface bfcp_interface_object;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:
+ {
+ switch_channel_set_flag(channel, CF_EARLY_MEDIA_BFCP);
+ bfcp_media_gen_local_sdp(session, SDP_TYPE_REQUEST);
+
+ if ((bfcp_interface_object = (bfcp_interface) switch_core_session_get_private_class(session, SWITCH_PVT_TERTIARY))) {
+ mod_bfcp_mutex_lock(&(bfcp_interface_object->bfcp_count_mutex));
+ bfcp_interface_add_conference_to_server(bfcp_interface_object);
+ mod_bfcp_mutex_unlock(&(bfcp_interface_object->bfcp_count_mutex));
+ }
+ }
+ break;
+ case SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS:
+ {
+ switch_channel_clear_flag(channel, CF_EARLY_MEDIA_BFCP);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Parsing BFCP-SDP, generating local SDP and adding BFCP related details to server */
+static switch_status_t bfcp_on_execute(switch_core_session_t *session)
+{
+ bfcp_interface bfcp_interface_object;
+
+ if (bfcp_parse(session) != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ bfcp_media_gen_local_sdp(session, SDP_TYPE_REQUEST);
+
+ if ((bfcp_interface_object = (bfcp_interface) switch_core_session_get_private_class(session, SWITCH_PVT_TERTIARY))) {
+ mod_bfcp_mutex_lock(&(bfcp_interface_object->bfcp_count_mutex));
+ bfcp_interface_add_conference_to_server(bfcp_interface_object);
+ mod_bfcp_mutex_unlock(&(bfcp_interface_object->bfcp_count_mutex));
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Parsing BFCP-SDP, generating local SDP and adding BFCP related details to server */
+static switch_status_t bfcp_on_exchange_media(switch_core_session_t *session)
+{
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ bfcp_interface bfcp_interface_object;
+
+ if (bfcp_parse(session) != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ bfcp_media_gen_local_sdp(session, SDP_TYPE_RESPONSE);
+
+ if (switch_channel_test_flag(channel, CF_PEER_BFCP) &&
+ switch_channel_test_flag(channel, CF_BFCP) &&
+ (bfcp_interface_object = (bfcp_interface) switch_core_session_get_private_class(session, SWITCH_PVT_TERTIARY))) {
+ mod_bfcp_mutex_lock(&(bfcp_interface_object->bfcp_count_mutex));
+ bfcp_interface_add_conference_to_server(bfcp_interface_object);
+ mod_bfcp_mutex_unlock(&(bfcp_interface_object->bfcp_count_mutex));
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Parsing BFCP-SDP, generating local SDP and adding BFCP related details to server */
+static switch_status_t bfcp_on_consume_media(switch_core_session_t *session)
+{
+ bfcp_interface bfcp_interface_object;
+
+ if (bfcp_parse(session) != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ bfcp_media_gen_local_sdp(session, SDP_TYPE_RESPONSE);
+
+ if ((bfcp_interface_object = (bfcp_interface) switch_core_session_get_private_class(session, SWITCH_PVT_TERTIARY))) {
+ mod_bfcp_mutex_lock(&(bfcp_interface_object->bfcp_count_mutex));
+ bfcp_interface_add_conference_to_server(bfcp_interface_object);
+ mod_bfcp_mutex_unlock(&(bfcp_interface_object->bfcp_count_mutex));
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Destroying BFCP interface object */
+static switch_status_t bfcp_on_destroy(switch_core_session_t *session)
+{
+ bfcp_interface bfcp_interface_object;
+
+ if ((bfcp_interface_object = (bfcp_interface) switch_core_session_get_private_class(session, SWITCH_PVT_TERTIARY))) {
+ bfcp_interface_destroy_interface(bfcp_interface_object);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* Initializing dummy values */
+SWITCH_DECLARE(void) bfcp_initialize_bfcp_configuration_parameter()
+{
+ bfcp_conf_globals.ip = NULL;
+ memset(bfcp_conf_globals.max_conf_per_server, 0, sizeof(bfcp_conf_globals.max_conf_per_server));
+ bfcp_conf_globals.max_floor_per_conf = 0;
+ memset(bfcp_conf_globals.max_floor_request_per_floor, 0, sizeof(bfcp_conf_globals.max_floor_request_per_floor));
+ bfcp_conf_globals.wait_time_chair_action = 0;
+ bfcp_conf_globals.bfcp_transport_tcp = 2;
+ bfcp_conf_globals.bfcp_transport_udp = 0;
+ bfcp_conf_globals.bfcp_port = 0;
+}
+
+/* Retrieving values from xml file and assigning it to configuration parameters */
+static switch_status_t do_config(switch_bool_t reload)
+{
+ char *cf = "bfcp.conf";
+ switch_xml_t cfg = NULL, xml = NULL, settings, param;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ switch_event_t *params = NULL;
+ char *end;
+ bfcp_initialize_bfcp_configuration_parameter();
+
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf);
+ status = SWITCH_STATUS_FALSE;
+ goto done;
+ }
+
+ if ((settings = switch_xml_child(cfg, "settings"))) {
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *name = (char *) switch_xml_attr_soft(param, "name");
+ char *value = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(name, "ip-address")) {
+ struct sockaddr_in sa;
+
+ if (inet_pton(AF_INET, value, &(sa.sin_addr))) {
+ bfcp_conf_globals.ip = value;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Starting FCS over ip : %s", bfcp_conf_globals.ip);
+ } else {
+ bfcp_conf_globals.ip = "0.0.0.0";
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_WARNING,
+ "Invalid ip address! Using all network interfaces %s\n",
+ bfcp_conf_globals.ip);
+ }
+
+ } else if (!strcasecmp(name, "max-conference-per-server")) {
+ int max_conf_per_server;
+
+ max_conf_per_server = strtol(value, &end, 10);
+
+ if (!strcmp(end, "") && max_conf_per_server > 0) {
+ bfcp_conf_globals.max_conf_per_server[0] = max_conf_per_server;
+ bfcp_conf_globals.max_conf_per_server[1] = max_conf_per_server;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Maximum concurrent conferences in a server %u\n",
+ bfcp_conf_globals.max_conf_per_server[0]);
+ } else {
+ bfcp_conf_globals.max_conf_per_server[0] = BFCP_MAX_CONF;
+ bfcp_conf_globals.max_conf_per_server[1] = BFCP_MAX_CONF;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_WARNING,
+ "Invalid parameter value, Using default value %u for maximum concurrent conferences in a server\n",
+ bfcp_conf_globals.max_conf_per_server[0]);
+ }
+
+ } else if (!strcasecmp(name, "max-floor-per-conference")) {
+ int max_floor_per_conf;
+
+ max_floor_per_conf = strtol(value, &end, 10);
+
+ if (!strcmp(end, "") && max_floor_per_conf > 0) {
+ bfcp_conf_globals.max_floor_per_conf = max_floor_per_conf;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Maximum concurrent floors in a conference %u\n",
+ bfcp_conf_globals.max_floor_per_conf);
+ } else {
+ bfcp_conf_globals.max_floor_per_conf = BFCP_MAX_FLOOR_PER_CONF;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_WARNING,
+ "Invalid parameter value, Using default value %u for maximum concurrent floors in a conference\n",
+ bfcp_conf_globals.max_floor_per_conf);
+ }
+
+ } else if (!strcasecmp(name, "max-floor-request-per-floor")) {
+ int max_floor_request_per_floor;
+
+ max_floor_request_per_floor = strtol(value, &end, 10);
+
+ if (!strcmp(end, "") && max_floor_request_per_floor > 0) {
+ bfcp_conf_globals.max_floor_request_per_floor[0] = max_floor_request_per_floor;
+ bfcp_conf_globals.max_floor_request_per_floor[1] = max_floor_request_per_floor;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Maximum FloorRequest for a floor %u\n",
+ bfcp_conf_globals.max_floor_request_per_floor[0]);
+ } else {
+ bfcp_conf_globals.max_floor_request_per_floor[0] = BFCP_MAX_FLOORREQUESTS_PER_FLOOR;
+ bfcp_conf_globals.max_floor_request_per_floor[1] = BFCP_MAX_FLOORREQUESTS_PER_FLOOR;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_WARNING,
+ "Invalid parameter value, Using default value %u for maximum FloorRequest for a floor\n",
+ bfcp_conf_globals.max_floor_request_per_floor[0]);
+ }
+
+ } else if (!strcasecmp(name, "wait-time-chair-action")) {
+ int wait_time_chair_action;
+
+ wait_time_chair_action = strtol(value, &end, 10);
+
+ if (!strcmp(end, "") && wait_time_chair_action > 0) {
+ bfcp_conf_globals.wait_time_chair_action = wait_time_chair_action;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Chair waiting time to take action %u seconds\n",
+ bfcp_conf_globals.wait_time_chair_action);
+ } else {
+ bfcp_conf_globals.wait_time_chair_action = BFCP_CHAIR_WAIT_REQUEST;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_WARNING,
+ "Invalid parameter value, Using default value %u seconds for chair waiting time\n",
+ bfcp_conf_globals.wait_time_chair_action);
+ }
+
+ } else if (!strcasecmp(name, "bfcp-transport-tcp")) {
+ int bfcp_transport_tcp;
+
+ if (strcmp(value, "")) {
+ bfcp_transport_tcp = strtol(value, &end, 10);
+
+ if (!strcmp(end, "") && (bfcp_transport_tcp == 0 || bfcp_transport_tcp == 1)) {
+ bfcp_conf_globals.bfcp_transport_tcp = bfcp_transport_tcp;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "FCS is up for %s\n",
+ (bfcp_conf_globals.bfcp_transport_tcp) ? "TCP/TLS/BFCP" : "TCP/BFCP");
+ } else {
+ bfcp_conf_globals.bfcp_transport_tcp = 2;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "FCS is down for TCP/TLS/BFCP and TCP/BFCP\n");
+ }
+ } else {
+ bfcp_conf_globals.bfcp_transport_tcp = 2;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "FCS is down for TCP/TLS/BFCP and TCP/BFCP\n");
+ }
+
+ } else if (!strcasecmp(name, "bfcp-port")) {
+ int bfcp_port;
+
+ bfcp_port = strtol(value, &end, 10);
+
+ if (!strcmp(end, "") && bfcp_port > 1024) {
+ bfcp_conf_globals.bfcp_port = bfcp_port;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FCS listening on port %u\n", bfcp_conf_globals.bfcp_port);
+ } else {
+ bfcp_conf_globals.bfcp_port = BFCP_FCS_DEFAULT_PORT;
+ switch_log_printf(SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_WARNING,
+ "Invalid parameter value, Using default value %u for port over which FCS will listen\n",
+ bfcp_conf_globals.bfcp_port);
+ }
+
+ } else if (!strcasecmp(name, "bfcp-transport-udp")) {
+ int bfcp_transport_udp;
+
+ bfcp_transport_udp = strtol(value, &end, 10);
+
+ if (!strcmp(end, "") && bfcp_transport_udp == 1) {
+ bfcp_conf_globals.bfcp_transport_udp = 1;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "FCS is up for UDP/BFCP\n");
+ } else {
+ bfcp_conf_globals.bfcp_transport_udp = 0;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "FCS is down for UDP/BFCP\n");
+ }
+ }
+ }
+ }
+
+ if ((!bfcp_conf_globals.bfcp_transport_udp) &&
+ (bfcp_conf_globals.bfcp_transport_tcp > 1)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FCS is down for all protocols, unloading mod_bfcp\n");
+ status = SWITCH_STATUS_FALSE;
+ goto done;
+ }
+
+ if (!bfcp_conf_globals.max_conf_per_server) {
+ bfcp_conf_globals.max_conf_per_server[0] = BFCP_MAX_CONF;
+ bfcp_conf_globals.max_conf_per_server[1] = BFCP_MAX_CONF;
+ } else if (!bfcp_conf_globals.max_floor_per_conf) {
+ bfcp_conf_globals.max_floor_per_conf = BFCP_MAX_FLOOR_PER_CONF;
+ } else if (!bfcp_conf_globals.max_floor_request_per_floor) {
+ bfcp_conf_globals.max_floor_request_per_floor[0] = BFCP_MAX_FLOORREQUESTS_PER_FLOOR;
+ bfcp_conf_globals.max_floor_request_per_floor[1] = BFCP_MAX_FLOORREQUESTS_PER_FLOOR;
+ } else if (!bfcp_conf_globals.wait_time_chair_action) {
+ bfcp_conf_globals.wait_time_chair_action = BFCP_CHAIR_WAIT_REQUEST;
+ } else if(!bfcp_conf_globals.bfcp_port) {
+ bfcp_conf_globals.bfcp_port = BFCP_FCS_DEFAULT_PORT;
+ }
+
+ done:
+ return status;
+}
+
+SWITCH_STANDARD_API(bfcp_function)
+{
+ char *argv[1024] = { 0 };
+ int argc = 0;
+ uint32_t max_request = 0, max_conf = 0;
+ char *mycmd = NULL;
+ bfcp_conference *lconferences = NULL;
+ bfcp_list_floors *list_floor = NULL;
+ bfcp_list_users *list_user = NULL;
+ bfcp_user *user = NULL;
+ floor_query *query = NULL;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ struct bfcp_server *bfcp_srv;
+
+ static const char bfcp_welcome[] = " BFCP CONFERENCE SERVER \n"
+ "**********************************************************************************\n"
+ "* bfcp help *\n"
+ "* bfcp 1.Change_max_number_of_conference [1-65535] *\n"
+ "* bfcp 2.Change_max_number_of_requests_for_same_floor [1-65535] *\n"
+ "* bfcp 3.Show_the_conferences_in_the_BFCP_Server *\n"
+ "* bfcp 4.Show_configuration_parameters *\n"
+ "**********************************************************************************\n";
+
+ if (zstr(cmd)) {
+ /* Display options for both tcp & udp server */
+ stream->write_function(stream, "%s", bfcp_welcome);
+ goto done;
+ }
+
+ if (!(mycmd = strdup(cmd))) {
+ /* Memory Error */
+ status = SWITCH_STATUS_MEMERR;
+ goto done;
+ }
+
+ if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
+ stream->write_function(stream, "%s", bfcp_welcome);
+ goto done;
+ }
+
+ if (!strcasecmp(argv[0], "udp")) {
+ bfcp_srv = bfcp_srv_udp;
+ } else if (!strcasecmp(argv[0], "tcp")) {
+ bfcp_srv = bfcp_srv_tcp;
+ } else if (!strcasecmp(argv[0], "help")) {
+ stream->write_function(stream, "%s", bfcp_welcome);
+ goto done;
+ } else {
+ stream->write_function(stream, "-ERR Usage: Invalid option. Please refer help option.\n");
+ goto done;
+ }
+
+ if (argc > 1) {
+ if (!strcasecmp(argv[1], "1.Change_max_number_of_conferences")) {
+ if (argc == 3) {
+ char *end;
+ max_conf = strtoul(argv[2], &end, 10);
+ if (max_conf < 1 || max_conf > 65535 || strcmp(end, "")) {
+ stream->write_function(stream, "-ERR Usage: Please enter value in range [1-65535]\n");
+ goto done;
+ }
+
+ if (bfcp_change_number_bfcp_conferences_server(bfcp_srv, max_conf) < 0) {
+ stream->write_function(stream, "Couldn't change maximum allowed conferences...\n");
+ } else {
+ int i = (!strcasecmp(argv[0], "tcp")) ? 0 : 1;
+ stream->write_function(stream, "Maximum allowed number of conferences changed to %i \n", max_conf);
+ bfcp_conf_globals.max_conf_per_server[i] = max_conf;
+ }
+ } else {
+ stream->write_function(stream, "-ERR Usage: bfcp %s 1.Change_max_number_of_conferences [1-65535]\n", !strcmp(argv[0], "udp") ? "udp" : "tcp");
+ }
+ goto done;
+
+ } else if (!strcasecmp(argv[1], "2.Change_max_number_of_requests_for_floor")) {
+ if (argc == 3) {
+ char *end;
+ max_request = strtoul(argv[2], &end, 10);
+ if(max_request < 1 || max_request > 65535 || strcmp(end, "")) {
+ stream->write_function(stream, "-ERR Usage: Please enter value in range [1-65535]\n");
+ goto done;
+ }
+ if (bfcp_change_user_req_floors_server(bfcp_srv, max_request) < 0) {
+ stream->write_function(stream, "Couldn't change the maximum number of requests...\n");
+ } else {
+ int i = (!strcasecmp(argv[0], "tcp")) ? 0 : 1;
+ stream->write_function(stream, "Maximum number of requests changed to %i\n", max_request);
+ bfcp_conf_globals.max_floor_request_per_floor[i] = max_request;
+ }
+ } else {
+ stream->write_function(stream, "-ERR Usage: bfcp %s 2.Change_max_number_of_requests_for_floor [1-65535]\n", !strcmp(argv[0], "udp") ? "udp" : "tcp");
+ }
+ goto done;
+
+ } else if (!strcasecmp(argv[1], "3.Show_conferences_in_the_BFCP_Server")) {
+ if (bfcp_srv == NULL) {
+ stream->write_function(stream, "The Floor Control Server is not up\n");
+ goto done;
+ }
+ lconferences = bfcp_srv->list_conferences;
+
+ if (lconferences == NULL || bfcp_srv->Actual_number_conference == 0) {
+ stream->write_function(stream, "There is no conference in the FCS\n");
+ goto done;
+ }
+
+ for (int i = 0; i < bfcp_srv->Actual_number_conference; i++) {
+ stream->write_function(stream, "CONFERENCE:\n");
+ stream->write_function(stream, "ConferenceID: %u\n", bfcp_srv->list_conferences[i].conferenceID);
+ stream->write_function(stream, "\n");
+ /* Print the list of floors */
+ list_floor = bfcp_srv->list_conferences[i].floor;
+
+ if (list_floor) {
+ stream->write_function(stream, "Maximum number of floors in the conference: %i\n", list_floor->number_floors + 1);
+ stream->write_function(stream, "FLOORS\n");
+
+ for (int j = 0; j < list_floor->actual_number_floors; j++) {
+ stream->write_function(stream, "FloorID: %u, ", list_floor->floors[j].floorID);
+ stream->write_function(stream, "ChairID: %u, " , list_floor->floors[j].chairID);
+
+ if (list_floor->floors[j].floorState == BFCP_FLOOR_STATE_WAITING) {
+ stream->write_function(stream, "state: FREE\n");
+ } else if (list_floor->floors[j].floorState == BFCP_FLOOR_STATE_ACCEPTED) {
+ stream->write_function(stream, "state: ACCEPTED\n");
+ } else if (list_floor->floors[j].floorState >= BFCP_FLOOR_STATE_GRANTED) {
+ stream->write_function(stream, "state: GRANTED\n");
+ } else {
+ stream->write_function(stream, "state: ERROR!\n");
+ }
+
+ stream->write_function(stream, "Number of simultaneous granted users:% i\n", list_floor->floors[j].limit_granted_floor-1);
+
+ query = list_floor->floors[j].floorquery;
+
+ if (query) {
+ stream->write_function(stream, "QUERY LIST\n");
+ }
+
+ while (query) {
+ stream->write_function(stream, "User: %u\n", query->userID);
+ query = query->next;
+ }
+ }
+ }
+
+ /* Print the list of users */
+ if ((list_user = bfcp_srv->list_conferences[i].user)) {
+ stream->write_function(stream, "Maximum number of request per floors in the conference: %i\n", list_user->max_number_floor_request);
+ stream->write_function(stream, "USERS\n");
+
+ user = list_user->users;
+ while (user) {
+ stream->write_function(stream, "UserID: %u\n", user->userID);
+ user = user->next;
+ }
+ }
+
+ /* Print the list of Pending requests */
+ print_requests_list(bfcp_srv, i, BFCP_PENDING, stream);
+ /* Print the list of Accepted requests */
+ print_requests_list(bfcp_srv, i, BFCP_ACCEPTED, stream);
+ /* Print the list of Granted requests */
+ print_requests_list(bfcp_srv, i, BFCP_GRANTED, stream);
+ }
+
+ goto done;
+ } else if (!strcasecmp(argv[1], "4.Show_configuration_parameters")) {
+ int i = (!strcasecmp(argv[0], "tcp")) ? 0 : 1;
+ stream->write_function(stream, "Maximum number of conference in a server:%i\n", bfcp_conf_globals.max_conf_per_server[i]);
+ stream->write_function(stream, "Maximum number of request per floor:%i\n", bfcp_conf_globals.max_floor_request_per_floor[i]);
+ stream->write_function(stream, "Maximum number of floor in a conference:%i\n", bfcp_conf_globals.max_floor_per_conf);
+ if (bfcp_conf_globals.bfcp_transport_tcp == 1) {
+ stream->write_function(stream, "TCP/TLS/BFCP socket is up.\n");
+ } else if (bfcp_conf_globals.bfcp_transport_tcp == 0) {
+ stream->write_function(stream, "TCP/BFCP socket is up.\n");
+ } else {
+ stream->write_function(stream, "TCP/BFCP or TCP/TLS/BFCP socket is down.\n");
+ }
+
+ if (bfcp_conf_globals.bfcp_transport_udp == 1) {
+ stream->write_function(stream, "UDP/BFCP socket is up.\n");
+ } else {
+ stream->write_function(stream, "UDP/BFCP socket is down.\n");
+ }
+
+ stream->write_function(stream, "BFPC server is running on port:%i\n", bfcp_conf_globals.bfcp_port);
+ goto done;
+ }
+ } else {
+ stream->write_function(stream, "-ERR Usage: Refer help option");
+ }
+
+ done:
+ switch_safe_free(mycmd);
+ return status;
+}
+
+/* Macro expands to: switch_status_t mod_bfcp_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
+SWITCH_MODULE_LOAD_FUNCTION(mod_bfcp_load)
+{
+ /* indicate that the module should continue to be loaded */
+ switch_api_interface_t *api_interface;
+
+ if (do_config(SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ /* Pointer to FCS instance */
+ bfcp_srv_tcp = NULL;
+ bfcp_srv_udp = NULL;
+
+ /* Flag to maintain server type */
+ udp_server = 0;
+ tcp_server = 0;
+
+ if (start_bfcp_server() != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ bfcp_endpoint_interface = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
+ bfcp_endpoint_interface->interface_name = "bfcp";
+ bfcp_endpoint_interface->state_handler = &bfcp_event_handlers;
+ bfcp_endpoint_interface->io_routines = &bfcp_io_routines;
+
+ conference_id_counter = 0;
+ user_id_counter = 0;
+
+ SWITCH_ADD_API(api_interface, "bfcp", "BFCP API", bfcp_function, "syntax");
+
+
+ switch_console_set_complete("add bfcp udp");
+ switch_console_set_complete("add bfcp udp 1.Change_max_number_of_conferences");
+ switch_console_set_complete("add bfcp udp 2.Change_max_number_of_requests_for_floor");
+ switch_console_set_complete("add bfcp udp 3.Show_conferences_in_the_BFCP_Server");
+ switch_console_set_complete("add bfcp udp 4.Show_configuration_parameters");
+ switch_console_set_complete("add bfcp tcp");
+ switch_console_set_complete("add bfcp tcp 1.Change_max_number_of_conferences");
+ switch_console_set_complete("add bfcp tcp 2.Change_max_number_of_requests_for_floor");
+ switch_console_set_complete("add bfcp tcp 3.Show_conferences_in_the_BFCP_Server");
+ switch_console_set_complete("add bfcp tcp 4.Show_configuration_parameters");
+ switch_console_set_complete("add bfcp help");
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/*
+ Called when the system shuts down
+ Macro expands to: switch_status_t mod_bfcp_shutdown() */
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_bfcp_shutdown)
+{
+ /* Condtion to check whether BFCP supported SIP call running or not */
+ if ((bfcp_srv_tcp && bfcp_srv_tcp->Actual_number_conference != 0) || (bfcp_srv_udp && bfcp_srv_udp->Actual_number_conference != 0)) {
+ return SWITCH_STATUS_NOUNLOAD;
+ }
+
+ stop_bfcp_server();
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Shutting Down BFCP\n");
+
+ return SWITCH_STATUS_UNLOAD;
+}
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/mod_bfcp.h b/src/mod/applications/mod_bfcp/mod_bfcp.h
new file mode 100644
index 00000000000..11db532f502
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/mod_bfcp.h
@@ -0,0 +1,70 @@
+/*!
+ * MODULE : mod_bfcp
+ *
+ * Owners : GSLab Pvt Ltd
+ * : www.gslab.com
+ * : © Copyright 2020 Great Software Laboratory. All rights reserved.
+ *
+ * The Original Code is mod_bfcp for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * Contributor(s):
+ *
+ * Aman Thakral
+ * Vaibhav Sathe
+ * Pushp Raj
+ * Vishal Abhishek
+ *
+ * Reviewer(s):
+ *
+ * Sagar Joshi
+ * Prashanth Regalla
+ *
+ * mod_bfcp.h -- LIBBFCP ENDPOINT CODE
+ *
+ */
+#include
+#include "switch_stun.h"
+/* Increment an attribute pointer to the next attribute in it's packet. */
+#define _switch_stun_packet_next_attribute(attribute, end) (attribute && (attribute = (switch_stun_packet_attribute_t *) (attribute->value + ntohs(attribute->length))) && ((void *)attribute < end) && ntohs(attribute->length) && ((void *)(attribute + ntohs(attribute->length)) < end))
+/* Obtain the padded length of an attribute's value. */
+#define _switch_stun_attribute_padded_length(attribute) ((uint16_t)(ntohs(attribute->length) + (sizeof(uint32_t)-1)) & ~sizeof(uint32_t))
+#define BFCPBUFLEN 200 /* BFCP SDP length "m=application 51762 UDP/BFCP *" + attributes */
+
+/* Library for integrating libbfcp with Freeswitch */
+#include "bfcp_interface.h"
+
+/*! \brief structure for configuration parameters */
+struct bfcp_conf_globals {
+ char* ip;
+ uint16_t max_conf_per_server[2]; /* index 0 : TCP, 1 : UDP */
+ uint16_t max_floor_request_per_floor[2]; /* index 0 : TCP, 1 : UDP */
+ uint16_t bfcp_transport_tcp;
+ uint16_t bfcp_transport_udp;
+ uint16_t bfcp_port;
+ uint32_t wait_time_chair_action;
+ uint16_t max_floor_per_conf;
+};
+
+extern struct bfcp_conf_globals bfcp_conf_globals;
+
+typedef switch_status_t (*bfcp_command_t) (bfcp server, int index, int status, switch_stream_handle_t *stream);
+
+/* Pointer to FLOOR CONTROL SERVER (FCS) instance */
+struct bfcp_server *bfcp_srv_udp;
+struct bfcp_server *bfcp_srv_tcp;
+
+/*!
+ \brief Generate LOCAL SDP for BFCP media which is sent to current/peer leg
+ \param session Pointer to session of current leg
+ \param sdp_type REQUEST or RESPONSE
+ */
+SWITCH_DECLARE(void) bfcp_media_gen_local_sdp(switch_core_session_t *session,
+ switch_sdp_type_t sdp_type);
+
+/*!
+ \brief Parse and validate BFCP attributes
+ \param session Pointer to sesion of current leg
+ \return SWITCH_STATUS_SUCCESS : If validation is successful
+ SWITCH_STATUS_FALSE : Otherwise
+ */
+switch_status_t bfcp_parse(switch_core_session_t *session);
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/unit_test_bfcp/README b/src/mod/applications/mod_bfcp/unit_test_bfcp/README
new file mode 100644
index 00000000000..2445fdfa9aa
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/unit_test_bfcp/README
@@ -0,0 +1,81 @@
+ FreeSWITCH BFCP INTEGRATION
+ ===========================
+
+********************************************************************************************************************************
+* NOTE: We used SIPp to verify the negotiation of BFCP only. There is no media flow involved in the SIPp scenario. *
+* SIPp scenario (we used) is attach in folder(SIPp) named uac.xml(legA) and uas.xml(legB) and also with telepresence *
+* unit (Yealink VC120, Polycom HDX 8000). Call is initiated by Polycom or Yealink and screen in being shared by Polycom *
+* to Yealink. *
+********************************************************************************************************************************
+
+
+Contents
+--------
+
+ 1. Steps to be followed
+ 2. Test Environment
+ 3. Running FreeSWITCH with BFCP
+
+
+================================================================================================================================
+
+1. Steps to be followed
+-----------------------
+
+ 1. Building libbfcp (/libs/libbfcp)
+ -----------------------------------
+
+ 1. Use the following command
+ > cd libs/libbfcp
+ > ./configure
+ > make
+ > make install
+ 2. After the building the libbfcp, copy "libbfcprel.so" which is present in libbfcp/lib file in
+ usr/lib and run the below command.
+ > cd usr/lib
+ > ldconfig
+
+ 2. Flags needs to be added in sip-profile (usr/local/freeswitch/conf/sip-profile/internal.xml)
+ ----------------------------------------------------------------------------------------------
+ i.
+ ii.
+ iii.
+ iv.
+ v.
+ vi.
+
+ 3. Flags needs to be added in vars.xml (usr/local/freeswitch/conf/vars.xml)
+ ---------------------------------------------------------------------------
+ i.
+
+ 4. Add the following line in modules.conf
+ -----------------------------------------
+ i. applications/mod_bfcp
+
+ 5. Add or set the following line in dialplan (usr/local/freeswitch/conf/dialplan/default.xml)
+ ---------------------------------------------------------------------------------------------
+ i.
+
+
+2. Test Environment
+-------------------
+ 1. FreeSWITCH Version 1.9.0+git~20190610T114556Z~22418f14de~64bit (git 22418f1 2019-06-10 11:45:56Z 64bit)
+ 2. Ubuntu 14.04 LTS
+ 3. Telepresence Unit with BFCP enabled. (we used :- Yealink VC120, Polycom HDX 8000, SIPp with pcap support)
+ (we tested the with codec H264)
+ 4. SIPp version: SIPp v3.2-PCAP
+
+
+3. Running FreeSWITCH with BFCP
+-------------------------------
+ 1. Configure the FreeSWICTH:
+ > ./configure
+ > make
+ > make install
+ 2. Run FreeSWITCH
+ 3. Load mod bfcp:
+ > load mod_bfcp
+ 4. Register the users(Endpoints) with FreeSWITCH and make a call(bfcp enabled).
+
+
+
diff --git a/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/register.xml b/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/register.xml
new file mode 100644
index 00000000000..741daac3f13
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/register.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [service]
+ Call-ID: [call_id]
+ CSeq: 1 REGISTER
+ Contact: sip:[service]@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Expires: 26400
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ ]]>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/sipp_test.csv b/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/sipp_test.csv
new file mode 100644
index 00000000000..65d73205556
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/sipp_test.csv
@@ -0,0 +1,2 @@
+SEQUENTIAL
+1008;1007
\ No newline at end of file
diff --git a/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/uac.xml b/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/uac.xml
new file mode 100644
index 00000000000..816fe0ec6fc
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/uac.xml
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [field1]
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:[field0]@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
+ s=TheSession
+ c=IN IP[media_ip_type] [media_ip]
+ t=0 0
+ m=audio [media_port] RTP/AVP 8
+ a=connection:new
+ a=label:myCustomLabel
+ a=setup:actpass
+ a=ptime:20
+ m=video [media_port+2] RTP/AVP 127
+ a=rtpmap:127 H264/90000
+ a=fmtp:127 profile-level-id=42801f; max-mbps=216000; max-fs=3600; sar=13
+ a=content:main
+ a=label:1
+ m=application 49426 UDP/BFCP *
+ a=confid:4488
+ a=userid:1001
+ a=floorctrl:c-only
+ a=floorid:1 mstrm:2
+ a=setup:active
+ a=connection:new
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [service] [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:1001@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [field1] [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 INVITE
+ Contact: sip:[field0]@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687638 IN IP[local_ip_type] [local_ip]
+ s=TheSession
+ c=IN IP[media_ip_type] [media_ip]
+ t=0 0
+ m=audio [media_port] RTP/AVP 8
+ a=connection:new
+ a=label:myCustomLabel
+ a=setup:actpass
+ a=ptime:20
+ m=video [media_port+2] RTP/AVP 127
+ a=rtpmap:127 H264/90000
+ a=fmtp:127 profile-level-id=42801f; max-mbps=216000; max-fs=3600; sar=13
+ a=content:main
+ a=label:1
+ m=application 49426 UDP/BFCP *
+ a=confid:4488
+ a=userid:1001
+ a=floorctrl:c-only
+ a=floorid:1 mstrm:2
+ a=setup:active
+ a=connection:new
+ m=video [media_port+4] RTP/AVP 98
+ a=rtpmap:98 H264/90000
+ a=fmtp:98 profile-level-id=42801f; max-mbps=206000; max-fs=3800; sar=13
+ a=content:slides
+ a=label:2
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [service] [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 ACK
+ Contact: sip:1001@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+
+
+
+
+ ;tag=[pid]SIPpTag00[call_number]
+ To: [service] [peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 BYE
+ Contact: sip:1001@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/uas.xml b/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/uas.xml
new file mode 100644
index 00000000000..9bdd105c163
--- /dev/null
+++ b/src/mod/applications/mod_bfcp/unit_test_bfcp/SIPp/uas.xml
@@ -0,0 +1,201 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Content-Length: [len]
+
+ ]]>
+
+
+
+
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
+ s=-
+ c=IN IP[media_ip_type] [media_ip]
+ t=0 0
+ m=audio [media_port] RTP/AVP 8
+ a=connection:new
+ a=label:myCustomLabel
+ a=setup:actpass
+ a=ptime:20
+ m=video [media_port+2] RTP/AVP 127
+ a=rtpmap:127 H264/90000
+ a=fmtp:127 profile-level-id=42801f; max-mbps=216000; max-fs=3600; sar=13
+ a=content:main
+ a=label:3
+ m=application 49428 UDP/BFCP *
+ a=confid:4488
+ a=userid:1002
+ a=floorctrl:c-only
+ a=floorid:1 mstrm:4
+ a=setup:active
+ a=connection:new
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Content-Length: [len]
+
+ ]]>
+
+
+
+
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
+ s=-
+ c=IN IP[media_ip_type] [media_ip]
+ t=0 0
+ m=audio [media_port] RTP/AVP 8
+ a=connection:new
+ a=label:myCustomLabel
+ a=setup:actpass
+ a=ptime:20
+ m=video [media_port+2] RTP/AVP 127
+ a=rtpmap:127 H264/90000
+ a=fmtp:127 profile-level-id=42801f; max-mbps=216000; max-fs=3600; sar=13
+ a=content:main
+ a=label:3
+ m=application 49428 UDP/BFCP *
+ a=confid:4488
+ a=userid:1002
+ a=floorctrl:c-only
+ a=floorid:1 mstrm:4
+ a=setup:active
+ a=connection:new
+ m=video [media_port+4] RTP/AVP 98
+ a=rtpmap:98 H264/90000
+ a=fmtp:98 profile-level-id=42801f; max-mbps=206000; max-fs=3800; sar=13
+ a=content:slides
+ a=label:4
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+ Content-Length: 0
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index ca6be2c16df..015126311ef 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -43,6 +43,10 @@
static switch_t38_options_t * switch_core_media_process_udptl(switch_core_session_t *session, sdp_session_t *sdp, sdp_media_t *m);
static void switch_core_media_find_zrtp_hash(switch_core_session_t *session, sdp_session_t *sdp);
static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp, switch_sdp_type_t sdp_type);
+static void switch_core_media_copy_media_attribute(switch_core_session_t *session, sdp_media_t *sdp_media);
+static void switch_core_media_set_media_protocol(switch_core_session_t *session, sdp_media_t *sdp_media, switch_sdp_type_t sdp_type);
+SWITCH_DECLARE(switch_status_t) switch_core_media_check_bfcp(sdp_media_t *sdp_media);
+static switch_status_t switch_core_media_check_supported_media_attribute(sdp_attribute_t *media_attribute, switch_media_type_t media_type);
static void gen_ice(switch_core_session_t *session, switch_media_type_t type, const char *ip, switch_port_t port);
//#define GOOGLE_ICE
#define RTCP_MUX
@@ -83,6 +87,7 @@ struct media_helper {
switch_mutex_t *file_write_mutex;
int up;
int ready;
+ int video_index; /* index for video media used in video_helper_thread */
};
typedef enum {
@@ -207,6 +212,10 @@ typedef struct switch_rtp_engine_s {
void *engine_user_data;
int8_t engine_function_running;
switch_frame_buffer_t *write_fb;
+ struct switch_rtp_engine_s *next; /* Used for additional video media */
+ int already_did[128]; /*used as flag for codec parsed in switch_core_session_get_payload_code() */
+ struct media_attribute_s *media_attribute; /* Stores attribute of particular media (all other attribute, except RTP related attribute) */
+ media_proto_name_t *media_proto; /* char* for protocol used by media */
} switch_rtp_engine_t;
#define MAX_REJ_STREAMS 10
@@ -219,7 +228,9 @@ struct switch_media_handle_s {
switch_rtp_engine_t engines[SWITCH_MEDIA_TYPE_TOTAL];
switch_msrp_session_t *msrp_session;
switch_mutex_t *read_mutex[SWITCH_MEDIA_TYPE_TOTAL];
+ switch_mutex_t *read_presentation_mutex;
switch_mutex_t *write_mutex[SWITCH_MEDIA_TYPE_TOTAL];
+ switch_mutex_t *write_presentation_mutex;
char *codec_order[SWITCH_MAX_CODECS];
int codec_order_last;
const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
@@ -241,7 +252,8 @@ struct switch_media_handle_s {
switch_payload_t cng_ianacodes[SWITCH_MAX_CODECS];
char *fmtps[SWITCH_MAX_CODECS];
int video_count;
-
+ int video_media_count; /* Keeps the count of video media present in SDP but also used as iterator in most of API's */
+ int video_pt_count[SWITCH_MAX_VIDEO_MEDIA]; /* Keeps the count of supported payload type of each video media */
int rates[SWITCH_MAX_CODECS];
uint32_t num_rates;
@@ -291,6 +303,9 @@ switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID] = {
{ "AES_CM_128_NULL_AUTH", "", AES_CM_128_NULL_AUTH, 30, 14}
};
+/* It will asssign the default values for additional video media */
+SWITCH_DECLARE(void) switch_media_add_video_rtp_engine(switch_core_session_t *session, switch_rtp_engine_t *v_engine);
+
SWITCH_DECLARE(switch_rtp_crypto_key_type_t) switch_core_media_crypto_str2type(const char *str)
{
int i;
@@ -430,6 +445,39 @@ SWITCH_DECLARE(uint32_t) switch_core_media_get_video_fps(switch_core_session_t *
return fps;
}
+/* Returning payload_map of particular media type and may need to work on it for multiple video media*/
+SWITCH_DECLARE(payload_map_t *) switch_core_media_get_payload_map(switch_core_session_t *session, switch_media_type_t type)
+{
+ switch_rtp_engine_t *engine;
+
+ switch_assert(session);
+
+ engine = &session->media_handle->engines[type];
+
+ if (type == SWITCH_MEDIA_TYPE_VIDEO)
+ for (int i = 1; i < session->media_handle->video_media_count; i++)
+ engine = engine->next; /*Move video engine to additional video engine*/
+
+ return engine->payload_map;
+
+}
+
+/* Returning media attributes and may need to work on it */
+SWITCH_DECLARE(media_attribute_t *) switch_core_media_get_media_attribute(switch_core_session_t *session, switch_media_type_t type)
+{
+ switch_rtp_engine_t *engine;
+
+ switch_assert(session);
+
+ engine = &session->media_handle->engines[type];
+
+ if (type == SWITCH_MEDIA_TYPE_VIDEO)
+ for (int i = 1; i < session->media_handle->video_media_count; i++)
+ engine = engine->next; /*Move video engine to additional video engine*/
+
+ return engine->media_attribute;
+}
+
SWITCH_DECLARE(void) switch_core_media_pass_zrtp_hash2(switch_core_session_t *aleg_session, switch_core_session_t *bleg_session)
{
_switch_core_media_pass_zrtp_hash2(aleg_session, bleg_session, SWITCH_MEDIA_TYPE_AUDIO);
@@ -751,6 +799,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core
switch_rtp_engine_t *engine;
switch_payload_t pt = 0, recv_pt = 0;
int found = 0;
+ int i = 0; /* Maintain count of rtp_engine for video in use */
char *fmtp = NULL;
switch_assert(session);
@@ -761,6 +810,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core
engine = &smh->engines[type];
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ i++;
+ if (!smh->video_media_count)
+ smh->video_media_count++;
+ }
+ next_engine:
switch_mutex_lock(smh->sdp_mutex);
for (pmap = engine->payload_map; pmap ; pmap = pmap->next) {
char *fmtp_a = pmap->rm_fmtp;
@@ -772,11 +827,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core
if (!strcasecmp(pmap->iananame, iananame) && !strcasecmp(fmtp_a, fmtp_in) && (!rate || (rate == pmap->rate))) {
- pt = pmap->pt;
- recv_pt = pmap->recv_pt;
- fmtp = pmap->rm_fmtp;
- found++;
- break;
+ if (engine->already_did[pmap->pt] == 0) {
+ pt = pmap->pt;
+ recv_pt = pmap->recv_pt;
+ fmtp = pmap->rm_fmtp;
+ engine->already_did[pmap->pt] = 1;
+ found++;
+ break;
+ }
}
}
switch_mutex_unlock(smh->sdp_mutex);
@@ -794,6 +852,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core
}
return SWITCH_STATUS_SUCCESS;
+ } else {
+ if (engine->next != NULL) {
+ engine = engine ->next; /* If currently parsed payload code not found in current media engine, then move to engine->next, if exist */
+ i++;
+ if (i > smh->video_media_count) {
+ smh->video_media_count++;
+ }
+ goto next_engine;
+ }
}
return SWITCH_STATUS_FALSE;
@@ -826,6 +893,11 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se
engine = &smh->engines[type];
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ for (int i = 1; i < smh->video_media_count; i++)
+ engine = engine->next; /*Move video engine to additional video engine*/
+ }
+
switch_mutex_lock(smh->sdp_mutex);
@@ -851,6 +923,8 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se
break;
+ case SWITCH_MEDIA_TYPE_APPLICATION:
+ break;
}
if (exists) {
@@ -2148,13 +2222,26 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].crypto_type = CRYPTO_INVALID;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_APPLICATION].type = SWITCH_MEDIA_TYPE_APPLICATION;
+
switch_channel_set_variable(session->channel, "video_media_flow", "disabled");
switch_channel_set_variable(session->channel, "audio_media_flow", "disabled");
switch_channel_set_variable(session->channel, "text_media_flow", "disabled");
+ switch_channel_set_variable(session->channel, "application_media_flow", "disabled");
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].smode = SWITCH_MEDIA_FLOW_DISABLED;
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].smode = SWITCH_MEDIA_FLOW_DISABLED;
session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].smode = SWITCH_MEDIA_FLOW_DISABLED;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_APPLICATION].smode = SWITCH_MEDIA_FLOW_DISABLED;
+
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].media_proto = NULL;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].media_attribute = NULL;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].media_proto = NULL;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].media_attribute = NULL;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].media_proto = NULL;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].media_attribute = NULL;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_APPLICATION].media_proto = NULL;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_APPLICATION].media_attribute = NULL;
for (i = 0; i < CRYPTO_INVALID; i++) {
session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].ssec[i].crypto_type = i;
@@ -2188,6 +2275,9 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t
session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].ssrc =
(uint32_t) ((intptr_t) &session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT] + (uint32_t) time(NULL) / 2);
+ memset(session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].already_did, 0, sizeof(session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].already_did));
+ memset(session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].already_did, 0, sizeof(session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].already_did));
+ memset(session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].already_did, 0, sizeof(session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].already_did));
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].payload_map = switch_core_alloc(session->pool, sizeof(payload_map_t));
@@ -2204,6 +2294,9 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t
session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].cur_payload_map = session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].payload_map;
session->media_handle->engines[SWITCH_MEDIA_TYPE_TEXT].cur_payload_map->current = 1;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_APPLICATION].payload_map = switch_core_alloc(session->pool, sizeof(payload_map_t));
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_APPLICATION].cur_payload_map = session->media_handle->engines[SWITCH_MEDIA_TYPE_APPLICATION].payload_map;
+ session->media_handle->engines[SWITCH_MEDIA_TYPE_APPLICATION].cur_payload_map->current = 1;
switch_channel_set_flag(session->channel, CF_DTLS_OK);
status = SWITCH_STATUS_SUCCESS;
@@ -2264,6 +2357,13 @@ SWITCH_DECLARE(switch_media_flow_t) switch_core_session_media_flow(switch_core_s
}
engine = &smh->engines[type];
+
+ /* There can be case where there will be multiple video media channel and for each video channel there will be thread running for RTP packet flow,
+ below logic handles video_rtp_engine to use by comparing thread_id stored in rtp_engine with thread_id of currently running thread */
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ if (engine->thread_id != switch_thread_self() && engine->next && engine->next->thread_id == switch_thread_self()) engine = engine->next;
+ }
+
flow = engine->smode;
end:
@@ -2337,14 +2437,20 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses
const char *ocodec = NULL, *val;
switch_media_handle_t *smh;
char *tmp_codec_string;
+ switch_core_session_t *orig_session;
switch_assert(session);
+ switch_core_session_get_partner(session, &orig_session);
+
if (!(smh = session->media_handle)) {
return;
}
if (!force && (switch_channel_test_flag(session->channel, CF_PROXY_MODE) || switch_channel_test_flag(session->channel, CF_PROXY_MEDIA))) {
+ if (orig_session) {
+ switch_core_session_rwunlock(orig_session);
+ }
return;
}
@@ -2396,7 +2502,18 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses
tmp_codec_string = switch_core_session_strdup(smh->session, codec_string);
switch_channel_set_variable(session->channel, "rtp_use_codec_string", codec_string);
smh->codec_order_last = switch_separate_string(tmp_codec_string, ',', smh->codec_order, SWITCH_MAX_CODECS);
- smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, smh->fmtp, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
+
+ if (orig_session) {
+ if (orig_session->media_handle->video_pt_count[1] == 0) {
+ smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, smh->fmtp, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
+ } else {
+ smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted2(smh->codecs, smh->fmtp, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last, orig_session->media_handle->video_pt_count);
+ }
+
+ switch_core_session_rwunlock(orig_session);
+ } else {
+ smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, smh->fmtp, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
+ }
}
static void check_jb(switch_core_session_t *session, const char *input, int32_t jb_msec, int32_t maxlen, switch_bool_t silent)
@@ -2871,6 +2988,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
switch_status_t status;
switch_media_handle_t *smh;
int do_cng = 0;
+ int is_presentation = 0;
switch_assert(session);
@@ -2884,6 +3002,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
engine = &smh->engines[type];
+ /* There can be case where there will be multiple video media channel and for each video channel there will be thread running for RTP packet flow,
+ below logic handles video_rtp_engine to use by comparing thread_id stored in rtp_engine with thread_id of currently running thread */
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ if (engine->thread_id != switch_thread_self() && engine->next && engine->next->thread_id == switch_thread_self()) {
+ engine = engine->next;
+ is_presentation = 1;
+ }
+ }
+
if (type == SWITCH_MEDIA_TYPE_AUDIO && ! switch_channel_test_flag(session->channel, CF_AUDIO)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s Reading audio from a non-audio session.\n", switch_channel_get_name(session->channel));
switch_yield(50000);
@@ -2900,12 +3027,21 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
return SWITCH_STATUS_FALSE;
}
+ if (!is_presentation) {
if (smh->read_mutex[type] && switch_mutex_trylock(smh->read_mutex[type]) != SWITCH_STATUS_SUCCESS) {
/* return CNG, another thread is already reading */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being read for %s\n",
switch_channel_get_name(session->channel), type2str(type));
return SWITCH_STATUS_INUSE;
}
+ } else {
+ if (smh->read_presentation_mutex && switch_mutex_trylock(smh->read_presentation_mutex) != SWITCH_STATUS_SUCCESS) {
+ /* return CNG, another thread is already reading */
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being read for presentation\n",
+ switch_channel_get_name(session->channel));
+ return SWITCH_STATUS_INUSE;
+ }
+ }
engine->read_frame.datalen = 0;
@@ -3405,9 +3541,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
end:
+ if (!is_presentation) {
if (smh->read_mutex[type]) {
switch_mutex_unlock(smh->read_mutex[type]);
}
+ } else if (smh->read_presentation_mutex) {
+ switch_mutex_unlock(smh->read_presentation_mutex);
+ }
return status;
}
@@ -3420,7 +3560,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_write_frame(switch_core_sessio
int bytes = 0, samples = 0, frames = 0;
switch_rtp_engine_t *engine;
switch_media_handle_t *smh;
-
+ switch_core_session_t *peer_session;
+ switch_rtp_engine_t *peer_engine;
switch_assert(session);
if (!(smh = session->media_handle)) {
@@ -3434,6 +3575,24 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_write_frame(switch_core_sessio
engine = &smh->engines[type];
if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+
+ switch_core_session_get_partner(session, &peer_session);
+
+ if (peer_session && peer_session->media_handle) {
+ peer_engine = &peer_session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ /* There can be case where there will be multiple video media channel and for each video channel there will be thread running for RTP packet flow,
+ below logic handles peer session's video_rtp_engine to use by comparing thread_id stored in rtp_engine with thread_id of currently running thread */
+ if (peer_engine->thread_id != switch_thread_self() && engine->next && peer_engine->next
+ && peer_engine->next->thread_id == switch_thread_self()) {
+ engine = engine->next;
+ }
+ }
+
+ if (peer_session) {
+ switch_core_session_rwunlock(peer_session);
+ }
+
if (engine->thread_write_lock && engine->thread_write_lock != switch_thread_self()) {
return SWITCH_STATUS_SUCCESS;
}
@@ -3549,6 +3708,8 @@ static void switch_core_session_parse_codec_settings(switch_core_session_t *sess
if (!(engine = &smh->engines[type])) return;
+ parse_codec_setting: /* If multiple video media, then need execute below statement for each video RTP engine */
+
switch(type) {
case SWITCH_MEDIA_TYPE_AUDIO:
break;
@@ -3580,6 +3741,10 @@ static void switch_core_session_parse_codec_settings(switch_core_session_t *sess
default:
break;
}
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ engine = engine->next;
+ if (engine) goto parse_codec_setting;
+ }
}
@@ -3596,6 +3761,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_codec(switch_core_se
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+ for (int i = 1; i < smh->video_media_count; i++) {
+ v_engine = v_engine->next;
+ }
if (!v_engine->codec_negotiated) {
return SWITCH_STATUS_FALSE;
@@ -4627,6 +4795,9 @@ static const char *media_flow_varname(switch_media_type_t type)
case SWITCH_MEDIA_TYPE_TEXT:
varname = "text_media_flow";
break;
+ case SWITCH_MEDIA_TYPE_APPLICATION:
+ varname = "application_media_flow";
+ break;
}
return varname;
@@ -4646,6 +4817,9 @@ static const char *remote_media_flow_varname(switch_media_type_t type)
case SWITCH_MEDIA_TYPE_TEXT:
varname = "remote_text_media_flow";
break;
+ case SWITCH_MEDIA_TYPE_APPLICATION:
+ varname = "remote_application_media_flow";
+ break;
}
return varname;
@@ -4759,6 +4933,12 @@ SWITCH_DECLARE(void) switch_core_media_set_smode(switch_core_session_t *session,
engine = &smh->engines[type];
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ for (int i = 1; i < smh->video_media_count; i++) {
+ engine = engine->next;
+ }
+ }
+
varname = media_flow_varname(type);
media_flow_get_mode(smode, &smode_str, &opp_smode);
@@ -4805,6 +4985,10 @@ static void switch_core_media_set_rmode(switch_core_session_t *session, switch_m
varname = remote_media_flow_varname(type);
media_flow_get_mode(rmode, &rmode_str, &opp_rmode);
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ for (int i = 1; i < smh->video_media_count; i++) engine = engine->next;
+ }
+
if (engine->rmode != rmode) {
engine->pass_codecs = 1;
}
@@ -4847,7 +5031,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
sdp_session_t *sdp;
const switch_codec_implementation_t **codec_array;
int total_codecs;
- switch_rtp_engine_t *a_engine, *v_engine, *t_engine;
+ switch_rtp_engine_t *a_engine, *v_engine, *t_engine, *app_engine;
switch_media_handle_t *smh;
uint32_t near_rate = 0;
const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
@@ -4863,6 +5047,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
int rtcp_auto_audio = 0, rtcp_auto_video = 0;
int got_audio_rtcp = 0, got_video_rtcp = 0;
switch_port_t audio_port = 0, video_port = 0;
+ int video_media_count = 0;
switch_assert(session);
@@ -4878,9 +5063,11 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO];
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
t_engine = &smh->engines[SWITCH_MEDIA_TYPE_TEXT];
+ app_engine = &smh->engines[SWITCH_MEDIA_TYPE_APPLICATION];
smh->mparams->num_codecs = 0;
smh->num_negotiated_codecs = 0;
+ smh->video_media_count = 0;
switch_core_media_prepare_codecs(session, SWITCH_TRUE);
codec_array = smh->codecs;
total_codecs = smh->mparams->num_codecs;
@@ -4907,8 +5094,12 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
rtcp_auto_audio = 1;
}
+ while (v_engine) {
v_engine->new_dtls = 1;
v_engine->new_ice = 1;
+ v_engine = v_engine->next;
+ }
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
a_engine->new_dtls = 1;
a_engine->new_ice = 1;
a_engine->reject_avp = 0;
@@ -4918,7 +5109,11 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
switch_core_session_parse_crypto_prefs(session);
clear_pmaps(a_engine);
+ while (v_engine) {
clear_pmaps(v_engine);
+ v_engine = v_engine->next;
+ }
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (proceed) *proceed = 1;
@@ -6029,11 +6224,26 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
} else if (m->m_type == sdp_media_video) {
sdp_rtpmap_t *map;
const char *rm_encoding;
+ switch_endpoint_interface_t *bfcp_endpoint_interface = NULL;
const switch_codec_implementation_t *mimp = NULL;
int i;
const char *inherit_video_fmtp = NULL;
+ video_media_count++;
+
+ if ((video_media_count > 1) && ((bfcp_endpoint_interface = switch_loadable_module_get_endpoint_interface(BFCP)) == NULL))
+ video_media_count--;
+ else if (bfcp_endpoint_interface)
+ UNPROTECT_INTERFACE(bfcp_endpoint_interface)
+
+ smh->video_media_count = video_media_count;
switch_core_media_set_rmode(smh->session, SWITCH_MEDIA_TYPE_VIDEO, sdp_media_flow(m->m_mode), sdp_type);
+
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ for (int i = 1; i < video_media_count; i++) {
+ v_engine = v_engine->next;
+ }
if (sdp_type == SDP_TYPE_REQUEST) {
sdp_bandwidth_t *bw;
@@ -6048,6 +6258,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
}
+ smh->video_media_count = video_media_count;
switch(v_engine->rmode) {
case SWITCH_MEDIA_FLOW_RECVONLY:
switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_MEDIA_FLOW_SENDONLY, sdp_type);
@@ -6133,7 +6344,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
} else if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value && !skip_video_rtcp) {
v_engine->remote_rtcp_port = (switch_port_t)atoi(attr->a_value);
+ if (video_media_count == 1)
switch_channel_set_variable_printf(session->channel, "rtp_remote_video_rtcp_port", "%d", v_engine->remote_rtcp_port);
+ else
+ switch_channel_set_variable_printf(session->channel, "rtp_remote_presentation_rtcp_port", "%d", v_engine->remote_rtcp_port);
if (!smh->mparams->rtcp_video_interval_msec) {
smh->mparams->rtcp_video_interval_msec = SWITCH_RTCP_VIDEO_INTERVAL_MSEC;
}
@@ -6207,7 +6421,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
if (vmatch && vmatch_pt) {
- const char *other_pt = switch_channel_get_variable_partner(channel, "rtp_video_pt");
+ const char *other_pt = (video_media_count == 1) ? switch_channel_get_variable_partner(channel, "rtp_video_pt") : switch_channel_get_variable_partner(channel, "rtp_presentation_pt");
if (other_pt) {
int opt = atoi(other_pt);
@@ -6215,7 +6429,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
vmatch = 0;
} else {
if (switch_channel_var_true(channel, "inherit_video_fmtp")) {
+ if (video_media_count == 1)
inherit_video_fmtp = switch_channel_get_variable_partner(channel, "rtp_video_fmtp");
+ else
+ inherit_video_fmtp = switch_channel_get_variable_partner(channel, "rtp_presentation_fmtp");
}
}
}
@@ -6267,6 +6484,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
vmatch = 1;
v_engine->codec_negotiated = 1;
v_engine->payload_map = NULL;
+ smh->video_media_count = video_media_count;
for(j = 0; j < m_idx && smh->num_negotiated_codecs < SWITCH_MAX_CODECS; j++) {
payload_map_t *pmap = switch_core_media_add_payload_map(session,
@@ -6311,6 +6529,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->cur_payload_map->remote_sdp_port);
+ if (smh->video_media_count == 1) {
switch_channel_set_variable(session->channel, SWITCH_REMOTE_VIDEO_IP_VARIABLE, v_engine->cur_payload_map->remote_sdp_ip);
switch_channel_set_variable(session->channel, SWITCH_REMOTE_VIDEO_PORT_VARIABLE, tmp);
switch_channel_set_variable(session->channel, "rtp_video_fmtp", v_engine->cur_payload_map->rm_fmtp);
@@ -6319,11 +6538,23 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
switch_core_media_check_video_codecs(session);
switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->cur_payload_map->recv_pt);
switch_channel_set_variable(session->channel, "rtp_video_recv_pt", tmp);
+ } else {
+ switch_channel_set_variable(session->channel, SWITCH_REMOTE_PRESENTATION_IP_VARIABLE, v_engine->cur_payload_map->remote_sdp_ip);
+ switch_channel_set_variable(session->channel, SWITCH_REMOTE_PRESENTATION_PORT_VARIABLE, tmp);
+ switch_channel_set_variable(session->channel, "rtp_presentation_fmtp", v_engine->cur_payload_map->rm_fmtp);
+ switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->cur_payload_map->pt);
+ switch_channel_set_variable(session->channel, "rtp_presentation_pt", tmp);
+ switch_core_media_check_video_codecs(session);
+ switch_snprintf(tmp, sizeof(tmp), "%d", v_engine->cur_payload_map->recv_pt);
+ switch_channel_set_variable(session->channel, "rtp_presentation_recv_pt", tmp);
+ }
if (switch_core_codec_ready(&v_engine->read_codec) && strcasecmp(matches[0].imp->iananame, v_engine->read_codec.implementation->iananame)) {
v_engine->reset_codec = 1;
}
+ smh->video_media_count = video_media_count;
+
if (switch_core_media_set_video_codec(session, 0) == SWITCH_STATUS_SUCCESS) {
if (check_ice(smh, SWITCH_MEDIA_TYPE_VIDEO, sdp, m) == SWITCH_STATUS_FALSE) {
vmatch = 0;
@@ -6332,7 +6563,143 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
video_port = m->m_port;
- }
+ } else if (m->m_type == sdp_media_application && m->m_port) {
+ /*Trying to be as close as possible to the audio media parsing*/
+ int ice = 0;
+ switch_port_t application_port = 0;
+ application_port = m->m_port;
+
+ if (!sendonly && (m->m_mode == sdp_sendonly || m->m_mode ==sdp_inactive)) {
+ sendonly = 1;
+ if (m->m_mode == sdp_inactive) {
+ inactive = 1;
+ }
+ }
+
+ if (!sendonly && m->m_connections && m->m_connections->c_address && !strcmp(m->m_connections->c_address, "0.0.0.0")) {
+ sendonly = 1;
+ }
+
+ switch_core_media_set_rmode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, sdp_media_flow(m->m_mode), sdp_type);
+
+ if (sdp_type == SDP_TYPE_REQUEST) {
+ switch(app_engine->rmode) {
+ case SWITCH_MEDIA_FLOW_RECVONLY:
+ switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, SWITCH_MEDIA_FLOW_SENDONLY, sdp_type);
+ break;
+ case SWITCH_MEDIA_FLOW_SENDONLY:
+ switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, SWITCH_MEDIA_FLOW_RECVONLY, sdp_type);
+ break;
+ case SWITCH_MEDIA_FLOW_INACTIVE:
+ switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, SWITCH_MEDIA_FLOW_INACTIVE, sdp_type);
+ break;
+ default:
+ switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, SWITCH_MEDIA_FLOW_SENDRECV, sdp_type);
+ break;
+ }
+ }
+
+ for (attr = sdp->sdp_attributes; attr; attr = attr->a_next) {
+ if (zstr(attr->a_name)) {
+ continue;
+ }
+
+
+ if (!strncasecmp(attr->a_name, "ice", 3)) {
+ ice++;
+ } else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendonly")) {
+ sendonly = 1;
+ switch_channel_set_variable(session->channel, "media_application_mode", "recvonly");
+ } else if (sendonly < 2 && !strcasecmp(attr->a_name, "inactive")) {
+ switch_channel_set_variable(session->channel, "media_application_mode", "inactive");
+ } else if (!strcasecmp(attr->a_name, "recvonly")) {
+ switch_channel_set_variable(session->channel, "media_application_mode", "sendonly");
+ recvonly = 1;
+
+ if (switch_rtp_ready(a_engine->rtp_session)) {
+ switch_rtp_set_max_missed_packets(a_engine->rtp_session, 0);
+ a_engine->max_missed_hold_packets = 0;
+ a_engine->max_missed_packets = 0;
+ } else {
+ switch_channel_set_variable(session->channel, "rtp_timeout_sec", "0");
+ switch_channel_set_variable(session->channel, "rtp_hold_timeout_sec", "0");
+ }
+ } else if (sendonly < 2 && !strcasecmp(attr->a_name, "sendrecv")) {
+ sendonly = 0;
+ } else if (!strcasecmp(attr->a_name, "ptime")) {
+ ptime = dptime = atoi(attr->a_value);
+ } else if (!strcasecmp(attr->a_name, "maxptime")) {
+ maxptime = dmaxptime = atoi(attr->a_value);
+ }
+ }
+
+ if (sendonly == 2 && ice) {
+ sendonly = 0;
+ }
+
+ if (sendonly != 1 && recvonly != 1 && inactive != 1) {
+ switch_channel_set_variable(session->channel, "media_application_mode", NULL);
+ }
+
+ if (sdp_type == SDP_TYPE_RESPONSE) {
+ if (inactive) {
+ // When freeswitch had previously sent inactive in sip request. it should remain inactive otherwise smode should be sendrecv
+ if (app_engine->smode == SWITCH_MEDIA_FLOW_INACTIVE) {
+ switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, sdp_media_flow(sdp_inactive), sdp_type);
+ } else {
+ switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, sdp_media_flow(sdp_sendrecv), sdp_type);
+ }
+ } else if (sendonly) {
+ switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, sdp_media_flow(sdp_sendonly), sdp_type);
+ } else if (recvonly) {
+ switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_APPLICATION, sdp_media_flow(sdp_recvonly), sdp_type);
+ }
+ }
+
+ connection = sdp->sdp_connection;
+ if (m->m_connections) {
+ connection = m->m_connections;
+ }
+
+ if (!connection) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+ // match = 0;
+ break;
+ }
+
+
+ switch_core_media_add_payload_map(session,
+ SWITCH_MEDIA_TYPE_APPLICATION,
+ "",
+ NULL,
+ NULL,
+ sdp_type,
+ 0,
+ 0,
+ ptime,
+ 1,
+ SWITCH_TRUE);
+
+ app_engine->payload_map->remote_sdp_port = application_port;
+
+ if (switch_channel_var_true(session->channel, "rtp_pass_codecs_on_stream_change")) {
+ if (sdp_type == SDP_TYPE_REQUEST && switch_channel_test_flag(session->channel, CF_REINVITE) &&
+ switch_channel_media_up(session->channel) && switch_channel_test_flag(session->channel, CF_BFCP_STREAM_CHANGE)) {
+ switch_channel_set_flag(session->channel, CF_STREAM_CHANGED);
+ }
+ }
+
+ if (switch_channel_test_flag(session->channel, CF_BFCP_STREAM_CHANGE)) {
+ switch_channel_clear_flag(session->channel, CF_BFCP_STREAM_CHANGE);
+ }
+ }
+
+ }
+
+ /*To add media attributes to the payload*/
+ for (m = sdp->sdp_media; m; m = m->m_next) {
+ switch_core_media_copy_media_attribute(session, m);
+ switch_core_media_set_media_protocol(session, m, sdp_type);
}
endsdp:
@@ -6347,7 +6714,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
}
if (rtcp_auto_video && !skip_video_rtcp && !got_video_rtcp && video_port) {
+ if (video_media_count == 1)
switch_channel_set_variable_printf(session->channel, "rtp_remote_video_rtcp_port", "%d", video_port + 1);
+ else
+ switch_channel_set_variable_printf(session->channel, "rtp_remote_presentation_rtcp_port", "%d", video_port + 1);
v_engine->remote_rtcp_port = video_port + 1;
if (!smh->mparams->rtcp_video_interval_msec) {
smh->mparams->rtcp_video_interval_msec = SWITCH_RTCP_VIDEO_INTERVAL_MSEC;
@@ -6454,6 +6824,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
smh->mparams->cng_rate = cng_rate;
check_stream_changes(session, r_sdp, sdp_type);
+ smh->video_media_count = 0;
return match || vmatch || tmatch || fmatch;
}
@@ -7483,9 +7854,12 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
}
}
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+ for (int i = 1; i < mh->video_index; i++) {
+ v_engine = v_engine->next;
+ }
- v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
v_engine->thread_id = switch_thread_self();
mh->up = 1;
@@ -7493,8 +7867,8 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
switch_core_media_check_dtls(session, SWITCH_MEDIA_TYPE_VIDEO);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread started. Echo is %s\n",
- switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread started [%d]. Echo is %s\n",
+ switch_channel_get_name(session->channel), mh->video_index, switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off");
switch_core_session_request_video_refresh(session);
buf = switch_core_session_alloc(session, buflen);
@@ -7537,9 +7911,17 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
continue;
}
+ /* If current v_engine is not having engine function i.e for 2nd video engine case, then calling API to create engine
+ function with user data same as for 1st video engine */
+ if (!v_engine->engine_function && switch_channel_test_flag(channel, CF_VIDEO)) {
+ switch_rtp_engine_t *engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+ struct vid_helper *vh = engine->engine_user_data;
+ switch_core_media_start_engine_function(session, SWITCH_MEDIA_TYPE_VIDEO, engine->engine_function, vh);
+ switch_channel_set_flag(channel, CF_VIDEO_BLANK);
+ }
+
if (v_engine->engine_function) {
int run = 0;
-
switch_mutex_lock(smh->control_mutex);
if (v_engine->engine_function_running == 0) {
v_engine->engine_function_running = 1;
@@ -7594,7 +7976,7 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
switch_img_free(&blank_img);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread ended\n", switch_channel_get_name(session->channel));
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread ended [%d]\n", switch_channel_get_name(session->channel), mh->video_index);
switch_mutex_unlock(mh->cond_mutex);
switch_core_session_rwunlock(session);
@@ -7622,12 +8004,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_start_video_thread(switch_co
switch_mutex_lock(smh->control_mutex);
+ for (int i = 1; i < smh->video_media_count; i++) {
+ v_engine = v_engine->next;
+ }
+
if (v_engine->media_thread) {
switch_mutex_unlock(smh->control_mutex);
return SWITCH_STATUS_FALSE;
}
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Starting Video thread\n", switch_core_session_get_name(session));
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Starting Video thread [%d]\n", switch_core_session_get_name(session), smh->video_media_count);
if (v_engine->rtp_session) {
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->pt);
@@ -7641,12 +8027,19 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_start_video_thread(switch_co
switch_mutex_init(&v_engine->mh.cond_mutex, SWITCH_MUTEX_NESTED, pool);
switch_mutex_init(&v_engine->mh.file_read_mutex, SWITCH_MUTEX_NESTED, pool);
switch_mutex_init(&v_engine->mh.file_write_mutex, SWITCH_MUTEX_NESTED, pool);
- switch_mutex_init(&smh->read_mutex[SWITCH_MEDIA_TYPE_VIDEO], SWITCH_MUTEX_NESTED, pool);
- switch_mutex_init(&smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO], SWITCH_MUTEX_NESTED, pool);
+ if (smh->video_media_count != 2) {
+ switch_mutex_init(&smh->read_mutex[SWITCH_MEDIA_TYPE_VIDEO], SWITCH_MUTEX_NESTED, pool);
+ switch_mutex_init(&smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO], SWITCH_MUTEX_NESTED, pool);
+ } else {
+ switch_mutex_init(&smh->read_presentation_mutex, SWITCH_MUTEX_NESTED, pool);
+ switch_mutex_init(&smh->write_presentation_mutex, SWITCH_MUTEX_NESTED, pool);
+ }
v_engine->mh.ready = 0;
if (switch_thread_create(&v_engine->media_thread, thd_attr, video_helper_thread, &v_engine->mh,
switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
+ struct media_helper *mh = &v_engine->mh;
+ mh->video_index = smh->video_media_count;
while(!v_engine->mh.ready) {
switch_cond_next();
}
@@ -7668,6 +8061,9 @@ SWITCH_DECLARE(void) switch_core_media_start_engine_function(switch_core_session
engine = &smh->engines[type];
if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ /* There can be case where there will be multiple video media channel and for each video channel there will be thread running for RTP packet flow,
+ below logic handles video_rtp_engine to use by comparing thread_id stored in rtp_engine with thread_id of currently running thread */
+ if (engine->next && engine->next->thread_id == switch_thread_self()) engine = engine->next;
switch_core_session_start_video_thread(session);
}
@@ -8155,6 +8551,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_sessio
return SWITCH_STATUS_FALSE;
}
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ for (int i = 1; i < smh->video_media_count; i++) {
+ engine = engine->next;
+ }
+ }
+
/* Don't do anything if we're in proxy mode or if a (remote) port already has been found */
if (!force) {
if (switch_channel_test_flag(session->channel, CF_PROXY_MODE) ||
@@ -8232,8 +8634,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_choose_port(switch_core_sessio
switch_channel_set_variable_printf(session->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, "%d", sdp_port);
switch_channel_set_variable(session->channel, SWITCH_ADVERTISED_MEDIA_IP_VARIABLE, engine->adv_sdp_ip);
} else if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ if (smh->video_media_count == 1) {
switch_channel_set_variable(session->channel, SWITCH_LOCAL_VIDEO_IP_VARIABLE, engine->adv_sdp_ip);
switch_channel_set_variable_printf(session->channel, SWITCH_LOCAL_VIDEO_PORT_VARIABLE, "%d", sdp_port);
+ } else {
+ switch_channel_set_variable(session->channel, SWITCH_LOCAL_PRESENTATION_IP_VARIABLE, engine->adv_sdp_ip);
+ switch_channel_set_variable_printf(session->channel, SWITCH_LOCAL_PRESENTATION_PORT_VARIABLE, "%d", sdp_port);
+ }
} else if (type == SWITCH_MEDIA_TYPE_TEXT) {
switch_channel_set_variable(session->channel, SWITCH_LOCAL_TEXT_IP_VARIABLE, engine->adv_sdp_ip);
switch_channel_set_variable_printf(session->channel, SWITCH_LOCAL_TEXT_PORT_VARIABLE, "%d", sdp_port);
@@ -8309,6 +8716,7 @@ SWITCH_DECLARE(void) switch_core_media_deactivate_rtp(switch_core_session_t *ses
a_engine->media_thread = NULL;
}
+ while (v_engine) {
if (v_engine->media_thread) {
switch_status_t st;
switch_channel_clear_flag(session->channel, CF_VIDEO_PASSIVE);
@@ -8330,6 +8738,8 @@ SWITCH_DECLARE(void) switch_core_media_deactivate_rtp(switch_core_session_t *ses
switch_nat_del_mapping((switch_port_t) v_engine->local_sdp_port, SWITCH_NAT_UDP);
switch_nat_del_mapping((switch_port_t) v_engine->local_sdp_port + 1, SWITCH_NAT_UDP);
}
+ v_engine = v_engine->next;
+ }
if (t_engine->media_thread) {
@@ -8525,6 +8935,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
switch_rtp_engine_t *a_engine, *v_engine, *t_engine;
switch_media_handle_t *smh;
int is_reinvite = 0;
+ int cur_video_count = 0;
#ifdef HAVE_OPENSSL_DTLSv1_2_method
uint8_t want_DTLSv1_2 = 1;
@@ -9345,6 +9756,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
switch_core_media_check_video_codecs(session);
}
+ while (v_engine) {
+ cur_video_count++;
if (switch_channel_test_flag(session->channel, CF_VIDEO_POSSIBLE) && v_engine->cur_payload_map->rm_encoding && v_engine->cur_payload_map->remote_sdp_port) {
/******************************************************************************************/
if (v_engine->rtp_session && is_reinvite) {
@@ -9390,7 +9803,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
//switch_channel_clear_flag(session->channel, CF_REINVITE);
if (!remote_rtcp_port) {
- if ((rport = switch_channel_get_variable(session->channel, "rtp_remote_video_rtcp_port"))) {
+
+ if ((cur_video_count == 1) && (rport = switch_channel_get_variable(session->channel, "rtp_remote_video_rtcp_port"))) {
+ remote_rtcp_port = (switch_port_t)atoi(rport);
+ } else if ((rport = switch_channel_get_variable(session->channel, "rtp_remote_presentation_rtcp_port"))) {
remote_rtcp_port = (switch_port_t)atoi(rport);
}
}
@@ -9443,7 +9859,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
goto video_up;
}
-
+ smh->video_media_count = cur_video_count;
if (!v_engine->local_sdp_port) {
switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 1);
}
@@ -9557,7 +9973,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
}
if ((val = switch_channel_get_variable(session->channel, "rtcp_video_interval_msec")) || (val = smh->mparams->rtcp_video_interval_msec)) {
- const char *rport = switch_channel_get_variable(session->channel, "rtp_remote_video_rtcp_port");
+ const char *rport = (cur_video_count == 1) ? switch_channel_get_variable(session->channel, "rtp_remote_video_rtcp_port") : switch_channel_get_variable(session->channel, "rtp_remote_presentation_rtcp_port");
switch_port_t remote_port = v_engine->remote_rtcp_port;
if (rport) {
@@ -9665,6 +10081,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
}
}
+ v_engine = v_engine->next;
+ }
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
switch_channel_hangup(session->channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
@@ -9674,9 +10092,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
video_up:
+ if (v_engine && v_engine->next) {
+ v_engine = v_engine->next;
+ goto video; /*If multiple video then it will move up for another video*/
+ }
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ while (v_engine) {
if (session && v_engine) {
check_dtls_reinvite(session, v_engine);
}
+ v_engine = v_engine->next;
+ }
status = SWITCH_STATUS_SUCCESS;
@@ -10350,6 +10777,19 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
switch_core_session_remote_media_flow(orig_session, SWITCH_MEDIA_TYPE_VIDEO), sdp_type);
}
+ if (orig_session) {
+ switch_rtp_engine_t *v_engine;
+
+ v_engine = &orig_session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ memset(orig_session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].already_did, 0, sizeof(orig_session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].already_did));
+
+ if (v_engine) {
+ memset(v_engine->already_did, 0 , sizeof(v_engine->already_did));
+ v_engine = v_engine->next;
+ }
+ }
+
for (i = 0; i < smh->mparams->num_codecs; i++) {
const switch_codec_implementation_t *imp = smh->codecs[i];
switch_payload_t orig_pt = 0;
@@ -10383,6 +10823,24 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
}
}
+ if (orig_session) {
+ smh->video_media_count = orig_session->media_handle->video_media_count; /* Assigning the video media count from peer session */
+ }
+
+ if (smh->video_media_count > 1) {
+ switch_rtp_engine_t *engine;
+ engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+ /* Logic to traverse video RTP engine if video media more than 2 */
+ // for (int i = 1; i < smh->video_media_count - 1; i++) {
+ // engine = engine->next;
+ // }
+
+ if (!engine->next) {
+ switch_media_add_video_rtp_engine(session, engine); /* If number of RTP engine for video is
+ less than video_media count then it create the new engine */
+ }
+ }
+
switch_core_media_add_payload_map(session,
imp->codec_type == SWITCH_CODEC_TYPE_AUDIO ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO,
imp->iananame,
@@ -10415,6 +10873,11 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
}
}
+ if (orig_session) {
+ for (int i = 0; i < SWITCH_MAX_VIDEO_MEDIA; i++) {
+ smh->video_pt_count[i] = orig_session->media_handle->video_pt_count[i];
+ }
+ }
if (orig_session) {
switch_core_session_rwunlock(orig_session);
@@ -10886,12 +11349,19 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
a_engine->crypto_type != CRYPTO_INVALID || switch_channel_test_flag(session->channel, CF_DTLS)));
}
} else {
+ int video_count = -1;
+ int cur_video_count = 0;
+ switch_endpoint_interface_t *bfcp_endpoint_interface;
+ while (v_engine) {
+ video_count++;
+ cur_video_count++;
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
if (switch_channel_test_flag(smh->session->channel, CF_DTLS)) {
v_engine->no_crypto = 1;
}
}
+ smh->video_media_count = cur_video_count;
if (!v_engine->local_sdp_port) {
switch_core_media_choose_port(session, SWITCH_MEDIA_TYPE_VIDEO, 0);
@@ -10940,6 +11410,13 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
} else if (smh->mparams->num_codecs) {
int already_did[128] = { 0 };
+ int skip_video_ianacode = 0, video_payload_count = 0;
+
+ for (i = 0; i < video_count; i++) {
+ skip_video_ianacode += smh->video_pt_count[i]; /* counts the number of video ianacodes to skip from parsing */
+ }
+
+ video_payload_count = smh->video_pt_count[video_count];
for (i = 0; i < smh->mparams->num_codecs; i++) {
const switch_codec_implementation_t *imp = smh->codecs[i];
@@ -10948,6 +11425,11 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
continue;
}
+ if(skip_video_ianacode) {
+ skip_video_ianacode--; /* skipping video ianacodes which had been already parsed */
+ goto next1;
+ }
+
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
continue;
@@ -10961,13 +11443,17 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
}
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), " %d", smh->ianacodes[i]);
+ video_payload_count--;
if (!ptime) {
ptime = imp->microseconds_per_packet / 1000;
}
got_vid++;
- }
+
+ next1:
+ if(!video_payload_count) break; /* If the payload for particular video are parsed then move to next video*/
+ }
}
if (got_vid && v_engine->smode == SWITCH_MEDIA_FLOW_DISABLED) {
switch_core_media_set_smode(smh->session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_MEDIA_FLOW_SENDRECV, sdp_type);
@@ -10991,7 +11477,42 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
//switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=TIAS:%d\r\n", bw);
}
+ if ((bfcp_endpoint_interface = switch_loadable_module_get_endpoint_interface(BFCP)) != NULL) {
+ switch_core_session_t *peer_session;
+ switch_rtp_engine_t *peer_engine;
+ media_attribute_t *media_attribute;
+
+ if (sdp_type == SDP_TYPE_RESPONSE) {
+ media_attribute = v_engine->media_attribute;
+
+ while (media_attribute) {
+ switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=%s:%s\r\n", media_attribute->a_name, media_attribute->a_value);
+ media_attribute = media_attribute->a_next;
+ }
+ } else {
+ switch_core_session_get_partner(session, &peer_session);
+ if (peer_session) {
+ peer_engine = &peer_session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ for (int i = 0; i < video_count; i++) {
+ peer_engine = peer_engine->next;
+ }
+
+ if (peer_engine) {
+ media_attribute = peer_engine->media_attribute;
+
+ while (media_attribute) {
+ switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=%s:%s\r\n", media_attribute->a_name, media_attribute->a_value);
+ media_attribute = media_attribute->a_next;
+ }
+ }
+ switch_core_session_rwunlock(peer_session);
+ }
+ }
+
+ UNPROTECT_INTERFACE(bfcp_endpoint_interface);
+ }
if (v_engine->codec_negotiated) {
payload_map_t *pmap;
@@ -11022,11 +11543,17 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
pass_fmtp = v_engine->cur_payload_map->fmtp_out;
if (!pass_fmtp || switch_true(switch_channel_get_variable_dup(session->channel, "rtp_mirror_fmtp", SWITCH_FALSE, -1))) {
+ if (cur_video_count == 1)
pass_fmtp = switch_channel_get_variable(session->channel, "rtp_video_fmtp");
+ else
+ pass_fmtp = switch_channel_get_variable(session->channel, "rtp_presentation_fmtp");
}
}
}
+ // if (v_engine->next) {
+ // pass_fmtp = v_engine->cur_payload_map->rm_fmtp;
+ // }
if (pass_fmtp) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\r\n", v_engine->cur_payload_map->pt, pass_fmtp);
@@ -11051,6 +11578,13 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
} else if (smh->mparams->num_codecs) {
int already_did[128] = { 0 };
+ int skip_video_ianacode = 0, video_payload_count = 0;
+
+ for (i = 0; i < video_count; i++) {
+ skip_video_ianacode += smh->video_pt_count[i];
+ }
+
+ video_payload_count = smh->video_pt_count[video_count];
for (i = 0; i < smh->mparams->num_codecs; i++) {
const switch_codec_implementation_t *imp = smh->codecs[i];
@@ -11062,6 +11596,11 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
continue;
}
+ if(skip_video_ianacode) {
+ skip_video_ianacode--;
+ goto next2;
+ }
+
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
continue;
@@ -11120,6 +11659,9 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
if (!zstr(fmtp) && strcasecmp(fmtp, "_blank_")) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=fmtp:%d %s\r\n", ianacode, fmtp);
}
+ video_payload_count--;
+ next2:
+ if(!video_payload_count) break;
}
}
@@ -11184,6 +11726,13 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
} else if (smh->mparams->num_codecs) {
int already_did[128] = { 0 };
+ int skip_video_ianacode = 0, video_payload_count = 0;
+
+ for (i = 0; i < video_count; i++) {
+ skip_video_ianacode += smh->video_pt_count[i];
+ }
+
+ video_payload_count = smh->video_pt_count[video_count];
for (i = 0; i < smh->mparams->num_codecs; i++) {
const switch_codec_implementation_t *imp = smh->codecs[i];
@@ -11192,6 +11741,11 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
continue;
}
+ if(skip_video_ianacode) {
+ skip_video_ianacode--;
+ goto next3;
+ }
+
if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_INBOUND &&
switch_channel_test_flag(session->channel, CF_NOVIDEO)) {
continue;
@@ -11205,6 +11759,9 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
}
add_fb(buf, SDPBUFLEN, smh->ianacodes[i], v_engine->fir || fir, v_engine->nack || nack, v_engine->pli || pli, v_engine->pli || pli);
+ video_payload_count--;
+ next3:
+ if(!video_payload_count) break;
}
}
@@ -11334,6 +11891,9 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
}
}
+ v_engine = v_engine->next;
+ }
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
}
if (switch_channel_test_cap(session->channel, CC_MSRP) && !smh->msrp_session) {
@@ -11695,6 +12255,22 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
switch_event_destroy(&ptmap);
}
+ /* APPLICATION MEDIA */
+
+ /* CF_PEER_BFCP is a channel flag to check peer_session contain application media or not */
+ if (switch_channel_test_flag(session->channel, CF_PEER_BFCP)) {
+ /* SWITCH_PEER_BFCP_LOCAL_SDP contains the local SDP part of BFCP media generated by mod_bfcp
+ which is used by freeswitch for sending to other leg */
+ if (switch_channel_get_variable(session->channel, SWITCH_PEER_BFCP_LOCAL_SDP )) {
+ switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s",switch_channel_get_variable(session->channel, SWITCH_PEER_BFCP_LOCAL_SDP));
+ }
+ } else if (switch_channel_test_flag(session->channel, CF_EARLY_MEDIA_BFCP)) {
+ if (switch_channel_get_variable(session->channel, SWITCH_BFCP_LOCAL_SDP )) {
+ switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "%s",switch_channel_get_variable(session->channel, SWITCH_BFCP_LOCAL_SDP));
+ }
+ switch_channel_clear_flag(session->channel, CF_EARLY_MEDIA_BFCP);
+ }
+
switch_core_media_set_local_sdp(session, buf, SWITCH_TRUE);
check_stream_changes(session, NULL, sdp_type);
@@ -13291,7 +13867,53 @@ SWITCH_DECLARE(switch_jb_t *) switch_core_media_get_jb(switch_core_session_t *se
//?
SWITCH_DECLARE(void) switch_core_media_set_sdp_codec_string(switch_core_session_t *session, const char *r_sdp, switch_sdp_type_t sdp_type)
{
+ switch_endpoint_interface_t *bfcp_endpoint_interface; /* bfcp_endpoint_interface is used to call mod_bfcp API's */
+
switch_core_media_merge_sdp_codec_string(session, r_sdp, sdp_type, switch_core_media_get_codec_string(session));
+
+ /* bfcp_endpoint_interface stores the object for endpoint interface of mod_bfcp */
+ if (switch_channel_test_flag(session->channel, CF_BFCP)) {
+ if ((bfcp_endpoint_interface = switch_loadable_module_get_endpoint_interface(BFCP)) == 0) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),SWITCH_LOG_INFO, "Module mod_bfcp not loaded\n");
+ }
+
+ if (bfcp_endpoint_interface) {
+ switch (switch_channel_get_state(session->channel)) {
+ case CS_EXECUTE:
+ {
+ if (!bfcp_endpoint_interface->state_handler->on_execute) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Could not locate execute state for bfcp\n");
+ } else {
+ bfcp_endpoint_interface->state_handler->on_execute(session);
+ }
+ }
+ break;
+ case CS_CONSUME_MEDIA:
+ {
+ if (!bfcp_endpoint_interface->state_handler->on_consume_media) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Could not locate consume media state for bfcp\n");
+ } else {
+ bfcp_endpoint_interface->state_handler->on_consume_media(session);
+ }
+ }
+ break;
+ case CS_EXCHANGE_MEDIA:
+ {
+ if (!bfcp_endpoint_interface->state_handler->on_exchange_media) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Could not locate exchange media state for bfcp\n");
+ } else {
+ bfcp_endpoint_interface->state_handler->on_exchange_media(session);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ UNPROTECT_INTERFACE(bfcp_endpoint_interface);
+ }
+ }
+
}
SWITCH_DECLARE(void) switch_core_media_merge_sdp_codec_string(switch_core_session_t *session, const char *r_sdp,
@@ -13390,6 +14012,232 @@ static void add_audio_codec(sdp_rtpmap_t *map, const switch_codec_implementation
}
+/* asssign pointer of structure containing media_attributes to media_attribute of payload_map */
+SWITCH_DECLARE(void) switch_core_media_set_media_attribute(switch_core_session_t *session, media_attribute_t *media_attribute, switch_media_type_t type)
+{
+ switch_rtp_engine_t *engine;
+
+ engine = &session->media_handle->engines[type];
+
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ for (int i = 1; i < session->media_handle->video_media_count; i++) {
+ engine = engine->next;
+ }
+ }
+
+ engine->media_attribute = media_attribute;
+}
+
+/* set string containing transport protocol to media_proto of payload_map of media */
+static void switch_core_media_set_media_protocol(switch_core_session_t *session, sdp_media_t *sdp_media, switch_sdp_type_t sdp_type)
+{
+ switch_rtp_engine_t *engine;
+ switch_media_type_t media_type;
+
+ switch (sdp_media->m_type) {
+
+ case sdp_media_audio:
+ media_type = SWITCH_MEDIA_TYPE_AUDIO;
+ break;
+ case sdp_media_video:
+ media_type = SWITCH_MEDIA_TYPE_VIDEO;
+ break;
+ case sdp_media_application:
+ media_type = SWITCH_MEDIA_TYPE_APPLICATION;
+ break;
+ default:
+ media_type = SWITCH_MEDIA_TYPE_AUDIO;
+ break;
+ }
+
+ engine = &session->media_handle->engines[media_type];
+
+ if (media_type == SWITCH_MEDIA_TYPE_VIDEO) {
+ for (int i = 1; i < session->media_handle->video_media_count; i++) {
+ engine = engine->next;
+ }
+ }
+
+ /* Currently assigning media protocol name for Application media only if BFCP */
+ if (media_type == SWITCH_MEDIA_TYPE_APPLICATION && switch_core_media_check_bfcp(sdp_media) == SWITCH_STATUS_SUCCESS) {
+ if ((engine->media_proto == NULL || (strcmp(engine->media_proto, sdp_media->m_proto_name) != 0)) && sdp_type == SDP_TYPE_REQUEST) {
+ switch_channel_set_flag(session->channel, CF_BFCP_STREAM_CHANGE);
+ }
+
+ engine->media_proto = strdup((char*)sdp_media->m_proto_name);
+ } else if (media_type != SWITCH_MEDIA_TYPE_APPLICATION) {
+ engine->media_proto = strdup((char*)sdp_media->m_proto_name);
+ }
+
+}
+
+SWITCH_DECLARE(media_proto_name_t *) switch_core_media_get_media_protocol(switch_core_session_t *session, switch_media_type_t type)
+{
+ switch_rtp_engine_t *engine;
+
+ engine = &session->media_handle->engines[type];
+
+ if (type == SWITCH_MEDIA_TYPE_VIDEO) {
+ for (int i = 1; i < session->media_handle->video_media_count; i++) {
+ engine = engine->next;
+ }
+ }
+
+ return engine->media_proto;
+}
+
+static switch_status_t switch_core_media_check_supported_media_attribute(sdp_attribute_t *media_attribute, switch_media_type_t media_type)
+{
+ switch (media_type) {
+ case SWITCH_MEDIA_TYPE_AUDIO:
+ case SWITCH_MEDIA_TYPE_VIDEO:
+ if (!strcmp(media_attribute->a_name, "content")) {
+ return SWITCH_STATUS_SUCCESS;
+ } else if (!strcmp(media_attribute->a_name, "label")) {
+ char *end;
+ uint16_t num = strtoul(media_attribute->a_value, &end, 10);
+
+ if (num && !strcmp(end, ""))
+ return SWITCH_STATUS_SUCCESS;
+ }
+ break;
+ case SWITCH_MEDIA_TYPE_APPLICATION:
+ if (!strcmp(media_attribute->a_name, "floorid") || !strcmp(media_attribute->a_name, "confid") || !strcmp(media_attribute->a_name, "userid")
+ || !strcmp(media_attribute->a_name, "setup") || !strcmp(media_attribute->a_name, "connection") || !strcmp(media_attribute->a_name, "floorctrl")) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return SWITCH_STATUS_FALSE;
+}
+
+/* Add media_attribute from sdp_media to rtp_engine of particular media */
+static void switch_core_media_copy_media_attribute(switch_core_session_t *session, sdp_media_t *sdp_media)
+{
+ sdp_attribute_t *in_attr;
+ switch_rtp_engine_t *engine;
+ switch_media_type_t media_type;
+ media_attribute_t *curr_pay_attr, *head, *temp;
+ curr_pay_attr = head = temp = NULL;
+
+ switch_assert(session);
+
+ switch (sdp_media->m_type) {
+
+ case sdp_media_audio:
+ media_type = SWITCH_MEDIA_TYPE_AUDIO;
+ break;
+ case sdp_media_video:
+ media_type = SWITCH_MEDIA_TYPE_VIDEO;
+ break;
+ case sdp_media_application:
+ media_type = SWITCH_MEDIA_TYPE_APPLICATION;
+ break;
+ default:
+ media_type = SWITCH_MEDIA_TYPE_AUDIO;
+ break;
+ }
+
+ engine = &session->media_handle->engines[media_type];
+
+ if (media_type == SWITCH_MEDIA_TYPE_VIDEO) {
+ for (int i = 1; i < session->media_handle->video_media_count; i++) {
+ engine = engine->next;
+ }
+ }
+
+ in_attr = sdp_media->m_attributes;
+
+ while(in_attr) {
+
+ curr_pay_attr = malloc(sizeof(media_attribute_t));
+
+ /* Copying currently parsed attribute in cur_pay_attr */
+ if (in_attr->a_name && in_attr->a_value && switch_core_media_check_supported_media_attribute(in_attr, media_type) == SWITCH_STATUS_SUCCESS) {
+ curr_pay_attr->a_size = sizeof (media_attribute_t);
+ curr_pay_attr->a_name = strdup((char*)in_attr->a_name);
+ curr_pay_attr->a_value = strdup((char*)in_attr->a_value);
+ curr_pay_attr->a_next = NULL;
+ } else {
+ in_attr = in_attr->a_next;
+ continue;
+ }
+
+ if (head == NULL) {
+ head = curr_pay_attr;
+ }
+ else {
+ /* setting cur_pay_attr as head */
+ temp = curr_pay_attr;
+ temp->a_next = head;
+ head = temp;
+ }
+
+ in_attr = in_attr->a_next;
+ }
+
+ if (head && engine->payload_map) {
+ /* Assigning head to media_attribute */
+ engine->media_attribute = head;
+ return;
+ }
+
+ return;
+}
+
+/* Check whether media_protocol is of BFCP type or not */
+SWITCH_DECLARE(switch_status_t) switch_core_media_check_bfcp(sdp_media_t *sdp_media)
+{
+ switch_status_t status;
+
+ switch (sdp_media->m_proto) {
+ case sdp_proto_udp_bfcp:
+ case sdp_proto_tcp_bfcp:
+
+ case sdp_proto_tcp_tls_bfcp:
+ status = SWITCH_STATUS_SUCCESS;
+ break;
+ default:
+ status = SWITCH_STATUS_FALSE;
+ break;
+ }
+
+ return status;
+}
+
+/* Creates new video RTP engine, initialiaze it with some default parameters and assign to v_engine->next */
+SWITCH_DECLARE(void) switch_media_add_video_rtp_engine(switch_core_session_t *session, switch_rtp_engine_t *v_engine)
+{
+ switch_rtp_engine_t *engine = switch_core_alloc(session->pool, sizeof(switch_rtp_engine_t));
+
+ v_engine->next = engine;
+
+ (*engine).read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
+ (*engine).type = SWITCH_MEDIA_TYPE_VIDEO;
+ (*engine).crypto_type = CRYPTO_INVALID;
+
+ (*engine).smode = SWITCH_MEDIA_FLOW_DISABLED;
+
+ for (int i = 0; i < CRYPTO_INVALID; i++) {
+ (*engine).ssec[i].crypto_type = i;
+ }
+
+ (*engine).media_proto = NULL;
+ (*engine).media_attribute = NULL;
+
+ (*engine).ssrc =
+ (uint32_t) ((intptr_t) &(*engine) + (uint32_t) time(NULL) / 2);
+
+ (*engine).payload_map = switch_core_alloc(session->pool, sizeof(payload_map_t));
+ (*engine).cur_payload_map = (*engine).payload_map;
+ (*engine).cur_payload_map->current = 1;
+ (*engine).codec_settings.video.try_hardware_encoder = 1;
+ memset((*engine).already_did, 0, sizeof((*engine).already_did));
+
+}
static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *session, const char *codec_string, sdp_session_t *sdp, switch_sdp_type_t sdp_type)
{
@@ -13397,12 +14245,13 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
sdp_media_t *m;
sdp_attribute_t *attr;
int ptime = 0, dptime = 0;
- sdp_connection_t *connection;
+ sdp_connection_t *connection = NULL;
sdp_rtpmap_t *map;
short int match = 0;
int i;
int already_did[128] = { 0 };
int num_codecs = 0;
+ int video_count = -1; /* To point index for currently parsed video media */
char *codec_order[SWITCH_MAX_CODECS];
const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 };
char fmtp[SWITCH_MAX_CODECS][MAX_FMTP_LEN];
@@ -13418,6 +14267,8 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
return;
}
+ smh->video_media_count = 0;
+ memset(smh->video_pt_count, 0, sizeof(smh->video_pt_count));
if ((var = switch_channel_get_variable(channel, "ep_codec_prefer_sdp")) && switch_true(var)) {
prefer_sdp = 1;
@@ -13459,6 +14310,28 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
ptime = dptime;
if ((m->m_type == sdp_media_audio || m->m_type == sdp_media_video) && m->m_port) {
+ if (m->m_type == sdp_media_video) {
+ smh->video_media_count++; /* Incrementing count if new video media found */
+ if (smh->video_media_count > 1) { /* If there is additional video media */
+ switch_rtp_engine_t *engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+ switch_endpoint_interface_t *bfcp_endpoint_interface;
+
+ if ((bfcp_endpoint_interface = switch_loadable_module_get_endpoint_interface(BFCP)) != NULL) {
+ /* Logic to traverse video RTP engine if video media more than 2 */
+ // for (int i = 1; i < smh->video_media_count - 1; i++) {
+ // engine = engine->next;
+ // }
+
+ if (!engine->next) {
+ switch_media_add_video_rtp_engine(session, engine); /* Assign new video RTP engine in engine->next */
+ }
+
+ UNPROTECT_INTERFACE(bfcp_endpoint_interface);
+ } else
+ smh->video_media_count--;
+ }
+ }
+
for (map = m->m_rtpmaps; map; map = map->rm_next) {
int found = 0;
for (attr = m->m_attributes; attr && found < 2; attr = attr->a_next) {
@@ -13490,6 +14363,17 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
SWITCH_FALSE);
}
}
+ /*This call is to add application media data to session parsed by FS, specifically used for BFCP */
+ if (m->m_type == sdp_media_application && m->m_port) {
+ /* set channel flag CF_BFCP, if current channel has application media with BFCP related transport proto in SDP */
+ if (switch_core_media_check_bfcp(m) == SWITCH_STATUS_SUCCESS) {
+ switch_channel_set_flag(channel, CF_BFCP);
+ }
+ }
+
+ /*To add media attributes to the switch_rtp-engine*/
+ switch_core_media_copy_media_attribute(session, m);
+ switch_core_media_set_media_protocol(session, m, sdp_type);
}
for (m = sdp->sdp_media; m; m = m->m_next) {
@@ -13576,6 +14460,8 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
}
} else if (m->m_type == sdp_media_video && m->m_port) {
+ int already_have[128] = { 0 }; /*To maintain video codec occurance */
+ video_count++;
connection = sdp->sdp_connection;
if (m->m_connections) {
connection = m->m_connections;
@@ -13590,7 +14476,7 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND || prefer_sdp) {
for (map = m->m_rtpmaps; map; map = map->rm_next) {
- if (map->rm_pt > 127 || already_did[map->rm_pt]) {
+ if (map->rm_pt > 127 || already_have[map->rm_pt]) {
continue;
}
@@ -13609,12 +14495,13 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
}
if (match) {
+ smh->video_pt_count[video_count]++;
if (map->rm_fmtp) {
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s~%s", imp->modname, imp->iananame, map->rm_fmtp);
} else {
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s", imp->modname, imp->iananame);
}
- already_did[imp->ianacode] = 1;
+ already_have[imp->ianacode] = 1;
}
}
}
@@ -13623,7 +14510,7 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
for (i = 0; i < num_codecs; i++) {
const switch_codec_implementation_t *imp = codecs[i];
- if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) {
+ if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_have[imp->ianacode]) {
continue;
}
@@ -13634,7 +14521,7 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
for (map = m->m_rtpmaps; map; map = map->rm_next) {
- if (map->rm_pt > 127 || already_did[map->rm_pt]) {
+ if (map->rm_pt > 127 || already_have[map->rm_pt]) {
continue;
}
@@ -13650,12 +14537,13 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
}
if (match) {
+ smh->video_pt_count[video_count]++;
if (map->rm_fmtp) {
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s~%s", imp->modname, imp->iananame, map->rm_fmtp);
} else {
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s.%s", imp->modname, imp->iananame);
}
- already_did[imp->ianacode] = 1;
+ already_have[imp->ianacode] = 1;
}
}
}
@@ -13666,12 +14554,19 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess
switch_channel_set_flag(channel, CF_WANT_MSRPS);
} else if (m->m_type == sdp_media_text) {
switch_channel_set_flag(channel, CF_WANT_RTT);
+ } else if ((m->m_type == sdp_media_application) && (switch_core_media_check_bfcp(m) == SWITCH_STATUS_SUCCESS)) {
+ switch_rtp_engine_t *app_engine = &smh->engines[SWITCH_MEDIA_TYPE_APPLICATION];
+
+ app_engine->payload_map->remote_sdp_ip = switch_core_session_strdup(session, connection->c_address);
+ app_engine->payload_map->remote_sdp_port = m->m_port;
}
}
if (buf[0] == ',') {
switch_channel_set_variable(channel, "ep_codec_string", buf + 1);
}
+
+ smh->video_media_count = 0;
}
//?
@@ -14418,6 +15313,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_sess
return SWITCH_STATUS_NOTIMPL;
}
+ if (mtype == SWITCH_MEDIA_TYPE_VIDEO) {
+ /* There can be case where there will be multiple video media channel and for each video channel there will be thread running for RTP packet flow,
+ below logic handles video_rtp_engine to use by comparing thread_id stored in rtp_engine with thread_id of currently running thread */
+ if (engine->next && engine->next->thread_id == switch_thread_self()) engine = engine->next;
+ }
+
if (iotype == SWITCH_IO_READ) {
codec = &engine->read_codec;
} else {
@@ -14525,14 +15426,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_time_t now = switch_micro_time_now();
- switch_codec_t *codec = switch_core_session_get_video_write_codec(session);
+ // switch_codec_t *codec = switch_core_session_get_video_write_codec(session);
+ switch_codec_t *codec = switch_core_media_get_video_write_codec(session, 0);
switch_timer_t *timer;
switch_media_handle_t *smh;
switch_image_t *dup_img = NULL, *img = frame->img;
switch_status_t encode_status;
switch_frame_t write_frame = {0};
switch_rtp_engine_t *v_engine = NULL;
+ switch_core_session_t *peer_session = NULL;
+ switch_rtp_engine_t *peer_v_engine = NULL;
switch_bool_t need_free = SWITCH_FALSE;
+ int is_presentation = 0;
switch_assert(session);
if (!(smh = session->media_handle)) {
@@ -14562,14 +15467,46 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
return SWITCH_STATUS_SUCCESS;
}
+
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ switch_core_session_get_partner(session, &peer_session);
+
+ if (peer_session) {
+ if (peer_session->media_handle) {
+ peer_v_engine = &peer_session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ if (peer_v_engine) {
+ if (peer_v_engine->thread_id != switch_thread_self() && peer_v_engine->next && peer_v_engine->next->thread_id == switch_thread_self()) {
+ v_engine = v_engine->next;
+ is_presentation = 1;
+ }
+ }
+ }
+ switch_core_session_rwunlock(peer_session);
+ }
+
+ if (v_engine->thread_id != switch_thread_self() && v_engine->next && v_engine->next->thread_id && v_engine->next->thread_id == switch_thread_self()) {
+ v_engine = v_engine->next;
+ is_presentation = 1;
+ }
+
+ if (!is_presentation) {
if (smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO] && switch_mutex_trylock(smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]) != SWITCH_STATUS_SUCCESS) {
/* return CNG, another thread is already writing */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being written to for %s\n",
switch_channel_get_name(session->channel), type2str(SWITCH_MEDIA_TYPE_VIDEO));
return SWITCH_STATUS_INUSE;
}
+ } else {
+ if (smh->write_presentation_mutex && switch_mutex_trylock(smh->write_presentation_mutex) != SWITCH_STATUS_SUCCESS) {
+ /* return CNG, another thread is already writing */
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s is already being written to for presentation\n",
+ switch_channel_get_name(session->channel));
+ return SWITCH_STATUS_INUSE;
+ }
+ }
- v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
if (v_engine->thread_write_lock && v_engine->thread_write_lock != switch_thread_self()) {
switch_goto_status(SWITCH_STATUS_SUCCESS, done);
}
@@ -14738,8 +15675,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
done:
- if (smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]) {
+ if (!is_presentation && smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]) {
switch_mutex_unlock(smh->write_mutex[SWITCH_MEDIA_TYPE_VIDEO]);
+ } else if (smh->write_presentation_mutex) {
+ switch_mutex_unlock(smh->write_presentation_mutex);
}
switch_img_free(&dup_img);
@@ -14835,6 +15774,10 @@ SWITCH_DECLARE(void) switch_core_session_passthru(switch_core_session_t *session
engine = &session->media_handle->engines[type];
+ if (type == SWITCH_MEDIA_TYPE_VIDEO)
+ {
+ if (engine->thread_id != switch_thread_self() && engine->next && engine->next->thread_id == switch_thread_self()) engine = engine->next;
+ }
if (switch_rtp_ready(engine->rtp_session)) {
char var[50] = "";
@@ -16288,6 +17231,65 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
return status;
}
+SWITCH_DECLARE(switch_codec_t *) switch_core_media_get_video_read_codec(switch_core_session_t *session)
+{
+ switch_codec_t *codec;
+ switch_media_handle_t *smh;
+ switch_rtp_engine_t *v_engine;
+
+ if (!(smh = session->media_handle)) {
+ return NULL;
+ }
+
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ if (v_engine->thread_id != switch_thread_self() && v_engine->next && v_engine->next->thread_id == switch_thread_self()) v_engine = v_engine->next;
+
+ codec = &v_engine->read_codec;
+
+ return codec;
+}
+
+SWITCH_DECLARE(switch_codec_t *) switch_core_media_get_video_write_codec(switch_core_session_t *session, int flag)
+{
+ switch_codec_t *codec;
+ switch_media_handle_t *smh;
+ switch_rtp_engine_t *v_engine;
+
+ if (!(smh = session->media_handle)) {
+ return NULL;
+ }
+
+ v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ if (flag) {
+ switch_core_session_t *peer_session = NULL;
+ switch_rtp_engine_t *peer_engine;
+
+ switch_core_session_get_partner(session, &peer_session);
+
+ if (peer_session && peer_session->media_handle) {
+ peer_engine = &peer_session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO];
+
+ if (peer_engine->thread_id != switch_thread_self() && v_engine->next && peer_engine->next
+ && peer_engine->next->thread_id == switch_thread_self()) {
+ v_engine = v_engine->next;
+ }
+ }
+
+ if (peer_session) {
+ switch_core_session_rwunlock(peer_session);
+ }
+ } else {
+ if (v_engine->thread_id != switch_thread_self() && v_engine->next && v_engine->next->thread_id && v_engine->next->thread_id == switch_thread_self()) {
+ v_engine = v_engine->next;
+ }
+ }
+
+ codec = &v_engine->write_codec;
+
+ return codec;
+}
/* For Emacs:
diff --git a/src/switch_core_session.c b/src/switch_core_session.c
index ca58566b2fe..2c012e9711e 100644
--- a/src/switch_core_session.c
+++ b/src/switch_core_session.c
@@ -659,6 +659,7 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_
const char *val;
switch_codec_t *vid_read_codec = NULL, *read_codec = switch_core_session_get_read_codec(session);
const char *ep = NULL, *max_forwards = switch_core_session_sprintf(session, "%d", forwardval);
+ const char *bfcp_local_sdp = switch_channel_get_variable(channel , SWITCH_BFCP_LOCAL_SDP);
switch_channel_set_variable(peer_channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
@@ -684,6 +685,12 @@ SWITCH_DECLARE(switch_call_cause_t) switch_core_session_outgoing_channel(switch_
switch_channel_set_variable(peer_channel, SWITCH_ORIGINATOR_CODEC_VARIABLE, ep);
}
+ /* set channel flag in peer_channel if current channel has application BFCP in sdp and also
+ store local sdp for BFCP media which will later append to local sdp for FS -> clients of other channel */
+ if (switch_channel_test_flag(channel,CF_BFCP) && bfcp_local_sdp) {
+ switch_channel_set_flag(peer_channel, CF_PEER_BFCP);
+ switch_channel_set_variable(peer_channel, SWITCH_PEER_BFCP_LOCAL_SDP, bfcp_local_sdp);
+ }
if (switch_channel_test_flag(channel, CF_MSRPS) || switch_channel_test_flag(channel, CF_WANT_MSRPS)) {
switch_channel_set_flag(peer_channel, CF_WANT_MSRPS);
@@ -917,6 +924,22 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_perform_receive_message(swit
status = switch_core_media_receive_message(session, message);
}
if (status == SWITCH_STATUS_SUCCESS) {
+ if (switch_channel_test_flag(session->channel, CF_BFCP)) {
+ switch_endpoint_interface_t *bfcp_endpoint_interface;
+ if ((bfcp_endpoint_interface = switch_loadable_module_get_endpoint_interface(BFCP)) == 0) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),SWITCH_LOG_INFO, "Module mod_bfcp not loaded\n");
+ }
+
+ if (bfcp_endpoint_interface) {
+ if (!bfcp_endpoint_interface->io_routines->receive_message) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Could not locate receive_message API for bfcp\n");
+ } else {
+ bfcp_endpoint_interface->io_routines->receive_message(session, message);
+ }
+
+ UNPROTECT_INTERFACE(bfcp_endpoint_interface);
+ }
+ }
if (session->endpoint_interface->io_routines->receive_message) {
status = session->endpoint_interface->io_routines->receive_message(session, message);
}
@@ -2167,6 +2190,10 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_xml(switch_e
flags[CF_SIMPLIFY] = 0;
flags[CF_VIDEO_READY] = 0;
flags[CF_VIDEO_DECODED_READ] = 0;
+ flags[CF_BFCP] = 0;
+ flags[CF_EARLY_MEDIA_BFCP] = 0;
+ flags[CF_PEER_BFCP] = 0;
+ flags[CF_BFCP_STREAM_CHANGE] = 0;
if (!(session = switch_core_session_request_uuid(endpoint_interface, direction, SOF_NO_LIMITS, pool, uuid))) {
return NULL;
diff --git a/src/switch_core_state_machine.c b/src/switch_core_state_machine.c
index 57ba3bfeb22..0fb6adb4f8c 100644
--- a/src/switch_core_state_machine.c
+++ b/src/switch_core_state_machine.c
@@ -533,6 +533,7 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
{
switch_channel_state_t state = CS_NEW, midstate = CS_DESTROY, endstate;
const switch_endpoint_interface_t *endpoint_interface;
+ switch_endpoint_interface_t *bfcp_endpoint_interface;
const switch_state_handler_table_t *driver_state_handler = NULL;
const switch_state_handler_table_t *application_state_handler = NULL;
int silly = 0;
@@ -638,6 +639,22 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
switch_event_fire(&event);
}
}
+
+ /* bfcp_endpoint_interface is used to call mod_bfcp API's */
+
+ if ((bfcp_endpoint_interface = switch_loadable_module_get_endpoint_interface(BFCP)) == 0) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),SWITCH_LOG_INFO, "Module mod_bfcp not loaded\n");
+ }
+
+ if (bfcp_endpoint_interface) {
+ if (!bfcp_endpoint_interface->state_handler->on_init) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Could not locate init state for bfcp\n");
+ } else {
+ bfcp_endpoint_interface->state_handler->on_init(session);
+ }
+
+ UNPROTECT_INTERFACE(bfcp_endpoint_interface);
+ }
}
break;
case CS_ROUTING: /* Look for a dialplan and find something to do */
@@ -648,7 +665,25 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
break;
/* These other states are intended for prolonged durations so we do not signal lock for them */
case CS_EXECUTE: /* Execute an Operation */
- STATE_MACRO(execute, "EXECUTE");
+ {
+ if (switch_channel_test_flag(session->channel, CF_BFCP)) {
+ if ((bfcp_endpoint_interface = switch_loadable_module_get_endpoint_interface(BFCP)) == 0) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),SWITCH_LOG_INFO, "Module mod_bfcp not loaded\n");
+ }
+
+ if (bfcp_endpoint_interface) {
+ if (!bfcp_endpoint_interface->state_handler->on_execute) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Could not locate execute state for bfcp\n");
+ } else {
+ bfcp_endpoint_interface->state_handler->on_execute(session);
+ }
+
+ UNPROTECT_INTERFACE(bfcp_endpoint_interface);
+ }
+ }
+
+ STATE_MACRO(execute, "EXECUTE");
+ }
break;
case CS_EXCHANGE_MEDIA: /* loop all data back to source */
STATE_MACRO(exchange_media, "EXCHANGE_MEDIA");
@@ -725,6 +760,7 @@ SWITCH_DECLARE(void) switch_core_session_destroy_state(switch_core_session_t *se
{
switch_channel_state_t state = CS_DESTROY, midstate = CS_DESTROY;
const switch_endpoint_interface_t *endpoint_interface;
+ switch_endpoint_interface_t *bfcp_endpoint_interface;
const switch_state_handler_table_t *driver_state_handler = NULL;
const switch_state_handler_table_t *application_state_handler = NULL;
int proceed = 1;
@@ -748,6 +784,21 @@ SWITCH_DECLARE(void) switch_core_session_destroy_state(switch_core_session_t *se
STATE_MACRO(destroy, "DESTROY");
+ /* bfcp_endpoint_interface stores the object for endpoint interface of mod_bfcp and used to call mod_bfcp API's */
+ if (switch_channel_test_flag(session->channel, CF_BFCP)) {
+ if ((bfcp_endpoint_interface = switch_loadable_module_get_endpoint_interface(BFCP)) == 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Module mod_bfcp not loaded\n");
+ } else {
+ if (!bfcp_endpoint_interface->state_handler->on_destroy) {
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Could not locate destroy state for bfcp\n");
+ } else {
+ bfcp_endpoint_interface->state_handler->on_destroy(session);
+ }
+
+ UNPROTECT_INTERFACE(bfcp_endpoint_interface);
+ }
+ }
+
switch_channel_clear_device_record(session->channel);
return;
diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c
index 3e5e2145be5..c61a732b574 100644
--- a/src/switch_ivr_bridge.c
+++ b/src/switch_ivr_bridge.c
@@ -175,7 +175,17 @@ static void video_bridge_thread(switch_core_session_t *session, void *obj)
while (switch_channel_up_nosig(channel) && switch_channel_up_nosig(b_channel) && vh->up == 1) {
if (switch_channel_media_up(channel)) {
- if (switch_core_session_transcoding(vh->session_a, vh->session_b, SWITCH_MEDIA_TYPE_VIDEO)) {
+ /* Not using session level API for getting read and write codec because we have multiple video media */
+ // switch_codec_t *a_codec = switch_core_session_get_video_read_codec(vh->session_a);
+ // switch_codec_t *b_codec = switch_core_session_get_video_write_codec(vh->session_b);
+
+ /* For implementing multiple video stream, we are using media specific API to get codec for particular video stream */
+ switch_codec_t *a_codec = switch_core_media_get_video_read_codec(vh->session_a);
+ switch_codec_t *b_codec = switch_core_media_get_video_write_codec(vh->session_b, 1);
+
+ if (!a_codec || !b_codec || !a_codec->implementation || !b_codec->implementation) continue;
+
+if (switch_core_session_transcoding(vh->session_a, vh->session_b, SWITCH_MEDIA_TYPE_VIDEO)) {
pass_val = 1;
} else {
pass_val = 2;
diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c
index 174644faffd..c9a5db01a10 100644
--- a/src/switch_loadable_module.c
+++ b/src/switch_loadable_module.c
@@ -2391,13 +2391,28 @@ static switch_status_t do_shutdown(switch_loadable_module_t *module, switch_bool
module->shutting_down = SWITCH_TRUE;
if (shutdown) {
- switch_loadable_module_unprocess(module);
if (module->switch_module_shutdown) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Stopping: %s\n", module->module_interface->module_name);
module->status = module->switch_module_shutdown();
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "%s has no shutdown routine\n", module->module_interface->module_name);
}
+
+ /* If mod_bfcp's switch_module_shutdown return SWITCH_STATUS_NOUNLOAD, then we will not destroy it's API and Endpoint interface
+ That's why we shifted switch_loadable_module_unprocess down so, that module's shutdown status can 1st analyzed*/
+ if (module->status == SWITCH_STATUS_NOUNLOAD && !strcmp(module->key, "mod_bfcp")) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Module %s is in use, cannot unload.\n", module->module_interface->module_name);
+ module->shutting_down = SWITCH_FALSE;
+
+ if (fail_if_busy && module->module_interface->rwlock) {
+ switch_thread_rwlock_unlock(module->module_interface->rwlock);
+ }
+
+ /* returning SWITCH_STATUS_FALSE so that it can be added back in loadable_module_list */
+ return SWITCH_STATUS_FALSE;
+ } else {
+ switch_loadable_module_unprocess(module);
+ }
}
if (fail_if_busy && module->module_interface->rwlock) {
@@ -2972,6 +2987,164 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_
return i;
}
+
+SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted2(const switch_codec_implementation_t **array, char fmtp_array[SWITCH_MAX_CODECS][MAX_FMTP_LEN], int arraylen, char **prefs, int preflen, int *video_pt_count)
+{
+ int x, i = 0, j = 0, video_count = 0, audio_count = 0;
+ switch_codec_interface_t *codec_interface;
+ const switch_codec_implementation_t *imp;
+
+ switch_mutex_lock(loadable_modules.mutex);
+
+ for (x = 0; x < preflen; x++) {
+ char *name, buf[256], jbuf[256], *modname = NULL, *fmtp = NULL;
+ uint32_t interval = 0, rate = 0, bit = 0, channels = 1;
+
+ switch_copy_string(buf, prefs[x], sizeof(buf));
+ name = switch_parse_codec_buf(buf, &interval, &rate, &bit, &channels, &modname, &fmtp);
+
+ for(j = 0; j < x; j++) {
+ char *jname, *jmodname = NULL, *jfmtp = NULL;
+ uint32_t jinterval = 0, jrate = 0, jbit = 0, jchannels = 1;
+ uint32_t ointerval = interval, orate = rate, ochannels = channels;
+
+ if (ointerval == 0) {
+ ointerval = switch_default_ptime(name, 0);
+ }
+
+ if (orate == 0) {
+ orate = switch_default_rate(name, 0);
+ }
+
+ if (ochannels == 0) {
+ ochannels = 1;
+ }
+
+ switch_copy_string(jbuf, prefs[j], sizeof(jbuf));
+ jname = switch_parse_codec_buf(jbuf, &jinterval, &jrate, &jbit, &jchannels, &jmodname, &jfmtp);
+
+ if (jinterval == 0) {
+ jinterval = switch_default_ptime(jname, 0);
+ }
+
+ if (jrate == 0) {
+ jrate = switch_default_rate(jname, 0);
+ }
+
+ if (jchannels == 0) {
+ jchannels = 1;
+ }
+
+ if (!strcasecmp(name, jname) && ointerval == jinterval && orate == jrate && ochannels == jchannels &&
+ !strcasecmp(switch_str_nil(fmtp), switch_str_nil(jfmtp))) {
+ if (video_count != 0) {
+ int a, b;
+ a = j - audio_count + 1;
+ b = x - audio_count + 1;
+
+ if (!(video_pt_count[0] >= a && video_pt_count[0] < b)) {
+ goto next_x;
+ }
+ } else {
+ goto next_x;
+ }
+ }
+ }
+
+ if ((codec_interface = switch_loadable_module_get_codec_interface(name, modname)) != 0) {
+ /* If no specific codec interval is requested opt for the default above all else because lots of stuff assumes it */
+ for (imp = codec_interface->implementations; imp; imp = imp->next) {
+ uint32_t default_ptime = switch_default_ptime(imp->iananame, imp->ianacode);
+ uint32_t default_rate = switch_default_rate(imp->iananame, imp->ianacode);
+
+ if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+ uint32_t crate = !strcasecmp(imp->iananame, "g722") ? imp->samples_per_second : imp->actual_samples_per_second;
+
+ if ((!interval && (uint32_t) (imp->microseconds_per_packet / 1000) != default_ptime) ||
+ (interval && (uint32_t) (imp->microseconds_per_packet / 1000) != interval)) {
+ continue;
+ }
+
+ if (((!rate && crate != default_rate) || (rate && (uint32_t) imp->actual_samples_per_second != rate))) {
+ continue;
+ }
+
+ if (bit && (uint32_t) imp->bits_per_second != bit) {
+ continue;
+ }
+
+ if (channels && imp->number_of_channels != channels) {
+ continue;
+ }
+ }
+
+ if (!zstr(fmtp)) {
+ switch_set_string(fmtp_array[i], fmtp);
+ }
+ array[i++] = imp;
+ if (imp->codec_type == SWITCH_CODEC_TYPE_VIDEO) { /* Updates video count in current codec parsed is of video media */
+ video_count++;
+ } else if (imp->codec_type == SWITCH_CODEC_TYPE_AUDIO) {
+ audio_count++;
+ }
+ goto found;
+
+ }
+
+ /* Either looking for a specific interval or there was no interval specified and there wasn't one at the default ptime available */
+ for (imp = codec_interface->implementations; imp; imp = imp->next) {
+ if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
+ uint32_t crate = !strcasecmp(imp->iananame, "g722") ? imp->samples_per_second : imp->actual_samples_per_second;
+
+ if (interval && (uint32_t) (imp->microseconds_per_packet / 1000) != interval) {
+ continue;
+ }
+
+ if (rate && (uint32_t) crate != rate) {
+ continue;
+ }
+
+ if (bit && (uint32_t) imp->bits_per_second != bit) {
+ continue;
+ }
+
+ if (channels && imp->number_of_channels != channels) {
+ continue;
+ }
+ }
+
+ array[i++] = imp;
+ if (imp->codec_type == SWITCH_CODEC_TYPE_VIDEO) { /* Updates video count in current codec parsed is of video media */
+ video_count++;
+ } else if (imp->codec_type == SWITCH_CODEC_TYPE_AUDIO) {
+ audio_count++;
+ }
+ goto found;
+
+ }
+
+ found:
+
+ UNPROTECT_INTERFACE(codec_interface);
+
+ if (i > arraylen) {
+ break;
+ }
+
+ }
+
+ next_x:
+
+ continue;
+ }
+
+ switch_mutex_unlock(loadable_modules.mutex);
+
+ switch_loadable_module_sort_codecs(array, i);
+
+ return i;
+}
+
SWITCH_DECLARE(switch_status_t) switch_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream)
{
switch_api_interface_t *api;