pax_global_header00006660000000000000000000000064125224222400014505gustar00rootroot0000000000000052 comment=ad48d8c538ce998707e0e1daceac23ba3636ecfa belle-sip-1.4.1/000077500000000000000000000000001252242224000133645ustar00rootroot00000000000000belle-sip-1.4.1/.cproject000066400000000000000000000456521252242224000152120ustar00rootroot00000000000000 make install true true true make CFLAGS="-g -Wall " -j3 all true true true make CFLAGS="-g -Wall " -j3 test true true true belle-sip-1.4.1/.gitignore000066400000000000000000000012071252242224000153540ustar00rootroot00000000000000INSTALL aclocal.m4 *~ configure Makefile.in Makefile build-aux m4 autom4te.cache *.o *.lo *.la config.log config.status .deps .libs libtool compile depcomp missing install-sh config.guess config.h.in config.sub ltmain.sh stamp-h1 .anjuta belle-sip.anjuta .kdev4/ belle-sip.kdev4 config.h src/specs.c belle-sip.pc belle-sip.spec html/ *.orig tester/belle_sip_object_describe tester/belle_sip_parse tester/belle_sip_tester tester/belle_http_get tester/belle_sip_resolve tester/CUnitAutomated-Results.xml tester/download.tar.gz tester/tmp_resolv.conf tester/belle_sip_tester_crt tester/CUnitAutomated-Results.xml.tmp-Results.xml belle-sip-tests.log belle-sip-1.4.1/.project000066400000000000000000000053541252242224000150420ustar00rootroot00000000000000 belle-sip org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, ?name? org.eclipse.cdt.make.core.append_environment true org.eclipse.cdt.make.core.autoBuildTarget all org.eclipse.cdt.make.core.buildArguments CFLAGS="-g -Wall " V=1 org.eclipse.cdt.make.core.buildCommand make org.eclipse.cdt.make.core.cleanBuildTarget clean org.eclipse.cdt.make.core.contents org.eclipse.cdt.make.core.activeConfigSettings org.eclipse.cdt.make.core.enableAutoBuild false org.eclipse.cdt.make.core.enableCleanBuild true org.eclipse.cdt.make.core.enableFullBuild true org.eclipse.cdt.make.core.fullBuildTarget all org.eclipse.cdt.make.core.stopOnError true org.eclipse.cdt.make.core.useDefaultBuildCmd false org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 1329213830469 22 org.eclipse.ui.ide.multiFilter 1.0-name-matches-false-false-*.lo 1329213830473 22 org.eclipse.ui.ide.multiFilter 1.0-name-matches-false-false-*.o belle-sip-1.4.1/AUTHORS000066400000000000000000000001101252242224000144240ustar00rootroot00000000000000Belledonne Communications SARL belle-sip-1.4.1/CMakeLists.txt000066400000000000000000000143721252242224000161330ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ cmake_minimum_required(VERSION 3.0) project(BELLESIP C CXX) set(PACKAGE "belle-sip") set(PACKAGE_NAME "${PACKAGE}") set(PACKAGE_VERSION "1.4.1") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "jehan.monnier@linphone.org") set(PACKAGE_TARNAME "belle-sip") set(PACKAGE_URL "") set(VERSION "${PACKAGE_VERSION}") option(ENABLE_SERVER_SOCKETS "Enable server sockets" ON) option(ENABLE_STATIC "Build static library (default is shared library)." OFF) option(ENABLE_TLS "Enable TLS support" ON) option(ENABLE_TUNNEL "Enable tunnel support" OFF) option(ENABLE_TESTS "Enable compilation of tests" ON) include(CheckLibraryExists) include(CheckSymbolExists) include(CheckCSourceCompiles) include(CMakePushCheckState) set(MSVC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/MSVC") if(MSVC) list(APPEND CMAKE_REQUIRED_INCLUDES ${MSVC_INCLUDE_DIR}) endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") check_library_exists("dl" "dlopen" "" HAVE_LIBDL) check_library_exists("rt" "clock_gettime" "" HAVE_LIBRT) cmake_push_check_state(RESET) check_symbol_exists("res_ndestroy" "resolv.h" HAVE_RES_NDESTROY) set(CMAKE_REQUIRED_LIBRARIES resolv) check_c_source_compiles("#include int main(int argc, char *argv[]) { res_getservers(NULL,NULL,0); return 0; }" HAVE_RES_GETSERVERS) if(HAVE_RES_NDESTROY AND HAVE_RES_GETSERVERS) set(HAVE_RESINIT 1) endif() cmake_pop_check_state() find_package(Threads) find_package(Antlr3 REQUIRED) cmake_push_check_state(RESET) set(CMAKE_REQUIRED_INCLUDES ${ANTLR3C_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${ANTLR3C_LIBRARIES}) check_symbol_exists("antlr3StringStreamNew" "antlr3.h" HAVE_ANTLR_STRING_STREAM_NEW) cmake_pop_check_state() if(ENABLE_TLS) find_package(PolarSSL REQUIRED) if(POLARSSL_FOUND) set(HAVE_POLARSSL 1) endif() endif() if(ENABLE_TUNNEL) find_package(Tunnel) if(TUNNEL_FOUND) set(HAVE_TUNNEL 1) else() message(WARNING "Could not find the tunnel library!") set(ENABLE_TUNNEL OFF CACHE BOOL "Enable tunnel support" FORCE) endif() endif() if(ENABLE_TESTS) find_package(CUnit) if(CUNIT_FOUND) check_library_exists(${CUNIT_LIBRARIES} "CU_add_suite" "" HAVE_CU_ADD_SUITE) check_library_exists(${CUNIT_LIBRARIES} "CU_get_suite" "" HAVE_CU_GET_SUITE) check_library_exists(${CUNIT_LIBRARIES} "CU_curses_run_tests" "" HAVE_CU_CURSES) else() message(WARNING "Could not find cunit framework, tests will not be compiled.") set(ENABLE_TESTS OFF CACHE BOOL "Enable compilation of tests" FORCE) endif() endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) set(prefix ${CMAKE_INSTALL_PREFIX}) set(exec_prefix ${prefix}/bin) set(libdir ${prefix}/lib) set(includedir ${prefix}/include) get_filename_component(antlr3c_library_path "${ANTLR3C_LIBRARIES}" PATH) set(LIBS_PRIVATE "-L${antlr3c_library_path} -lantlr3c") if(CUNIT_FOUND) set(REQUIRES_PRIVATE "${REQUIRES_PRIVATE} cunit") endif() if(HAVE_POLARSSL) get_filename_component(polarssl_library_path "${POLARSSL_LIBRARIES}" PATH) set(LIBS_PRIVATE "${LIBS_PRIVATE} -L${polarssl_library_path} -lpolarssl") endif() if(HAVE_LIBDL) set(LIBS_PRIVATE "${LIBS_PRIVATE} -ldl") endif() if(HAVE_LIBRT) set(LIBS_PRIVATE "${LIBS_PRIVATE} -lrt") endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/belle-sip.pc.in ${CMAKE_CURRENT_BINARY_DIR}/belle-sip.pc) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/belle-sip.pc DESTINATION lib/pkgconfig) include_directories( include src ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/src ${POLARSSL_INCLUDE_DIRS} ) if(TUNNEL_FOUND) include_directories(${TUNNEL_INCLUDE_DIRS}) endif() if(CUNIT_FOUND) include_directories(${CUNIT_INCLUDE_DIRS}) endif() if(MSVC) include_directories(${MSVC_INCLUDE_DIR}) endif() add_definitions(-DHAVE_CONFIG_H) if(NOT MSVC) add_definitions(-Wall -Wno-error=unknown-pragmas) if("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") add_definitions(-Werror -Wno-error=unknown-warning-option -Qunused-arguments -Wno-tautological-compare) elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") add_definitions(-Werror -Wno-error=pragmas) endif() endif() set(LINK_FLAGS ) if(APPLE) list(APPEND LINK_FLAGS "-framework CoreFoundation" "-framework CFNetwork") endif() if(WIN32) add_definitions( -DBELLESIP_EXPORTS -DBELLESIP_INTERNAL_EXPORTS ) endif() if("${CMAKE_SYSTEM_NAME}" STREQUAL "WindowsPhone") add_definitions( -DHAVE_COMPILER_TLS -DUSE_FIXED_NAMESERVERS ) endif() add_subdirectory(include) add_subdirectory(src) if(ENABLE_TESTS) enable_testing() add_subdirectory(tester) endif() include(CMakePackageConfigHelpers) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/BelleSIPConfigVersion.cmake" VERSION ${PACKAGE_VERSION} COMPATIBILITY AnyNewerVersion ) export(EXPORT BelleSIPTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/BelleSIPTargets.cmake" NAMESPACE BelledonneCommunications:: ) configure_file(cmake/BelleSIPConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/BelleSIPConfig.cmake" @ONLY ) set(ConfigPackageLocation lib/cmake/BelleSIP) install(EXPORT BelleSIPTargets FILE BelleSIPTargets.cmake NAMESPACE BelledonneCommunications:: DESTINATION ${ConfigPackageLocation} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/BelleSIPConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/BelleSIPConfigVersion.cmake" DESTINATION ${ConfigPackageLocation} ) belle-sip-1.4.1/COPYING000066400000000000000000000431271252242224000144260ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. belle-sip-1.4.1/ChangeLog000066400000000000000000000000001252242224000151240ustar00rootroot00000000000000belle-sip-1.4.1/Makefile.am000066400000000000000000000005111252242224000154150ustar00rootroot00000000000000#ACLOCAL_AMFLAGS = -I m4 SUBDIRS=include src tester EXTRA_DIST = belle-sip.spec test: cd tester $(MAKE) -C tester test rpm: $(MAKE) dist TAR_OPTIONS=--wildcards rpmbuild -ta --clean --rmsource --rmspec $(PACKAGE)-$(VERSION).tar.gz pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = belle-sip.pc EXTRA_DIST=autogen.sh belle-sip-1.4.1/NEWS000066400000000000000000000017311252242224000140650ustar00rootroot00000000000000belle-sip-1.4.1 -- May 6th, 2015 * Bug fixes belle-sip-1.4.0 -- March 11th, 2015 * support of display names of type (token LWS)* instead of just token * support for absolute URIs belle-sip-1.3.3 -- September 18th, 2014 * DNS SRV weight selection * support of multipart messages * support of Wake Locks on Android * support of backslash escaped display name belle-sip-1.3.0 -- February 20th, 2014 -- initial release of belle-sip * RFC3261 compliant implementation of SIP parser, writer, transactions and dialog layers. * http client api * support of client TLS certificate * fully asynchronous transport layer (UDP, TCP, TLS) * fully asynchronous DNS resolution with SRV * full dual-stack IPv6 support * SIP transaction state machines with lastest corrections (RFC6026) * automatic management of request refreshes with network disconnection resiliency thanks to the "refresher" object * supported platforms: Linux, Mac OSX, windows XP+, iOS, Android, Blackberry 10. belle-sip-1.4.1/README000066400000000000000000000053761252242224000142570ustar00rootroot00000000000000# Belle-sip ## Overview Belle-sip is a SIP (RFC3261) implementation written in C, with an object oriented API. Please check "NEWS" file for an overview of current features. Copyright 2012-2014, Belledonne Communications SARL , all rights reserved. Belle-sip is distributed to everyone under the GNU GPLv2 (see COPYING file for details). Incorporating belle-sip within a closed source project is not possible under the GPL. Commercial licensing can be purchased for that purpose from [Belledonne Communications](http://www.belledonne-communications.com). ## Build prerequisite * [Java SE](http://www.oracle.com/technetwork/java/javase/downloads/index.html) on openJDK This is required to generate a C sourcefile from SIP grammar using [antlr3](http://www.antlr3.org/) generator. ### Dependencies * libtool * intltool * pkg-config * libantlr3c-3.2 or 3.4 * antlr3-3.2 or 3.4 * C++ compiler (for instance g++ or clang++) * (optional) CUnit * (optional) polarssl >= 1.2 (see below) #### Under Debian/Ubuntu apt-get install libtool intltool pkg-config libantlr3c-dev antlr3 g++ make #and for optional dependencies apt-get install libcunit1-dev libpolarssl-dev #### Under MacOS X using HomeBrew brew tap Gui13/linphone brew install intltool libtool pkg-config automake libantlr3.4c antlr3.2 ln -s /usr/local/bin/glibtoolize /usr/local/bin/libtoolize #### Under Windows using mingw and Visual Studio The procedure is tested for Visual Studio Express 2012. * Compile and install libantlr3c, CUnit with ./configure && make && make install * get antlr3 from linphone's git server (see above). This version contains up to date visual studio project and solution files. * get CUnit from linphone's git server (see above). This version contains up to date visual studio project and solution files. * put belle-sip next to antlr3 and to cunit (in the same directory). * open belle-sip/build/windows/belle-sip-tester/belle-sip-tester.sln or belle-sip/build/windows/belle-sip/belle-sip.sln * Build the solution (antlr3 and cunit are built automatically) #### Building polarssl Polarssl build system is Make (or Cmake). To build the shared library version, use `make SHARED=1 DEBUG=1`, followed by `make install`. We maintain a branch of polarssl with automake/autoconf/libtool support at git://git.linphone.org/polarssl.git -b linphone #### Known issues 1. Antlr3 on windows On windows you have to edit /usr/local/include/antl3defs.h replace: #include with: #include Or get the source code from linphone's git (linphone branch): git clone -b linphone git://git.linphone.org/antlr3.git git clone -b linphone git://git.linphone.org/cunit.git belle-sip-1.4.1/README.centos000077500000000000000000000015161252242224000155440ustar00rootroot00000000000000Belle-sip rpm can be built applying the following procedure: centos6.4 *********** *antlr.jar* Belle sip needs antlr.jar to generate parser code. A prebuilt jar is available from the antlr git and should be manually install using the following command: git clone -b linphone git://git.linphone.org/antlr3 sudo mkdir /usr/local/share/java sudo cp antlr3/antlr-3.4-complete.jar /usr/local/share/java/antlr.jar *libantlr3c* Belle sip uses libantlr3c version 3.2 or above. This dependency cannot be easely met on centos 6.4. To manually build libantlr3c on a 64 bits system, checkout source code using: cd antlr3/runtime/C ./autogen.sh ./configure --disable-shared --enable-64bit --with-pic make sudo make install Now, back to belle-sip ./autogen.sh ./configure make rpm belle-sip-1.4.1/autogen.sh000077500000000000000000000012661252242224000153720ustar00rootroot00000000000000#!/bin/sh if ! type aclocal-$AM_VERSION 1>/dev/null 2>&1; then # automake-1.10 (recommended) is not available on Fedora 8 AUTOMAKE=automake ACLOCAL=aclocal else ACLOCAL=aclocal-${AM_VERSION} AUTOMAKE=automake-${AM_VERSION} fi if test -f /opt/local/bin/glibtoolize ; then # darwin LIBTOOLIZE=/opt/local/bin/glibtoolize else LIBTOOLIZE=libtoolize fi if test -d /opt/local/share/aclocal ; then ACLOCAL_ARGS="-I /opt/local/share/aclocal" fi if test -d /share/aclocal ; then ACLOCAL_ARGS="-I /share/aclocal" fi echo "Generating build scripts in belle-sip..." set -x $LIBTOOLIZE --copy --force $ACLOCAL $ACLOCAL_ARGS autoheader $AUTOMAKE --force-missing --add-missing --copy autoconf belle-sip-1.4.1/belle-sip.pc.in000066400000000000000000000005131252242224000161700ustar00rootroot00000000000000# This is a comment prefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ Name: belle-sip Description: A c based implementation of the SIP (RFC 3261) telephony protocol Requires.private: @REQUIRES_PRIVATE@ @TLS_PC@ Version: @VERSION@ Libs: -L@libdir@ -lbellesip Libs.private: @LIBS_PRIVATE@ Cflags: -I@includedir@ belle-sip-1.4.1/belle-sip.spec.in000077500000000000000000000027651252242224000165360ustar00rootroot00000000000000# -*- rpm-spec -*- ## rpmbuild options Name: belle-sip Version: @VERSION@ Release: %(version=`git describe --tags --abbrev=40 | sed -rn 's/^.*-([0-9]+)-g[a-z0-9]{40}$/\1/p'` && if test -z "$version" ; then echo 0 ; else echo $version ; fi)%{?dist} Summary: Linphone sip stack Group: Applications/Communications License: GPL URL: http://www.belle-sip.org BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Source0: %{name}-%{version}.tar.gz %description Belle-sip is an object oriented c written SIP stack used by Linphone. BuildRequires: antlr3-tool antlr3-C-devel %package devel Summary: Development libraries for belle-sip Group: Development/Libraries Requires: %{name} = %{version}-%{release} %description devel Libraries and headers required to develop software with belle-sip %prep %setup -q %build %configure \ --disable-tests --enable-static --docdir=%{_docdir} %__make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT %clean rm -rf $RPM_BUILD_ROOT %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %defattr(-,root,root) %doc AUTHORS ChangeLog COPYING NEWS README %{_libdir}/*.so.* %files devel %defattr(-,root,root) %{_includedir}/belle-sip %{_libdir}/libbellesip.a %{_libdir}/libbellesip.la %{_libdir}/libbellesip.so %{_libdir}/pkgconfig/belle-sip.pc %changelog * Mon Aug 19 2013 jehan.monnier - Initial RPM release. belle-sip-1.4.1/build/000077500000000000000000000000001252242224000144635ustar00rootroot00000000000000belle-sip-1.4.1/build/android/000077500000000000000000000000001252242224000161035ustar00rootroot00000000000000belle-sip-1.4.1/build/android/Android.mk000066400000000000000000000052761252242224000200260ustar00rootroot00000000000000## ## Android.mk -Android build script- ## ## ## Copyright (C) 2013 Belledonne Communications, Grenoble, France ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ## LOCAL_PATH:= $(call my-dir)/../../src include $(CLEAR_VARS) LOCAL_MODULE := libbellesip LOCAL_CFLAGS += \ -DHAVE_CONFIG_H \ -DBELLESIP_VERSION=\"$(BELLESIP_VERSION)\" LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/../../externals/antlr3/runtime/C/include \ $(LOCAL_PATH)/../include \ $(LOCAL_PATH)/../build/android LOCAL_SRC_FILES := \ auth_event.c \ auth_helper.c \ belle_sdp_impl.c \ http-listener.c \ http-provider.c \ http-message.c \ generic-uri.c \ belle_sip_headers_impl.c \ belle_sip_loop.c \ grammars/belle_sip_messageLexer.c \ grammars/belle_sip_messageParser.c \ grammars/belle_sdpLexer.c \ grammars/belle_sdpParser.c \ belle_sip_object.c \ belle_sip_dict.c \ belle_sip_parameters.c \ belle_sip_resolver.c \ belle_sip_uri_impl.c \ belle_sip_utils.c \ channel.c \ clock_gettime.c \ dialog.c \ dns.c \ ict.c \ ist.c \ listeningpoint.c \ md5.c \ message.c \ nict.c \ nist.c \ port.c \ provider.c \ refresher.c \ siplistener.c \ sipstack.c \ transaction.c \ bodyhandler.c \ transports/stream_channel.c \ transports/stream_listeningpoint.c \ transports/tls_channel_polarssl.c \ transports/tls_listeningpoint_polarssl.c \ transports/udp_channel.c \ transports/udp_listeningpoint.c \ wakelock.c ifeq ($(BUILD_TUNNEL), 1) LOCAL_CFLAGS += -DHAVE_TUNNEL LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../tunnel/include LOCAL_SRC_FILES += \ transports/tunnel_listeningpoint.c \ transports/tunnel_channel.c \ transports/tunnel_wrapper.cc endif ifeq ($(BUILD_RTP_MAP),1) LOCAL_CFLAGS += -DBELLE_SDP_FORCE_RTP_MAP endif ifeq ($(BUILD_DONT_CHECK_HEADERS_IN_MESSAGE),1) LOCAL_CFLAGS += -DBELLE_SIP_DONT_CHECK_HEADERS_IN_MESSAGE endif LOCAL_STATIC_LIBRARIES := \ antlr3 ifeq ($(BUILD_TLS),1) LOCAL_STATIC_LIBRARIES += polarssl LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../externals/polarssl/include LOCAL_CFLAGS += -DHAVE_POLARSSL=1 endif include $(BUILD_STATIC_LIBRARY) belle-sip-1.4.1/build/android/config.h000066400000000000000000000050731252242224000175260ustar00rootroot00000000000000/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #define HAVE_ANTLR3_H 1 /* Define to 1 if you have the header file. */ /* #undef HAVE_CUNIT_CUNIT_H */ /* defined when CU_curses_run_tests is available */ /* #undef HAVE_CU_CURSES */ /* defined when CU_get_suite is available */ /* #undef HAVE_CU_GET_SUITE */ /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Defined when gnutls api is available */ /* #undef HAVE_GNUTLS */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `dl' library (-ldl). */ #define HAVE_LIBDL 1 /* Define to 1 if you have the `rt' library (-lrt). */ /* #undef HAVE_LIBRT */ /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ #define PACKAGE "belle-sip" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "jehan.monnier@linphone.org" /* Define to the full name of this package. */ #define PACKAGE_NAME "belle-sip" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "belle-sip 0.0.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "belle-sip" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ //#define PACKAGE_VERSION "0.0.1" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ #define VERSION "0.0.1" /* Defined when antlr 3.4 api is detected */ #define HAVE_ANTLR_STRING_STREAM_NEW 1 #define ENABLE_SERVER_SOCKETS 1 belle-sip-1.4.1/build/wp8/000077500000000000000000000000001252242224000152015ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/000077500000000000000000000000001252242224000210755ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-native/000077500000000000000000000000001252242224000255415ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-native/belle-sip-tester-native.cpp000066400000000000000000000056461252242224000327240ustar00rootroot00000000000000#include #include "belle-sip-tester-native.h" #include "belle-sip/belle-sip.h" #include "cunit/Util.h" using namespace belle_sip_tester_native; using namespace Platform; #define MAX_TRACE_SIZE 512 #define MAX_SUITE_NAME_SIZE 128 static OutputTraceListener^ sTraceListener; static void nativeOutputTraceHandler(int lev, const char *fmt, va_list args) { if (sTraceListener) { wchar_t wstr[MAX_TRACE_SIZE]; std::string str; str.resize(MAX_TRACE_SIZE); vsnprintf((char *)str.c_str(), MAX_TRACE_SIZE, fmt, args); mbstowcs(wstr, str.c_str(), sizeof(wstr)); String^ msg = ref new String(wstr); sTraceListener->outputTrace(msg); } } static void belleSipNativeOutputTraceHandler(belle_sip_log_level lev, const char *fmt, va_list args) { nativeOutputTraceHandler((int)lev, fmt, args); } BelleSipTesterNative::BelleSipTesterNative() { belle_sip_tester_init(); } BelleSipTesterNative::~BelleSipTesterNative() { belle_sip_tester_uninit(); } void BelleSipTesterNative::setOutputTraceListener(OutputTraceListener^ traceListener) { sTraceListener = traceListener; } void BelleSipTesterNative::run(Platform::String^ suiteName, Platform::String^ caseName, Platform::Boolean verbose) { std::wstring all(L"ALL"); std::wstring wssuitename = suiteName->Data(); std::wstring wscasename = caseName->Data(); char csuitename[MAX_SUITE_NAME_SIZE] = { 0 }; char ccasename[MAX_SUITE_NAME_SIZE] = { 0 }; wcstombs(csuitename, wssuitename.c_str(), sizeof(csuitename)); wcstombs(ccasename, wscasename.c_str(), sizeof(ccasename)); if (verbose) { belle_sip_set_log_level(BELLE_SIP_LOG_DEBUG); } else { belle_sip_set_log_level(BELLE_SIP_LOG_ERROR); } belle_sip_set_log_handler(belleSipNativeOutputTraceHandler); CU_set_trace_handler(nativeOutputTraceHandler); belle_sip_tester_set_root_ca_path("Assets/rootca.pem"); belle_sip_tester_run_tests(wssuitename == all ? 0 : csuitename, wscasename == all ? 0 : ccasename); } unsigned int BelleSipTesterNative::nbTestSuites() { return belle_sip_tester_nb_test_suites(); } unsigned int BelleSipTesterNative::nbTests(Platform::String^ suiteName) { std::wstring suitename = suiteName->Data(); char cname[MAX_SUITE_NAME_SIZE] = { 0 }; wcstombs(cname, suitename.c_str(), sizeof(cname)); return belle_sip_tester_nb_tests(cname); } Platform::String^ BelleSipTesterNative::testSuiteName(int index) { const char *cname = belle_sip_tester_test_suite_name(index); wchar_t wcname[MAX_SUITE_NAME_SIZE]; mbstowcs(wcname, cname, sizeof(wcname)); return ref new String(wcname); } Platform::String^ BelleSipTesterNative::testName(Platform::String^ suiteName, int testIndex) { std::wstring suitename = suiteName->Data(); char csuitename[MAX_SUITE_NAME_SIZE] = { 0 }; wcstombs(csuitename, suitename.c_str(), sizeof(csuitename)); const char *cname = belle_sip_tester_test_name(csuitename, testIndex); wchar_t wcname[MAX_SUITE_NAME_SIZE]; mbstowcs(wcname, cname, sizeof(wcname)); return ref new String(wcname); } belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-native/belle-sip-tester-native.h000066400000000000000000000013321252242224000323550ustar00rootroot00000000000000#pragma once #include "belle-sip/belle-sip.h" #include "belle_sip_tester.h" namespace belle_sip_tester_native { public interface class OutputTraceListener { public: void outputTrace(Platform::String^ msg); }; public ref class BelleSipTesterNative sealed { public: BelleSipTesterNative(); virtual ~BelleSipTesterNative(); void setOutputTraceListener(OutputTraceListener^ traceListener); unsigned int nbTestSuites(); unsigned int nbTests(Platform::String^ suiteName); Platform::String^ testSuiteName(int index); Platform::String^ testName(Platform::String^ suiteName, int testIndex); void run(Platform::String^ suiteName, Platform::String^ caseName, Platform::Boolean verbose); }; }belle-sip-tester-native.vcxproj000066400000000000000000000153451252242224000335530ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-native Debug Win32 Debug ARM Release Win32 Release ARM {3b4e9c2c-d5dc-4cf9-a7f4-5cb4ab55af79} belle_sip_tester_native en-US 11.0 true DynamicLibrary true v110_wp80 DynamicLibrary false true v110_wp80 $(SolutionDir)$(Platform)\$(Configuration)\ $(SolutionDir)$(Platform)\$(Configuration)\ false Level4 $(ProjectDir);$(GeneratedFilesDir);$(IntDir);$(ProjectDir)..\..\..\..\include;$(ProjectDir)..\..\..\..\src;$(ProjectDir)..\..\..\..\tester;$(ProjectDir)..\..\..\..\..\cunit\build\wp8\cunit\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories) WIN32;_WINDOWS;_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;HAVE_CU_GET_SUITE;PACKAGE_VERSION=$(BELLESIP_PACKAGE_VERSION);%(PreprocessorDefinitions) Default NotUsing $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) false Console false ole32.lib;%(IgnoreSpecificDefaultLibraries) true WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;ws2_32.lib;%(AdditionalDependencies) $(SolutionDir)$(Platform)\$(Configuration) _DEBUG;%(PreprocessorDefinitions) NDEBUG;%(PreprocessorDefinitions) MaxSpeed true true true true false true {902daf1d-ebf1-4d03-b598-143500a50ab4} {4c225a82-800b-427b-ba7b-61686a9b347f} belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8.sln000066400000000000000000000151111252242224000255060ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Express 2012 for Windows Phone Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "belle-sip-tester-wp8", "belle-sip-tester-wp8\belle-sip-tester-wp8.csproj", "{2CEBCF29-6B23-46C2-B579-588321228F3E}" ProjectSection(ProjectDependencies) = postProject {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79} = {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip-tester-native", "belle-sip-tester-native\belle-sip-tester-native.vcxproj", "{3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}" ProjectSection(ProjectDependencies) = postProject {4C225A82-800B-427B-BA7B-61686A9B347F} = {4C225A82-800B-427B-BA7B-61686A9B347F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cunit", "..\..\..\..\cunit\build\wp8\cunit\cunit.vcxproj", "{902DAF1D-EBF1-4D03-B598-143500A50AB4}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libantlr3c", "..\..\..\..\antlr3\runtime\C\build\wp8\libantlr3c\libantlr3c.vcxproj", "{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "..\belle-sip\belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}" ProjectSection(ProjectDependencies) = postProject {8FA74260-151B-429B-83EF-3CF3EAC8CFD9} = {8FA74260-151B-429B-83EF-3CF3EAC8CFD9} {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09} = {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\wp8\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tunnel", "..\..\..\..\tunnel\build\wp8\tunnel\tunnel.vcxproj", "{59500DD1-B192-4DDF-A402-8A8E3739E032}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM Debug|x86 = Debug|x86 Release|ARM = Release|ARM Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2CEBCF29-6B23-46C2-B579-588321228F3E}.Debug|ARM.ActiveCfg = Debug|ARM {2CEBCF29-6B23-46C2-B579-588321228F3E}.Debug|ARM.Build.0 = Debug|ARM {2CEBCF29-6B23-46C2-B579-588321228F3E}.Debug|ARM.Deploy.0 = Debug|ARM {2CEBCF29-6B23-46C2-B579-588321228F3E}.Debug|x86.ActiveCfg = Debug|x86 {2CEBCF29-6B23-46C2-B579-588321228F3E}.Debug|x86.Build.0 = Debug|x86 {2CEBCF29-6B23-46C2-B579-588321228F3E}.Debug|x86.Deploy.0 = Debug|x86 {2CEBCF29-6B23-46C2-B579-588321228F3E}.Release|ARM.ActiveCfg = Release|ARM {2CEBCF29-6B23-46C2-B579-588321228F3E}.Release|ARM.Build.0 = Release|ARM {2CEBCF29-6B23-46C2-B579-588321228F3E}.Release|ARM.Deploy.0 = Release|ARM {2CEBCF29-6B23-46C2-B579-588321228F3E}.Release|x86.ActiveCfg = Release|x86 {2CEBCF29-6B23-46C2-B579-588321228F3E}.Release|x86.Build.0 = Release|x86 {2CEBCF29-6B23-46C2-B579-588321228F3E}.Release|x86.Deploy.0 = Release|x86 {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}.Debug|ARM.ActiveCfg = Debug|ARM {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}.Debug|ARM.Build.0 = Debug|ARM {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}.Debug|x86.ActiveCfg = Debug|Win32 {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}.Debug|x86.Build.0 = Debug|Win32 {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}.Release|ARM.ActiveCfg = Release|ARM {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}.Release|ARM.Build.0 = Release|ARM {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}.Release|x86.ActiveCfg = Release|Win32 {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79}.Release|x86.Build.0 = Release|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.ActiveCfg = Debug|ARM {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|ARM.Build.0 = Debug|ARM {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.ActiveCfg = Debug|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Debug|x86.Build.0 = Debug|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.ActiveCfg = Release|ARM {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|ARM.Build.0 = Release|ARM {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.ActiveCfg = Release|Win32 {902DAF1D-EBF1-4D03-B598-143500A50AB4}.Release|x86.Build.0 = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.ActiveCfg = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|x86.Build.0 = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.ActiveCfg = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|x86.Build.0 = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.ActiveCfg = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|x86.Build.0 = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.ActiveCfg = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|x86.Build.0 = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.ActiveCfg = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|x86.Build.0 = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.ActiveCfg = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|x86.Build.0 = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.ActiveCfg = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|x86.Build.0 = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.ActiveCfg = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/000077500000000000000000000000001252242224000247715ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/App.xaml000066400000000000000000000016451252242224000264020ustar00rootroot00000000000000 belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/App.xaml.cs000066400000000000000000000222371252242224000270060ustar00rootroot00000000000000using System; using System.Diagnostics; using System.Resources; using System.Windows; using System.Windows.Markup; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using belle_sip_tester_wp8.Resources; using belle_sip_tester_native; namespace belle_sip_tester_wp8 { public partial class App : Application { /// /// Provides easy access to the root frame of the Phone Application. /// /// The root frame of the Phone Application. public static PhoneApplicationFrame RootFrame { get; private set; } /// /// Constructor for the Application object. /// public App() { // Global handler for uncaught exceptions. UnhandledException += Application_UnhandledException; // Standard XAML initialization InitializeComponent(); // Phone-specific initialization InitializePhoneApplication(); // Language display initialization InitializeLanguage(); // Show graphics profiling information while debugging. if (Debugger.IsAttached) { // Display the current frame rate counters. Application.Current.Host.Settings.EnableFrameRateCounter = true; // Show the areas of the app that are being redrawn in each frame. //Application.Current.Host.Settings.EnableRedrawRegions = true; // Enable non-production analysis visualization mode, // which shows areas of a page that are handed off to GPU with a colored overlay. //Application.Current.Host.Settings.EnableCacheVisualization = true; // Prevent the screen from turning off while under the debugger by disabling // the application's idle detection. // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run // and consume battery power when the user is not using the phone. PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled; } tester = new BelleSipTesterNative(); suite = null; } // Code to execute when the application is launching (eg, from Start) // This code will not execute when the application is reactivated private void Application_Launching(object sender, LaunchingEventArgs e) { } // Code to execute when the application is activated (brought to foreground) // This code will not execute when the application is first launched private void Application_Activated(object sender, ActivatedEventArgs e) { } // Code to execute when the application is deactivated (sent to background) // This code will not execute when the application is closing private void Application_Deactivated(object sender, DeactivatedEventArgs e) { } // Code to execute when the application is closing (eg, user hit Back) // This code will not execute when the application is deactivated private void Application_Closing(object sender, ClosingEventArgs e) { } // Code to execute if a navigation fails private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) { if (Debugger.IsAttached) { // A navigation has failed; break into the debugger Debugger.Break(); } } // Code to execute on Unhandled Exceptions private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) { if (Debugger.IsAttached) { // An unhandled exception has occurred; break into the debugger Debugger.Break(); } } #region Phone application initialization // Avoid double-initialization private bool phoneApplicationInitialized = false; // Do not add any additional code to this method private void InitializePhoneApplication() { if (phoneApplicationInitialized) return; // Create the frame but don't set it as RootVisual yet; this allows the splash // screen to remain active until the application is ready to render. RootFrame = new PhoneApplicationFrame(); RootFrame.Navigated += CompleteInitializePhoneApplication; // Handle navigation failures RootFrame.NavigationFailed += RootFrame_NavigationFailed; // Handle reset requests for clearing the backstack RootFrame.Navigated += CheckForResetNavigation; // Ensure we don't initialize again phoneApplicationInitialized = true; } // Do not add any additional code to this method private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) { // Set the root visual to allow the application to render if (RootVisual != RootFrame) RootVisual = RootFrame; // Remove this handler since it is no longer needed RootFrame.Navigated -= CompleteInitializePhoneApplication; } private void CheckForResetNavigation(object sender, NavigationEventArgs e) { // If the app has received a 'reset' navigation, then we need to check // on the next navigation to see if the page stack should be reset if (e.NavigationMode == NavigationMode.Reset) RootFrame.Navigated += ClearBackStackAfterReset; } private void ClearBackStackAfterReset(object sender, NavigationEventArgs e) { // Unregister the event so it doesn't get called again RootFrame.Navigated -= ClearBackStackAfterReset; // Only clear the stack for 'new' (forward) and 'refresh' navigations if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh) return; // For UI consistency, clear the entire page stack while (RootFrame.RemoveBackEntry() != null) { ; // do nothing } } #endregion // Initialize the app's font and flow direction as defined in its localized resource strings. // // To ensure that the font of your application is aligned with its supported languages and that the // FlowDirection for each of those languages follows its traditional direction, ResourceLanguage // and ResourceFlowDirection should be initialized in each resx file to match these values with that // file's culture. For example: // // AppResources.es-ES.resx // ResourceLanguage's value should be "es-ES" // ResourceFlowDirection's value should be "LeftToRight" // // AppResources.ar-SA.resx // ResourceLanguage's value should be "ar-SA" // ResourceFlowDirection's value should be "RightToLeft" // // For more info on localizing Windows Phone apps see http://go.microsoft.com/fwlink/?LinkId=262072. // private void InitializeLanguage() { try { // Set the font to match the display language defined by the // ResourceLanguage resource string for each supported language. // // Fall back to the font of the neutral language if the Display // language of the phone is not supported. // // If a compiler error is hit then ResourceLanguage is missing from // the resource file. RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage); // Set the FlowDirection of all elements under the root frame based // on the ResourceFlowDirection resource string for each // supported language. // // If a compiler error is hit then ResourceFlowDirection is missing from // the resource file. FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection); RootFrame.FlowDirection = flow; } catch { // If an exception is caught here it is most likely due to either // ResourceLangauge not being correctly set to a supported language // code or ResourceFlowDirection is set to a value other than LeftToRight // or RightToLeft. if (Debugger.IsAttached) { Debugger.Break(); } throw; } } public bool suiteRunning() { return (suite != null) && (suite.running); } public BelleSipTesterNative tester { get; set; } public UnitTestSuite suite { get; set; } } }belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Assets/000077500000000000000000000000001252242224000262335ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Assets/AlignmentGrid.png000066400000000000000000000215221252242224000314670ustar00rootroot00000000000000‰PNG  IHDRðQ5´ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF}IDATxÚìÙ Ü0DÁ(¸ ÷â:Ý‹;Ú4!ŽíLZa ­$€]@€ @ @€ € @€@€ @€ @€ € @€@€ @€ @€  Ø5út÷zFŸïËk«­¶ÚzôÖé{›¶úŽmµµû_¼‘("@€ @ @€ € @€@ø/­$nJx@€ @€ @Øì}º{=£Ï÷åµÕV[m=zëô½M[}ǶÚÚý/ÞÈ  @€ € @€@€ @ `¶•Ä-@ / @€ € à7®Ñ§»×3ú|_^[mµÕÖ£·NßÛ´Õwl«­Ýÿâ¼@€ @€@€ @€ @€ @€f[IÜ”ð€ @€@€~ã}º{=£Ï÷åµÕV[m=zëô½M[}ǶÚÚý/ÞÈ  @€ € @€@€ @ `¶•Ä-@ / @€ € à7®Ñ§»×3ú|_^[mµÕÖ£·NßÛ´Õwl«­Ýÿâ¼@€ @€@€ @€ @€ @€f[IÜ”ð€ @€@€~ã}º{=£Ï÷åµÕV[m=zëô½M[}ǶÚÚý/ÞÈ  @€ € @€@€ @ `¶•Ä-@ / @€ € à7®Ñ§»×3ú|_^[mµÕÖ£·NßÛ´Õwl«­Ýÿâ¼@€ @€@€ @€ @€ @€f[IÜ”ð€ @€@€~ã}º{=£Ï÷åµÕV[m=zëô½M[}ǶÚÚý/ÞÈ  @€ € @€@€ @ `¶•Ä-@ / @€ € @›]£Ow¯gôù¾¼¶Új«­Go¾·i«ïØV[»ÿÅy€" @€ € @€@€ @€ €ÿÒJâ „€ @€@€ €Í®Ñ§»×3ú|_^[mµÕÖ£·NßÛ´Õwl«­Ýÿâ¼@€ @€@€ @€ @€ @€f[IÜ”ð€ @€@€~ã}º{=£Ï÷åµÕV[m=zëô½M[}ǶÚÚý/ÞÈ  @€ € @€@€ @ `¶•Ä-@ / @€ € à7®Ñ§»×3ú|_^[mµÕÖ£·NßÛ´Õwl«­Ýÿâ¼@€ @€@€ @€ @€ @€f[IÜ”ð€ @€@€~ã}º{=£Ï÷åµÕV[m=zëô½M[}ǶÚÚý/ÞÈ  @€ € @€@€ @ `¶•Ä-@ / @€ € à7®Ñ§»×3ú|_^[mµÕÖ£·NßÛ´Õwl«­Ýÿâ¼@€ @€@€ @€ @€ @€f[IÜ”ð€ @€@€~ã}º{=£Ï÷åµÕV[m=zëô½M[}ǶÚÚý/ÞÈ  @€ € @€@€ @ `¶•Ä-@ / @€ € à7®Ñ§»×3ú|_^[mµÕÖ£·NßÛ´Õwl«­Ýÿâ¼@€ @€@€ @€ @€ @€f[IÜ”ð€ @€@€~ã}º{=£Ï÷åµÕV[m=zëô½M[}ǶÚÚý/ÞÈ  @€ € @€@€ @ `¶•Ä-@ / @€ € @›]£Ow¯gôù¾¼¶Új«­Go¾·i«ïØV[»ÿÅy€" @€ € @€@€ @€ ̶’¸(á @€ € üÆ5út÷zFŸïËk«­¶ÚzôÖé{›¶úŽmµµû_¼‘("@€ @ @€ € @€@Àl+‰[€^@€ @ @Ào\£Ow¯gôù¾¼¶Új«­Go¾·i«ïØV[»ÿÅy€" @€ € @€@€ @€ ̶’¸(á @€ € @€àÿ›W`g“&IEND®B`‚belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Assets/ApplicationIcon.png000066400000000000000000000065001252242224000320160ustar00rootroot00000000000000‰PNG  IHDRddpâ•TsRGB®ÎégAMA± üa pHYs.#.#x¥?v ÕIDATx^í]{tUŸ<š&-¡o‘RµzDWQëz_+]+¥ìÊ9+¨kÕŽ‹® ÈžÍîqñQW÷, ²¨È>Ú"/[E^-"²-}µ¥¥Ï¤MÓ$Ís23É$Ùï–öœò˜ffÒIÍüÍw¿ûû¾ß½÷»ß{‚3IØd,‹?cï±TŒaE?L{$qC.€‘ø#$Ä €%NHœy@`pâ=$NˆÀ< 08ñ'D`œx‰"0 N¼‡Ä ˜'æzÈmÅÉL}8CÕ$Ãæ—2•†\Œ­öVw9Š´Ø–0q^Cã½²Z}YAÈ qK„–ÈtV—ÖNº_Ô™nåÄc?Xž¤Ýo«Ž,„³™€ˆ5BÊj­wè°:[Vÿ§mb ;÷5ò”ÛŽäLÚºðýÎTþ1áWD0„̯H<Öb}»h¼½ ñ\Ð’{.Ñqéi×S1LuY|ù³¾ÌA;Ýé+ºŸ¥÷ÅÏ:&•ÕZVòëmÚCÈo“-ÚÛgv6—Ö[ï ½ð“¶,é&|þ}¦ ß0"‚¸zÐYå/Ó¡'«»C%þºÉ¶êÖµß0p¿"B!dÕç=Ù†üHºÜ®zµ£Ø¿·œhµ­öw4ú?òÐGžBA< átÓªýê\_o®ß£ŸŒâ‹{x ì0P§ùõ6íB!dÃÞžHçppöèå½E%î6P5œþ-|ðÄëză=µÝ„ê’KTâã-Ög ŒÉW¶SO50p¿"B!dëQí=.úJgŽô–åêñbá*®`QœqѨ‚Ðè­ôWŒQ LÐåöbÕ­Ö#Ñ€5BÎtÛA<†Mœ×¡·Ñ]/~t²sÅFU¯hê v÷`4Œâº á®ÂJ—º¹ÖHŸhèÕ?§kÙVöüNõ”t¥7M®HPdÈ%‰I EJ²8)Q,NJ’‹’%"‘âÚ Ù³SÓe3ÙÖíòµÝøg8å=E{D¸ÝEãá"씈°9Ý ‹²Q˜£ÇHhKŸ»Á —ÓÞƒ¶%0eô_ÞíD46äQžb°¹Œë÷ë&±"æré¤àvåžNY:ö¯ÝX»eT €¬^ãX½qÁ$ݨ æ2†x·|Õ»ÒBxô\‹íz羇oIùœ+¼\‚mzúFýévó*Ôj~ ÄÁÿ³<¶rf0§„ ™QÚ1@îï„ F× qü«¡jÄ_œ‚ZËîãJX*1ŒgR: ®Š¹7Mü”kù ÛPpMoM¾f¼]ÐØÌûë œU|ö +,‘œï&Ú ìçº AŸÖâªõb"Æ[ZG‡™Ã‹OBrxªÃþ ,§7„ÚpFh”°ÏÛ‹¾=Öl+ZSÒ”>:§‘æ"1Ì.:“t Á¼´µŸü@²~÷‹d â´£EK–”TE£CÄä°"¤°IVÙbù‹ÞæÒÅ¢ùÀì†ÕÓ^Õûõyûï#"…U¦^:ÃÙm&Ë`VÀný&"äÂ,$†n¯èb³†Ø)BV³¬å÷N:»vwÿ½Ýgy¤ÆK9Þ™œÓ8¶,*=ûКG³X,ÖrÔ窤µ]øÎñɃŒsV’¶¿`þëÆÅ*†¨ýðyó/œ…ñY¨:ugë®ZÛ-¬É@ Xž5uÏ®ÓÝz;]?Þ—³PÒÛ6@•í8¤¾û׳”œmCeCµŠ¢ÙY­M}äǰ—“F#T%VÒckÒÚ‹_]Êò¥”Ÿœ’»º-ñœß:;7y“fãùIUH”ßœzâd›õníä"¨¢7ª§ôšœ'„:Öó… ÍcšµÄ§áN1"« ~°Ñü ÙAkø2:ôBc¬ûä[ÝõŒLˆ}PW‰¿o·¿ôÈtå×) IÈÆ@áìÔ„;ß™Q}¤Œ ÜÈc,Ôõ¬Ûžw}òßdRqŒÎgã²àeS’$³såÿ`~=Ò"'–N6Öÿñt;¾Vcr5Äê&¸Hç_Ž€7gõ©‹Ž*ÎÛ¶F®—‹ +œ[* wŸU;6ÿ˜Q@ï39»àÜË_ß=d¸9r†KrÔ}\ZŽ7¢åørÒé¦b! #,·ãp¾åß»k?gµÜîÏ „ŒÔñv…&njӆÑ òHØ ïå>Ñb?Ë ÖI½¢Å³27£ Ǻ PÁu™²ù•­ø > EÔC 9Ò‚/»>K¶€ÀBÐ)†ª?™"ïÇ59\ã᜔±ßuMâßèñü@ïOÍŸ‘¹ läÔP® -¹+ëý”$iæx&cĶi²ücÍö'¸´•SB¾i2/ɽJVÈ%@!ëBgßïœ*ßÄÉÎ÷aC9#¤®Eºçº [ÈÓCWúò<å‡\ÙÌÙ²3¦å3s €$‰Xœ,¼IFb1¦Š¨D¥\¬œ(¹ìÒ® áSÁFÛ w@"èòzEœÌ#0‘‡]&Cÿ†{XÈõæ ë ²[Xáà3ñ&Âà½;ܸS y†?Æ“mö×8Mƒ±Æ_rEÞ¹=‘š©”ÄÜq6dÉÕ¥FëŒ!g1$\W}5ÿêù±8\!»²”Ò9¼ßâÀuPGÈÔ4ÙCád„úûD…$᩼œŸE_tz¬§ÊÅs¢a_uÜ’­XÈ—n_½Q!ä­s¦g*¦EàHë·I&U.y =*„Üó„üÉåù E{1µÉÙy^K~XÙfçl)!6ÊcßYmZÖÔçØÞoquù¿pƒ82 5¬Hõ3-B2'Hæ¡7êPíÔÑSñ—7WéfLM3wf¶âœð¹Æ•©ìå`o®kÅ»-ûn’\4y펛^?Ø{[u±.^«Ä)5¨û§OÈg_S8 \¼1 U¼{‡k\ßÙSgzüñ·[^±·«Æ2¬ó“~‹s¬Lù©ª)ý‹Óâϫφs'«ß£˜†Ä¹½Êðß„„ºdÕ Ûxº¢#B:"ЉaH8IãÁ. ²8Üæšnü¿¬Z†‹š)¸;q ,sÐtÁ^]$¶õ°-•¤™ lè|…ï-ƒ;vË·UõÏ,>¤[iÂݶ`zP|ÒYé7HôÙè/gMM^µ¿Ñ2¯ßêºà¯‹vcføÛ˜oH!˜#}g5¨Wœh·?•{•¼`]~Žݲ£³¹ö#¤m€Üõñ‘ÞÛ´®@2ˆ°óÇNôÛÒ»ÒOþi—áÎ5ñ®“öR>òcÞ;.aá;¨‡ëðû¢ÍÍpöÛ‹ÎèÁ‚/Ñ ÿbÿú®ÿ@ç µ7«†?[q Ñr/<%ýãúæć+ööoõ³ vÀÑ ô¥ò0¨üŠ%¨cp?.L/MÇ[­+ÀâÀ/T Û‡•¾Î¶Âýí;NÜè륑¹øÊë#>æÉÜÕ‰5¸ ®É8À¯·h!%ô pÏtâq´Óåö½`]¨ lØÛ4"bÞmÇúóÂé~¤øâUádxÿ]0„0´}r}z9»v +6ü‘¡£=FªiÌïtghߥð!€Â/’ƒÛ*; ä¡p9Ã;åW£/í|ßi_7ýc*‹„”Õ æo¬Ð2º_½ñ¾×Ëû®S'¦òX$d4öÅœ¬P2õ˜s€…‘òh`¬©Ž"0Æâ„Ä ˜'ÞCâ„̃ï!qBæÁ‰÷8!ó€ÀàÄ{ˆÀa¿=7 Sqb„@Œ$aâÿ&²™[è3UIEND®B`‚belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Assets/Tiles/000077500000000000000000000000001252242224000273135ustar00rootroot00000000000000FlipCycleTileLarge.png000066400000000000000000000233121252242224000334060ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Assets/Tiles‰PNG  IHDR³P¬ßöª pHYs.#.#x¥?v OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFõIDATxÚìÝ}¬d÷Yðç93÷}_¼»Y{µX§II”@œÚ$ÈqÒ'iœÔy!B©‚¥¹»T‚ºR S5‰Á© ‰³­ ì­±yIƒTBÈÚ P°BbßÝ묽Ùû²3s~ýÃ×îe¹ï3÷Þ½w>)’wæÌ9sŸ3ùïùÍ3çd)%`'ª”a„Yff@˜a„Y„Yf@˜@˜a„Yff@˜aa„Yf@˜@˜a„Y„Yf@˜aa„Yff@˜a„Y„Yf@˜@˜a„Yff@˜aa„Yf@˜@˜a„Yff@˜aa„Yf@˜@˜a„Y„Yf@˜aa„Yff@˜a„Yv‹¦À`ËLEXƒéé齇>¿Û*¥Œeæì–³c€gf`õÐø²C‡ݽÛšœœ¬"â7K)ר<€0 зe曺ÝîäfoèCúÐŽˆ›êº¾MÙV—¾¦‚´¬¨”2RJy"3”RJfÞœ™lÒ¶~8">½ðÏ/gæw®²¼ <3³+ûÁÌ<°ü3"îž››ûöM²/ŽˆO,zè…¥”—)?€0 ЋÛ.ù÷á‘‘‘ÿYJë×Î;w0ž™‘[eÛ³kÓjµ®.¥Ü´ÄS/®ëú£ýØÆäädµo߾߈ˆ^ú\)奔{`yzfaÐ=³Ë*¥üTDܾÜóu]ÿD£ÑøH/Ûèv»?WUÕWXä–Ì<±Ìû³“Ç1ƒ!³,VOeæÑÂn;3_›™mdýNç‡Æo®²Ø}™ùa@˜vY˜m·Û7EÄ…¡¡¡?ê÷º~|õù5,:=;;ûÝããã_[ÏúçççÿñðððCqÅ*ï£;;;ûü‰‰‰'6áo¼ivvö‘ñññ¿Û©ŸÇ0@Ï,°c5›Íok4—R~±Ÿ?ÈZpÛ—;<::úéõlzzzïððð‰Õ‚ìÂÉFc||üÖ~þagÏžÝ_JùxD|flllŸO Ìlƒº®÷/\.ë'"âÏÛíö÷õc½ ×–}ÇZ—ÏÌïˆÿ²–e'''«…»‰½pïç¶~Õ¬”rÓW\ñ¥ˆxß³aÜ' f¶c«ªÅ¿ôAgiŸ»¶ì:üH§Óyÿj }øÃþ`f¾i=+ÎÌ£ סݰų±™ùÍ>=€0 °ýö]úú5K{ÛÃõ¯\¼xñåË=ßét~¨”ò6øž6Üj°Älìbffa`›,w Ö ÏÒ®pmÙUeæÐÐÐн­Vëê%å5Fã×rƒ¿¸+¥¼ëäÉ“Íõ¼Æl, ÌìÌ0»áYÚñññ[3³ÑÃ{ºfllìÞÅÁszzzoDÜkøÁ× ϑ믿~Í!{•ÙØÅü f¶ÉZ‚غfiûñc«Ì¼þÕ¯~õÏF<󃯃~<"¾«×õ6±Ú2˜u‡1`Gk*°ƒ­)ˆ-š¥}c»Ý~Ïr×¥]¸¶ìѾÌTÕ;ΗÆ?Šˆ[úô÷þ`)å`fž]æýß´d×ÜRP×õ~#`'33 ìdëýŠ|µYÚÛú:ÀVÕGK)ÇûÞß~都ôÆ^rEa`«”RF×ûšåzi×{mÙ5nk¼ÇþÛX-p¯£7¶_'Â,@ŸÂb/AìïÍÒv»Ý×nàÚ²Ûáeóóó×õñJffMÏ,°“õÄ÷Ò6'vÊ=44ô³øžˆø–>¬ÎÌ, Ìl“~±,üoGÈÌ7_.'ÛM›°“ b—Ï €0 ˆ9!fËJ»Ýþ¾¥nñÚ‹RŠÖŸ:öý:³ßøÆ7ž777÷ª ³ÀîhªêÆÇǯëú/ºÝî/¶Ûíמ:uj¸ÇÕš•íƒÌìù¤àäÉ“Ív»}}·Ûý¹RÊç÷ìÙsfddä%ª lÉ8VJQì0³éÛh·Û×7›Í‡?VJ™É̇뺾¯Ýnß7::ú×ëYçÌÌÌóÇÆÆ¾böì«™ùüõ¾h¡þ¯/¥Ü¯^|Y³RJ·Õj}ÓÞ½{Ïlö›w „Yf·d;¥”3qx…E«ëú÷J)÷?õÔSŸ=|øðùUÖw]D|ÉìÙtf^¹†ý7ÖívoÈÌ›3ó2ó;WXöªªºa‹>Wö 8—æ¶ÊƒñÃ+<MUUˆˆ:t¨]×õÿ.¥Ü×ívþ?K,¯g¶?–mטŸŸ¿®ÙlÞTUÕë"âUFclóAe¶Š™YôA`ëffo‹ˆ_Ûàk§K)¿_UÕýçÏŸÿ̾}ûž,¥Ü'íÁ¾|r¡ÎWDÄÔu}sUU¯‰ß”áå™ù§[ô¹²A˜5€0»ùΟ?åž={N÷!¼”ˆøbDüuf¾Åì]]×?Ÿ™¯Žˆ—eæP«[SÛ‚0 ³ÀŽ ³ ¡éTfUõ]íDfÞ"Ì[Å¥¹€­ ο« »Þ}J³€ ÃŽtáÂûØRÚ `Ð-l3X¸k×¹p%‚]©”òHUU×mñ6œ™Y`+ƒó|D|V%víþÕF³ÀîV×µ¯¡w/ûfÝ­Óé<¨ »Ò|Dü‰2Â,°«ŒŒœŠˆ/«ÄîRJ¹o¡@˜v=}³»/ÌÚ§€0 Œ•`wÑ>³ÀÀ8}úô}ñL%»Ã—ÚG„Y`÷;räH«”ò9•Ø5´Â,0XôXîÝn×¾¶;€Á [x°Åæçç¯þ’=°ãÍGÄþíº’c`fØ =–Ó*±³•R>ç’\Àv23 ƒ>¬aföÔ©SÃGŸ¨ªj¢ªªñÌœh6›ãÝnw""F"b¢ÑhŒ×u=1UU—R&"b"3Ÿûï…ç¯ÎÌ!{aG‡Ù™ˆ8™­…ÿnef+"f#b¶®ë™ˆhEÄLD´ªªju»Ý™ˆh5V§Ó™)¥´J)3¥”ÖÈÈHëÉ'Ÿœ¹ãŽ;Z“““õ¶o'€0k avÕÀ𙈸IµØBwfæû…Y@˜úf¿%"þ<"®P1¶ÀW"â%™ù´0 ¬FÏ,°–Àû•ˆø7*ÁùÀZ‚,€0 ¬'ÐÞ¨›ìÎÌô9Ö~|ò |H]ó²Ú Ødkn/Xô™T5pffõ_íl&í€0 lz ÕnÀfÐ^lì¸ä+øpºî×h7 ÏÖÝ^°è³¨z0àÌÌ ÀÚ è'í€0 ly Õn@?Ü£½èéxä+øPºá×j7 G§#â;{™•u Ì̽aíôB{Ðû±ÈY- | íy¥”ÏDÄMªÉ:Ü“™ïêÃgO%A˜5€0Ûs ÐnÀzôÜ^ ÌÏÒfô#k7`=´ý;9«…¢}[—vÖ /í‹>s* ¬„Ù¾ í¬¤oíÂ,ð,m@?ƒ±vV¢½fËÛ… ~§”òU•`±RÊßFÄTfË1¨Œu:·•R~gbbâñÌüfUa±Ì¼¶”òX)åd§ÓyïÔÔÔ„ªÂ,°­Úíö+K)wDÄãFãSñÆÌl¨ ËÚŒˆÆW^yåT)åívûµ“““ŽEÀÆÇÍó0ðc]ËÏÍÍ}ëÐÐЭ™ykf¾@éU)åñÌüÕùùù»GGGÿr¯U@f  Ì®lzzzïóž÷¼7GÄ{"âUcƒíç2óîóçÏzß¾}O ³Àj|µ,éäÉ“ÍRÊMÝn÷×:4ŸdÙ‚“«WDÄ{÷îýj·Û½·”òÆ“'O6UXvÜpV þÞ¿ççç¿«ÙlÞš™ïÍÌ#*Äv+¥Lgæ'#âÎÌüâ%Ï)³ô0{þüù+÷ìÙóöRÊ»3ó{T…Ë8Øþy)å¿ÏÍÍ}rbbâ Ç0@˜þIDüqDŒ);(Ô~#3¯ˆ/ª 6=³0èg´™_èt:¯)¥<®ì û·ívûU—¶Â,0 †††þdvvö¥¥”?V .ó û{.\xùÈÈÈ_¨ ÌÏ™˜˜xâÑG½1">¦\¦þÓñãÇo^Ë%»€Á¡g}Xâ:³NçUU}<3ÇUˆíVJ™©ëú½ÍfóÞ%žS f  ÌþCóóó× ýNf^«Jl£¿ºxñâ[–k+p ´K9uþüù—–R>£l“§OŸþný±€0 lÈþýûÏ?~ü u]ß^L±EJ)¥®ë;vìíGŽi©°m0èƒÀ2m—êt:o¨ªê™yHÕØÄ ûT]×ïl6›÷¯qyEƒgfX“f³ù»/^|y)åKªÁ&ÙG.^¼øÒµYaX—ÑÑÑ¿9sæÌ+êºþ´jÐg'Μ9óòÑÑÑ¿Q @˜6Í‘#GZFãmñÓúhéU)¥]×õOè6JÏ, ú °ÆžÙ¥´ÛíëƧ2ó›T’ Ù©n·ûÖ¡¡¡?êa ÎÌ,°aCCC» . ¡Ÿ›››{i/A@˜z611ñD)å>•`=2ówo¿ýö'Tèy<ñ |¨Øðk§¦¦&>ü«UUÝ¢’lÀ‰Ó§O¿§—^YÇ0@˜avC¯›ŸŸ¿nxxø7#âªHaô‘Ìü¡Ìü+aØmÀFÄ }^¥'SGK)_èt:oS @˜6ÕäädÕívÿc)åÞÌWúhÇƧJ)·ONN:.ëC|E$ִܹsçîÝ»÷×3óuªÆf)¥üÞ… Þ¹oß¾'׸¼¢0k aveívû•ÍfóSñ-*ÆÚ¿m·Ûoù aX¯s€u:÷7?dÙ¬k‡††>§f ;uêÔp)å£Fãc™9¤"lq o4Ÿêv»9uêÔ°ŠË޾¢ ÿà±V«uõØØØÿÈÌïU!¶ÛÂÝÂÞ:>>þµ%žS f  Ìþívû¦F£qwfV.£@;ÕívßzéíoÃmÀâ`ðSFã~A–Ëð¤ëH£Ñ8YJùÕ„Yàššèv»÷FÄíÙËýmasíPD|´Ûí~\-ðÜØà+lóóóß:<<ü[™ù"Õ`§x¶vllìkªƒÍÌ, ¸™™™¯—R~9"þP5Ø)A63ïît:󪘙…Au”R^X×õ»«ªº5\W–Ë+À>^J¹§ÓéÜ522òè¢Çœ™Y`q°ýr£Ñø™cÇŽ]7FÄ=¥”•a›ÌÖuýén·ûÆãÇ?¿ÑhüÛÅA ÂÌ,Vù½×ôôôÞ¼¥Ñh¼/"^¥bl¶gÛ"â72óéU–U0f  Ì®ÍÜÜÜ· ÝZUÕ{"âÕ£vÉ6‚5¼Nñ`Ài3ÖlttôoÆñcÇŽ}[<Ó†pg)å*Ãi#zff}èñ²²SSSW]uÕ[J)ïwZV³ž6‚5¬KAA˜5€0Û·rM]×ïÎÌw1.ùl77÷’ñññ¯õy½Š NÏ,Ð7“““Õðð卿,qÒthllìWTèûøâ¬>dôm]Ýn÷'«ªúUeïÊÌ{úµ2Ç0@˜a¶/ëÑ^ÀÃg_Û Ãm@Ï´°Ž“'í@Çgµ0ðá¢çuh/`úÒnà³ Ìöôzíl0„ö¥ÝÀ1 Ðfl˜öz8‰ÒnôgªêÛggg¿¹Ûí¾'"NDÄÓ=„Ù£­VëjU„Y`Wi6›ën1(¥üY]×?ßétn|ôÑGdæ›2ó¿ŽŽþe<óc#úd||ükÍfó®Ì¼åÁ<¯¨ëúX)åse¿²ÕjlW3€A¶èju]ŸÊÌ£«„ׯ—R¨ªêþ™™™ÏNLL<±Â²×E„+#ôn:3¯\isçÎÜ·oßk꺾93oÎÌ#«¬óDfÞ²oÞ1 03 lºV«uõRA¶”Ò-¥üa]×ÿ."^~üøñ+Æ;3óž•‚lDÄüü¼™Ù-²ÿþ³™y¢Ñh¼·ªª«/^¼øâº®ÿuD|¶”Ò^â%7œlÁÌl·Ûý±ªª~y!À~µ”r_)åþV«õÐþýûÏnd¥”ÃqÆìÙ#™¹áÛÐNMMM\uÕU¯ªëú ™ùúÌü¶…§nÌÌ7ûÍ;†Â,³›¾RÊ×u]u:ßy´OëÜçìÁí ³Kì—k"â¦n·û•f³y¿0 ³À޳›d `½{03oÜÁŸ{œžY`'Ó7 ÌìXßP‚žM+ Ìl¾ÍÌ–R.ì”?º”ò”] Ì;_Ï3³¥”¯FÄë2óøNù£ëº~WDÜRJéǬª™Y@˜Ø¥”^gfï|úé§_”™ÌÌÌÜSJéyêá‡~ 3O´Z­Å3·ŸfvšÌÜÐ¥¹ÍƾÿàÁƒç""&&&žÈÌv@˜=qã7v""öîÝ{fáN[½ÌÒš™„Y€m²‘™Ùçfc—xî®>Ïß*¥üi_íªº{‰Po–fv 5÷Ì.5»„ßî㫾xæÌ™wÎÍͽ¹”òxŸÂñ#™¹d8îa–Ö]Ôaàrµpc…•fcŸ“™ó™ùÉ>lóBDÜräÈ‘Öøøø×ºÝî;J)í^×›™w­a™­VëEu]ÿ†½³—·Õf ÿªÛí^¿Êlì¥îêå •RJ]×·dæ—Ÿ}lhhè¡Ìü±×Û™™¹g-ËîÝ»÷L£ÑxgD¼naFz%®Õ ³—“…ÙØ_Šˆ— ýÑz^›™ZJyd£ÛÎÌŸk6›÷/ñøÇ"âžÖûÀÄÄÄë}ÍÓO?ý¢ˆ¸s…ÅÜE f¶ÉR3³ÏÎÆþdfÎn08ÞµÁý[ÇŽûÐrÏ?òÈ#ïëáazO<—™ïågiÍÌ;Z>3 ì ¹cß{)e2">¼ðß%3??³Ñû¬V«uõØØØßefc/{,"¾;3Ÿ^å=_SJù“Ì<²Ž¿ó©Ì¼:3{šE={öìþüBD¼oÑÃ7fæƒ;ø3àÿÄ0àÌÌ;Ù³¿Äïy6v±õ^svá_o^-È.œ<<Öívß¶ž4dæ'{ ²ËÎÒš™„Y€íP×õ†{c×à®u¼ÍÌ/¬uù¡¡¡‡J)?½Öå;Χúù‡]ÒK«gØÑ´À ;¸Í`rr²šœœ¬7cÝ¥”‘RÊ™y`• ûKFã'7²n·ûëUUýóU{,3¯]æ=úÏÌ,°“Ãl½Yë^Ë5gK)?ôÐC?½ÑmLOO`µ„Õuý {`…ñÚ™= ø °ƒgf7[)åeñùež~lffæ{×{¹¬%¶qMDüYD\±Ì"×fæc˼ÖNž™Y€åƒþ’ל-¥´ÛíöÛz ² Ûx,"ÞºÌÂ\.È Ì¬%lÞuécu]ÿËáááÏ÷qŸ-¥,u}Z-«¡¾¦‚kа‚%®9û±ÌüÀflkñÂJ)3gΜ¹òÈ‘#­å–7~˜™XÑâkΖRþ8"þÕfmëìÙ³?.lëÄJAa`­NDÄôÜÜÜ-ý¸)Ãr>|>"^OWUu—²¬N› ú  Í`USSS‡zåÐÐÐÿÚŠí•R^“™Ÿ]Ãrvà8f0`§Òf€0 Â,³³ Ì€0 Â,Â,³ Ì Ì€0 Â,³³ Ì€0 €0 Â,³ Ì Ì€0 Â,Â,³ Ì€0 €0 Â,³³ Ì€0 Â,Â,³ Ì Ì€0 Â,³³ Ì€0 €0 Â,³ Ì Ì€0 Â,³³ Ì€0 €0 Â,³ Ì Ì€0 Â,Â,³ Ì€0 €0 Â,³³ Ì€0 Â,Â,³ Ì Ì€0 Â,³³pYøëKœÐ­|G¤IEND®B`‚FlipCycleTileMedium.png000066400000000000000000000215561252242224000336040ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Assets/Tiles‰PNG  IHDRPPéè&Ù pHYs.#.#x¥?v OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF™IDATxÚìÝÜu}Çñ÷ûóýîíÝn.¿sI¨8`•9«È5p b-‚¨®Ú‘qm‹?f(— B¡£•±¶EÐ` HBÑb ¡CT­£ÈÑŽ0bÍyùu·{··ûý¼û›ô¼Þåîö»{·ßÝçc&Éí}w÷ýÝïëû~¿ßÝU3Àì9J( @€ @€P @( @€ (€P @( @€ (€P @€ @€ (€P @€ @€ ( P @€ @€ ( P @€@€ ( P @€ðÿ„” U¥Ól_±bÅÐ\ÝŸ™µ©ê•Ÿ¶NõnéÒ¥_2³us §ŠÈfªŽ9i Ø ÑÖR¶££c@D ªz¦ª>_Ãð\af?‘Õ###Çf³Ù½¬:P:P$ÖòåË/VÕŒª.‘-fÖV‹ûéëëk‘{Uõ5ª´¶¶®§ú @‘hAtûë©Þû;jq?'tÒ­"rþ‘¶sÝTŒðŒð‰•ËåV·µµ½¤ªÁø÷Þ"‚¿¯â(º^D¶Lü÷±±±SÒétk‚ž‰“Édº'†gy§s«™]¥8UDîžìg---d-€ER;œ+¦èÚS"ò@>Ÿÿƒ˜Ë_afŠHÛ?ÿóÞÞ^.ÕŠÄ…ç[UuÍQn²¢µµµâ“J===ND6«êNuU]µvíÚu¬  ¨EÈuïÛ·oQÅt7PÕ³DäK•,üú믿ID¦ Ç j2Æ÷õõµ”J¥wñ*jnœDŠ[ÀŸD2³^3{½ª^­ªÛ«¸Ü´™í-_º4­(Š® ÃðΙ.¿T*]Á·fx󂈣ªûªøüÞdf›Tu¿ªž›àõÏLŠP«ª¾FD1³;«Ø^<ÓðqÎ}ell쌥a¡ðÆ ¾>‹Ç’‘T«ëŒ¢¨ÇÌv«êif¶ˆWŠæížŽûëU‹/~¶o¹4³?›åãH¥R©ûs¹Üê£Ýnpp°½¥¥e«ˆ,®å㙪ë<ùä“w;çn(ŸUMó*"@ѼÒ‚,v7jfKUõ¢ ~õ¸¶¶¶û§:kÞÓÓã–-[¶EDN¬`Gñv3;®]ç„/ä%ÄÇŸ¾îl Þû—*éFÍì£CE_˜b¹Ÿ¹ÜžJºNïýO޲ضýæþCJ:U×Vi7zE¬‘ȹO”J¥ËÆÿ[©TºÄÌ>s¹3>?M×IŠÿÛN8û8b’;›áí~3“3õ…B¡³¥¥åÙ*<®aU=CUŸ=!N?%³<î9…sUuÇt]gù ûi3\ÿšàõÏhóº™ñ ™v£Õz뤪.‘mù|þØt:ýP•ÂS¼÷WT¡ëœXGºP:P4[jf+Dd ‚ß›´ííí Ï9眗TuUæ¡jŽÉf–èXµjU.N×9A‡ªÒÒ¢‰ŒŒŒ´V¸Ã˜´]»víº*‡§H•1ªjfåÊ•ëãv[p-(ŠfÓÖÖ7œ~ïºÑZ½e²>x¸ëœx]g%Òé4ׂ hB±7üñݨˆ\œçÝef§ë¬e—Œd᣾šW57ü«öÜÿ²ŠÇ®é@é@A :P `ÃgG"¯¾¼T*]Xƒo³dïÓÑØØØ›gs.æׯ-à\ê½ï+òú.Ù>66¶-î—¥™ÙGEäXƒ±]«ª_‰³€C‡-Ïd2ë‚ ¸ÀÌÞ¡ªªvÔú³íÓ63{¼Ü1ž'"·¶´´<ë½ÿŸ(Š6™Ùz3[\A(·RÙªìÜf}hoooX,×FQt³™í^°`Á@÷ˆH·ª®òÞ?Ne PTk%9÷à$ï1åÈØbf/›Ù“Qõ‹Å3Ëß4Ý29Zu3£Q;ŸÏkfñÞûœsÎÃp§sîÓ"ò։履l}ƒž¾ò4-"e†Ç-Íl¿ª>EÑ#…Báál6»w’ÛÜ,"Ÿf ÆöEUýä$õm‹¢¨KU/TÕóUõ¤™.pxxxe{{ûÀ¼®X{1qh2BºPã/šáí—ˆÈú Ög2ñÞ?kfßóÞoûÅ/~±³³³sL8 _-Gvj…B¡3 Ãuι DäíATrâïé¹OÐ6M*"Eѵι/W¡ëÈ«êf¶\UßÂŒ]ÏÝfÖçœ;OD^wyÞû AôÌÑcg Í Õú¬MÔ½i?³”%@ ÐÊ^ð/ˆÈqT½a»ÙýªºZU h2p>Y¶Q‚†Þ?6Wá ´í Ë{ÿ}ªÀÏ_»‘k©ˆüVxf£:^U_œÃ×§mª°ÞgfOR‰Æcf{æ2϶OÚ¬÷ˆ™=ÉåK(æHEŒ{ –!@1WFFFø¼ÈR*•XŸ Å1иœ‡c ""ÞûgTõ¬ÄwŸýιÕót߬:PÆ>$zÌz$@1ç+ιT¡!°á᦯¯¯eÍš5™‘‘‘¬s.ëœË¨j6 ÃLEYÉAñÞgE$+"É:ç2Þû¬ªfU5cfG~®ª Dd5k ñ~gf‡D$/"9UÍ™YÞÌrιœ÷>/"¹Ã?wÎå¢(Ê‹H.‚\©TÊ›YÎ{Ÿ÷ÞçÚÚÚr{öìÉ—?4›žMv€:thù‚ ö¨*×mbN”?4ûͪú<ÊŸh .|YU¯¥˜Ã½~ºðš¤.u«ˆl¥˜»vîÜy;e`„oˆ~\W°ÂÌúå1ߣ;#<hƒvQŒî(åÁèFø¹áåQ/£;#<(£<ÀèN€2ÊŒîŒðŒð³íVŠÈÏEd1UD…¯¡b±X<-N?WáïSD:ÐÄïïDäcT1ô†JÃh#„è="ò•@žÞ¹sçm”¾)GxFyÌ×èÎOÊ(Fw `”£;#<#<£<1º3ÂÓ2ʃÑ(åÁèN€¢*¢(º‹*`"ïý·¨B6=‰Ý5Æ^F.—[ÝÚÚz¹ªv«ê)TSŒðƒªzŸˆÜ¥ªÏTay•Mf€šY[EAÐmfªj@51‹×ÏOÍ죣£÷e³Ù½(ÚZ,Ï Ãð*3[¯ª © bi$"ßóÞßÁwTµ@€   £££¯K¥RÝåý T 5rÀ{¿Å9·YUw hbtpp°}ùòå—ŠÈ•"ÒE¥0Çž÷Þo.‡é¯ ÐÚà,|õôô83[Eѽ˖-ë‘» OÌ“sŸ3³ͬ·T*}¨¿¿?KYª+¤ñ …“Ã0ìvÎu‹Èkc¿„º™TDº‚ èêèèø’™=X*•6ßtÓMÿ!"ž 1ÂÏ+ïýGœsÿD%0w‰ÈÕ”~^AðÏQ]cfEª„¸mÆ ¦ t õ0"‰È«—'Að€ªCUPÌ,ï½ÿP†÷—ÿNQè@ëC*•úÑÈÈÈéföCª: ÏŠÅâÛ‡'к“Íf÷>÷ÜsçŠÈW©ê(<>#NÿŒj u­³³sLU?EÑ5"2BE0ÁiÞû[7nÜxáÂ… _¦"ÕÇ1и<Ê;‘ …Bg*•úŽªO¥0Çá¹ß{Y†å6Š´~¥Ó龡¡¡ÓÍìª9 Ï=ccc§-joëÀÀÀ­­­¿¢Œð‰á'é Ö›Ù&UÍP9T¹ë43ûÌ7Þx[OOŸáïP849*ÂqQÔ$<§=ÞI€2Â7„qÇEùŠTÃSï$@›Ê¢E‹ö9çÞ+"×q\•òÞßµgÏž³9ÞÉß4#üDÅbq]÷ªê2ª‰ŽÞEU½VU¿s9“4ÙòùüÓ"ò •À,ü¦P(Z·šËåV·µµ= ªgQ%ÌSˆ¾P,ß3Õ'ѳí3Â×¥b±xf[[Ûž˜çûñ©TêÉR©ô~ªA€&B©Tº:‚ïó휨“ÍAðMŽ‹2Â×õÏñN$`¤ÿ½ã¢lûh](Ç;‘ =r\”mŸ­‡‘ýÌ `dG‚B4ï½ÿP|G|L‰) ܪ~ÛÌ^¡H@xEd{9ªAZ#¼È«Ç@O<ñÄ‹œsݪúnISÔQp>©ª›‡††¶p ”­»ïàÁƒK.\Ømf—«ê[¨æ)4kf÷”J¥Métú¹I~N‘áëÏ¢E‹ö©êíιÓÇÆÆÖxï?ofýTsšyùF©T:ãÆÇAð©ÉÂt uÛN¦··7ìêê:Ï{¹ª^ÂGÙ¡Š¡iªú}¹gÿþý,]ºôà â ÉÐñÛ—,Yò§A\%"o§Š¨08_0³MιMªúë ~Ÿ" É ÐñFGG_—J¥ºUµ[Uß@E1Þû-ιͪº+fSM4Ù:áÝ彿Ü9w%•Å„×F¯÷þ«A<¨ª…*-“ÂÆÄI¤ú ã"ò_T“„ÝSaÞW­ðh#v Ç™Y'˜0Ék#*•Jgµ´´ì®â2),hcèééqfö5ÂS쨃0 ï2³6ªAJ:AE×:ç¾LEq4Þû[‚ ø (J€2ºcGy¶}FxFw0ʃ´Y;PFwÌ×(϶O€&:@Ý1Ÿ£<Û>#|Ò7FwÄå{{{CªAÚt¨™]%"wRAÄå7AÐCJ€6M€šÙkEä§"²˜ "æSTÕ3Tõ'(#|³¸ƒðD•và)¹›Qž´):PFwÔË(϶O€&*@ÝQO£<Û>#<£;À(OÚè(£;êm”gÛ'@ Œî¨ÇQžmŸžÑ`”§mÔthh¨#“É\)"YɈHÖ9—‘6i3³¬ˆdU5cfGþ[þ7¥ÂMßQšˆäT5gfùÃÿ=üo"2""#Þû¼ˆäD$/"¹b±¸µµµõWt hâGøOÛÐÐP6•Je[[[3Åb1›J¥2QeUµÓ9wk ñ>EÑ® rÅb1ŸJ¥r£££ùb±˜kooÏ©êH __T?&Úüúç‘r‡ñòÄŸEQô:*”|Þûb†S‰dâhRWœsçP…†ØIvQFxFø9dfi3ÛÇ'9%Ÿ™E¹\î˜öööy¸oVhS:“ðl˜p°`Á¦ sÅ{ÏØ×XXŸŒðŒðs Ï¨ê©~ÃŒñýιՌðt ¨±¡¡¡³áv« …B'• @QcmmmçQ…Ɔ!ë•E­Ap)UhÈ.ô½T!ëã ±_øszf6 "+¨|Ã)ˆÈ"U-Ìák‰ªÓ63;•ðlXéR©´–2 ¨ï=c^ ÃÃ3(jx¸ ‹*4ô„Áú%@Q ýýýYU}•hèäš\.·šJ ¨²•+W^$"é*.²@U«â™«µ°ÖÖVÓ ¨X㙑‡Dä/Däx¹‹’VÅ=KDä=Þû;Ìì—±6H>e+Qø<Ðä¸h–i"òŒ™=ì½ß¶k×®{î¹¥q?§­’U«VåÊ;§‡DDFGG_ŸJ¥.RÕu"r¶ª.˜Åz{‡™¥çòr&  ­ü6¿ãf°ñ šÙ÷œs?²pá—6zRÙªœd ÿo¹]Dnïëëk9á„ÎÃðföNU=íh SÕ%"r¦ˆì ´(ª±’°kŠÀ,ŠÈSf¶-Š¢í---?žé2½÷ç8‚Skc"òXùÏu¹\nu:¾0‚wšÙ;TuÙ$릋M¶ $¬$çÆï/zïèÒW^ye™snm7Ï&<ËËv›ÙÊ?EÑ_Oœ‡——6³½åĈó¸þÍ9wɸ¿o‘î˜O· "Ǩê¾Üÿ:3ûGU=~ë_¼þÙ€é@Ãt]èÖááágžå0)¨ê}1Ó3—ÿ‡={ö\efqÏò?4“ð<ܪj§ˆ|qš Ý'({¡&î@'ýŠd3TÕk+y‹¢™½UDvWøx†UõtU}~’Ÿgf?®´»¢èÝa~w¶¿W,ÿ8 ï‹È&Û©j((è@t¹\î”Jßß­ªO›ÙžJ'xïß7Yx–—ûbE—TrRÉÌúŸx≊Np¥R©ˆÈiSt£t (ðj×)¯~0ÆûÚÛÛc]š£ª›*ø›Ã0|xš0Ûif×U°ìÍã?¿‚ßQÕOFQ´VDÆeŸ'@€¢‰ T£ëœ(ŸÏß3ËNqÛŽ;n˜É ƒ ø‚÷þ_fóxÆÆÆî®ÆóšØ–¿g MŒc q ˜ìc [Ddk->ŽÍ{ÿ˜ªž7ƒ›¾("¤ªf|Üap°}ùòå;EäM3xŽ?sÎZíçW>6úAUýp‚×?0(*µaÆÔê³,UõžlÀÃ"rélÂSDdÅŠC"r©ˆ˜ÁãØ\‹ç—J¥~äð(hëïïÏvtt ¨jfªÛDQÔ†á½1:¨óÌl»ªSü<96›ÍîeÐÒ"1V­Z•3³­Gñ¿'<Ë;¯ÇUõoŽòóí„'P$óÅåܦ):Ÿ'vîÜy]5îcÆ ·xï§új’M¬0Â3Â'yL|A~ÿ;í_ÌçógU³3,ŸTzJDNw¿ûUuµªr©#<(’É{÷¸ ¶X,ß_í±º|Ré"wRIUï#„ßižþrN@ú[q‹Ñì÷Š-á%|wWXœcccð÷žOxgdd¤ž¿·ˆå0F«_ZÇqn@Ø)¯xÜÿerc£8EðûJƒ°òõ¦¨ù¿ávÀõD Kÿ‘*„0Oéôà·?@<3"êFñáû'‚Ââ·CQpÀÿ=Hï¿nœ_–~3$àÁL[ATöpˆ€äçíÞ¢á»u-f}”+ðԵvõá8` §åwŸ>Wh+ˆ0_3Þ¬Œf­•ÿ®„;k6lÎÏÓÚQ|ZešÔXg€¶‚3h" ñ#\½ÃÃËð÷Ópðç;ç× µ«¶Ï´üô—!ÔXWüú‚‡Z€0£D$<2ÀhÝÐÚQ|ê(VÒ/^¼ÅPDW[A˜Ñû Ã4í­6çgÐÚÕ§õX, d—j¬ÇT!u­à>Ó0ÍúCšÄþýº‘¬I”-)¾Ø“±v%)µNSߟÁ¿?…»ß4L³þdiþüù/áó³âêŽà77^[Q|m¹¡_ðŒªŸôÝd^–¬"Ö‘qË1Þ,½wEM\ø%±'1jºQü«À} óôòÒ¥K?A§è \?íM–™ ÙòO;nÖõÐ<‡þämmmïÏ›7ï+QÄ@¿uñMoo\¦8dĈïe÷É/0|·Ñ¤Ÿ3?»ü„!7#Xü ey®ê-Óùóç[²¯hå&‘9»)(ü=)&ÆÝ=üX΄e’Ý=\n6¸ÜÍ®'CØ [©¤&‘ÑžÚ p+Èœñ‚<üÿc$ùeµ…Š‘1”KVFNÁ­AÙæF± ~aè7oÚÅ×ð"¦ë2¡“ïD×‚Ûæ"¨p4À›€;¨ Ò¼M _ÿTš·«ÙR->É%útoh‡¨-°¯Ê«-_Þü¨¦þ¡¢¶üA|¹`¦^|˜¯’g"Žk«`ÍùÉË «^|nßOuÇY“åF•VSžå%âüV.̈† ×>­g” ña™m?2­¾­A|¸Q_Õ“<äB|2rƒ9yÛ¤@÷357SSÖ'™e lË–-åeË–•°6Y†°Ä•äsÁ‚%ܹòpuK˜f™ý®„Eòïà“ åw—¬ðÀí„—*œfxÎþ ž²‰UÖwØAßÐ9sæLuppÐA½LÛ¾q­‹ÿ ùÛez  NÞÅÍß wÁ&'ëfwš<\Í“›lÖrpky-â#¶…'Y².¾®®®ó0+a_øl !ضhÑ¢#Y€°nvk…„Ñ'iÉc²¨È8ifenkyµÞòÕÆ£ƒ¿¢ù#™d€}fæ6sñÑü&#¢¸±dinkyÎÌìÒüÆ•Móá²6·™·|4¿Í‹(N Ì­ñÑüÆ‘Pü0Ì­³Kó_HQCj1·jZ>šß¨Šç_“¹U'>šßx¢2 ¥ÉܪŸ{ŠûCXüþµ<‹j ”þÌ `ùl&öŸ‘W5˜‡jQŸîÞòš©]rlXÐÐü-Yà}TN:Ó÷³”—õy>Üy«°uj#–Ö6¢àŸË²ðEO[ú`ðwˆñX¿Ù~âÍŠøPÈ%(àP¸‡eëNÑ+]iùÿ‡:ÚƒFaêè-yLM|rÎq¥R¹Â{…ù SÈÓ£lTbÒiÈš;Ünñ¨»’Ž?õǪU«äz?Dæ ðÒª¾tâE}îGØç—껂SkùjXpÉ[}žq M‡cM”êëm.ù`©T’ÉR»RßRÑmÃÈj= $'HñRN@'Nœ¸;má †Ô[¾kÜI7cÇì¾V;¾L¹–Œ³‡Æau³îÆšô˜zËWËßâÅ‹?½CFTMæ™Á&áÀ:É‘jÖ„gµå«çÅ~`Âêi":[ý;¿,Zkùêg?° µ$ÔfÿÎ/ÛÖú|~‰³˜ ’"D•EÿNMËÇ~`¥$ì5«þ:ñÕ2„™ô©„3º ÙÍA%%Å›]¼7ãyRžó~IK+<>0__Û1½²C^X"ÖG»²…þ%¶ð¼KÓ)c5!€îÎ#Xƒ-a&[Û¬šÝsçÎ]ßÑÑñˆî»&pèLjï¬lÁ>Ë×ì¤x%k-Ÿ¼' Â{‡Â³Y½fi¡N®C+¸_,’X&³PÍû²ÒòáÎ’—ôí”C ›Ï2cH™ÀÞÓ§Oo^±b…“r:é¶|Ò™•‡V ¼¿RxiWebñ÷uwwA}!±D”ZË'¯Û,—Ë/Ctw¦]ÆŸ<ˆ¯Š~à&ô÷&{Ê}>ôïFÑêýɼ€‚|šVoòP_2Ö_­Vßø'©µ|õ™AaÚ!Ä 2´Ç÷ßâ®æ8U•nYvƒû3¶ÎïÆAáÿN7µ+±[_}Ap7ÝØÞÞ¾Ù}°(õ~… ˆ9Nc¦uŸ<±644t`íÚµV—9­‹ÏÓ"V𿼖¾­agŽ+1WYwÍê‹è—ïéìì<“Uæ3_­Ð###ååË—ËSn›áD¼&…Y +‚ ñÕ2 @߀B+hú*÷°òñw—ÌëÓXÒ|R5âs[¿Η4j•¼¸;YäE/Gµ”ÉÚRJXqDÚÓ^¥ø¿»;Y^”“$âÇ’lH-Ím²•ÌïS0¿öRlœRæâ£¹µ+Mæ7s³KskW|šÌo¦-Í­]áÕ§¦Áüf&>šÛì„')k0¿™™]šÛlŧÁüfÒòÑÜf+<-æ×ºøhnõ/kókÝìÒÜê_–æ×zË'[ëW¯^]ºpáB[yÄ• Œ³%ìù+£jʘ-a46û7œ<÷Q†Ÿu|Æ7X¸r'Ünø’ç/ªò ¾¸Îþ ®öëUáÇ_Ù©ì`{›süøñjOOÏ%Û·…uñÅ- @Ɇƒ»ã†/H¸ ”óZp’Oõ—u³‡îÔ6½#NØ‚…iC+÷í¼”9âÐû”¯R0PLë½ÞTxÉ…øt Z9ȬD%ÙœÍb.Ä—' YW<º'«q:Ä­YçÃ$}õâÔ¤0ôs…fra)Ô‹// 5 _¦¥4å§Q^Ô‹óTœ^‰¨$ˆOÞy§~€¦Z|.7S5’¦wÞš4H"nÕâ€r|—iAÝþwMýçÅÊuî-8y?®é¥~ÊEµø°ª8m •!•¿Á²Ñ[·ní†XoZ;yñ‡2½ƒîÇ7ñ¹ y~åÝŽÏ‚ò.27Ê+.@~ç\øî&wÊ)pK¼qã;9¡Õ®]~ åÀMy]= û:œ¬Ùι䤰¸ì NÀ Iˆí>Âõ ì0(®([M|ƒånGë¿b|Ì>øûÇaáø»¼èÀÜ066Ö˜ßßjÊCyBÅçe$üpâ¿êAGnvµ˜ %ýÄTÏ•3ÍK‚þžBo ÁøTD¥zÀ“P.¶Å,[KkEñŸ‚ŠVrR!ÄçK¶jUèNÈHÇ"¤9Áon¼¶œø0(1jù¤òaÊzåèðO¶j éî]¸páa¼J¾×þ¤­´™NÊP¹]A=c8PÿÚ'9<ße "S>p¯D ãú•>éÕ ßÝŽxކÄÓ—26FŸTbg£Št+ùv¿tæ·¦Bãêãoym€éuÒ/m÷•ÒË´’ßEñ%!qxkϯµóæCæM„>Û£µð³î¬IXiqƒÊÐ Îi-m0d1  /ÖÄÔÚy£G“VL–¶æ\·éLpeX‘´‚_8-¿C£&­ˆúCú‹‡ñ{{³ýDˆø"Í=zZÁЕ-ì ŸTœ¬uúöí‚à8ŽsC@ 6*¯qh^^˜2Ùµbj­ V+¾5,ýçD»ß¯Ïˆïî +Ž,Âß{>á9&$,</8GvË̹0PxÜ .·y ² Ç4<ý˜„Óó9^SŸ¼ >*ÙáÑ/ Q!Õ?÷¼+žcaldzn¾s{aáù{A @41c€qS\2AÂæöâÆÏp-L ‰½p_W3na¼, €!ÿ©õÌì£ÝlIEND®B`‚IconicTileMediumLarge.png000066400000000000000000000115111252242224000340770ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Assets/Tiles‰PNG  IHDR†Ê`ã8† pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFtIDATxÚìëqâJF{(ÀfÀf "0Ž`µ,ŽàÚ,ŽßŒ#G`ÈÀdÌýAëše%¡‘4 Ω¢\åG{Ôó©#d¬µpÊ„ @€0a„„ @€0a„„ @€0a´ kí§µvØ ½¡µöÏv[S{ iÐf¢6§x¸»ÂXÚ/^°÷rdo‰‡»)Š‘ý›i {Ó {#<Ý=a<Øl¢ ¶¢[xº{ÂHr&Ó©M‹Í[ ž¾à™Þ€¼3<åÝÁÖû[Q޹°z¶G5lÌíyæ—²sFÀ‰å)¼¥…‘2«hcgË1u,6³ØUãìØ3ï& çèa­myvY¶õLÞ9؉«D „QONÑãdí¢ £gŠÍ<–U¢¨·öP:zè¤VaYCX)C×(ÁšHyaLJNÂÌqí¢”Í¢3º®Qâ„ ¨/ŒÌèQâ¬ôIR!J´V]¾ì‰H’F ÅÑ5Ç“¦SråñÔâ&€@óÛZûCD¶-˼E'Ñ£ “âÏÖ¥’>Wæ#„0ú%ŒtM@ÛFúrÿ]\¤¾^6½HÖt±Ò<k!¶‘µˆ¼‰ÈÚ³g:k a("ù¡_G'¾o­0>N °‘ˆLõ#ÖÚµþÎʳaªËEõé­Š¡È÷­ŽE—¡'úùm­Ýëï§B!š|E…T±ˆ |߯Ã}V,¤6G­g©sü[cÌ÷¶w%뎯E\‹:Ç¿jz0>„ñFB¸8Mô‘J†"²c®.Ê·¦k´Æ#†pÍ\] /˾V>I'—˯} ƒˆqÁˆáèñ5Z½{zȼy¥ñ6ÕwÄðÒBÁå"³Oa|0oÝkS/‘Jh[;ئz:à sçÏëK7ŽQ Ê)(ó¾OñéaÎ6мrïrEÛˆ`*"/ø?hî1 çC0Áav4Ƙ»Jŧޞ—‚c/"cc̶Rñ©ø„ƒã©H¥ÛURJRˆ«0H)=I!¥R )¥)Ä)bRú“Bª ƒ”x qJ%¤”þ¤Jƒ”~ ©+ RJ )¤R*!¥„ŸBjE RJ¸)¤VÄPQDÒŽÇA6Û:ÝvmW‡rعþKú½°KlDäUD.7ö”]U 1~î4+y5Ƭ* CÃÐ/táu+ Éæ¬0´ Eäé÷ó°zU‹ˆÈ¿rxFÉöaèm|?H¤y3Æ,L@ÀQd "cá6ø³‹Œ1{cÌX‹è7 cÌØ³ÿËs/"÷Z±Bÿº”{Õ@v»ªmê’º£W]ÉÏÓ¶5sCW8—ÂuÐY«(þÊ™×J´î¸‘g|,ÏÆ˜»¼eò³KâºÆ1V?C«'VE¿TöZI$‡}¬~í|+z_fssé««Zw¼«£]e¥¢(Õu–¾C뎟Â[]äÉóÓå²ûŸA©„¶'©Ä¥ødÑ«ûl%c1«R*ÑvõQÁHDÞuN«G kí\Dðg<c„A=ÑÖ’³$ÎE4Ȭ;õD‚(¨;Ì‘(^Dßv½e‘Þ“a´žx®ƒÀˆÜq30dÖ}ߎð øZýž·áˆ½©ýJ¯’µá( ¶(Í^\¶(ˆ$"1>í|ª¨·©9G CùÚÛJªéNªH÷¦îËþQå'êh=2'Š´::Gn­M„µ_lôÁ½^0E1‘óç•o.we¹àó‰:1óæo>ö)Œ[æÍ;Þ|ì3•ìhu½³Õ c݈Ý 4˨Λ¯‘JhQ/ǤKÂøÁ|] /¾n¼Æ M £mõ1H#¤ жúH%UIJѯQO'·Îñ7Þ¶ÅÈA{9lÅ¿×9‘·Ÿõoêƒoê“…”?ÝH}ß7 \|æçk9\\UÙÕ´ˆ\¤'®SÄrþJu, ¾‘ªiaœæº­ŠáMDÖ¾.ø.”Mšf´ã›h79‰Î·mF,‡í÷iTØ2µG“•~Ò扊"nòÝ4« ëÌØfy˜ywa$.÷5Zkc‡ ÝeÙÖ3|ç`'v_fô`æÝ„1«h£ì¤N lLËŠ«âgÃ]I»Ÿ­µó:¿”2у™?﬇lDg&óÝÁÖû[QŽÊ;;)Sl–°STŒò\².Fž¦Îð‚Ä™Țȴ†½)káˆãxMã¥{/®kÐNaL›®Žj—)î¶8œŠÍ²Åhè~3´ÐÅ„ @€0a„„ @€0a„„ @€0a@×øoÌÇöúhWIEND®B`‚belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Assets/Tiles/IconicTileSmall.png000066400000000000000000000072141252242224000330400ustar00rootroot00000000000000‰PNG  IHDRGnuá pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF·IDATxÚìÝuâ0…ïøP€K ˜ „t*XSAB¦Ø’ pq¸ƒÙkŒ­Ÿ]C,4÷œ<tléËŒf4²bfˆš #pŽÀ8Gà#8Gà#pŽÀÝF̼`æÔ²mÊÌ‹à|óQSC»©j÷ ˜„ÿêÀ̉¦Ý¡Ò6ñ}à©E›Œ/µgæ¸Ö&VŸW•uqÿŸ„sl¢isàke€Ì̃5î¹ÏûLµÁ¤ ßϸ]‹ÊdݦYË„}–/p®¬ˆ™·¬Wjø~Ûd-½‡£æ Ý ‡Ü†ˆqáL ƒ:tÇt‰rܳëtG%n[5©=K1†ªß[—„ràpÀTý€™ ;_D´ë!)€±êoõ¹»ÅÍf_ßs?dêÇÌvÌäbšaóDDE§sŽº`î9˜ÜÌ¿D«OÏá8õßΗçpœúO®Wg"$"§ñLKICH÷±¶’7dÏ9•Öõ[©Ö­˜yï©etÉF¦ yŽ057F+"ʬ³Rã¶‹V¹×•;Ùä9óPÝÉ'÷jt'«$P-6÷÷,0ÝQ%€‘n­iÊ[µ ÔjbçžÖrÔ.Á›*ÅO%Ž…°õÉÕHí½á²Zº ëHY‰€¹Ô@LÊ¥¦²@ݩɽæD´£ZdÚº®ªV^O,ªä5€g›@Ál /// Provides access to string resources. /// public class LocalizedStrings { private static AppResources _localizedResources = new AppResources(); public AppResources LocalizedResources { get { return _localizedResources; } } } }belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/MainPage.xaml000066400000000000000000000074611252242224000273450ustar00rootroot00000000000000 belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/MainPage.xaml.cs000066400000000000000000000054061252242224000277460ustar00rootroot00000000000000using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using belle_sip_tester_wp8.Resources; namespace belle_sip_tester_wp8 { public partial class MainPage : PhoneApplicationPage { // Constructor public MainPage() { InitializeComponent(); var tester = (Application.Current as App).tester; List source = new List(); source.Add(new UnitTestSuiteName("ALL")); for (int i = 0; i < tester.nbTestSuites(); i++) { source.Add(new UnitTestSuiteName(tester.testSuiteName(i))); } Tests.ItemsSource = source; // Sample code to localize the ApplicationBar //BuildLocalizedApplicationBar(); } private void Tests_Tap(object sender, System.Windows.Input.GestureEventArgs e) { UnitTestSuiteName test = (sender as LongListSelector).SelectedItem as UnitTestSuiteName; if (test == null) return; if (test.Name == "ALL") { NavigationService.Navigate(new Uri("/TestResultPage.xaml?SuiteName=" + test.Name + "&Verbose=" + Verbose.IsChecked.GetValueOrDefault(), UriKind.Relative)); } else { NavigationService.Navigate(new Uri("/TestCasePage.xaml?SuiteName=" + test.Name + "&Verbose=" + Verbose.IsChecked.GetValueOrDefault(), UriKind.Relative)); } } // Sample code for building a localized ApplicationBar //private void BuildLocalizedApplicationBar() //{ // // Set the page's ApplicationBar to a new instance of ApplicationBar. // ApplicationBar = new ApplicationBar(); // // Create a new button and set the text value to the localized string from AppResources. // ApplicationBarIconButton appBarButton = new ApplicationBarIconButton(new Uri("/Assets/AppBar/appbar.add.rest.png", UriKind.Relative)); // appBarButton.Text = AppResources.AppBarButtonText; // ApplicationBar.Buttons.Add(appBarButton); // // Create a new menu item with the localized string from AppResources. // ApplicationBarMenuItem appBarMenuItem = new ApplicationBarMenuItem(AppResources.AppBarMenuItemText); // ApplicationBar.MenuItems.Add(appBarMenuItem); //} } public class UnitTestSuiteName { public string Name { get; set; } public UnitTestSuiteName(string name) { this.Name = name; } } }belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Properties/000077500000000000000000000000001252242224000271255ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Properties/AppManifest.xml000066400000000000000000000003111252242224000320510ustar00rootroot00000000000000 belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Properties/AssemblyInfo.cs000066400000000000000000000027721252242224000320570ustar00rootroot00000000000000using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Resources; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("BelleSip Tester")] [assembly: AssemblyDescription("BelleSip tester for Windows Phone 8")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Belledonne Communications")] [assembly: AssemblyProduct("BelleSip Tester")] [assembly: AssemblyCopyright("Copyright © Belledonne Communications 2013")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("9455c69c-2077-4be0-b75c-13dc43bafef6")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: NeutralResourcesLanguageAttribute("en-US")] belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Properties/WMAppManifest.xml000066400000000000000000000036611252242224000323300ustar00rootroot00000000000000 Assets\ApplicationIcon.png Assets\Tiles\FlipCycleTileSmall.png 0 Assets\Tiles\FlipCycleTileMedium.png belle_sip_tester_wp8 belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Resources/000077500000000000000000000000001252242224000267435ustar00rootroot00000000000000AppResources.Designer.cs000066400000000000000000000104461252242224000333720ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Resources//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.17626 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace belle_sip_tester_wp8.Resources { using System; /// /// A strongly-typed resource class, for looking up localized strings, etc. /// // This class was auto-generated by the StronglyTypedResourceBuilder // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class AppResources { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal AppResources() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("belle_sip_tester_wp8.Resources.AppResources", typeof(AppResources).Assembly); resourceMan = temp; } return resourceMan; } } /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// Looks up a localized string similar to LeftToRight. /// public static string ResourceFlowDirection { get { return ResourceManager.GetString("ResourceFlowDirection", resourceCulture); } } /// /// Looks up a localized string similar to us-EN. /// public static string ResourceLanguage { get { return ResourceManager.GetString("ResourceLanguage", resourceCulture); } } /// /// Looks up a localized string similar to MY APPLICATION. /// public static string ApplicationTitle { get { return ResourceManager.GetString("ApplicationTitle", resourceCulture); } } /// /// Looks up a localized string similar to button. /// public static string AppBarButtonText { get { return ResourceManager.GetString("AppBarButtonText", resourceCulture); } } /// /// Looks up a localized string similar to menu item. /// public static string AppBarMenuItemText { get { return ResourceManager.GetString("AppBarMenuItemText", resourceCulture); } } } } belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/Resources/AppResources.resx000066400000000000000000000144551252242224000322720ustar00rootroot00000000000000 text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 LeftToRight Controls the FlowDirection for all elements in the RootFrame. Set to the traditional direction of this resource file's language en-US Controls the Language and ensures that the font for all elements in the RootFrame aligns with the app's language. Set to the language code of this resource file's language. MY APPLICATION add Menu Item belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/TestCasePage.xaml000066400000000000000000000040661252242224000301720ustar00rootroot00000000000000 belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/TestCasePage.xaml.cs000066400000000000000000000036671252242224000306040ustar00rootroot00000000000000using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; namespace belle_sip_tester_wp8 { public partial class TestCasePage : PhoneApplicationPage { public TestCasePage() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); suiteName = NavigationContext.QueryString["SuiteName"]; verbose = Convert.ToBoolean(NavigationContext.QueryString["Verbose"]); var tester = (Application.Current as App).tester; List source = new List(); source.Add(new UnitTestCaseName("ALL")); for (int i = 0; i < tester.nbTests(suiteName); i++) { source.Add(new UnitTestCaseName(tester.testName(suiteName, i))); } Tests.ItemsSource = source; } private void Tests_Tap(object sender, System.Windows.Input.GestureEventArgs e) { UnitTestCaseName test = (sender as LongListSelector).SelectedItem as UnitTestCaseName; if (test == null) return; test.Name = test.Name.Replace("+", "%2B").Replace(" ", "%20"); if (!(Application.Current as App).suiteRunning()) { NavigationService.Navigate(new Uri("/TestResultPage.xaml?SuiteName=" + suiteName + "&CaseName=" + test.Name + "&Verbose=" + verbose, UriKind.Relative)); } } private string suiteName; private bool verbose; } public class UnitTestCaseName { public string Name { get; set; } public UnitTestCaseName(string name) { this.Name = name; } } }belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/TestResultPage.xaml000066400000000000000000000036661252242224000306020ustar00rootroot00000000000000 belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/TestResultPage.xaml.cs000066400000000000000000000057231252242224000312020ustar00rootroot00000000000000using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using belle_sip_tester_native; using belle_sip_tester_wp8; namespace belle_sip_tester_wp8 { public delegate void OutputDisplayDelegate(String msg); public partial class TestResultPage : PhoneApplicationPage { public TestResultPage() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); string suiteName = NavigationContext.QueryString["SuiteName"]; string caseName; if (NavigationContext.QueryString.ContainsKey("CaseName")) { caseName = NavigationContext.QueryString["CaseName"]; } else { caseName = "ALL"; } bool verbose = Convert.ToBoolean(NavigationContext.QueryString["Verbose"]); var app = (Application.Current as App); app.suite = new UnitTestSuite(suiteName, caseName, verbose, new OutputDisplayDelegate(OutputDisplay)); app.suite.run(); } public void OutputDisplay(String msg) { this.Dispatcher.BeginInvoke(() => { TestResults.Text += msg; }); } } public class UnitTestSuite : OutputTraceListener { public UnitTestSuite(string SuiteName, string CaseName, bool Verbose, OutputDisplayDelegate OutputDisplay) { this.SuiteName = SuiteName; this.CaseName = CaseName; this.Verbose = Verbose; this.Running = false; this.OutputDisplay = OutputDisplay; } async public void run() { Running = true; var tup = new Tuple(SuiteName, CaseName, Verbose); var t = Task.Factory.StartNew((object parameters) => { var tester = (Application.Current as App).tester; tester.setOutputTraceListener(this); var p = parameters as Tuple; tester.run(p.Item1, p.Item2, p.Item3); }, tup); await t; Running = false; } public void outputTrace(String msg) { if (OutputDisplay != null) { OutputDisplay(msg); } System.Diagnostics.Debug.WriteLine(msg); } public bool running { get { return Running; } protected set { Running = value; } } private string SuiteName; private string CaseName; private bool Verbose; private bool Running; private OutputDisplayDelegate OutputDisplay; } }belle-sip-1.4.1/build/wp8/belle-sip-tester-wp8/belle-sip-tester-wp8/belle-sip-tester-wp8.csproj000066400000000000000000000175241252242224000321200ustar00rootroot00000000000000 Debug AnyCPU 10.0.20506 2.0 {2CEBCF29-6B23-46C2-B579-588321228F3E} {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} Library Properties belle_sip_tester_wp8 belle_sip_tester_wp8 WindowsPhone v8.0 $(TargetFrameworkVersion) true true true belle_sip_tester_wp8_$(Configuration)_$(Platform).xap Properties\AppManifest.xml belle_sip_tester_wp8.App true 11.0 true true full false Bin\Debug\ DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE true true prompt 4 pdbonly true Bin\Release\ TRACE;SILVERLIGHT;WINDOWS_PHONE true true prompt 4 true full false Bin\x86\Debug\ DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE true true prompt 4 pdbonly true Bin\x86\Release\ TRACE;SILVERLIGHT;WINDOWS_PHONE true true prompt 4 true full false Bin\ARM\Debug\ DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE true true prompt 4 pdbonly true Bin\ARM\Release\ TRACE;SILVERLIGHT;WINDOWS_PHONE true true prompt 4 App.xaml MainPage.xaml True True AppResources.resx TestCasePage.xaml TestResultPage.xaml Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile Designer MSBuild:Compile PreserveNewest Designer PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PreserveNewest PublicResXFileCodeGenerator AppResources.Designer.cs {3B4E9C2C-D5DC-4CF9-A7F4-5CB4AB55AF79} belle-sip-tester-native belle-sip-1.4.1/build/wp8/belle-sip/000077500000000000000000000000001252242224000170555ustar00rootroot00000000000000belle-sip-1.4.1/build/wp8/belle-sip/belle-sip.props000066400000000000000000000007761252242224000220300ustar00rootroot00000000000000 "1.3.2" $(BELLESIP_PACKAGE_VERSION) belle-sip-1.4.1/build/wp8/belle-sip/belle-sip.sln000066400000000000000000000071041252242224000214510ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Express 2012 for Windows Phone Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "belle-sip", "belle-sip.vcxproj", "{4C225A82-800B-427B-BA7B-61686A9B347F}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libantlr3c", "..\..\..\..\antlr3\runtime\C\build\wp8\libantlr3c\libantlr3c.vcxproj", "{8FA74260-151B-429B-83EF-3CF3EAC8CFD9}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tunnel", "..\..\..\..\tunnel\build\wp8\tunnel\tunnel.vcxproj", "{59500DD1-B192-4DDF-A402-8A8E3739E032}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "polarssl", "..\..\..\..\polarssl\build\wp8\polarssl\polarssl.vcxproj", "{E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM Debug|Win32 = Debug|Win32 Release|ARM = Release|ARM Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.ActiveCfg = Debug|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|ARM.Build.0 = Debug|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.ActiveCfg = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Debug|Win32.Build.0 = Debug|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.ActiveCfg = Release|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|ARM.Build.0 = Release|ARM {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.ActiveCfg = Release|Win32 {4C225A82-800B-427B-BA7B-61686A9B347F}.Release|Win32.Build.0 = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.ActiveCfg = Debug|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|ARM.Build.0 = Debug|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.ActiveCfg = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Debug|Win32.Build.0 = Debug|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.ActiveCfg = Release|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|ARM.Build.0 = Release|ARM {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.ActiveCfg = Release|Win32 {8FA74260-151B-429B-83EF-3CF3EAC8CFD9}.Release|Win32.Build.0 = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.ActiveCfg = Debug|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|ARM.Build.0 = Debug|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.ActiveCfg = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Debug|Win32.Build.0 = Debug|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.ActiveCfg = Release|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|ARM.Build.0 = Release|ARM {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.ActiveCfg = Release|Win32 {59500DD1-B192-4DDF-A402-8A8E3739E032}.Release|Win32.Build.0 = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.ActiveCfg = Debug|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|ARM.Build.0 = Debug|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.ActiveCfg = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Debug|Win32.Build.0 = Debug|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.ActiveCfg = Release|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|ARM.Build.0 = Release|ARM {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.ActiveCfg = Release|Win32 {E9F8C5D1-13A2-46B6-A9BC-878030D4BE09}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal belle-sip-1.4.1/build/wp8/belle-sip/belle-sip.vcxproj000066400000000000000000000304731252242224000223550ustar00rootroot00000000000000 Debug Win32 Debug ARM Release Win32 Release ARM {4C225A82-800B-427B-BA7B-61686A9B347F} belle_sip en-US 11.0 DynamicLibrary true v110_wp80 false DynamicLibrary false true v110_wp80 false $(SolutionDir)$(Platform)\$(Configuration)\ $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ false Level4 WIN32;_WINDOWS;_USRDLL;BELLESIP_EXPORTS;BELLESIP_INTERNAL_EXPORTS;HAVE_POLARSSL;HAVE_TUNNEL;HAVE_ANTLR_STRING_STREAM_NEW;HAVE_COMPILER_TLS;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;USE_FIXED_NAMESERVERS;USE_GETADDRINFO_FALLBACK;ENABLE_SERVER_SOCKETS;HAVE_CONFIG_H;%(PreprocessorDefinitions) $(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\antlr3\runtime\C\include;$(ProjectDir)..\..\..\src;$(ProjectDir)..\..\..\..\polarssl\include;$(ProjectDir)..\..\..\..\tunnel\include;$(ProjectDir);%(AdditionalIncludeDirectories) Default NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) Console false false ws2_32.lib;libantlr3c.lib;polarssl.lib;tunnel.lib;%(AdditionalDependencies) $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) $(TargetDir)$(TargetName).lib java -jar $(ProjectDir)..\..\..\..\antlr3\antlr-3.4-complete.jar -make -fo $(ProjectDir)..\..\..\src\grammars\ %(FullPath) version.bat Sets the package version _DEBUG;%(PreprocessorDefinitions) true NDEBUG;%(PreprocessorDefinitions) MaxSpeed true true true false Document $(ProjectDir)..\..\..\src\grammars\belle_sdpLexer.c;$(ProjectDir)..\..\..\src\grammars\belle_sdpLexer.h;$(ProjectDir)..\..\..\src\grammars\belle_sdpParser.c;$(ProjectDir)..\..\..\src\grammars\belle_sdpParser.h Document $(ProjectDir)..\..\..\src\grammars\belle_sip_messageLexer.c;$(ProjectDir)..\..\..\src\grammars\belle_sip_messageLexer.h;$(ProjectDir)..\..\..\src\grammars\belle_sip_messageParser.c;$(ProjectDir)..\..\..\src\grammars\belle_sip_messageParser.h true true false {8fa74260-151b-429b-83ef-3cf3eac8cfd9} {e9f8c5d1-13a2-46b6-a9bc-878030d4be09} {59500dd1-b192-4ddf-a402-8a8e3739e032} belle-sip-1.4.1/build/wp8/belle-sip/belle-sip_no_tunnel.vcxproj000066400000000000000000000275311252242224000244370ustar00rootroot00000000000000 Debug Win32 Debug ARM Release Win32 Release ARM {4C225A82-800B-427B-BA7B-61686A9B347F} belle_sip en-US 11.0 DynamicLibrary true v110_wp80 false DynamicLibrary false true v110_wp80 false $(SolutionDir)$(Platform)\$(Configuration)\ $(SolutionDir)$(Platform)\$(Configuration)\$(TargetName)\ false Level4 WIN32;_WINDOWS;_USRDLL;BELLESIP_EXPORTS;BELLESIP_INTERNAL_EXPORTS;HAVE_POLARSSL;HAVE_ANTLR_STRING_STREAM_NEW;HAVE_COMPILER_TLS;_CRT_SECURE_NO_WARNINGS;_UNICODE;UNICODE;USE_FIXED_NAMESERVERS;USE_GETADDRINFO_FALLBACK;ENABLE_SERVER_SOCKETS;HAVE_CONFIG_H;%(PreprocessorDefinitions) $(ProjectDir)..\..\..\include;$(ProjectDir)..\..\..\..\antlr3\runtime\C\include;$(ProjectDir)..\..\..\src;$(ProjectDir)..\..\..\..\polarssl\include;$(ProjectDir)..\..\..\..\tunnel\include;$(ProjectDir);%(AdditionalIncludeDirectories) Default NotUsing false $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories) Console false false ws2_32.lib;libantlr3c.lib;polarssl.lib;%(AdditionalDependencies) $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) $(TargetDir)$(TargetName).lib java -jar $(ProjectDir)..\..\..\..\antlr3\antlr-3.4-complete.jar -make -fo $(ProjectDir)..\..\..\src\grammars\ %(FullPath) version.bat Sets the package version _DEBUG;%(PreprocessorDefinitions) true NDEBUG;%(PreprocessorDefinitions) MaxSpeed true true true false Document $(ProjectDir)..\..\..\src\grammars\belle_sdpLexer.c;$(ProjectDir)..\..\..\src\grammars\belle_sdpLexer.h;$(ProjectDir)..\..\..\src\grammars\belle_sdpParser.c;$(ProjectDir)..\..\..\src\grammars\belle_sdpParser.h Document $(ProjectDir)..\..\..\src\grammars\belle_sip_messageLexer.c;$(ProjectDir)..\..\..\src\grammars\belle_sip_messageLexer.h;$(ProjectDir)..\..\..\src\grammars\belle_sip_messageParser.c;$(ProjectDir)..\..\..\src\grammars\belle_sip_messageParser.h true true false {8fa74260-151b-429b-83ef-3cf3eac8cfd9} {e9f8c5d1-13a2-46b6-a9bc-878030d4be09} belle-sip-1.4.1/build/wp8/belle-sip/version.bat000066400000000000000000000003071252242224000212320ustar00rootroot00000000000000@ECHO off FOR /F "delims=" %%a IN ('findstr /B AC_INIT ..\..\..\configure.ac') DO ( FOR /F "tokens=1,2,3 delims=[,]" %%1 IN ("%%a") DO ( ECHO #define PACKAGE_VERSION "%%3" > config.h ) ) belle-sip-1.4.1/cmake/000077500000000000000000000000001252242224000144445ustar00rootroot00000000000000belle-sip-1.4.1/cmake/BelleSIPConfig.cmake.in000066400000000000000000000034651252242224000206100ustar00rootroot00000000000000############################################################################ # BelleSIPConfig.cmake # Copyright (C) 2015 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ # # Config file for the belle-sip package. # It defines the following variables: # # BELLESIP_FOUND - system has belle-sip # BELLESIP_INCLUDE_DIRS - the belle-sip include directory # BELLESIP_LIBRARIES - The libraries needed to use belle-sip # BELLESIP_LDFLAGS - The linking flags needed to use belle-sip include("${CMAKE_CURRENT_LIST_DIR}/BelleSIPTargets.cmake") if(@ENABLE_TUNNEL@) find_package(Tunnel) endif() get_filename_component(BELLESIP_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) set(BELLESIP_INCLUDE_DIRS "${BELLESIP_CMAKE_DIR}/../../../include") set(BELLESIP_LIBRARIES BelledonneCommunications::bellesip) set(BELLESIP_LDFLAGS @LINK_FLAGS@) if(TUNNEL_FOUND) list(APPEND BELLESIP_INCLUDE_DIRS ${TUNNEL_INCLUDE_DIRS}) list(APPEND BELLESIP_LIBRARIES ${TUNNEL_LIBRARIES}) endif() set(BELLESIP_FOUND 1) belle-sip-1.4.1/cmake/FindAntlr3.cmake000066400000000000000000000044661252242224000174240ustar00rootroot00000000000000############################################################################ # FindAntlr3.txt # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ # # - Find the antlr3c include file and library and antlr.jar # # ANTLR3_FOUND - system has antlr3c # ANTLR3C_INCLUDE_DIR - the antlr3c include directory # ANTLR3C_LIBRARIES - The libraries needed to use antlr3c # ANTLR3_COMMAND - The command to run the antlr jar find_package(Java COMPONENTS Runtime REQUIRED) set(_ANTLR3C_ROOT_PATHS ${CMAKE_INSTALL_PREFIX} ) set(_ANTLR3_JAR_ROOT_PATHS ${CMAKE_INSTALL_PREFIX} /usr/local /usr /opt/local ) find_path(ANTLR3C_INCLUDE_DIRS NAMES antlr3.h HINTS _ANTLR3C_ROOT_PATHS PATH_SUFFIXES include ) if(ANTLR3C_INCLUDE_DIRS) set(HAVE_ANTLR3_H 1) endif() find_library(ANTLR3C_LIBRARIES NAMES antlr3c HINTS _ANTLR3C_ROOT_PATHS PATH_SUFFIXES bin lib ) find_file(ANTLR3_COMMAND NAMES antlr3 HINTS ${_ANTLR3_JAR_ROOT_PATHS} PATH_SUFFIXES bin ) if(NOT ANTLR3_COMMAND) # antlr3 command not found, search for the jar file find_file(ANTLR3_JAR_PATH NAMES antlr3.jar antlr.jar HINTS _ANTLR3_JAR_ROOT_PATHS PATH_SUFFIXES share/java ) if(ANTLR3_JAR_PATH) set(ANTLR3_COMMAND ${Java_JAVA_EXECUTABLE} -Xmx256m -jar ${ANTLR3_JAR_PATH}) endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Antlr3 DEFAULT_MSG ANTLR3C_INCLUDE_DIRS ANTLR3C_LIBRARIES ANTLR3_COMMAND ) mark_as_advanced(ANTLR3C_INCLUDE_DIRS ANTLR3C_LIBRARIES ANTLR3_COMMAND) belle-sip-1.4.1/cmake/FindCUnit.cmake000066400000000000000000000033331252242224000172730ustar00rootroot00000000000000############################################################################ # FindCUnit.txt # Copyright (C) 2015 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ # # - Find the CUnit include file and library # # CUNIT_FOUND - system has CUnit # CUNIT_INCLUDE_DIRS - the CUnit include directory # CUNIT_LIBRARIES - The libraries needed to use CUnit include(CheckIncludeFile) include(CheckLibraryExists) set(_CUNIT_ROOT_PATHS ${CMAKE_INSTALL_PREFIX} ) find_path(CUNIT_INCLUDE_DIRS NAMES CUnit/CUnit.h HINTS _CUNIT_ROOT_PATHS PATH_SUFFIXES include ) if(CUNIT_INCLUDE_DIRS) set(HAVE_CUNIT_CUNIT_H 1) endif() find_library(CUNIT_LIBRARIES NAMES cunit HINTS ${_CUNIT_ROOT_PATHS} PATH_SUFFIXES bin lib ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(CUnit DEFAULT_MSG CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES ) mark_as_advanced(CUNIT_INCLUDE_DIRS CUNIT_LIBRARIES) belle-sip-1.4.1/cmake/FindPolarSSL.cmake000066400000000000000000000047651252242224000177220ustar00rootroot00000000000000############################################################################ # FindPolarSSL.txt # Copyright (C) 2015 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ # # - Find the polarssl include file and library # # POLARSSL_FOUND - system has polarssl # POLARSSL_INCLUDE_DIRS - the polarssl include directory # POLARSSL_LIBRARIES - The libraries needed to use polarssl include(CMakePushCheckState) include(CheckIncludeFile) include(CheckCSourceCompiles) include(CheckSymbolExists) set(_POLARSSL_ROOT_PATHS ${CMAKE_INSTALL_PREFIX} ) find_path(POLARSSL_INCLUDE_DIRS NAMES polarssl/ssl.h HINTS _POLARSSL_ROOT_PATHS PATH_SUFFIXES include ) if(POLARSSL_INCLUDE_DIRS) set(HAVE_POLARSSL_SSL_H 1) endif() find_library(POLARSSL_LIBRARIES NAMES polarssl HINTS _POLARSSL_ROOT_PATHS PATH_SUFFIXES bin lib ) if(POLARSSL_LIBRARIES) cmake_push_check_state(RESET) set(CMAKE_REQUIRED_INCLUDES ${POLARSSL_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${POLARSSL_LIBRARIES}) check_c_source_compiles("#include #include #if POLARSSL_VERSION_NUMBER >= 0x01030000 #include #endif int main(int argc, char *argv[]) { x509parse_crtpath(0,0); return 0; }" X509PARSE_CRTPATH_OK) check_symbol_exists(ssl_get_dtls_srtp_protection_profile "polarssl/ssl.h" HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) cmake_pop_check_state() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(PolarSSL DEFAULT_MSG POLARSSL_INCLUDE_DIRS POLARSSL_LIBRARIES HAVE_POLARSSL_SSL_H ) mark_as_advanced(POLARSSL_INCLUDE_DIRS POLARSSL_LIBRARIES HAVE_POLARSSL_SSL_H X509PARSE_CRTPATH_OK HAVE_SSL_GET_DTLS_SRTP_PROTECTION_PROFILE) belle-sip-1.4.1/config.h.cmake000066400000000000000000000033121252242224000160600ustar00rootroot00000000000000/*************************************************************************** * antlr3config.h.cmake * Copyright (C) 2014 Belledonne Communications, Grenoble France * **************************************************************************** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ****************************************************************************/ #cmakedefine PACKAGE "@PACKAGE@" #cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" #cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" #cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" #cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@" #cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" #cmakedefine PACKAGE_URL "@PACKAGE_URL@" #cmakedefine VERSION "@VERSION@" #cmakedefine HAVE_LIBDL #cmakedefine HAVE_LIBRT #cmakedefine HAVE_RESINIT #cmakedefine HAVE_ANTLR3_H #cmakedefine HAVE_ANTLR_STRING_STREAM_NEW #cmakedefine HAVE_POLARSSL_SSL_H #cmakedefine HAVE_POLARSSL #cmakedefine HAVE_CUNIT_CUNIT_H #cmakedefine HAVE_CU_CURSES #cmakedefine HAVE_CU_GET_SUITE #cmakedefine HAVE_TUNNEL #cmakedefine ENABLE_SERVER_SOCKETS belle-sip-1.4.1/configure.ac000077500000000000000000000266241252242224000156670ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) AC_INIT([belle-sip],[1.4.1],[jehan.monnier@linphone.org]) BELLESIP_SO_CURRENT=0 dnl increment this number when you add/change/remove an interface BELLESIP_SO_REVISION=0 dnl increment this number when you change source code, without changing interfaces; set to 0 when incrementing CURRENT BELLESIP_SO_AGE=0 dnl increment this number when you add an interface, set to 0 if you remove an interface BELLESIP_SO_VERSION=$BELLESIP_SO_CURRENT:$BELLESIP_SO_REVISION:$BELLESIP_SO_AGE AC_SUBST(BELLESIP_SO_CURRENT, $BELLESIP_SO_CURRENT) AC_SUBST(BELLESIP_SO_VERSION) AC_CONFIG_SRCDIR([src/belle_sip_utils.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) AC_CANONICAL_SYSTEM dnl initialize pkg-config so that we can use it within if else fi statements. PKG_PROG_PKG_CONFIG() AM_INIT_AUTOMAKE([subdir-objects]) AM_SILENT_RULES(yes) # Checks for programs. dnl do not put anythingelse before AC_PROG_CC unless checking if macro still work for clang dnl because of tunnel library wrapper, C++ is required. AC_PROG_CXX(["xcrun clang++" g++]) AC_PROG_CC(["xcrun clang" gcc]) AC_PROG_OBJC(["xcrun clang" gcc]) AM_PROG_CC_C_O case $INSTALL in *ginstall*) INSTALL="$INSTALL -C" ;; esac dnl AC_PROG_CC_C99 LT_INIT(win32-dll) case "$target" in *-apple-darwin.ios|i386-apple*|armv6-apple*|armv7-apple*|armv7s-apple*|arm64-apple*|aarch64-apple*) LIBS="$LIBS -framework Foundation -framework CoreFoundation -framework CFNetwork -framework UIKit" build_apple=yes ;; #macosx 64 bits x86_64-apple-darwin*) LIBS="$LIBS -framework Foundation" OBJCFLAGS="$OBJCFLAGS -fmodules" build_apple=yes ;; esac AM_CONDITIONAL([BUILD_APPLE], [test "x$build_apple" = "xyes"]) dnl Workaround for mingw, whose compiler does not check in /usr/include ... case "$target_os" in *mingw*) if test "$cross_compiling" != "yes"; then if test "$prefix" = "/usr" ; then CPPFLAGS="$CPPFLAGS -I/usr/include" LDFLAGS="$LDFLAGS -L/usr/lib" fi fi ;; esac if test -f /etc/debian_version ; then use_deb=true; else use_rpm=true; fi AC_ARG_ENABLE(debug, [ --enable-debug Turn on debug mode (default=no)], [case "${enableval}" in yes) debug=true ;; no) debug=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;; esac],[debug=false]) CFLAGS="$CFLAGS -fms-extensions" if test "$debug" = "no" ; then CFLAGS="$CFLAGS -g -O2" else CFLAGS="$CFLAGS -g" fi AC_ARG_ENABLE(strict, [ --enable-strict Turn on strict mode compilation, no warnings allowed (default=yes)], [case "${enableval}" in yes) strict=true ;; no) strict=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-strict) ;; esac],[strict=true]) STRICT_OPTIONS="-Wall" STRICT_OPTIONS_CC="" STRICT_OPTIONS_CXX="" case "$CC" in *clang*) STRICT_OPTIONS="$STRICT_OPTIONS -Wno-error=unknown-warning-option -Qunused-arguments -Wno-tautological-compare -Wno-builtin-requires-header -Wno-unused-function -Wno-gnu-designator " #disabled due to wrong optimization false positive with small string #(cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35903) STRICT_OPTIONS="$STRICT_OPTIONS -Wno-array-bounds " ;; gcc*) STRICT_OPTIONS="$STRICT_OPTIONS -Wno-error=pragmas" ;; esac # because Darwin's gcc is actually clang, we need to check it... case "$target_os" in *darwin*) STRICT_OPTIONS="$STRICT_OPTIONS -Wno-error=unknown-warning-option -Qunused-arguments -Wno-tautological-compare -Wno-unused-function " #disabled due to wrong optimization false positive with small string #(cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35903) STRICT_OPTIONS="$STRICT_OPTIONS -Wno-array-bounds " ;; esac if test "$strict" = "true"; then STRICT_OPTIONS="$STRICT_OPTIONS -Werror -Wno-error=unknown-pragmas -Wuninitialized" STRICT_OPTIONS_CC="$STRICT_OPTIONS_CC -Wdeclaration-after-statement" fi dnl because of antlr3 we must accept a few warnings... dnl more portable for the moment LESS_STRICT_OPTIONS= dnl LESS_STRICT_OPTIONS="$STRICT_OPTIONS -Wno-error=unused-function \ dnl -Wno-error=uninitialized -Wno-error=unused-variable \ dnl -Wno-error=unused-but-set-variable " AC_SUBST(STRICT_OPTIONS) AC_SUBST(STRICT_OPTIONS_CC) AC_SUBST(STRICT_OPTIONS_CXX) AC_SUBST(LESS_STRICT_OPTIONS) # Checks for libraries. # Checks for header files. AC_ARG_WITH( antlr, [ --with-antlr Set prefix where libantlr3c can be found (ex:/usr or /usr/local)[default=PREFIX] ], [ antlr_prefix=${withval}],[ antlr_prefix=${prefix} ]) found_antlr3=no if test "$antlr_prefix" != "NONE" && test "$antlr_prefix" != "/usr" ; then ANTLR_CFLAGS="-I${antlr_prefix}/include" ANTLR_LIBS="-L${antlr_prefix}/lib" fi ANTLR_LIBS="$ANTLR_LIBS -lantlr3c" dnl check antlr headers CPPFLAGS_save=$CPPFLAGS CPPFLAGS="$ANTLR_CFLAGS $CPPFLAGS" AC_CHECK_HEADERS([antlr3.h], [found_antlr3=yes]) AC_CHECK_DECL([antlr3StringStreamNew], [AC_DEFINE(HAVE_ANTLR_STRING_STREAM_NEW,1,[Defined when antlr 3.4 api is detected])], [foo=bar], [#include ]) libresolv_have_res_get_servers=no resolv_h_hav_res_ndestroy=no LIBS_save=$LIBS LIBS="$LIBS -lresolv" AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[res_getservers(NULL,NULL,0)]])] ,[libresolv_have_res_get_servers=yes AC_MSG_NOTICE([res_getservers usable])] ,[LIBS=$LIBS_save AC_MSG_WARN([res_getservers not usable])]) AC_CHECK_DECL([res_ndestroy], [resolv_h_hav_res_ndestroy=yes], [foo=bar], [#include ]) if test "${libresolv_have_res_get_servers}${resolv_h_hav_res_ndestroy}" == "yesyes" ; then AC_DEFINE(HAVE_RESINIT,1,[Defined when res_ninit api is available]) fi CPPFLAGS=$CPPFLAGS_save if test "$found_antlr3" != "yes" ; then AC_MSG_ERROR([Could not find antlr3 development files. Please install antlr3 version > 3.2 (libantlr3c-dev on debian/ubuntu systems)]) ANTLR_CFLAGS= ANTLR_LIBS= fi AC_PATH_PROG([ANTLR],[antlr3],[no],[$antlr_prefix/bin /usr/bin]) if test $ANTLR = "no" ; then antlr_java_prefixes="$antlr_prefix/share/java /usr/local/share/java /usr/share/java /opt/local/share/java" for antlr_java_prefix in $antlr_java_prefixes do antlr_jar=$antlr_java_prefix/antlr.jar if test -f $antlr_jar ; then break else antlr_jar=no fi antlr_jar=$antlr_java_prefix/antlr3.jar if test -f $antlr_jar ; then break else antlr_jar=no fi done if test $antlr_jar = "no" ; then AC_MSG_ERROR([Could not find antlr.jar. Please install antlr3 ]) fi AC_PATH_PROG([JAVA],[java],[no]) if test $JAVA = "no" ; then AC_MSG_ERROR([Could not find java prog. Please install java ]) else ANTLR="$JAVA -Xmx256m -jar $antlr_jar" fi fi AC_SUBST(ANTLR_CFLAGS) AC_SUBST(ANTLR_LIBS) AC_ARG_ENABLE( tls, [ --enable-tls Enable TLS support (default=yes)], [case "${enableval}" in yes) use_tls=true ;; no) use_tls=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-tls) ;; esac],[use_tls=true]) AC_ARG_WITH( polarssl, [ --with-polarssl Set prefix where polarssl can be found (ex:/usr, /usr/local)[default=PREFIX] ], [ polarssl_prefix=${withval}],[ polarssl_prefix=${prefix} ]) if test "$polarssl_prefix" != "NONE" && test "$polarssl_prefix" != "/usr"; then POLARSSL_CFLAGS="-I${polarssl_prefix}/include" POLARSSL_LIBS="-L${polarssl_prefix}/lib" fi POLARSSL_LIBS="$POLARSSL_LIBS -lpolarssl" found_polarssl=no if test "$use_tls" = "true" ; then CPPFLAGS_save=$CPPFLAGS LIBS_save=$LIBS CPPFLAGS="$CPPFLAGS $POLARSSL_CFLAGS" LIBS="$LIBS $POLARSSL_LIBS" AC_CHECK_HEADERS(polarssl/ssl.h, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #if POLARSSL_VERSION_NUMBER >= 0x01030000 #include #endif ]], [[x509parse_crtpath(0,0)]])] ,[found_polarssl=yes POLARSSL_LIBS=" -lpolarssl" AC_MSG_NOTICE([polarssl usable])] ,[AC_MSG_ERROR([polarssl not found or usable but TLS support required.])]) ]) CPPFLAGS=$CPPFLAGS_save LIBS=$LIBS_save fi AM_CONDITIONAL([BUILD_TLS], [test "x$found_polarssl" = "xyes"]) TLS_CFLAGS="" TLS_LIBS="" TLS_PC="" if test "x$found_polarssl" = "xyes" ; then AC_DEFINE(HAVE_POLARSSL,1,[Defined when polarssl api is available]) TLS_CFLAGS=$POLARSSL_CFLAGS TLS_LIBS=$POLARSSL_LIBS fi AC_SUBST(TLS_CFLAGS) AC_SUBST(TLS_LIBS) AC_SUBST(TLS_PC) AC_ARG_ENABLE(server_sockets, [AS_HELP_STRING([--disable-server-sockets], [Disable server sockets creation])], [case "${enableval}" in yes) server_sockets_enabled=true ;; no) server_sockets_enabled=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-server-sockets) ;; esac], [server_sockets_enabled=yes] ) if test "x$server_sockets_enabled" = "xyes" ; then AC_DEFINE(ENABLE_SERVER_SOCKETS,1,[Defined when server sockets are enabled]) fi AC_ARG_ENABLE(tunnel, [AS_HELP_STRING([--enable-tunnel], [Enable tunnel support (default=no)])]) if test "$enable_tunnel" = "yes" ; then PKG_CHECK_MODULES(TUNNEL, tunnel, [found_tunnel=yes], [found_tunnel=no]) if test "$found_tunnel" = "yes" ; then AC_DEFINE(HAVE_TUNNEL, 1, [Defined when tunnel is enabled and available]) fi fi AM_CONDITIONAL(BUILD_TUNNEL, test "$found_tunnel" = "yes") PKG_CHECK_MODULES(CUNIT, cunit, [found_pkg_config_cunit=yes],[found_pkg_config_cunit=no]) if test "$found_pkg_config_cunit" = "no" ; then AC_CHECK_HEADERS(CUnit/CUnit.h, [ AC_CHECK_LIB(cunit,CU_add_suite,[ found_cunit=yes CUNIT_LIBS+=" -lcunit" ]) ]) else found_cunit=yes fi case "$target_os" in *darwin*) #hack for macport CUNIT_LIBS+=" -lncurses" ;; *mingw*) LIBBELLESIP_CFLAGS="-DBELLESIP_EXPORTS" CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0501" LIBS="$LIBS -lws2_32 -liphlpapi" LDFLAGS="$LDFLAGS -Wl,--export-all-symbols" ;; esac AC_SUBST(LIBBELLESIP_CFLAGS) if test "$found_cunit" = "no" ; then AC_MSG_WARN([Could not find cunit framework, tests are not compiled.]) else AC_CHECK_LIB(cunit,CU_get_suite,[ AC_DEFINE(HAVE_CU_GET_SUITE,1,[defined when CU_get_suite is available]) ],[foo=bar],[$CUNIT_LIBS]) AC_CHECK_LIB(cunit,CU_curses_run_tests,[ AC_DEFINE(HAVE_CU_CURSES,1,[defined when CU_curses_run_tests is available]) ],[foo=bar],[$CUNIT_LIBS]) fi AC_ARG_ENABLE(tests, [AS_HELP_STRING([--disable-tests], [Disable compilation of tests])], [case "${enableval}" in yes) tests_enabled=true ;; no) tests_enabled=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --disable-tests) ;; esac], [tests_enabled=yes] ) AM_CONDITIONAL(ENABLE_TESTS, test x$tests_enabled = xyes && test x$found_cunit = xyes) REQUIRES_PRIVATE="" LIBS_PRIVATE="" if test "$found_pkg_config_cunit" = "yes" ; then REQUIRES_PRIVATE="$REQUIRES_PRIVATE cunit" else if test "$found_cunit" = "yes" ; then LIBS_PRIVATE="$LIBS_PRIVATE $CUNIT_LIBS" fi fi LIBS_PRIVATE="$LIBS_PRIVATE $ANTLR_LIBS $POLARSSL_LIBS" AC_SUBST(REQUIRES_PRIVATE) AC_SUBST(LIBS_PRIVATE) # Checks for typedefs, structures, and compiler characteristics. # Eliminate -lstdc++ addition to postdeps for cross compiles. postdeps_CXX=`echo " $postdeps_CXX " | sed 's, -lstdc++ ,,g'` # Checks for library functions. AC_CHECK_LIB(rt, clock_gettime) AC_CHECK_LIB(dl, dlopen) AC_CHECK_LIB(pthread, pthread_getspecific,, [AC_MSG_ERROR([pthread library not found])]) AC_CONFIG_FILES( [ Makefile include/Makefile include/belle-sip/Makefile src/Makefile src/grammars/Makefile tester/Makefile belle-sip.pc belle-sip.spec ]) AC_OUTPUT belle-sip-1.4.1/include/000077500000000000000000000000001252242224000150075ustar00rootroot00000000000000belle-sip-1.4.1/include/CMakeLists.txt000066400000000000000000000002571252242224000175530ustar00rootroot00000000000000file(GLOB HEADER_FILES "belle-sip/*.h") install(FILES ${HEADER_FILES} DESTINATION include/belle-sip PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) belle-sip-1.4.1/include/MSVC/000077500000000000000000000000001252242224000155575ustar00rootroot00000000000000belle-sip-1.4.1/include/MSVC/inttypes.h000066400000000000000000000175041252242224000176160ustar00rootroot00000000000000// ISO C9x compliant inttypes.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ #if _MSC_VER > 1000 #pragma once #endif #include "stdint.h" // 7.8 Format conversion of integer types typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t; // 7.8.1 Macros for format specifiers #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 // The fprintf macros for signed integers are: #define PRId8 "d" #define PRIi8 "i" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRId16 "hd" #define PRIi16 "hi" #define PRIdLEAST16 "hd" #define PRIiLEAST16 "hi" #define PRIdFAST16 "hd" #define PRIiFAST16 "hi" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIdLEAST32 "I32d" #define PRIiLEAST32 "I32i" #define PRIdFAST32 "I32d" #define PRIiFAST32 "I32i" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIdLEAST64 "I64d" #define PRIiLEAST64 "I64i" #define PRIdFAST64 "I64d" #define PRIiFAST64 "I64i" #define PRIdMAX "I64d" #define PRIiMAX "I64i" #define PRIdPTR "Id" #define PRIiPTR "Ii" // The fprintf macros for unsigned integers are: #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRIoLEAST16 "ho" #define PRIuLEAST16 "hu" #define PRIxLEAST16 "hx" #define PRIXLEAST16 "hX" #define PRIoFAST16 "ho" #define PRIuFAST16 "hu" #define PRIxFAST16 "hx" #define PRIXFAST16 "hX" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRIoLEAST32 "I32o" #define PRIuLEAST32 "I32u" #define PRIxLEAST32 "I32x" #define PRIXLEAST32 "I32X" #define PRIoFAST32 "I32o" #define PRIuFAST32 "I32u" #define PRIxFAST32 "I32x" #define PRIXFAST32 "I32X" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #define PRIoLEAST64 "I64o" #define PRIuLEAST64 "I64u" #define PRIxLEAST64 "I64x" #define PRIXLEAST64 "I64X" #define PRIoFAST64 "I64o" #define PRIuFAST64 "I64u" #define PRIxFAST64 "I64x" #define PRIXFAST64 "I64X" #define PRIoMAX "I64o" #define PRIuMAX "I64u" #define PRIxMAX "I64x" #define PRIXMAX "I64X" #define PRIoPTR "Io" #define PRIuPTR "Iu" #define PRIxPTR "Ix" #define PRIXPTR "IX" // The fscanf macros for signed integers are: #define SCNd8 "d" #define SCNi8 "i" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNd16 "hd" #define SCNi16 "hi" #define SCNdLEAST16 "hd" #define SCNiLEAST16 "hi" #define SCNdFAST16 "hd" #define SCNiFAST16 "hi" #define SCNd32 "ld" #define SCNi32 "li" #define SCNdLEAST32 "ld" #define SCNiLEAST32 "li" #define SCNdFAST32 "ld" #define SCNiFAST32 "li" #define SCNd64 "I64d" #define SCNi64 "I64i" #define SCNdLEAST64 "I64d" #define SCNiLEAST64 "I64i" #define SCNdFAST64 "I64d" #define SCNiFAST64 "I64i" #define SCNdMAX "I64d" #define SCNiMAX "I64i" #ifdef _WIN64 // [ # define SCNdPTR "I64d" # define SCNiPTR "I64i" #else // _WIN64 ][ # define SCNdPTR "ld" # define SCNiPTR "li" #endif // _WIN64 ] // The fscanf macros for unsigned integers are: #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNX8 "X" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNXLEAST8 "X" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNXFAST8 "X" #define SCNo16 "ho" #define SCNu16 "hu" #define SCNx16 "hx" #define SCNX16 "hX" #define SCNoLEAST16 "ho" #define SCNuLEAST16 "hu" #define SCNxLEAST16 "hx" #define SCNXLEAST16 "hX" #define SCNoFAST16 "ho" #define SCNuFAST16 "hu" #define SCNxFAST16 "hx" #define SCNXFAST16 "hX" #define SCNo32 "lo" #define SCNu32 "lu" #define SCNx32 "lx" #define SCNX32 "lX" #define SCNoLEAST32 "lo" #define SCNuLEAST32 "lu" #define SCNxLEAST32 "lx" #define SCNXLEAST32 "lX" #define SCNoFAST32 "lo" #define SCNuFAST32 "lu" #define SCNxFAST32 "lx" #define SCNXFAST32 "lX" #define SCNo64 "I64o" #define SCNu64 "I64u" #define SCNx64 "I64x" #define SCNX64 "I64X" #define SCNoLEAST64 "I64o" #define SCNuLEAST64 "I64u" #define SCNxLEAST64 "I64x" #define SCNXLEAST64 "I64X" #define SCNoFAST64 "I64o" #define SCNuFAST64 "I64u" #define SCNxFAST64 "I64x" #define SCNXFAST64 "I64X" #define SCNoMAX "I64o" #define SCNuMAX "I64u" #define SCNxMAX "I64x" #define SCNXMAX "I64X" #ifdef _WIN64 // [ # define SCNoPTR "I64o" # define SCNuPTR "I64u" # define SCNxPTR "I64x" # define SCNXPTR "I64X" #else // _WIN64 ][ # define SCNoPTR "lo" # define SCNuPTR "lu" # define SCNxPTR "lx" # define SCNXPTR "lX" #endif // _WIN64 ] #endif // __STDC_FORMAT_MACROS ] // 7.8.2 Functions for greatest-width integer types // 7.8.2.1 The imaxabs function #define imaxabs _abs64 // 7.8.2.2 The imaxdiv function // This is modified version of div() function from Microsoft's div.c found // in %MSVC.NET%\crt\src\div.c #ifdef STATIC_IMAXDIV // [ static #else // STATIC_IMAXDIV ][ _inline #endif // STATIC_IMAXDIV ] imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) { imaxdiv_t result; result.quot = numer / denom; result.rem = numer % denom; if (numer < 0 && result.rem > 0) { // did division wrong; must fix up ++result.quot; result.rem -= denom; } return result; } // 7.8.2.3 The strtoimax and strtoumax functions #define strtoimax _strtoi64 #define strtoumax _strtoui64 // 7.8.2.4 The wcstoimax and wcstoumax functions #define wcstoimax _wcstoi64 #define wcstoumax _wcstoui64 #endif // _MSC_INTTYPES_H_ ] belle-sip-1.4.1/include/MSVC/stdint.h000066400000000000000000000170601252242224000172410ustar00rootroot00000000000000// ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2008 Alexander Chemeris // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. The name of the author may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////////// #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when // compiling for ARM we should wrap include with 'extern "C++" {}' // or compiler give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #ifdef __cplusplus extern "C" { #endif # include #ifdef __cplusplus } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types // Visual Studio 6 and Embedded Visual C++ 4 doesn't // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants #define INTMAX_C INT64_C #define UINTMAX_C UINT64_C #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_STDINT_H_ ] belle-sip-1.4.1/include/Makefile.am000066400000000000000000000000221252242224000170350ustar00rootroot00000000000000SUBDIRS=belle-sip belle-sip-1.4.1/include/belle-sip/000077500000000000000000000000001252242224000166635ustar00rootroot00000000000000belle-sip-1.4.1/include/belle-sip/Makefile.am000066400000000000000000000010551252242224000207200ustar00rootroot00000000000000bellesipdir=$(includedir)/belle-sip bellesip_HEADERS=\ object.h \ sip-uri.h \ list.h \ headers.h \ parameters.h \ mainloop.h \ transaction.h \ message.h \ listeningpoint.h \ sipstack.h \ provider.h \ listener.h \ dialog.h \ utils.h \ auth-helper.h \ belle-sdp.h \ belle-sip.h \ refresher.h \ defs.h \ resolver.h \ dict.h \ http-provider.h \ http-message.h \ http-listener.h \ generic-uri.h \ types.h \ bodyhandler.h EXTRA_DIST=$(bellesip_HEADERS) belle-sip-1.4.1/include/belle-sip/auth-helper.h000066400000000000000000000223631252242224000212600ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef AUTHENTICATION_HELPER_H_ #define AUTHENTICATION_HELPER_H_ #include "belle-sip/defs.h" #include "belle-sip/belle-sip.h" BELLE_SIP_BEGIN_DECLS /** * Create an authorization header from an www_authenticate header, all common parameters are copyed. * copy params: scheme, realm, nonce, algorithm, opaque * @param authentication source to be used as input * @return belle_sip_header_authorization_t* */ BELLESIP_EXPORT belle_sip_header_authorization_t* belle_sip_auth_helper_create_authorization(const belle_sip_header_www_authenticate_t* authentication); /** * Create an http authorization header from an www_authenticate header, all common parameters are copyed. * copy params: scheme, realm, nonce, algorithm, opaque * @param authentication source to be used as input * @return belle_http_header_authorization_t* */ BELLESIP_EXPORT belle_http_header_authorization_t* belle_http_auth_helper_create_authorization(const belle_sip_header_www_authenticate_t* authentication); /** * Create an proxy_authorization header from an www_authenticate header, all common parameters are copyed. * copy params: scheme, realm, nonce, algorithm, opaque * @param authentication source to be used as input * @return belle_sip_header_authorization_t* */ BELLESIP_EXPORT belle_sip_header_proxy_authorization_t* belle_sip_auth_helper_create_proxy_authorization(const belle_sip_header_proxy_authenticate_t* proxy_authentication); /** * compute and set response value according to parameters * HA1=MD5(username:realm:passwd) * fills cnonce if needed (qop=auth); * fills qop * * @return 0 if succeed */ BELLESIP_EXPORT int belle_sip_auth_helper_fill_authorization(belle_sip_header_authorization_t* authorization ,const char* method ,const char* ha1); /** * compute and set response value according to parameters * @return 0 if succeed */ BELLESIP_EXPORT int belle_sip_auth_helper_fill_proxy_authorization(belle_sip_header_proxy_authorization_t* proxy_authorization ,const char* method ,const char* ha1); /* * compute HA1 (NULL terminated) * HA1=MD5(userid:realm:passwd) * return 0 in case of success * */ BELLESIP_EXPORT int belle_sip_auth_helper_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]); /* * compute HA2 (NULL terminated) * HA2=MD5(method:uri) * return 0 in case of success * */ BELLESIP_EXPORT int belle_sip_auth_helper_compute_ha2(const char* method,const char* uri, char ha2[33]); /* * compute response(NULL terminated) * res=MD5(ha1:nonce:ha2) * return 0 in case of success * */ BELLESIP_EXPORT int belle_sip_auth_helper_compute_response(const char* ha1,const char* nonce, const char* ha2, char response[33]); /* * compute response(NULL terminated) * res=MD5(HA1:nonce:nonce_count:cnonce:qop:HA2) * return 0 in case of success * */ BELLESIP_EXPORT int belle_sip_auth_helper_compute_response_qop_auth( const char* ha1 , const char* nonce , unsigned int nonce_count , const char* cnonce , const char* qop , const char* ha2 , char response[33]); /*TLS client certificate auth*/ /** * Set TLS certificate verification callback * * @param callback function pointer for callback, or NULL to unset * * Callback signature is: * int (*verify_cb_error_cb_t)(unsigned char* der, int length, int depth, int* flags); * der - raw certificate data, in DER format * length - length of certificate DER data * depth - position of certificate in cert chain, ending at 0 = root or top * flags - verification state for CURRENT certificate only */ BELLESIP_EXPORT int belle_sip_tls_set_verify_error_cb(void *callback); /** * Format of certificate buffer **/ typedef enum belle_sip_certificate_raw_format { BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM, /** PEM format*/ BELLE_SIP_CERTIFICATE_RAW_FORMAT_DER /** ASN.1 raw format*/ }belle_sip_certificate_raw_format_t; /** * Parse a buffer containing either a certificate chain order in PEM format or a single DER cert * @param buff raw buffer * @param size buffer size * @param format either PEM or DER * @return belle_sip_certificates_chain_t or NUL if cannot be decoded */ BELLESIP_EXPORT belle_sip_certificates_chain_t* belle_sip_certificates_chain_parse(const char* buff, size_t size,belle_sip_certificate_raw_format_t format); /** * Parse a buffer containing either a private or public rsa key * @param buff raw buffer * @param size buffer size * @param passwd password (optionnal) * @return list of belle_sip_signing_key_t or NUL iff cannot be decoded */ BELLESIP_EXPORT belle_sip_signing_key_t* belle_sip_signing_key_parse(const char* buff, size_t size,const char* passwd); /** * Parse a pather containing either a certificate chain order in PEM format or a single DER cert * @param path file * @param format either PEM or DER * @return belle_sip_certificates_chain_t or NUL if cannot be decoded */ BELLESIP_EXPORT belle_sip_certificates_chain_t* belle_sip_certificates_chain_parse_file(const char* path, belle_sip_certificate_raw_format_t format); /** * Parse a directory for *.pem file containing a certificate and private key in PEM format or a single DER cert with subject CNAME as given * * @param[in] path directory to parse * @param[in] subject subject CNAME to look for * @param[out] certificate result certificate, NULL if not found. Is allocated by this function, caller must do a belle_sip_object_unref on it after use * @param[out] pkey result private key, NULL if not found. Is allocated by this function, caller must do a belle_sip_object_unref on it after use * @param[in] format either PEM or DER * @return 0 if we found a certificate and key matching given subject common name */ BELLESIP_EXPORT int belle_sip_get_certificate_and_pkey_in_dir(const char *path, const char *subject, belle_sip_certificates_chain_t **certificate, belle_sip_signing_key_t **pkey, belle_sip_certificate_raw_format_t format); /** * Generate a self signed certificate and key and save them in a file if a path is given, file will be .pem * * @param[in] path If not NULL a file will be written in the given directory. filename is .pem * @param[in] subject used in the CN= field of issuer and subject name * @param[out] certificate the generated certificate. Must be destroyed using belle_sip_certificates_chain_destroy * @param[out] key the generated key. Must be destroyed using belle_sip_signing_key_destroy * @return 0 on success */ BELLESIP_EXPORT int belle_sip_generate_self_signed_certificate(const char* path, const char *subject, belle_sip_certificates_chain_t **certificate, belle_sip_signing_key_t **pkey); /** * Convert a certificate into a its PEM format string * * @param[in] cert The certificate to be converted into PEM format string * @return the PEM representation of certificate. Buffer is allocated by this function and must be freed by caller */ BELLESIP_EXPORT char *belle_sip_certificates_chain_get_pem(belle_sip_certificates_chain_t *cert); /** * Convert a key into a its PEM format string * * @param[in] key The key to be converted into PEM format string * @return the PEM representation of key. Buffer is allocated by this function and must be freed by caller */ BELLESIP_EXPORT char *belle_sip_signing_key_get_pem(belle_sip_signing_key_t *key); /** * Generate a certificate fingerprint as described in RFC4572 * Note: only SHA1 signing algo is supported for now * * @param[in] certificate The certificate used to generate the fingerprint * @return The generated fingerprint formatted according to RFC4572 section 5. Is a null terminated string, must be freed by caller */ BELLESIP_EXPORT char *belle_sip_certificates_chain_get_fingerprint(belle_sip_certificates_chain_t *certificate); /** * Parse a pather containing either a private or public rsa key * @param path file * @param passwd password (optionnal) * @return list of belle_sip_signing_key_t or NUL iff cannot be decoded */ BELLESIP_EXPORT belle_sip_signing_key_t* belle_sip_signing_key_parse_file(const char* path, const char* passwd); BELLESIP_EXPORT belle_tls_verify_policy_t *belle_tls_verify_policy_new(void); BELLESIP_EXPORT int belle_tls_verify_policy_set_root_ca(belle_tls_verify_policy_t *obj, const char *path); #define BELLE_TLS_VERIFY_CN_MISMATCH (1) #define BELLE_TLS_VERIFY_ANY_REASON (0xff) BELLESIP_EXPORT void belle_tls_verify_policy_set_exceptions(belle_tls_verify_policy_t *obj, int flags); BELLESIP_EXPORT unsigned int belle_tls_verify_policy_get_exceptions(const belle_tls_verify_policy_t *obj); BELLE_SIP_END_DECLS #endif /* AUTHENTICATION_HELPER_H_ */ belle-sip-1.4.1/include/belle-sip/belle-sdp.h000066400000000000000000001007751252242224000207150ustar00rootroot00000000000000/* belle-sdp - SIP (RFC4566) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SDP_H_ #define BELLE_SDP_H_ #include "belle-sip/defs.h" #include "belle-sip/list.h" #define BELLE_SDP_CAST(obj,t) BELLE_SIP_CAST(obj,t) BELLE_SIP_BEGIN_DECLS /*************************************************************************************** * Attribute * **************************************************************************************/ typedef struct _belle_sdp_attribute belle_sdp_attribute_t; BELLESIP_EXPORT belle_sdp_attribute_t* belle_sdp_attribute_new(); BELLESIP_EXPORT belle_sdp_attribute_t* belle_sdp_attribute_parse (const char* attribute); BELLESIP_EXPORT belle_sdp_attribute_t* belle_sdp_attribute_create (const char* name,const char* value); BELLESIP_EXPORT const char* belle_sdp_attribute_get_name(const belle_sdp_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_attribute_set_name(belle_sdp_attribute_t* attribute, const char* name); BELLESIP_EXPORT const char* belle_sdp_attribute_get_value(belle_sdp_attribute_t* attribute); BELLESIP_EXPORT unsigned int belle_sdp_attribute_has_value(belle_sdp_attribute_t* attribute); #define BELLE_SDP_ATTRIBUTE(t) BELLE_SDP_CAST(t,belle_sdp_attribute_t) #define belle_sdp_attribute_init(obj) /*nothing*/ /*************************************************************************************** * RAW Attribute * **************************************************************************************/ typedef struct _belle_sdp_raw_attribute belle_sdp_raw_attribute_t; BELLESIP_EXPORT belle_sdp_raw_attribute_t* belle_sdp_raw_attribute_new(); BELLESIP_EXPORT belle_sdp_raw_attribute_t* belle_sdp_raw_attribute_parse(const char* attribute); BELLESIP_EXPORT belle_sdp_raw_attribute_t* belle_sdp_raw_attribute_create(const char* name, const char* value); BELLESIP_EXPORT void belle_sdp_raw_attribute_set_value(belle_sdp_raw_attribute_t* attribute, const char* value); #define BELLE_SDP_RAW_ATTRIBUTE(t) BELLE_SDP_CAST(t,belle_sdp_raw_attribute_t) /*************************************************************************************** * RTCP-FB Attribute * **************************************************************************************/ typedef enum _belle_sdp_rtcp_fb_val_type { BELLE_SDP_RTCP_FB_ACK, BELLE_SDP_RTCP_FB_NACK, BELLE_SDP_RTCP_FB_TRR_INT, BELLE_SDP_RTCP_FB_CCM } belle_sdp_rtcp_fb_val_type_t; typedef enum _belle_sdp_rtcp_fb_val_param { BELLE_SDP_RTCP_FB_NONE, BELLE_SDP_RTCP_FB_PLI, BELLE_SDP_RTCP_FB_SLI, BELLE_SDP_RTCP_FB_RPSI, BELLE_SDP_RTCP_FB_APP, BELLE_SDP_RTCP_FB_FIR, BELLE_SDP_RTCP_FB_TMMBR } belle_sdp_rtcp_fb_val_param_t; typedef struct _belle_sdp_rtcp_fb_attribute belle_sdp_rtcp_fb_attribute_t; BELLESIP_EXPORT belle_sdp_rtcp_fb_attribute_t* belle_sdp_rtcp_fb_attribute_new(); BELLESIP_EXPORT belle_sdp_rtcp_fb_attribute_t* belle_sdp_rtcp_fb_attribute_parse(const char* attribute); BELLESIP_EXPORT belle_sdp_rtcp_fb_attribute_t* belle_sdp_rtcp_fb_attribute_create(); BELLESIP_EXPORT int8_t belle_sdp_rtcp_fb_attribute_get_id(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_id(belle_sdp_rtcp_fb_attribute_t* attribute, int8_t id); BELLESIP_EXPORT belle_sdp_rtcp_fb_val_type_t belle_sdp_rtcp_fb_attribute_get_type(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_type(belle_sdp_rtcp_fb_attribute_t* attribute, belle_sdp_rtcp_fb_val_type_t type); BELLESIP_EXPORT belle_sdp_rtcp_fb_val_param_t belle_sdp_rtcp_fb_attribute_get_param(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_param(belle_sdp_rtcp_fb_attribute_t* attribute, belle_sdp_rtcp_fb_val_param_t param); BELLESIP_EXPORT uint16_t belle_sdp_rtcp_fb_attribute_get_trr_int(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_trr_int(belle_sdp_rtcp_fb_attribute_t* attribute, uint16_t milliseconds); BELLESIP_EXPORT uint32_t belle_sdp_rtcp_fb_attribute_get_smaxpr(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_smaxpr(belle_sdp_rtcp_fb_attribute_t* attribute, uint32_t smaxpr); #define BELLE_SDP_RTCP_FB_ATTRIBUTE(t) BELLE_SDP_CAST(t,belle_sdp_rtcp_fb_attribute_t) /*************************************************************************************** * RTCP-XR Attribute * **************************************************************************************/ typedef struct _belle_sdp_rtcp_xr_attribute belle_sdp_rtcp_xr_attribute_t; BELLESIP_EXPORT belle_sdp_rtcp_xr_attribute_t* belle_sdp_rtcp_xr_attribute_new(); BELLESIP_EXPORT belle_sdp_rtcp_xr_attribute_t* belle_sdp_rtcp_xr_attribute_parse(const char* attribute); BELLESIP_EXPORT belle_sdp_rtcp_xr_attribute_t* belle_sdp_rtcp_xr_attribute_create(); BELLESIP_EXPORT const char* belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(const belle_sdp_rtcp_xr_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode(belle_sdp_rtcp_xr_attribute_t* attribute, const char *mode); BELLESIP_EXPORT int belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(const belle_sdp_rtcp_xr_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_max_size(belle_sdp_rtcp_xr_attribute_t* attribute, int max_size); BELLESIP_EXPORT unsigned int belle_sdp_rtcp_xr_attribute_has_stat_summary(const belle_sdp_rtcp_xr_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_xr_attribute_set_stat_summary(belle_sdp_rtcp_xr_attribute_t* attribute, unsigned int enable); BELLESIP_EXPORT const belle_sip_list_t* belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(const belle_sdp_rtcp_xr_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(belle_sdp_rtcp_xr_attribute_t* attribute, const char* flag); BELLESIP_EXPORT unsigned int belle_sdp_rtcp_xr_attribute_has_voip_metrics(const belle_sdp_rtcp_xr_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_xr_attribute_set_voip_metrics(belle_sdp_rtcp_xr_attribute_t* attribute, unsigned int enable); #define BELLE_SDP_RTCP_XR_ATTRIBUTE(t) BELLE_SDP_CAST(t,belle_sdp_rtcp_xr_attribute_t) /*************************************************************************************** * Bandwidth * **************************************************************************************/ typedef struct _belle_sdp_bandwidth belle_sdp_bandwidth_t; BELLESIP_EXPORT belle_sdp_bandwidth_t* belle_sdp_bandwidth_new(); BELLESIP_EXPORT belle_sdp_bandwidth_t* belle_sdp_bandwidth_parse (const char* bandwidth); BELLESIP_EXPORT int belle_sdp_bandwidth_get_value(const belle_sdp_bandwidth_t* attribute); BELLESIP_EXPORT const char* belle_sdp_bandwidth_get_type(const belle_sdp_bandwidth_t* attribute); BELLESIP_EXPORT void belle_sdp_bandwidth_set_value(belle_sdp_bandwidth_t* attribute, int value); BELLESIP_EXPORT void belle_sdp_bandwidth_set_type(belle_sdp_bandwidth_t* attribute, const char* type); #define BELLE_SDP_BANDWIDTH(t) BELLE_SDP_CAST(t,belle_sdp_bandwidth_t) /*************************************************************************************** * Connection * **************************************************************************************/ typedef struct _belle_sdp_connection belle_sdp_connection_t; BELLESIP_EXPORT belle_sdp_connection_t* belle_sdp_connection_new(); BELLESIP_EXPORT belle_sdp_connection_t* belle_sdp_connection_create(const char* net_type, const char* addr_type, const char* addr); BELLESIP_EXPORT belle_sdp_connection_t* belle_sdp_connection_parse (const char* connection); BELLESIP_EXPORT const char* belle_sdp_connection_get_address(const belle_sdp_connection_t* connection); BELLESIP_EXPORT const char* belle_sdp_connection_get_address_type(const belle_sdp_connection_t* connection); BELLESIP_EXPORT const char* belle_sdp_connection_get_network_type(const belle_sdp_connection_t* connection); BELLESIP_EXPORT int belle_sdp_connection_get_ttl(const belle_sdp_connection_t* connection); BELLESIP_EXPORT int belle_sdp_connection_get_range(const belle_sdp_connection_t* connection); BELLESIP_EXPORT void belle_sdp_connection_set_address(belle_sdp_connection_t* connection, const char* addr); BELLESIP_EXPORT void belle_sdp_connection_set_address_type(belle_sdp_connection_t* connection, const char* type); BELLESIP_EXPORT void belle_sdp_connection_set_network_type(belle_sdp_connection_t* connection, const char* type); BELLESIP_EXPORT void belle_sdp_connection_set_ttl(belle_sdp_connection_t* connection,int ttl); BELLESIP_EXPORT void belle_sdp_connection_set_range(belle_sdp_connection_t* connection,int range); #define BELLE_SDP_CONNECTION(t) BELLE_SDP_CAST(t,belle_sdp_connection_t) /*************************************************************************************** * Email * **************************************************************************************/ typedef struct _belle_sdp_email belle_sdp_email_t; BELLESIP_EXPORT belle_sdp_email_t* belle_sdp_email_new(); BELLESIP_EXPORT belle_sdp_email_t* belle_sdp_email_parse (const char* email); BELLESIP_EXPORT const char* belle_sdp_email_get_value(const belle_sdp_email_t* email); BELLESIP_EXPORT void belle_sdp_email_set_value(belle_sdp_email_t* email, const char* value); #define BELLE_SDP_EMAIL(t) BELLE_SDP_CAST(t,belle_sdp_email_t) /*************************************************************************************** * Info * **************************************************************************************/ typedef struct _belle_sdp_info belle_sdp_info_t; BELLESIP_EXPORT belle_sdp_info_t* belle_sdp_info_new(); BELLESIP_EXPORT belle_sdp_info_t* belle_sdp_info_parse (const char* info); BELLESIP_EXPORT const char* belle_sdp_info_get_value(const belle_sdp_info_t* info); BELLESIP_EXPORT void belle_sdp_info_set_value(belle_sdp_info_t* info, const char* value); #define BELLE_SDP_INFO(t) BELLE_SDP_CAST(t,belle_sdp_info_t) /*************************************************************************************** * Key * **************************************************************************************/ //typedef struct _belle_sdp_key belle_sdp_key_t; //belle_sdp_key_t* belle_sdp_key_new(); //belle_sdp_key_t* belle_sdp_key_parse (const char* key); //const char* belle_sdp_key_get_key(const belle_sdp_key_t* key); //const char* belle_sdp_key_get_method(const belle_sdp_key_t* key); //unsigned int belle_sdp_key_as_key(const belle_sdp_key_t* key); //void belle_sdp_key_set_key(belle_sdp_key_t* key, const char* keyvalue); //void belle_sdp_key_set_method(belle_sdp_key_t* key, const char* method); //#define BELLE_SDP_KEY(t) BELLE_SDP_CAST(t,belle_sdp_key_t); /*************************************************************************************** * Media * **************************************************************************************/ typedef struct _belle_sdp_media belle_sdp_media_t; BELLESIP_EXPORT belle_sdp_media_t* belle_sdp_media_new(); BELLESIP_EXPORT belle_sdp_media_t* belle_sdp_media_parse (const char* media); BELLESIP_EXPORT belle_sdp_media_t* belle_sdp_media_create(const char* media_type ,int media_port ,int port_count ,const char* protocol ,belle_sip_list_t* static_media_formats); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_media_get_media_formats(const belle_sdp_media_t* media); BELLESIP_EXPORT const char* belle_sdp_media_get_raw_fmt(const belle_sdp_media_t* media); BELLESIP_EXPORT int belle_sdp_media_get_media_port(const belle_sdp_media_t* media); BELLESIP_EXPORT const char* belle_sdp_media_get_media_type(const belle_sdp_media_t* media); BELLESIP_EXPORT int belle_sdp_media_get_port_count(const belle_sdp_media_t* media); BELLESIP_EXPORT const char* belle_sdp_media_get_protocol(const belle_sdp_media_t* media); BELLESIP_EXPORT void belle_sdp_media_set_media_formats(belle_sdp_media_t* media, belle_sip_list_t* mediaFormats); BELLESIP_EXPORT void belle_sdp_media_set_raw_fmt(belle_sdp_media_t* media, const char* fmt); BELLESIP_EXPORT void belle_sdp_media_set_media_port(belle_sdp_media_t* media, int port); BELLESIP_EXPORT void belle_sdp_media_set_media_type(belle_sdp_media_t* media, const char* mediaType); BELLESIP_EXPORT void belle_sdp_media_set_port_count(belle_sdp_media_t* media, int port_count); BELLESIP_EXPORT void belle_sdp_media_set_protocol(belle_sdp_media_t* media, const char* protocole); #define BELLE_SDP_MEDIA(t) BELLE_SDP_CAST(t,belle_sdp_media_t) /*************************************************************************************** * mime_parameter * **************************************************************************************/ typedef struct _belle_sdp_mime_parameter belle_sdp_mime_parameter_t; BELLESIP_EXPORT belle_sdp_mime_parameter_t* belle_sdp_mime_parameter_new(); BELLESIP_EXPORT belle_sdp_mime_parameter_t* belle_sdp_mime_parameter_create(const char* type, int media_format, int rate,int channel_count); BELLESIP_EXPORT int belle_sdp_mime_parameter_get_rate(const belle_sdp_mime_parameter_t* mime_parameter); BELLESIP_EXPORT void belle_sdp_mime_parameter_set_rate(belle_sdp_mime_parameter_t* mime_parameter,int rate); BELLESIP_EXPORT int belle_sdp_mime_parameter_get_channel_count(const belle_sdp_mime_parameter_t* mime_parameter); BELLESIP_EXPORT void belle_sdp_mime_parameter_set_channel_count(belle_sdp_mime_parameter_t* mime_parameter,int count); BELLESIP_EXPORT int belle_sdp_mime_parameter_get_ptime(const belle_sdp_mime_parameter_t* mime_parameter); BELLESIP_EXPORT void belle_sdp_mime_parameter_set_ptime(belle_sdp_mime_parameter_t* mime_parameter,int ptime); BELLESIP_EXPORT int belle_sdp_mime_parameter_get_max_ptime(const belle_sdp_mime_parameter_t* mime_parameter); BELLESIP_EXPORT void belle_sdp_mime_parameter_set_max_ptime(belle_sdp_mime_parameter_t* mime_parameter,int max_ptime); BELLESIP_EXPORT const char* belle_sdp_mime_parameter_get_type(const belle_sdp_mime_parameter_t* mime_parameter); BELLESIP_EXPORT void belle_sdp_mime_parameter_set_type(belle_sdp_mime_parameter_t* mime_parameter,const char* type); BELLESIP_EXPORT int belle_sdp_mime_parameter_get_media_format(const belle_sdp_mime_parameter_t* mime_parameter); BELLESIP_EXPORT void belle_sdp_mime_parameter_set_media_format(belle_sdp_mime_parameter_t* mime_parameter,int format); BELLESIP_EXPORT const char* belle_sdp_mime_parameter_get_parameters(const belle_sdp_mime_parameter_t* mime_parameter); BELLESIP_EXPORT void belle_sdp_mime_parameter_set_parameters(belle_sdp_mime_parameter_t* mime_parameter,const char* parameters); #define BELLE_SDP_MIME_PARAMETER(t) BELLE_SDP_CAST(t,belle_sdp_mime_parameter_t) /*************************************************************************************** * Media Description * **************************************************************************************/ typedef struct _belle_sdp_media_description belle_sdp_media_description_t; BELLESIP_EXPORT belle_sdp_media_description_t* belle_sdp_media_description_new(); BELLESIP_EXPORT belle_sdp_media_description_t* belle_sdp_media_description_parse (const char* media_description); BELLESIP_EXPORT belle_sdp_media_description_t* belle_sdp_media_description_create(const char* media_type ,int media_port ,int port_count ,const char* protocol ,belle_sip_list_t* static_media_formats); BELLESIP_EXPORT void belle_sdp_media_description_add_dynamic_payloads(belle_sdp_media_description_t* media_description, belle_sip_list_t* payloadNames, belle_sip_list_t* payloadValues); BELLESIP_EXPORT const char* belle_sdp_media_description_get_attribute_value(const belle_sdp_media_description_t* media_description, const char* name); BELLESIP_EXPORT belle_sdp_attribute_t* belle_sdp_media_description_get_attribute(const belle_sdp_media_description_t* media_description, const char* name); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_media_description_get_attributes(const belle_sdp_media_description_t* media_description); BELLESIP_EXPORT int belle_sdp_media_description_get_bandwidth(const belle_sdp_media_description_t* media_description, const char* name); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_media_description_get_bandwidths(const belle_sdp_media_description_t* media_description); BELLESIP_EXPORT belle_sdp_connection_t* belle_sdp_media_description_get_connection(const belle_sdp_media_description_t* media_description); BELLESIP_EXPORT belle_sdp_info_t* belle_sdp_media_description_get_info(const belle_sdp_media_description_t* media_description); /*belle_sdp_key_t* belle_sdp_media_description_get_key(const belle_sdp_media_description_t* media_description);*/ BELLESIP_EXPORT belle_sdp_media_t* belle_sdp_media_description_get_media(const belle_sdp_media_description_t* media_description); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_media_description_build_mime_parameters(const belle_sdp_media_description_t* media_description); /*belle_sip_list_t* belle_sdp_media_description_get_mime_types(const belle_sdp_media_description_t* media_description);*/ BELLESIP_EXPORT void belle_sdp_media_description_remove_attribute(belle_sdp_media_description_t* media_description,const char* attribute); BELLESIP_EXPORT void belle_sdp_media_description_remove_bandwidth(belle_sdp_media_description_t* media_description,const char* bandwidth); BELLESIP_EXPORT void belle_sdp_media_description_set_attribute_value(belle_sdp_media_description_t* media_description, const char* name, const char* value); BELLESIP_EXPORT void belle_sdp_media_description_add_attribute(belle_sdp_media_description_t* media_description, const belle_sdp_attribute_t* attr); BELLESIP_EXPORT void belle_sdp_media_description_set_attributes(belle_sdp_media_description_t* media_description, belle_sip_list_t* Attributes); BELLESIP_EXPORT void belle_sdp_media_description_set_bandwidth(belle_sdp_media_description_t* media_description, const char* name, int value); BELLESIP_EXPORT void belle_sdp_media_description_add_bandwidth(belle_sdp_media_description_t* media_description, const belle_sdp_bandwidth_t* bandwidth); BELLESIP_EXPORT void belle_sdp_media_description_set_bandwidths(belle_sdp_media_description_t* media_description, belle_sip_list_t* bandwidths); BELLESIP_EXPORT void belle_sdp_media_description_set_connection(belle_sdp_media_description_t* media_description, belle_sdp_connection_t* conn); BELLESIP_EXPORT void belle_sdp_media_description_set_info(belle_sdp_media_description_t* media_description,belle_sdp_info_t* i); /*void belle_sdp_media_description_set_key(belle_sdp_media_description_t* media_description,belle_sdp_key_t* key);*/ BELLESIP_EXPORT void belle_sdp_media_description_set_media(belle_sdp_media_description_t* media_description, belle_sdp_media_t* media); BELLESIP_EXPORT void belle_sdp_media_description_append_values_from_mime_parameter(belle_sdp_media_description_t* media_description, const belle_sdp_mime_parameter_t* mime_parameter); #define BELLE_SDP_MEDIA_DESCRIPTION(t) BELLE_SDP_CAST(t,belle_sdp_media_description_t) /*************************************************************************************** * Origin * **************************************************************************************/ typedef struct _belle_sdp_origin belle_sdp_origin_t; BELLESIP_EXPORT belle_sdp_origin_t* belle_sdp_origin_new(); BELLESIP_EXPORT belle_sdp_origin_t* belle_sdp_origin_parse (const char* origin); BELLESIP_EXPORT belle_sdp_origin_t* belle_sdp_origin_create(const char* user_name , unsigned int session_id , unsigned int session_version , const char* network_type , const char* addr_type , const char* address); BELLESIP_EXPORT const char* belle_sdp_origin_get_address(const belle_sdp_origin_t* origin); BELLESIP_EXPORT const char* belle_sdp_origin_get_address_type(const belle_sdp_origin_t* origin); BELLESIP_EXPORT const char* belle_sdp_origin_get_network_type(const belle_sdp_origin_t* origin); BELLESIP_EXPORT unsigned int belle_sdp_origin_get_session_id(const belle_sdp_origin_t* origin); BELLESIP_EXPORT unsigned int belle_sdp_origin_get_session_version(const belle_sdp_origin_t* origin); BELLESIP_EXPORT const char* belle_sdp_origin_get_username(const belle_sdp_origin_t* origin); BELLESIP_EXPORT void belle_sdp_origin_set_address(belle_sdp_origin_t* origin, const char* address); BELLESIP_EXPORT void belle_sdp_origin_set_address_type(belle_sdp_origin_t* origin, const char* address); BELLESIP_EXPORT void belle_sdp_origin_set_network_type(belle_sdp_origin_t* origin, const char* network_type); BELLESIP_EXPORT void belle_sdp_origin_set_session_id(belle_sdp_origin_t* origin, unsigned int session_id); BELLESIP_EXPORT void belle_sdp_origin_set_session_version(belle_sdp_origin_t* origin, unsigned int version); BELLESIP_EXPORT void belle_sdp_origin_set_username(belle_sdp_origin_t* origin, const char* username); #define BELLE_SDP_ORIGIN(t) BELLE_SDP_CAST(t,belle_sdp_origin_t) /*************************************************************************************** * Phone * **************************************************************************************/ typedef struct _belle_sdp_phone belle_sdp_phone_t; BELLESIP_EXPORT belle_sdp_phone_t* belle_sdp_phone_new(); BELLESIP_EXPORT belle_sdp_phone_t* belle_sdp_phone_parse (const char* phone); BELLESIP_EXPORT const char* belle_sdp_phone_get_value(const belle_sdp_phone_t* phone); BELLESIP_EXPORT void belle_sdp_phone_set_value(belle_sdp_phone_t* phone, const char* value); #define BELLE_SDP_PHONE(t) BELLE_SDP_CAST(t,belle_sdp_phone_t) /*************************************************************************************** * Repeat time * **************************************************************************************/ typedef struct _belle_sdp_repeate_time belle_sdp_repeate_time_t; BELLESIP_EXPORT belle_sdp_repeate_time_t* belle_sdp_repeate_time_new(); BELLESIP_EXPORT belle_sdp_repeate_time_t* belle_sdp_repeate_time_parse (const char* repeate_time); BELLESIP_EXPORT const char* belle_sdp_repeate_time_get_value(const belle_sdp_repeate_time_t* repeate_time); BELLESIP_EXPORT void belle_sdp_repeate_time_set_value(belle_sdp_repeate_time_t* repeate_time, const char* value); #define BELLE_SDP_REPEATE_TIME(t) BELLE_SDP_CAST(t,belle_sdp_repeate_time_t) /*************************************************************************************** * Session Name * **************************************************************************************/ typedef struct _belle_sdp_session_name belle_sdp_session_name_t; BELLESIP_EXPORT belle_sdp_session_name_t* belle_sdp_session_name_new(); BELLESIP_EXPORT belle_sdp_session_name_t* belle_sdp_session_name_create (const char* name); BELLESIP_EXPORT const char* belle_sdp_session_name_get_value(const belle_sdp_session_name_t* session_name); BELLESIP_EXPORT void belle_sdp_session_name_set_value(belle_sdp_session_name_t* session_name, const char* value); #define BELLE_SDP_SESSION_NAME(t) BELLE_SDP_CAST(t,belle_sdp_session_name_t) /*************************************************************************************** * Time * **************************************************************************************/ typedef struct _belle_sdp_time belle_sdp_time_t; BELLESIP_EXPORT belle_sdp_time_t* belle_sdp_time_new(); BELLESIP_EXPORT belle_sdp_time_t* belle_sdp_time_parse (const char* time); BELLESIP_EXPORT int belle_sdp_time_get_start(const belle_sdp_time_t* time); BELLESIP_EXPORT int belle_sdp_time_get_stop(const belle_sdp_time_t* time); BELLESIP_EXPORT void belle_sdp_time_set_start(belle_sdp_time_t* time, int value); BELLESIP_EXPORT void belle_sdp_time_set_stop(belle_sdp_time_t* time, int value); #define BELLE_SDP_TIME(t) BELLE_SDP_CAST(t,belle_sdp_time_t) /*************************************************************************************** * Time description * **************************************************************************************/ typedef struct _belle_sdp_time_description belle_sdp_time_description_t; BELLESIP_EXPORT belle_sdp_time_description_t* belle_sdp_time_description_new(); BELLESIP_EXPORT belle_sdp_time_description_t* belle_sdp_time_description_parse (const char* time_description); BELLESIP_EXPORT belle_sdp_time_description_t* belle_sdp_time_description_create (int start,int stop); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_time_description_get_repeate_times(const belle_sdp_time_description_t* time_description); BELLESIP_EXPORT belle_sdp_time_t* belle_sdp_time_description_get_time(const belle_sdp_time_description_t* time_description); BELLESIP_EXPORT void belle_sdp_time_description_set_repeate_times(belle_sdp_time_description_t* time_description, belle_sip_list_t* times); BELLESIP_EXPORT void belle_sdp_time_description_set_time(belle_sdp_time_description_t* time_description, belle_sdp_time_t* times); #define BELLE_SDP_TIME_DESCRIPTION(t) BELLE_SDP_CAST(t,belle_sdp_time_description_t) /*************************************************************************************** * URI * **************************************************************************************/ typedef struct _belle_sdp_uri belle_sdp_uri_t; BELLESIP_EXPORT belle_sdp_uri_t* belle_sdp_uri_new(); BELLESIP_EXPORT belle_sdp_uri_t* belle_sdp_uri_parse (const char* uri); BELLESIP_EXPORT const char* belle_sdp_uri_get_value(const belle_sdp_uri_t* uri); BELLESIP_EXPORT void belle_sdp_uri_set_value(belle_sdp_uri_t* uri, const char* value); #define BELLE_SDP_URI(t) BELLE_SDP_CAST(t,belle_sdp_uri_t) /*************************************************************************************** * Version * **************************************************************************************/ typedef struct _belle_sdp_version belle_sdp_version_t; belle_sdp_version_t* belle_sdp_version_new(); BELLESIP_EXPORT belle_sdp_version_t* belle_sdp_version_create(int version); BELLESIP_EXPORT int belle_sdp_version_get_version(const belle_sdp_version_t* version); BELLESIP_EXPORT void belle_sdp_version_set_version(belle_sdp_version_t* version, int value); #define BELLE_SDP_VERSION(t) BELLE_SDP_CAST(t,belle_sdp_version_t) /*************************************************************************************** * Session Description * **************************************************************************************/ typedef struct _belle_sdp_session_description belle_sdp_session_description_t; BELLESIP_EXPORT belle_sdp_session_description_t* belle_sdp_session_description_new(); BELLESIP_EXPORT belle_sdp_session_description_t* belle_sdp_session_description_parse (const char* session_description); BELLESIP_EXPORT const char* belle_sdp_session_description_get_attribute_value(const belle_sdp_session_description_t* session_description, const char* name); BELLESIP_EXPORT const belle_sdp_attribute_t* belle_sdp_session_description_get_attribute(const belle_sdp_session_description_t* session_description, const char* name); BELLESIP_EXPORT int belle_sdp_session_description_get_bandwidth(const belle_sdp_session_description_t* session_description, const char* name); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_session_description_get_bandwidths(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sdp_connection_t* belle_sdp_session_description_get_connection(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_session_description_get_emails(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sdp_info_t* belle_sdp_session_description_get_info(const belle_sdp_session_description_t* session_description); /*belle_sdp_key_t* belle_sdp_session_description_get_key(const belle_sdp_session_description_t* session_description);*/ BELLESIP_EXPORT belle_sip_list_t* belle_sdp_session_description_get_media_descriptions(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sdp_origin_t* belle_sdp_session_description_get_origin(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_session_description_get_phones(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sdp_session_name_t* belle_sdp_session_description_get_session_name(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sip_list_t* belle_sdp_session_description_get_time_descriptions(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sdp_uri_t* belle_sdp_session_description_get_uri(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sdp_version_t* belle_sdp_session_description_get_version(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT belle_sdp_uri_t* belle_sdp_session_description_get_zone_adjustments(const belle_sdp_session_description_t* session_description); BELLESIP_EXPORT void belle_sdp_session_description_remove_attribute(belle_sdp_session_description_t* session_description, const char* name); BELLESIP_EXPORT void belle_sdp_session_description_remove_bandwidth(belle_sdp_session_description_t* session_description, const char* name); BELLESIP_EXPORT void belle_sdp_session_description_set_attribute_value(belle_sdp_session_description_t* session_description, const char* name, const char* value); BELLESIP_EXPORT void belle_sdp_session_description_add_attribute(belle_sdp_session_description_t* session_description, const belle_sdp_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_session_description_set_attributes(belle_sdp_session_description_t* session_description, belle_sip_list_t* Attributes); BELLESIP_EXPORT void belle_sdp_session_description_set_bandwidth(belle_sdp_session_description_t* session_description, const char* name, int value); BELLESIP_EXPORT void belle_sdp_session_description_set_bandwidths(belle_sdp_session_description_t* session_description, belle_sip_list_t* bandwidths); BELLESIP_EXPORT void belle_sdp_session_description_add_bandwidth(belle_sdp_session_description_t* session_description, const belle_sdp_bandwidth_t* bandwidth); BELLESIP_EXPORT void belle_sdp_session_description_set_connection(belle_sdp_session_description_t* session_description, belle_sdp_connection_t* conn); BELLESIP_EXPORT void belle_sdp_session_description_set_emails(belle_sdp_session_description_t* session_description, belle_sip_list_t* emails); BELLESIP_EXPORT void belle_sdp_session_description_set_info(belle_sdp_session_description_t* session_description, belle_sdp_info_t* i); /*void belle_sdp_session_description_set_key(belle_sdp_session_description_t* session_description, belle_sdp_key_t* key);*/ BELLESIP_EXPORT void belle_sdp_session_description_set_media_descriptions(belle_sdp_session_description_t* session_description, belle_sip_list_t* mediaDescriptions); BELLESIP_EXPORT void belle_sdp_session_description_add_media_description(belle_sdp_session_description_t* session_description, belle_sdp_media_description_t* media_description); BELLESIP_EXPORT void belle_sdp_session_description_set_origin(belle_sdp_session_description_t* session_description, belle_sdp_origin_t* origin); BELLESIP_EXPORT void belle_sdp_session_description_set_phones(belle_sdp_session_description_t* session_description, belle_sip_list_t* phones); BELLESIP_EXPORT void belle_sdp_session_description_set_session_name(belle_sdp_session_description_t* session_description, belle_sdp_session_name_t* sessionName); BELLESIP_EXPORT void belle_sdp_session_description_set_time_descriptions(belle_sdp_session_description_t* session_description, belle_sip_list_t* times); BELLESIP_EXPORT void belle_sdp_session_description_set_time_description(belle_sdp_session_description_t* session_description, belle_sdp_time_description_t* time_desc); BELLESIP_EXPORT void belle_sdp_session_description_set_uri(belle_sdp_session_description_t* session_description, belle_sdp_uri_t* uri); BELLESIP_EXPORT void belle_sdp_session_description_set_version(belle_sdp_session_description_t* session_description, belle_sdp_version_t* v); BELLESIP_EXPORT void belle_sdp_session_description_set_zone_adjustments(belle_sdp_session_description_t* session_description, belle_sdp_uri_t* zoneAdjustments); #define BELLE_SDP_SESSION_DESCRIPTION(t) BELLE_SDP_CAST(t,belle_sdp_session_description_t) BELLE_SIP_END_DECLS #endif /* BELLE_SDP_H_ */ belle-sip-1.4.1/include/belle-sip/belle-sip.h000066400000000000000000000033371252242224000207160ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_H #define BELLE_SIP_H #include "belle-sip/types.h" #include "belle-sip/utils.h" #include "belle-sip/list.h" #include "belle-sip/listener.h" #include "belle-sip/mainloop.h" #include "belle-sip/sip-uri.h" #include "belle-sip/headers.h" #include "belle-sip/parameters.h" #include "belle-sip/message.h" #include "belle-sip/refresher.h" #include "belle-sip/transaction.h" #include "belle-sip/dialog.h" #include "belle-sip/sipstack.h" #include "belle-sip/resolver.h" #include "belle-sip/listeningpoint.h" #include "belle-sip/provider.h" #include "belle-sip/auth-helper.h" #include "belle-sip/generic-uri.h" #include "belle-sip/http-listener.h" #include "belle-sip/http-provider.h" #include "belle-sip/http-listener.h" #include "belle-sip/http-message.h" #include "belle-sip/belle-sdp.h" #include "belle-sip/bodyhandler.h" #ifdef ANDROID #include "belle-sip/wakelock.h" #endif #define BELLE_SIP_POINTER_TO_INT(p) ((int)(long)(p)) #define BELLE_SIP_INT_TO_POINTER(i) ((void*)(long)(i)) #endif belle-sip-1.4.1/include/belle-sip/bodyhandler.h000066400000000000000000000076571252242224000213460ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2014 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_body_handler_h #define belle_sip_body_handler_h BELLE_SIP_BEGIN_DECLS #define BELLE_SIP_BODY_HANDLER(obj) BELLE_SIP_CAST(obj,belle_sip_body_handler_t) /* * Body handler base class. **/ typedef void (*belle_sip_body_handler_progress_callback_t)(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, void *user_data, size_t transfered, size_t expected_total); BELLESIP_EXPORT void belle_sip_body_handler_add_header(belle_sip_body_handler_t *obj, belle_sip_header_t *header); BELLESIP_EXPORT size_t belle_sip_body_handler_get_size(const belle_sip_body_handler_t *obj); BELLESIP_EXPORT void belle_sip_body_handler_set_size(belle_sip_body_handler_t *obj, size_t size); BELLESIP_EXPORT size_t belle_sip_body_handler_get_transfered_size(const belle_sip_body_handler_t *obj); /* * body handler that read/write from a memory buffer. **/ #define BELLE_SIP_MEMORY_BODY_HANDLER(obj) BELLE_SIP_CAST(obj,belle_sip_memory_body_handler_t) BELLESIP_EXPORT belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new(belle_sip_body_handler_progress_callback_t progress_cb, void *data); BELLESIP_EXPORT belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new_copy_from_buffer(const void *buffer, size_t bufsize, belle_sip_body_handler_progress_callback_t cb, void *user_data); BELLESIP_EXPORT belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new_from_buffer(void *buffer, size_t bufsize, belle_sip_body_handler_progress_callback_t cb, void *user_data); BELLESIP_EXPORT const void *belle_sip_memory_body_handler_get_buffer(const belle_sip_memory_body_handler_t *obj); /* * body handler that get/puts data from application. **/ #define BELLE_SIP_USER_BODY_HANDLER(obj) BELLE_SIP_CAST(obj,belle_sip_user_body_handler_t) typedef void (*belle_sip_user_body_handler_recv_callback_t)(belle_sip_user_body_handler_t *obj, belle_sip_message_t *msg, void *user_data, size_t offset, const uint8_t* buffer, size_t size); typedef int (*belle_sip_user_body_handler_send_callback_t)(belle_sip_user_body_handler_t *obj, belle_sip_message_t *msg, void *user_data, size_t offset, uint8_t* buffer, size_t *size); BELLESIP_EXPORT belle_sip_user_body_handler_t *belle_sip_user_body_handler_new( size_t total_size, belle_sip_body_handler_progress_callback_t progress_cb, belle_sip_user_body_handler_recv_callback_t recv_cb, belle_sip_user_body_handler_send_callback_t send_cb, void *data); /** * Body handler that gets/puts data from/to a file. **/ #define BELLE_SIP_FILE_BODY_HANDLER(obj) BELLE_SIP_CAST(obj, belle_sip_file_body_handler_t) BELLESIP_EXPORT belle_sip_file_body_handler_t *belle_sip_file_body_handler_new(const char *filepath, belle_sip_body_handler_progress_callback_t progress_cb, void *data); /* * Multipart body handler */ #define BELLE_SIP_MULTIPART_BODY_HANDLER(obj) BELLE_SIP_CAST(obj,belle_sip_multipart_body_handler_t) BELLESIP_EXPORT belle_sip_multipart_body_handler_t *belle_sip_multipart_body_handler_new(belle_sip_body_handler_progress_callback_t progress_cb, void *data, belle_sip_body_handler_t *first_part); BELLESIP_EXPORT void belle_sip_multipart_body_handler_add_part(belle_sip_multipart_body_handler_t *obj, belle_sip_body_handler_t *part); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/defs.h000066400000000000000000000033111252242224000177530ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010-2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_DEFS_H #define BELLE_SIP_DEFS_H #ifdef __cplusplus #define BELLE_SIP_BEGIN_DECLS extern "C"{ #define BELLE_SIP_END_DECLS } #else #define BELLE_SIP_BEGIN_DECLS #define BELLE_SIP_END_DECLS #endif #ifdef _MSC_VER #define BELLESIP_INLINE __inline typedef signed char int8_t; typedef unsigned char uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include #define BELLESIP_INLINE inline #endif #ifdef WIN32 #ifdef BELLESIP_EXPORTS #define BELLESIP_EXPORT __declspec(dllexport) #define BELLESIP_VAR_EXPORT __declspec(dllexport) #else #define BELLESIP_EXPORT #define BELLESIP_VAR_EXPORT extern __declspec(dllimport) #endif #else #define BELLESIP_VAR_EXPORT extern #define BELLESIP_EXPORT extern #endif #define BELLESIP_UNUSED(a) (void)a; #undef TRUE #define TRUE 1 #undef FALSE #define FALSE 0 #endif belle-sip-1.4.1/include/belle-sip/dialog.h000066400000000000000000000124051252242224000202750ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_dialog_h #define belle_sip_dialog_h enum belle_sip_dialog_state{ BELLE_SIP_DIALOG_NULL, BELLE_SIP_DIALOG_EARLY, BELLE_SIP_DIALOG_CONFIRMED, BELLE_SIP_DIALOG_TERMINATED }; typedef enum belle_sip_dialog_state belle_sip_dialog_state_t; BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT const char* belle_sip_dialog_state_to_string(const belle_sip_dialog_state_t state); BELLESIP_EXPORT belle_sip_request_t *belle_sip_dialog_create_ack(belle_sip_dialog_t *dialog, unsigned int cseq); /** * Create a request part of this dialog. **/ BELLESIP_EXPORT belle_sip_request_t *belle_sip_dialog_create_request(belle_sip_dialog_t *dialog, const char *method); /** * Create a request within a dialog keeping non system header from an initial request. This function is very useful to resend request after expiration or chalenge. * @param obj dialog associated to the request * @param initial_req, all headers + body are re-used from this request except: Via,From, To, Allows, CSeq, Call-ID, Max-Forwards * */ BELLESIP_EXPORT belle_sip_request_t * belle_sip_dialog_create_request_from(belle_sip_dialog_t *obj, const belle_sip_request_t *initial_req); /** * Create a new request part of this dialog. If dialog is busy (pending transaction), the request can be created anyway and will be sent by the transaction * when the dialog becomes available. **/ BELLESIP_EXPORT belle_sip_request_t * belle_sip_dialog_create_queued_request(belle_sip_dialog_t *obj, const char *method); /** * Create a new request part of this dialog keeping non system header from an initial request. If dialog is busy (pending transaction), the request can be created anyway and will be sent by the transaction * when the dialog becomes available. * @param obj dialog associated to the request * @param initial_req, all headers + body are re-used from this request except: Via,From, To, Allows, CSeq, Call-ID, Max-Forwards **/ BELLESIP_EXPORT belle_sip_request_t *belle_sip_dialog_create_queued_request_from(belle_sip_dialog_t *obj, const belle_sip_request_t *initial_req); BELLESIP_EXPORT void belle_sip_dialog_delete(belle_sip_dialog_t *dialog); BELLESIP_EXPORT void *belle_sip_dialog_get_application_data(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT void belle_sip_dialog_set_application_data(belle_sip_dialog_t *dialog, void *data); BELLESIP_EXPORT const char *belle_sip_dialog_get_dialog_id(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT const belle_sip_header_call_id_t *belle_sip_dialog_get_call_id(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT const belle_sip_header_address_t *belle_sip_dialog_get_local_party(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT const belle_sip_header_address_t *belle_sip_dialog_get_remote_party(const belle_sip_dialog_t *dialog); /** * get the value of the last cseq used to issue a request * @return local cseq **/ BELLESIP_EXPORT unsigned int belle_sip_dialog_get_local_seq_number(const belle_sip_dialog_t *dialog); unsigned int belle_sip_dialog_get_remote_seq_number(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT const char *belle_sip_dialog_get_local_tag(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT const char *belle_sip_dialog_get_remote_tag(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT const belle_sip_header_address_t *belle_sip_dialog_get_remote_target(belle_sip_dialog_t *dialog); BELLESIP_EXPORT const belle_sip_list_t* belle_sip_dialog_get_route_set(belle_sip_dialog_t *dialog); BELLESIP_EXPORT belle_sip_dialog_state_t belle_sip_dialog_get_state(const belle_sip_dialog_t *dialog); /** * return the dialog state before last transition. Can be useful to detect early avorted dialogs * @param dialog * @returns state **/ BELLESIP_EXPORT belle_sip_dialog_state_t belle_sip_dialog_get_previous_state(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT int belle_sip_dialog_is_server(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT int belle_sip_dialog_is_secure(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT void belle_sip_dialog_send_ack(belle_sip_dialog_t *dialog, belle_sip_request_t *request); BELLESIP_EXPORT void belle_sip_dialog_terminate_on_bye(belle_sip_dialog_t *dialog, int val); /** * Give access to the last transaction processed by a dialog. Can be useful to get reason code for dialog terminated before reaching established state * @param dialog * @return last transaction */ BELLESIP_EXPORT belle_sip_transaction_t* belle_sip_dialog_get_last_transaction(const belle_sip_dialog_t *dialog); BELLESIP_EXPORT int belle_sip_dialog_request_pending(const belle_sip_dialog_t *dialog); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/dict.h000066400000000000000000000116471252242224000177700ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef DICT_H #define DICT_H #ifndef WIN32 #include #endif #include "belle-sip/object.h" BELLE_SIP_BEGIN_DECLS typedef struct belle_sip_dict belle_sip_dict_t; #define BELLE_SIP_DICT(obj) BELLE_SIP_CAST(obj,belle_sip_dict_t) /** * @brief belle_sip_dict_create * @return an instance of a belle_sip_dict_t object. * @note The object is not owned by default. * @note all belle_sip_dict_set_* functions will overwrite existing values. */ BELLESIP_EXPORT belle_sip_dict_t* belle_sip_dict_create(); /** * @brief belle_sip_dict_set_int stores an integer into the dictionary * @param obj the dictionary instance * @param key the name of the integer to store * @param value value to store */ BELLESIP_EXPORT void belle_sip_dict_set_int(belle_sip_dict_t* obj, const char* key, int value); /** * @brief belle_sip_dict_get_int retrieves an integer from the dictionary * @param obj the dictionary instance * @param key name of the integer to retrieve * @param default_value value to return if the key is not found * @return the searched integer if the key exists, default_value if not found */ BELLESIP_EXPORT int belle_sip_dict_get_int(belle_sip_dict_t* obj, const char* key, int default_value); /** * @brief belle_sip_dict_set_string stores a string into the dictionary * @param obj the dictionary instance * @param key the name of the string to store * @param value value to store */ BELLESIP_EXPORT void belle_sip_dict_set_string(belle_sip_dict_t* obj, const char* key, const char*value); /** * @brief belle_sip_dict_get_string retrieves a string from the dictionary * @param obj the dictionary instance * @param key the name of the string to retrieve * @param default_value * @return the searched string if the key exists, default_value if not found */ BELLESIP_EXPORT const char* belle_sip_dict_get_string(belle_sip_dict_t* obj, const char* key, const char* default_value); /** * @brief belle_sip_dict_set_int64 stores an int64 in the dictionary * @param obj the dictionary instance * @param key the name of the integer to store * @param value value to store */ BELLESIP_EXPORT void belle_sip_dict_set_int64(belle_sip_dict_t* obj, const char* key, int64_t value); /** * @brief belle_sip_dict_get_int64 retrieves an int64 from the dictionary * @param obj the dictionary instance * @param key the name of the integer to retrieve * @param default_value value to return if the key is not found * @return the searched int64 if the key exists, default_value if not found */ BELLESIP_EXPORT int64_t belle_sip_dict_get_int64(belle_sip_dict_t* obj, const char* key, int64_t default_value); /** * @brief belle_sip_dict_remove will erase the value for a key * @param obj the dictionary instance * @param key the name of the integer to remove * @return 0 if the key was found, 1 otherwise */ BELLESIP_EXPORT int belle_sip_dict_remove(belle_sip_dict_t* obj, const char* key); /** * @brief belle_sip_dict_clear will clear the object's dictionary. * @param obj the dictionary instance */ BELLESIP_EXPORT void belle_sip_dict_clear(belle_sip_dict_t* obj); /** * Clones the source dictionary into the dst dictionary. The dst dictionary is cleared before the cloning * is done. * @param src source dictionary * @param dst destination dictionary */ BELLESIP_EXPORT void belle_sip_dict_clone( const belle_sip_dict_t* src, belle_sip_dict_t* dst); /** * Merge the source dictionary into the destination dictionary. * * Same function as #belle_sip_dict_clone, except the destination dictionary is not cleared before inserting the source data. * This overwrites common keys, and keeps existing keys. */ BELLESIP_EXPORT void belle_sip_dict_merge( const belle_sip_dict_t* src, belle_sip_dict_t* dst); /** * @brief belle_sip_dict_haskey tells if a key exists in the dictionary. * @param obj the dictionary instance * @param key the key to look for * @return 1 if the key exists, 0 otherwise * @todo create unit test */ BELLESIP_EXPORT int belle_sip_dict_haskey(const belle_sip_dict_t* obj, const char* key); /** * Apply a function for all keys stored in the dictionary */ BELLESIP_EXPORT void belle_sip_dict_foreach(const belle_sip_dict_t* obj, void (*apply_func)(const char*, void*, void*), void* userdata); BELLE_SIP_END_DECLS #endif // DICT_H belle-sip-1.4.1/include/belle-sip/generic-uri.h000066400000000000000000000106071252242224000212510ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL, Grenoble, France This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_GENERIC_URI_H_ #define BELLE_GENERIC_URI_H_ #include "belle-sip/defs.h" #include "belle-sip/list.h" #include "belle-sip/utils.h" BELLE_SIP_BEGIN_DECLS /** * */ BELLESIP_EXPORT belle_generic_uri_t* belle_generic_uri_new(); /** * */ BELLESIP_EXPORT belle_generic_uri_t* belle_generic_uri_parse (const char* uri); /* * Returns the host part of this uri. * */ BELLESIP_EXPORT const char* belle_generic_uri_get_host(const belle_generic_uri_t* uri) ; /** * Returns the value of the maddr parameter, or null if this is not set. * */ BELLESIP_EXPORT int belle_generic_uri_get_port(const belle_generic_uri_t* uri) ; /** * Returns the port of the uri, if not specified in the uri returns the well known port according to the transport. **/ BELLESIP_EXPORT int belle_generic_uri_get_listening_port(const belle_generic_uri_t *uri); /** * Returns the user part of this URI. * */ BELLESIP_EXPORT const char* belle_generic_uri_get_user(const belle_generic_uri_t* uri) ; /** * Gets user password of uri, or null if it is not set. * */ BELLESIP_EXPORT const char* belle_generic_uri_get_user_password(const belle_generic_uri_t* uri) ; /** * * Returns uri scheme. * */ BELLESIP_EXPORT const char* belle_generic_uri_get_scheme(const belle_generic_uri_t* uri) ; /** * * Returns uri path. * */ BELLESIP_EXPORT const char* belle_generic_uri_get_path(const belle_generic_uri_t* uri) ; /** * * Returns uri query. * */ BELLESIP_EXPORT const char* belle_generic_uri_get_query(const belle_generic_uri_t* uri) ; /** * Removes the port part of this uri. * */ BELLESIP_EXPORT void belle_generic_uri_remove_port(belle_generic_uri_t* uri) ; /** * Set the host part of this uri to the newly supplied host parameter. * */ BELLESIP_EXPORT void belle_generic_uri_set_host(belle_generic_uri_t* uri,const char*host) ; /** * Set the port part of this uri to the newly supplied port parameter. * */ BELLESIP_EXPORT void belle_generic_uri_set_port(belle_generic_uri_t* uri, int port) ; /** * Sets the scheme of this URI . * */ BELLESIP_EXPORT void belle_generic_uri_set_scheme(belle_generic_uri_t* uri,const char* scheme) ; /** * Sets the path of this URI . * */ BELLESIP_EXPORT void belle_generic_uri_set_path(belle_generic_uri_t* uri,const char* scheme) ; /** * Sets the query of this URI . * */ BELLESIP_EXPORT void belle_generic_uri_set_query(belle_generic_uri_t* uri,const char* scheme) ; /** * Sets the user of uri. * */ BELLESIP_EXPORT void belle_generic_uri_set_user(belle_generic_uri_t* uri,const char*user) ; /** * Sets the user password associated with the user of uri. * */ BELLESIP_EXPORT void belle_generic_uri_set_user_password(belle_generic_uri_t* uri,const char*userPassword) ; /** * This method returns the URI as a string. * */ BELLESIP_EXPORT char* belle_generic_uri_to_string(belle_generic_uri_t* uri) ; BELLESIP_EXPORT belle_sip_error_code belle_generic_uri_marshal(const belle_generic_uri_t* uri, char* buff, size_t buff_size, size_t *offset); /** * gets opaque part of this uri if hierarchies part not detected. * */ BELLESIP_EXPORT const char* belle_generic_uri_get_opaque_part(const belle_generic_uri_t* uri) ; /** * sets opaque part of this uri. Means hierarchies part is ignored if present. * */ BELLESIP_EXPORT void belle_generic_uri_set_opaque_part(belle_generic_uri_t* uri,const char * opaque_part) ; #define BELLE_GENERIC_URI(obj) BELLE_SIP_CAST(obj,belle_generic_uri_t) BELLE_SIP_END_DECLS #endif /* belle_generic_uri_H_ */ belle-sip-1.4.1/include/belle-sip/headers.h000066400000000000000000001165651252242224000204650ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef HEADERS_H_ #define HEADERS_H_ #include "belle-sip/defs.h" #include "belle-sip/sip-uri.h" #include "belle-sip/generic-uri.h" #include "belle-sip/utils.h" #include "belle-sip/parameters.h" #include BELLE_SIP_BEGIN_DECLS /*************************************************************************************** * header address * **************************************************************************************/ typedef struct _belle_sip_header_address belle_sip_header_address_t; BELLESIP_EXPORT belle_sip_header_address_t* belle_sip_header_address_new(); /* * creates an address from a display name and an uri * Note the uri not copied but only its ref count is incremented * @param display display name. May be null. * @param uri uri set to the newly created header_address * @return * */ BELLESIP_EXPORT belle_sip_header_address_t* belle_sip_header_address_create(const char* display, belle_sip_uri_t* uri); /* * creates an address from a display name and an absolute uri * Note the uri not copied but only its ref count is incremented * @param display display name. May be null. * @param uri uri set to the newly created header_address * @return * */ BELLESIP_EXPORT belle_sip_header_address_t* belle_sip_header_address_create2(const char* display, belle_generic_uri_t* uri); BELLESIP_EXPORT belle_sip_header_address_t* belle_sip_header_address_parse (const char* address) ; /** * returns a sip uri. A header address cannot have both a sip uri and an absolute uri. */ BELLESIP_EXPORT belle_sip_uri_t* belle_sip_header_address_get_uri(const belle_sip_header_address_t* address); /** * set an absolute uri. A header address cannot have both a sip uri and an absolute uri. This function also to absolute uri to NULL */ BELLESIP_EXPORT void belle_sip_header_address_set_uri(belle_sip_header_address_t* address, belle_sip_uri_t* uri); /** * returns an absolute uri. A header address cannot have both a sip uri and an absolute uri. */ BELLESIP_EXPORT belle_generic_uri_t* belle_sip_header_address_get_absolute_uri(const belle_sip_header_address_t* address); /** * set an absolute uri. A header address cannot have both a sip uri and an absolute uri. This function also to uri to NULL */ BELLESIP_EXPORT void belle_sip_header_address_set_absolute_uri(belle_sip_header_address_t* address, belle_generic_uri_t* uri); /** * */ BELLESIP_EXPORT const char* belle_sip_header_address_get_displayname(const belle_sip_header_address_t* address); /** * */ BELLESIP_EXPORT void belle_sip_header_address_set_displayname(belle_sip_header_address_t* address, const char* uri); #define BELLE_SIP_HEADER_ADDRESS(t) BELLE_SIP_CAST(t,belle_sip_header_address_t) /*************************************************************************************** * header common * **************************************************************************************/ BELLESIP_EXPORT belle_sip_header_t* belle_sip_header_parse (const char* header); BELLESIP_EXPORT belle_sip_header_t* belle_sip_header_create (const char* name,const char* value); BELLESIP_EXPORT belle_sip_header_t* belle_http_header_create (const char* name,const char* value); BELLESIP_EXPORT const char* belle_sip_header_get_name (const belle_sip_header_t* obj); BELLESIP_EXPORT void belle_sip_header_set_name (belle_sip_header_t* obj,const char* value); BELLESIP_EXPORT belle_sip_error_code belle_sip_header_marshal(belle_sip_header_t* header, char* buff, size_t buff_size, size_t *offset); BELLESIP_EXPORT const char *belle_sip_header_get_unparsed_value(belle_sip_header_t* obj); #define BELLE_SIP_HEADER(t) BELLE_SIP_CAST(t,belle_sip_header_t) /****************************** * * Allow header inherit from header * ******************************/ typedef struct _belle_sip_header_allow belle_sip_header_allow_t; belle_sip_header_allow_t* belle_sip_header_allow_new(); BELLESIP_EXPORT belle_sip_header_allow_t* belle_sip_header_allow_parse (const char* allow) ; BELLESIP_EXPORT belle_sip_header_allow_t* belle_sip_header_allow_create (const char* methods) ; BELLESIP_EXPORT const char* belle_sip_header_allow_get_method(const belle_sip_header_allow_t* allow); BELLESIP_EXPORT void belle_sip_header_allow_set_method(belle_sip_header_allow_t* allow,const char* method); #define BELLE_SIP_HEADER_ALLOW(t) BELLE_SIP_CAST(t,belle_sip_header_allow_t) #define BELLE_SIP_ALLOW "Allow" /*********************** * Contact header object ************************/ typedef struct _belle_sip_header_contact belle_sip_header_contact_t; BELLESIP_EXPORT belle_sip_header_contact_t* belle_sip_header_contact_new(); BELLESIP_EXPORT belle_sip_header_contact_t* belle_sip_header_contact_parse (const char* contact) ; BELLESIP_EXPORT belle_sip_header_contact_t* belle_sip_header_contact_create (const belle_sip_header_address_t* contact) ; /** * Returns the value of the expires parameter or -1 if no expires parameter was specified or if the parameter value cannot be parsed as an int. *@returns value of the expires parameter measured in delta-seconds, O implies removal of Registration specified in Contact Header. * */ BELLESIP_EXPORT int belle_sip_header_contact_get_expires(const belle_sip_header_contact_t* contact); /** * Returns the value of the q-value parameter of this ContactHeader. The q-value parameter indicates the relative preference amongst a set of locations. q-values are decimal numbers from 0 to 1, with higher values indicating higher preference. * @return the q-value parameter of this ContactHeader, -1 if the q-value is not set. */ BELLESIP_EXPORT float belle_sip_header_contact_get_qvalue(const belle_sip_header_contact_t* contact); /** * Returns a boolean value that indicates if the contact header has the format of Contact: *. * @return true if this is a wildcard address, false otherwise. */ BELLESIP_EXPORT unsigned int belle_sip_header_contact_is_wildcard(const belle_sip_header_contact_t* contact); /** * */ BELLESIP_EXPORT int belle_sip_header_contact_set_expires(belle_sip_header_contact_t* contact, int expires); /** * Sets the qValue value of the Name Address. */ BELLESIP_EXPORT int belle_sip_header_contact_set_qvalue(belle_sip_header_contact_t* contact, float qvalue); /** * Sets a wildcard on this contact address that is "*" is assigned to the contact header so that the header will have the format of Contact: *. * */ BELLESIP_EXPORT void belle_sip_header_contact_set_wildcard(belle_sip_header_contact_t* contact,unsigned int is_wildcard); /** Contact heaader equality function * @return 0 if not equals * * */ BELLESIP_EXPORT unsigned int belle_sip_header_contact_equals(const belle_sip_header_contact_t* a,const belle_sip_header_contact_t* b); /** Contact heaader equality function, same as #belle_sip_header_contact_equals but return 0 if equals, very useful with #belle_sip_list * @return 0 if equals * * */ BELLESIP_EXPORT unsigned int belle_sip_header_contact_not_equals(const belle_sip_header_contact_t* a,const belle_sip_header_contact_t* b); /** * Enable automatic filling of the contact ip, port and transport according to the channel that sends this message. **/ BELLESIP_EXPORT void belle_sip_header_contact_set_automatic(belle_sip_header_contact_t *a, int enabled); BELLESIP_EXPORT int belle_sip_header_contact_get_automatic(const belle_sip_header_contact_t *a); /** * Indicates whether a contact in automatic mode (see belle_sip_header_contact_set_automatic()) could be filled properly when the message was sent. * If a message is sent through a connection that has just been initiated, public IP and port are unknown, they will be learned after receiving the first response. * This can be used by the upper layer to decide to resubmit the request. **/ BELLESIP_EXPORT int belle_sip_header_contact_is_unknown(const belle_sip_header_contact_t *a); #define BELLE_SIP_RANDOM_TAG ((const char*)-1) #define BELLE_SIP_HEADER_CONTACT(t) BELLE_SIP_CAST(t,belle_sip_header_contact_t) #define BELLE_SIP_CONTACT "Contact" /****************************** * From header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_from belle_sip_header_from_t; BELLESIP_EXPORT belle_sip_header_from_t* belle_sip_header_from_new(); BELLESIP_EXPORT belle_sip_header_from_t* belle_sip_header_from_create(const belle_sip_header_address_t* address, const char *tag); BELLESIP_EXPORT belle_sip_header_from_t* belle_sip_header_from_create2(const char *address, const char *tag); BELLESIP_EXPORT belle_sip_header_from_t* belle_sip_header_from_parse(const char* from) ; BELLESIP_EXPORT void belle_sip_header_from_set_tag(belle_sip_header_from_t* from, const char* tag); BELLESIP_EXPORT const char* belle_sip_header_from_get_tag(const belle_sip_header_from_t* from); BELLESIP_EXPORT void belle_sip_header_from_set_random_tag(belle_sip_header_from_t *obj); #define BELLE_SIP_HEADER_FROM(t) BELLE_SIP_CAST(t,belle_sip_header_from_t) #define BELLE_SIP_FROM "From" /****************************** * To header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_to belle_sip_header_to_t; BELLESIP_EXPORT belle_sip_header_to_t* belle_sip_header_to_new(); BELLESIP_EXPORT belle_sip_header_to_t* belle_sip_header_to_parse(const char* to) ; BELLESIP_EXPORT belle_sip_header_to_t* belle_sip_header_to_create(const belle_sip_header_address_t *address, const char *tag); BELLESIP_EXPORT belle_sip_header_to_t* belle_sip_header_to_create2(const char *address, const char *tag); BELLESIP_EXPORT void belle_sip_header_to_set_tag(belle_sip_header_to_t* from, const char* tag); BELLESIP_EXPORT const char* belle_sip_header_to_get_tag(const belle_sip_header_to_t* from); BELLESIP_EXPORT void belle_sip_header_to_set_random_tag(belle_sip_header_to_t *obj); #define BELLE_SIP_HEADER_TO(t) BELLE_SIP_CAST(t,belle_sip_header_to_t) #define BELLE_SIP_TO "To" /****************************** * Via header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_via belle_sip_header_via_t; BELLESIP_EXPORT belle_sip_header_via_t* belle_sip_header_via_new(); BELLESIP_EXPORT belle_sip_header_via_t* belle_sip_header_via_create(const char *host, int port, const char *transport, const char *branch); BELLESIP_EXPORT belle_sip_header_via_t* belle_sip_header_via_parse (const char* via) ; BELLESIP_EXPORT const char* belle_sip_header_via_get_branch(const belle_sip_header_via_t* via); BELLESIP_EXPORT const char* belle_sip_header_via_get_transport(const belle_sip_header_via_t* via); /** * Get lower case version of the transport * @return the lower case version of the transport if from tcp,udp,tls or dtls else, return the value from #belle_sip_header_via_get_transport */ BELLESIP_EXPORT const char* belle_sip_header_via_get_transport_lowercase(const belle_sip_header_via_t* via); BELLESIP_EXPORT const char* belle_sip_header_via_get_host(const belle_sip_header_via_t* via); BELLESIP_EXPORT int belle_sip_header_via_get_port(const belle_sip_header_via_t* via); BELLESIP_EXPORT int belle_sip_header_via_get_listening_port(const belle_sip_header_via_t *via); BELLESIP_EXPORT const char* belle_sip_header_via_get_maddr(const belle_sip_header_via_t* via); BELLESIP_EXPORT const char* belle_sip_header_via_get_protocol(const belle_sip_header_via_t* via); BELLESIP_EXPORT const char* belle_sip_header_via_get_received(const belle_sip_header_via_t* via); BELLESIP_EXPORT int belle_sip_header_via_get_rport(const belle_sip_header_via_t* via); BELLESIP_EXPORT int belle_sip_header_via_get_ttl(const belle_sip_header_via_t* via); BELLESIP_EXPORT void belle_sip_header_via_set_branch(belle_sip_header_via_t* via,const char* branch); BELLESIP_EXPORT void belle_sip_header_via_set_host(belle_sip_header_via_t* via, const char* host); BELLESIP_EXPORT int belle_sip_header_via_set_port(belle_sip_header_via_t* via,int port); BELLESIP_EXPORT void belle_sip_header_via_set_maddr(belle_sip_header_via_t* via, const char* maddr); BELLESIP_EXPORT void belle_sip_header_via_set_protocol(belle_sip_header_via_t* via, const char* protocol); BELLESIP_EXPORT void belle_sip_header_via_set_received(belle_sip_header_via_t* via, const char* received); BELLESIP_EXPORT int belle_sip_header_via_set_rport(belle_sip_header_via_t* via,int rport); BELLESIP_EXPORT void belle_sip_header_via_set_transport(belle_sip_header_via_t* via,const char* transport); BELLESIP_EXPORT int belle_sip_header_via_set_ttl(belle_sip_header_via_t* via, int ttl); #define BELLE_SIP_HEADER_VIA(t) BELLE_SIP_CAST(t,belle_sip_header_via_t) #define BELLE_SIP_VIA "Via" /****************************** * Call id object inherent from object * ******************************/ typedef struct _belle_sip_header_call_id belle_sip_header_call_id_t; BELLESIP_EXPORT belle_sip_header_call_id_t* belle_sip_header_call_id_new(); BELLESIP_EXPORT belle_sip_header_call_id_t* belle_sip_header_call_id_parse (const char* call_id) ; BELLESIP_EXPORT const char* belle_sip_header_call_id_get_call_id(const belle_sip_header_call_id_t* call_id); BELLESIP_EXPORT void belle_sip_header_call_id_set_call_id(belle_sip_header_call_id_t* call_id,const char* id); unsigned int belle_sip_header_call_id_equals(const belle_sip_header_call_id_t* a,const belle_sip_header_call_id_t* b); #define BELLE_SIP_HEADER_CALL_ID(t) BELLE_SIP_CAST(t,belle_sip_header_call_id_t) #define BELLE_SIP_CALL_ID "Call-ID" /****************************** * cseq object inherent from object * ******************************/ typedef struct _belle_sip_header_cseq belle_sip_header_cseq_t; BELLESIP_EXPORT belle_sip_header_cseq_t* belle_sip_header_cseq_new(); BELLESIP_EXPORT belle_sip_header_cseq_t* belle_sip_header_cseq_create(unsigned int number, const char *method); BELLESIP_EXPORT belle_sip_header_cseq_t* belle_sip_header_cseq_parse (const char* cseq) ; BELLESIP_EXPORT const char* belle_sip_header_cseq_get_method(const belle_sip_header_cseq_t* cseq); BELLESIP_EXPORT void belle_sip_header_cseq_set_method(belle_sip_header_cseq_t* cseq,const char* method); BELLESIP_EXPORT unsigned int belle_sip_header_cseq_get_seq_number(const belle_sip_header_cseq_t* cseq); BELLESIP_EXPORT void belle_sip_header_cseq_set_seq_number(belle_sip_header_cseq_t* cseq,unsigned int seq_number); #define BELLE_SIP_HEADER_CSEQ(t) BELLE_SIP_CAST(t,belle_sip_header_cseq_t) #define BELLE_SIP_CSEQ "CSeq" /****************************** * content type object inherent from parameters * ******************************/ typedef struct _belle_sip_header_content_type belle_sip_header_content_type_t; BELLESIP_EXPORT belle_sip_header_content_type_t* belle_sip_header_content_type_new(); BELLESIP_EXPORT belle_sip_header_content_type_t* belle_sip_header_content_type_parse (const char* content_type) ; BELLESIP_EXPORT belle_sip_header_content_type_t* belle_sip_header_content_type_create (const char* type,const char* sub_type) ; BELLESIP_EXPORT belle_sip_header_content_type_t* belle_sip_header_content_type_parse (const char* content_type) ; BELLESIP_EXPORT const char* belle_sip_header_content_type_get_type(const belle_sip_header_content_type_t* content_type); BELLESIP_EXPORT void belle_sip_header_content_type_set_type(belle_sip_header_content_type_t* content_type,const char* type); BELLESIP_EXPORT const char* belle_sip_header_content_type_get_subtype(const belle_sip_header_content_type_t* content_type); BELLESIP_EXPORT void belle_sip_header_content_type_set_subtype(belle_sip_header_content_type_t* content_type,const char* sub_type); #define BELLE_SIP_HEADER_CONTENT_TYPE(t) BELLE_SIP_CAST(t,belle_sip_header_content_type_t) #define BELLE_SIP_CONTENT_TYPE "Content-Type" /****************************** * * Expires inherit from header * ******************************/ typedef struct _belle_sip_header_expires belle_sip_header_expires_t; BELLESIP_EXPORT belle_sip_header_expires_t* belle_sip_header_expires_new(); BELLESIP_EXPORT belle_sip_header_expires_t* belle_sip_header_expires_parse (const char* expires) ; BELLESIP_EXPORT int belle_sip_header_expires_get_expires(const belle_sip_header_expires_t* expires); BELLESIP_EXPORT void belle_sip_header_expires_set_expires(belle_sip_header_expires_t* expires,int value); BELLESIP_EXPORT int belle_sip_header_expires_decrement_expires(belle_sip_header_expires_t* expires); BELLESIP_EXPORT belle_sip_header_expires_t* belle_sip_header_expires_create(int expires); #define BELLE_SIP_HEADER_EXPIRES(t) BELLE_SIP_CAST(t,belle_sip_header_expires_t) #define BELLE_SIP_EXPIRES "Expires" /****************************** * Route header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_route belle_sip_header_route_t; BELLESIP_EXPORT belle_sip_header_route_t* belle_sip_header_route_new(); BELLESIP_EXPORT belle_sip_header_route_t* belle_sip_header_route_parse (const char* route) ; BELLESIP_EXPORT belle_sip_header_route_t* belle_sip_header_route_create(const belle_sip_header_address_t* route); #define BELLE_SIP_HEADER_ROUTE(t) BELLE_SIP_CAST(t,belle_sip_header_route_t) #define BELLE_SIP_ROUTE "Route" /****************************** * Record route header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_record_route belle_sip_header_record_route_t; BELLESIP_EXPORT belle_sip_header_record_route_t* belle_sip_header_record_route_new(); BELLESIP_EXPORT belle_sip_header_record_route_t* belle_sip_header_record_route_parse (const char* route); BELLESIP_EXPORT belle_sip_header_record_route_t* belle_sip_header_record_route_new_auto_outgoing(); BELLESIP_EXPORT unsigned char belle_sip_header_record_route_get_auto_outgoing(const belle_sip_header_record_route_t *a); #define BELLE_SIP_HEADER_RECORD_ROUTE(t) BELLE_SIP_CAST(t,belle_sip_header_record_route_t) #define BELLE_SIP_RECORD_ROUTE "Record-route" /****************************** * Service route header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_service_route belle_sip_header_service_route_t; BELLESIP_EXPORT belle_sip_header_service_route_t* belle_sip_header_service_route_new(); BELLESIP_EXPORT belle_sip_header_service_route_t* belle_sip_header_service_route_parse (const char* route) ; #define BELLE_SIP_HEADER_SERVICE_ROUTE(t) BELLE_SIP_CAST(t,belle_sip_header_service_route_t) #define BELLE_SIP_SERVICE_ROUTE "Service-route" /****************************** * * user-Agent header inherit from header * ******************************/ typedef struct _belle_sip_header_user_agent belle_sip_header_user_agent_t; BELLESIP_EXPORT belle_sip_header_user_agent_t* belle_sip_header_user_agent_new(); BELLESIP_EXPORT belle_sip_header_user_agent_t* belle_sip_header_user_agent_parse (const char* user_agent) ; BELLESIP_EXPORT belle_sip_list_t* belle_sip_header_user_agent_get_products(const belle_sip_header_user_agent_t* user_agent); /** * concatenates products * @param user_agent [in] user agent header * @param value [out]buffer where to put result in * @param value_size [in] size of the buffer * @return number of written characters or -1 inca se of error; */ BELLESIP_EXPORT int belle_sip_header_user_agent_get_products_as_string(const belle_sip_header_user_agent_t* user_agent,char* value,unsigned int value_size); BELLESIP_EXPORT void belle_sip_header_user_agent_set_products(belle_sip_header_user_agent_t* user_agent,belle_sip_list_t* value); BELLESIP_EXPORT void belle_sip_header_user_agent_add_product(belle_sip_header_user_agent_t* user_agent,const char* product); #define BELLE_SIP_HEADER_USER_AGENT(t) BELLE_SIP_CAST(t,belle_sip_header_user_agent_t) #define BELLE_SIP_USER_AGENT "User-Agent" /****************************** * Content length inherent from object * ******************************/ typedef struct _belle_sip_header_content_length belle_sip_header_content_length_t; BELLESIP_EXPORT belle_sip_header_content_length_t* belle_sip_header_content_length_new(); BELLESIP_EXPORT belle_sip_header_content_length_t* belle_sip_header_content_length_parse (const char* content_length) ; BELLESIP_EXPORT belle_sip_header_content_length_t* belle_sip_header_content_length_create (int content_length) ; BELLESIP_EXPORT unsigned int belle_sip_header_content_length_get_content_length(const belle_sip_header_content_length_t* content_length); BELLESIP_EXPORT void belle_sip_header_content_length_set_content_length(belle_sip_header_content_length_t* content_length,unsigned int length); #define BELLE_SIP_HEADER_CONTENT_LENGTH(t) BELLE_SIP_CAST(t,belle_sip_header_content_length_t) #define BELLE_SIP_CONTENT_LENGTH "Content-Length" /****************************** * authorization header inherit from parameters * ******************************/ typedef struct _belle_sip_header_authorization belle_sip_header_authorization_t; BELLESIP_EXPORT belle_sip_header_authorization_t* belle_sip_header_authorization_new(); BELLESIP_EXPORT belle_sip_header_authorization_t* belle_sip_header_authorization_parse(const char* authorization); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_algorithm(const belle_sip_header_authorization_t* authorization ); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_cnonce(const belle_sip_header_authorization_t* authorization ); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_nonce(const belle_sip_header_authorization_t* authorization); /*convert nonce count as string id present * @return 0 in case of success * */ BELLESIP_EXPORT int belle_sip_header_authorization_get_nonce_count_as_string(const belle_sip_header_authorization_t* authorization,char nounce_count[9]); BELLESIP_EXPORT int belle_sip_header_authorization_get_nonce_count(const belle_sip_header_authorization_t* authorization); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_opaque(const belle_sip_header_authorization_t* authorization); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_qop(const belle_sip_header_authorization_t* authorization); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_realm(const belle_sip_header_authorization_t* authorization); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_response(const belle_sip_header_authorization_t* authorization); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_scheme(const belle_sip_header_authorization_t* authorization); BELLESIP_EXPORT belle_sip_uri_t* belle_sip_header_authorization_get_uri(const belle_sip_header_authorization_t* authorization); BELLESIP_EXPORT const char* belle_sip_header_authorization_get_username(const belle_sip_header_authorization_t* authorization); BELLESIP_EXPORT void belle_sip_header_authorization_set_algorithm(belle_sip_header_authorization_t* authorization, const char* algorithm); BELLESIP_EXPORT void belle_sip_header_authorization_set_cnonce(belle_sip_header_authorization_t* authorization, const char* cNonce); BELLESIP_EXPORT void belle_sip_header_authorization_set_nonce(belle_sip_header_authorization_t* authorization, const char* nonce); BELLESIP_EXPORT void belle_sip_header_authorization_set_nonce_count(belle_sip_header_authorization_t* authorization, int nonceCount); BELLESIP_EXPORT void belle_sip_header_authorization_set_opaque(belle_sip_header_authorization_t* authorization, const char* opaque); BELLESIP_EXPORT void belle_sip_header_authorization_set_qop(belle_sip_header_authorization_t* authorization, const char* qop); BELLESIP_EXPORT void belle_sip_header_authorization_add_qop(belle_sip_header_authorization_t* authorization, const char* qop); BELLESIP_EXPORT void belle_sip_header_authorization_set_realm(belle_sip_header_authorization_t* authorization, const char* realm); BELLESIP_EXPORT void belle_sip_header_authorization_set_response(belle_sip_header_authorization_t* authorization, const char* response); BELLESIP_EXPORT void belle_sip_header_authorization_set_scheme(belle_sip_header_authorization_t* authorization, const char* scheme); BELLESIP_EXPORT void belle_sip_header_authorization_set_uri(belle_sip_header_authorization_t* authorization, belle_sip_uri_t* uri); BELLESIP_EXPORT void belle_sip_header_authorization_set_username(belle_sip_header_authorization_t* authorization, const char* username); #define BELLE_SIP_HEADER_AUTHORIZATION(t) BELLE_SIP_CAST(t,belle_sip_header_authorization_t) #define BELLE_SIP_AUTHORIZATION "Authorization" /******************************* * proxy_authorization inherit from Authorization */ typedef struct _belle_sip_header_proxy_authorization belle_sip_header_proxy_authorization_t; BELLESIP_EXPORT belle_sip_header_proxy_authorization_t* belle_sip_header_proxy_authorization_new(); BELLESIP_EXPORT belle_sip_header_proxy_authorization_t* belle_sip_header_proxy_authorization_parse(const char* proxy_authorization); #define BELLE_SIP_HEADER_PROXY_AUTHORIZATION(t) BELLE_SIP_CAST(t,belle_sip_header_proxy_authorization_t) #define BELLE_SIP_PROXY_AUTHORIZATION "Proxy-Authorization" /******************************* * http_authorization inherit from Authorization */ typedef struct _belle_http_header_authorization belle_http_header_authorization_t; BELLESIP_EXPORT belle_http_header_authorization_t* belle_http_header_authorization_new(); /*cannot be parsed for now BELLESIP_EXPORT belle_http_header_authorization_t* belle_http_header_authorization_parse(const char* proxy_authorization); */ BELLESIP_EXPORT void belle_http_header_authorization_set_uri(belle_http_header_authorization_t* authorization, belle_generic_uri_t* uri); BELLESIP_EXPORT belle_generic_uri_t* belle_http_header_authorization_get_uri(const belle_http_header_authorization_t* authorization); #define BELLE_HTTP_HEADER_AUTHORIZATION(t) BELLE_SIP_CAST(t,belle_http_header_authorization_t) #define BELLE_HTTP_AUTHORIZATION "Authorization" /******************************* * www_authenticate inherit from parameters */ typedef struct _belle_sip_header_www_authenticate belle_sip_header_www_authenticate_t; BELLESIP_EXPORT belle_sip_header_www_authenticate_t* belle_sip_header_www_authenticate_new(); BELLESIP_EXPORT belle_sip_header_www_authenticate_t* belle_sip_header_www_authenticate_parse(const char* www_authenticate); BELLESIP_EXPORT const char* belle_sip_header_www_authenticate_get_algorithm(const belle_sip_header_www_authenticate_t* www_authenticate ); BELLESIP_EXPORT const char* belle_sip_header_www_authenticate_get_nonce(const belle_sip_header_www_authenticate_t* www_authenticate); BELLESIP_EXPORT const char* belle_sip_header_www_authenticate_get_opaque(const belle_sip_header_www_authenticate_t* www_authenticate); BELLESIP_EXPORT belle_sip_list_t* belle_sip_header_www_authenticate_get_qop(const belle_sip_header_www_authenticate_t* www_authetication); BELLESIP_EXPORT const char* belle_sip_header_www_authenticate_get_qop_first(const belle_sip_header_www_authenticate_t* www_authetication); BELLESIP_EXPORT const char* belle_sip_header_www_authenticate_get_realm(const belle_sip_header_www_authenticate_t* www_authenticate); BELLESIP_EXPORT const char* belle_sip_header_www_authenticate_get_scheme(const belle_sip_header_www_authenticate_t* www_authenticate); BELLESIP_EXPORT const char* belle_sip_header_www_authenticate_get_domain(const belle_sip_header_www_authenticate_t* www_authenticate); BELLESIP_EXPORT unsigned int belle_sip_header_www_authenticate_is_stale(const belle_sip_header_www_authenticate_t* www_authenticate); BELLESIP_EXPORT void belle_sip_header_www_authenticate_set_algorithm(belle_sip_header_www_authenticate_t* www_authenticate, const char* algorithm); BELLESIP_EXPORT void belle_sip_header_www_authenticate_set_nonce(belle_sip_header_www_authenticate_t* www_authenticate, const char* nonce); BELLESIP_EXPORT void belle_sip_header_www_authenticate_set_opaque(belle_sip_header_www_authenticate_t* www_authenticate, const char* opaque); BELLESIP_EXPORT void belle_sip_header_www_authenticate_set_qop(belle_sip_header_www_authenticate_t* www_authentication, belle_sip_list_t* qop); BELLESIP_EXPORT void belle_sip_header_www_authenticate_add_qop(belle_sip_header_www_authenticate_t* www_authentication, const char* qop_param); BELLESIP_EXPORT void belle_sip_header_www_authenticate_set_realm(belle_sip_header_www_authenticate_t* www_authenticate, const char* realm); BELLESIP_EXPORT void belle_sip_header_www_authenticate_set_scheme(belle_sip_header_www_authenticate_t* www_authenticate, const char* scheme); BELLESIP_EXPORT void belle_sip_header_www_authenticate_set_domain(belle_sip_header_www_authenticate_t* www_authenticate,const char* domain); BELLESIP_EXPORT void belle_sip_header_www_authenticate_set_stale(belle_sip_header_www_authenticate_t* www_authenticate, unsigned int enable); #define BELLE_SIP_HEADER_WWW_AUTHENTICATE(t) BELLE_SIP_CAST(t,belle_sip_header_www_authenticate_t) #define BELLE_SIP_WWW_AUTHENTICATE "WWW-Authenticate" /******************************* * proxy_authenticate inherit from www_authenticate */ typedef struct _belle_sip_header_proxy_authenticate belle_sip_header_proxy_authenticate_t; BELLESIP_EXPORT belle_sip_header_proxy_authenticate_t* belle_sip_header_proxy_authenticate_new(); BELLESIP_EXPORT belle_sip_header_proxy_authenticate_t* belle_sip_header_proxy_authenticate_parse(const char* proxy_authenticate); #define BELLE_SIP_HEADER_PROXY_AUTHENTICATE(t) BELLE_SIP_CAST(t,belle_sip_header_proxy_authenticate_t) #define BELLE_SIP_PROXY_AUTHENTICATE "Proxy-Authenticate" /****************************** * * Max forward inherit from header * ******************************/ typedef struct _belle_sip_header_max_forwards belle_sip_header_max_forwards_t; BELLESIP_EXPORT belle_sip_header_max_forwards_t* belle_sip_header_max_forwards_new(); BELLESIP_EXPORT belle_sip_header_max_forwards_t* belle_sip_header_max_forwards_create(int value); BELLESIP_EXPORT belle_sip_header_max_forwards_t* belle_sip_header_max_forwards_parse (const char* max_forwards) ; BELLESIP_EXPORT int belle_sip_header_max_forwards_get_max_forwards(const belle_sip_header_max_forwards_t* max_forwards); BELLESIP_EXPORT void belle_sip_header_max_forwards_set_max_forwards(belle_sip_header_max_forwards_t* max_forwards,int value); BELLESIP_EXPORT int belle_sip_header_max_forwards_decrement_max_forwards(belle_sip_header_max_forwards_t* max_forwards); #define BELLE_SIP_HEADER_MAX_FORWARDS(t) BELLE_SIP_CAST(t,belle_sip_header_max_forwards_t) #define BELLE_SIP_MAX_FORWARDS "Max-Forwards" /****************************** * * Subscription state inherit from parameters * ******************************/ typedef struct _belle_sip_header_subscription_state belle_sip_header_subscription_state_t; BELLESIP_EXPORT belle_sip_header_subscription_state_t* belle_sip_header_subscription_state_new(); BELLESIP_EXPORT belle_sip_header_subscription_state_t* belle_sip_header_subscription_state_parse (const char* subscription_state) ; BELLESIP_EXPORT belle_sip_header_subscription_state_t* belle_sip_header_subscription_state_create (const char* subscription_state,int expires); BELLESIP_EXPORT const char* belle_sip_header_subscription_state_get_state(const belle_sip_header_subscription_state_t* subscription_state); BELLESIP_EXPORT int belle_sip_header_subscription_state_get_expires(const belle_sip_header_subscription_state_t* subscription_state); BELLESIP_EXPORT const char* belle_sip_header_subscription_state_get_reason(const belle_sip_header_subscription_state_t* subscription_state); BELLESIP_EXPORT int belle_sip_header_subscription_state_get_retry_after(const belle_sip_header_subscription_state_t* subscription_state); BELLESIP_EXPORT void belle_sip_header_subscription_state_set_state(belle_sip_header_subscription_state_t* subscription_state,const char* state); BELLESIP_EXPORT void belle_sip_header_subscription_state_set_expires(belle_sip_header_subscription_state_t* subscription_state,int expire); BELLESIP_EXPORT void belle_sip_header_subscription_state_set_reason(belle_sip_header_subscription_state_t* subscription_state, const char* reason); BELLESIP_EXPORT void belle_sip_header_subscription_state_set_retry_after(belle_sip_header_subscription_state_t* subscription_state, int retry_after ); #define BELLE_SIP_HEADER_SUBSCRIPTION_STATE(t) BELLE_SIP_CAST(t,belle_sip_header_subscription_state_t) #define BELLE_SIP_SUBSCRIPTION_STATE "Subscription-State" #define BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE "active" #define BELLE_SIP_SUBSCRIPTION_STATE_PENDING "pending" #define BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED "terminated" /****************************** * Refer-To header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_refer_to belle_sip_header_refer_to_t; BELLESIP_EXPORT belle_sip_header_refer_to_t* belle_sip_header_refer_to_new(); BELLESIP_EXPORT belle_sip_header_refer_to_t* belle_sip_header_refer_to_parse(const char* refer_to) ; BELLESIP_EXPORT belle_sip_header_refer_to_t* belle_sip_header_refer_to_create(const belle_sip_header_address_t *address); #define BELLE_SIP_HEADER_REFER_TO(t) BELLE_SIP_CAST(t,belle_sip_header_refer_to_t) #define BELLE_SIP_REFER_TO "Refer-To" /****************************** * Referred-by header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_referred_by belle_sip_header_referred_by_t; BELLESIP_EXPORT belle_sip_header_referred_by_t* belle_sip_header_referred_by_new(); BELLESIP_EXPORT belle_sip_header_referred_by_t* belle_sip_header_referred_by_parse(const char* referred_by) ; BELLESIP_EXPORT belle_sip_header_referred_by_t* belle_sip_header_referred_by_create(const belle_sip_header_address_t *address); #define BELLE_SIP_HEADER_REFERRED_BY(t) BELLE_SIP_CAST(t,belle_sip_header_referred_by_t) #define BELLE_SIP_REFERRED_BY "Referred-By" /****************************** * Replace header object inherent from parameters * ******************************/ typedef struct _belle_sip_header_replaces belle_sip_header_replaces_t; BELLESIP_EXPORT belle_sip_header_replaces_t* belle_sip_header_replaces_new(); BELLESIP_EXPORT belle_sip_header_replaces_t* belle_sip_header_replaces_parse(const char* replaces) ; BELLESIP_EXPORT belle_sip_header_replaces_t* belle_sip_header_replaces_create(const char* call_id,const char* from_tag,const char* to_tag); /* * Creates a Eeplaces header from an escaped value that can be found in Referred-by header * @param escaped_replace ex : 12345%40192.168.118.3%3Bto-tag%3D12345%3Bfrom-tag%3D5FFE-3994 * @return a newly allocated Replace header * */ BELLESIP_EXPORT belle_sip_header_replaces_t* belle_sip_header_replaces_create2(const char* escaped_replace); BELLESIP_EXPORT const char* belle_sip_header_replaces_get_call_id(const belle_sip_header_replaces_t* obj); BELLESIP_EXPORT const char* belle_sip_header_replaces_get_from_tag(const belle_sip_header_replaces_t* obj); BELLESIP_EXPORT const char* belle_sip_header_replaces_get_to_tag(const belle_sip_header_replaces_t* obj); BELLESIP_EXPORT void belle_sip_header_replaces_set_call_id(belle_sip_header_replaces_t* obj, const char* callid); BELLESIP_EXPORT void belle_sip_header_replaces_set_from_tag(belle_sip_header_replaces_t* obj,const char* from_tag); BELLESIP_EXPORT void belle_sip_header_replaces_set_to_tag(belle_sip_header_replaces_t* obj,const char* to_tag); /*return a newly allocated string with the content of the header value in escaped form. *
Purpose of this function is to be used to set Refer-To uri header Replaces * @param obj Replaces object * @return newly allocated string ex: 12345%40192.168.118.3%3Bto-tag%3D12345%3Bfrom-tag%3D5FFE-3994*/ BELLESIP_EXPORT char* belle_sip_header_replaces_value_to_escaped_string(const belle_sip_header_replaces_t* obj); #define BELLE_SIP_HEADER_REPLACES(t) BELLE_SIP_CAST(t,belle_sip_header_replaces_t) #define BELLE_SIP_REPLACES "Replaces" /******* * Date header *******/ typedef struct belle_sip_header_date belle_sip_header_date_t; BELLESIP_EXPORT belle_sip_header_date_t* belle_sip_header_date_new(); BELLESIP_EXPORT belle_sip_header_date_t* belle_sip_header_date_parse(const char* date) ; BELLESIP_EXPORT belle_sip_header_date_t* belle_sip_header_date_create_from_time(const time_t *utc_time); BELLESIP_EXPORT time_t belle_sip_header_date_get_time(belle_sip_header_date_t *obj); BELLESIP_EXPORT void belle_sip_header_date_set_time(belle_sip_header_date_t *obj, const time_t *utc_time); BELLESIP_EXPORT const char * belle_sip_header_date_get_date(const belle_sip_header_date_t *obj); BELLESIP_EXPORT void belle_sip_header_date_set_date(belle_sip_header_date_t *obj, const char *date); #define BELLE_SIP_HEADER_DATE(obj) BELLE_SIP_CAST(obj,belle_sip_header_date_t) #define BELLE_SIP_DATE "Date" /****************************** * P-Preferred-Identity header object inherent from header_address * ******************************/ typedef struct _belle_sip_header_p_preferred_identity belle_sip_header_p_preferred_identity_t; BELLESIP_EXPORT belle_sip_header_p_preferred_identity_t* belle_sip_header_p_preferred_identity_new(); BELLESIP_EXPORT belle_sip_header_p_preferred_identity_t* belle_sip_header_p_preferred_identity_parse(const char* p_preferred_identity) ; BELLESIP_EXPORT belle_sip_header_p_preferred_identity_t* belle_sip_header_p_preferred_identity_create(const belle_sip_header_address_t *address); #define BELLE_SIP_HEADER_P_PREFERRED_IDENTITY(t) BELLE_SIP_CAST(t,belle_sip_header_p_preferred_identity_t) #define BELLE_SIP_P_PREFERRED_IDENTITY "P-Preferred-Identity" /****************************** * Privacy header object inherent from header * ******************************/ typedef struct _belle_sip_header_privacy belle_sip_header_privacy_t; BELLESIP_EXPORT belle_sip_header_privacy_t* belle_sip_header_privacy_new(); BELLESIP_EXPORT belle_sip_header_privacy_t* belle_sip_header_privacy_parse(const char* privacy) ; BELLESIP_EXPORT belle_sip_header_privacy_t* belle_sip_header_privacy_create(const char* privacy); BELLESIP_EXPORT void belle_sip_header_privacy_add_privacy(belle_sip_header_privacy_t* privacy, const char* value); BELLESIP_EXPORT void belle_sip_header_privacy_set_privacy(belle_sip_header_privacy_t* privacy, belle_sip_list_t* privacy_values); BELLESIP_EXPORT belle_sip_list_t* belle_sip_header_privacy_get_privacy(const belle_sip_header_privacy_t* privacy); #define BELLE_SIP_HEADER_PRIVACY(t) BELLE_SIP_CAST(t,belle_sip_header_privacy_t) #define BELLE_SIP_PRIVACY "Privacy" /****************************** * Event header object inherent from parameters * ******************************/ typedef struct _belle_sip_header_event belle_sip_header_event_t; BELLESIP_EXPORT belle_sip_header_event_t* belle_sip_header_event_new(); BELLESIP_EXPORT belle_sip_header_event_t* belle_sip_header_event_parse(const char* event) ; BELLESIP_EXPORT belle_sip_header_event_t* belle_sip_header_event_create(const char* event); BELLESIP_EXPORT const char* belle_sip_header_event_get_package_name(const belle_sip_header_event_t* event); BELLESIP_EXPORT void belle_sip_header_event_set_package_name(belle_sip_header_event_t* event, const char* package_name); BELLESIP_EXPORT const char* belle_sip_header_event_get_id(const belle_sip_header_event_t* event); BELLESIP_EXPORT void belle_sip_header_event_set_id(belle_sip_header_event_t* event, const char* id); #define BELLE_SIP_HEADER_EVENT(t) BELLE_SIP_CAST(t,belle_sip_header_event_t) #define BELLE_SIP_EVENT "Event" BELLE_SIP_END_DECLS #endif /* HEADERS_H_ */ belle-sip-1.4.1/include/belle-sip/http-listener.h000066400000000000000000000045041252242224000216410ustar00rootroot00000000000000 /* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_http_listener_h #define belle_http_listener_h struct belle_http_response_event{ belle_sip_object_t *source; belle_http_request_t *request; belle_http_response_t *response; }; typedef struct belle_http_response_event belle_http_response_event_t; #define BELLE_HTTP_INTERFACE_FUNCS(argT) \ void (*process_response_headers)(argT *user_ctx, const belle_http_response_event_t *event); \ void (*process_response)(argT *user_ctx, const belle_http_response_event_t *event); \ void (*process_io_error)(argT *user_ctx, const belle_sip_io_error_event_t *event); \ void (*process_timeout)(argT *user_ctx, const belle_sip_timeout_event_t *event); \ void (*process_auth_requested)(argT *user_ctx, belle_sip_auth_event_t *event); BELLE_SIP_DECLARE_INTERFACE_BEGIN(belle_http_request_listener_t) BELLE_HTTP_INTERFACE_FUNCS(belle_http_request_listener_t) BELLE_SIP_DECLARE_INTERFACE_END struct belle_http_request_listener_callbacks{ BELLE_HTTP_INTERFACE_FUNCS(void) void (*listener_destroyed)(void *user_ctx); }; typedef struct belle_http_request_listener_callbacks belle_http_request_listener_callbacks_t; #define BELLE_HTTP_REQUEST_LISTENER(obj) BELLE_SIP_INTERFACE_CAST(obj,belle_http_request_listener_t) BELLE_SIP_BEGIN_DECLS /** * Creates an object implementing the belle_http_request_listener_t interface. * This object passes the events to the callbacks, providing also the user context. **/ BELLESIP_EXPORT belle_http_request_listener_t *belle_http_request_listener_create_from_callbacks(const belle_http_request_listener_callbacks_t *callbacks, void *user_ctx); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/http-message.h000066400000000000000000000051721252242224000214420ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_HTTP_MESSAGE_H #define BELLE_HTTP_MESSAGE_H #include "belle-sip/generic-uri.h" #define BELLE_HTTP_REQUEST(obj) BELLE_SIP_CAST(obj,belle_http_request_t) #define BELLE_HTTP_RESPONSE(obj) BELLE_SIP_CAST(obj,belle_http_response_t) BELLE_SIP_BEGIN_DECLS /** * Create an http request. * @param method * @param uri the http uri * @param ... optional list of belle_sip_header_t* to be included in the request, ending with NULL. */ BELLESIP_EXPORT belle_http_request_t *belle_http_request_create(const char *method, belle_generic_uri_t *uri, ...); BELLESIP_EXPORT belle_http_request_t* belle_http_request_new(); BELLESIP_EXPORT belle_http_request_t* belle_http_request_parse(const char* raw); BELLESIP_EXPORT int belle_http_request_is_cancelled(const belle_http_request_t *req); BELLESIP_EXPORT void belle_http_request_cancel(belle_http_request_t *req); BELLESIP_EXPORT belle_generic_uri_t* belle_http_request_get_uri(const belle_http_request_t* request); BELLESIP_EXPORT void belle_http_request_set_uri(belle_http_request_t* request, belle_generic_uri_t* uri); BELLESIP_EXPORT const char* belle_http_request_get_method(const belle_http_request_t* request); BELLESIP_EXPORT void belle_http_request_set_method(belle_http_request_t* request,const char* method); BELLESIP_EXPORT belle_http_response_t *belle_http_request_get_response(belle_http_request_t *req); /** * http response * */ BELLESIP_EXPORT int belle_http_response_get_status_code(const belle_http_response_t *response); BELLESIP_EXPORT void belle_http_response_set_status_code(belle_http_response_t *response,int status); BELLESIP_EXPORT const char* belle_http_response_get_reason_phrase(const belle_http_response_t *response); BELLESIP_EXPORT void belle_http_response_set_reason_phrase(belle_http_response_t *response,const char* reason_phrase); BELLESIP_EXPORT belle_http_response_t *belle_http_response_new(void); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/http-provider.h000066400000000000000000000025041252242224000216440ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_http_provider_h #define belle_sip_http_provider_h BELLE_SIP_BEGIN_DECLS #define BELLE_SIP_HTTP_PROVIDER(obj) BELLE_SIP_CAST(obj,belle_http_provider_t) BELLESIP_EXPORT int belle_http_provider_set_tls_verify_policy(belle_http_provider_t *obj, belle_tls_verify_policy_t *verify_ctx); BELLESIP_EXPORT int belle_http_provider_send_request(belle_http_provider_t *obj, belle_http_request_t *req, belle_http_request_listener_t *listener); BELLESIP_EXPORT void belle_http_provider_cancel_request(belle_http_provider_t *obj, belle_http_request_t *req); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/list.h000066400000000000000000000067771252242224000200300ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_LIST_H_ #define BELLE_SIP_LIST_H_ struct _belle_sip_list { struct _belle_sip_list *next; struct _belle_sip_list *prev; void *data; }; typedef struct _belle_sip_list belle_sip_list_t; BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_append(belle_sip_list_t * elem, void * data); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_prepend(belle_sip_list_t * elem, void * data); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_last_elem(const belle_sip_list_t *l); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_free(belle_sip_list_t * elem); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_concat(belle_sip_list_t * first, belle_sip_list_t * second); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_remove(belle_sip_list_t * first, void *data); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_pop_front(belle_sip_list_t *list, void **front_data); BELLESIP_EXPORT int belle_sip_list_size(const belle_sip_list_t * first); BELLESIP_EXPORT void belle_sip_list_for_each(const belle_sip_list_t * list, void (*func)(void *)); BELLESIP_EXPORT void belle_sip_list_for_each2(const belle_sip_list_t * list, void (*func)(void *, void *), void *user_data); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_remove_link(belle_sip_list_t * list, belle_sip_list_t * elem); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_delete_link(belle_sip_list_t * list, belle_sip_list_t * elem); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_find(belle_sip_list_t * list, void *data); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_free(belle_sip_list_t *list); /*frees list elements and associated data, using the supplied function pointer*/ BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_free_with_data(belle_sip_list_t *list, void (*freefunc)(void*)); typedef int (*belle_sip_compare_func)(const void *, const void*); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_find_custom(const belle_sip_list_t * list, belle_sip_compare_func cmp, const void *user_data); BELLESIP_EXPORT void * belle_sip_list_nth_data(const belle_sip_list_t * list, int index); BELLESIP_EXPORT int belle_sip_list_position(const belle_sip_list_t * list, belle_sip_list_t * elem); BELLESIP_EXPORT int belle_sip_list_index(const belle_sip_list_t * list, void *data); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_insert_sorted(belle_sip_list_t * list, void *data, belle_sip_compare_func cmp); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_insert(belle_sip_list_t * list, belle_sip_list_t * before, void *data); BELLESIP_EXPORT belle_sip_list_t * belle_sip_list_copy(const belle_sip_list_t * list); /*copy list elements and associated data, using the supplied function pointer*/ BELLESIP_EXPORT belle_sip_list_t* belle_sip_list_copy_with_data(const belle_sip_list_t* list, void* (*copyfunc)(void*)); #endif /* BELLE_SIP_LIST_H_ */ belle-sip-1.4.1/include/belle-sip/listener.h000066400000000000000000000220771252242224000206710ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_listener_h #define belle_sip_listener_h BELLE_SIP_BEGIN_DECLS typedef struct belle_sip_dialog_terminated_event belle_sip_dialog_terminated_event_t; typedef struct belle_sip_io_error_event belle_sip_io_error_event_t; typedef struct belle_sip_request_event belle_sip_request_event_t; typedef struct belle_sip_response_event belle_sip_response_event_t; typedef struct belle_sip_timeout_event belle_sip_timeout_event_t; typedef struct belle_sip_transaction_terminated_event belle_sip_transaction_terminated_event_t; typedef struct belle_sip_auth_event belle_sip_auth_event_t; typedef struct belle_sip_certificates_chain belle_sip_certificates_chain_t; typedef struct belle_sip_signing_key belle_sip_signing_key_t; BELLE_SIP_DECLARE_INTERFACE_BEGIN(belle_sip_listener_t) void (*process_dialog_terminated)(belle_sip_listener_t *user_ctx, const belle_sip_dialog_terminated_event_t *event); void (*process_io_error)(belle_sip_listener_t *user_ctx, const belle_sip_io_error_event_t *event); void (*process_request_event)(belle_sip_listener_t *user_ctx, const belle_sip_request_event_t *event); void (*process_response_event)(belle_sip_listener_t *user_ctx, const belle_sip_response_event_t *event); void (*process_timeout)(belle_sip_listener_t *user_ctx, const belle_sip_timeout_event_t *event); void (*process_transaction_terminated)(belle_sip_listener_t *user_ctx, const belle_sip_transaction_terminated_event_t *event); void (*process_auth_requested)(belle_sip_listener_t *user_ctx, belle_sip_auth_event_t *event); BELLE_SIP_DECLARE_INTERFACE_END #define BELLE_SIP_LISTENER(obj) BELLE_SIP_INTERFACE_CAST(obj,belle_sip_listener_t) /*Response event*/ BELLESIP_EXPORT belle_sip_response_t* belle_sip_response_event_get_response(const belle_sip_response_event_t* event); BELLESIP_EXPORT belle_sip_client_transaction_t *belle_sip_response_event_get_client_transaction(const belle_sip_response_event_t* event); BELLESIP_EXPORT belle_sip_dialog_t *belle_sip_response_event_get_dialog(const belle_sip_response_event_t* event); /*Request event*/ BELLESIP_EXPORT belle_sip_request_t* belle_sip_request_event_get_request(const belle_sip_request_event_t* event); BELLESIP_EXPORT belle_sip_server_transaction_t *belle_sip_request_event_get_server_transaction(const belle_sip_request_event_t* event); BELLESIP_EXPORT belle_sip_dialog_t *belle_sip_request_event_get_dialog(const belle_sip_request_event_t* event); /*Dialog terminated event*/ BELLESIP_EXPORT belle_sip_dialog_t* belle_sip_dialog_terminated_event_get_dialog(const belle_sip_dialog_terminated_event_t *event); /** * Timeout Event */ BELLESIP_EXPORT belle_sip_client_transaction_t *belle_sip_timeout_event_get_client_transaction(const belle_sip_timeout_event_t* event); belle_sip_server_transaction_t *belle_sip_timeout_event_get_server_transaction(const belle_sip_timeout_event_t* event); /** * Transaction Termonated Event */ BELLESIP_EXPORT belle_sip_client_transaction_t *belle_sip_transaction_terminated_event_get_client_transaction(const belle_sip_transaction_terminated_event_t* event); BELLESIP_EXPORT belle_sip_server_transaction_t *belle_sip_transaction_terminated_event_get_server_transaction(const belle_sip_transaction_terminated_event_t* event); /** * auth event mode * */ typedef enum belle_sip_auth_mode { BELLE_SIP_AUTH_MODE_HTTP_DIGEST, /** Digest authentication has been requested by the server*/ BELLE_SIP_AUTH_MODE_TLS /** Client certificate has been requested by the server*/ } belle_sip_auth_mode_t; BELLESIP_EXPORT void belle_sip_auth_event_destroy(belle_sip_auth_event_t* event); BELLESIP_EXPORT const char* belle_sip_auth_event_get_username(const belle_sip_auth_event_t* event); BELLESIP_EXPORT void belle_sip_auth_event_set_username(belle_sip_auth_event_t* event, const char* value); BELLESIP_EXPORT const char* belle_sip_auth_event_get_userid(const belle_sip_auth_event_t* event); BELLESIP_EXPORT void belle_sip_auth_event_set_userid(belle_sip_auth_event_t* event, const char* value); BELLESIP_EXPORT const char* belle_sip_auth_event_get_realm(const belle_sip_auth_event_t* event); BELLESIP_EXPORT void belle_sip_auth_event_set_realm(belle_sip_auth_event_t* event, const char* value); BELLESIP_EXPORT const char* belle_sip_auth_event_get_domain(const belle_sip_auth_event_t* event); BELLESIP_EXPORT void belle_sip_auth_event_set_domain(belle_sip_auth_event_t* event, const char* value); BELLESIP_EXPORT const char* belle_sip_auth_event_get_passwd(const belle_sip_auth_event_t* event); BELLESIP_EXPORT void belle_sip_auth_event_set_passwd(belle_sip_auth_event_t* event, const char* value); BELLESIP_EXPORT const char* belle_sip_auth_event_get_ha1(const belle_sip_auth_event_t* event); BELLESIP_EXPORT void belle_sip_auth_event_set_ha1(belle_sip_auth_event_t* event, const char* value); /** * get the authentication mode requested by the server, can be either TLS client certificates of http digest * @param event * @return belle_sip_auth_mode_t * */ BELLESIP_EXPORT belle_sip_auth_mode_t belle_sip_auth_event_get_mode(const belle_sip_auth_event_t* event); /** * In case of TLS auth, get value of the distinguished name sent by the server * @param event * @return DN has sent by the server * */ BELLESIP_EXPORT const char* belle_sip_auth_event_get_distinguished_name(const belle_sip_auth_event_t* event); /** * get client certificate * @return belle_sip_certificate_t* * */ BELLESIP_EXPORT belle_sip_certificates_chain_t* belle_sip_auth_event_get_client_certificates_chain(const belle_sip_auth_event_t* event); /** * set client certificate to be sent in answer to the certificate request issued by the server for the DN belle_sip_auth_event_get_distinguished_name() name * @return belle_sip_certificate_t* * */ BELLESIP_EXPORT void belle_sip_auth_event_set_client_certificates_chain(belle_sip_auth_event_t* event, belle_sip_certificates_chain_t* value); /** * get client certificate private key * @return belle_sip_signing_key_t* * */ BELLESIP_EXPORT belle_sip_signing_key_t* belle_sip_auth_event_get_signing_key(const belle_sip_auth_event_t* event); /** * set the private key attached to the client certificate. * @param event belle_sip_auth_event_t * @param value belle_sip_signing_key_t signing key * */ BELLESIP_EXPORT void belle_sip_auth_event_set_signing_key(belle_sip_auth_event_t* event, belle_sip_signing_key_t* value); /*Io error event*/ /* * Give access to the remote host * @param event object * @return host value the socket is pointing to * */ const char* belle_sip_io_error_event_get_host(const belle_sip_io_error_event_t* event); /* * Give access to the used transport * @param event object * @return host value the socket is pointing to * */ const char* belle_sip_io_error_event_get_transport(const belle_sip_io_error_event_t* event); /* * Give access to the remote port * @param event object * @return port value the socket is pointing to * */ unsigned int belle_sip_io_error_event_port(const belle_sip_io_error_event_t* event); /* * Get access to the object involved in this error, can be either belle_sip_dialog_t or belle_sip_transaction_t or belle_sip_provider_t * @param event * @return belle_sip_object_t source, use belle_sip_object_is_instance_of to check returns type * */ BELLESIP_EXPORT belle_sip_object_t* belle_sip_io_error_event_get_source(const belle_sip_io_error_event_t* event); struct belle_sip_listener_callbacks{ void (*process_dialog_terminated)(void *user_ctx, const belle_sip_dialog_terminated_event_t *event); void (*process_io_error)(void *user_ctx, const belle_sip_io_error_event_t *event); void (*process_request_event)(void *user_ctx, const belle_sip_request_event_t *event); void (*process_response_event)(void *user_ctx, const belle_sip_response_event_t *event); void (*process_timeout)(void *user_ctx, const belle_sip_timeout_event_t *event); void (*process_transaction_terminated)(void *user_ctx, const belle_sip_transaction_terminated_event_t *event); void (*process_auth_requested)(void *user_ctx, belle_sip_auth_event_t *auth_event); void (*listener_destroyed)(void *user_ctx); }; typedef struct belle_sip_listener_callbacks belle_sip_listener_callbacks_t; /** * Creates an object implementing the belle_sip_listener_t interface. * This object passes the events to the callbacks, providing also the user context. **/ BELLESIP_EXPORT belle_sip_listener_t *belle_sip_listener_create_from_callbacks(const belle_sip_listener_callbacks_t *callbacks, void *user_ctx); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/listeningpoint.h000066400000000000000000000066641252242224000221160ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_TRANSPORT_H #define BELLE_SIP_TRANSPORT_H BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT const char *belle_sip_listening_point_get_ip_address(const belle_sip_listening_point_t *lp); BELLESIP_EXPORT int belle_sip_listening_point_get_port(const belle_sip_listening_point_t *lp); BELLESIP_EXPORT const char *belle_sip_listening_point_get_transport(const belle_sip_listening_point_t *lp); BELLESIP_EXPORT const char *belle_sip_listening_point_get_ip_address(const belle_sip_listening_point_t *lp); /* * set keep alive frequency in ms * @param lp object * @param ms keep alive period in ms. Values <=0 disable keep alive * */ BELLESIP_EXPORT void belle_sip_listening_point_set_keep_alive(belle_sip_listening_point_t *lp,int ms); /* * get keep alive frequency in ms * @param lp object * @return keep alive period in ms. Values <=0 disable keep alive * */ BELLESIP_EXPORT int belle_sip_listening_point_get_keep_alive(const belle_sip_listening_point_t *lp); /** * get the listening information as an URI * @return IP/port/transport as an URI */ BELLESIP_EXPORT const belle_sip_uri_t* belle_sip_listening_point_get_uri(const belle_sip_listening_point_t *ip); BELLESIP_EXPORT int belle_sip_listening_point_is_reliable(const belle_sip_listening_point_t *lp); /** * Clean (close) all channels (connection) managed by this listening point. **/ BELLESIP_EXPORT void belle_sip_listening_point_clean_channels(belle_sip_listening_point_t *lp); /** * Get the number of channels managed by this listening point. **/ BELLESIP_EXPORT int belle_sip_listening_point_get_channel_count(const belle_sip_listening_point_t *lp); BELLESIP_EXPORT int belle_sip_listening_point_get_well_known_port(const char *transport); /*deprecated*/ BELLESIP_EXPORT int belle_sip_tls_listening_point_set_root_ca(belle_sip_tls_listening_point_t *s, const char *path); /*deprecated*/ #define BELLE_SIP_TLS_LISTENING_POINT_BADCERT_CN_MISMATCH BELLE_TLS_VERIFY_CN_MISMATCH #define BELLE_SIP_TLS_LISTENING_POINT_BADCERT_ANY_REASON BELLE_TLS_VERIFY_ANY_REASON BELLESIP_EXPORT int belle_sip_tls_listening_point_set_verify_exceptions(belle_sip_tls_listening_point_t *s, int flags); BELLESIP_EXPORT int belle_sip_tls_listening_point_set_verify_policy(belle_sip_tls_listening_point_t *s, belle_tls_verify_policy_t *pol); BELLESIP_EXPORT belle_sip_listening_point_t * belle_sip_tunnel_listening_point_new(belle_sip_stack_t *s, void *tunnelclient); #define BELLE_SIP_UDP_LISTENING_POINT(obj) BELLE_SIP_CAST(obj,belle_sip_udp_listening_point_t) #define BELLE_SIP_STREAM_LISTENING_POINT(obj) BELLE_SIP_CAST(obj,belle_sip_stream_listening_point_t) #define BELLE_SIP_TLS_LISTENING_POINT(obj) BELLE_SIP_CAST(obj,belle_sip_tls_listening_point_t) BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/mainloop.h000066400000000000000000000120471252242224000206560ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_MAINLOOP_H #define BELLE_SIP_MAINLOOP_H #define BELLE_SIP_EVENT_READ 1 #define BELLE_SIP_EVENT_WRITE (1<<1) #define BELLE_SIP_EVENT_ERROR (1<<2) #define BELLE_SIP_EVENT_TIMEOUT (1<<3) typedef struct belle_sip_source belle_sip_source_t; BELLESIP_EXPORT int belle_sip_source_set_events(belle_sip_source_t* source, int event_mask); BELLESIP_EXPORT belle_sip_socket_t belle_sip_source_get_socket(const belle_sip_source_t* source); /** * Callback function prototype for main loop notifications. * Return value is important: * BELLE_SIP_STOP => source is removed from main loop. * BELLE_SIP_CONTINUE => source is kept, timeout is restarted if any according to last expiry time * BELLE_SIP_CONTINUE_WITHOUT_CATCHUP => source is kept, timeout is restarted if any according to current time **/ typedef int (*belle_sip_source_func_t)(void *user_data, unsigned int events); typedef void (*belle_sip_callback_t)(void *user_data); typedef struct belle_sip_main_loop belle_sip_main_loop_t; #define BELLE_SIP_CONTINUE_WITHOUT_CATCHUP 2 #define BELLE_SIP_CONTINUE 1 #define BELLE_SIP_STOP 0 BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT void belle_sip_main_loop_add_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source); BELLESIP_EXPORT void belle_sip_main_loop_remove_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source); /** * Creates a mainloop. **/ BELLESIP_EXPORT belle_sip_main_loop_t *belle_sip_main_loop_new(void); /** * Adds a timeout into the main loop * @param ml * @param func a callback function to be called to notify timeout expiration * @param data a pointer to be passed to the callback * @param timeout_value_ms duration of the timeout. * @returns timeout id **/ BELLESIP_EXPORT unsigned long belle_sip_main_loop_add_timeout(belle_sip_main_loop_t *ml, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms); /** * Adds a timeout into the main loop * The caller of this function is responsible for freeing (with belle_sip_object_unref()) the returned belle_sip_source_t object when it is no longer * needed. * @param ml * @param func a callback function to be called to notify timeout expiration * @param data a pointer to be passed to the callback * @param timeout_value_ms duration of the timeout. * @param timer_name name of the timer, can be null * @returns timeout belle_sip_source_t with ref count = 1 **/ BELLESIP_EXPORT belle_sip_source_t* belle_sip_main_loop_create_timeout(belle_sip_main_loop_t *ml , belle_sip_source_func_t func , void *data , unsigned int timeout_value_ms ,const char* timer_name); /** * Schedule an arbitrary task at next main loop iteration. **/ BELLESIP_EXPORT void belle_sip_main_loop_do_later(belle_sip_main_loop_t *ml, belle_sip_callback_t func, void *data); /** * Creates a timeout source, similarly to belle_sip_main_loop_add_timeout(). * However in this case the timeout must be entered manually using belle_sip_main_loop_add_source(). * Its pointer can be used to remove it from the source (that is cancelling it). **/ BELLESIP_EXPORT belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms); BELLESIP_EXPORT void belle_sip_source_set_timeout(belle_sip_source_t *s, unsigned int value_ms); BELLESIP_EXPORT unsigned int belle_sip_source_get_timeout(const belle_sip_source_t *s); BELLESIP_EXPORT belle_sip_source_t * belle_sip_socket_source_new(belle_sip_source_func_t func, void *data, belle_sip_socket_t fd, unsigned int events, unsigned int timeout_value_ms); BELLESIP_EXPORT unsigned long belle_sip_source_get_id(belle_sip_source_t *s); BELLESIP_EXPORT belle_sip_source_t *belle_sip_main_loop_find_source(belle_sip_main_loop_t *ml, unsigned long id); /** * Executes the main loop forever (or until belle_sip_main_loop_quit() is called) **/ BELLESIP_EXPORT void belle_sip_main_loop_run(belle_sip_main_loop_t *ml); /** * Executes the main loop for the time specified in milliseconds. **/ BELLESIP_EXPORT void belle_sip_main_loop_sleep(belle_sip_main_loop_t *ml, int milliseconds); /** * Break out the main loop. **/ BELLESIP_EXPORT int belle_sip_main_loop_quit(belle_sip_main_loop_t *ml); /** * Cancel (removes) a source. It is not freed. **/ BELLESIP_EXPORT void belle_sip_main_loop_cancel_source(belle_sip_main_loop_t *ml, unsigned long id); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/message.h000066400000000000000000000165211252242224000204650ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_MESSAGE_H #define BELLE_SIP_MESSAGE_H #include "belle-sip/headers.h" #define BELLE_SIP_MESSAGE(obj) BELLE_SIP_CAST(obj,belle_sip_message_t) #define BELLE_SIP_REQUEST(obj) BELLE_SIP_CAST(obj,belle_sip_request_t) #define BELLE_SIP_RESPONSE(obj) BELLE_SIP_CAST(obj,belle_sip_response_t) BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT belle_sip_message_t* belle_sip_message_parse(const char* raw); /** * Parse sip message from a raw buffer * @param [in] buff buffer to be parsed * @param [in] buff_length size of the buffer to be parsed * @param [out] message_length number of bytes read * @return parsed message */ BELLESIP_EXPORT belle_sip_message_t* belle_sip_message_parse_raw (const char* buff, size_t buff_length,size_t* message_length ); BELLESIP_EXPORT int belle_sip_message_is_request(belle_sip_message_t *msg); BELLESIP_EXPORT belle_sip_request_t* belle_sip_request_new(); BELLESIP_EXPORT belle_sip_request_t* belle_sip_request_parse(const char* raw); BELLESIP_EXPORT belle_sip_request_t* belle_sip_request_create(belle_sip_uri_t *requri, const char* method, belle_sip_header_call_id_t *callid, belle_sip_header_cseq_t *cseq, belle_sip_header_from_t *from, belle_sip_header_to_t *to, belle_sip_header_via_t *via, int max_forwards); BELLESIP_EXPORT belle_sip_uri_t* belle_sip_request_get_uri(const belle_sip_request_t* request); BELLESIP_EXPORT void belle_sip_request_set_uri(belle_sip_request_t* request, belle_sip_uri_t* uri); BELLESIP_EXPORT const char* belle_sip_request_get_method(const belle_sip_request_t* request); BELLESIP_EXPORT void belle_sip_request_set_method(belle_sip_request_t* request,const char* method); /** * Guess the origin of the received sip message from VIA header (thanks to received/rport) * @param req request to be analyzed * @ return a newly allocated uri * */ BELLESIP_EXPORT belle_sip_uri_t* belle_sip_request_extract_origin(const belle_sip_request_t* req); /** * Clone all sip headers + body if any * @param req message to be cloned * @return newly allocated request */ BELLESIP_EXPORT belle_sip_request_t * belle_sip_request_clone_with_body(const belle_sip_request_t *initial_req); /** * returns an absolute uri. A header address cannot have both a sip uri and an absolute uri. */ BELLESIP_EXPORT belle_generic_uri_t* belle_sip_request_get_absolute_uri(const belle_sip_request_t* req); /** * set an absolute uri. A header address cannot have both a sip uri and an absolute uri. This function also to uri to NULL */ BELLESIP_EXPORT void belle_sip_request_set_absolute_uri(belle_sip_request_t* req, belle_generic_uri_t* uri); BELLESIP_EXPORT int belle_sip_message_is_response(const belle_sip_message_t *msg); BELLESIP_EXPORT belle_sip_header_t *belle_sip_message_get_header(const belle_sip_message_t *msg, const char *header_name); BELLESIP_EXPORT belle_sip_object_t *_belle_sip_message_get_header_by_type_id(const belle_sip_message_t *message, belle_sip_type_id_t id); #define belle_sip_message_get_header_by_type(msg,header_type)\ (header_type*)_belle_sip_message_get_header_by_type_id(BELLE_SIP_MESSAGE(msg),BELLE_SIP_TYPE_ID(header_type)) BELLESIP_EXPORT const belle_sip_list_t* belle_sip_message_get_headers(const belle_sip_message_t *message,const char* header_name); /** * Get list of all headers present in the message. * @param message * @return a newly allocated list of belle_sip_header_t * */ BELLESIP_EXPORT belle_sip_list_t* belle_sip_message_get_all_headers(const belle_sip_message_t *message); BELLESIP_EXPORT void belle_sip_message_add_first(belle_sip_message_t *msg, belle_sip_header_t* header); /** * add an header to this message * @param msg * @param header to add, must be one of header type */ BELLESIP_EXPORT void belle_sip_message_add_header(belle_sip_message_t *msg, belle_sip_header_t* header); BELLESIP_EXPORT void belle_sip_message_add_headers(belle_sip_message_t *message, const belle_sip_list_t *header_list); BELLESIP_EXPORT void belle_sip_message_set_header(belle_sip_message_t *msg, belle_sip_header_t* header); BELLESIP_EXPORT void belle_sip_message_remove_first(belle_sip_message_t *msg, const char *header_name); BELLESIP_EXPORT void belle_sip_message_remove_last(belle_sip_message_t *msg, const char *header_name); BELLESIP_EXPORT void belle_sip_message_remove_header(belle_sip_message_t *msg, const char *header_name); BELLESIP_EXPORT char *belle_sip_message_to_string(belle_sip_message_t *msg); BELLESIP_EXPORT belle_sip_body_handler_t *belle_sip_message_get_body_handler(const belle_sip_message_t *msg); BELLESIP_EXPORT void belle_sip_message_set_body_handler(belle_sip_message_t *msg, belle_sip_body_handler_t *body_handler); BELLESIP_EXPORT const char* belle_sip_message_get_body(belle_sip_message_t *msg); BELLESIP_EXPORT size_t belle_sip_message_get_body_size(const belle_sip_message_t *msg); BELLESIP_EXPORT void belle_sip_message_set_body(belle_sip_message_t *msg,const char* body,unsigned int size); BELLESIP_EXPORT void belle_sip_message_assign_body(belle_sip_message_t *msg, char* body, unsigned int size); BELLESIP_EXPORT int belle_sip_response_get_status_code(const belle_sip_response_t *response); BELLESIP_EXPORT void belle_sip_response_set_status_code(belle_sip_response_t *response,int status); BELLESIP_EXPORT const char* belle_sip_response_get_reason_phrase(const belle_sip_response_t *response); BELLESIP_EXPORT void belle_sip_response_set_reason_phrase(belle_sip_response_t *response,const char* reason_phrase); BELLESIP_EXPORT belle_sip_response_t *belle_sip_response_new(void); BELLESIP_EXPORT belle_sip_response_t *belle_sip_response_create_from_request(belle_sip_request_t *req, int status_code); /** * This method takes received/rport/via value of the reponse and update the contact IP/port accordingly * @param response use to extract via/received/rport from top most via. * @param contact contact to be updated * @returns 0 if no error * */ BELLESIP_EXPORT int belle_sip_response_fix_contact(const belle_sip_response_t* response,belle_sip_header_contact_t* contact); /** * Check for mandatory headers and parameters. * If message does not satisfy minimum requirements return FALSE, otherwise return TRUE. **/ BELLESIP_EXPORT int belle_sip_message_check_headers(const belle_sip_message_t* message); /** * check uri components of headers and req uri. * return 0 if not compliant * */ BELLESIP_EXPORT int belle_sip_request_check_uris_components(const belle_sip_request_t* request); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/object.h000066400000000000000000000506531252242224000203130ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_object_h #define belle_sip_object_h #include "belle-sip/defs.h" #include "belle-sip/utils.h" /* * typedefs, macros and functions for object definition and manipulation. */ #define BELLE_SIP_TYPE_ID(_type) _type##_id typedef unsigned int belle_sip_type_id_t; #define BELLE_SIP_DECLARE_TYPES_BEGIN(namezpace,unique_namespace_id) \ enum namezpace##type_ids{\ namezpace##type_id_first=unique_namespace_id, #define BELLE_SIP_DECLARE_TYPES_END }; #define BELLE_SIP_OBJECT_VPTR_NAME(object_type) object_type##_vptr #define BELLE_SIP_OBJECT_GET_VPTR_FUNC(object_type) object_type##_vptr_get #define BELLE_SIP_OBJECT_VPTR_TYPE(object_type) object_type##_vptr_t #define BELLE_SIP_DECLARE_VPTR(object_type) \ typedef belle_sip_object_vptr_t BELLE_SIP_OBJECT_VPTR_TYPE(object_type);\ BELLESIP_EXPORT BELLE_SIP_OBJECT_VPTR_TYPE(object_type) * BELLE_SIP_OBJECT_GET_VPTR_FUNC(object_type)(void); #define BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(object_type, parent_type) \ typedef struct object_type##_vptr_struct BELLE_SIP_OBJECT_VPTR_TYPE(object_type);\ BELLESIP_EXPORT BELLE_SIP_OBJECT_VPTR_TYPE(object_type) * BELLE_SIP_OBJECT_GET_VPTR_FUNC(object_type)(void); \ struct object_type##_vptr_struct{\ BELLE_SIP_OBJECT_VPTR_TYPE(parent_type) base; #define BELLE_SIP_DECLARE_CUSTOM_VPTR_END }; #define BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(object_type) \ extern BELLE_SIP_OBJECT_VPTR_TYPE(object_type) BELLE_SIP_OBJECT_VPTR_NAME(object_type);\ BELLE_SIP_OBJECT_VPTR_TYPE(object_type) * BELLE_SIP_OBJECT_GET_VPTR_FUNC(object_type)(void){\ return &BELLE_SIP_OBJECT_VPTR_NAME(object_type); \ }\ BELLE_SIP_OBJECT_VPTR_TYPE(object_type) BELLE_SIP_OBJECT_VPTR_NAME(object_type)={ #define BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END }; #define BELLE_SIP_VPTR_INIT(object_type,parent_type,unowned) \ BELLE_SIP_TYPE_ID(object_type), \ sizeof(object_type), \ #object_type,\ unowned,\ (belle_sip_object_get_vptr_t)BELLE_SIP_OBJECT_GET_VPTR_FUNC(parent_type), \ (belle_sip_interface_desc_t**)object_type##interfaces_table #define BELLE_SIP_INSTANCIATE_VPTR(object_type,parent_type,destroy,clone,marshal,unowned) \ static BELLE_SIP_OBJECT_VPTR_TYPE(object_type) BELLE_SIP_OBJECT_VPTR_NAME(object_type)={ \ BELLE_SIP_VPTR_INIT(object_type,parent_type,unowned), \ (belle_sip_object_destroy_t)destroy, \ (belle_sip_object_clone_t)clone, \ (belle_sip_object_marshal_t)marshal\ }; \ BELLE_SIP_OBJECT_VPTR_TYPE(object_type) * BELLE_SIP_OBJECT_GET_VPTR_FUNC(object_type)(void){\ return &BELLE_SIP_OBJECT_VPTR_NAME(object_type); \ } /** * belle_sip_object_t is the base object. * It is the base class for all belle sip non trivial objects. * It owns a reference count which allows to trigger the destruction of the object when the last * user of it calls belle_sip_object_unref(). * * It contains a generic data store that allows users to store named data in it and retrieve them afterwards. * * About object lifecycle
* In belle-sip, objects can be, depending on their types, initially owned, that there are created with a ref count of 1, or * initially unowned, that is with reference count of 0. Such objets are also referred as "floating object". They are automatically destroyed * by the main loop iteration, so a floating object can be seen as a temporary object, until someones calls belle_sip_object_ref() on it. * * In order to know whether a kind of object is initially owned or initially unowned, you can use the test program tester/belle_sip_object_describe. * This tool gives the hierarchy and properties of the object type whose name is supplied in argument. For example: * *
./tester/belle_sip_object_describe belle_sip_request_t
* * The object memory management depends slightly on whether an object type is created initially owned or not. * In order not to be lost and make memory fault or leaks, consider the following rules: * * When an object is of type initially unowned: * * call belle_sip_object_ref() on it only if you need a pointer to this object to be used outside the scope of the current function. * * call belle_sip_object_unref() on it only if you previously called belle_sip_object_ref(). * * When an object is of type initially owned: * * you can safely store its pointer. * * use belle_sip_object_unref() when you no longer need it. * * Also, keep in mind that most objects of belle-sip are initially unowned, especially * * all objects who are usually required to be used inside another object (for example: an URI is part of a from header, a contact header is part of a message) * * all objects whose lifecyle is maintained by the stack: transactions, dialogs. * * On the contrary, top level objects whose lifecyle belongs only to the application are initially owned: * * belle_sip_provider_t, belle_sip_stack_t, belle_sip_source_t. * * Internally, belle-sip objects containing pointers to other objects must take a reference count on the other objects they hold; and leave this reference * when they no longer need it. This rule must be strictly followed by developers doing things inside belle-sip. **/ typedef struct _belle_sip_object belle_sip_object_t; typedef void (*belle_sip_object_destroy_t)(belle_sip_object_t*); typedef void (*belle_sip_object_clone_t)(belle_sip_object_t* obj, const belle_sip_object_t *orig); typedef int (*belle_sip_object_marshal_t)(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset); typedef struct _belle_sip_object_vptr *(*belle_sip_object_get_vptr_t)(void); struct _belle_sip_object_vptr{ belle_sip_type_id_t id; size_t size; /*the size of the object - not the vptr size*/ const char *type_name; int initially_unowned; belle_sip_object_get_vptr_t get_parent; struct belle_sip_interface_desc **interfaces; /*NULL terminated table of */ belle_sip_object_destroy_t destroy; belle_sip_object_clone_t clone; belle_sip_object_marshal_t marshal; int tostring_bufsize_hint; /*optimization: you can suggest here the typical size for a to_string() result.*/ }; typedef struct _belle_sip_object_vptr belle_sip_object_vptr_t; struct _belle_sip_object{ belle_sip_object_vptr_t *vptr; int ref; char* name; struct weak_ref *weak_refs; struct belle_sip_object_pool *pool; struct _belle_sip_list *pool_iterator; struct _belle_sip_list *data_store; }; BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr_t *vptr); #define belle_sip_object_new(_type) (_type*)_belle_sip_object_new(sizeof(_type),(belle_sip_object_vptr_t*)BELLE_SIP_OBJECT_GET_VPTR_FUNC(_type)()) /** * Activates checks on object marshalling. * Useful for debug purposes. * @param enable TRUE to enable, FALSE to disable. **/ BELLESIP_EXPORT void belle_sip_object_enable_marshal_check(int enable); /** * Activates an object leak detector. When enabled, belle-sip will reference all created objects. * At program termination, application can check if objects remain alive using belle_sip_object_get_object_count() and dump them with * belle_sip_object_dump_active_objects(). * @warning this must not be used in multi-threaded programs (when multiple threads can access belle-sip at the same time) * Useful for debug purposes. * @param enable TRUE to enable, FALSE to disable. **/ BELLESIP_EXPORT void belle_sip_object_enable_leak_detector(int enable); BELLESIP_EXPORT int belle_sip_object_get_object_count(void); BELLESIP_EXPORT void belle_sip_object_dump_active_objects(void); /** * Suspend leak detector from this point. If the leak detector wasn't activated, this function does nothing. * This can be useful to make object allocation that have to remain active beyond the scope of a test. **/ BELLESIP_EXPORT void belle_sip_object_inhibit_leak_detector(int yes); int belle_sip_object_is_unowed(const belle_sip_object_t *obj); /** * Increments reference counter, which prevents the object from being destroyed. * If the object is initially unowed, this acquires the first reference. * **/ BELLESIP_EXPORT belle_sip_object_t * belle_sip_object_ref(void *obj); /** * Decrements the reference counter. When it drops to zero, the object is destroyed. **/ BELLESIP_EXPORT void belle_sip_object_unref(void *obj); typedef void (*belle_sip_object_destroy_notify_t)(void *userpointer, belle_sip_object_t *obj_being_destroyed); /** * Add a weak reference to object. * When object will be destroyed, then the destroy_notify callback will be called. * This allows another object to be informed when object is destroyed, and then possibly * cleanups pointer it holds to this object. **/ BELLESIP_EXPORT belle_sip_object_t *belle_sip_object_weak_ref(void *obj, belle_sip_object_destroy_notify_t destroy_notify, void *userpointer); /** * Remove a weak reference to object. **/ BELLESIP_EXPORT void belle_sip_object_weak_unref(void *obj, belle_sip_object_destroy_notify_t destroy_notify, void *userpointer); /** * Set object name. **/ void belle_sip_object_set_name(belle_sip_object_t *obj,const char* name); /** * Get object name. **/ const char* belle_sip_object_get_name(belle_sip_object_t *obj); /*copy the content of ref object to new object, for the part they have in common in their inheritence diagram*/ void _belle_sip_object_copy(belle_sip_object_t *newobj, const belle_sip_object_t *ref); /** * Clone an object. * * This clone function makes a deep copy of all object internal structure, so that the new object and the reference object have no dependencies at all. * **/ BELLESIP_EXPORT belle_sip_object_t *belle_sip_object_clone(const belle_sip_object_t *obj); /** * Same as #belle_sip_object_clone but with ref count set to 1 * **/ belle_sip_object_t *belle_sip_object_clone_and_ref(const belle_sip_object_t *obj); typedef void (*belle_sip_data_destroy)(void* data); typedef void* (*belle_sip_data_clone)(const char* name, void* data); /** * Add an entry to the object's embedded data store, with the key name specified. * The destroy function is used when the data is cleaned. * * If an entry already exists, the existing data will be cleaned by calling its destroy function and the new data will be placed instead. * * Returns -1 in case of error, 0 in case the insertion was successful, and 1 if existing data was present. **/ BELLESIP_EXPORT int belle_sip_object_data_set( belle_sip_object_t *obj, const char* name, void* data, belle_sip_data_destroy destroy_func ); /** * Retrieve data that has been stored in the object data store. **/ BELLESIP_EXPORT void* belle_sip_object_data_get( belle_sip_object_t *obj, const char* name ); /** * Return 1 if the key exists in the data store, 0 otherwise **/ BELLESIP_EXPORT int belle_sip_object_data_exists( const belle_sip_object_t *obj, const char* name ); /** * Destroys the named data associated by the name provided. * * Returns 0 for success, -1 for error **/ BELLESIP_EXPORT int belle_sip_object_data_remove( belle_sip_object_t *obj, const char* name); /** * Retrieve the data from the data store and removes it from the data store, without calling the destructor. * This transfers ownership of the data to the caller, which will be in charge of releasing it. **/ BELLESIP_EXPORT void* belle_sip_object_data_grab( belle_sip_object_t* obj, const char* name); /** * Clears all data in the object's storage, invoking the destroy_func when possible **/ BELLESIP_EXPORT void belle_sip_object_data_clear( belle_sip_object_t* obj ); /** * clones the object's data store to another one, using the provided clone function to clone individual data items. * * The destination data store will be cleaned before pushing the source data into it. * For a merge, use #belle_sip_object_data_merge. * This is equivalent to the following code: * { * belle_sip_object_data_clear(dst); * belle_sip_object_data_merge(src, dst, clone_func); * } * * Note that providing NULL as a cloning function will simply assign the src object's data to the dst object. * **/ BELLESIP_EXPORT void belle_sip_object_data_clone( const belle_sip_object_t* src, belle_sip_object_t* dst, belle_sip_data_clone clone_func); /** * Merge the source data store into the destination data store. * * Same function as #belle_sip_object_data_clone, except the destination data store is not cleared before inserting the source data. * This overwrites common keys, and keeps existing keys. */ BELLESIP_EXPORT void belle_sip_object_data_merge( const belle_sip_object_t* src, belle_sip_object_t* dst, belle_sip_data_clone clone_func); /** * Apply a function for each entry in the data store */ BELLESIP_EXPORT void belle_sip_object_data_foreach( const belle_sip_object_t* obj, void (*apply_func)(const char* key, void* data, void* userdata), void* userdata); /** * Returns a string describing the inheritance diagram and implemented interfaces of object obj. **/ char *belle_sip_object_describe(void *obj); /** * Returns a string describing the inheritance diagram and implemented interfaces of an object given its type name. **/ BELLESIP_EXPORT char *belle_sip_object_describe_type_from_name(const char *name); BELLESIP_EXPORT void *belle_sip_object_cast(belle_sip_object_t *obj, belle_sip_type_id_t id, const char *castname, const char *file, int fileno); /** * Returns a newly allocated string representing the object. * WHen the object is a sip header, uri or message, this is the textual representation of the header, uri or message. * This function internally calls belle_sip_object_marshal(). **/ BELLESIP_EXPORT char* belle_sip_object_to_string(void* obj); /** * Writes a string representation of the object into the supplied buffer. * Same as belle_sip_object_to_string(), but without allocating space for the output string. **/ BELLESIP_EXPORT belle_sip_error_code belle_sip_object_marshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset); /* use BELLE_SIP_OBJECT_IS_INSTANCE_OF macro(), this function is for use by the macro only*/ BELLESIP_EXPORT int _belle_sip_object_is_instance_of(belle_sip_object_t * obj,belle_sip_type_id_t id); BELLE_SIP_END_DECLS #define BELLE_SIP_CAST(obj,_type) ((_type*)belle_sip_object_cast((belle_sip_object_t *)(obj), _type##_id, #_type, __FILE__, __LINE__)) #define BELLE_SIP_OBJECT(obj) BELLE_SIP_CAST(obj,belle_sip_object_t) #define BELLE_SIP_OBJECT_IS_INSTANCE_OF(obj,_type) _belle_sip_object_is_instance_of((belle_sip_object_t*)obj,_type##_id) #define BELLE_SIP_OBJECT_VPTR(obj,object_type) ((BELLE_SIP_OBJECT_VPTR_TYPE(object_type)*)(((belle_sip_object_t*)obj)->vptr)) /*deprecated*/ #define BELLE_SIP_IS_INSTANCE_OF(obj,_type) BELLE_SIP_OBJECT_IS_INSTANCE_OF(obj,_type) #define belle_sip_object_describe_type(type) \ belle_sip_object_describe_type_from_name(#type) /* * typedefs, macros and functions for interface definition and manipulation. */ #define BELLE_SIP_INTERFACE_ID(_interface) _interface##_id typedef unsigned int belle_sip_interface_id_t; BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT void *belle_sip_object_interface_cast(belle_sip_object_t *obj, belle_sip_interface_id_t id, const char *castname, const char *file, int fileno); int belle_sip_object_implements(belle_sip_object_t *obj, belle_sip_interface_id_t id); BELLE_SIP_END_DECLS #define BELLE_SIP_INTERFACE_METHODS_TYPE(interface_name) methods_##interface_name #define BELLE_SIP_INTERFACE_CAST(obj,_iface) ((_iface*)belle_sip_object_interface_cast((belle_sip_object_t*)(obj),_iface##_id,#_iface,__FILE__,__LINE__)) #define BELLE_SIP_IMPLEMENTS(obj,_iface) belle_sip_object_implements((belle_sip_object_t*)obj,_iface##_id) typedef struct belle_sip_interface_desc{ belle_sip_interface_id_t id; const char *ifname; }belle_sip_interface_desc_t; #define BELLE_SIP_DECLARE_INTERFACE_BEGIN(interface_name) \ typedef struct struct##interface_name interface_name;\ typedef struct struct_methods_##interface_name BELLE_SIP_INTERFACE_METHODS_TYPE(interface_name);\ struct struct_methods_##interface_name {\ belle_sip_interface_desc_t desc;\ #define BELLE_SIP_DECLARE_INTERFACE_END }; #define BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(object_type,interface_name) \ static BELLE_SIP_INTERFACE_METHODS_TYPE(interface_name) methods_##object_type##_##interface_name={\ { BELLE_SIP_INTERFACE_ID(interface_name),\ #interface_name }, #define BELLE_SIP_IMPLEMENT_INTERFACE_END }; #define BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(object_type)\ static belle_sip_interface_desc_t * object_type##interfaces_table[]={\ NULL \ } #define BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(object_type,iface1) \ static belle_sip_interface_desc_t * object_type##interfaces_table[]={\ (belle_sip_interface_desc_t*)&methods_##object_type##_##iface1, \ NULL \ } #define BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_2(object_type,iface1,iface2) \ static belle_sip_interface_desc_t * object_type##interfaces_table[]={\ (belle_sip_interface_desc_t*)&methods_##object_type##_##iface1, \ (belle_sip_interface_desc_t*)&methods_##object_type##_##iface2, \ NULL \ } /** * Object holding unowned objects - used as a kind of garbage collector for temporary objects. **/ typedef struct belle_sip_object_pool belle_sip_object_pool_t; BELLE_SIP_BEGIN_DECLS /** * Push a new object pool for use for creation of new objects. * When no longer needed, this pool can be destroyed with belle_sip_object_unref(). **/ BELLESIP_EXPORT belle_sip_object_pool_t * belle_sip_object_pool_push(void); belle_sip_object_pool_t * belle_sip_object_pool_get_current(); int belle_sip_object_pool_cleanable(belle_sip_object_pool_t *pool); void belle_sip_object_pool_clean(belle_sip_object_pool_t *obj); BELLE_SIP_DECLARE_VPTR(belle_sip_object_t) BELLE_SIP_END_DECLS /** * Adding a new type in belle-sip in 5 steps * ========================================= * * Let's suppose you want to add an object called belle_sip_something_t * 1) Declare the type in the enum in belle-sip.h: * BELLE_SIP_TYPE_ID(belle_sip_something_t) * 2) Declare the api of the new object in .h, including a typedef and a cast macro: * typedef struct belle_sip_something belle_sip_something_t; * #define BELLE_SIP_SOMETHING(obj) BELLE_SIP_CAST(obj,belle_sip_something_t) * * belle_sip_something_t *belle_sip_something_create(int arg1, int arg2); * void belle_sip_something_do_cooking(belle_sip_something_t *obj); * Do not add any destructor, belle_sip_object_unref() does it for all objects. * * 3) in the c file contaning the object's implementation, define the internal structure for your object. * The first field of the struct must be the parent type. * struct belle_sip_something{ * belle_sip_object_t base; * int myint1; * int myint2; * char *mychar; * }; * 4) still in the C file contaning the object's implementation, define a destructor and all functions of its API: * The destructor must only manage the fields from the type, not the parent. * static void belle_sip_something_destroy(belle_sip_something_t *obj){ * if (obj->mychar) belle_sip_free(obj->mychar); * } * * belle_sip_something_t *belle_sip_something_create(int arg1, int arg2){ * belle_sip_something_t *obj=belle_sip_object_new(belle_sip_something_t); * obj->myint1=arg1; * obj->myint2=arg2; * obj->mychar=belle_sip_strdup("Hello world"); * return obj; * } * Declare the interfaces implemented by the object (to be documented) and instanciate its "vptr", necessary for dynamic casting. * BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_something_t); * BELLE_SIP_INSTANCIATE_VPTR(belle_sip_something_t, belle_sip_object_t,belle_sip_something_destroy, NULL, NULL,FALSE); * * 5) in .h file included everywhere in the source (typically belle_sip_internal.h), declare the vptr * BELLE_SIP_DECLARE_VPTR(belle_sip_dns_srv_t); */ #if defined(__cplusplus) && defined(BELLE_SIP_USE_STL) #include inline std::ostream& operator<<( std::ostream& __os, const belle_sip_object_t* object) { char* object_as_string = belle_sip_object_to_string((void*)object); __os << object_as_string; belle_sip_free(object_as_string); return __os; } #endif #endif belle-sip-1.4.1/include/belle-sip/parameters.h000066400000000000000000000053501252242224000212020ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PARAMETERS_H_ #define PARAMETERS_H_ #include "belle-sip/utils.h" #include "belle-sip/list.h" BELLE_SIP_BEGIN_DECLS /*** * parameters * */ belle_sip_parameters_t* belle_sip_parameters_new(); /* * remove all parameters */ BELLESIP_EXPORT void belle_sip_parameters_clean(belle_sip_parameters_t* params); BELLESIP_EXPORT const char* belle_sip_parameters_get_parameter(const belle_sip_parameters_t* obj,const char* name); /* * same as #belle_sip_parameters_get_parameter but name is case insensitive */ BELLESIP_EXPORT const char* belle_sip_parameters_get_case_parameter(const belle_sip_parameters_t* params,const char* name); /** * returns 0 if not found */ BELLESIP_EXPORT unsigned int belle_sip_parameters_has_parameter(const belle_sip_parameters_t* obj,const char* name); BELLESIP_EXPORT void belle_sip_parameters_set_parameter(belle_sip_parameters_t* obj,const char* name,const char* value); /** * Assign a full set of parameters to the belle_sip_parameters_t object. * Parameters are given as string of key=value pairs separated with semicolons, where value is optional. * @example belle_sip_parameters_set(parameters,"param1=value1;param2;param3=value3"); **/ BELLESIP_EXPORT void belle_sip_parameters_set(belle_sip_parameters_t *parameters, const char* params); BELLESIP_EXPORT const belle_sip_list_t * belle_sip_parameters_get_parameter_names(const belle_sip_parameters_t* obj); BELLESIP_EXPORT const belle_sip_list_t * belle_sip_parameters_get_parameters(const belle_sip_parameters_t* obj); BELLESIP_EXPORT void belle_sip_parameters_remove_parameter(belle_sip_parameters_t* obj,const char* name); BELLESIP_EXPORT belle_sip_error_code belle_sip_parameters_marshal(const belle_sip_parameters_t* obj, char* buff, size_t buff_size, size_t *offset); BELLESIP_EXPORT void belle_sip_parameters_copy_parameters_from(belle_sip_parameters_t *params, const belle_sip_parameters_t *orig); #define BELLE_SIP_PARAMETERS(obj) BELLE_SIP_CAST(obj,belle_sip_parameters_t) BELLE_SIP_END_DECLS #endif /*PARAMETERS_H_*/ belle-sip-1.4.1/include/belle-sip/provider.h000066400000000000000000000133461252242224000206750ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_provider_h #define belle_sip_provider_h #define BELLE_SIP_BRANCH_MAGIC_COOKIE "z9hG4bK" BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT belle_sip_uri_t *belle_sip_provider_create_inbound_record_route(belle_sip_provider_t *p, belle_sip_request_t *req); BELLESIP_EXPORT int belle_sip_provider_is_us(belle_sip_provider_t *p, belle_sip_uri_t*); BELLESIP_EXPORT int belle_sip_provider_add_listening_point(belle_sip_provider_t *p, belle_sip_listening_point_t *lp); BELLESIP_EXPORT void belle_sip_provider_remove_listening_point(belle_sip_provider_t *p, belle_sip_listening_point_t *lp); BELLESIP_EXPORT belle_sip_listening_point_t *belle_sip_provider_get_listening_point(belle_sip_provider_t *p, const char *transport); BELLESIP_EXPORT const belle_sip_list_t *belle_sip_provider_get_listening_points(belle_sip_provider_t *p); BELLESIP_EXPORT void belle_sip_provider_add_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l); BELLESIP_EXPORT void belle_sip_provider_remove_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l); BELLESIP_EXPORT belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_provider_t *prov); BELLESIP_EXPORT belle_sip_dialog_t *belle_sip_provider_create_dialog(belle_sip_provider_t *prov, belle_sip_transaction_t *t); BELLESIP_EXPORT belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *p, belle_sip_request_t *req); BELLESIP_EXPORT belle_sip_server_transaction_t *belle_sip_provider_create_server_transaction(belle_sip_provider_t *p, belle_sip_request_t *req); BELLESIP_EXPORT belle_sip_stack_t *belle_sip_provider_get_sip_stack(belle_sip_provider_t *p); BELLESIP_EXPORT void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req); BELLESIP_EXPORT void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp); BELLESIP_EXPORT void belle_sip_provider_clean_channels(belle_sip_provider_t *p); /** * Add auth info to the request if found * @param p object * @param request to be updated * @param resp response to take authentication values from, might be NULL * @param from_uri optional - an uri to use instead of the from of the request, which can be anonymous. * @param auth_infos optional - A newly allocated belle_sip_auth_info_t object is added to this list. These object contains useful information like realm and username. * @param realm optional - If an outbound proxy realm is used, nounce can be reused from previous request to avoid re-authentication. * @returns 0 in case of success, * **/ BELLESIP_EXPORT int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_request_t* request,belle_sip_response_t *resp, belle_sip_uri_t *from_uri, belle_sip_list_t** auth_infos, const char* realm); /** * Can be used to simulate network recv error, for tests. * @param prov * @param recv_error if <=0, will cause channel error to be reported **/ BELLESIP_EXPORT void belle_sip_provider_set_recv_error(belle_sip_provider_t *prov, int recv_error); /** * Can be used to unconditionally answer to incoming sip messages. By default 480 is answered. * Can be enhanced by a new method belle_sip_provider_set_unconditional_answer to allows user to provide answer code * @param prov * @param enable 0 to disable **/ BELLESIP_EXPORT void belle_sip_provider_enable_unconditional_answer(belle_sip_provider_t *prov, int enable); /** * Provides access to a specific dialog * @param prov object * @param call_if of the dialog * @param from_tag of the dialog * @param to_tag of the dialog * @returns dialog corresponding to this parameter or NULL if not found * **/ BELLESIP_EXPORT belle_sip_dialog_t* belle_sip_provider_find_dialog(const belle_sip_provider_t *prov, const char* call_id,const char* from_tag,const char* to_tag); /** * Enable rport in via header. Enabled by default * @param prov * @return enable 0 to disable **/ BELLESIP_EXPORT void belle_sip_provider_enable_rport(belle_sip_provider_t *prov, int enable); /** * get Enable rport in via header. Enabled by default * @param prov * @param enable 0 to disable **/ BELLESIP_EXPORT int belle_sip_provider_is_rport_enabled(belle_sip_provider_t *prov); /** * Enable discovery of NAT's public address and port during SIP exchanges. * When activated, automatic contacts ( see belle_sip_header_contact_set_automatic() ) * will use discovered public IP address and port (if any) instead of local ones. * NAT public address and port are discovered using received and rport parameters in via header of responses. * As a result, disabling rport ( see belle_sip_provider_enable_rport() ) will also break this feature. **/ BELLESIP_EXPORT void belle_sip_provider_enable_nat_helper(belle_sip_provider_t *prov, int enabled); /** * Returns if nat helper behavior is enabled. * @see belle_sip_provider_enable_nat_helper() **/ BELLESIP_EXPORT int belle_sip_provider_nat_helper_enabled(const belle_sip_provider_t *prov); BELLE_SIP_END_DECLS #define BELLE_SIP_PROVIDER(obj) BELLE_SIP_CAST(obj,belle_sip_provider_t) #endif belle-sip-1.4.1/include/belle-sip/refresher.h000066400000000000000000000100371252242224000210220ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2012 Belledonne Communications SARL, Grenoble, France This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef REFRESHER_HELPER_H_ #define REFRESHER_HELPER_H_ #define BELLE_SIP_REFRESHER_REUSE_EXPIRES -1 BELLE_SIP_BEGIN_DECLS typedef struct belle_sip_refresher belle_sip_refresher_t; /** * Refresher listener invoked every time a refresh action is performed * @param refresher corresponding refresher object. * @param user_pointer user pointer * @param status_code status code for the last refresh action * @param reason_phrase * */ typedef void (*belle_sip_refresher_listener_t) (belle_sip_refresher_t* refresher ,void* user_pointer ,unsigned int status_code ,const char* reason_phrase); /** * add a refresher listener */ BELLESIP_EXPORT void belle_sip_refresher_set_listener(belle_sip_refresher_t* refresher, belle_sip_refresher_listener_t listener,void* user_pointer); /** * start the refresher */ int belle_sip_refresher_start(belle_sip_refresher_t* refresher); /** * stop refresher. * If a transaction is pending, it will be terminated. */ BELLESIP_EXPORT void belle_sip_refresher_stop(belle_sip_refresher_t* refresher); /** * Manually initiate a new transaction . * @param refresher object * @param expires #BELLE_SIP_REFRESHER_REUSE_EXPIRES means value extracted from the transaction * @return 0 if succeed */ BELLESIP_EXPORT int belle_sip_refresher_refresh(belle_sip_refresher_t* refresher,int expires); /** * returns current expires value; */ BELLESIP_EXPORT int belle_sip_refresher_get_expires(const belle_sip_refresher_t* refresher); /** * returns delay in ms after which the refresher will retry in case of recoverable error (I.E 408, 480, 503, 504, io error); */ BELLESIP_EXPORT int belle_sip_refresher_get_retry_after(const belle_sip_refresher_t* refresher); /** * Delay in ms after which the refresher will retry in case of recoverable error (I.E 408, 480, 503, 504, io error); */ BELLESIP_EXPORT void belle_sip_refresher_set_retry_after(belle_sip_refresher_t* refresher, int delay_ms); /** * returns realm of the outbound proxy used for authentication, if any */ BELLESIP_EXPORT const char* belle_sip_refresher_get_realm(const belle_sip_refresher_t* refresher); /** * Realm of the outbound proxy used for authentication, if any */ BELLESIP_EXPORT void belle_sip_refresher_set_realm(belle_sip_refresher_t* refresher, const char* realm); /** * get current client transaction * @param refresher object * @return transaction */ BELLESIP_EXPORT const belle_sip_client_transaction_t* belle_sip_refresher_get_transaction(const belle_sip_refresher_t* refresher); /** * Get current list of auth info if any. Contains the list of filled #belle_sip_auth_event_t in case of a 401 or 407 is repported to the #belle_sip_refresher_listener_t ; * @param refresher object * @return list of #belle_sip_auth_info_t */ BELLESIP_EXPORT const belle_sip_list_t* belle_sip_refresher_get_auth_events(const belle_sip_refresher_t* refresher); /** * Enable manual mode: only belle_sip_refresher_refresh() called by application will cause requests to be resubmitted. **/ BELLESIP_EXPORT void belle_sip_refresher_enable_manual_mode(belle_sip_refresher_t *refresher, int enabled); /** * Retrieve last know public ip:port contact used. **/ BELLESIP_EXPORT char* belle_sip_refresher_get_public_uri(belle_sip_refresher_t* refresher); BELLE_SIP_END_DECLS #endif /* REFRESHER_HELPER_H_ */ belle-sip-1.4.1/include/belle-sip/resolver.h000066400000000000000000000140411252242224000206750ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_resolver_h #define belle_sip_resolver_h typedef struct belle_sip_dns_srv belle_sip_dns_srv_t; #define BELLE_SIP_DNS_SRV(obj) BELLE_SIP_CAST(obj,belle_sip_dns_srv_t) typedef struct belle_sip_resolver_context belle_sip_resolver_context_t; #define BELLE_SIP_RESOLVER_CONTEXT(obj) BELLE_SIP_CAST(obj,belle_sip_resolver_context_t) /** * Callback prototype for asynchronous DNS SRV resolution. * The srv_list contains struct dns_srv elements that must be taken and (possibly later) freed by the callee, using belle_sip_free(). */ typedef void (*belle_sip_resolver_srv_callback_t)(void *data, const char *name, belle_sip_list_t *srv_list); /** * Callback prototype for asynchronous DNS A and AAAA resolution. * The ai_list contains addrinfo elements that must be taken and (possibly later) freed by the callee, using freeaddrinfo(). * These elements are linked by their ai_next field. **/ typedef void (*belle_sip_resolver_callback_t)(void *data, const char *name, struct addrinfo *ai_list); BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT const char *belle_sip_dns_srv_get_target(const belle_sip_dns_srv_t *obj); BELLESIP_EXPORT unsigned short belle_sip_dns_srv_get_priority(const belle_sip_dns_srv_t *obj); BELLESIP_EXPORT unsigned short belle_sip_dns_srv_get_weight(const belle_sip_dns_srv_t *obj); BELLESIP_EXPORT unsigned short belle_sip_dns_srv_get_port(const belle_sip_dns_srv_t *obj); BELLESIP_EXPORT int belle_sip_addrinfo_to_ip(const struct addrinfo *ai, char *ip, size_t ip_size, int *port); BELLESIP_EXPORT struct addrinfo * belle_sip_ip_address_to_addrinfo(int family, const char *ipaddress, int port); /** * Asynchronously performs DNS SRV followed A/AAAA query. Automatically fallbacks to A/AAAA if SRV isn't found. * @param stack the belle_sip_stack_t, used to schedule asynchronous execution. * @param transport the queried transport ("udp", "tcp", "tls") * @param name the SIP domain name * @param port a port that will be filled in the addrinfo list returned by the callback, for the case where no SRV records are found. * @param family address family expected in the addrinfo result list. AF_INET or AF_INET6. If AF_INET6 is used but no IPv6 records are found, the IPv4 addresses * will be returned as IPv6 with v4 mapping (AI_V4MAPPED). * @param cb a callback function that will be called to notify the results. * @param data a user pointer passed through the callback as first argument. * @return a #belle_sip_resolver_context_t that can be used to cancel the resolution if needed. The context must have been ref'd with belle_sip_object_ref(). **/ BELLESIP_EXPORT belle_sip_resolver_context_t * belle_sip_stack_resolve(belle_sip_stack_t *stack, const char *transport, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data); /** * Asynchronously performs DNS A or AAAA query. * @param stack the belle_sip_stack_t, used to schedule asynchronous execution. * @param name the SIP domain name * @param port a port that will be filled in the addrinfo list returned by the callback, for the case where no SRV records are found. * @param family address family expected in the addrinfo result list. AF_INET or AF_INET6. If AF_INET6 is used but no IPv4 records are found, the IPv4 addresses * will be returned as IPv6 with v4 mapping (AI_V4MAPPED). * @param cb a callback function that will be called to notify the results. * @param data a user pointer passed through the callback as first argument. * @return a #belle_sip_resolver_context_t that can be used to cancel the resolution if needed. The context must have been ref'd with belle_sip_object_ref(). **/ BELLESIP_EXPORT belle_sip_resolver_context_t * belle_sip_stack_resolve_a(belle_sip_stack_t *stack, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data); /** * Asynchronously performs DNS SRV query. * @return a #belle_sip_resolver_context_t that can be used to cancel the resolution if needed. The context must have been ref'd with belle_sip_object_ref(). **/ BELLESIP_EXPORT belle_sip_resolver_context_t * belle_sip_stack_resolve_srv(belle_sip_stack_t *stack, const char *transport, const char *name, belle_sip_resolver_srv_callback_t cb, void *data); /** * Cancel a pending asynchronous DNS query. The context is unref'd automatically, as a result the context shall no longer be used after this call. * If the query is already performed, cancellation has no effect, but context is unref'd anyway. **/ BELLESIP_EXPORT void belle_sip_resolver_context_cancel(belle_sip_resolver_context_t *ctx); /** * Lookups the source address from local interface that can be used to connect to a destination address. * local_port is only used to be assigned into the result source address. **/ BELLESIP_EXPORT void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen, int local_port); /** * This function will transform a V4 to V6 mapped address to a pure V4 and write it into result, or will just copy it otherwise. * The memory for v6 and result may be the same, in which case processing is done in place or no copy is done. * The pointer to result must have sufficient storage, typically a struct sockaddr_storage. **/ BELLESIP_EXPORT void belle_sip_address_remove_v4_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/sip-uri.h000066400000000000000000000201351252242224000204250ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_URI_H_ #define BELLE_SIP_URI_H_ #include "belle-sip/defs.h" #include "belle-sip/list.h" #include "belle-sip/utils.h" #include "belle-sip/types.h" BELLE_SIP_BEGIN_DECLS /** * */ BELLESIP_EXPORT belle_sip_uri_t* belle_sip_uri_new(); /** * */ BELLESIP_EXPORT belle_sip_uri_t* belle_sip_uri_parse (const char* uri) ; /** * */ BELLESIP_EXPORT belle_sip_uri_t* belle_sip_uri_create (const char* username,const char* host) ; /** * Returns the value of the named header, or null if it is not set. * */ BELLESIP_EXPORT const char* belle_sip_uri_get_header(const belle_sip_uri_t* uri,const char* name); /** * remove all headers * */ BELLESIP_EXPORT void belle_sip_uri_headers_clean(belle_sip_uri_t* uri); /** * Returns an Iterator over the const char*names of all headers present in this SipURI. * */ BELLESIP_EXPORT const belle_sip_list_t* belle_sip_uri_get_header_names(const belle_sip_uri_t* uri) ; /** * Returns the host part of this SipURI. * */ BELLESIP_EXPORT const char* belle_sip_uri_get_host(const belle_sip_uri_t* uri) ; /** * Returns the value of the maddr parameter, or null if this is not set. * */ BELLESIP_EXPORT const char* belle_sip_uri_get_maddr_param(const belle_sip_uri_t* uri) ; /** * Returns the value of the method parameter, or null if this is not set. * */ BELLESIP_EXPORT const char* belle_sip_uri_get_method_param(const belle_sip_uri_t* uri) ; /** * Returns the port part of this SipURI. * */ BELLESIP_EXPORT int belle_sip_uri_get_port(const belle_sip_uri_t* uri) ; /** * Returns the port of the uri, if not specified in the uri returns the well known port according to the transport. **/ BELLESIP_EXPORT int belle_sip_uri_get_listening_port(const belle_sip_uri_t *uri); /** * Returns the value of the "transport" parameter, or null if this is not set. * */ BELLESIP_EXPORT const char* belle_sip_uri_get_transport_param(const belle_sip_uri_t* uri) ; /** * Returns the value of the "ttl" parameter, or -1 if this is not set. * */ BELLESIP_EXPORT int belle_sip_uri_get_ttl_param(const belle_sip_uri_t* uri) ; /** * Returns the user part of this SipURI. * */ BELLESIP_EXPORT const char* belle_sip_uri_get_user(const belle_sip_uri_t* uri) ; /** * Returns the value of the userParam, or null if this is not set. * */ BELLESIP_EXPORT const char* belle_sip_uri_get_user_param(const belle_sip_uri_t* uri) ; /** * Gets user password of SipURI, or null if it is not set. * */ BELLESIP_EXPORT const char* belle_sip_uri_get_user_password(const belle_sip_uri_t* uri) ; /** * Returns whether the the lr parameter is set. * */ BELLESIP_EXPORT unsigned int belle_sip_uri_has_lr_param(const belle_sip_uri_t* uri) ; /** * * Returns true if this SipURI is secure i.e. if this SipURI represents a sips URI. * */ BELLESIP_EXPORT unsigned int belle_sip_uri_is_secure(const belle_sip_uri_t* uri) ; /** * Sets the value of the specified header fields to be included in a request constructed from the URI. * */ BELLESIP_EXPORT void belle_sip_uri_set_header(belle_sip_uri_t* uri,const char*name, const char*value) ; /** * Removes specified header from uri. **/ BELLESIP_EXPORT void belle_sip_uri_remove_header(belle_sip_uri_t *uri, const char *name); /** * Removes the port part of this SipURI. * */ BELLESIP_EXPORT void belle_sip_uri_remove_port(belle_sip_uri_t* uri) ; /** * Set the host part of this SipURI to the newly supplied host parameter. * */ BELLESIP_EXPORT void belle_sip_uri_set_host(belle_sip_uri_t* uri,const char*host) ; /** * Sets the value of the lr parameter of this SipURI. * */ BELLESIP_EXPORT void belle_sip_uri_set_lr_param(belle_sip_uri_t* uri,unsigned int param) ; /** * Sets the value of the maddr parameter of this SipURI. * */ BELLESIP_EXPORT void belle_sip_uri_set_maddr_param(belle_sip_uri_t* uri,const char*mAddr) ; /** * Sets the value of the method parameter. * */ BELLESIP_EXPORT void belle_sip_uri_set_method_param(belle_sip_uri_t* uri,const char*method) ; /** * Set the port part of this SipURI to the newly supplied port parameter. * */ BELLESIP_EXPORT void belle_sip_uri_set_port(belle_sip_uri_t* uri, int port) ; /** * Sets the scheme of this URI to sip or sips depending on whether the argument is true or false. * */ BELLESIP_EXPORT void belle_sip_uri_set_secure(belle_sip_uri_t* uri,unsigned int secure) ; /** * Sets the value of the "transport" parameter. * */ BELLESIP_EXPORT void belle_sip_uri_set_transport_param(belle_sip_uri_t* uri,const char*transport) ; /** * Sets the value of the ttl parameter. * */ BELLESIP_EXPORT void belle_sip_uri_set_ttl_param(belle_sip_uri_t* uri,int ttl) ; /** * Sets the user of SipURI. * */ BELLESIP_EXPORT void belle_sip_uri_set_user(belle_sip_uri_t* uri,const char*user) ; /** * Sets the value of the user parameter. * */ BELLESIP_EXPORT void belle_sip_uri_set_user_param(belle_sip_uri_t* uri,const char*userParam) ; /** * Sets the user password associated with the user of SipURI. * */ BELLESIP_EXPORT void belle_sip_uri_set_user_password(belle_sip_uri_t* uri,const char*userPassword) ; /** * This method returns the URI as a string. * */ BELLESIP_EXPORT char* belle_sip_uri_to_string(const belle_sip_uri_t* uri) ; belle_sip_error_code belle_sip_uri_marshal(const belle_sip_uri_t* uri, char* buff, size_t buff_size, size_t *offset); #define BELLE_SIP_URI(obj) BELLE_SIP_CAST(obj,belle_sip_uri_t) /**define URI equality as using comparison rules from RFC3261 section 19.1.4 * @param belle_sip_uri_t* uri_a * @param belle_sip_uri_t* uri_a * @return 0 if not matched. * * */ BELLESIP_EXPORT int belle_sip_uri_equals(const belle_sip_uri_t* uri_a,const belle_sip_uri_t* uri_b); /** * returns 0 if uri does follows components requirement for being a request uri * */ BELLESIP_EXPORT int belle_sip_uri_check_components_from_request_uri(const belle_sip_uri_t* uri); /** * returns 0 if uri does follows components requirement for a given method/header */ BELLESIP_EXPORT int belle_sip_uri_check_components_from_context(const belle_sip_uri_t* uri,const char* method,const char* header_name); BELLE_SIP_END_DECLS #if defined(__cplusplus) && defined(BELLE_SIP_USE_STL) #include inline std::ostream& operator<<( std::ostream& __os, const belle_sip_uri_t* uri) { char* uri_as_string = belle_sip_uri_to_string(uri); __os << uri_as_string; belle_sip_free(uri_as_string); return __os; } template <> struct std::hash { size_t operator()(const belle_sip_uri_t *x ) const { std::hash H; size_t h=0; if (belle_sip_uri_get_user(x)) h = H(belle_sip_uri_get_user(x)); if (belle_sip_uri_get_host(x)) h ^=H(belle_sip_uri_get_host(x)); if (belle_sip_uri_get_port(x)>0) { std::hash H2; h ^=H2(belle_sip_uri_get_port(x)); } if (belle_sip_uri_get_transport_param(x)) { h ^=H(belle_sip_uri_get_transport_param(x)); } if (belle_sip_uri_is_secure(x)) h+=1; return h; } }; #include namespace bellesip { struct UriComparator : public std::binary_function { bool operator()(const belle_sip_uri_t* lhs, const belle_sip_uri_t* rhs) const { return belle_sip_uri_equals(lhs,rhs); } }; } #endif #endif /*BELLE_SIP_URI_H_*/ belle-sip-1.4.1/include/belle-sip/sipstack.h000066400000000000000000000130461252242224000206610ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_stack_h #define belle_sip_stack_h struct belle_sip_timer_config{ int T1; int T2; int T3; int T4; }; typedef struct belle_sip_timer_config belle_sip_timer_config_t; BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT belle_sip_stack_t * belle_sip_stack_new(const char *properties); BELLESIP_EXPORT belle_sip_listening_point_t *belle_sip_stack_create_listening_point(belle_sip_stack_t *s, const char *ipaddress, int port, const char *transport); BELLESIP_EXPORT void belle_sip_stack_delete_listening_point(belle_sip_stack_t *s, belle_sip_listening_point_t *lp); BELLESIP_EXPORT belle_sip_provider_t *belle_sip_stack_create_provider(belle_sip_stack_t *s, belle_sip_listening_point_t *lp); BELLESIP_EXPORT belle_http_provider_t * belle_sip_stack_create_http_provider(belle_sip_stack_t *s, const char *bind_ip); BELLESIP_EXPORT belle_sip_main_loop_t* belle_sip_stack_get_main_loop(belle_sip_stack_t *stack); BELLESIP_EXPORT void belle_sip_stack_main(belle_sip_stack_t *stack); BELLESIP_EXPORT void belle_sip_stack_sleep(belle_sip_stack_t *stack, unsigned int milliseconds); /*the transport timeout is typically the maximum time given for making a connection*/ BELLESIP_EXPORT void belle_sip_stack_set_transport_timeout(belle_sip_stack_t *stack, int timeout_ms); BELLESIP_EXPORT int belle_sip_stack_get_transport_timeout(const belle_sip_stack_t *stack); BELLESIP_EXPORT int belle_sip_stack_get_dns_timeout(const belle_sip_stack_t *stack); BELLESIP_EXPORT void belle_sip_stack_set_dns_timeout(belle_sip_stack_t *stack, int timeout); BELLESIP_EXPORT unsigned char belle_sip_stack_dns_srv_enabled(const belle_sip_stack_t *stack); BELLESIP_EXPORT void belle_sip_stack_enable_dns_srv(belle_sip_stack_t *stack, unsigned char enable); /** * Can be used to simulate network transmission delays, for tests. **/ BELLESIP_EXPORT void belle_sip_stack_set_tx_delay(belle_sip_stack_t *stack, int delay_ms); /** * Can be used to simulate network sending error, for tests. * @param stack * @param send_error if <0, will cause channel error to be reported **/ BELLESIP_EXPORT void belle_sip_stack_set_send_error(belle_sip_stack_t *stack, int send_error); /** * Can be used to simulate network transmission delays, for tests. **/ BELLESIP_EXPORT void belle_sip_stack_set_resolver_tx_delay(belle_sip_stack_t *stack, int delay_ms); /** * Can be used to simulate network sending error, for tests. * @param stack * @param send_error if <0, will cause the resolver to fail with this error code. **/ BELLESIP_EXPORT void belle_sip_stack_set_resolver_send_error(belle_sip_stack_t *stack, int send_error); /** * Get the additional DNS hosts file. * @return The path to the additional DNS hosts file. **/ BELLESIP_EXPORT const char * belle_sip_stack_get_dns_user_hosts_file(const belle_sip_stack_t *stack); /** * Can be used to load an additional DNS hosts file for tests. * @param stack * @param hosts_file The path to the additional DNS hosts file to load. **/ BELLESIP_EXPORT void belle_sip_stack_set_dns_user_hosts_file(belle_sip_stack_t *stack, const char *hosts_file); /** * Get the overriding DNS resolv.conf file. * @return The path to the overriding DNS resolv.conf file. **/ BELLESIP_EXPORT const char * belle_sip_stack_get_dns_resolv_conf_file(const belle_sip_stack_t *stack); /** * Can be used to load an overriding DNS resolv.conf file for tests. * @param stack * @param hosts_file The path to the overriding DNS resolv.conf file to load. **/ BELLESIP_EXPORT void belle_sip_stack_set_dns_resolv_conf_file(belle_sip_stack_t *stack, const char *hosts_file); /** * Returns the time interval in seconds after which a connection must be closed when inactive. **/ BELLESIP_EXPORT int belle_sip_stack_get_inactive_transport_timeout(const belle_sip_stack_t *stack); /** * Sets the time interval in seconds after which a connection must be closed when inactive. **/ BELLESIP_EXPORT void belle_sip_stack_set_inactive_transport_timeout(belle_sip_stack_t *stack, int seconds); /** * Set the default dscp value to be used for all SIP sockets created and used in the stack. **/ BELLESIP_EXPORT void belle_sip_stack_set_default_dscp(belle_sip_stack_t *stack, int dscp); /** * Get the default dscp value to be used for all SIP sockets created and used in the stack. **/ BELLESIP_EXPORT int belle_sip_stack_get_default_dscp(belle_sip_stack_t *stack); /** * Returns TRUE if TLS support has been compiled into, FALSE otherwise. **/ BELLESIP_EXPORT int belle_sip_stack_tls_available(belle_sip_stack_t *stack); /* * returns timer config for this stack * */ BELLESIP_EXPORT const belle_sip_timer_config_t *belle_sip_stack_get_timer_config(const belle_sip_stack_t *stack); /* * * set sip timer config to be used for this stack * */ BELLESIP_EXPORT void belle_sip_stack_set_timer_config(belle_sip_stack_t *stack, const belle_sip_timer_config_t *timer_config); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/transaction.h000066400000000000000000000114071252242224000213640ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_TRANSACTION_H #define BELLE_SIP_TRANSACTION_H typedef enum belle_sip_transaction_state{ BELLE_SIP_TRANSACTION_INIT, BELLE_SIP_TRANSACTION_CALLING, BELLE_SIP_TRANSACTION_COMPLETED, BELLE_SIP_TRANSACTION_CONFIRMED, BELLE_SIP_TRANSACTION_ACCEPTED, /* BELLE_SIP_TRANSACTION_INIT, *
BELLE_SIP_TRANSACTION_CALLING, *
BELLE_SIP_TRANSACTION_PROCEEDING, *
BELLE_SIP_TRANSACTION_TRYING, * @param state * @return 0 if not transient * */ BELLESIP_EXPORT int belle_sip_transaction_state_is_transient(const belle_sip_transaction_state_t state); BELLESIP_EXPORT void *belle_sip_transaction_get_application_data(const belle_sip_transaction_t *t); BELLESIP_EXPORT void belle_sip_transaction_set_application_data(belle_sip_transaction_t *t, void *data); BELLESIP_EXPORT const char *belle_sip_transaction_get_branch_id(const belle_sip_transaction_t *t); BELLESIP_EXPORT belle_sip_transaction_state_t belle_sip_transaction_get_state(const belle_sip_transaction_t *t); BELLESIP_EXPORT const char *belle_sip_transaction_get_method(const belle_sip_transaction_t *t); BELLESIP_EXPORT void belle_sip_transaction_terminate(belle_sip_transaction_t *t); BELLESIP_EXPORT belle_sip_request_t *belle_sip_transaction_get_request(const belle_sip_transaction_t *t); BELLESIP_EXPORT belle_sip_response_t *belle_sip_transaction_get_response(const belle_sip_transaction_t *t); BELLESIP_EXPORT belle_sip_dialog_t* belle_sip_transaction_get_dialog(const belle_sip_transaction_t *t); BELLESIP_EXPORT void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp); BELLESIP_EXPORT belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t); BELLESIP_EXPORT int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t); /* * Same as #belle_sip_client_transaction_send_request but with a predefined route. * @param t belle_sip_client_transaction_t * @param outbound_proxy uri use to directly send the request, useful for outbound proxy. * */ BELLESIP_EXPORT int belle_sip_client_transaction_send_request_to(belle_sip_client_transaction_t *t,belle_sip_uri_t* outbound_proxy); BELLESIP_EXPORT belle_sip_uri_t *belle_sip_client_transaction_get_route(belle_sip_client_transaction_t *t); /** * Creates an a sip refresher for transaction like REGISTER/SUBSCRIBE or INVITE which could be refreshed. * Transaction must in be in stated BELLE_SIP_TRANSACTION_COMPLETED. Refresher is created and started. A ref is taken on object transaction * */ BELLESIP_EXPORT belle_sip_refresher_t* belle_sip_client_transaction_create_refresher(belle_sip_client_transaction_t *t); /** * Create an authenticated request based on an existing terminated transaction. *
This function, update cseq, put route set and try to fill authorization headers. Initial request is not cloned. * @param transaction . must be in state completed * @param auth_infos if auth infos cannot be added for an authenticate header, * @param realm optional - If an outbound proxy realm is used, digestion authentication can be optimized. * a newly allocated belle_sip_auth_info_t object is added to this list. These object contains useful information like realm and username. May be NULL * */ BELLESIP_EXPORT belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos,const char* realm); #define BELLE_SIP_TRANSACTION(t) BELLE_SIP_CAST(t,belle_sip_transaction_t) #define BELLE_SIP_SERVER_TRANSACTION(t) BELLE_SIP_CAST(t,belle_sip_server_transaction_t) #define BELLE_SIP_CLIENT_TRANSACTION(t) BELLE_SIP_CAST(t,belle_sip_client_transaction_t) BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/types.h000066400000000000000000000174421252242224000202100ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_TYPES_H #define BELLE_SIP_TYPES_H #include "belle-sip/defs.h" #include "belle-sip/object.h" #include "belle-sip/dict.h" /** * This enum declares all object types used in belle-sip (see belle_sip_object_t) **/ BELLE_SIP_DECLARE_TYPES_BEGIN(belle_sip,1) BELLE_SIP_TYPE_ID(belle_sip_stack_t), BELLE_SIP_TYPE_ID(belle_sip_hop_t), BELLE_SIP_TYPE_ID(belle_sip_object_pool_t), BELLE_SIP_TYPE_ID(belle_sip_listening_point_t), BELLE_SIP_TYPE_ID(belle_sip_datagram_listening_point_t), BELLE_SIP_TYPE_ID(belle_sip_udp_listening_point_t), BELLE_SIP_TYPE_ID(belle_sip_stream_listening_point_t), BELLE_SIP_TYPE_ID(belle_sip_tls_listening_point_t), BELLE_SIP_TYPE_ID(belle_sip_tunnel_listening_point_t), BELLE_SIP_TYPE_ID(belle_sip_channel_t), BELLE_SIP_TYPE_ID(belle_sip_udp_channel_t), BELLE_SIP_TYPE_ID(belle_sip_stream_channel_t), BELLE_SIP_TYPE_ID(belle_sip_tls_channel_t), BELLE_SIP_TYPE_ID(belle_sip_tunnel_channel_t), BELLE_SIP_TYPE_ID(belle_sip_provider_t), BELLE_SIP_TYPE_ID(belle_sip_main_loop_t), BELLE_SIP_TYPE_ID(belle_sip_source_t), BELLE_SIP_TYPE_ID(belle_sip_resolver_context_t), BELLE_SIP_TYPE_ID(belle_sip_transaction_t), BELLE_SIP_TYPE_ID(belle_sip_server_transaction_t), BELLE_SIP_TYPE_ID(belle_sip_client_transaction_t), BELLE_SIP_TYPE_ID(belle_sip_ict_t), BELLE_SIP_TYPE_ID(belle_sip_nict_t), BELLE_SIP_TYPE_ID(belle_sip_ist_t), BELLE_SIP_TYPE_ID(belle_sip_nist_t), BELLE_SIP_TYPE_ID(belle_sip_dialog_t), BELLE_SIP_TYPE_ID(belle_sip_header_address_t), BELLE_SIP_TYPE_ID(belle_sip_header_contact_t), BELLE_SIP_TYPE_ID(belle_sip_header_from_t), BELLE_SIP_TYPE_ID(belle_sip_header_to_t), BELLE_SIP_TYPE_ID(belle_sip_header_via_t), BELLE_SIP_TYPE_ID(belle_sip_uri_t), BELLE_SIP_TYPE_ID(belle_sip_message_t), BELLE_SIP_TYPE_ID(belle_sip_request_t), BELLE_SIP_TYPE_ID(belle_sip_response_t), BELLE_SIP_TYPE_ID(belle_sip_object_t), BELLE_SIP_TYPE_ID(belle_sip_parameters_t), BELLE_SIP_TYPE_ID(belle_sip_header_call_id_t), BELLE_SIP_TYPE_ID(belle_sip_header_cseq_t), BELLE_SIP_TYPE_ID(belle_sip_header_content_type_t), BELLE_SIP_TYPE_ID(belle_sip_header_route_t), BELLE_SIP_TYPE_ID(belle_sip_header_record_route_t), BELLE_SIP_TYPE_ID(belle_sip_header_user_agent_t), BELLE_SIP_TYPE_ID(belle_sip_header_content_length_t), BELLE_SIP_TYPE_ID(belle_sip_header_t), BELLE_SIP_TYPE_ID(belle_sip_header_extension_t), BELLE_SIP_TYPE_ID(belle_sip_header_authorization_t), BELLE_SIP_TYPE_ID(belle_sip_header_proxy_authorization_t), BELLE_SIP_TYPE_ID(belle_sip_header_www_authenticate_t), BELLE_SIP_TYPE_ID(belle_sip_header_proxy_authenticate_t), BELLE_SIP_TYPE_ID(belle_sip_header_max_forwards_t), BELLE_SIP_TYPE_ID(belle_sip_header_expires_t), BELLE_SIP_TYPE_ID(belle_sip_header_allow_t), BELLE_SIP_TYPE_ID(belle_sdp_attribute_t), BELLE_SIP_TYPE_ID(belle_sdp_bandwidth_t), BELLE_SIP_TYPE_ID(belle_sdp_connection_t), BELLE_SIP_TYPE_ID(belle_sdp_email_t), BELLE_SIP_TYPE_ID(belle_sdp_info_t), BELLE_SIP_TYPE_ID(belle_sdp_key_t), BELLE_SIP_TYPE_ID(belle_sdp_media_t), BELLE_SIP_TYPE_ID(belle_sdp_media_description_t), BELLE_SIP_TYPE_ID(belle_sdp_origin_t), BELLE_SIP_TYPE_ID(belle_sdp_phone_t), BELLE_SIP_TYPE_ID(belle_sdp_raw_attribute_t), BELLE_SIP_TYPE_ID(belle_sdp_repeate_time_t), BELLE_SIP_TYPE_ID(belle_sdp_rtcp_fb_attribute_t), BELLE_SIP_TYPE_ID(belle_sdp_rtcp_xr_attribute_t), BELLE_SIP_TYPE_ID(belle_sdp_session_description_t), BELLE_SIP_TYPE_ID(belle_sdp_session_name_t), BELLE_SIP_TYPE_ID(belle_sdp_time_t), BELLE_SIP_TYPE_ID(belle_sdp_time_description_t), BELLE_SIP_TYPE_ID(belle_sdp_uri_t), BELLE_SIP_TYPE_ID(belle_sdp_version_t), BELLE_SIP_TYPE_ID(belle_sdp_base_description_t), BELLE_SIP_TYPE_ID(belle_sdp_mime_parameter_t), BELLE_SIP_TYPE_ID(belle_sip_callbacks_t), BELLE_SIP_TYPE_ID(belle_sip_refresher_t), BELLE_SIP_TYPE_ID(belle_sip_header_subscription_state_t), BELLE_SIP_TYPE_ID(belle_sip_header_service_route_t), BELLE_SIP_TYPE_ID(belle_sip_header_refer_to_t), BELLE_SIP_TYPE_ID(belle_sip_header_referred_by_t), BELLE_SIP_TYPE_ID(belle_sip_header_replaces_t), BELLE_SIP_TYPE_ID(belle_sip_header_date_t), BELLE_SIP_TYPE_ID(belle_sip_header_p_preferred_identity_t), BELLE_SIP_TYPE_ID(belle_sip_header_privacy_t), BELLE_SIP_TYPE_ID(belle_sip_certificates_chain_t), BELLE_SIP_TYPE_ID(belle_sip_signing_key_t), BELLE_SIP_TYPE_ID(belle_sip_dns_srv_t), BELLE_SIP_TYPE_ID(belle_sip_simple_resolver_context_t), BELLE_SIP_TYPE_ID(belle_sip_combined_resolver_context_t), BELLE_SIP_TYPE_ID(belle_sip_dict_t), BELLE_SIP_TYPE_ID(belle_sip_dual_resolver_context_t), BELLE_SIP_TYPE_ID(belle_http_provider_t), BELLE_SIP_TYPE_ID(belle_http_request_t), BELLE_SIP_TYPE_ID(belle_http_response_t), BELLE_SIP_TYPE_ID(belle_http_channel_context_t), BELLE_SIP_TYPE_ID(belle_generic_uri_t), BELLE_SIP_TYPE_ID(belle_http_callbacks_t), BELLE_SIP_TYPE_ID(belle_tls_verify_policy_t), BELLE_SIP_TYPE_ID(belle_http_header_authorization_t), BELLE_SIP_TYPE_ID(belle_sip_body_handler_t), BELLE_SIP_TYPE_ID(belle_sip_memory_body_handler_t), BELLE_SIP_TYPE_ID(belle_sip_user_body_handler_t), BELLE_SIP_TYPE_ID(belle_sip_file_body_handler_t), BELLE_SIP_TYPE_ID(belle_sip_multipart_body_handler_t), BELLE_SIP_TYPE_ID(belle_sip_header_event_t) BELLE_SIP_DECLARE_TYPES_END enum belle_sip_interface_ids{ belle_sip_interface_id_first=1, BELLE_SIP_INTERFACE_ID(belle_sip_channel_listener_t), BELLE_SIP_INTERFACE_ID(belle_sip_listener_t), BELLE_SIP_INTERFACE_ID(belle_http_request_listener_t) }; /*these types are declared here because they are widely used in many headers included after*/ typedef struct belle_sip_listening_point belle_sip_listening_point_t; typedef struct belle_sip_tls_listening_point belle_sip_tls_listening_point_t; typedef struct belle_sip_stack belle_sip_stack_t; typedef struct belle_sip_provider belle_sip_provider_t; typedef struct belle_http_provider belle_http_provider_t; typedef struct belle_sip_dialog belle_sip_dialog_t; typedef struct belle_sip_transaction belle_sip_transaction_t; typedef struct belle_sip_server_transaction belle_sip_server_transaction_t; typedef struct belle_sip_client_transaction belle_sip_client_transaction_t; typedef struct _belle_sip_message belle_sip_message_t; typedef struct _belle_sip_request belle_sip_request_t; typedef struct _belle_sip_response belle_sip_response_t; typedef struct belle_http_request belle_http_request_t; typedef struct belle_http_response belle_http_response_t; typedef struct belle_sip_hop belle_sip_hop_t; typedef struct _belle_generic_uri belle_generic_uri_t; typedef struct _belle_sip_uri belle_sip_uri_t; typedef struct _belle_sip_parameters belle_sip_parameters_t; typedef struct belle_sip_param_pair belle_sip_param_pair_t; typedef struct _belle_sip_header belle_sip_header_t; typedef struct belle_tls_verify_policy belle_tls_verify_policy_t; typedef struct belle_sip_body_handler belle_sip_body_handler_t; typedef struct belle_sip_memory_body_handler belle_sip_memory_body_handler_t; typedef struct belle_sip_user_body_handler belle_sip_user_body_handler_t; typedef struct belle_sip_file_body_handler belle_sip_file_body_handler_t; typedef struct belle_sip_multipart_body_handler belle_sip_multipart_body_handler_t; #endif belle-sip-1.4.1/include/belle-sip/utils.h000066400000000000000000000143331252242224000202000ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_UTILS_H #define BELLE_SIP_UTILS_H #include #include #include #include #include "belle-sip/defs.h" BELLE_SIP_BEGIN_DECLS BELLESIP_EXPORT void *belle_sip_malloc(size_t size); BELLESIP_EXPORT void *belle_sip_malloc0(size_t size); BELLESIP_EXPORT void *belle_sip_realloc(void *ptr, size_t size); BELLESIP_EXPORT void belle_sip_free(void *ptr); BELLESIP_EXPORT char * belle_sip_strdup(const char *s); BELLE_SIP_END_DECLS /***************/ /* logging api */ /***************/ typedef enum { BELLE_SIP_LOG_FATAL=1, BELLE_SIP_LOG_ERROR=1<<1, BELLE_SIP_LOG_WARNING=1<<2, BELLE_SIP_LOG_MESSAGE=1<<3, BELLE_SIP_LOG_DEBUG=1<<4, BELLE_SIP_LOG_END=1<<5 } belle_sip_log_level; typedef void (*belle_sip_log_function_t)(belle_sip_log_level lev, const char *fmt, va_list args); typedef enum { BELLE_SIP_NOT_IMPLEMENTED = -2, BELLE_SIP_BUFFER_OVERFLOW = -1, BELLE_SIP_OK = 0 } belle_sip_error_code; #ifdef __GNUC__ #define BELLE_SIP_CHECK_FORMAT_ARGS(m,n) __attribute__((format(printf,m,n))) #else #define BELLE_SIP_CHECK_FORMAT_ARGS(m,n) #endif BELLE_SIP_BEGIN_DECLS BELLESIP_VAR_EXPORT belle_sip_log_function_t belle_sip_logv_out; BELLESIP_VAR_EXPORT unsigned int __belle_sip_log_mask; #define belle_sip_log_level_enabled(level) (__belle_sip_log_mask & (level)) #if !defined(WIN32) && !defined(_WIN32_WCE) #define belle_sip_logv(level,fmt,args) \ {\ if (belle_sip_logv_out!=NULL && belle_sip_log_level_enabled(level)) \ belle_sip_logv_out(level,fmt,args);\ if ((level)==BELLE_SIP_LOG_FATAL) abort();\ }while(0) #else BELLESIP_EXPORT void belle_sip_logv(int level, const char *fmt, va_list args); #endif #ifdef BELLE_SIP_DEBUG_MODE static BELLESIP_INLINE void belle_sip_debug(const char *fmt,...) { va_list args; va_start (args, fmt); belle_sip_logv(BELLE_SIP_LOG_DEBUG, fmt, args); va_end (args); } #else #define belle_sip_debug(...) #endif #ifdef BELLE_SIP_NOMESSAGE_MODE #define belle_sip_log(...) #define belle_sip_message(...) #define belle_sip_warning(...) #else static BELLESIP_INLINE void BELLE_SIP_CHECK_FORMAT_ARGS(2,3) belle_sip_log(belle_sip_log_level lev, const char *fmt,...){ va_list args; va_start (args, fmt); belle_sip_logv(lev, fmt, args); va_end (args); } static BELLESIP_INLINE void BELLE_SIP_CHECK_FORMAT_ARGS(1,2) belle_sip_message(const char *fmt,...) { va_list args; va_start (args, fmt); belle_sip_logv(BELLE_SIP_LOG_MESSAGE, fmt, args); va_end (args); } static BELLESIP_INLINE void BELLE_SIP_CHECK_FORMAT_ARGS(1,2) belle_sip_warning(const char *fmt,...) { va_list args; va_start (args, fmt); belle_sip_logv(BELLE_SIP_LOG_WARNING, fmt, args); va_end (args); } #endif static BELLESIP_INLINE void BELLE_SIP_CHECK_FORMAT_ARGS(1,2) belle_sip_error(const char *fmt,...) { va_list args; va_start (args, fmt); belle_sip_logv(BELLE_SIP_LOG_ERROR, fmt, args); va_end (args); } static BELLESIP_INLINE void BELLE_SIP_CHECK_FORMAT_ARGS(1,2) belle_sip_fatal(const char *fmt,...) { va_list args; va_start (args, fmt); belle_sip_logv(BELLE_SIP_LOG_FATAL, fmt, args); va_end (args); } BELLESIP_EXPORT void belle_sip_set_log_file(FILE *file); BELLESIP_EXPORT void belle_sip_set_log_handler(belle_sip_log_function_t func); BELLESIP_EXPORT belle_sip_log_function_t belle_sip_get_log_handler(); BELLESIP_EXPORT char * BELLE_SIP_CHECK_FORMAT_ARGS(1,2) belle_sip_strdup_printf(const char *fmt,...); BELLESIP_EXPORT char * belle_sip_strcat_vprintf(char* dst, const char *fmt, va_list ap); BELLESIP_EXPORT char * BELLE_SIP_CHECK_FORMAT_ARGS(2,3) belle_sip_strcat_printf(char* dst, const char *fmt,...); BELLESIP_EXPORT belle_sip_error_code BELLE_SIP_CHECK_FORMAT_ARGS(4,5) belle_sip_snprintf(char *buff, size_t buff_size, size_t *offset, const char *fmt, ...); BELLESIP_EXPORT belle_sip_error_code belle_sip_snprintf_valist(char *buff, size_t buff_size, size_t *offset, const char *fmt, va_list args); BELLESIP_EXPORT void belle_sip_set_log_level(int level); BELLESIP_EXPORT char * belle_sip_random_token(char *ret, size_t size); BELLESIP_EXPORT unsigned char * belle_sip_random_bytes(unsigned char *ret, size_t size); BELLESIP_EXPORT char * belle_sip_octets_to_text(const unsigned char *hash, size_t hash_len, char *ret, size_t size); BELLESIP_EXPORT char * belle_sip_create_tag(char *ret, size_t size); BELLESIP_EXPORT const char* belle_sip_version_to_string(); /** * Returns string without surrounding quotes if any, else just call belle_sip_strdup(). **/ BELLESIP_EXPORT char *belle_sip_unquote_strdup(const char *str); BELLESIP_EXPORT uint64_t belle_sip_time_ms(void); BELLESIP_EXPORT unsigned int belle_sip_random(void); #if defined(WIN32) #include #include typedef SOCKET belle_sip_socket_t; typedef HANDLE belle_sip_fd_t; #else #include #include #include typedef int belle_sip_socket_t; typedef int belle_sip_fd_t; #endif BELLESIP_EXPORT int belle_sip_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); BELLESIP_EXPORT void belle_sip_freeaddrinfo(struct addrinfo *res); typedef void (*belle_sip_background_task_end_callback_t)(void *); BELLESIP_EXPORT unsigned long belle_sip_begin_background_task(const char *name, belle_sip_background_task_end_callback_t cb, void *data); BELLESIP_EXPORT void belle_sip_end_background_task(unsigned long id); BELLE_SIP_END_DECLS #endif belle-sip-1.4.1/include/belle-sip/wakelock.h000066400000000000000000000011401252242224000206300ustar00rootroot00000000000000#ifndef WAKE_LOCK_H #define WAKE_LOCK_H #include #include "belle-sip/defs.h" /** * Initialize the Android wake lock system inside Belle-SIP. * This function must be called only once when the program starts. * @param env A JNI environment * @parma pm An android.os.PowerManager java object. */ BELLESIP_EXPORT void bellesip_wake_lock_init(JNIEnv *env, jobject pm); /** * Uninit the the Android wake lock system. This function may be called * while the program stopping. * @param env A JNI environment. */ BELLESIP_EXPORT void bellesip_wake_lock_uninit(JNIEnv *env); #endif // WALE_LOCK_H belle-sip-1.4.1/src/000077500000000000000000000000001252242224000141535ustar00rootroot00000000000000belle-sip-1.4.1/src/CMakeLists.txt000066400000000000000000000120511252242224000167120ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ set(INCLUDES ${ANTLR3C_INCLUDE_DIRS}) set(LIBS ${ANTLR3C_LIBRARIES}) if(Threads_FOUND) if(CMAKE_USE_PTHREADS_INIT AND NOT CMAKE_SYSTEM_NAME MATCHES "QNX") list(APPEND LIBS pthread) endif() endif() if(HAVE_LIBDL) list(APPEND LIBS dl) endif() if(HAVE_LIBRT) list(APPEND LIBS rt) endif() if(HAVE_RESINIT) list(APPEND LIBS resolv) endif() if(WIN32) list(APPEND LIBS ws2_32) endif() set(SDP_GENERATED_SOURCE_FILES ${CMAKE_CURRENT_BINARY_DIR}/grammars/belle_sdpLexer.c ${CMAKE_CURRENT_BINARY_DIR}/grammars/belle_sdpLexer.h ${CMAKE_CURRENT_BINARY_DIR}/grammars/belle_sdpParser.c ${CMAKE_CURRENT_BINARY_DIR}/grammars/belle_sdpParser.h ) add_custom_command( OUTPUT ${SDP_GENERATED_SOURCE_FILES} COMMAND ${ANTLR3_COMMAND} -make -Xmultithreaded -Xconversiontimeout 10000 -fo ${CMAKE_CURRENT_BINARY_DIR}/grammars ${CMAKE_CURRENT_SOURCE_DIR}/grammars/belle_sdp.g DEPENDS grammars/belle_sdp.g ) set(SIP_MESSAGE_GENERATED_SOURCE_FILES ${CMAKE_CURRENT_BINARY_DIR}/grammars/belle_sip_messageLexer.c ${CMAKE_CURRENT_BINARY_DIR}/grammars/belle_sip_messageLexer.h ${CMAKE_CURRENT_BINARY_DIR}/grammars/belle_sip_messageParser.c ${CMAKE_CURRENT_BINARY_DIR}/grammars/belle_sip_messageParser.h ) add_custom_command( OUTPUT ${SIP_MESSAGE_GENERATED_SOURCE_FILES} COMMAND ${ANTLR3_COMMAND} -make -Xmultithreaded -Xconversiontimeout 10000 -fo ${CMAKE_CURRENT_BINARY_DIR}/grammars ${CMAKE_CURRENT_SOURCE_DIR}/grammars/belle_sip_message.g DEPENDS grammars/belle_sip_message.g ) set_source_files_properties(${GRAMMARS_SOURCE_FILES} ${SIP_MESSAGE_GENERATED_SOURCE_FILES} PROPERTIES GENERATED TRUE) if(ENABLE_TLS) set(TLS_SOURCE_FILES transports/tls_listeningpoint_polarssl.c transports/tls_channel_polarssl.c ) list(APPEND INCLUDES ${POLARSSL_INCLUDE_DIR}) list(APPEND LIBS ${POLARSSL_LIBRARIES}) endif() if(ENABLE_TUNNEL) set(TUNNEL_SOURCE_FILES transports/tunnel_listeningpoint.c transports/tunnel_channel.c transports/tunnel_wrapper.cc ) set_source_files_properties(transports/tunnel_wrapper.cc PROPERTIES LANGUAGE CXX) list(APPEND LIBS ${TUNNEL_LIBRARIES}) endif() set(SOURCE_FILES auth_event.c auth_helper.c belle_sdp_impl.c belle_sip_dict.c belle_sip_headers_impl.c belle_sip_internal.h belle_sip_loop.c belle_sip_object.c belle_sip_parameters.c belle_sip_resolver.c belle_sip_uri_impl.c belle_sip_utils.c bodyhandler.c channel.c channel.h clock_gettime.c clock_gettime.h dialog.c dns.c dns.h generic-uri.c http-listener.c http-message.c http-provider.c ict.c ist.c listeningpoint.c listeningpoint_internal.h md5.c md5.h message.c nict.c nist.c parserutils.h port.c port.h provider.c refresher.c siplistener.c sipstack.c transaction.c transports/stream_channel.c transports/stream_channel.h transports/stream_listeningpoint.c transports/udp_channel.c transports/udp_listeningpoint.c ${SDP_GENERATED_SOURCE_FILES} ${SIP_MESSAGE_GENERATED_SOURCE_FILES} ${TLS_SOURCE_FILES} ${TUNNEL_SOURCE_FILES} ) if(APPLE) list(APPEND SOURCE_FILES backgroundtask.m) set_source_files_properties(backgroundtask.m PROPERTIES COMPILE_FLAGS "-fmodules") endif() if(ENABLE_STATIC) add_library(bellesip STATIC ${SOURCE_FILES}) else() add_library(bellesip SHARED ${SOURCE_FILES}) set_target_properties(bellesip PROPERTIES VERSION 0.0.0 SOVERSION 0) if(MSVC) if(CMAKE_BUILD_TYPE STREQUAL "Debug") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/bellesip.pdb DESTINATION bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) endif() endif() endif() set_target_properties(bellesip PROPERTIES LINKER_LANGUAGE CXX) string(REPLACE ";" " " LINK_FLAGS_STR "${LINK_FLAGS}") if(NOT "${LINK_FLAGS_STR}" STREQUAL "") set_target_properties(bellesip PROPERTIES LINK_FLAGS "${LINK_FLAGS_STR}") endif() target_include_directories(bellesip PUBLIC ${INCLUDES}) target_link_libraries(bellesip ${LIBS}) install(TARGETS bellesip EXPORT BelleSIPTargets RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) belle-sip-1.4.1/src/Makefile.am000077500000000000000000000036301252242224000162140ustar00rootroot00000000000000SUBDIRS=grammars AUTOMAKE_OPTIONS = subdir-objects lib_LTLIBRARIES=libbellesip.la libbellesip_la_SOURCES= \ clock_gettime.c clock_gettime.h \ port.c port.h \ parserutils.h \ belle_sip_uri_impl.c \ belle_sip_headers_impl.c \ belle_sip_utils.c belle_sip_internal.h \ belle_sip_object.c \ belle_sip_loop.c \ belle_sip_resolver.c \ belle_sip_parameters.c \ belle_sdp_impl.c \ transaction.c \ listeningpoint.c listeningpoint_internal.h \ sipstack.c \ provider.c \ channel.c channel.h \ message.c \ md5.c md5.h \ auth_helper.c \ siplistener.c \ ict.c \ ist.c \ nict.c \ nist.c \ dialog.c \ auth_event.c \ transports/udp_listeningpoint.c \ transports/udp_channel.c \ transports/stream_channel.c \ transports/stream_channel.h \ transports/stream_listeningpoint.c \ transports/tls_listeningpoint_polarssl.c \ transports/tls_channel_polarssl.c \ refresher.c \ dns.c dns.h \ belle_sip_dict.c \ generic-uri.c \ http-provider.c \ http-message.c \ http-listener.c \ bodyhandler.c if BUILD_APPLE libbellesip_la_SOURCES+=backgroundtask.m endif if BUILD_TUNNEL libbellesip_la_SOURCES+=transports/tunnel_listeningpoint.c \ transports/tunnel_channel.c \ transports/tunnel_wrapper.cc endif libbellesip_la_CFLAGS=$(STRICT_OPTIONS) $(STRICT_OPTIONS_CC) $(ANTLR_CFLAGS) $(TLS_CFLAGS) $(TUNNEL_CFLAGS) $(LIBBELLESIP_CFLAGS) libbellesip_la_CXXFLAGS=$(STRICT_OPTIONS) $(STRICT_OPTIONS_CXX) $(TLS_CFLAGS) $(TUNNEL_CFLAGS) $(LIBBELLESIP_CFLAGS) libbellesip_la_LIBADD=grammars/libbellesip_generated.la $(ANTLR_LIBS) $(TLS_LIBS) $(TUNNEL_LIBS) libbellesip_la_LDFLAGS=-no-undefined -version-info $(BELLESIP_SO_VERSION) $(LDFLAGS) AM_CPPFLAGS=-I$(top_srcdir)/include -I$(builddir)/grammars discovery: touch specs.c $(CC) $(CFLAGS) -include $(top_builddir)/config.h $(ANTLR_CFLAGS) $(CUNIT_CFLAGS) $(TLS_CFLAGS) -E -P -v -dD specs.c belle-sip-1.4.1/src/auth_event.c000066400000000000000000000102431252242224000164610ustar00rootroot00000000000000/* auth_info.c belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/auth-helper.h" #include "belle_sip_internal.h" GET_SET_STRING(belle_sip_auth_event,username) GET_SET_STRING(belle_sip_auth_event,userid) GET_SET_STRING(belle_sip_auth_event,realm) GET_SET_STRING(belle_sip_auth_event,domain) GET_SET_STRING(belle_sip_auth_event,passwd) GET_SET_STRING(belle_sip_auth_event,ha1) GET_SET_STRING(belle_sip_auth_event,distinguished_name) belle_sip_auth_event_t* belle_sip_auth_event_create(belle_sip_object_t *source, const char* realm, const belle_sip_uri_t *from_uri) { belle_sip_auth_event_t* result = belle_sip_new0(belle_sip_auth_event_t); result->source=source; belle_sip_auth_event_set_realm(result,realm); if (from_uri){ belle_sip_auth_event_set_username(result,belle_sip_uri_get_user(from_uri)); belle_sip_auth_event_set_domain(result,belle_sip_uri_get_host(from_uri)); } return result; } void belle_sip_auth_event_destroy(belle_sip_auth_event_t* event) { DESTROY_STRING(event,username); DESTROY_STRING(event,userid); DESTROY_STRING(event,realm); DESTROY_STRING(event,domain); DESTROY_STRING(event,passwd); DESTROY_STRING(event,ha1); DESTROY_STRING(event,distinguished_name); if (event->cert) belle_sip_object_unref(event->cert); if (event->key) belle_sip_object_unref(event->key); belle_sip_free(event); } belle_sip_certificates_chain_t* belle_sip_auth_event_get_client_certificates_chain(const belle_sip_auth_event_t* event) { return event->cert; } void belle_sip_auth_event_set_client_certificates_chain(belle_sip_auth_event_t* event, belle_sip_certificates_chain_t* value) { if (event->cert) belle_sip_object_unref(event->cert); event->cert=value; if (event->cert) belle_sip_object_ref(event->cert); } belle_sip_signing_key_t* belle_sip_auth_event_get_signing_key(const belle_sip_auth_event_t* event) { return event->key; } void belle_sip_auth_event_set_signing_key(belle_sip_auth_event_t* event, belle_sip_signing_key_t* value) { SET_OBJECT_PROPERTY(event,key,value); } belle_sip_auth_mode_t belle_sip_auth_event_get_mode(const belle_sip_auth_event_t* event) { return event->mode; } static void verify_policy_uninit(belle_tls_verify_policy_t *obj){ if (obj->root_ca) belle_sip_free(obj->root_ca); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_tls_verify_policy_t); BELLE_SIP_INSTANCIATE_VPTR(belle_tls_verify_policy_t,belle_sip_object_t,verify_policy_uninit,NULL,NULL,FALSE); belle_tls_verify_policy_t *belle_tls_verify_policy_new(){ belle_tls_verify_policy_t *obj=belle_sip_object_new(belle_tls_verify_policy_t); /*default to "system" default root ca, wihtout warranty...*/ #ifdef __linux belle_tls_verify_policy_set_root_ca(obj,"/etc/ssl/certs"); #elif defined(__APPLE__) belle_tls_verify_policy_set_root_ca(obj,"/opt/local/share/curl/curl-ca-bundle.crt"); #elif __QNX__ belle_tls_verify_policy_set_root_ca(obj,"/var/certs/web_trusted@personal@certmgr"); #endif return obj; } int belle_tls_verify_policy_set_root_ca(belle_tls_verify_policy_t *obj, const char *path){ if (obj->root_ca){ belle_sip_free(obj->root_ca); obj->root_ca=NULL; } if (path){ obj->root_ca=belle_sip_strdup(path); belle_sip_message("Root ca path set to %s",obj->root_ca); } else { belle_sip_message("Root ca path disabled"); } return 0; } void belle_tls_verify_policy_set_exceptions(belle_tls_verify_policy_t *obj, int flags){ obj->exception_flags=flags; } unsigned int belle_tls_verify_policy_get_exceptions(const belle_tls_verify_policy_t *obj){ return obj->exception_flags; } belle-sip-1.4.1/src/auth_helper.c000066400000000000000000000233461252242224000166270ustar00rootroot00000000000000/* auth_helper.c belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/auth-helper.h" #include "belle_sip_internal.h" #include "md5.h" #include #define CHECK_IS_PRESENT(obj,header_name,name) \ if (!belle_sip_header_##header_name##_get_##name(obj)) {\ belle_sip_error("parameter ["#name"]not found for header ["#header_name"]");\ return-1;\ } static void belle_sip_auth_helper_clone_authorization(belle_sip_header_authorization_t* authorization, const belle_sip_header_www_authenticate_t* authentication) { CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,scheme,authorization,authentication) CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,realm,authorization,authentication) CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,nonce,authorization,authentication) CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,algorithm,authorization,authentication) CLONE_STRING_GENERIC(belle_sip_header_www_authenticate,belle_sip_header_authorization,opaque,authorization,authentication) } belle_sip_header_authorization_t* belle_sip_auth_helper_create_authorization(const belle_sip_header_www_authenticate_t* authentication) { belle_sip_header_authorization_t* authorization = belle_sip_header_authorization_new(); belle_sip_auth_helper_clone_authorization(authorization,authentication); return authorization; } belle_http_header_authorization_t* belle_http_auth_helper_create_authorization(const belle_sip_header_www_authenticate_t* authentication) { belle_http_header_authorization_t* authorization = belle_http_header_authorization_new(); belle_sip_auth_helper_clone_authorization(BELLE_SIP_HEADER_AUTHORIZATION(authorization),authentication); return authorization; } belle_sip_header_proxy_authorization_t* belle_sip_auth_helper_create_proxy_authorization(const belle_sip_header_proxy_authenticate_t* proxy_authentication){ belle_sip_header_proxy_authorization_t* authorization = belle_sip_header_proxy_authorization_new(); belle_sip_auth_helper_clone_authorization(BELLE_SIP_HEADER_AUTHORIZATION(authorization),BELLE_SIP_HEADER_WWW_AUTHENTICATE(proxy_authentication)); return authorization; } int belle_sip_auth_helper_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]) { md5_byte_t out[16]; md5_state_t state; int di; if (!userid) { belle_sip_error("belle_sip_fill_authorization_header, username not found "); return -1; } if (!password) { belle_sip_error("belle_sip_fill_authorization_header, password not found "); return -1; } if (!realm) { belle_sip_error("belle_sip_fill_authorization_header, password not found "); return -1; } belle_sip_md5_init(&state); belle_sip_md5_append(&state,(const md5_byte_t *)userid,strlen(userid)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state,(const md5_byte_t *)realm,strlen(realm)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state,(const md5_byte_t *)password,strlen(password)); belle_sip_md5_finish(&state,out); for (di = 0; di < 16; ++di) sprintf(ha1 + di * 2, "%02x", out[di]); ha1[32]='\0'; return 0; } int belle_sip_auth_helper_compute_ha2(const char* method,const char* uri, char ha2[33]) { md5_byte_t out[16]; md5_state_t state; int di; ha2[32]='\0'; /*HA2=MD5(method:uri)*/ belle_sip_md5_init(&state); belle_sip_md5_append(&state,(const md5_byte_t *)method,strlen(method)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state,(const md5_byte_t *)uri,strlen(uri)); belle_sip_md5_finish(&state,out); for (di = 0; di < 16; ++di) sprintf(ha2 + di * 2, "%02x", out[di]); return 0; } int belle_sip_auth_helper_compute_response(const char* ha1,const char* nonce, const char* ha2, char response[33]) { md5_byte_t out[16]; md5_state_t state; int di; response[32]='\0'; belle_sip_md5_init(&state); belle_sip_md5_append(&state,(const md5_byte_t *)ha1,strlen(ha1)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state ,(const md5_byte_t *)nonce ,strlen(nonce)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state,(const md5_byte_t *)ha2,strlen(ha2)); belle_sip_md5_finish(&state,out); /*copy values*/ for (di = 0; di < 16; ++di) sprintf(response + di * 2, "%02x", out[di]); return 0; } int belle_sip_auth_helper_compute_response_qop_auth(const char* ha1 , const char* nonce , unsigned int nonce_count , const char* cnonce , const char* qop , const char* ha2, char response[33]) { md5_byte_t out[16]; md5_state_t state; char nounce_count_as_string[9]; int di; response[32]='\0'; snprintf(nounce_count_as_string,sizeof(nounce_count_as_string),"%08x",nonce_count); /*response=MD5(HA1:nonce:nonce_count:cnonce:qop:HA2)*/ belle_sip_md5_init(&state); belle_sip_md5_append(&state,(const md5_byte_t *)ha1,strlen(ha1)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state ,(const md5_byte_t *)nonce ,strlen(nonce)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state ,(const md5_byte_t *)nounce_count_as_string ,strlen(nounce_count_as_string)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state ,(const md5_byte_t *)cnonce ,strlen(cnonce)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state ,(const md5_byte_t *)qop ,strlen(qop)); belle_sip_md5_append(&state,(const md5_byte_t *)":",1); belle_sip_md5_append(&state,(const md5_byte_t *)ha2,strlen(ha2)); belle_sip_md5_finish(&state,out); /*copy values*/ for (di = 0; di < 16; ++di) sprintf(response + di * 2, "%02x", out[di]); return 0; } int belle_sip_auth_helper_fill_authorization(belle_sip_header_authorization_t* authorization ,const char* method ,const char* ha1) { int auth_mode=0; char* uri; char ha2[16*2 + 1]; char response[16*2 + 1]; char cnonce[9]; response[32]=ha2[32]='\0'; if (belle_sip_header_authorization_get_scheme(authorization) != NULL && strcmp("Digest",belle_sip_header_authorization_get_scheme(authorization))!=0) { belle_sip_error("belle_sip_fill_authorization_header, unsupported schema [%s]" ,belle_sip_header_authorization_get_scheme(authorization)); return -1; } if (belle_sip_header_authorization_get_qop(authorization) && !(auth_mode=strcmp("auth",belle_sip_header_authorization_get_qop(authorization))==0)) { belle_sip_error("belle_sip_fill_authorization_header, unsupported qop [%s], use auth or nothing instead" ,belle_sip_header_authorization_get_qop(authorization)); return -1; } CHECK_IS_PRESENT(authorization,authorization,realm) CHECK_IS_PRESENT(authorization,authorization,nonce) if (BELLE_SIP_IS_INSTANCE_OF(authorization,belle_http_header_authorization_t)) { /*http case*/ if (!belle_http_header_authorization_get_uri(BELLE_HTTP_HEADER_AUTHORIZATION(authorization))) { belle_sip_error("parameter uri not found for http header authorization"); return-1; } } else { CHECK_IS_PRESENT(authorization,authorization,uri) } if (auth_mode) { CHECK_IS_PRESENT(authorization,authorization,nonce_count) if (!belle_sip_header_authorization_get_cnonce(authorization)) { snprintf(cnonce,sizeof(cnonce),"%08x",(short)(long)authorization^0x5555555); /*spseudo randomly genrated cnonce*/ belle_sip_header_authorization_set_cnonce(authorization,cnonce); } } if (!method) { belle_sip_error("belle_sip_fill_authorization_header, method not found "); return -1; } if (BELLE_SIP_IS_INSTANCE_OF(authorization,belle_http_header_authorization_t)) { /*http case*/ uri=belle_generic_uri_to_string(belle_http_header_authorization_get_uri(BELLE_HTTP_HEADER_AUTHORIZATION(authorization))); } else { uri=belle_sip_uri_to_string(belle_sip_header_authorization_get_uri(authorization)); } belle_sip_auth_helper_compute_ha2(method,uri,ha2); belle_sip_free(uri); if (auth_mode) { /*response=MD5(HA1:nonce:nonce_count:cnonce:qop:HA2)*/ belle_sip_auth_helper_compute_response_qop_auth(ha1 ,belle_sip_header_authorization_get_nonce(authorization) ,belle_sip_header_authorization_get_nonce_count(authorization) ,belle_sip_header_authorization_get_cnonce(authorization) ,belle_sip_header_authorization_get_qop(authorization) ,ha2 ,response); } else { /*response=MD5(ha1:nonce:ha2)*/ belle_sip_auth_helper_compute_response(ha1,belle_sip_header_authorization_get_nonce(authorization),ha2,response); } belle_sip_header_authorization_set_response(authorization,(const char*)response); return 0; } int belle_sip_auth_helper_fill_proxy_authorization(belle_sip_header_proxy_authorization_t* proxy_authorization ,const char* method ,const char* ha1) { return belle_sip_auth_helper_fill_authorization(BELLE_SIP_HEADER_AUTHORIZATION(proxy_authorization) ,method, ha1); } belle-sip-1.4.1/src/backgroundtask.m000066400000000000000000000061331252242224000173360ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #if TARGET_OS_IPHONE==1 #include typedef struct fallback_callback_data{ unsigned long task_id; }fallback_callback_data_t; static void fallback_callback(void *data){ fallback_callback_data_t *fbd=(fallback_callback_data_t*)data; belle_sip_end_background_task(fbd->task_id); belle_sip_free(fbd); } unsigned long belle_sip_begin_background_task(const char *name, belle_sip_background_task_end_callback_t cb, void *data){ UIApplication *app=[UIApplication sharedApplication]; UIBackgroundTaskIdentifier bgid = UIBackgroundTaskInvalid; fallback_callback_data_t *fbd=NULL; if (cb==NULL){ cb=fallback_callback; data=fbd=(fallback_callback_data_t*)belle_sip_malloc0(sizeof(fallback_callback_data_t)); } void (^handler)() = ^{ cb(data); }; if([app respondsToSelector:@selector(beginBackgroundTaskWithName:expirationHandler:)]){ bgid = [app beginBackgroundTaskWithName:[NSString stringWithUTF8String:name] expirationHandler:handler]; } else { bgid = [app beginBackgroundTaskWithExpirationHandler:handler]; } if (bgid==UIBackgroundTaskInvalid){ belle_sip_error("Could not start background task %s.", name); return 0; } if (fbd) fbd->task_id=bgid; return (unsigned long)bgid; } void belle_sip_end_background_task(unsigned long id){ UIApplication *app=[UIApplication sharedApplication]; [app endBackgroundTask:(UIBackgroundTaskIdentifier)id]; } #else /*mac*/ @import Foundation; static unsigned long dummy_id=0; static id activity_id=0; static int activity_refcnt=0; unsigned long belle_sip_begin_background_task(const char *name, belle_sip_background_task_end_callback_t cb, void *data){ activity_refcnt++; if (activity_refcnt==1){ NSProcessInfo *pinfo=[NSProcessInfo processInfo]; if (pinfo && [pinfo respondsToSelector:@selector(beginActivityWithOptions:reason:)]){ activity_id=[pinfo beginActivityWithOptions:NSActivityUserInitiatedAllowingIdleSystemSleep reason:@"Processing SIP signaling"]; [activity_id retain]; belle_sip_message("Activity started"); } } return ++dummy_id; } void belle_sip_end_background_task(unsigned long id){ activity_refcnt--; if (activity_refcnt==0){ if (activity_id!=0){ NSProcessInfo *pinfo=[NSProcessInfo processInfo]; [pinfo endActivity:activity_id]; [activity_id release]; belle_sip_message("Activity ended"); activity_id=0; } } } #endif belle-sip-1.4.1/src/belle_sdp_impl.c000066400000000000000000002122341252242224000172750ustar00rootroot00000000000000/* belle-sdp - SIP (RFC4566) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/belle-sip.h" #include "grammars/belle_sdpParser.h" #include "grammars/belle_sdpLexer.h" #include "belle_sip_internal.h" struct _belle_sdp_mime_parameter { belle_sip_object_t base; int rate; int channel_count; int ptime; int max_ptime; int media_format; const char* type; const char* parameters; }; static void belle_sip_object_freefunc(void* obj) { belle_sip_object_unref(BELLE_SIP_OBJECT(obj)); } static void* belle_sip_object_copyfunc(void* obj) { return belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(obj)); } static void * belle_sip_string_copyfunc(void *obj) { return (void *)belle_sip_strdup((const char *)obj); } /*************************************************************************************** * Attribute * **************************************************************************************/ typedef belle_sdp_attribute_t* (*attribute_parse_func)(const char*) ; struct attribute_name_func_pair { const char* name; attribute_parse_func func; }; static struct attribute_name_func_pair attribute_table[] = { { "rtcp-fb", (attribute_parse_func)belle_sdp_rtcp_fb_attribute_parse }, { "rtcp-xr", (attribute_parse_func)belle_sdp_rtcp_xr_attribute_parse } }; struct _belle_sdp_attribute { belle_sip_object_t base; const char* name; char *unparsed_value; }; void belle_sdp_attribute_destroy(belle_sdp_attribute_t* attribute) { DESTROY_STRING(attribute,name) DESTROY_STRING(attribute,unparsed_value) } void belle_sdp_attribute_clone(belle_sdp_attribute_t *attribute, const belle_sdp_attribute_t *orig){ CLONE_STRING(belle_sdp_attribute,name,attribute,orig) } belle_sip_error_code belle_sdp_attribute_marshal(belle_sdp_attribute_t* attribute, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf(buff, buff_size, offset, "a=%s", attribute->name); } belle_sdp_attribute_t* belle_sdp_attribute_create(const char* name, const char* value) { belle_sdp_attribute_t* ret; int i; size_t elements = sizeof(attribute_table) / sizeof(attribute_table[0]); if (!name || name[0] == '\0') { belle_sip_error("Cannot create SDP attribute without name"); return NULL; } for (i = 0; i < elements; i++) { if (strcasecmp(attribute_table[i].name, name) == 0) { char* raw; if (value) raw = belle_sip_strdup_printf("a=%s:%s", name, value); else raw = belle_sip_strdup_printf("a=%s", name); ret = attribute_table[i].func(raw); belle_sip_free(raw); return ret; } } /* Not a specialized SDP attribute */ return BELLE_SDP_ATTRIBUTE(belle_sdp_raw_attribute_create(name, value)); } const char *belle_sdp_attribute_get_value(belle_sdp_attribute_t *attribute) { char *ret; char *end; if (attribute->unparsed_value) { belle_sip_free(attribute->unparsed_value); attribute->unparsed_value = NULL; } attribute->unparsed_value = belle_sip_object_to_string(attribute); ret = attribute->unparsed_value; ret += strlen(attribute->name) + 2; /* "a=" + name*/ if (*ret==':') ret++; for (; *ret == ' '; ret++) {}; /* skip eventual spaces */ return ret; } unsigned int belle_sdp_attribute_has_value(belle_sdp_attribute_t* attribute) { return belle_sdp_attribute_get_value(attribute) != NULL; } BELLE_SDP_NEW(attribute,belle_sip_object) BELLE_SDP_PARSE(attribute) GET_SET_STRING(belle_sdp_attribute,name); /*************************************************************************************** * RAW Attribute * **************************************************************************************/ struct _belle_sdp_raw_attribute { belle_sdp_attribute_t base; const char* value; }; void belle_sdp_raw_attribute_destroy(belle_sdp_raw_attribute_t* attribute) { DESTROY_STRING(attribute,value) } void belle_sdp_raw_attribute_clone(belle_sdp_raw_attribute_t* attribute, const belle_sdp_raw_attribute_t* orig) { if (belle_sdp_attribute_get_value(BELLE_SDP_ATTRIBUTE(orig))) { belle_sdp_raw_attribute_set_value(attribute, belle_sdp_attribute_get_value(BELLE_SDP_ATTRIBUTE(orig))); } } belle_sip_error_code belle_sdp_raw_attribute_marshal(belle_sdp_raw_attribute_t* attribute, char* buff, size_t buff_size, size_t* offset) { belle_sip_error_code error = belle_sdp_attribute_marshal(BELLE_SDP_ATTRIBUTE(attribute), buff, buff_size, offset); if (error != BELLE_SIP_OK) return error; if (attribute->value) { error = belle_sip_snprintf(buff, buff_size, offset, ":%s", attribute->value); if (error != BELLE_SIP_OK) return error; } return error; } BELLE_SDP_NEW(raw_attribute,belle_sdp_attribute) belle_sdp_raw_attribute_t* belle_sdp_raw_attribute_create(const char* name, const char* value) { belle_sdp_raw_attribute_t* attribute = belle_sdp_raw_attribute_new(); belle_sdp_attribute_set_name(BELLE_SDP_ATTRIBUTE(attribute), name); belle_sdp_raw_attribute_set_value(attribute, value); return attribute; } void belle_sdp_raw_attribute_set_value(belle_sdp_raw_attribute_t* attribute, const char* value) { if (attribute->value != NULL) belle_sip_free((void*)attribute->value); if (value) { attribute->value = belle_sip_strdup(value); } else attribute->value = NULL; } /*************************************************************************************** * RTCP-FB Attribute * **************************************************************************************/ struct _belle_sdp_rtcp_fb_attribute { belle_sdp_attribute_t base; belle_sdp_rtcp_fb_val_type_t type; belle_sdp_rtcp_fb_val_param_t param; uint32_t smaxpr; uint16_t trr_int; int8_t id; }; BELLESIP_EXPORT unsigned int belle_sdp_rtcp_fb_attribute_has_pli(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_pli(belle_sdp_rtcp_fb_attribute_t* attribute, unsigned int enable); BELLESIP_EXPORT unsigned int belle_sdp_rtcp_fb_attribute_has_sli(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_sli(belle_sdp_rtcp_fb_attribute_t* attribute, unsigned int enable); BELLESIP_EXPORT unsigned int belle_sdp_rtcp_fb_attribute_has_rpsi(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_rpsi(belle_sdp_rtcp_fb_attribute_t* attribute, unsigned int enable); BELLESIP_EXPORT unsigned int belle_sdp_rtcp_fb_attribute_has_app(const belle_sdp_rtcp_fb_attribute_t* attribute); BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_app(belle_sdp_rtcp_fb_attribute_t* attribute, unsigned int enable); void belle_sdp_rtcp_fb_attribute_destroy(belle_sdp_rtcp_fb_attribute_t* attribute) { } void belle_sdp_rtcp_fb_attribute_clone(belle_sdp_rtcp_fb_attribute_t* attribute, const belle_sdp_rtcp_fb_attribute_t *orig) { attribute->type = orig->type; attribute->param = orig->param; attribute->trr_int = orig->trr_int; attribute->id = orig->id; attribute->smaxpr = orig->smaxpr; } belle_sip_error_code belle_sdp_rtcp_fb_attribute_marshal(belle_sdp_rtcp_fb_attribute_t* attribute, char * buff, size_t buff_size, size_t *offset) { int8_t id = belle_sdp_rtcp_fb_attribute_get_id(attribute); belle_sdp_rtcp_fb_val_type_t type = belle_sdp_rtcp_fb_attribute_get_type(attribute); belle_sdp_rtcp_fb_val_param_t param = belle_sdp_rtcp_fb_attribute_get_param(attribute); belle_sip_error_code error = belle_sdp_attribute_marshal(BELLE_SDP_ATTRIBUTE(attribute), buff, buff_size, offset); if (error != BELLE_SIP_OK) return error; if (id < 0) { error = belle_sip_snprintf(buff, buff_size, offset, ":* "); } else { error = belle_sip_snprintf(buff, buff_size, offset, ":%u ", id); } if (error != BELLE_SIP_OK) return error; switch (type) { case BELLE_SDP_RTCP_FB_ACK: error = belle_sip_snprintf(buff, buff_size, offset, "ack"); if (error != BELLE_SIP_OK) return error; switch (param) { default: case BELLE_SDP_RTCP_FB_NONE: break; case BELLE_SDP_RTCP_FB_RPSI: error = belle_sip_snprintf(buff, buff_size, offset, " rpsi"); break; case BELLE_SDP_RTCP_FB_APP: error = belle_sip_snprintf(buff, buff_size, offset, " app"); break; } break; case BELLE_SDP_RTCP_FB_NACK: error = belle_sip_snprintf(buff, buff_size, offset, "nack"); if (error != BELLE_SIP_OK) return error; switch (param) { default: case BELLE_SDP_RTCP_FB_NONE: break; case BELLE_SDP_RTCP_FB_PLI: error = belle_sip_snprintf(buff, buff_size, offset, " pli"); break; case BELLE_SDP_RTCP_FB_SLI: error = belle_sip_snprintf(buff, buff_size, offset, " sli"); break; case BELLE_SDP_RTCP_FB_RPSI: error = belle_sip_snprintf(buff, buff_size, offset, " rpsi"); break; case BELLE_SDP_RTCP_FB_APP: error = belle_sip_snprintf(buff, buff_size, offset, " app"); break; } break; case BELLE_SDP_RTCP_FB_TRR_INT: error = belle_sip_snprintf(buff, buff_size, offset, "trr-int %u", belle_sdp_rtcp_fb_attribute_get_trr_int(attribute)); break; case BELLE_SDP_RTCP_FB_CCM: error = belle_sip_snprintf(buff, buff_size, offset, "ccm"); if (error != BELLE_SIP_OK) return error; switch (param) { case BELLE_SDP_RTCP_FB_FIR: error = belle_sip_snprintf(buff, buff_size, offset, " fir"); break; case BELLE_SDP_RTCP_FB_TMMBR: error = belle_sip_snprintf(buff, buff_size, offset, " tmmbr"); if (belle_sdp_rtcp_fb_attribute_get_smaxpr(attribute) > 0) { error = belle_sip_snprintf(buff, buff_size, offset, " smaxpr=%u", belle_sdp_rtcp_fb_attribute_get_smaxpr(attribute)); } break; default: break; } break; } return error; } static void belle_sdp_rtcp_fb_attribute_init(belle_sdp_rtcp_fb_attribute_t* attribute) { belle_sdp_attribute_set_name(BELLE_SDP_ATTRIBUTE(attribute), "rtcp-fb"); attribute->id = -1; attribute->type = BELLE_SDP_RTCP_FB_TRR_INT; attribute->param = BELLE_SDP_RTCP_FB_NONE; attribute->trr_int = 0; attribute->smaxpr = 0; } BELLE_SDP_NEW_WITH_CTR(rtcp_fb_attribute,belle_sdp_attribute) BELLE_SDP_PARSE(rtcp_fb_attribute) GET_SET_INT(belle_sdp_rtcp_fb_attribute,id,int8_t) GET_SET_INT(belle_sdp_rtcp_fb_attribute,type,belle_sdp_rtcp_fb_val_type_t) GET_SET_INT(belle_sdp_rtcp_fb_attribute,param,belle_sdp_rtcp_fb_val_param_t) GET_SET_INT(belle_sdp_rtcp_fb_attribute,trr_int,uint16_t) GET_SET_INT(belle_sdp_rtcp_fb_attribute,smaxpr,uint32_t) /*************************************************************************************** * RTCP-XR Attribute * **************************************************************************************/ struct _belle_sdp_rtcp_xr_attribute { belle_sdp_attribute_t base; const char* rcvr_rtt_mode; int rcvr_rtt_max_size; unsigned int stat_summary; belle_sip_list_t* stat_summary_flags; unsigned int voip_metrics; }; const belle_sip_list_t* belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(const belle_sdp_rtcp_xr_attribute_t* attribute) { return attribute->stat_summary_flags; } void belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(belle_sdp_rtcp_xr_attribute_t* attribute, const char* flag) { attribute->stat_summary_flags = belle_sip_list_append(attribute->stat_summary_flags, belle_sip_strdup(flag)); } void belle_sdp_rtcp_xr_attribute_destroy(belle_sdp_rtcp_xr_attribute_t* attribute) { DESTROY_STRING(attribute,rcvr_rtt_mode) belle_sip_list_free_with_data(attribute->stat_summary_flags, belle_sip_free); } void belle_sdp_rtcp_xr_attribute_clone(belle_sdp_rtcp_xr_attribute_t* attribute, const belle_sdp_rtcp_xr_attribute_t *orig) { CLONE_STRING(belle_sdp_rtcp_xr_attribute,rcvr_rtt_mode,attribute,orig) attribute->rcvr_rtt_max_size = orig->rcvr_rtt_max_size; attribute->stat_summary = orig->stat_summary; attribute->stat_summary_flags = belle_sip_list_copy_with_data(orig->stat_summary_flags, belle_sip_string_copyfunc); attribute->voip_metrics = orig->voip_metrics; } belle_sip_error_code belle_sdp_rtcp_xr_attribute_marshal(belle_sdp_rtcp_xr_attribute_t* attribute, char * buff, size_t buff_size, size_t *offset) { const char *rcvr_rtt_mode = NULL; int rcvr_rtt_max_size = -1; int nb_xr_formats = 0; belle_sip_error_code error = belle_sdp_attribute_marshal(BELLE_SDP_ATTRIBUTE(attribute), buff, buff_size, offset); if (error != BELLE_SIP_OK) return error; rcvr_rtt_mode = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(attribute); if (rcvr_rtt_mode != NULL) { error = belle_sip_snprintf(buff, buff_size, offset, "%srcvr-rtt=%s", nb_xr_formats++ == 0 ? ":" : " ", rcvr_rtt_mode); if (error != BELLE_SIP_OK) return error; rcvr_rtt_max_size = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(attribute); if (rcvr_rtt_max_size > 0) { error = belle_sip_snprintf(buff, buff_size, offset, ":%u", rcvr_rtt_max_size); if (error != BELLE_SIP_OK) return error; } } if (belle_sdp_rtcp_xr_attribute_has_stat_summary(attribute)) { belle_sip_list_t* list; int nb_stat_flags = 0; error = belle_sip_snprintf(buff, buff_size, offset, "%sstat-summary", nb_xr_formats++ == 0 ? ":" : " "); if (error != BELLE_SIP_OK) return error; for (list = attribute->stat_summary_flags; list != NULL; list = list->next) { error = belle_sip_snprintf(buff, buff_size, offset, "%s%s", nb_stat_flags++ == 0 ? "=" : ",", (const char*)list->data); if (error != BELLE_SIP_OK) return error; } } if (belle_sdp_rtcp_xr_attribute_has_voip_metrics(attribute)) { error = belle_sip_snprintf(buff, buff_size, offset, "%svoip-metrics", nb_xr_formats++ == 0 ? ":" : " "); if (error != BELLE_SIP_OK) return error; } return error; } static void belle_sdp_rtcp_xr_attribute_init(belle_sdp_rtcp_xr_attribute_t* attribute) { belle_sdp_attribute_set_name(BELLE_SDP_ATTRIBUTE(attribute), "rtcp-xr"); } BELLE_SDP_NEW_WITH_CTR(rtcp_xr_attribute,belle_sdp_attribute) BELLE_SDP_PARSE(rtcp_xr_attribute) GET_SET_STRING(belle_sdp_rtcp_xr_attribute,rcvr_rtt_mode) GET_SET_INT(belle_sdp_rtcp_xr_attribute,rcvr_rtt_max_size,int) GET_SET_BOOL(belle_sdp_rtcp_xr_attribute,stat_summary,has) GET_SET_BOOL(belle_sdp_rtcp_xr_attribute,voip_metrics,has) /*************************************************************************************** * Bandwidth * **************************************************************************************/ struct _belle_sdp_bandwidth { belle_sip_object_t base; const char* type; int value; }; void belle_sdp_bandwidth_destroy(belle_sdp_bandwidth_t* bandwidth) { if (bandwidth->type) belle_sip_free((void*)bandwidth->type); } void belle_sdp_bandwidth_clone(belle_sdp_bandwidth_t *bandwidth, const belle_sdp_bandwidth_t *orig){ CLONE_STRING(belle_sdp_bandwidth,type,bandwidth,orig) bandwidth->value=orig->value; } belle_sip_error_code belle_sdp_bandwidth_marshal(belle_sdp_bandwidth_t* bandwidth, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf(buff,buff_size,offset,"b=%s:%i",bandwidth->type,bandwidth->value); } BELLE_SDP_NEW(bandwidth,belle_sip_object) BELLE_SDP_PARSE(bandwidth) GET_SET_STRING(belle_sdp_bandwidth,type); GET_SET_INT(belle_sdp_bandwidth,value,int) /************************ * connection ***********************/ struct _belle_sdp_connection { belle_sip_object_t base; const char* network_type; const char* address_type; const char* address; int ttl; int range; }; void belle_sdp_connection_destroy(belle_sdp_connection_t* connection) { DESTROY_STRING(connection,network_type) DESTROY_STRING(connection,address_type) DESTROY_STRING(connection,address) } void belle_sdp_connection_clone(belle_sdp_connection_t *connection, const belle_sdp_connection_t *orig){ CLONE_STRING(belle_sdp_connection,network_type,connection,orig) CLONE_STRING(belle_sdp_connection,address_type,connection,orig) CLONE_STRING(belle_sdp_connection,address,connection,orig) connection->range=orig->range; connection->ttl=orig->ttl; } belle_sip_error_code belle_sdp_connection_marshal(belle_sdp_connection_t* connection, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error = belle_sip_snprintf(buff,buff_size,offset,"c=%s %s %s",connection->network_type,connection->address_type,connection->address); if (error!=BELLE_SIP_OK) return error; if (connection->ttl>0) error = belle_sip_snprintf(buff,buff_size,offset,"/%i",connection->ttl); if (error!=BELLE_SIP_OK) return error; if (connection->range>0) error = belle_sip_snprintf(buff,buff_size,offset,"/%i",connection->range); return error; } BELLE_SDP_NEW(connection,belle_sip_object) BELLE_SDP_PARSE(connection) belle_sdp_connection_t* belle_sdp_connection_create(const char* net_type, const char* addr_type, const char* addr) { belle_sdp_connection_t* connection = belle_sdp_connection_new(); belle_sdp_connection_set_network_type(connection,net_type); belle_sdp_connection_set_address_type(connection,addr_type); belle_sdp_connection_set_address(connection,addr); return connection; } GET_SET_STRING(belle_sdp_connection,network_type); GET_SET_STRING(belle_sdp_connection,address_type); GET_SET_STRING(belle_sdp_connection,address); GET_SET_INT(belle_sdp_connection,ttl,int); GET_SET_INT(belle_sdp_connection,range,int); /************************ * email ***********************/ struct _belle_sdp_email { belle_sip_object_t base; char* value; }; void belle_sdp_email_destroy(belle_sdp_email_t* email) { DESTROY_STRING(email,value) } void belle_sdp_email_clone(belle_sdp_email_t *email, const belle_sdp_email_t *orig){ CLONE_STRING(belle_sdp_email,value,email,orig) } belle_sip_error_code belle_sdp_email_marshal(belle_sdp_email_t* email, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf(buff,buff_size,offset,"e=%s",email->value); } BELLE_SDP_NEW(email,belle_sip_object) BELLE_SDP_PARSE(email) GET_SET_STRING(belle_sdp_email,value); /************************ * info ***********************/ struct _belle_sdp_info { belle_sip_object_t base; const char* value; }; void belle_sdp_info_destroy(belle_sdp_info_t* info) { DESTROY_STRING(info,value) } void belle_sdp_info_clone(belle_sdp_info_t *info, const belle_sdp_info_t *orig){ CLONE_STRING(belle_sdp_info,value,info,orig) } belle_sip_error_code belle_sdp_info_marshal(belle_sdp_info_t* info, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf(buff,buff_size,offset,"i=%s",info->value); } BELLE_SDP_NEW(info,belle_sip_object) BELLE_SDP_PARSE(info) GET_SET_STRING(belle_sdp_info,value); /************************ * media ***********************/ struct _belle_sdp_media { belle_sip_object_t base; const char* media_type; int media_port; belle_sip_list_t* media_formats; int port_count; const char* protocol; const char* raw_fmt; }; belle_sip_list_t* belle_sdp_media_get_media_formats(const belle_sdp_media_t* media) { return media->media_formats; } void belle_sdp_media_set_media_formats( belle_sdp_media_t* media, belle_sip_list_t* formats) { /*belle_sip_list_free(media->media_formats); to allow easy list management might be better to add an append format method*/ media->media_formats = formats; } void belle_sdp_media_destroy(belle_sdp_media_t* media) { DESTROY_STRING(media,media_type) belle_sip_list_free(media->media_formats); DESTROY_STRING(media,protocol) } static void belle_sdp_media_init(belle_sdp_media_t* media) { media->port_count=1; } void belle_sdp_media_clone(belle_sdp_media_t *media, const belle_sdp_media_t *orig){ CLONE_STRING(belle_sdp_media,media_type,media,orig) media->media_port=orig->media_port; media->media_formats = belle_sip_list_copy(orig->media_formats); media->port_count=orig->port_count; CLONE_STRING(belle_sdp_media,protocol,media,orig) } belle_sip_error_code belle_sdp_media_marshal(belle_sdp_media_t* media, char* buff, size_t buff_size, size_t *offset) { belle_sip_list_t* list=media->media_formats; belle_sip_error_code error=belle_sip_snprintf(buff,buff_size,offset,"m=%s %i",media->media_type,media->media_port); if (error!=BELLE_SIP_OK) return error; if (media->port_count>1) { error=belle_sip_snprintf(buff,buff_size,offset,"/%i",media->port_count); if (error!=BELLE_SIP_OK) return error; } error=belle_sip_snprintf(buff,buff_size,offset," %s",media->protocol); if (error!=BELLE_SIP_OK) return error; for(;list!=NULL;list=list->next){ error=belle_sip_snprintf(buff,buff_size,offset," %li",(long)list->data); if (error!=BELLE_SIP_OK) return error; } return error; } BELLE_SDP_NEW_WITH_CTR(media,belle_sip_object) BELLE_SDP_PARSE(media) belle_sdp_media_t* belle_sdp_media_create(const char* media_type ,int media_port ,int port_count ,const char* protocol ,belle_sip_list_t* static_media_formats) { belle_sdp_media_t* media= belle_sdp_media_new(); belle_sdp_media_set_media_type(media,media_type); belle_sdp_media_set_media_port(media,media_port); belle_sdp_media_set_port_count(media,port_count); belle_sdp_media_set_protocol(media,protocol); if (static_media_formats) belle_sdp_media_set_media_formats(media,static_media_formats); return media; } GET_SET_STRING(belle_sdp_media,media_type); GET_SET_STRING(belle_sdp_media,protocol); GET_SET_INT(belle_sdp_media,media_port,int) GET_SET_INT(belle_sdp_media,port_count,int) /************************ * base_description ***********************/ typedef struct _belle_sdp_base_description { belle_sip_object_t base; belle_sdp_info_t* info; belle_sdp_connection_t* connection; belle_sip_list_t* bandwidths; belle_sip_list_t* attributes; } belle_sdp_base_description_t; static void belle_sdp_base_description_destroy(belle_sdp_base_description_t* base_description) { if (base_description->info) belle_sip_object_unref(BELLE_SIP_OBJECT(base_description->info)); if (base_description->connection) belle_sip_object_unref(BELLE_SIP_OBJECT(base_description->connection)); belle_sip_list_free_with_data(base_description->bandwidths,belle_sip_object_freefunc); belle_sip_list_free_with_data(base_description->attributes,belle_sip_object_freefunc); } static void belle_sdp_base_description_init(belle_sdp_base_description_t* base_description) { } static void belle_sdp_base_description_clone(belle_sdp_base_description_t *base_description, const belle_sdp_base_description_t *orig){ if (orig->info) base_description->info = BELLE_SDP_INFO(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->info))); if (orig->connection) base_description->connection = BELLE_SDP_CONNECTION(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->connection))); base_description->bandwidths = belle_sip_list_copy_with_data(orig->bandwidths,belle_sip_object_copyfunc); base_description->attributes = belle_sip_list_copy_with_data(orig->attributes,belle_sip_object_copyfunc); } belle_sip_error_code belle_sdp_base_description_marshal(belle_sdp_base_description_t* base_description, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=BELLE_SIP_OK; belle_sip_list_t* bandwidths; // belle_sip_list_t* attributes; if (base_description->info) { error=belle_sip_object_marshal(BELLE_SIP_OBJECT(base_description->info),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; } if (base_description->connection) { error=belle_sip_object_marshal(BELLE_SIP_OBJECT(base_description->connection),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; } for(bandwidths=base_description->bandwidths;bandwidths!=NULL;bandwidths=bandwidths->next){ error=belle_sip_object_marshal(BELLE_SIP_OBJECT(bandwidths->data),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; } // for(attributes=base_description->attributes;attributes!=NULL;attributes=attributes->next){ // error=belle_sip_object_marshal(BELLE_SIP_OBJECT(attributes->data),buff,buff_size,offset); // error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); // } return error; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sdp_base_description_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sdp_base_description_t ,belle_sip_object_t ,belle_sdp_base_description_destroy ,belle_sdp_base_description_clone ,belle_sdp_base_description_marshal ,FALSE); static int belle_sdp_base_description_attribute_comp_func(const belle_sdp_attribute_t* a, const char*b) { return strcmp(a->name,b); } belle_sdp_attribute_t* belle_sdp_base_description_get_attribute(const belle_sdp_base_description_t* base_description, const char* name) { belle_sip_list_t* attribute; attribute = belle_sip_list_find_custom(base_description->attributes, (belle_sip_compare_func)belle_sdp_base_description_attribute_comp_func, name); if (attribute) { return ((belle_sdp_attribute_t*)attribute->data); } else { return NULL; } } const char* belle_sdp_base_description_get_attribute_value(const belle_sdp_base_description_t* base_description, const char* name) { belle_sdp_attribute_t* attribute = belle_sdp_base_description_get_attribute(base_description,name); if (attribute) { return belle_sdp_attribute_get_value(attribute); } else return NULL; } belle_sip_list_t* belle_sdp_base_description_get_attributes(const belle_sdp_base_description_t* base_description) { return base_description->attributes; } static int belle_sdp_base_description_bandwidth_comp_func(const belle_sdp_bandwidth_t* a, const char*b) { return strcmp(a->type,b); } belle_sdp_bandwidth_t* belle_sdp_base_description_get_bandwidth(const belle_sdp_base_description_t *base_description, const char *name){ belle_sip_list_t* found = belle_sip_list_find_custom(base_description->bandwidths, (belle_sip_compare_func)belle_sdp_base_description_bandwidth_comp_func, name); if( found ){ return ((belle_sdp_bandwidth_t*)found->data); } else { return NULL; } } int belle_sdp_base_description_get_bandwidth_value(const belle_sdp_base_description_t* base_description, const char* name) { belle_sip_list_t* bandwidth; bandwidth = belle_sip_list_find_custom(base_description->bandwidths, (belle_sip_compare_func)belle_sdp_base_description_bandwidth_comp_func, name); if (bandwidth) { return ((belle_sdp_bandwidth_t*)bandwidth->data)->value; } else { return -1; } } void belle_sdp_base_description_remove_attribute(belle_sdp_base_description_t* base_description,const char* name) { belle_sip_list_t* attribute; attribute = belle_sip_list_find_custom(base_description->attributes, (belle_sip_compare_func)belle_sdp_base_description_attribute_comp_func, name); if (attribute) { belle_sip_object_unref(BELLE_SIP_OBJECT(attribute->data)); base_description->attributes = belle_sip_list_delete_link(base_description->attributes,attribute); } } void belle_sdp_base_description_remove_bandwidth(belle_sdp_base_description_t* base_description,const char* name) { belle_sip_list_t* bandwidth; bandwidth = belle_sip_list_find_custom(base_description->bandwidths, (belle_sip_compare_func)belle_sdp_base_description_bandwidth_comp_func, name); if (bandwidth) { belle_sip_object_unref(BELLE_SIP_OBJECT(bandwidth->data)); base_description->bandwidths = belle_sip_list_delete_link(base_description->bandwidths,bandwidth); } } void belle_sdp_base_description_set_attribute_value(belle_sdp_base_description_t* base_description, const char* name, const char* value) { belle_sdp_raw_attribute_t* attribute = belle_sdp_raw_attribute_new(); belle_sdp_attribute_set_name(BELLE_SDP_ATTRIBUTE(attribute),name); belle_sdp_raw_attribute_set_value(attribute,value); base_description->attributes = belle_sip_list_append(base_description->attributes,belle_sip_object_ref(attribute)); } void belle_sdp_base_description_add_attribute(belle_sdp_base_description_t* base_description, const belle_sdp_attribute_t* attribute) { base_description->attributes = belle_sip_list_append(base_description->attributes,(void*)belle_sip_object_ref(BELLE_SIP_OBJECT(attribute))); } #define SET_LIST(list_name,value) \ belle_sip_list_t* list;\ if (list_name) {\ belle_sip_list_free_with_data(list_name,belle_sip_object_unref);\ } \ for (list=value;list !=NULL; list=list->next) {\ belle_sip_object_ref(BELLE_SIP_OBJECT(list->data));\ }\ list_name=value; void belle_sdp_base_description_set_attributes(belle_sdp_base_description_t* base_description, belle_sip_list_t* attributes) { SET_LIST(base_description->attributes,attributes) } void belle_sdp_base_description_set_bandwidth(belle_sdp_base_description_t* base_description, const char* type, int value) { belle_sdp_bandwidth_t* bandwidth = BELLE_SDP_BANDWIDTH(belle_sdp_base_description_get_bandwidth(base_description, type)); if( bandwidth == NULL ){ bandwidth= belle_sdp_bandwidth_new(); belle_sdp_bandwidth_set_type(bandwidth,type); belle_sdp_bandwidth_set_value(bandwidth,value); base_description->bandwidths = belle_sip_list_append(base_description->bandwidths,belle_sip_object_ref(bandwidth)); } else { belle_sdp_bandwidth_set_value(bandwidth,value); } } void belle_sdp_base_description_add_bandwidth(belle_sdp_base_description_t* base_description, const belle_sdp_bandwidth_t* bandwidth) { base_description->bandwidths = belle_sip_list_append(base_description->bandwidths,(void *)belle_sip_object_ref((void *)bandwidth)); } void belle_sdp_base_description_set_bandwidths(belle_sdp_base_description_t* base_description, belle_sip_list_t* bandwidths) { SET_LIST(base_description->bandwidths,bandwidths) } /************************ * media_description ***********************/ struct _belle_sdp_media_description { belle_sdp_base_description_t base_description; belle_sdp_media_t* media; }; void belle_sdp_media_description_destroy(belle_sdp_media_description_t* media_description) { if (media_description->media) belle_sip_object_unref(BELLE_SIP_OBJECT((media_description->media))); } void belle_sdp_media_description_clone(belle_sdp_media_description_t *media_description, const belle_sdp_media_description_t *orig){ if (orig->media) media_description->media = BELLE_SDP_MEDIA(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT((orig->media)))); } belle_sip_error_code belle_sdp_media_description_marshal(belle_sdp_media_description_t* media_description, char* buff, size_t buff_size, size_t *offset) { belle_sip_list_t* attributes; belle_sip_error_code error=belle_sip_object_marshal(BELLE_SIP_OBJECT(media_description->media),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; error=belle_sdp_base_description_marshal(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; for(attributes=media_description->base_description.attributes;attributes!=NULL;attributes=attributes->next){ error=belle_sip_object_marshal(BELLE_SIP_OBJECT(attributes->data),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; } return error; } BELLE_SDP_NEW(media_description,belle_sdp_base_description) belle_sdp_media_description_t* belle_sdp_media_description_create(const char* media_type ,int media_port ,int port_count ,const char* protocol ,belle_sip_list_t* static_media_formats) { belle_sdp_media_description_t* media_desc=belle_sdp_media_description_new(); belle_sdp_media_description_set_media(media_desc,belle_sdp_media_create(media_type,media_port,port_count,protocol,static_media_formats)); return media_desc; } BELLE_SDP_PARSE(media_description) void belle_sdp_media_description_add_dynamic_payloads(belle_sdp_media_description_t* media_description, belle_sip_list_t* payloadNames, belle_sip_list_t* payloadValues) { belle_sip_error("belle_sdp_media_description_add_dynamic_payloads not implemented yet"); } belle_sdp_attribute_t* belle_sdp_media_description_get_attribute(const belle_sdp_media_description_t* media_description, const char* name) { return belle_sdp_base_description_get_attribute(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name); } const char* belle_sdp_media_description_get_attribute_value(const belle_sdp_media_description_t* media_description, const char* name) { return belle_sdp_base_description_get_attribute_value(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name); } belle_sip_list_t* belle_sdp_media_description_get_attributes(const belle_sdp_media_description_t* media_description) { return BELLE_SIP_CAST(media_description,belle_sdp_base_description_t)->attributes; } int belle_sdp_media_description_get_bandwidth(const belle_sdp_media_description_t* media_description, const char* name) { return belle_sdp_base_description_get_bandwidth_value(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name); } belle_sip_list_t* belle_sdp_media_description_get_bandwidths(const belle_sdp_media_description_t* media_description) { return BELLE_SIP_CAST(media_description,belle_sdp_base_description_t)->bandwidths; } belle_sdp_connection_t* belle_sdp_media_description_get_connection(const belle_sdp_media_description_t* media_description) { return BELLE_SIP_CAST(media_description,belle_sdp_base_description_t)->connection; } belle_sdp_info_t* belle_sdp_media_description_get_info(const belle_sdp_media_description_t* media_description) { return BELLE_SIP_CAST(media_description,belle_sdp_base_description_t)->info; } /*belle_sdp_key_t* belle_sdp_media_description_get_key(const belle_sdp_media_description_t* media_description);*/ belle_sdp_media_t* belle_sdp_media_description_get_media(const belle_sdp_media_description_t* media_description) { return media_description->media; } struct static_payload { unsigned char number; int channel_count; const char* type; int rate; }; #define STATIC_PAYLOAD_LIST_LENTH 8 /* * rfc 3551 * PT encoding media type clock rate channels name (Hz) ___________________________________________________ 0 PCMU A 8,000 1 1 reserved A 2 reserved A 3 GSM A 8,000 1 4 G723 A 8,000 1 5 DVI4 A 8,000 1 6 DVI4 A 16,000 1 7 LPC A 8,000 1 8 PCMA A 8,000 1 9 G722 A 8,000 1 10 L16 A 44,100 2 11 L16 A 44,100 1 12 QCELP A 8,000 1 13 CN A 8,000 1 14 MPA A 90,000 (see text) 15 G728 A 8,000 1 16 DVI4 A 11,025 1 17 DVI4 A 22,050 1 18 G729 A 8,000 1 Table 4: Payload types (PT) for audio encodings PT encoding media type clock rate name (Hz) _____________________________________________ 24 unassigned V 25 CelB V 90,000 26 JPEG V 90,000 27 unassigned V 28 nv V 90,000 29 unassigned V 30 unassigned V 31 H261 V 90,000 32 MPV V 90,000 33 MP2T AV 90,000 34 H263 V 90,000 Table 5: Payload types (PT) for video and combined encodings * * */ const struct static_payload static_payload_list [] ={ /*audio*/ {0,1,"PCMU",8000}, {3,1,"GSM",8000}, {4,1,"G723",8000}, {5,1,"DVI4",8000}, {6,1,"DVI4",16000}, {7,1,"LPC",8000}, {8,1,"PCMA",8000}, {9,1,"G722",8000}, {10,2,"L16",44100}, {11,1,"L16",44100}, {12,1,"QCELP",8000}, {13,1,"CN",8000}, {14,1,"MPA",90000}, {15,1,"G728",8000}, {16,1,"DVI4",11025}, {17,1,"DVI4",22050}, {18,1,"G729",8000}, /*video*/ {25,0,"CelB",90000}, {26,0,"JPEG",90000}, {28,0,"nv",90000}, {31,0,"H261",90000}, {32,0,"MPV",90000}, {33,0,"MP2T",90000}, {34,0,"H263",90000} }; static const size_t payload_list_elements=sizeof(static_payload_list)/sizeof(struct static_payload); static int mime_parameter_is_static(const belle_sdp_mime_parameter_t *param){ const struct static_payload* iterator; int i; for (iterator = static_payload_list,i=0;inumber == param->media_format && strcasecmp(iterator->type,param->type)==0 && iterator->channel_count==param->channel_count && iterator->rate==param->rate ) { return TRUE; } } return FALSE; } static int mime_parameter_fill_from_static(belle_sdp_mime_parameter_t *mime_parameter,int format) { const struct static_payload* iterator; int i; for (iterator = static_payload_list,i=0;inumber == format) { belle_sdp_mime_parameter_set_type(mime_parameter,iterator->type); belle_sdp_mime_parameter_set_rate(mime_parameter,iterator->rate); belle_sdp_mime_parameter_set_channel_count(mime_parameter,iterator->channel_count); break; } } return 0; } static int mime_parameter_fill_from_rtpmap(belle_sdp_mime_parameter_t *mime_parameter, const char *rtpmap, int is_audio){ char *mime=belle_sip_strdup(rtpmap); char *p=strchr(mime,'/'); if (p){ char *chans; *p='\0'; p++; chans=strchr(p,'/'); if (chans){ *chans='\0'; chans++; belle_sdp_mime_parameter_set_channel_count(mime_parameter,atoi(chans)); }else if (is_audio) belle_sdp_mime_parameter_set_channel_count(mime_parameter,1); /*in absence of channel count, 1 is implicit for audio streams*/ belle_sdp_mime_parameter_set_rate(mime_parameter,atoi(p)); } belle_sdp_mime_parameter_set_type(mime_parameter,mime); belle_sip_free(mime); return 0; } /* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/ static const char *belle_sdp_media_description_a_attr_value_get_with_pt(const belle_sdp_media_description_t* media_description,int pt,const char *field) { int tmppt=0,scanned=0; const char *tmp; belle_sdp_attribute_t *attr; belle_sip_list_t* attribute_list; for ( attribute_list =belle_sdp_media_description_get_attributes(media_description) ;attribute_list!=NULL ;attribute_list=attribute_list->next) { attr = BELLE_SDP_ATTRIBUTE(attribute_list->data); if (strcmp(field,belle_sdp_attribute_get_name(attr))==0 && belle_sdp_attribute_get_value(attr)!=NULL){ int nb = sscanf(belle_sdp_attribute_get_value(attr),"%i %n",&tmppt,&scanned); /* the return value may depend on how %n is interpreted by the libc: see manpage*/ if (nb == 1 || nb==2 ){ if (pt==tmppt){ tmp=belle_sdp_attribute_get_value(attr)+scanned; if (strlen(tmp)>0) return tmp; } }else belle_sip_warning("sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value(attr),nb); } } return NULL; } belle_sip_list_t* belle_sdp_media_description_build_mime_parameters(const belle_sdp_media_description_t* media_description) { /*First, get media type*/ belle_sdp_media_t* media = belle_sdp_media_description_get_media(media_description); belle_sip_list_t* mime_parameter_list=NULL; belle_sip_list_t* media_formats=NULL; belle_sdp_mime_parameter_t* mime_parameter; const char* rtpmap=NULL; const char* fmtp=NULL; const char* ptime=NULL; const char* max_ptime=NULL; int ptime_as_int=-1; int max_ptime_as_int=-1; int is_audio=0; if (!media) { belle_sip_error("belle_sdp_media_description_build_mime_parameters: no media"); return NULL; } if (strcasecmp(belle_sdp_media_get_media_type(media),"audio")==0) is_audio=1; ptime = belle_sdp_media_description_get_attribute_value(media_description,"ptime"); ptime?ptime_as_int=atoi(ptime):-1; max_ptime = belle_sdp_media_description_get_attribute_value(media_description,"maxptime"); max_ptime?max_ptime_as_int=atoi(max_ptime):-1; for (media_formats = belle_sdp_media_get_media_formats(media);media_formats!=NULL;media_formats=media_formats->next) { /*create mime parameters with format*/ mime_parameter = belle_sdp_mime_parameter_new(); belle_sdp_mime_parameter_set_ptime(mime_parameter,ptime_as_int); belle_sdp_mime_parameter_set_max_ptime(mime_parameter,max_ptime_as_int); belle_sdp_mime_parameter_set_media_format(mime_parameter,(int)(long)media_formats->data); /*get rtpmap*/ rtpmap = belle_sdp_media_description_a_attr_value_get_with_pt(media_description ,belle_sdp_mime_parameter_get_media_format(mime_parameter) ,"rtpmap"); if (rtpmap) { mime_parameter_fill_from_rtpmap(mime_parameter,rtpmap,is_audio); }else{ mime_parameter_fill_from_static(mime_parameter,belle_sdp_mime_parameter_get_media_format(mime_parameter)); } fmtp = belle_sdp_media_description_a_attr_value_get_with_pt(media_description ,belle_sdp_mime_parameter_get_media_format(mime_parameter) ,"fmtp"); if (fmtp) { belle_sdp_mime_parameter_set_parameters(mime_parameter,fmtp); } mime_parameter_list=belle_sip_list_append(mime_parameter_list,mime_parameter); } return mime_parameter_list; } #define MAX_FMTP_LENGTH 512 void belle_sdp_media_description_append_values_from_mime_parameter(belle_sdp_media_description_t* media_description, const belle_sdp_mime_parameter_t* mime_parameter) { belle_sdp_media_t* media = belle_sdp_media_description_get_media(media_description); char atribute_value [MAX_FMTP_LENGTH]; int current_ptime=0; int current_max_ptime=0; belle_sdp_media_set_media_formats(media,belle_sip_list_append(belle_sdp_media_get_media_formats(media) ,(void*)(long)(belle_sdp_mime_parameter_get_media_format(mime_parameter)))); if (belle_sdp_media_description_get_attribute_value(media_description,"ptime")) { current_ptime=atoi(belle_sdp_media_description_get_attribute_value(media_description,"ptime")); belle_sdp_media_description_remove_attribute(media_description,"ptime"); } if (belle_sdp_media_description_get_attribute_value(media_description,"maxptime")) { current_max_ptime=atoi(belle_sdp_media_description_get_attribute_value(media_description,"maxptime")); belle_sdp_media_description_remove_attribute(media_description,"maxptime"); } #ifndef BELLE_SDP_FORCE_RTP_MAP /* defined to for RTP map even for static codec*/ if (!mime_parameter_is_static(mime_parameter)) { /*dynamic payload*/ #endif if (belle_sdp_mime_parameter_get_channel_count(mime_parameter)>1) { snprintf(atribute_value,MAX_FMTP_LENGTH,"%i %s/%i/%i" ,belle_sdp_mime_parameter_get_media_format(mime_parameter) ,belle_sdp_mime_parameter_get_type(mime_parameter) ,belle_sdp_mime_parameter_get_rate(mime_parameter) ,belle_sdp_mime_parameter_get_channel_count(mime_parameter)); } else { snprintf(atribute_value,MAX_FMTP_LENGTH,"%i %s/%i" ,belle_sdp_mime_parameter_get_media_format(mime_parameter) ,belle_sdp_mime_parameter_get_type(mime_parameter) ,belle_sdp_mime_parameter_get_rate(mime_parameter)); } belle_sdp_media_description_set_attribute_value(media_description,"rtpmap",atribute_value); #ifndef BELLE_SDP_FORCE_RTP_MAP } #endif // always include fmtp parameters if available if (belle_sdp_mime_parameter_get_parameters(mime_parameter)) { snprintf(atribute_value,MAX_FMTP_LENGTH,"%i %s" ,belle_sdp_mime_parameter_get_media_format(mime_parameter) ,belle_sdp_mime_parameter_get_parameters(mime_parameter)); belle_sdp_media_description_set_attribute_value(media_description,"fmtp",atribute_value); } if (belle_sdp_mime_parameter_get_ptime(mime_parameter)>current_ptime) { current_ptime=belle_sdp_mime_parameter_get_ptime(mime_parameter); } if (current_ptime>0){ char ptime[10]; snprintf(ptime,sizeof(ptime),"%i",current_ptime); belle_sdp_media_description_set_attribute_value(media_description,"ptime",ptime); } if (belle_sdp_mime_parameter_get_max_ptime(mime_parameter)>current_max_ptime) { current_max_ptime=belle_sdp_mime_parameter_get_max_ptime(mime_parameter); } if (current_max_ptime>0){ char max_ptime[10]; snprintf(max_ptime,sizeof(max_ptime),"%i",current_max_ptime); belle_sdp_media_description_set_attribute_value(media_description,"maxptime",max_ptime); } } belle_sip_list_t* belle_sdp_media_description_get_mime_types(const belle_sdp_media_description_t* media_description) { belle_sip_error("belle_sdp_media_description_get_mime_types: not implemented yet"); return NULL; } void belle_sdp_media_description_remove_attribute(belle_sdp_media_description_t* media_description,const char* name) { belle_sdp_base_description_remove_attribute(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name); } void belle_sdp_media_description_remove_bandwidth(belle_sdp_media_description_t* media_description,const char* name) { belle_sdp_base_description_remove_bandwidth(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name); } void belle_sdp_media_description_set_attribute_value(belle_sdp_media_description_t* media_description, const char* name, const char* value) { belle_sdp_base_description_set_attribute_value(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name,value); } void belle_sdp_media_description_set_attributes(belle_sdp_media_description_t* media_description, belle_sip_list_t* value) { belle_sdp_base_description_set_attributes(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),value); } void belle_sdp_media_description_add_attribute(belle_sdp_media_description_t* media_description, const belle_sdp_attribute_t* attribute) { belle_sdp_base_description_add_attribute(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),attribute); } void belle_sdp_media_description_set_bandwidth(belle_sdp_media_description_t* media_description, const char* type, int value) { belle_sdp_base_description_set_bandwidth(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),type,value); } void belle_sdp_media_description_add_bandwidth(belle_sdp_media_description_t* media_description, const belle_sdp_bandwidth_t* bandwidth) { belle_sdp_base_description_add_bandwidth(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),bandwidth); } void belle_sdp_media_description_set_bandwidths(belle_sdp_media_description_t* media_description, belle_sip_list_t* bandwidths) { belle_sdp_base_description_set_bandwidths(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),bandwidths); } #define SET_OBJECT(object,param,param_type) \ param_type** current = &object->param; \ if (param) belle_sip_object_ref(param); \ if (*current) { \ belle_sip_object_unref(BELLE_SIP_OBJECT(*current)); \ } \ *current=param; \ void belle_sdp_media_description_set_connection(belle_sdp_media_description_t* media_description, belle_sdp_connection_t* connection) { SET_OBJECT(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),connection,belle_sdp_connection_t) } void belle_sdp_media_description_set_info(belle_sdp_media_description_t* media_description,belle_sdp_info_t* info) { SET_OBJECT(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),info,belle_sdp_info_t) } /*void belle_sdp_media_description_set_key(belle_sdp_media_description_t* media_description,belle_sdp_key_t* key);*/ void belle_sdp_media_description_set_media(belle_sdp_media_description_t* media_description, belle_sdp_media_t* media) { SET_OBJECT(media_description,media,belle_sdp_media_t) } /************************ * origin ***********************/ struct _belle_sdp_origin { belle_sip_object_t base; const char* address; const char* address_type; const char* network_type; const char* username; unsigned int session_id; unsigned int session_version; }; void belle_sdp_origin_destroy(belle_sdp_origin_t* origin) { DESTROY_STRING(origin,address) DESTROY_STRING(origin,address_type) DESTROY_STRING(origin,network_type) DESTROY_STRING(origin,username) } void belle_sdp_origin_clone(belle_sdp_origin_t *origin, const belle_sdp_origin_t *orig){ CLONE_STRING(belle_sdp_origin,username,origin,orig); CLONE_STRING(belle_sdp_origin,address,origin,orig); CLONE_STRING(belle_sdp_origin,address_type,origin,orig); CLONE_STRING(belle_sdp_origin,network_type,origin,orig); origin->session_id = orig->session_id; origin->session_version = orig->session_version; } belle_sip_error_code belle_sdp_origin_marshal(belle_sdp_origin_t* origin, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf( buff ,buff_size ,offset ,"o=%s %i %i %s %s %s" ,origin->username ,origin->session_id ,origin->session_version ,origin->network_type ,origin->address_type ,origin->address); } BELLE_SDP_NEW(origin,belle_sip_object) belle_sdp_origin_t* belle_sdp_origin_create(const char* user_name , unsigned int session_id , unsigned int session_version , const char* network_type , const char* addr_type , const char* address) { belle_sdp_origin_t* origin=belle_sdp_origin_new(); belle_sdp_origin_set_username(origin,user_name); belle_sdp_origin_set_session_id(origin,session_id); belle_sdp_origin_set_session_version(origin,session_version); belle_sdp_origin_set_network_type(origin,network_type); belle_sdp_origin_set_address_type(origin,addr_type); belle_sdp_origin_set_address(origin,address); return origin; } BELLE_SDP_PARSE(origin) GET_SET_STRING(belle_sdp_origin,username); GET_SET_STRING(belle_sdp_origin,address); GET_SET_STRING(belle_sdp_origin,address_type); GET_SET_STRING(belle_sdp_origin,network_type); GET_SET_INT(belle_sdp_origin,session_id,unsigned int); GET_SET_INT(belle_sdp_origin,session_version,unsigned int); /************************ * session_name ***********************/ struct _belle_sdp_session_name { belle_sip_object_t base; const char* value; }; void belle_sdp_session_name_destroy(belle_sdp_session_name_t* session_name) { DESTROY_STRING(session_name,value) } void belle_sdp_session_name_clone(belle_sdp_session_name_t *session_name, const belle_sdp_session_name_t *orig){ CLONE_STRING(belle_sdp_session_name,value,session_name,orig); } belle_sip_error_code belle_sdp_session_name_marshal(belle_sdp_session_name_t* session_name, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf(buff,buff_size,offset,"s=%s",session_name->value); } BELLE_SDP_NEW(session_name,belle_sip_object) belle_sdp_session_name_t* belle_sdp_session_name_create (const char* name) { belle_sdp_session_name_t* n=belle_sdp_session_name_new(); belle_sdp_session_name_set_value(n,name); return n; } //BELLE_SDP_PARSE(session_name) GET_SET_STRING(belle_sdp_session_name,value); /************************ * session_description ***********************/ struct _belle_sdp_session_description { belle_sdp_base_description_t base_description; belle_sdp_version_t* version; belle_sip_list_t* emails; belle_sdp_origin_t* origin; belle_sdp_session_name_t* session_name; belle_sip_list_t* phones; belle_sip_list_t* times; belle_sdp_uri_t* uri; belle_sdp_uri_t* zone_adjustments; belle_sip_list_t* media_descriptions; }; void belle_sdp_session_description_destroy(belle_sdp_session_description_t* session_description) { if (session_description->version) belle_sip_object_unref(BELLE_SIP_OBJECT(session_description->version)); belle_sip_list_free_with_data(session_description->emails,belle_sip_object_freefunc); if (session_description->origin) belle_sip_object_unref(BELLE_SIP_OBJECT(session_description->origin)); if (session_description->session_name) belle_sip_object_unref(BELLE_SIP_OBJECT(session_description->session_name)); belle_sip_list_free_with_data(session_description->phones,belle_sip_object_freefunc); belle_sip_list_free_with_data(session_description->times,belle_sip_object_freefunc); if (session_description->uri) belle_sip_object_unref(BELLE_SIP_OBJECT(session_description->uri)); if (session_description->zone_adjustments) belle_sip_object_unref(BELLE_SIP_OBJECT(session_description->zone_adjustments)); belle_sip_list_free_with_data(session_description->media_descriptions,belle_sip_object_freefunc); } void belle_sdp_session_description_clone(belle_sdp_session_description_t *session_description, const belle_sdp_session_description_t *orig){ if (orig->version) session_description->version = BELLE_SDP_VERSION(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->version))); session_description->emails = belle_sip_list_copy_with_data(orig->emails,belle_sip_object_copyfunc); if (orig->origin) session_description->origin = BELLE_SDP_ORIGIN(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->origin))); if (orig->session_name) session_description->session_name = BELLE_SDP_SESSION_NAME(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->session_name))); session_description->phones = belle_sip_list_copy_with_data(orig->phones,belle_sip_object_copyfunc); session_description->times = belle_sip_list_copy_with_data(orig->times,belle_sip_object_copyfunc); if (orig->uri) session_description->uri = BELLE_SDP_URI(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->uri))); if (orig->zone_adjustments) session_description->zone_adjustments = BELLE_SDP_URI(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->zone_adjustments))); session_description->media_descriptions = belle_sip_list_copy_with_data(orig->media_descriptions,belle_sip_object_copyfunc); } belle_sip_error_code belle_sdp_session_description_marshal(belle_sdp_session_description_t* session_description, char* buff, size_t buff_size, size_t *offset) { /*session_description: proto_version CR LF origin_field session_name_field (info CR LF)? uri_field? (email CR LF)* phone_field* (connection CR LF)? (bandwidth CR LF)* time_field (repeat_time CR LF)? (zone_adjustments CR LF)? (key_field CR LF)? (attribute CR LF)* media_descriptions; */ belle_sip_error_code error=BELLE_SIP_OK; belle_sip_list_t* media_descriptions; belle_sip_list_t* times; belle_sip_list_t* attributes; error=belle_sip_object_marshal(BELLE_SIP_OBJECT(session_description->version),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; error=belle_sip_object_marshal(BELLE_SIP_OBJECT(session_description->origin),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; error=belle_sip_object_marshal(BELLE_SIP_OBJECT(session_description->session_name),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; error=belle_sdp_base_description_marshal((belle_sdp_base_description_t*)(&session_description->base_description),buff,buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "t="); if (error!=BELLE_SIP_OK) return error; for(times=session_description->times;times!=NULL;times=times->next){ error=belle_sip_object_marshal(BELLE_SIP_OBJECT(times->data),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; } for(attributes=session_description->base_description.attributes;attributes!=NULL;attributes=attributes->next){ error=belle_sip_object_marshal(BELLE_SIP_OBJECT(attributes->data),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff, buff_size, offset, "\r\n"); if (error!=BELLE_SIP_OK) return error; } for(media_descriptions=session_description->media_descriptions;media_descriptions!=NULL;media_descriptions=media_descriptions->next){ error=belle_sip_object_marshal(BELLE_SIP_OBJECT(media_descriptions->data),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; } return error; } BELLE_SDP_NEW(session_description,belle_sdp_base_description) BELLE_SDP_PARSE(session_description) const char* belle_sdp_session_description_get_attribute_value(const belle_sdp_session_description_t* session_description, const char* name) { return belle_sdp_base_description_get_attribute_value(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),name); } const belle_sdp_attribute_t* belle_sdp_session_description_get_attribute(const belle_sdp_session_description_t* session_description, const char* name) { return belle_sdp_base_description_get_attribute(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),name); } int belle_sdp_session_description_get_bandwidth(const belle_sdp_session_description_t* session_description, const char* name) { return belle_sdp_base_description_get_bandwidth_value(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),name); } belle_sip_list_t* belle_sdp_session_description_get_bandwidths(const belle_sdp_session_description_t* session_description) { return BELLE_SIP_CAST(session_description,belle_sdp_base_description_t)->bandwidths; } belle_sdp_connection_t* belle_sdp_session_description_get_connection(const belle_sdp_session_description_t* session_description) { return BELLE_SIP_CAST(session_description,belle_sdp_base_description_t)->connection; } belle_sip_list_t* belle_sdp_session_description_get_emails(const belle_sdp_session_description_t* session_description){ return session_description->emails; } belle_sdp_info_t* belle_sdp_session_description_get_info(const belle_sdp_session_description_t* session_description) { return BELLE_SIP_CAST(session_description,belle_sdp_base_description_t)->info; } /*belle_sdp_key_t* belle_sdp_session_description_get_key(const belle_sdp_session_description_t* session_description);*/ belle_sip_list_t* belle_sdp_session_description_get_media_descriptions(const belle_sdp_session_description_t* session_description) { return session_description->media_descriptions; } belle_sdp_origin_t* belle_sdp_session_description_get_origin(const belle_sdp_session_description_t* session_description){ return session_description->origin; } belle_sip_list_t* belle_sdp_session_description_get_phones(const belle_sdp_session_description_t* session_description) { return session_description->phones; } belle_sdp_session_name_t* belle_sdp_session_description_get_session_name(const belle_sdp_session_description_t* session_description) { return session_description->session_name; } belle_sip_list_t* belle_sdp_session_description_get_time_descriptions(const belle_sdp_session_description_t* session_description) { return session_description->times; } belle_sdp_uri_t* belle_sdp_session_description_get_uri(const belle_sdp_session_description_t* session_description) { return session_description->uri; } belle_sdp_version_t* belle_sdp_session_description_get_version(const belle_sdp_session_description_t* session_description) { return session_description->version; } belle_sdp_uri_t* belle_sdp_session_description_get_zone_adjustments(const belle_sdp_session_description_t* session_description) { return session_description->zone_adjustments; } void belle_sdp_session_description_remove_attribute(belle_sdp_session_description_t* session_description, const char* name) { belle_sdp_base_description_remove_attribute(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),name); } void belle_sdp_session_description_remove_bandwidth(belle_sdp_session_description_t* session_description, const char* name) { belle_sdp_base_description_remove_bandwidth(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),name); } void belle_sdp_session_description_set_attribute_value(belle_sdp_session_description_t* session_description, const char* name, const char* value) { belle_sdp_base_description_set_attribute_value(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),name,value); } void belle_sdp_session_description_set_attributes(belle_sdp_session_description_t* session_description, belle_sip_list_t* attributes) { belle_sdp_base_description_set_attributes(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),attributes); } void belle_sdp_session_description_add_attribute(belle_sdp_session_description_t* session_description, const belle_sdp_attribute_t* attribute) { belle_sdp_base_description_add_attribute(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),attribute); } void belle_sdp_session_description_set_bandwidth(belle_sdp_session_description_t* session_description, const char* type, int value) { belle_sdp_base_description_set_bandwidth(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),type,value); } void belle_sdp_session_description_set_bandwidths(belle_sdp_session_description_t* session_description, belle_sip_list_t* bandwidths) { belle_sdp_base_description_set_bandwidths(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),bandwidths); } void belle_sdp_session_description_add_bandwidth(belle_sdp_session_description_t* session_description, const belle_sdp_bandwidth_t* bandwidth) { belle_sdp_base_description_add_bandwidth(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),bandwidth); } void belle_sdp_session_description_set_connection(belle_sdp_session_description_t* session_description, belle_sdp_connection_t* connection) { SET_OBJECT(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),connection,belle_sdp_connection_t) } void belle_sdp_session_description_set_emails(belle_sdp_session_description_t* session_description, belle_sip_list_t* emails) { SET_LIST(session_description->emails,emails) } void belle_sdp_session_description_set_info(belle_sdp_session_description_t* session_description, belle_sdp_info_t* info) { SET_OBJECT(BELLE_SIP_CAST(session_description,belle_sdp_base_description_t),info,belle_sdp_info_t) } /*void belle_sdp_session_description_set_key(belle_sdp_session_description_t* session_description, belle_sdp_key_t* key);*/ void belle_sdp_session_description_set_media_descriptions(belle_sdp_session_description_t* session_description, belle_sip_list_t* media_descriptions) { SET_LIST(session_description->media_descriptions,media_descriptions) } void belle_sdp_session_description_add_media_description(belle_sdp_session_description_t* session_description, belle_sdp_media_description_t* media_description) { session_description->media_descriptions = belle_sip_list_append(session_description->media_descriptions,belle_sip_object_ref(media_description)); } void belle_sdp_session_description_set_origin(belle_sdp_session_description_t* session_description, belle_sdp_origin_t* origin) { SET_OBJECT(session_description,origin,belle_sdp_origin_t) } void belle_sdp_session_description_set_phones(belle_sdp_session_description_t* session_description, belle_sip_list_t* phones) { SET_LIST(session_description->phones,phones) } void belle_sdp_session_description_set_session_name(belle_sdp_session_description_t* session_description, belle_sdp_session_name_t* session_name) { SET_OBJECT(session_description,session_name,belle_sdp_session_name_t) } void belle_sdp_session_description_set_time_descriptions(belle_sdp_session_description_t* session_description, belle_sip_list_t* times) { SET_LIST(session_description->times,times) } void belle_sdp_session_description_set_time_description(belle_sdp_session_description_t* session_description, belle_sdp_time_description_t* time_desc) { belle_sdp_session_description_set_time_descriptions(session_description,belle_sip_list_new(time_desc)); } void belle_sdp_session_description_set_uri(belle_sdp_session_description_t* session_description, belle_sdp_uri_t* uri) { SET_OBJECT(session_description,uri,belle_sdp_uri_t) } void belle_sdp_session_description_set_version(belle_sdp_session_description_t* session_description, belle_sdp_version_t* version) { SET_OBJECT(session_description,version,belle_sdp_version_t) } void belle_sdp_session_description_set_zone_adjustments(belle_sdp_session_description_t* session_description, belle_sdp_uri_t* zone_adjustments) { SET_OBJECT(session_description,zone_adjustments,belle_sdp_uri_t) } /************************ * time ***********************/ struct _belle_sdp_time { belle_sip_object_t base; int start; int stop; }; void belle_sdp_time_destroy(belle_sdp_time_t* time) { } void belle_sdp_time_clone(belle_sdp_time_t *time, const belle_sdp_time_t *orig){ time->start=orig->start; time->stop=orig->stop; } belle_sip_error_code belle_sdp_time_marshal(belle_sdp_time_t* time, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf(buff,buff_size,offset,"%i %i",time->start,time->stop); } BELLE_SDP_NEW(time,belle_sip_object) //BELLE_SDP_PARSE(version) GET_SET_INT(belle_sdp_time,start,int); GET_SET_INT(belle_sdp_time,stop,int); /************************ * time description ***********************/ struct _belle_sdp_time_description { belle_sip_object_t base; belle_sdp_time_t* time; }; void belle_sdp_time_description_destroy(belle_sdp_time_description_t* time_description) { if (time_description->time) belle_sip_object_unref(BELLE_SIP_OBJECT(time_description->time)); } void belle_sdp_time_description_clone(belle_sdp_time_description_t *time_description, const belle_sdp_time_description_t *orig){ if (orig->time) time_description->time = BELLE_SDP_TIME(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->time))); } belle_sip_error_code belle_sdp_time_description_marshal(belle_sdp_time_description_t* time_description, char* buff, size_t buff_size, size_t *offset) { return belle_sip_object_marshal(BELLE_SIP_OBJECT(time_description->time),buff,buff_size,offset); } BELLE_SDP_NEW(time_description,belle_sip_object) belle_sdp_time_description_t* belle_sdp_time_description_create (int start,int stop) { belle_sdp_time_description_t* time_desc= belle_sdp_time_description_new(); belle_sdp_time_t* time = belle_sdp_time_new(); belle_sdp_time_set_start(time,start); belle_sdp_time_set_stop(time,stop); belle_sdp_time_description_set_time(time_desc,time); return time_desc; } belle_sip_list_t* belle_sdp_time_description_get_repeate_times(const belle_sdp_time_description_t* time_description) { return NULL; } belle_sdp_time_t* belle_sdp_time_description_get_time(const belle_sdp_time_description_t* time_description) { return time_description->time; } void belle_sdp_time_description_set_repeate_times(belle_sdp_time_description_t* time_description, belle_sip_list_t* times) { belle_sip_error("time description repeat time not implemented"); } void belle_sdp_time_description_set_time(belle_sdp_time_description_t* time_description, belle_sdp_time_t* time) { SET_OBJECT(time_description,time,belle_sdp_time_t) } /************************ * version ***********************/ struct _belle_sdp_version { belle_sip_object_t base; int version; }; void belle_sdp_version_destroy(belle_sdp_version_t* version) { } void belle_sdp_version_clone(belle_sdp_version_t *version, const belle_sdp_version_t *orig){ version->version = orig->version; } belle_sip_error_code belle_sdp_version_marshal(belle_sdp_version_t* version, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf(buff,buff_size,offset,"v=%i",version->version); } BELLE_SDP_NEW(version,belle_sip_object) belle_sdp_version_t* belle_sdp_version_create(int version) { belle_sdp_version_t* v = belle_sdp_version_new(); belle_sdp_version_set_version(v,version); return v; } //BELLE_SDP_PARSE(version) GET_SET_INT(belle_sdp_version,version,int); /*************************************************************************************** * mime_parameter * **************************************************************************************/ static void belle_sdp_mime_parameter_destroy(belle_sdp_mime_parameter_t *mime_parameter) { if (mime_parameter->type) belle_sip_free((void*)mime_parameter->type); if (mime_parameter->parameters) belle_sip_free((void*)mime_parameter->parameters); } static void belle_sdp_mime_parameter_clone(belle_sdp_mime_parameter_t *mime_parameter,belle_sdp_mime_parameter_t *orig) { mime_parameter->rate = orig->rate; mime_parameter->channel_count = orig->channel_count; mime_parameter->ptime = orig->ptime; mime_parameter->max_ptime = orig->max_ptime; mime_parameter->media_format = orig->media_format; CLONE_STRING(belle_sdp_mime_parameter,type,mime_parameter,orig); CLONE_STRING(belle_sdp_mime_parameter,parameters,mime_parameter,orig); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sdp_mime_parameter_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sdp_mime_parameter_t ,belle_sip_object_t ,belle_sdp_mime_parameter_destroy ,belle_sdp_mime_parameter_clone ,NULL ,TRUE); belle_sdp_mime_parameter_t* belle_sdp_mime_parameter_new() { belle_sdp_mime_parameter_t* l_param = belle_sip_object_new(belle_sdp_mime_parameter_t); l_param->ptime = -1; l_param->max_ptime = -1; return l_param; } belle_sdp_mime_parameter_t* belle_sdp_mime_parameter_create(const char* type, int media_format, int rate,int channel_count) { belle_sdp_mime_parameter_t* mime_param= belle_sdp_mime_parameter_new(); belle_sdp_mime_parameter_set_type(mime_param,type); belle_sdp_mime_parameter_set_media_format(mime_param,media_format); belle_sdp_mime_parameter_set_rate(mime_param,rate); belle_sdp_mime_parameter_set_channel_count(mime_param,channel_count); return mime_param; } GET_SET_INT(belle_sdp_mime_parameter,rate,int); GET_SET_INT(belle_sdp_mime_parameter,channel_count,int); GET_SET_INT(belle_sdp_mime_parameter,ptime,int); GET_SET_INT(belle_sdp_mime_parameter,max_ptime,int); GET_SET_INT(belle_sdp_mime_parameter,media_format,int); GET_SET_STRING(belle_sdp_mime_parameter,type); GET_SET_STRING(belle_sdp_mime_parameter,parameters); belle-sip-1.4.1/src/belle_sip_dict.c000066400000000000000000000075711252242224000172720ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/dict.h" #include "belle-sip/object.h" #include "belle-sip/belle-sip.h" #include "belle_sip_internal.h" #define BELLE_SIP_DICT(obj) BELLE_SIP_CAST(obj,belle_sip_dict_t) static void belle_sip_dict_string_destroy( void* data ) { belle_sip_free(data); } static void* belle_sip_dict_string_clone( const char* str, void* data ) { (void)str; return belle_sip_strdup((const char*)data); } belle_sip_dict_t* belle_sip_dict_create() { return belle_sip_object_new(belle_sip_dict_t); } static void belle_sip_dict_destroy( belle_sip_dict_t* obj) { } void belle_sip_dict_set_int(belle_sip_dict_t* obj, const char* key, int value) { char tmp[30]; snprintf(tmp,sizeof(tmp),"%i",value); belle_sip_dict_set_string(obj, key, tmp); } int belle_sip_dict_get_int(belle_sip_dict_t* obj, const char* key, int default_value) { const char *str=belle_sip_object_data_get(BELLE_SIP_OBJECT(obj),key); if (str!=NULL) { int ret=0; if (strstr(str,"0x")==str){ sscanf(str,"%x",&ret); }else ret=atoi(str); return ret; } else return default_value; } void belle_sip_dict_set_string(belle_sip_dict_t* obj, const char*key, const char*value) { belle_sip_object_data_set( BELLE_SIP_OBJECT(obj), key, (void*)belle_sip_strdup(value), belle_sip_dict_string_destroy ); } const char* belle_sip_dict_get_string(belle_sip_dict_t* obj, const char* key, const char* default_value) { void* data = belle_sip_object_data_get( BELLE_SIP_OBJECT(obj), key ); if( data ) return (const char *)data; else return default_value; } void belle_sip_dict_set_int64(belle_sip_dict_t* obj, const char* key, int64_t value) { char tmp[30]; #if defined (_MSC_VER) snprintf(tmp,sizeof(tmp),"%I64d",value); #else snprintf(tmp,sizeof(tmp),"%" PRId64"",value); #endif belle_sip_dict_set_string(obj,key,tmp); } int64_t belle_sip_dict_get_int64(belle_sip_dict_t* obj, const char* key, int64_t default_value) { const char *str= belle_sip_object_data_get( BELLE_SIP_OBJECT(obj), key ); if (str!=NULL) { #ifdef WIN32 return (int64_t)_atoi64(str); #else return atoll(str); #endif } else return default_value; } int belle_sip_dict_remove(belle_sip_dict_t* obj, const char*key) { return belle_sip_object_data_remove(BELLE_SIP_OBJECT(obj), key); } void belle_sip_dict_clone( const belle_sip_dict_t* src, belle_sip_dict_t* dst) { belle_sip_dict_clear(dst); belle_sip_dict_merge(src, dst); } void belle_sip_dict_merge( const belle_sip_dict_t* src, belle_sip_dict_t* dst) { belle_sip_object_data_merge(BELLE_SIP_OBJECT(src), BELLE_SIP_OBJECT(dst), belle_sip_dict_string_clone); } int belle_sip_dict_haskey(const belle_sip_dict_t* obj, const char* key) { return belle_sip_object_data_exists(BELLE_SIP_OBJECT(obj), key); } void belle_sip_dict_foreach(const belle_sip_dict_t* obj, void (*apply_func)(const char*, void*, void*), void* userdata) { belle_sip_object_data_foreach(BELLE_SIP_OBJECT(obj),apply_func, userdata); } void belle_sip_dict_clear(belle_sip_dict_t* obj) { return belle_sip_object_data_clear(BELLE_SIP_OBJECT(obj)); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_dict_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_dict_t, belle_sip_object_t, belle_sip_dict_destroy, NULL, NULL, TRUE); belle-sip-1.4.1/src/belle_sip_headers_impl.c000066400000000000000000002162041252242224000207760ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/headers.h" #include "belle-sip/parameters.h" #include #include #include #include "grammars/belle_sip_messageLexer.h" #include "grammars/belle_sip_messageParser.h" #include "belle_sip_internal.h" #include "listeningpoint_internal.h" /************************ * header ***********************/ GET_SET_STRING(belle_sip_header,name); #define PROTO_SIP 0x1 #define PROTO_HTTP 0x1<<1 typedef belle_sip_header_t* (*header_parse_func)(const char*) ; struct header_name_func_pair { int protocol; const char* name; header_parse_func func; }; static struct header_name_func_pair header_table[] = { {PROTO_SIP, "m", (header_parse_func)belle_sip_header_contact_parse} ,{PROTO_SIP, BELLE_SIP_CONTACT, (header_parse_func)belle_sip_header_contact_parse} ,{PROTO_SIP, "f", (header_parse_func)belle_sip_header_from_parse} ,{PROTO_SIP, BELLE_SIP_FROM, (header_parse_func)belle_sip_header_from_parse} ,{PROTO_SIP, "t", (header_parse_func)belle_sip_header_to_parse} ,{PROTO_SIP, BELLE_SIP_TO, (header_parse_func)belle_sip_header_to_parse} ,{PROTO_SIP, "i", (header_parse_func)belle_sip_header_call_id_parse} ,{PROTO_SIP, BELLE_SIP_CALL_ID, (header_parse_func)belle_sip_header_call_id_parse} ,{PROTO_SIP, "l", (header_parse_func)belle_sip_header_content_length_parse} ,{PROTO_SIP|PROTO_HTTP, BELLE_SIP_CONTENT_LENGTH, (header_parse_func)belle_sip_header_content_length_parse} ,{PROTO_SIP, "c", (header_parse_func)belle_sip_header_content_type_parse} ,{PROTO_SIP|PROTO_HTTP, BELLE_SIP_CONTENT_TYPE, (header_parse_func)belle_sip_header_content_type_parse} ,{PROTO_SIP, BELLE_SIP_CSEQ, (header_parse_func)belle_sip_header_cseq_parse} ,{PROTO_SIP, BELLE_SIP_ROUTE, (header_parse_func)belle_sip_header_route_parse} ,{PROTO_SIP, BELLE_SIP_RECORD_ROUTE, (header_parse_func)belle_sip_header_record_route_parse} ,{PROTO_SIP, "v", (header_parse_func)belle_sip_header_via_parse} ,{PROTO_SIP, BELLE_SIP_VIA, (header_parse_func)belle_sip_header_via_parse} ,{PROTO_SIP, BELLE_SIP_AUTHORIZATION, (header_parse_func)belle_sip_header_authorization_parse} ,{PROTO_SIP, BELLE_SIP_PROXY_AUTHORIZATION, (header_parse_func)belle_sip_header_proxy_authorization_parse} ,{PROTO_SIP|PROTO_HTTP, BELLE_SIP_WWW_AUTHENTICATE, (header_parse_func)belle_sip_header_www_authenticate_parse} ,{PROTO_SIP|PROTO_HTTP, BELLE_SIP_PROXY_AUTHENTICATE, (header_parse_func)belle_sip_header_proxy_authenticate_parse} ,{PROTO_SIP, BELLE_SIP_MAX_FORWARDS, (header_parse_func)belle_sip_header_max_forwards_parse} ,{PROTO_SIP|PROTO_HTTP, BELLE_SIP_USER_AGENT, (header_parse_func)belle_sip_header_user_agent_parse} ,{PROTO_SIP, BELLE_SIP_EXPIRES, (header_parse_func)belle_sip_header_expires_parse} ,{PROTO_SIP|PROTO_HTTP, BELLE_SIP_ALLOW, (header_parse_func)belle_sip_header_allow_parse} ,{PROTO_SIP, BELLE_SIP_SUBSCRIPTION_STATE, (header_parse_func)belle_sip_header_subscription_state_parse} ,{PROTO_SIP, BELLE_SIP_SERVICE_ROUTE, (header_parse_func)belle_sip_header_service_route_parse} ,{PROTO_SIP, BELLE_SIP_REFER_TO, (header_parse_func)belle_sip_header_refer_to_parse} ,{PROTO_SIP, BELLE_SIP_REFERRED_BY, (header_parse_func)belle_sip_header_referred_by_parse} ,{PROTO_SIP, BELLE_SIP_REPLACES, (header_parse_func)belle_sip_header_replaces_parse} ,{PROTO_SIP, BELLE_SIP_DATE, (header_parse_func)belle_sip_header_date_parse} ,{PROTO_SIP, BELLE_SIP_P_PREFERRED_IDENTITY, (header_parse_func)belle_sip_header_p_preferred_identity_parse} ,{PROTO_SIP, BELLE_SIP_PRIVACY, (header_parse_func)belle_sip_header_privacy_parse} ,{PROTO_SIP, BELLE_SIP_EVENT, (header_parse_func)belle_sip_header_event_parse} }; static belle_sip_header_t* belle_header_create(const char* name,const char* value,int protocol) { int i; belle_sip_header_t* ret; size_t elements =sizeof(header_table)/sizeof(struct header_name_func_pair); if (!name || name[0]=='\0') { belle_sip_error("Cannot create header without name"); return NULL; } for(i=0;iname) belle_sip_free(header->name); if (header->unparsed_value) belle_sip_free(header->unparsed_value); if (header->next) belle_sip_object_unref(BELLE_SIP_OBJECT(header->next)); } void belle_sip_header_set_next(belle_sip_header_t* header,belle_sip_header_t* next) { if (next) belle_sip_object_ref(next); if(header->next) belle_sip_object_unref(header->next); header->next = next; } belle_sip_header_t* belle_sip_header_get_next(const belle_sip_header_t* header) { return header->next; } const char *belle_sip_header_get_unparsed_value(belle_sip_header_t* obj){ if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(obj,belle_sip_header_extension_t)) { return belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(obj)); } else { char *tmp=belle_sip_object_to_string(obj); char *ret; char *end; if (obj->unparsed_value){ belle_sip_free(obj->unparsed_value); obj->unparsed_value=NULL; } obj->unparsed_value=tmp; ret=tmp; ret+=strlen(obj->name)+1; /* name + semicolon*/ for(;*ret==' ';ret++){};/*skip spaces*/ return ret; } } belle_sip_error_code belle_sip_header_marshal(belle_sip_header_t* header, char* buff, size_t buff_size, size_t *offset) { if (header->name) { return belle_sip_snprintf(buff,buff_size,offset,"%s: ",header->name); } else { belle_sip_warning("no header name found"); return BELLE_SIP_OK; } } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_header_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_header_t,belle_sip_object_t,belle_sip_header_destroy,belle_sip_header_clone,belle_sip_header_marshal,TRUE); BELLE_SIP_PARSE(header) /************************ * header_address ***********************/ struct _belle_sip_header_address { belle_sip_parameters_t base; char* displayname; belle_sip_uri_t* uri; belle_generic_uri_t* absolute_uri; }; static void belle_sip_header_address_init(belle_sip_header_address_t* object){ belle_sip_parameters_init((belle_sip_parameters_t*)object); /*super*/ } static void belle_sip_header_address_destroy(belle_sip_header_address_t* address) { if (address->displayname) belle_sip_free(address->displayname); if (address->uri) belle_sip_object_unref(address->uri); } static void belle_sip_header_address_clone(belle_sip_header_address_t *addr, const belle_sip_header_address_t *orig){ CLONE_STRING(belle_sip_header_address,displayname,addr,orig) if (belle_sip_header_address_get_uri(orig)) { belle_sip_header_address_set_uri(addr,BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_header_address_get_uri(orig))))); } if (belle_sip_header_address_get_absolute_uri(orig)) { belle_sip_header_address_set_absolute_uri(addr,BELLE_GENERIC_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_header_address_get_absolute_uri(orig))))); } } static belle_sip_error_code _belle_sip_header_address_marshal(belle_sip_header_address_t* header, char* buff, size_t buff_size, size_t *offset, int force_angle_quote) { belle_sip_error_code error=BELLE_SIP_OK; /*1 display name*/ if (header->displayname) { char* escaped_display_name = belle_sip_display_name_to_backslashed_escaped_string(header->displayname); error=belle_sip_snprintf(buff,buff_size,offset,"\"%s\" ",escaped_display_name); belle_sip_free(escaped_display_name); if (error!=BELLE_SIP_OK) return error; } if (header->uri || header->absolute_uri) { /*cases where < is required*/ if (force_angle_quote || header->displayname || header->absolute_uri || belle_sip_parameters_get_parameter_names((belle_sip_parameters_t*)header->uri) || belle_sip_uri_get_header_names(header->uri) || belle_sip_parameters_get_parameter_names(&header->base)) { error=belle_sip_snprintf(buff,buff_size,offset,"%s","<"); if (error!=BELLE_SIP_OK) return error; } if (header->uri) { error=belle_sip_uri_marshal(header->uri,buff,buff_size,offset); } else { error=belle_generic_uri_marshal(header->absolute_uri,buff,buff_size,offset); } if (error!=BELLE_SIP_OK) return error; if (force_angle_quote || header->displayname || header->absolute_uri || belle_sip_parameters_get_parameter_names((belle_sip_parameters_t*)header->uri) || belle_sip_uri_get_header_names(header->uri) || belle_sip_parameters_get_parameter_names(&header->base)) { error=belle_sip_snprintf(buff,buff_size,offset,"%s",">"); if (error!=BELLE_SIP_OK) return error; } } error=belle_sip_parameters_marshal(&header->base,buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; return error; } belle_sip_error_code belle_sip_header_address_marshal(belle_sip_header_address_t* header, char* buff, size_t buff_size, size_t *offset){ return _belle_sip_header_address_marshal(header, buff, buff_size, offset, FALSE); } BELLE_SIP_NEW_HEADER(header_address,parameters,"header_address") BELLE_SIP_PARSE(header_address) GET_SET_STRING(belle_sip_header_address,displayname); void belle_sip_header_address_set_quoted_displayname(belle_sip_header_address_t* address,const char* value) { if (address->displayname != NULL) belle_sip_free(address->displayname); if (strlen(value)>2) address->displayname=_belle_sip_str_dup_and_unquote_string(value); else address->displayname=NULL; } belle_sip_uri_t* belle_sip_header_address_get_uri(const belle_sip_header_address_t* address) { return address->uri; } void belle_sip_header_address_set_uri(belle_sip_header_address_t* address, belle_sip_uri_t* uri) { if (uri) belle_sip_object_ref(uri); if (address->uri){ belle_sip_object_unref(address->uri); } address->uri=uri; if (address->absolute_uri && uri) { belle_sip_warning("sip absolute uri [%p] already set for header_address [%p], cleaning it",address->absolute_uri, address); belle_sip_header_address_set_absolute_uri(address,NULL); } } belle_generic_uri_t* belle_sip_header_address_get_absolute_uri(const belle_sip_header_address_t* address) { return address->absolute_uri; } void belle_sip_header_address_set_absolute_uri(belle_sip_header_address_t* address, belle_generic_uri_t* absolute_uri) { belle_sip_object_ref(absolute_uri); if (address->absolute_uri){ belle_sip_object_unref(address->absolute_uri); } address->absolute_uri=absolute_uri; if (address->uri && absolute_uri) { belle_sip_warning("sip uri [%p] already set for header_address [%p], cleaning it",address->uri, address); belle_sip_header_address_set_uri(address,NULL); } } belle_sip_header_address_t* belle_sip_header_address_create(const char* display, belle_sip_uri_t* uri) { belle_sip_header_address_t* address = belle_sip_header_address_new(); belle_sip_header_address_set_displayname(address,display); belle_sip_header_address_set_uri(address,uri); return address; } belle_sip_header_address_t* belle_sip_header_address_create2(const char* display, belle_generic_uri_t* uri) { belle_sip_header_address_t* address = belle_sip_header_address_new(); belle_sip_header_address_set_displayname(address,display); belle_sip_header_address_set_absolute_uri(address,uri); return address; } /****************************** * Extension header inherits from header * ******************************/ struct _belle_sip_header_allow { belle_sip_header_t header; const char* method; }; static void belle_sip_header_allow_clone(belle_sip_header_allow_t *allow, const belle_sip_header_allow_t *orig){ CLONE_STRING(belle_sip_header_allow,method,allow,orig) } static void belle_sip_header_allow_destroy(belle_sip_header_allow_t* allow) { if (allow->method) belle_sip_free((void*)allow->method); } belle_sip_error_code belle_sip_header_allow_marshal(belle_sip_header_allow_t* allow, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(allow), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s",allow->method); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_allow,header,"Allow") BELLE_SIP_PARSE(header_allow) belle_sip_header_allow_t* belle_sip_header_allow_create (const char* methods) { belle_sip_header_allow_t* allow = belle_sip_header_allow_new(); belle_sip_header_allow_set_method(allow,methods); return allow; } GET_SET_STRING(belle_sip_header_allow,method); /************************ * header_contact ***********************/ struct _belle_sip_header_contact { belle_sip_header_address_t address; unsigned char wildcard; unsigned char automatic; unsigned char unknown; unsigned char pad[1]; }; void belle_sip_header_contact_destroy(belle_sip_header_contact_t* contact) { } void belle_sip_header_contact_clone(belle_sip_header_contact_t *contact, const belle_sip_header_contact_t *orig){ contact->wildcard=orig->wildcard; contact->automatic=orig->automatic; } belle_sip_error_code belle_sip_header_contact_marshal(belle_sip_header_contact_t* contact, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(contact), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; if (contact->wildcard) { error=belle_sip_snprintf(buff,buff_size,offset,"%s","*"); } else { error=belle_sip_header_address_marshal(&contact->address, buff, buff_size, offset); } return error; } BELLE_SIP_NEW_HEADER(header_contact,header_address,BELLE_SIP_CONTACT) BELLE_SIP_PARSE(header_contact) belle_sip_header_contact_t* belle_sip_header_contact_create (const belle_sip_header_address_t* contact) { belle_sip_header_contact_t* header = belle_sip_header_contact_new(); _belle_sip_object_copy(BELLE_SIP_OBJECT(header),BELLE_SIP_OBJECT(contact)); belle_sip_header_set_name(BELLE_SIP_HEADER(header),BELLE_SIP_CONTACT); /*restaure header name*/ return header; } GET_SET_INT_PARAM_PRIVATE(belle_sip_header_contact,expires,int,_) GET_SET_INT_PARAM_PRIVATE(belle_sip_header_contact,q,float,_); GET_SET_BOOL(belle_sip_header_contact,wildcard,is); int belle_sip_header_contact_set_expires(belle_sip_header_contact_t* contact, int expires) { if (expires < 0 ) { belle_sip_error("bad expires value [%i] for contact",expires); return -1; } _belle_sip_header_contact_set_expires(contact,expires); return 0; } int belle_sip_header_contact_set_qvalue(belle_sip_header_contact_t* contact, float qValue) { if (qValue != -1 && qValue < 0 && qValue >1) { belle_sip_error("bad q value [%f] for contact",qValue); return -1; } _belle_sip_header_contact_set_q(contact,qValue); return 0; } float belle_sip_header_contact_get_qvalue(const belle_sip_header_contact_t* contact) { return belle_sip_header_contact_get_q(contact); } unsigned int belle_sip_header_contact_equals(const belle_sip_header_contact_t* a,const belle_sip_header_contact_t* b) { if (!a | !b) return 0; return belle_sip_uri_equals(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(a)) ,belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(b))); } unsigned int belle_sip_header_contact_not_equals(const belle_sip_header_contact_t* a,const belle_sip_header_contact_t* b) { return !belle_sip_header_contact_equals(a,b); } void belle_sip_header_contact_set_automatic(belle_sip_header_contact_t *a, int enabled){ a->automatic=enabled; } int belle_sip_header_contact_get_automatic(const belle_sip_header_contact_t *a){ return a->automatic; } void belle_sip_header_contact_set_unknown(belle_sip_header_contact_t *a, int value){ a->unknown=value; } int belle_sip_header_contact_is_unknown(const belle_sip_header_contact_t *a){ return a->unknown; } /************************** * From header object inherent from header_address **************************** */ #define BELLE_SIP_FROM_LIKE_MARSHAL(header,force_angle_quote) \ belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(header), buff, buff_size, offset);\ if (error!=BELLE_SIP_OK) return error;\ error=_belle_sip_header_address_marshal(&header->address, buff, buff_size, offset, force_angle_quote); \ if (error!=BELLE_SIP_OK) return error;\ return error; struct _belle_sip_header_from { belle_sip_header_address_t address; }; static void belle_sip_header_from_destroy(belle_sip_header_from_t* from) { } static void belle_sip_header_from_clone(belle_sip_header_from_t* from, const belle_sip_header_from_t* cloned) { } belle_sip_error_code belle_sip_header_from_marshal(belle_sip_header_from_t* from, char* buff, size_t buff_size, size_t *offset) { BELLE_SIP_FROM_LIKE_MARSHAL(from,FALSE); } belle_sip_header_from_t* belle_sip_header_from_create2(const char *uri, const char *tag){ belle_sip_header_address_t* address = belle_sip_header_address_parse(uri); if (address) { belle_sip_header_from_t* from = belle_sip_header_from_create(address,tag); belle_sip_object_unref(address); return from; } else return NULL; } belle_sip_header_from_t* belle_sip_header_from_create(const belle_sip_header_address_t* address, const char *tag) { belle_sip_header_from_t* header= belle_sip_header_from_new(); belle_sip_uri_t* uri; _belle_sip_object_copy((belle_sip_object_t*)header,(belle_sip_object_t*)address); /*clear unwanted uri components*/ if ((uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)))) { belle_sip_parameters_t* params=BELLE_SIP_PARAMETERS(uri); belle_sip_parameters_remove_parameter(params,"lr"); belle_sip_parameters_remove_parameter(params,"ttl"); belle_sip_parameters_remove_parameter(params,"method"); belle_sip_parameters_remove_parameter(params,"maddr"); belle_sip_parameters_remove_parameter(params,"transport"); belle_sip_uri_set_port(uri,0); belle_sip_uri_headers_clean(uri); } belle_sip_header_set_name(BELLE_SIP_HEADER(header),BELLE_SIP_FROM); /*restore header name*/ if (tag) belle_sip_header_from_set_tag(header,tag); return header; } BELLE_SIP_NEW_HEADER(header_from,header_address,BELLE_SIP_FROM) BELLE_SIP_PARSE(header_from) GET_SET_STRING_PARAM2(belle_sip_header_from,tag,raw_tag); void belle_sip_header_from_set_random_tag(belle_sip_header_from_t *obj){ char tmp[BELLE_SIP_TAG_LENGTH]; belle_sip_header_from_set_raw_tag(obj,belle_sip_random_token(tmp,sizeof(tmp))); } void belle_sip_header_from_set_tag(belle_sip_header_from_t *obj, const char *tag){ if (tag==BELLE_SIP_RANDOM_TAG) belle_sip_header_from_set_random_tag(obj); else belle_sip_header_from_set_raw_tag(obj,tag); } const char *belle_sip_header_from_get_tag(const belle_sip_header_from_t *obj){ return belle_sip_header_from_get_raw_tag(obj); } /************************** * To header object inherits from header_address **************************** */ struct _belle_sip_header_to { belle_sip_header_address_t address; }; static void belle_sip_header_to_destroy(belle_sip_header_to_t* to) { } void belle_sip_header_to_clone(belle_sip_header_to_t *contact, const belle_sip_header_to_t *orig){ } belle_sip_error_code belle_sip_header_to_marshal(belle_sip_header_to_t* to, char* buff, size_t buff_size, size_t *offset) { BELLE_SIP_FROM_LIKE_MARSHAL(to,FALSE) } BELLE_SIP_NEW_HEADER(header_to,header_address,BELLE_SIP_TO) BELLE_SIP_PARSE(header_to) GET_SET_STRING_PARAM2(belle_sip_header_to,tag,raw_tag); belle_sip_header_to_t* belle_sip_header_to_create2(const char *uri, const char *tag){ belle_sip_header_address_t* address = belle_sip_header_address_parse(uri); if (address) { belle_sip_header_to_t* to = belle_sip_header_to_create(address,tag); belle_sip_object_unref(address); return to; } else return NULL; } belle_sip_header_to_t* belle_sip_header_to_create(const belle_sip_header_address_t* address, const char *tag) { belle_sip_header_to_t* header= belle_sip_header_to_new(); belle_sip_uri_t* uri; _belle_sip_object_copy((belle_sip_object_t*)header,(belle_sip_object_t*)address); /*clear unwanted uri components*/ if ((uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)))) { belle_sip_parameters_t* params=BELLE_SIP_PARAMETERS(uri); belle_sip_parameters_remove_parameter(params,"lr"); belle_sip_parameters_remove_parameter(params,"ttl"); belle_sip_parameters_remove_parameter(params,"method"); belle_sip_parameters_remove_parameter(params,"maddr"); belle_sip_parameters_remove_parameter(params,"transport"); belle_sip_uri_set_port(uri,0); belle_sip_uri_headers_clean(uri); } belle_sip_header_set_name(BELLE_SIP_HEADER(header),BELLE_SIP_TO); /*restaure header name*/ if (tag) belle_sip_header_to_set_tag(header,tag); return header; } void belle_sip_header_to_set_random_tag(belle_sip_header_to_t *obj){ char tmp[8]; /*not less than 32bit */ belle_sip_header_to_set_tag(obj,belle_sip_random_token(tmp,sizeof(tmp))); } void belle_sip_header_to_set_tag(belle_sip_header_to_t *obj, const char *tag){ if (tag==BELLE_SIP_RANDOM_TAG) belle_sip_header_to_set_random_tag(obj); else belle_sip_header_to_set_raw_tag(obj,tag); } const char *belle_sip_header_to_get_tag(const belle_sip_header_to_t *obj){ return belle_sip_header_to_get_raw_tag(obj); } /****************************** * User-Agent header inherits from header * ******************************/ struct _belle_sip_header_user_agent { belle_sip_header_t header; belle_sip_list_t* products; }; static void belle_sip_header_user_agent_destroy(belle_sip_header_user_agent_t* user_agent) { belle_sip_header_user_agent_set_products(user_agent,NULL); } static void belle_sip_header_user_agent_clone(belle_sip_header_user_agent_t* user_agent, const belle_sip_header_user_agent_t* orig){ belle_sip_list_t* list=orig->products; for(;list!=NULL;list=list->next){ belle_sip_header_user_agent_add_product(user_agent,(const char *)list->data); } } belle_sip_error_code belle_sip_header_user_agent_marshal(belle_sip_header_user_agent_t* user_agent, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=BELLE_SIP_OK; belle_sip_list_t* list = user_agent->products; error=belle_sip_header_marshal(BELLE_SIP_HEADER(user_agent), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; for(;list!=NULL;list=list->next){ error=belle_sip_snprintf(buff,buff_size,offset,list==user_agent->products ? "%s" : " %s",(const char *)list->data); if (error!=BELLE_SIP_OK) return error; } return error; } BELLE_SIP_NEW_HEADER(header_user_agent,header,"User-Agent") BELLE_SIP_PARSE(header_user_agent) belle_sip_list_t* belle_sip_header_user_agent_get_products(const belle_sip_header_user_agent_t* user_agent) { return user_agent->products; } void belle_sip_header_user_agent_set_products(belle_sip_header_user_agent_t* user_agent,belle_sip_list_t* products) { belle_sip_list_t* list; if (user_agent->products) { for (list=user_agent->products;list !=NULL; list=list->next) { belle_sip_free((void*)list->data); } belle_sip_list_free(user_agent->products); } user_agent->products=products; } void belle_sip_header_user_agent_add_product(belle_sip_header_user_agent_t* user_agent,const char* product) { user_agent->products = belle_sip_list_append(user_agent->products ,belle_sip_strdup(product)); } int belle_sip_header_user_agent_get_products_as_string(const belle_sip_header_user_agent_t* user_agent,char* value,unsigned int value_size) { size_t result = 0; belle_sip_error_code error=BELLE_SIP_OK; belle_sip_list_t* list = user_agent->products; for(;list!=NULL;list=list->next){ error=belle_sip_snprintf(value,value_size,&result,"%s ",(const char *)list->data); if (error!=BELLE_SIP_OK) return -1; } if (result>0) value[result]='\0'; /*remove last space */ return result-1; } /************************** * Via header object inherits from parameters **************************** */ struct _belle_sip_header_via { belle_sip_parameters_t params_list; char* protocol; char* transport; char* host; int port; char* received; }; static void belle_sip_header_via_destroy(belle_sip_header_via_t* via) { if (via->protocol) belle_sip_free(via->protocol); if (via->transport) belle_sip_free(via->transport); if (via->host) belle_sip_free(via->host); DESTROY_STRING(via,received) } static void belle_sip_header_via_clone(belle_sip_header_via_t* via, const belle_sip_header_via_t*orig){ CLONE_STRING(belle_sip_header_via,protocol,via,orig) CLONE_STRING(belle_sip_header_via,transport,via,orig) CLONE_STRING(belle_sip_header_via,host,via,orig) CLONE_STRING(belle_sip_header_via,received,via,orig) via->port=orig->port; } belle_sip_error_code belle_sip_header_via_marshal(belle_sip_header_via_t* via, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(via), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s/%s",via->protocol,via->transport); if (error!=BELLE_SIP_OK) return error; if (via->host) { if (strchr(via->host,':')) { /*ipv6*/ error=belle_sip_snprintf(buff,buff_size,offset," [%s]",via->host); } else { error=belle_sip_snprintf(buff,buff_size,offset," %s",via->host); } if (error!=BELLE_SIP_OK) return error; } else { belle_sip_warning("no host found in this via"); } if (via->port > 0) { error=belle_sip_snprintf(buff,buff_size,offset,":%i",via->port); if (error!=BELLE_SIP_OK) return error; } if (via->received) { error=belle_sip_snprintf(buff,buff_size,offset,";received=%s",via->received); if (error!=BELLE_SIP_OK) return error; } error=belle_sip_parameters_marshal(&via->params_list, buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; return error; } belle_sip_header_via_t* belle_sip_header_via_create(const char *host, int port, const char *transport, const char *branch){ belle_sip_header_via_t *via=belle_sip_header_via_new(); via->host=belle_sip_strdup(host); via->port=port; via->transport=belle_sip_strdup(transport); via->protocol=belle_sip_strdup("SIP/2.0"); belle_sip_header_via_set_branch(via,branch); return via; } BELLE_SIP_NEW_HEADER(header_via,parameters,BELLE_SIP_VIA) BELLE_SIP_PARSE(header_via) GET_SET_STRING(belle_sip_header_via,protocol); GET_SET_STRING(belle_sip_header_via,transport); GET_SET_STRING(belle_sip_header_via,host); GET_SET_STRING(belle_sip_header_via,received); GET_SET_INT_PRIVATE(belle_sip_header_via,port,int,_); GET_SET_STRING_PARAM(belle_sip_header_via,branch); GET_SET_STRING_PARAM(belle_sip_header_via,maddr); GET_SET_INT_PARAM_PRIVATE(belle_sip_header_via,rport,int,_) GET_SET_INT_PARAM_PRIVATE(belle_sip_header_via,ttl,int,_) int belle_sip_header_via_set_rport (belle_sip_header_via_t* obj,int value) { if (value == -1) { belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(obj),"rport",NULL); return 0; } if (value>0 && value<65536) { _belle_sip_header_via_set_rport(obj,value); return 0; } else { belle_sip_error("bad rport value [%i] for via",value); return -1; } } int belle_sip_header_via_set_ttl (belle_sip_header_via_t* obj,int value) { if (value ==-1 || (value>0 && value<=255)) { _belle_sip_header_via_set_ttl(obj,value); return 0; } else { belle_sip_error("bad ttl value [%i] for via",value); return -1; } } int belle_sip_header_via_set_port (belle_sip_header_via_t* obj,int value) { if (value ==-1 || (value>0 && value<65536)) { _belle_sip_header_via_set_port(obj,value); return 0; } else { belle_sip_error("bad port value [%i] for via",value); return -1; } } int belle_sip_header_via_get_listening_port(const belle_sip_header_via_t *via){ int ret=belle_sip_header_via_get_port(via); if (ret==0) ret=belle_sip_listening_point_get_well_known_port(via->transport); return ret; } const char* belle_sip_header_via_get_transport_lowercase(const belle_sip_header_via_t* via) { if (strcasecmp("udp",via->transport)==0) return "udp"; else if (strcasecmp("tcp",via->transport)==0) return "tcp"; else if (strcasecmp("tls",via->transport)==0) return "tls"; else if (strcasecmp("dtls",via->transport)==0) return "dtls"; else { belle_sip_warning("Cannot convert [%s] to lower case",via->transport); return via->transport; } } /************************** * call_id header object inherits from object **************************** */ struct _belle_sip_header_call_id { belle_sip_header_t header; const char* call_id; }; static void belle_sip_header_call_id_destroy(belle_sip_header_call_id_t* call_id) { if (call_id->call_id) belle_sip_free((void*)call_id->call_id); } static void belle_sip_header_call_id_clone(belle_sip_header_call_id_t* call_id,const belle_sip_header_call_id_t *orig){ CLONE_STRING(belle_sip_header_call_id,call_id,call_id,orig); } belle_sip_error_code belle_sip_header_call_id_marshal(belle_sip_header_call_id_t* call_id, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(call_id), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s",call_id->call_id); if (error!=BELLE_SIP_OK) return error; return error; } unsigned int belle_sip_header_call_id_equals(const belle_sip_header_call_id_t* a,const belle_sip_header_call_id_t* b) { return strcasecmp(a->call_id,b->call_id) == 0; } BELLE_SIP_NEW_HEADER(header_call_id,header,BELLE_SIP_CALL_ID) BELLE_SIP_PARSE(header_call_id) GET_SET_STRING(belle_sip_header_call_id,call_id); /************************** * cseq header object inherent from object **************************** */ struct _belle_sip_header_cseq { belle_sip_header_t header; char* method; unsigned int seq_number; }; static void belle_sip_header_cseq_destroy(belle_sip_header_cseq_t* cseq) { if (cseq->method) belle_sip_free(cseq->method); } static void belle_sip_header_cseq_clone(belle_sip_header_cseq_t* cseq, const belle_sip_header_cseq_t *orig) { CLONE_STRING(belle_sip_header_cseq,method,cseq,orig) cseq->seq_number=orig->seq_number; } belle_sip_error_code belle_sip_header_cseq_marshal(belle_sip_header_cseq_t* cseq, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(cseq), buff,buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%i %s",cseq->seq_number,cseq->method); if (error!=BELLE_SIP_OK) return error; return error; } belle_sip_header_cseq_t * belle_sip_header_cseq_create(unsigned int number, const char *method){ belle_sip_header_cseq_t *cseq=belle_sip_header_cseq_new(); belle_sip_header_cseq_set_method(cseq,method); cseq->seq_number=number; return cseq; } BELLE_SIP_NEW_HEADER(header_cseq,header,BELLE_SIP_CSEQ) BELLE_SIP_PARSE(header_cseq) GET_SET_STRING(belle_sip_header_cseq,method); GET_SET_INT(belle_sip_header_cseq,seq_number,unsigned int) /************************** * content type header object inherent from parameters **************************** */ struct _belle_sip_header_content_type { belle_sip_parameters_t params_list; const char* type; const char* subtype; }; static void belle_sip_header_content_type_destroy(belle_sip_header_content_type_t* content_type) { if (content_type->type) belle_sip_free((void*)content_type->type); if (content_type->subtype) belle_sip_free((void*)content_type->subtype); } static void belle_sip_header_content_type_clone(belle_sip_header_content_type_t* content_type, const belle_sip_header_content_type_t* orig){ CLONE_STRING(belle_sip_header_content_type,type,content_type,orig); CLONE_STRING(belle_sip_header_content_type,subtype,content_type,orig); } belle_sip_error_code belle_sip_header_content_type_marshal(belle_sip_header_content_type_t* content_type, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(content_type), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s/%s",content_type->type, content_type->subtype); if (error!=BELLE_SIP_OK) return error; error=belle_sip_parameters_marshal(&content_type->params_list, buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_content_type,parameters,BELLE_SIP_CONTENT_TYPE) BELLE_SIP_PARSE(header_content_type) belle_sip_header_content_type_t* belle_sip_header_content_type_create (const char* type,const char* sub_type) { belle_sip_header_content_type_t* header = belle_sip_header_content_type_new(); belle_sip_header_content_type_set_type(header,type); belle_sip_header_content_type_set_subtype(header,sub_type); return header; } GET_SET_STRING(belle_sip_header_content_type,type); GET_SET_STRING(belle_sip_header_content_type,subtype); /************************** * Route header object inherent from header_address **************************** */ struct _belle_sip_header_route { belle_sip_header_address_t address; }; static void belle_sip_header_route_destroy(belle_sip_header_route_t* route) { } static void belle_sip_header_route_clone(belle_sip_header_route_t* route, const belle_sip_header_route_t* orig) { } belle_sip_error_code belle_sip_header_route_marshal(belle_sip_header_route_t* route, char* buff, size_t buff_size, size_t *offset) { BELLE_SIP_FROM_LIKE_MARSHAL(route,TRUE) } BELLE_SIP_NEW_HEADER(header_route,header_address,BELLE_SIP_ROUTE) BELLE_SIP_PARSE(header_route) belle_sip_header_route_t* belle_sip_header_route_create(const belle_sip_header_address_t* route) { belle_sip_header_route_t* header= belle_sip_header_route_new(); _belle_sip_object_copy((belle_sip_object_t*)header,(belle_sip_object_t*)route); belle_sip_header_set_name(BELLE_SIP_HEADER(header),BELLE_SIP_ROUTE); /*restore header name*/ return header; } /************************** * Record route header object inherent from header_address **************************** */ struct _belle_sip_header_record_route { belle_sip_header_address_t address; unsigned char auto_outgoing; unsigned char pad[3]; }; static void belle_sip_header_record_route_destroy(belle_sip_header_record_route_t* record_route) { } static void belle_sip_header_record_route_clone(belle_sip_header_record_route_t* record_route, const belle_sip_header_record_route_t* orig ) { } belle_sip_error_code belle_sip_header_record_route_marshal(belle_sip_header_record_route_t* record_route, char* buff, size_t buff_size, size_t *offset) { BELLE_SIP_FROM_LIKE_MARSHAL(record_route,TRUE) } belle_sip_header_record_route_t *belle_sip_header_record_route_new_auto_outgoing() { belle_sip_header_record_route_t *rr = belle_sip_header_record_route_new(); rr->auto_outgoing = TRUE; return rr; } unsigned char belle_sip_header_record_route_get_auto_outgoing(const belle_sip_header_record_route_t *a) { return a->auto_outgoing; } BELLE_SIP_NEW_HEADER(header_record_route,header_address,BELLE_SIP_RECORD_ROUTE) BELLE_SIP_PARSE(header_record_route) /************************** * Service route header object inherent from header_address **************************** */ struct _belle_sip_header_service_route { belle_sip_header_address_t address; }; static void belle_sip_header_service_route_destroy(belle_sip_header_service_route_t* service_route) { } static void belle_sip_header_service_route_clone(belle_sip_header_service_route_t* service_route, const belle_sip_header_service_route_t* orig ) { } belle_sip_error_code belle_sip_header_service_route_marshal(belle_sip_header_service_route_t* service_route, char* buff, size_t buff_size, size_t *offset) { BELLE_SIP_FROM_LIKE_MARSHAL(service_route,TRUE) } BELLE_SIP_NEW_HEADER(header_service_route,header_address,BELLE_SIP_SERVICE_ROUTE) BELLE_SIP_PARSE(header_service_route) /************************** * content length header object inherent from object **************************** */ struct _belle_sip_header_content_length { belle_sip_header_t header; unsigned int content_length; }; static void belle_sip_header_content_length_destroy(belle_sip_header_content_length_t* content_length) { } static void belle_sip_header_content_length_clone(belle_sip_header_content_length_t* content_length, const belle_sip_header_content_length_t *orig ) { content_length->content_length=orig->content_length; } belle_sip_error_code belle_sip_header_content_length_marshal(belle_sip_header_content_length_t* content_length, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(content_length), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%i",content_length->content_length); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_content_length,header,BELLE_SIP_CONTENT_LENGTH) BELLE_SIP_PARSE(header_content_length) GET_SET_INT(belle_sip_header_content_length,content_length,unsigned int) belle_sip_header_content_length_t* belle_sip_header_content_length_create (int content_length) { belle_sip_header_content_length_t* obj; obj = belle_sip_header_content_length_new(); belle_sip_header_content_length_set_content_length(obj,content_length); return obj; } /************************** * Expires header object inherent from header **************************** */ struct _belle_sip_header_expires { belle_sip_header_t header; int expires; }; static void belle_sip_header_expires_destroy(belle_sip_header_expires_t* expires) { } static void belle_sip_header_expires_clone(belle_sip_header_expires_t* expires, const belle_sip_header_expires_t *orig ) { expires->expires=orig->expires; } belle_sip_error_code belle_sip_header_expires_marshal(belle_sip_header_expires_t* expires, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(expires), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%i",expires->expires); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_expires,header,BELLE_SIP_EXPIRES) BELLE_SIP_PARSE(header_expires) GET_SET_INT(belle_sip_header_expires,expires,int) belle_sip_header_expires_t* belle_sip_header_expires_create(int expires) { belle_sip_header_expires_t* obj = belle_sip_header_expires_new(); belle_sip_header_expires_set_expires(obj,expires); return obj; } /****************************** * Extension header hinerite from header * ******************************/ struct _belle_sip_header_extension { belle_sip_header_t header; const char* value; }; static void belle_sip_header_extension_destroy(belle_sip_header_extension_t* extension) { if (extension->value) belle_sip_free((void*)extension->value); } static void belle_sip_header_extension_clone(belle_sip_header_extension_t* extension, const belle_sip_header_extension_t* orig){ CLONE_STRING(belle_sip_header_extension,value,extension,orig) } belle_sip_error_code belle_sip_header_extension_marshal(belle_sip_header_extension_t* extension, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(extension), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; if (extension->value) error=belle_sip_snprintf(buff,buff_size,offset,"%s",extension->value); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_extension,header,NULL) belle_sip_header_extension_t* belle_sip_header_extension_create (const char* name,const char* value) { belle_sip_header_extension_t* ext = belle_sip_header_extension_new(); belle_sip_header_set_name(BELLE_SIP_HEADER(ext),name); belle_sip_header_extension_set_value(ext,value); return ext; } GET_SET_STRING(belle_sip_header_extension,value); /************************** *Authorization header object inherent from parameters **************************** */ #define AUTH_BASE \ belle_sip_parameters_t params_list; \ const char* scheme; \ const char* realm; \ const char* nonce; \ const char* algorithm; \ const char* opaque; #define AUTH_BASE_DESTROY(obj) \ if (obj->scheme) belle_sip_free((void*)obj->scheme);\ if (obj->realm) belle_sip_free((void*)obj->realm);\ if (obj->nonce) belle_sip_free((void*)obj->nonce);\ if (obj->algorithm) belle_sip_free((void*)obj->algorithm);\ if (obj->opaque) belle_sip_free((void*)obj->opaque);\ /*if (obj->params_list) FIXME free list*/ #define AUTH_BASE_CLONE(object_type,dest,src) \ CLONE_STRING(object_type,scheme,dest,src)\ CLONE_STRING(object_type,realm,dest,src)\ CLONE_STRING(object_type,nonce,dest,src)\ CLONE_STRING(object_type,algorithm,dest,src)\ CLONE_STRING(object_type,opaque,dest,src) \ #define AUTH_BASE_MARSHAL(header) \ char* border=" ";\ const belle_sip_list_t* list;\ belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(header), buff, buff_size, offset);\ if (error!=BELLE_SIP_OK) return error;\ list=belle_sip_parameters_get_parameters(&header->params_list);\ if (header->scheme) { \ error=belle_sip_snprintf(buff,buff_size,offset," %s",header->scheme);\ if (error!=BELLE_SIP_OK) return error;\ } else { \ belle_sip_error("missing mandatory scheme"); \ } \ for(;list!=NULL;list=list->next){\ belle_sip_param_pair_t* container = list->data;\ error=belle_sip_snprintf(buff,buff_size,offset,"%s%s=%s",border, container->name,container->value);\ if (error!=BELLE_SIP_OK) return error;\ border=", ";\ }\ if (header->realm) {\ error=belle_sip_snprintf(buff,buff_size,offset,"%srealm=\"%s\"",border,header->realm);\ if (error!=BELLE_SIP_OK) return error;\ border=", ";\ }\ if (header->nonce) {\ error=belle_sip_snprintf(buff,buff_size,offset,"%snonce=\"%s\"",border,header->nonce);\ if (error!=BELLE_SIP_OK) return error;\ border=", ";\ }\ if (header->algorithm) {\ const char* format;\ if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(header,belle_http_header_authorization_t)) {\ format="%salgorithm=\"%s\"";\ } else {\ format="%salgorithm=%s";\ }\ error=belle_sip_snprintf(buff,buff_size,offset,format,border,header->algorithm);\ if (error!=BELLE_SIP_OK) return error;\ border=", ";\ }\ if (header->opaque) {\ error=belle_sip_snprintf(buff,buff_size,offset,"%sopaque=\"%s\"",border,header->opaque);\ if (error!=BELLE_SIP_OK) return error;\ border=", ";\ } struct _belle_sip_header_authorization { AUTH_BASE const char* username; belle_sip_uri_t* uri; const char* response; const char* cnonce; int nonce_count; const char* qop; }; static void belle_sip_header_authorization_destroy(belle_sip_header_authorization_t* authorization) { if (authorization->username) belle_sip_free((void*)authorization->username); if (authorization->uri) { belle_sip_object_unref(authorization->uri); } if (authorization->cnonce) belle_sip_free((void*)authorization->cnonce); AUTH_BASE_DESTROY(authorization) DESTROY_STRING(authorization,response); DESTROY_STRING(authorization,qop); } static void belle_sip_header_authorization_clone(belle_sip_header_authorization_t* authorization, const belle_sip_header_authorization_t *orig ) { AUTH_BASE_CLONE(belle_sip_header_authorization,authorization,orig) CLONE_STRING(belle_sip_header_authorization,username,authorization,orig) if (belle_sip_header_authorization_get_uri(orig)) { belle_sip_header_authorization_set_uri(authorization,BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_header_authorization_get_uri(orig))))); } CLONE_STRING(belle_sip_header_authorization,response,authorization,orig) CLONE_STRING(belle_sip_header_authorization,cnonce,authorization,orig) authorization->nonce_count=orig->nonce_count; CLONE_STRING(belle_sip_header_authorization,qop,authorization,orig) } static void belle_sip_header_authorization_init(belle_sip_header_authorization_t* authorization) { } belle_sip_uri_t* belle_sip_header_authorization_get_uri(const belle_sip_header_authorization_t* authorization) { return authorization->uri; } void belle_sip_header_authorization_set_uri(belle_sip_header_authorization_t* authorization, belle_sip_uri_t* uri) { if (uri) belle_sip_object_ref(uri); if (authorization->uri) { belle_sip_object_unref(BELLE_SIP_OBJECT(authorization->uri)); } authorization->uri=uri; } belle_sip_error_code belle_sip_header_authorization_marshal(belle_sip_header_authorization_t* authorization, char* buff, size_t buff_size, size_t *offset) { char nonce_count[10]; AUTH_BASE_MARSHAL(authorization) if (authorization->username) { error=belle_sip_snprintf(buff,buff_size,offset,"%susername=\"%s\"",border,authorization->username); if (error!=BELLE_SIP_OK) return error; border=", "; } if (authorization->uri) { error=belle_sip_snprintf(buff,buff_size,offset,"%s uri=\"",border); if (error!=BELLE_SIP_OK) return error; border=", "; error=belle_sip_uri_marshal(authorization->uri,buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s","\""); if (error!=BELLE_SIP_OK) return error; } if (authorization->response) { error=belle_sip_snprintf(buff,buff_size,offset,"%sresponse=\"%s\"",border,authorization->response); if (error!=BELLE_SIP_OK) return error; border=", "; } if (authorization->cnonce) { error=belle_sip_snprintf(buff,buff_size,offset,"%scnonce=\"%s\"",border,authorization->cnonce); if (error!=BELLE_SIP_OK) return error; border=", "; } if (authorization->nonce_count>0) { belle_sip_header_authorization_get_nonce_count_as_string(authorization,nonce_count); error=belle_sip_snprintf(buff,buff_size,offset,"%snc=%s",border,nonce_count); if (error!=BELLE_SIP_OK) return error; border=", "; } if (authorization->qop) { const char* format; if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(authorization,belle_http_header_authorization_t)) { format="%sqop=\"%s\""; } else { format="%sqop=%s"; } error=belle_sip_snprintf(buff,buff_size,offset,format,border,authorization->qop); if (error!=BELLE_SIP_OK) return error; } return error; } BELLE_SIP_NEW_HEADER(header_authorization,parameters,BELLE_SIP_AUTHORIZATION) BELLE_SIP_PARSE(header_authorization) GET_SET_STRING(belle_sip_header_authorization,scheme); GET_SET_STRING(belle_sip_header_authorization,username); GET_SET_STRING(belle_sip_header_authorization,realm); GET_SET_STRING(belle_sip_header_authorization,nonce); GET_SET_STRING(belle_sip_header_authorization,response); GET_SET_STRING(belle_sip_header_authorization,algorithm); GET_SET_STRING(belle_sip_header_authorization,cnonce); GET_SET_STRING(belle_sip_header_authorization,opaque); GET_SET_STRING(belle_sip_header_authorization,qop); GET_SET_INT(belle_sip_header_authorization,nonce_count,int) int belle_sip_header_authorization_get_nonce_count_as_string(const belle_sip_header_authorization_t* authorization,char nounce_count[9]) { nounce_count[0]='\0'; if (authorization->nonce_count>0) { snprintf(nounce_count,9,"%08x",authorization->nonce_count); return 0; } else { return -1; } } /************************** *Proxy-Authorization header object inherent from parameters **************************** */ struct _belle_sip_header_proxy_authorization { belle_sip_header_authorization_t authorization; }; static void belle_sip_header_proxy_authorization_destroy(belle_sip_header_proxy_authorization_t* proxy_authorization) { } static void belle_sip_header_proxy_authorization_clone(belle_sip_header_proxy_authorization_t* proxy_authorization, const belle_sip_header_proxy_authorization_t *orig ) { } belle_sip_error_code belle_sip_header_proxy_authorization_marshal(belle_sip_header_proxy_authorization_t* proxy_authorization, char* buff, size_t buff_size, size_t *offset) { return belle_sip_header_authorization_marshal(&proxy_authorization->authorization,buff,buff_size,offset); } BELLE_SIP_NEW_HEADER(header_proxy_authorization,header_authorization,BELLE_SIP_PROXY_AUTHORIZATION) BELLE_SIP_PARSE(header_proxy_authorization) /************************** *HTTP Authorization header object inherent from Authorization **************************** */ struct _belle_http_header_authorization { belle_sip_header_authorization_t authorization; belle_generic_uri_t* uri; }; static void belle_http_header_authorization_init(belle_http_header_authorization_t* authorization) { belle_sip_header_set_name(BELLE_SIP_HEADER(authorization),BELLE_HTTP_AUTHORIZATION); } static void belle_http_header_authorization_destroy(belle_http_header_authorization_t* authorization) { if (authorization->uri) { belle_sip_object_unref(authorization->uri); } } static void belle_http_header_authorization_clone(belle_http_header_authorization_t* authorization, const belle_http_header_authorization_t *orig ) { if (belle_http_header_authorization_get_uri(orig)) { belle_http_header_authorization_set_uri(authorization,BELLE_GENERIC_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_http_header_authorization_get_uri(orig))))); } } belle_sip_error_code belle_http_header_authorization_marshal(belle_http_header_authorization_t* authorization, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=BELLE_SIP_OK; /*first make sure there is no sip uri*/ if (belle_sip_header_authorization_get_uri(BELLE_SIP_HEADER_AUTHORIZATION(authorization))) { belle_sip_error ("Cannot marshal http_header_authorization because a sip uri is set. Use belle_http_authorization_set uri instead of belle_sip_header_authorization_set_uri"); return BELLE_SIP_NOT_IMPLEMENTED; } belle_sip_header_authorization_marshal(BELLE_SIP_HEADER_AUTHORIZATION(authorization),buff,buff_size,offset); if (authorization->uri) { error=belle_sip_snprintf(buff,buff_size,offset,", uri=\""); if (error!=BELLE_SIP_OK) return error; error=belle_generic_uri_marshal(authorization->uri,buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s","\""); if (error!=BELLE_SIP_OK) return error; } return error; } BELLE_NEW(belle_http_header_authorization,belle_sip_header_authorization) belle_generic_uri_t* belle_http_header_authorization_get_uri(const belle_http_header_authorization_t* authorization) { return authorization->uri; } void belle_http_header_authorization_set_uri( belle_http_header_authorization_t* authorization,belle_generic_uri_t* uri) { if (authorization->uri) belle_sip_object_unref(authorization->uri); if (uri) belle_sip_object_ref(uri); authorization->uri=uri; } /************************** *WWW-Authenticate header object inherent from parameters **************************** */ struct _belle_sip_header_www_authenticate { AUTH_BASE const char* domain; int stale; belle_sip_list_t* qop; }; static void belle_sip_header_www_authenticate_destroy(belle_sip_header_www_authenticate_t* www_authenticate) { AUTH_BASE_DESTROY(www_authenticate) if (www_authenticate->domain) belle_sip_free((void*)www_authenticate->domain); if (www_authenticate->qop) belle_sip_list_free_with_data(www_authenticate->qop,belle_sip_free); } void belle_sip_header_www_authenticate_init(belle_sip_header_www_authenticate_t* www_authenticate) { www_authenticate->stale=-1; } static void belle_sip_header_www_authenticate_clone(belle_sip_header_www_authenticate_t* www_authenticate, const belle_sip_header_www_authenticate_t *orig ) { AUTH_BASE_CLONE(belle_sip_header_www_authenticate,www_authenticate,orig) CLONE_STRING(belle_sip_header_www_authenticate,domain,www_authenticate,orig) www_authenticate->stale=orig->stale; www_authenticate->qop=belle_sip_list_copy_with_data(orig->qop,(void* (*)(void*))belle_sip_strdup); } belle_sip_error_code belle_sip_header_www_authenticate_marshal(belle_sip_header_www_authenticate_t* www_authenticate, char* buff, size_t buff_size, size_t *offset) { belle_sip_list_t* qops=www_authenticate->qop; AUTH_BASE_MARSHAL(www_authenticate) if (www_authenticate->domain) { error=belle_sip_snprintf(buff,buff_size,offset,"%sdomain=\"%s\"",border,www_authenticate->domain); if (error!=BELLE_SIP_OK) return error; border=", "; } if (www_authenticate->stale>=0) { error=belle_sip_snprintf(buff,buff_size,offset,"%sstale=%s",border,www_authenticate->stale?"true":"false"); if (error!=BELLE_SIP_OK) return error; } if (qops!=NULL && qops->data!=NULL) { error=belle_sip_snprintf(buff,buff_size,offset,"%sqop=\"",border); if (error!=BELLE_SIP_OK) return error; border=""; for(;qops!=NULL;qops=qops->next){ error=belle_sip_snprintf(buff,buff_size,offset,"%s%s",border, (const char*)qops->data); if (error!=BELLE_SIP_OK) return error; border=","; }\ error=belle_sip_snprintf(buff,buff_size,offset,"\""); if (error!=BELLE_SIP_OK) return error; border=", "; } return error; } #define SET_ADD_STRING_LIST(header,name) \ void header##_set_##name(header##_t* obj, belle_sip_list_t* value) {\ if (obj->name) {\ belle_sip_list_free_with_data(obj->name,belle_sip_free);\ } \ obj->name=value;\ }\ void header##_add_##name(header##_t* obj, const char* value) {\ obj->name=belle_sip_list_append(obj->name,strdup(value));\ } BELLE_SIP_NEW_HEADER_INIT(header_www_authenticate,parameters,BELLE_SIP_WWW_AUTHENTICATE,header_www_authenticate) BELLE_SIP_PARSE(header_www_authenticate) GET_SET_STRING(belle_sip_header_www_authenticate,scheme); GET_SET_STRING(belle_sip_header_www_authenticate,realm); GET_SET_STRING(belle_sip_header_www_authenticate,nonce); GET_SET_STRING(belle_sip_header_www_authenticate,algorithm); GET_SET_STRING(belle_sip_header_www_authenticate,opaque); /*GET_SET_STRING(belle_sip_header_www_authenticate,qop);*/ SET_ADD_STRING_LIST(belle_sip_header_www_authenticate,qop) GET_SET_STRING(belle_sip_header_www_authenticate,domain) GET_SET_BOOL(belle_sip_header_www_authenticate,stale,is) belle_sip_list_t* belle_sip_header_www_authenticate_get_qop(const belle_sip_header_www_authenticate_t* www_authetication) { return www_authetication->qop; } const char* belle_sip_header_www_authenticate_get_qop_first(const belle_sip_header_www_authenticate_t* www_authetication) { return www_authetication->qop?(const char*)www_authetication->qop->data:NULL; } /************************** *Proxy-authenticate header object inherent from www_authenticate **************************** */ struct _belle_sip_header_proxy_authenticate { belle_sip_header_www_authenticate_t www_authenticate; }; static void belle_sip_header_proxy_authenticate_destroy(belle_sip_header_proxy_authenticate_t* proxy_authenticate) { } static void belle_sip_header_proxy_authenticate_clone(belle_sip_header_proxy_authenticate_t* proxy_authenticate, const belle_sip_header_proxy_authenticate_t *orig ) { } belle_sip_error_code belle_sip_header_proxy_authenticate_marshal(belle_sip_header_proxy_authenticate_t* proxy_authenticate, char* buff, size_t buff_size, size_t *offset) { return belle_sip_header_www_authenticate_marshal(&proxy_authenticate->www_authenticate,buff,buff_size,offset); } BELLE_SIP_NEW_HEADER(header_proxy_authenticate,header_www_authenticate,BELLE_SIP_PROXY_AUTHENTICATE) BELLE_SIP_PARSE(header_proxy_authenticate) /************************** * max forwards header object inherent from header **************************** */ struct _belle_sip_header_max_forwards { belle_sip_header_t header; int max_forwards; }; static void belle_sip_header_max_forwards_destroy(belle_sip_header_max_forwards_t* max_forwards) { } static void belle_sip_header_max_forwards_clone(belle_sip_header_max_forwards_t* max_forwards, const belle_sip_header_max_forwards_t *orig ) { max_forwards->max_forwards=orig->max_forwards; } belle_sip_error_code belle_sip_header_max_forwards_marshal(belle_sip_header_max_forwards_t* max_forwards, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(max_forwards), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%i",max_forwards->max_forwards); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_max_forwards,header,"Max-Forwards") BELLE_SIP_PARSE(header_max_forwards) GET_SET_INT(belle_sip_header_max_forwards,max_forwards,int) int belle_sip_header_max_forwards_decrement_max_forwards(belle_sip_header_max_forwards_t* max_forwards) { return max_forwards->max_forwards--; } belle_sip_header_max_forwards_t* belle_sip_header_max_forwards_create(int value) { belle_sip_header_max_forwards_t* max_forwards=belle_sip_header_max_forwards_new(); max_forwards->max_forwards=value; return max_forwards; } /************************** * Subscription state header object inherent from parameters **************************** */ struct _belle_sip_header_subscription_state { belle_sip_parameters_t parameters; const char* state; }; static void belle_sip_header_subscription_state_destroy(belle_sip_header_subscription_state_t* subscription_state) { DESTROY_STRING(subscription_state,state); } static void belle_sip_header_subscription_state_clone(belle_sip_header_subscription_state_t* subscription_state, const belle_sip_header_subscription_state_t *orig ) { CLONE_STRING(belle_sip_header_subscription_state,state,subscription_state,orig) } belle_sip_error_code belle_sip_header_subscription_state_marshal(belle_sip_header_subscription_state_t* subscription_state, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(subscription_state), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s",subscription_state->state); if (error!=BELLE_SIP_OK) return error; error=belle_sip_parameters_marshal(BELLE_SIP_PARAMETERS(subscription_state), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_subscription_state,parameters,BELLE_SIP_SUBSCRIPTION_STATE) BELLE_SIP_PARSE(header_subscription_state) GET_SET_STRING(belle_sip_header_subscription_state,state); GET_SET_STRING_PARAM(belle_sip_header_subscription_state,reason); GET_SET_INT_PARAM2(belle_sip_header_subscription_state,retry-after,int,retry_after); GET_SET_INT_PARAM(belle_sip_header_subscription_state,expires,int) belle_sip_header_subscription_state_t* belle_sip_header_subscription_state_create (const char* subscription_state,int expires) { belle_sip_header_subscription_state_t* sub_state=belle_sip_header_subscription_state_new(); belle_sip_header_subscription_state_set_state(sub_state,subscription_state); belle_sip_header_subscription_state_set_expires(sub_state,expires); return sub_state; } #define HEADER_TO_LIKE_IMPL(name,header_name) \ struct _belle_sip_header_##name { \ belle_sip_header_address_t address; \ }; \ \ static void belle_sip_header_##name##_destroy(belle_sip_header_##name##_t * obj) { \ } \ void belle_sip_header_##name##_clone(belle_sip_header_##name##_t *contact, const belle_sip_header_##name##_t *orig){ }\ belle_sip_error_code belle_sip_header_##name##_marshal(belle_sip_header_##name##_t* name, char* buff, size_t buff_size, size_t *offset) {\ BELLE_SIP_FROM_LIKE_MARSHAL(name,FALSE)\ }\ BELLE_SIP_NEW_HEADER(header_##name,header_address,header_name)\ BELLE_SIP_PARSE(header_##name)\ belle_sip_header_##name##_t* belle_sip_header_##name##_create(const belle_sip_header_address_t* address) { \ belle_sip_header_##name##_t* header= belle_sip_header_##name##_new();\ _belle_sip_object_copy((belle_sip_object_t*)header,(belle_sip_object_t*)address);\ belle_sip_header_set_name(BELLE_SIP_HEADER(header),header_name); \ return header;\ } /************************** * Refer-To header object inherits from header_address **************************** */ HEADER_TO_LIKE_IMPL(refer_to,BELLE_SIP_REFER_TO) /************************** * Referred-By header object inherits from header_address **************************** */ HEADER_TO_LIKE_IMPL(referred_by,BELLE_SIP_REFERRED_BY) /************************** * Replaces state header object inherent from parameters **************************** */ struct _belle_sip_header_replaces { belle_sip_parameters_t parameters; char* call_id; }; static void belle_sip_header_replaces_destroy(belle_sip_header_replaces_t* replaces) { DESTROY_STRING(replaces,call_id); } static void belle_sip_header_replaces_clone(belle_sip_header_replaces_t* replaces, const belle_sip_header_replaces_t *orig ) { CLONE_STRING(belle_sip_header_replaces,call_id,replaces,orig) } belle_sip_error_code belle_sip_header_replaces_marshal(belle_sip_header_replaces_t* replaces, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(replaces), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s",replaces->call_id); if (error!=BELLE_SIP_OK) return error; error=belle_sip_parameters_marshal(BELLE_SIP_PARAMETERS(replaces), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_replaces,parameters,BELLE_SIP_REPLACES) BELLE_SIP_PARSE(header_replaces) GET_SET_STRING(belle_sip_header_replaces,call_id); GET_SET_STRING_PARAM2(belle_sip_header_replaces,to-tag,to_tag); GET_SET_STRING_PARAM2(belle_sip_header_replaces,from-tag,from_tag); static void escaped_to_ascii(const char*a,char*b,size_t n) { size_t index_a=0,index_b=0; while (a[index_a]!='\0'&& index_acall_id); if (error!=BELLE_SIP_OK) return NULL; error=belle_sip_parameters_marshal(BELLE_SIP_PARAMETERS(replaces), buff, buff_size, &offset); if (error!=BELLE_SIP_OK) return NULL; buff[offset]='\0'; return strdup(buff); } belle_sip_header_replaces_t* belle_sip_header_replaces_create(const char* call_id,const char* from_tag,const char* to_tag) { belle_sip_header_replaces_t* replaces=belle_sip_header_replaces_new(); belle_sip_header_replaces_set_call_id(replaces,call_id); belle_sip_header_replaces_set_from_tag(replaces,from_tag); belle_sip_header_replaces_set_to_tag(replaces,to_tag); return replaces; } struct belle_sip_header_date{ belle_sip_header_t base; char *date; }; static void belle_sip_header_date_destroy(belle_sip_header_date_t* obj) { DESTROY_STRING(obj,date); } static void belle_sip_header_date_clone(belle_sip_header_date_t* obj, const belle_sip_header_date_t *orig ) { CLONE_STRING(belle_sip_header_date,date,obj,orig); } belle_sip_error_code belle_sip_header_date_marshal(belle_sip_header_date_t* obj, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(obj), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s",obj->date); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_date,header,BELLE_SIP_DATE) BELLE_SIP_PARSE(header_date) BELLESIP_EXPORT belle_sip_header_date_t* belle_sip_header_date_create_from_time(const time_t *utc_time){ belle_sip_header_date_t *obj=belle_sip_header_date_new(); belle_sip_header_date_set_time(obj,utc_time); return obj; } static const char *days[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; static const char *months[]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; BELLESIP_EXPORT time_t belle_sip_header_date_get_time(belle_sip_header_date_t *obj){ struct tm ret ={0}; char tmp1[16] ={0}; char tmp2[16] ={0}; int i,j; time_t seconds; time_t adjust_timezone; /* time headers are in GMT as spec says */ sscanf(obj->date,"%3c,%d %16s %d %d:%d:%d",tmp1,&ret.tm_mday,tmp2, &ret.tm_year,&ret.tm_hour,&ret.tm_min,&ret.tm_sec); ret.tm_year-=1900; for(i=0;i<7;i++) { if(strcmp(tmp1,days[i])==0) { ret.tm_wday=i; for(j=0;j<12;j++) { if(strcmp(tmp2,months[j])==0) { ret.tm_mon=j; goto success; } } } } belle_sip_warning("Failed to parse date %s",obj->date); return (time_t)-1; success: ret.tm_isdst=0; #if TARGET_IPHONE_SIMULATOR /* 'timezone' is buggy on iOS simulator, use the timegm() function to convert to UTC timestamp and discard the adjust timezone value */ seconds = timegm(&ret); adjust_timezone = 0; #else seconds = mktime(&ret); adjust_timezone = timezone; #endif if (seconds==(time_t)-1){ belle_sip_error("mktime() failed: %s",strerror(errno)); return (time_t)-1; } return seconds-adjust_timezone; } BELLESIP_EXPORT void belle_sip_header_date_set_time(belle_sip_header_date_t *obj, const time_t *utc_time){ struct tm *ret; #ifndef WIN32 struct tm gmt; ret=gmtime_r(utc_time,&gmt); #else ret=gmtime(utc_time); #endif /*cannot use strftime because it is locale dependant*/ if (obj->date){ belle_sip_free(obj->date); } obj->date=belle_sip_strdup_printf("%s, %i %s %i %02i:%02i:%02i GMT", days[ret->tm_wday],ret->tm_mday,months[ret->tm_mon],1900+ret->tm_year,ret->tm_hour,ret->tm_min,ret->tm_sec); } GET_SET_STRING(belle_sip_header_date,date); /************************ * header_p_prefered_identity ***********************/ struct _belle_sip_header_p_preferred_identity { belle_sip_header_address_t address; }; void belle_sip_header_p_preferred_identity_destroy(belle_sip_header_p_preferred_identity_t* p_preferred_identity) { } void belle_sip_header_p_preferred_identity_clone(belle_sip_header_p_preferred_identity_t *p_preferred_identity, const belle_sip_header_p_preferred_identity_t *orig){ } belle_sip_error_code belle_sip_header_p_preferred_identity_marshal(belle_sip_header_p_preferred_identity_t* p_preferred_identity, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(p_preferred_identity), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_header_address_marshal(&p_preferred_identity->address, buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_p_preferred_identity,header_address,BELLE_SIP_P_PREFERRED_IDENTITY) BELLE_SIP_PARSE(header_p_preferred_identity) belle_sip_header_p_preferred_identity_t* belle_sip_header_p_preferred_identity_create (const belle_sip_header_address_t* p_preferred_identity) { belle_sip_header_p_preferred_identity_t* header = belle_sip_header_p_preferred_identity_new(); _belle_sip_object_copy(BELLE_SIP_OBJECT(header),BELLE_SIP_OBJECT(p_preferred_identity)); belle_sip_header_set_name(BELLE_SIP_HEADER(header),BELLE_SIP_P_PREFERRED_IDENTITY); /*restaure header name*/ return header; } /****************************** * Privacy header inherits from header * ******************************/ struct _belle_sip_header_privacy { belle_sip_header_t header; belle_sip_list_t* privacy; }; static void belle_sip_header_privacy_destroy(belle_sip_header_privacy_t* p) { belle_sip_header_privacy_set_privacy(p,NULL); } static void belle_sip_header_privacy_clone(belle_sip_header_privacy_t* p, const belle_sip_header_privacy_t* orig){ belle_sip_list_t* list=orig->privacy; for(;list!=NULL;list=list->next){ belle_sip_header_privacy_add_privacy(p,(const char *)list->data); } } belle_sip_error_code belle_sip_header_privacy_marshal(belle_sip_header_privacy_t* p, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=BELLE_SIP_OK; belle_sip_list_t* list = p->privacy; error=belle_sip_header_marshal(BELLE_SIP_HEADER(p), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; for(;list!=NULL;list=list->next){ error=belle_sip_snprintf(buff,buff_size,offset,list==p->privacy ? "%s" : ";%s",(const char *)list->data); if (error!=BELLE_SIP_OK) return error; } return error; } BELLE_SIP_NEW_HEADER(header_privacy,header,BELLE_SIP_PRIVACY) BELLE_SIP_PARSE(header_privacy) belle_sip_list_t* belle_sip_header_privacy_get_privacy(const belle_sip_header_privacy_t* p) { return p->privacy; } SET_ADD_STRING_LIST(belle_sip_header_privacy,privacy) belle_sip_header_privacy_t* belle_sip_header_privacy_create(const char* privacy) { belle_sip_header_privacy_t* privacy_header=belle_sip_header_privacy_new(); belle_sip_header_privacy_add_privacy(privacy_header,privacy); return privacy_header; } /************************** * Event header object inherent from parameters **************************** */ struct _belle_sip_header_event { belle_sip_parameters_t parameters; const char* package_name; }; static void belle_sip_header_event_destroy(belle_sip_header_event_t* event) { DESTROY_STRING(event,package_name); } static void belle_sip_header_event_clone(belle_sip_header_event_t* event, const belle_sip_header_event_t *orig ) { CLONE_STRING(belle_sip_header_event,package_name,event,orig) } belle_sip_error_code belle_sip_header_event_marshal(belle_sip_header_event_t* event, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_header_marshal(BELLE_SIP_HEADER(event), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s",event->package_name); if (error!=BELLE_SIP_OK) return error; error=belle_sip_parameters_marshal(BELLE_SIP_PARAMETERS(event), buff, buff_size, offset); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW_HEADER(header_event,parameters,BELLE_SIP_EVENT) BELLE_SIP_PARSE(header_event) GET_SET_STRING(belle_sip_header_event,package_name); GET_SET_STRING_PARAM(belle_sip_header_event,id); belle_sip_header_event_t* belle_sip_header_event_create (const char* package_name) { belle_sip_header_event_t* event=belle_sip_header_event_new(); belle_sip_header_event_set_package_name(event,package_name); return event; } belle-sip-1.4.1/src/belle_sip_internal.h000066400000000000000000001163511252242224000201650ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_utils_h #define belle_utils_h #include #include #include #include #include /* include all public headers*/ #include "belle-sip/belle-sip.h" #include "port.h" #ifdef HAVE_CONFIG_H #ifdef PACKAGE #undef PACKAGE #endif #ifdef PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #endif #ifdef PACKAGE_NAME #undef PACKAGE_NAME #endif #ifdef PACKAGE_STRING #undef PACKAGE_STRING #endif #ifdef PACKAGE_TARNAME #undef PACKAGE_TARNAME #endif #ifdef VERSION #undef VERSION #endif #ifdef PACKAGE_VERSION #undef PACKAGE_VERSION #endif #include "config.h" #else #ifndef PACKAGE_VERSION #error "PACKAGE_VERSION must be defined and equal to the VERSION file included in the belle-sip repository" #endif #endif /*etc*/ #define BELLE_SIP_INTERFACE_GET_METHODS(obj,interface) \ ((BELLE_SIP_INTERFACE_METHODS_TYPE(interface)*)belle_sip_object_get_interface_methods((belle_sip_object_t*)obj,BELLE_SIP_INTERFACE_ID(interface))) #define __BELLE_SIP_INVOKE_LISTENER_BEGIN(list,interface_name,method) \ if (list!=NULL) {\ belle_sip_list_t *__copy=belle_sip_list_copy_with_data((list), (void* (*)(void*))belle_sip_object_ref);\ const belle_sip_list_t *__elem=__copy;\ do{\ void *__method;\ interface_name *__obj=(interface_name*)__elem->data;\ __method=BELLE_SIP_INTERFACE_GET_METHODS(__obj,interface_name)->method;\ if (__method) BELLE_SIP_INTERFACE_GET_METHODS(__obj,interface_name)-> #define __BELLE_SIP_INVOKE_LISTENER_END \ __elem=__elem->next;\ }while(__elem!=NULL);\ belle_sip_list_free_with_data(__copy,belle_sip_object_unref);\ } #define BELLE_SIP_INVOKE_LISTENERS_VOID(list,interface_name,method) \ __BELLE_SIP_INVOKE_LISTENER_BEGIN(list,interface_name,method)\ method(__obj);\ __BELLE_SIP_INVOKE_LISTENER_END #define BELLE_SIP_INVOKE_LISTENERS_ARG(list,interface_name,method,arg) \ __BELLE_SIP_INVOKE_LISTENER_BEGIN(list,interface_name,method)\ method(__obj,arg);\ __BELLE_SIP_INVOKE_LISTENER_END #define BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2(list,interface_name,method,arg1,arg2) \ __BELLE_SIP_INVOKE_LISTENER_BEGIN(list,interface_name,method)\ method(__obj,arg1,arg2);\ __BELLE_SIP_INVOKE_LISTENER_END #define BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2_ARG3(list,interface_name,method,arg1,arg2,arg3) \ __BELLE_SIP_INVOKE_LISTENER_BEGIN(list,interface_name)\ method(__obj,arg1,arg2,arg3);\ __BELLE_SIP_INVOKE_LISTENER_END #define BELLE_SIP_INVOKE_LISTENER_ARG(listener,interface_name,method,arg) \ ((BELLE_SIP_INTERFACE_GET_METHODS((listener),interface_name)->method!=NULL) ? \ BELLE_SIP_INTERFACE_GET_METHODS((listener),interface_name)->method(listener,(arg)) : 0 ) typedef struct weak_ref{ struct weak_ref *next; belle_sip_object_destroy_notify_t notify; void *userpointer; }weak_ref_t; void *belle_sip_object_get_interface_methods(belle_sip_object_t *obj, belle_sip_interface_id_t ifid); /*used internally by unref()*/ void belle_sip_object_delete(void *obj); void belle_sip_object_pool_add(belle_sip_object_pool_t *pool, belle_sip_object_t *obj); void belle_sip_object_pool_remove(belle_sip_object_pool_t *pool, belle_sip_object_t *obj); #define belle_sip_object_init(obj) /*nothing*/ /*list of all vptrs (classes) used in belle-sip*/ BELLE_SIP_DECLARE_VPTR(belle_sip_stack_t); BELLE_SIP_DECLARE_VPTR(belle_sip_datagram_listening_point_t); BELLE_SIP_DECLARE_VPTR(belle_sip_provider_t); BELLE_SIP_DECLARE_VPTR(belle_sip_main_loop_t); BELLE_SIP_DECLARE_VPTR(belle_sip_source_t); BELLE_SIP_DECLARE_VPTR(belle_sip_dialog_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_address_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_contact_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_from_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_to_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_via_t); BELLE_SIP_DECLARE_VPTR(belle_sip_uri_t); BELLE_SIP_DECLARE_VPTR(belle_sip_message_t); BELLE_SIP_DECLARE_VPTR(belle_sip_request_t); BELLE_SIP_DECLARE_VPTR(belle_sip_response_t); BELLE_SIP_DECLARE_VPTR(belle_sip_parameters_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_call_id_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_cseq_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_content_type_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_route_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_record_route_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_user_agent_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_content_length_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_extension_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_authorization_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_www_authenticate_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_proxy_authenticate_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_proxy_authorization_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_max_forwards_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_expires_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_allow_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_attribute_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_bandwidth_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_connection_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_email_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_info_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_key_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_media_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_media_description_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_origin_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_phone_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_raw_attribute_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_repeate_time_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_rtcp_fb_attribute_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_rtcp_xr_attribute_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_session_description_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_session_name_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_time_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_time_description_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_uri_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_version_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_base_description_t); BELLE_SIP_DECLARE_VPTR(belle_sdp_mime_parameter_t); BELLE_SIP_DECLARE_VPTR(belle_sip_refresher_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_subscription_state_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_service_route_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_refer_to_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_referred_by_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_replaces_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_date_t); BELLE_SIP_DECLARE_VPTR(belle_sip_hop_t); BELLE_SIP_DECLARE_VPTR(belle_sip_object_pool_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_p_preferred_identity_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_privacy_t); BELLE_SIP_DECLARE_VPTR(belle_sip_certificates_chain_t); BELLE_SIP_DECLARE_VPTR(belle_sip_signing_key_t); BELLE_SIP_DECLARE_VPTR(belle_sip_dns_srv_t); BELLE_SIP_DECLARE_VPTR(belle_sip_dict_t) BELLE_SIP_DECLARE_VPTR(belle_http_provider_t); BELLE_SIP_DECLARE_VPTR(belle_http_channel_context_t); BELLE_SIP_DECLARE_VPTR(belle_http_request_t); BELLE_SIP_DECLARE_VPTR(belle_http_response_t); BELLE_SIP_DECLARE_VPTR(belle_generic_uri_t); BELLE_SIP_DECLARE_VPTR(belle_http_callbacks_t); BELLE_SIP_DECLARE_VPTR(belle_tls_verify_policy_t); BELLE_SIP_DECLARE_VPTR(belle_http_header_authorization_t); BELLE_SIP_DECLARE_VPTR(belle_sip_header_event_t); BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_resolver_context_t,belle_sip_source_t) void (*cancel)(belle_sip_resolver_context_t *); BELLE_SIP_DECLARE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_simple_resolver_context_t,belle_sip_resolver_context_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_combined_resolver_context_t,belle_sip_resolver_context_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_dual_resolver_context_t,belle_sip_resolver_context_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END typedef void (*belle_sip_source_remove_callback_t)(belle_sip_source_t *); struct belle_sip_source{ belle_sip_object_t base; belle_sip_list_t node; unsigned long id; belle_sip_fd_t fd; unsigned short events,revents; #ifdef WIN32 unsigned short armed_events; unsigned short pad; #endif int timeout; void *data; uint64_t expire_ms; int index; /* index in pollfd table */ belle_sip_source_func_t notify; belle_sip_source_remove_callback_t on_remove; belle_sip_socket_t sock; unsigned char cancelled; unsigned char expired; unsigned char oneshot; unsigned char notify_required; /*for testing purpose, use to ask for being scheduled*/ }; void belle_sip_socket_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, belle_sip_socket_t fd, unsigned int events, unsigned int timeout_value_ms); void belle_sip_fd_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, belle_sip_fd_t fd, unsigned int events, unsigned int timeout_value_ms); void belle_sip_source_uninit(belle_sip_source_t *s); void belle_sip_source_set_notify(belle_sip_source_t *s, belle_sip_source_func_t func); /* include private headers */ #include "channel.h" #define belle_sip_new(type) (type*)belle_sip_malloc(sizeof(type)) #define belle_sip_new0(type) (type*)belle_sip_malloc0(sizeof(type)) #define belle_list_next(elem) ((elem)->next) belle_sip_list_t *belle_sip_list_new(void *data); belle_sip_list_t* belle_sip_list_append_link(belle_sip_list_t* elem,belle_sip_list_t *new_elem); belle_sip_list_t *belle_sip_list_delete_custom(belle_sip_list_t *list, belle_sip_compare_func compare_func, const void *user_data); belle_sip_list_t* _belle_sip_list_remove(belle_sip_list_t* first, void *data, int warn_if_not_found); #define belle_sip_list_next(elem) ((elem)->next) /* dictionary */ struct belle_sip_dict { belle_sip_object_t base; }; #undef MIN #define MIN(a,b) ((a)>(b) ? (b) : (a)) #undef MAX #define MAX(a,b) ((a)>(b) ? (a) : (b)) BELLESIP_INTERNAL_EXPORT char * belle_sip_concat (const char *str, ...); /*parameters accessors*/ #define GET_SET_STRING(object_type,attribute) \ const char* object_type##_get_##attribute (const object_type##_t* obj) {\ return obj->attribute;\ }\ void object_type##_set_##attribute (object_type##_t* obj,const char* value) {\ const char* previous_value = obj->attribute; /*preserve if same value re-asigned*/ \ if (value) {\ obj->attribute=belle_sip_strdup(value); \ } else obj->attribute=NULL;\ if (previous_value != NULL) belle_sip_free((void*)previous_value);\ } /*#define GET_SET_STRING_PARAM_NULL_ALLOWED(object_type,attribute) \ GET_STRING_PARAM2(object_type,attribute,attribute) \ void object_type##_set_##func_name (object_type##_t* obj,const char* value) {\ belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(obj),#attribute,value);\ } */ #define GET_SET_STRING_PARAM(object_type,attribute) GET_SET_STRING_PARAM2(object_type,attribute,attribute) #define GET_SET_STRING_PARAM2(object_type,attribute,func_name) \ GET_STRING_PARAM2(object_type,attribute,func_name) \ void object_type##_set_##func_name (object_type##_t* obj,const char* value) {\ if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(obj),#attribute) && !value) {\ belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(obj),#attribute); \ } else \ belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(obj),#attribute,value);\ } #define GET_STRING_PARAM2(object_type,attribute,func_name) \ const char* object_type##_get_##func_name (const object_type##_t* obj) {\ const char* l_value = belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(obj),#attribute);\ if (l_value == NULL) { \ /*belle_sip_warning("cannot find parameters [%s]",#attribute);*/\ return NULL;\ }\ return l_value;\ } #define DESTROY_STRING(object,attribute) if (object->attribute) belle_sip_free((void*)object->attribute); #define CLONE_STRING_GENERIC(object_type_src,object_type_dest,attribute,dest,src) \ if ( object_type_src##_get_##attribute (src)) {\ object_type_dest##_set_##attribute(dest,object_type_src##_get_##attribute(src));\ } #define CLONE_STRING(object_type,attribute,dest,src) CLONE_STRING_GENERIC(object_type,object_type,attribute,dest,src) #define GET_SET_INT(object_type,attribute,type) GET_SET_INT_PRIVATE(object_type,attribute,type,) #define GET_SET_INT_PRIVATE(object_type,attribute,type,set_prefix) \ type object_type##_get_##attribute (const object_type##_t* obj) {\ return obj->attribute;\ }\ void set_prefix##object_type##_set_##attribute (object_type##_t* obj,type value) {\ obj->attribute=value;\ } #define GET_SET_INT_PARAM(object_type,attribute,type) GET_SET_INT_PARAM_PRIVATE(object_type,attribute,type,) #define GET_SET_INT_PARAM2(object_type,attribute,type,func_name) GET_SET_INT_PARAM_PRIVATE2(object_type,attribute,type,,func_name) #define ATO_(type,value) ATO_##type(value) #define ATO_int(value) atoi(value) #define ATO_float(value) (float)strtod(value,NULL) #define FORMAT_(type) FORMAT_##type #define FORMAT_int "%i" #define FORMAT_float "%f" #define GET_SET_INT_PARAM_PRIVATE(object_type,attribute,type,set_prefix) GET_SET_INT_PARAM_PRIVATE2(object_type,attribute,type,set_prefix,attribute) #define GET_SET_INT_PARAM_PRIVATE2(object_type,attribute,type,set_prefix,func_name) \ type object_type##_get_##func_name (const object_type##_t* obj) {\ const char* l_value = belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(obj),#attribute);\ if (l_value == NULL) { \ /*belle_sip_error("cannot find parameters [%s]",#attribute);*/\ return -1;\ }\ return ATO_(type,l_value);\ }\ void set_prefix##object_type##_set_##func_name (object_type##_t* obj,type value) {\ char l_str_value[16];\ if (value == -1) { \ belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(obj),#attribute);\ return;\ }\ snprintf(l_str_value,16,FORMAT_(type),value);\ belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(obj),#attribute,(const char*)l_str_value);\ } #define GET_SET_BOOL(object_type,attribute,getter) \ unsigned int object_type##_##getter##_##attribute (const object_type##_t* obj) {\ return obj->attribute;\ }\ void object_type##_set_##attribute (object_type##_t* obj,unsigned int value) {\ obj->attribute=value;\ } #define GET_SET_BOOL_PARAM2(object_type,attribute,getter,func_name) \ unsigned int object_type##_##getter##_##func_name (const object_type##_t* obj) {\ return belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(obj),#attribute);\ }\ void object_type##_set_##func_name (object_type##_t* obj,unsigned int value) {\ belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(obj),#attribute,NULL);\ } #ifdef HAVE_ANTLR_STRING_STREAM_NEW #define ANTLR_STREAM_NEW(object_type, value,length) \ antlr3StringStreamNew((pANTLR3_UINT8)value,ANTLR3_ENC_8BIT,(ANTLR3_UINT32)length,(pANTLR3_UINT8)#object_type) #else #define ANTLR_STREAM_NEW(object_type, value, length) \ antlr3NewAsciiStringCopyStream((pANTLR3_UINT8)value,(ANTLR3_UINT32)length,NULL) #endif /*HAVE_ANTLR_STRING_STREAM_NEW*/ #define BELLE_PARSE(parser_name, object_type_prefix, object_type) \ object_type_prefix##object_type##_t* object_type_prefix##object_type##_parse (const char* value) { \ pANTLR3_INPUT_STREAM input; \ pbelle_sip_messageLexer lex; \ pANTLR3_COMMON_TOKEN_STREAM tokens; \ p##parser_name parser; \ object_type_prefix##object_type##_t* l_parsed_object; \ input = ANTLR_STREAM_NEW(object_type,value,strlen(value));\ lex = belle_sip_messageLexerNew (input);\ tokens = antlr3CommonTokenStreamSourceNew (ANTLR3_SIZE_HINT, TOKENSOURCE(lex));\ parser = parser_name##New (tokens);\ l_parsed_object = parser->object_type(parser);\ parser ->free(parser);\ tokens ->free(tokens);\ lex ->free(lex);\ input ->close(input);\ if (l_parsed_object == NULL) belle_sip_error(#object_type" parser error for [%s]",value);\ return l_parsed_object;\ } #define BELLE_SIP_PARSE(object_type) BELLE_PARSE(belle_sip_messageParser,belle_sip_,object_type) #define BELLE_NEW(object_type,super_type) \ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(object_type##_t); \ BELLE_SIP_INSTANCIATE_VPTR( object_type##_t\ , super_type##_t\ , object_type##_destroy\ , object_type##_clone\ , object_type##_marshal, TRUE); \ object_type##_t* object_type##_new () { \ object_type##_t* l_object = belle_sip_object_new(object_type##_t);\ super_type##_init((super_type##_t*)l_object); \ object_type##_init((object_type##_t*) l_object); \ return l_object;\ } #define BELLE_SIP_NEW(object_type,super_type) BELLE_NEW (belle_sip_##object_type, belle_sip_##super_type) #define BELLE_SIP_NEW_HEADER(object_type,super_type,name) BELLE_SIP_NEW_HEADER_INIT(object_type,super_type,name,header) #define BELLE_SIP_NEW_HEADER_INIT(object_type,super_type,name,init_type) \ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_##object_type##_t); \ BELLE_SIP_INSTANCIATE_VPTR( belle_sip_##object_type##_t\ , belle_sip_##super_type##_t\ , belle_sip_##object_type##_destroy\ , belle_sip_##object_type##_clone\ , belle_sip_##object_type##_marshal, TRUE); \ belle_sip_##object_type##_t* belle_sip_##object_type##_new () { \ belle_sip_##object_type##_t* l_object = belle_sip_object_new(belle_sip_##object_type##_t);\ belle_sip_##super_type##_init((belle_sip_##super_type##_t*)l_object); \ belle_sip_##init_type##_init((belle_sip_##init_type##_t*) l_object); \ if (name) belle_sip_header_set_name(BELLE_SIP_HEADER(l_object),name);\ return l_object;\ } struct belle_sip_param_pair { int ref; char* name; char* value; } ; void belle_sip_param_pair_destroy(belle_sip_param_pair_t* pair) ; int belle_sip_param_pair_comp_func(const belle_sip_param_pair_t *a, const char*b) ; int belle_sip_param_pair_case_comp_func(const belle_sip_param_pair_t *a, const char*b) ; belle_sip_param_pair_t* belle_sip_param_pair_ref(belle_sip_param_pair_t* obj); void belle_sip_param_pair_unref(belle_sip_param_pair_t* obj); /*calss header*/ struct _belle_sip_header { belle_sip_object_t base; belle_sip_header_t* next; char *name; char *unparsed_value; }; void belle_sip_response_fill_for_dialog(belle_sip_response_t *obj, belle_sip_request_t *req); void belle_sip_util_copy_headers(belle_sip_message_t *orig, belle_sip_message_t *dest, const char*header, int multiple); void belle_sip_header_init(belle_sip_header_t* obj); /*class parameters*/ struct _belle_sip_parameters { belle_sip_header_t base; belle_sip_list_t* param_list; belle_sip_list_t* paramnames_list; }; void belle_sip_parameters_init(belle_sip_parameters_t *obj); /* * Listening points */ #include "listeningpoint_internal.h" struct belle_sip_hop{ belle_sip_object_t base; char *cname; char *host; char *transport; int port; }; /* belle_sip_stack_t */ struct belle_sip_stack{ belle_sip_object_t base; belle_sip_main_loop_t *ml; belle_sip_timer_config_t timer_config; int transport_timeout; int inactive_transport_timeout; int dns_timeout; int tx_delay; /*used to simulate network transmission delay, for tests*/ int send_error; /* used to simulate network error. if <0, channel_send will return this value*/ int resolver_tx_delay; /*used to simulate network transmission delay, for tests*/ int resolver_send_error; /* used to simulate network error*/ int dscp; char *dns_user_hosts_file; /* used to load additional hosts file for tests */ char *dns_resolv_conf; /*used to load custom resolv.conf, for tests*/ unsigned char dns_srv_enabled; }; belle_sip_hop_t* belle_sip_hop_new(const char* transport, const char *cname, const char* host,int port); belle_sip_hop_t* belle_sip_hop_new_from_uri(const belle_sip_uri_t *uri); belle_sip_hop_t* belle_sip_hop_new_from_generic_uri(const belle_generic_uri_t *uri); belle_sip_hop_t * belle_sip_stack_get_next_hop(belle_sip_stack_t *stack, belle_sip_request_t *req); /* belle_sip_provider_t */ struct belle_sip_provider{ belle_sip_object_t base; belle_sip_stack_t *stack; belle_sip_list_t *lps; /*listening points*/ belle_sip_list_t *listeners; belle_sip_list_t *internal_listeners; /*for transaction internaly managed by belle-sip. I.E by refreshers*/ belle_sip_list_t *client_transactions; belle_sip_list_t *server_transactions; belle_sip_list_t *dialogs; belle_sip_list_t *auth_contexts; unsigned char rport_enabled; /*0 if rport should not be set in via header*/ unsigned char nat_helper; unsigned char unconditional_answer_enabled; }; BELLESIP_INTERNAL_EXPORT belle_sip_provider_t *belle_sip_provider_new(belle_sip_stack_t *s, belle_sip_listening_point_t *lp); void belle_sip_provider_add_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t); belle_sip_client_transaction_t *belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov, belle_sip_response_t *resp); void belle_sip_provider_remove_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t); void belle_sip_provider_add_server_transaction(belle_sip_provider_t *prov, belle_sip_server_transaction_t *t); BELLESIP_INTERNAL_EXPORT belle_sip_server_transaction_t * belle_sip_provider_find_matching_server_transaction(belle_sip_provider_t *prov,belle_sip_request_t *req); void belle_sip_provider_remove_server_transaction(belle_sip_provider_t *prov, belle_sip_server_transaction_t *t); void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t); belle_sip_channel_t * belle_sip_provider_get_channel(belle_sip_provider_t *p, const belle_sip_hop_t *hop); void belle_sip_provider_add_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog); void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog); void belle_sip_provider_release_channel(belle_sip_provider_t *p, belle_sip_channel_t *chan); void belle_sip_provider_add_internal_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l, int prepend); void belle_sip_provider_remove_internal_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l); belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction_from_req(belle_sip_provider_t *prov, belle_sip_request_t *req); belle_sip_dialog_t *belle_sip_provider_find_dialog_from_message(belle_sip_provider_t *prov, belle_sip_message_t *msg, int as_uas); /*for testing purpose only:*/ BELLESIP_INTERNAL_EXPORT void belle_sip_provider_dispatch_message(belle_sip_provider_t *prov, belle_sip_message_t *msg); typedef struct listener_ctx{ belle_sip_listener_t *listener; void *data; }listener_ctx_t; #define BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,callback,event) \ BELLE_SIP_PROVIDER_INVOKE_LISTENERS((t)->is_internal?(t)->provider->internal_listeners:(t)->provider->listeners,callback,event) #define BELLE_SIP_PROVIDER_INVOKE_LISTENERS(listeners,callback,event) \ BELLE_SIP_INVOKE_LISTENERS_ARG((listeners),belle_sip_listener_t,callback,(event)) /* * http provider */ belle_http_provider_t *belle_http_provider_new(belle_sip_stack_t *s, const char *bind_ip); /* * SIP and http messages **/ #define BELLESIP_MULTIPART_BOUNDARY "---------------------------14737809831466499882746641449" void belle_sip_message_init(belle_sip_message_t *message); struct _belle_sip_message { belle_sip_object_t base; belle_sip_list_t* header_list; belle_sip_body_handler_t *body_handler; }; struct _belle_sip_request { belle_sip_message_t base; char* method; belle_sip_uri_t* uri; belle_generic_uri_t *absolute_uri; belle_sip_dialog_t *dialog;/*set if request was created by a dialog to avoid to search in dialog list*/ char *rfc2543_branch; /*computed 'branch' id in case we receive this request from an old RFC2543 stack*/ unsigned char dialog_queued; }; /** HTTP request**/ struct belle_http_request{ belle_sip_message_t base; belle_generic_uri_t *req_uri; char* method; belle_http_request_listener_t *listener; belle_generic_uri_t *orig_uri;/*original uri before removing host and user/passwd*/ belle_http_response_t *response; belle_sip_channel_t *channel; int auth_attempt_count; int background_task_id; int cancelled; }; void belle_http_request_set_listener(belle_http_request_t *req, belle_http_request_listener_t *l); void belle_http_request_set_channel(belle_http_request_t *req, belle_sip_channel_t *chan); void belle_http_request_set_response(belle_http_request_t *req, belle_http_response_t *resp); /* belle_sip_transaction_t */ struct belle_sip_transaction{ belle_sip_object_t base; belle_sip_provider_t *provider; /*the provider that created this transaction */ belle_sip_request_t *request; belle_sip_response_t *last_response; belle_sip_channel_t *channel; belle_sip_dialog_t *dialog; char *branch_id; belle_sip_transaction_state_t state; void *appdata; unsigned char is_internal; unsigned char timed_out; unsigned char sent_by_dialog_queue; }; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_transaction_t,belle_sip_object_t) void (*on_terminate)(belle_sip_transaction_t *obj); BELLE_SIP_DECLARE_CUSTOM_VPTR_END static BELLESIP_INLINE const belle_sip_timer_config_t * belle_sip_transaction_get_timer_config(belle_sip_transaction_t *obj){ return belle_sip_stack_get_timer_config(obj->provider->stack); } static BELLESIP_INLINE void belle_sip_transaction_start_timer(belle_sip_transaction_t *obj, belle_sip_source_t *timer){ belle_sip_main_loop_add_source(obj->provider->stack->ml,timer); } /** */ static BELLESIP_INLINE void belle_sip_transaction_stop_timer(belle_sip_transaction_t *obj, belle_sip_source_t *timer){ belle_sip_main_loop_remove_source(obj->provider->stack->ml,timer); } void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t); void belle_sip_transaction_set_dialog(belle_sip_transaction_t *t, belle_sip_dialog_t *dialog); void belle_sip_transaction_set_state(belle_sip_transaction_t *t, belle_sip_transaction_state_t state); /* * * * Client transaction * * */ struct belle_sip_client_transaction{ belle_sip_transaction_t base; belle_sip_uri_t* preset_route; /*use to store outbound proxy, will be helpful for refresher*/ belle_sip_hop_t* next_hop; /*use to send cancel request*/ }; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_client_transaction_t,belle_sip_transaction_t) void (*send_request)(belle_sip_client_transaction_t *); void (*on_response)(belle_sip_client_transaction_t *obj, belle_sip_response_t *resp); BELLE_SIP_DECLARE_CUSTOM_VPTR_END void belle_sip_client_transaction_init(belle_sip_client_transaction_t *obj, belle_sip_provider_t *prov, belle_sip_request_t *req); void belle_sip_client_transaction_add_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp); void belle_sip_client_transaction_notify_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp); struct belle_sip_ict{ belle_sip_client_transaction_t base; belle_sip_source_t *timer_A; belle_sip_source_t *timer_B; belle_sip_source_t *timer_D; belle_sip_source_t *timer_M; belle_sip_request_t *ack; }; typedef struct belle_sip_ict belle_sip_ict_t; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_ict_t,belle_sip_client_transaction_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END belle_sip_ict_t * belle_sip_ict_new(belle_sip_provider_t *prov, belle_sip_request_t *req); struct belle_sip_nict{ belle_sip_client_transaction_t base; belle_sip_source_t *timer_F; belle_sip_source_t *timer_E; belle_sip_source_t *timer_K; }; typedef struct belle_sip_nict belle_sip_nict_t; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_nict_t,belle_sip_client_transaction_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END belle_sip_nict_t * belle_sip_nict_new(belle_sip_provider_t *prov, belle_sip_request_t *req); /* * * * Server transaction * * */ struct belle_sip_server_transaction{ belle_sip_transaction_t base; char to_tag[8]; }; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_server_transaction_t,belle_sip_transaction_t) int (*send_new_response)(belle_sip_server_transaction_t *, belle_sip_response_t *resp); void (*on_request_retransmission)(belle_sip_server_transaction_t *obj); BELLE_SIP_DECLARE_CUSTOM_VPTR_END void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req); void belle_sip_server_transaction_on_request(belle_sip_server_transaction_t *t, belle_sip_request_t *req); struct belle_sip_ist{ belle_sip_server_transaction_t base; belle_sip_source_t *timer_G; belle_sip_source_t *timer_H; belle_sip_source_t *timer_I; belle_sip_source_t *timer_L; }; typedef struct belle_sip_ist belle_sip_ist_t; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_ist_t,belle_sip_server_transaction_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END belle_sip_ist_t * belle_sip_ist_new(belle_sip_provider_t *prov, belle_sip_request_t *req); /* returns 0 if the ack should be notified to TU, or -1 otherwise*/ int belle_sip_ist_process_ack(belle_sip_ist_t *obj, belle_sip_message_t *ack); struct belle_sip_nist{ belle_sip_server_transaction_t base; belle_sip_source_t *timer_J; }; typedef struct belle_sip_nist belle_sip_nist_t; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_nist_t,belle_sip_server_transaction_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END belle_sip_nist_t * belle_sip_nist_new(belle_sip_provider_t *prov, belle_sip_request_t *req); /* * Dialogs */ struct belle_sip_dialog{ belle_sip_object_t base; void *appdata; belle_sip_provider_t *provider; belle_sip_request_t *last_out_invite; belle_sip_request_t *last_out_ack; /*so that it can be retransmitted when needed*/ belle_sip_response_t *last_200Ok; belle_sip_source_t *timer_200Ok; belle_sip_source_t *timer_200Ok_end; belle_sip_dialog_state_t state; belle_sip_dialog_state_t previous_state; belle_sip_header_call_id_t *call_id; belle_sip_header_address_t *local_party; belle_sip_header_address_t *remote_party; belle_sip_list_t *route_set; belle_sip_header_address_t *remote_target; char *local_tag; char *remote_tag; unsigned int local_cseq; unsigned int remote_cseq; belle_sip_transaction_t* last_transaction; belle_sip_header_privacy_t* privacy; belle_sip_list_t *queued_ct;/* queued client transactions*/ unsigned char is_server; unsigned char is_secure; unsigned char terminate_on_bye; unsigned char needs_ack; }; belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t); belle_sip_dialog_t * belle_sip_provider_create_dialog_internal(belle_sip_provider_t *prov, belle_sip_transaction_t *t,unsigned int check_last_resp); int belle_sip_dialog_is_authorized_transaction(const belle_sip_dialog_t *dialog,const char* method) ; /*returns 1 if message belongs to the dialog, 0 otherwise */ int _belle_sip_dialog_match(belle_sip_dialog_t *obj, const char *call_id, const char *local_tag, const char *remote_tag); int belle_sip_dialog_match(belle_sip_dialog_t *obj, belle_sip_message_t *msg, int as_uas); int belle_sip_dialog_update(belle_sip_dialog_t *obj,belle_sip_transaction_t* transaction, int as_uas); void belle_sip_dialog_check_ack_sent(belle_sip_dialog_t*obj); int belle_sip_dialog_handle_ack(belle_sip_dialog_t *obj, belle_sip_request_t *ack); void belle_sip_dialog_queue_client_transaction(belle_sip_dialog_t *dialog, belle_sip_client_transaction_t *tr); /* belle_sip_response_t */ belle_sip_hop_t* belle_sip_response_get_return_hop(belle_sip_response_t *msg); /********************************************************* * SDP */ #define BELLE_SDP_PARSE(object_type) \ belle_sdp_##object_type##_t* belle_sdp_##object_type##_parse (const char* value) { \ pANTLR3_INPUT_STREAM input; \ pbelle_sdpLexer lex; \ pANTLR3_COMMON_TOKEN_STREAM tokens; \ pbelle_sdpParser parser; \ belle_sdp_##object_type##_t* l_parsed_object; \ input = ANTLR_STREAM_NEW(object_type, value,strlen(value));\ lex = belle_sdpLexerNew (input);\ tokens = antlr3CommonTokenStreamSourceNew (ANTLR3_SIZE_HINT, TOKENSOURCE(lex));\ parser = belle_sdpParserNew (tokens);\ l_parsed_object = parser->object_type(parser).ret;\ parser ->free(parser);\ tokens ->free(tokens);\ lex ->free(lex);\ input ->close(input);\ if (l_parsed_object == NULL) belle_sip_error(#object_type" parser error for [%s]",value);\ return l_parsed_object;\ } #define BELLE_SDP_NEW(object_type,super_type) \ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sdp_##object_type##_t); \ BELLE_SIP_INSTANCIATE_VPTR( belle_sdp_##object_type##_t\ , super_type##_t\ , belle_sdp_##object_type##_destroy\ , belle_sdp_##object_type##_clone\ , belle_sdp_##object_type##_marshal, TRUE); \ belle_sdp_##object_type##_t* belle_sdp_##object_type##_new () { \ belle_sdp_##object_type##_t* l_object = belle_sip_object_new(belle_sdp_##object_type##_t);\ super_type##_init((super_type##_t*)l_object); \ return l_object;\ } #define BELLE_SDP_NEW_WITH_CTR(object_type,super_type) \ BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sdp_##object_type##_t); \ BELLE_SIP_INSTANCIATE_VPTR( belle_sdp_##object_type##_t\ , super_type##_t\ , belle_sdp_##object_type##_destroy\ , belle_sdp_##object_type##_clone\ , belle_sdp_##object_type##_marshal,TRUE); \ belle_sdp_##object_type##_t* belle_sdp_##object_type##_new () { \ belle_sdp_##object_type##_t* l_object = belle_sip_object_new(belle_sdp_##object_type##_t);\ super_type##_init((super_type##_t*)l_object); \ belle_sdp_##object_type##_init(l_object); \ return l_object;\ } struct belle_sip_dialog_terminated_event{ belle_sip_provider_t *source; belle_sip_dialog_t *dialog; }; struct belle_sip_io_error_event{ belle_sip_object_t *source; /*the object impacted by this error*/ const char *transport; const char *host; unsigned int port; }; struct belle_sip_request_event{ belle_sip_object_t *source; belle_sip_server_transaction_t *server_transaction; belle_sip_dialog_t *dialog; belle_sip_request_t *request; }; struct belle_sip_response_event{ belle_sip_object_t *source; belle_sip_client_transaction_t *client_transaction; belle_sip_dialog_t *dialog; belle_sip_response_t *response; }; struct belle_sip_timeout_event{ belle_sip_object_t *source; belle_sip_transaction_t *transaction; int is_server_transaction; }; struct belle_sip_transaction_terminated_event{ belle_sip_provider_t *source; belle_sip_transaction_t *transaction; int is_server_transaction; }; struct belle_sip_auth_event { belle_sip_object_t *source; belle_sip_auth_mode_t mode; char* username; char* userid; char* realm; char* passwd; char* ha1; char* domain; char* distinguished_name; belle_sip_certificates_chain_t * cert; belle_sip_signing_key_t* key; }; belle_sip_auth_event_t* belle_sip_auth_event_create(belle_sip_object_t *source, const char* realm,const belle_sip_uri_t * from_uri); void belle_sip_auth_event_set_distinguished_name(belle_sip_auth_event_t* event,const char* value); /* * refresher * */ belle_sip_refresher_t* belle_sip_refresher_new(belle_sip_client_transaction_t* transaction); /* * returns a char, even if entry is escaped*/ int belle_sip_get_char (const char*a,int n,char*out); /*return an escaped string*/ BELLESIP_INTERNAL_EXPORT char* belle_sip_uri_to_escaped_username(const char* buff) ; BELLESIP_INTERNAL_EXPORT char* belle_sip_uri_to_escaped_userpasswd(const char* buff) ; BELLESIP_INTERNAL_EXPORT char* belle_sip_uri_to_escaped_parameter(const char* buff) ; BELLESIP_INTERNAL_EXPORT char* belle_sip_uri_to_escaped_header(const char* buff) ; /*(uri RFC 2396)*/ BELLESIP_INTERNAL_EXPORT char* belle_generic_uri_to_escaped_query(const char* buff); BELLESIP_INTERNAL_EXPORT char* belle_generic_uri_to_escaped_path(const char* buff); #define BELLE_SIP_SOCKET_TIMEOUT 30000 #define BELLE_SIP_BRANCH_ID_LENGTH 10 /*Shall not be less than 32bit */ #define BELLE_SIP_TAG_LENGTH 6 #define BELLE_SIP_MAX_TO_STRING_SIZE 2048 void belle_sip_header_contact_set_unknown(belle_sip_header_contact_t *a, int value); void belle_sip_request_set_dialog(belle_sip_request_t *req, belle_sip_dialog_t *dialog); void belle_sip_request_set_rfc2543_branch(belle_sip_request_t *req, const char *rfc2543branch); void belle_sip_dialog_update_request(belle_sip_dialog_t *dialog, belle_sip_request_t *req); belle_sip_error_code belle_sip_headers_marshal(belle_sip_message_t *message, char* buff, size_t buff_size, size_t *offset); #define SET_OBJECT_PROPERTY(obj,property_name,new_value) \ if (new_value) belle_sip_object_ref(new_value); \ if (obj->property_name){ \ belle_sip_object_unref(obj->property_name); \ }\ obj->property_name=new_value; #include "parserutils.h" /****************************** * * private Extension header inherit from header * ******************************/ typedef struct _belle_sip_header_extension belle_sip_header_extension_t; belle_sip_header_extension_t* belle_sip_header_extension_new(); belle_sip_header_extension_t* belle_sip_header_extension_parse (const char* extension) ; belle_sip_header_extension_t* belle_sip_header_extension_create (const char* name,const char* value); BELLESIP_INTERNAL_EXPORT const char* belle_sip_header_extension_get_value(const belle_sip_header_extension_t* extension); void belle_sip_header_extension_set_value(belle_sip_header_extension_t* extension,const char* value); #define BELLE_SIP_HEADER_EXTENSION(t) BELLE_SIP_CAST(t,belle_sip_header_extension_t) /**************** * belle_sip_body_handler_t object ***************/ BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_body_handler_t,belle_sip_object_t) void (*chunk_recv)(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, size_t offset, const uint8_t *buf, size_t size); int (*chunk_send)(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, size_t offset, uint8_t *buf, size_t * size); BELLE_SIP_DECLARE_CUSTOM_VPTR_END void belle_sip_body_handler_begin_transfer(belle_sip_body_handler_t *obj); void belle_sip_body_handler_recv_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, const uint8_t *buf, size_t size); int belle_sip_body_handler_send_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, uint8_t *buf, size_t *size); void belle_sip_body_handler_end_transfer(belle_sip_body_handler_t *obj); BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_memory_body_handler_t,belle_sip_body_handler_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_user_body_handler_t,belle_sip_body_handler_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_file_body_handler_t,belle_sip_body_handler_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_multipart_body_handler_t,belle_sip_body_handler_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END /** * file manipulation */ /** * Parse a directory and return all files in it. * * @param[in] path The directory to be parsed * @param[in] file_type if not NULL return only the file with the given extension, must include the '.', ex:".pem" * @return a belle_sip list containing all found file or NULL if no file were found or directory doesn't exist. List must be destroyed using belle_sip_list_free_with_data(, belle_sip_free) */ belle_sip_list_t *belle_sip_parse_directory(const char *path, const char *file_type); /** * create a directory if it doesn't already exists * * @param[in] path The directory to be created * @return 0 in case of succes, -1 otherwise, note it returns -1 if the directory already exists */ int belle_sip_mkdir(const char *path); #endif belle-sip-1.4.1/src/belle_sip_loop.c000066400000000000000000000347521252242224000173210ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/belle-sip.h" #include "belle_sip_internal.h" #ifndef WIN32 #include #include typedef struct pollfd belle_sip_pollfd_t; static int belle_sip_poll(belle_sip_pollfd_t *pfd, int count, int duration){ int err; err=poll(pfd,count,duration); if (err==-1 && errno!=EINTR) belle_sip_error("poll() error: %s",strerror(errno)); return err; } /* Poll() based implementation of event loop. */ static int belle_sip_event_to_poll(unsigned int events){ int ret=0; if (events & BELLE_SIP_EVENT_READ) ret|=POLLIN; if (events & BELLE_SIP_EVENT_WRITE) ret|=POLLOUT; if (events & BELLE_SIP_EVENT_ERROR) ret|=POLLERR; return ret; } static unsigned int belle_sip_poll_to_event(belle_sip_pollfd_t * pfd){ unsigned int ret=0; short events=pfd->revents; if (events & POLLIN) ret|=BELLE_SIP_EVENT_READ; if (events & POLLOUT) ret|=BELLE_SIP_EVENT_WRITE; if (events & POLLERR) ret|=BELLE_SIP_EVENT_ERROR; return ret; } static void belle_sip_source_to_poll(belle_sip_source_t *s, belle_sip_pollfd_t *pfd, int i){ pfd[i].fd=s->fd; pfd[i].events=belle_sip_event_to_poll(s->events); pfd[i].revents=0; s->index=i; } static unsigned int belle_sip_source_get_revents(belle_sip_source_t *s,belle_sip_pollfd_t *pfd){ return belle_sip_poll_to_event(&pfd[s->index]); } #else #include typedef HANDLE belle_sip_pollfd_t; static void belle_sip_source_to_poll(belle_sip_source_t *s, belle_sip_pollfd_t *pfd,int i){ s->index=i; pfd[i]=s->fd; /*special treatments for windows sockets*/ if (s->sock!=(belle_sip_socket_t)-1){ int err; long events=0; if (s->events & BELLE_SIP_EVENT_READ) events|=FD_READ|FD_ACCEPT; if (s->events & BELLE_SIP_EVENT_WRITE) events|=FD_WRITE|FD_CONNECT; if (events!=s->armed_events){ s->armed_events=events; err=WSAEventSelect(s->sock,s->fd,events); if (err!=0) belle_sip_error("WSAEventSelect() failed: %s",belle_sip_get_socket_error_string()); } } } static unsigned int belle_sip_source_get_revents(belle_sip_source_t *s,belle_sip_pollfd_t *pfd){ WSANETWORKEVENTS revents={0}; int err; unsigned int ret=0; if (WaitForSingleObjectEx(s->fd,0,FALSE)==WAIT_OBJECT_0){ if (s->sock!=(belle_sip_socket_t)-1){ /*special treatments for windows sockets*/ err=WSAEnumNetworkEvents(s->sock,s->fd,&revents); if (err!=0){ belle_sip_error("WSAEnumNetworkEvents() failed: %s socket=%x",belle_sip_get_socket_error_string(),(unsigned int)s->sock); return 0; } if (revents.lNetworkEvents & FD_READ || revents.lNetworkEvents & FD_ACCEPT){ ret|=BELLE_SIP_EVENT_READ; } if (revents.lNetworkEvents & FD_WRITE || revents.lNetworkEvents & FD_CONNECT){ ret|=BELLE_SIP_EVENT_WRITE; } s->armed_events=0; }else{ ret=BELLE_SIP_EVENT_READ; ResetEvent(s->fd); } } return ret; } static int belle_sip_poll(belle_sip_pollfd_t *pfd, int count, int duration){ DWORD ret; if (count == 0) { belle_sip_sleep(duration); return 0; } ret=WaitForMultipleObjectsEx(count,pfd,FALSE,duration,FALSE); if (ret==WAIT_FAILED){ belle_sip_error("WaitForMultipleObjectsEx() failed."); return -1; } if (ret==WAIT_TIMEOUT){ return 0; } return ret-WAIT_OBJECT_0; } #endif static void belle_sip_source_destroy(belle_sip_source_t *obj){ if (obj->node.next || obj->node.prev){ belle_sip_fatal("Destroying source currently used in main loop !"); } belle_sip_source_uninit(obj); } static void belle_sip_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, belle_sip_fd_t fd, unsigned int events, unsigned int timeout_value_ms){ static unsigned long global_id=1; s->node.data=s; if (s->id==0) s->id=global_id++; s->fd=fd; s->events=events; s->timeout=timeout_value_ms; s->data=data; s->notify=func; s->sock=(belle_sip_socket_t)-1; } void belle_sip_source_uninit(belle_sip_source_t *obj){ #ifdef WIN32 if (obj->sock!=(belle_sip_socket_t)-1){ WSACloseEvent(obj->fd); obj->fd=(WSAEVENT)-1; } #endif obj->fd=(belle_sip_fd_t)-1; obj->sock=(belle_sip_socket_t)-1; } void belle_sip_source_set_notify(belle_sip_source_t *s, belle_sip_source_func_t func) { s->notify = func; } void belle_sip_socket_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, belle_sip_socket_t sock, unsigned int events, unsigned int timeout_value_ms){ #ifdef WIN32 /*on windows, the fd to poll is not the socket */ belle_sip_fd_t fd=(belle_sip_fd_t)-1; if (sock!=(belle_sip_socket_t)-1) fd=WSACreateEvent(); else fd=(WSAEVENT)-1; belle_sip_source_init(s,func,data,fd,events,timeout_value_ms); #else belle_sip_source_init(s,func,data,sock,events,timeout_value_ms); #endif s->sock=sock; if (sock!=(belle_sip_socket_t)-1) belle_sip_socket_set_nonblocking(sock); } void belle_sip_fd_source_init(belle_sip_source_t *s, belle_sip_source_func_t func, void *data, belle_sip_fd_t fd, unsigned int events, unsigned int timeout_value_ms){ belle_sip_source_init(s,func,data,fd,events,timeout_value_ms); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_source_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_source_t,belle_sip_object_t,belle_sip_source_destroy,NULL,NULL,FALSE); belle_sip_source_t * belle_sip_socket_source_new(belle_sip_source_func_t func, void *data, belle_sip_socket_t sock, unsigned int events, unsigned int timeout_value_ms){ belle_sip_source_t *s=belle_sip_object_new(belle_sip_source_t); belle_sip_socket_source_init(s,func,data,sock,events,timeout_value_ms); return s; } belle_sip_source_t * belle_sip_fd_source_new(belle_sip_source_func_t func, void *data, belle_sip_fd_t fd, unsigned int events, unsigned int timeout_value_ms){ belle_sip_source_t *s=belle_sip_object_new(belle_sip_source_t); belle_sip_fd_source_init(s,func,data,fd,events,timeout_value_ms); return s; } belle_sip_source_t * belle_sip_timeout_source_new(belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){ return belle_sip_socket_source_new(func,data,(belle_sip_socket_t)-1,0,timeout_value_ms); } unsigned long belle_sip_source_get_id(belle_sip_source_t *s){ return s->id; } int belle_sip_source_set_events(belle_sip_source_t* source, int event_mask) { source->events = event_mask; return 0; } belle_sip_socket_t belle_sip_source_get_socket(const belle_sip_source_t* source) { return source->sock; } struct belle_sip_main_loop{ belle_sip_object_t base; belle_sip_list_t *sources; belle_sip_object_pool_t *pool; int nsources; int run; int in_iterate; }; void belle_sip_main_loop_remove_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source){ if (!source->node.next && !source->node.prev && &source->node!=ml->sources) return; /*nothing to do*/ source->cancelled=TRUE; ml->sources=belle_sip_list_remove_link(ml->sources,&source->node); ml->nsources--; if (source->on_remove) source->on_remove(source); belle_sip_object_unref(source); } static void belle_sip_main_loop_destroy(belle_sip_main_loop_t *ml){ while (ml->sources){ belle_sip_main_loop_remove_source(ml,(belle_sip_source_t*)ml->sources->data); } if (belle_sip_object_pool_cleanable(ml->pool)){ belle_sip_object_unref(ml->pool); } } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_main_loop_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_main_loop_t,belle_sip_object_t,belle_sip_main_loop_destroy,NULL,NULL,FALSE); belle_sip_main_loop_t *belle_sip_main_loop_new(void){ belle_sip_main_loop_t*m=belle_sip_object_new(belle_sip_main_loop_t); m->pool=belle_sip_object_pool_push(); return m; } void belle_sip_main_loop_add_source(belle_sip_main_loop_t *ml, belle_sip_source_t *source){ if (source->node.next || source->node.prev){ belle_sip_fatal("Source is already linked somewhere else."); return; } if (source->node.data!=source){ belle_sip_fatal("Insane source passed to belle_sip_main_loop_add_source() !"); return; } belle_sip_object_ref(source); if (source->timeout>=0){ source->expire_ms=belle_sip_time_ms()+source->timeout; } source->cancelled=FALSE; ml->sources=belle_sip_list_append_link(ml->sources,&source->node); ml->nsources++; } belle_sip_source_t* belle_sip_main_loop_create_timeout(belle_sip_main_loop_t *ml , belle_sip_source_func_t func , void *data , unsigned int timeout_value_ms ,const char* timer_name) { belle_sip_source_t * s=belle_sip_timeout_source_new(func,data,timeout_value_ms); belle_sip_object_set_name((belle_sip_object_t*)s,timer_name); belle_sip_main_loop_add_source(ml,s); return s; } unsigned long belle_sip_main_loop_add_timeout(belle_sip_main_loop_t *ml, belle_sip_source_func_t func, void *data, unsigned int timeout_value_ms){ belle_sip_source_t * s=belle_sip_main_loop_create_timeout(ml,func,data,timeout_value_ms,"Timer"); belle_sip_object_unref(s); return s->id; } void belle_sip_main_loop_do_later(belle_sip_main_loop_t *ml, belle_sip_callback_t func, void *data){ belle_sip_source_t * s=belle_sip_main_loop_create_timeout(ml,(belle_sip_source_func_t)func,data,0,"defered task"); s->oneshot=TRUE; belle_sip_object_unref(s); } void belle_sip_source_set_timeout(belle_sip_source_t *s, unsigned int value_ms){ if (!s->expired){ s->expire_ms=belle_sip_time_ms()+value_ms; } s->timeout=value_ms; } unsigned int belle_sip_source_get_timeout(const belle_sip_source_t *s){ return s->timeout; } static int match_source_id(const void *s, const void *pid){ if ( ((belle_sip_source_t*)s)->id==(unsigned long)pid){ return 0; } return -1; } belle_sip_source_t *belle_sip_main_loop_find_source(belle_sip_main_loop_t *ml, unsigned long id){ belle_sip_list_t *elem=belle_sip_list_find_custom(ml->sources,match_source_id,(const void*)id); if (elem!=NULL){ return (belle_sip_source_t*)elem->data; } return NULL; } void belle_sip_main_loop_cancel_source(belle_sip_main_loop_t *ml, unsigned long id){ belle_sip_source_t *s=belle_sip_main_loop_find_source(ml,id); if (s) s->cancelled=TRUE; } void belle_sip_main_loop_iterate(belle_sip_main_loop_t *ml){ size_t pfd_size = ml->nsources * sizeof(belle_sip_pollfd_t); belle_sip_pollfd_t *pfd=(belle_sip_pollfd_t*)belle_sip_malloc0(pfd_size); int i=0; belle_sip_source_t *s; belle_sip_list_t *elem,*next; uint64_t min_time_ms=(uint64_t)-1; int duration=-1; int ret; uint64_t cur; belle_sip_list_t *to_be_notified=NULL; int can_clean=belle_sip_object_pool_cleanable(ml->pool); /*iterate might not be called by the thread that created the main loop*/ belle_sip_object_pool_t *tmp_pool=NULL; if (ml->in_iterate){ belle_sip_warning("belle_sip_main_loop_iterate([%p]): reentrancy detected, doing nothing.",ml); return; } ml->in_iterate=TRUE; if (!can_clean){ /*Push a temporary pool for the time of the iterate loop*/ tmp_pool=belle_sip_object_pool_push(); } /*Step 1: prepare the pollfd table and get the next timeout value */ for(elem=ml->sources;elem!=NULL;elem=next){ next=elem->next; s=(belle_sip_source_t*)elem->data; if (!s->cancelled){ if (s->fd!=(belle_sip_fd_t)-1){ belle_sip_source_to_poll(s,pfd,i); ++i; } if (s->timeout>=0){ if (min_time_ms>s->expire_ms){ min_time_ms=s->expire_ms; } } } } if (min_time_ms!=(uint64_t)-1 ){ int64_t diff; /* compute the amount of time to wait for shortest timeout*/ cur=belle_sip_time_ms(); diff=min_time_ms-cur; if (diff>0) duration=(int)diff; else duration=0; } /* do the poll */ ret=belle_sip_poll(pfd,i,duration); if (ret==-1){ goto end; } /* Step 2: examine poll results and determine the list of source to be notified */ cur=belle_sip_time_ms(); for(elem=ml->sources;elem!=NULL;elem=elem->next){ unsigned revents=0; s=(belle_sip_source_t*)elem->data; if (!s->cancelled){ if (s->fd!=(belle_sip_fd_t)-1){ if (s->notify_required) { /*for testing purpose to force channel to read*/ revents=BELLE_SIP_EVENT_READ; s->notify_required=0; /*reset*/ } else { revents=belle_sip_source_get_revents(s,pfd); } s->revents=revents; } if (revents!=0 || (s->timeout>=0 && cur>=s->expire_ms)){ to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s)); s->expired=TRUE; if (s->revents==0) s->revents=BELLE_SIP_EVENT_TIMEOUT; } }else to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s)); } /* Step 3: notify those to be notified */ for(elem=to_be_notified;elem!=NULL;){ s=(belle_sip_source_t*)elem->data; next=elem->next; if (!s->cancelled){ char *objdesc=belle_sip_object_to_string((belle_sip_object_t*)s); if (s->timeout>0) { /*to avoid too many traces*/ belle_sip_debug("source %s notified revents=%u, timeout=%i",objdesc,revents,s->timeout); } belle_sip_free(objdesc); ret=s->notify(s->data,s->revents); if (ret==BELLE_SIP_STOP || s->oneshot){ /*this source needs to be removed*/ belle_sip_main_loop_remove_source(ml,s); }else if (s->revents==BELLE_SIP_EVENT_TIMEOUT){ /*timeout needs to be started again */ if (ret==BELLE_SIP_CONTINUE_WITHOUT_CATCHUP){ s->expire_ms=cur+s->timeout; }else{ s->expire_ms+=s->timeout; } s->expired=FALSE; } }else belle_sip_main_loop_remove_source(ml,s); belle_sip_object_unref(s); belle_sip_free(elem); /*free just the element*/ elem=next; } if (can_clean) belle_sip_object_pool_clean(ml->pool); else if (tmp_pool) belle_sip_object_unref(tmp_pool); end: belle_sip_free(pfd); ml->in_iterate=FALSE; } void belle_sip_main_loop_run(belle_sip_main_loop_t *ml){ ml->run=1; while(ml->run){ belle_sip_main_loop_iterate(ml); if (ml->in_iterate) break; } } int belle_sip_main_loop_quit(belle_sip_main_loop_t *ml){ ml->run=0; return BELLE_SIP_STOP; } void belle_sip_main_loop_sleep(belle_sip_main_loop_t *ml, int milliseconds){ belle_sip_source_t * s=belle_sip_main_loop_create_timeout(ml,(belle_sip_source_func_t)belle_sip_main_loop_quit,ml,milliseconds,"Main loop sleep timer"); belle_sip_main_loop_run(ml); belle_sip_main_loop_remove_source(ml,s); belle_sip_object_unref(s); } belle-sip-1.4.1/src/belle_sip_object.c000066400000000000000000000616101252242224000176070ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" static void _belle_sip_object_pool_remove_from_stack(belle_sip_object_pool_t *pool); static int _belle_sip_object_marshal_check_enabled = FALSE; static int has_type(belle_sip_object_t *obj, belle_sip_type_id_t id){ belle_sip_object_vptr_t *vptr=obj->vptr; while(vptr!=NULL){ if (vptr->id==id) return TRUE; vptr=vptr->get_parent(); } return FALSE; } int _belle_sip_object_is_instance_of(belle_sip_object_t * obj,belle_sip_type_id_t id) { return has_type(obj,id); } void belle_sip_object_enable_marshal_check(int enable) { _belle_sip_object_marshal_check_enabled = (enable) ? TRUE : FALSE; } static belle_sip_list_t *all_objects=NULL; static int belle_sip_leak_detector_enabled=FALSE; static int belle_sip_leak_detector_inhibited=FALSE; static void add_new_object(belle_sip_object_t *obj){ if (belle_sip_leak_detector_enabled && !belle_sip_leak_detector_inhibited){ all_objects=belle_sip_list_prepend(all_objects,obj); } } static void remove_free_object(belle_sip_object_t *obj){ if (belle_sip_leak_detector_enabled && !belle_sip_leak_detector_inhibited){ all_objects=_belle_sip_list_remove(all_objects,obj,FALSE); /*it may fail if the leak detector was inhibitted at the time the object was created*/ } } void belle_sip_object_inhibit_leak_detector(int yes){ belle_sip_leak_detector_inhibited=yes ? TRUE : FALSE; } void belle_sip_object_enable_leak_detector(int enable){ belle_sip_leak_detector_enabled=enable; } int belle_sip_object_get_object_count(void){ return belle_sip_list_size(all_objects); } void belle_sip_object_dump_active_objects(void){ belle_sip_list_t *elem; if (all_objects){ belle_sip_message("List of leaked objects:"); for(elem=all_objects;elem!=NULL;elem=elem->next){ belle_sip_object_t *obj=(belle_sip_object_t*)elem->data; char* content= belle_sip_object_to_string(obj); belle_sip_message("%s(%p) ref=%i, content [%10s...]",obj->vptr->type_name,obj,obj->ref,content); belle_sip_free(content); } }else belle_sip_message("No objects leaked."); } belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr_t *vptr){ belle_sip_object_t *obj=(belle_sip_object_t *)belle_sip_malloc0(vptr->size); obj->ref=vptr->initially_unowned ? 0 : 1; obj->vptr=vptr; if (obj->ref==0){ belle_sip_object_pool_t *pool=belle_sip_object_pool_get_current(); if (pool) belle_sip_object_pool_add(pool,obj); } add_new_object(obj); return obj; } int belle_sip_object_is_initially_unowned(const belle_sip_object_t *obj){ return obj->vptr->initially_unowned; } belle_sip_object_t * belle_sip_object_ref(void *obj){ belle_sip_object_t *o=BELLE_SIP_OBJECT(obj); if (o->ref==0 && o->pool){ belle_sip_object_pool_remove(o->pool,obj); } o->ref++; return obj; } void belle_sip_object_unref(void *ptr){ belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr); if (obj->ref==-1) { belle_sip_error("Object [%p] freed twice !",obj); if (obj->vptr && obj->vptr->type_name) belle_sip_error("Object type might be [%s]",obj->vptr->type_name); if (obj->name) belle_sip_error("Object name might be [%s]",obj->name); belle_sip_fatal("Fatal object error encountered, aborting."); return; } if (obj->ref==0 && obj->pool){ belle_sip_object_pool_remove(obj->pool,obj); obj->ref=-1; belle_sip_object_delete(obj); return; } obj->ref--; if (obj->ref==0){ obj->ref=-1; belle_sip_object_delete(obj); } } static weak_ref_t *weak_ref_new(belle_sip_object_destroy_notify_t destroy_notify, void *userpointer){ weak_ref_t *r=belle_sip_new(weak_ref_t); r->next=NULL; r->notify=destroy_notify; r->userpointer=userpointer; return r; } belle_sip_object_t *belle_sip_object_weak_ref(void *obj, belle_sip_object_destroy_notify_t destroy_notify, void *userpointer){ belle_sip_object_t *o=BELLE_SIP_OBJECT(obj); weak_ref_t *old=o->weak_refs; o->weak_refs=weak_ref_new(destroy_notify,userpointer); o->weak_refs->next=old; return o; } void belle_sip_object_weak_unref(void *obj, belle_sip_object_destroy_notify_t destroy_notify, void *userpointer){ belle_sip_object_t *o=BELLE_SIP_OBJECT(obj); weak_ref_t *ref,*prevref=NULL,*next=NULL; int found=FALSE; if (o->ref==-1) return; /*too late and avoid recursions*/ for(ref=o->weak_refs;ref!=NULL;ref=next){ next=ref->next; if (ref->notify==destroy_notify && ref->userpointer==userpointer){ if (prevref==NULL) o->weak_refs=next; else prevref->next=next; belle_sip_free(ref); found=TRUE; /*do not break or return, someone could have put twice the same weak ref on the same object*/ }else{ prevref=ref; } } if (!found) belle_sip_fatal("Could not find weak_ref, you're a looser."); } static void belle_sip_object_loose_weak_refs(belle_sip_object_t *obj){ weak_ref_t *ref,*next; for(ref=obj->weak_refs;ref!=NULL;ref=next){ next=ref->next; ref->notify(ref->userpointer,obj); belle_sip_free(ref); } obj->weak_refs=NULL; } static void _belle_sip_object_uninit(belle_sip_object_t *obj){ if (obj->name) belle_sip_free(obj->name); } static void _belle_sip_object_clone(belle_sip_object_t *obj, const belle_sip_object_t *orig){ if (orig->name!=NULL) obj->name=belle_sip_strdup(obj->name); } static belle_sip_error_code _belle_object_marshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset) { return belle_sip_snprintf(buff,buff_size,offset,"{%s::%s %p}",obj->vptr->type_name,obj->name ? obj->name : "(no name)",obj); } static belle_sip_object_vptr_t *no_parent(void){ return NULL; } belle_sip_object_vptr_t belle_sip_object_t_vptr={ BELLE_SIP_TYPE_ID(belle_sip_object_t), sizeof(belle_sip_object_t), "belle_sip_object_t", FALSE, no_parent, /*no parent, it's god*/ NULL, _belle_sip_object_uninit, _belle_sip_object_clone, _belle_object_marshal }; belle_sip_object_vptr_t *belle_sip_object_t_vptr_get(void){ return &belle_sip_object_t_vptr; } void belle_sip_object_delete(void *ptr){ belle_sip_object_t *obj=BELLE_SIP_OBJECT(ptr); belle_sip_object_vptr_t *vptr; belle_sip_object_loose_weak_refs(obj); remove_free_object(obj); vptr=obj->vptr; while(vptr!=NULL){ if (vptr->destroy) vptr->destroy(obj); vptr=vptr->get_parent(); } belle_sip_object_data_clear(obj); belle_sip_free(obj); } static belle_sip_object_vptr_t *find_common_floor(belle_sip_object_vptr_t *vptr1, belle_sip_object_vptr_t *vptr2){ belle_sip_object_vptr_t *it1,*it2; for (it1=vptr1;it1!=NULL;it1=it1->get_parent()){ if (it1==vptr2) return vptr2; } for(it2=vptr2;it2!=NULL;it2=it2->get_parent()){ if (vptr1==it2) return vptr1; } return find_common_floor(vptr1->get_parent(),vptr2); } /*copy the content of ref object to new object, for the part they have in common in their inheritence diagram*/ void _belle_sip_object_copy(belle_sip_object_t *newobj, const belle_sip_object_t *ref){ belle_sip_object_vptr_t *vptr; vptr=find_common_floor(newobj->vptr,ref->vptr); if (vptr==NULL){ belle_sip_fatal("Should not happen"); } while(vptr!=NULL){ if (vptr->clone==NULL){ belle_sip_fatal("Object of type %s cannot be cloned, it does not provide a clone() implementation.",vptr->type_name); return; }else vptr->clone(newobj,ref); vptr=vptr->get_parent(); } } belle_sip_object_t *belle_sip_object_clone(const belle_sip_object_t *obj){ belle_sip_object_t *newobj; newobj=belle_sip_malloc0(obj->vptr->size); newobj->ref=obj->vptr->initially_unowned ? 0 : 1; newobj->vptr=obj->vptr; _belle_sip_object_copy(newobj,obj); if (newobj->ref==0){ belle_sip_object_pool_t *pool=belle_sip_object_pool_get_current(); if (pool) belle_sip_object_pool_add(pool,newobj); } add_new_object(newobj); return newobj; } belle_sip_object_t *belle_sip_object_clone_and_ref(const belle_sip_object_t *obj) { return belle_sip_object_ref(belle_sip_object_clone(obj)); } struct belle_sip_object_data{ char* name; void* data; belle_sip_data_destroy destroy_func; }; static int belle_sip_object_data_find(const void* a, const void* b) { struct belle_sip_object_data* da = (struct belle_sip_object_data*)a; return strcmp(da->name, (const char*)b); } static void belle_sip_object_data_destroy(void* data) { struct belle_sip_object_data* da = (struct belle_sip_object_data*)data; if (da->destroy_func) da->destroy_func(da->data); belle_sip_free(da->name); belle_sip_free(da); } int belle_sip_object_data_set( belle_sip_object_t *obj, const char* name, void* data, belle_sip_data_destroy destroy_func ) { int ret = 0; struct _belle_sip_list* list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name); struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL; if( entry == NULL){ entry = belle_sip_malloc0(sizeof( struct belle_sip_object_data)); obj->data_store = belle_sip_list_append(obj->data_store, entry); } else { // clean previous data if( entry->destroy_func ) entry->destroy_func(entry->data); belle_sip_free(entry->name); ret = 1; } if( entry ){ entry->data = data; entry->name = belle_sip_strdup(name); entry->destroy_func = destroy_func; } else { ret = -1; } return ret; } void* belle_sip_object_data_get( belle_sip_object_t *obj, const char* name ) { struct _belle_sip_list* list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name); struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL; return entry? entry->data : NULL; } int belle_sip_object_data_remove( belle_sip_object_t *obj, const char* name) { struct _belle_sip_list* list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name); struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL; if( entry ){ belle_sip_free(entry->name); if( entry->destroy_func ) entry->destroy_func(entry->data); belle_sip_free(entry); } if( list_entry ) obj->data_store = belle_sip_list_remove_link(obj->data_store, list_entry); return !(list_entry!= NULL); } int belle_sip_object_data_exists( const belle_sip_object_t *obj, const char* name ) { return (belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name) != NULL); } void* belle_sip_object_data_grab( belle_sip_object_t* obj, const char* name) { struct _belle_sip_list* list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name); struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL; void* data =NULL; if( entry ){ belle_sip_free(entry->name); data = entry->data; } obj->data_store = belle_sip_list_remove_link(obj->data_store, list_entry); belle_sip_free(entry); return data; } void belle_sip_object_data_clear( belle_sip_object_t* obj ) { belle_sip_list_for_each(obj->data_store, belle_sip_object_data_destroy); obj->data_store = belle_sip_list_free(obj->data_store); } void belle_sip_object_data_clone( const belle_sip_object_t* src, belle_sip_object_t* dst, belle_sip_data_clone clone_func) { belle_sip_object_data_clear(dst); belle_sip_object_data_merge(src, dst, clone_func); } void belle_sip_object_data_merge( const belle_sip_object_t* src, belle_sip_object_t* dst, belle_sip_data_clone clone_func) { struct _belle_sip_list* list = src->data_store; struct belle_sip_object_data* it = NULL; void* cloned_data = NULL; while( list ){ it = list->data; if( it ){ cloned_data = (clone_func)? clone_func( it->name, it->data ) : it->data; belle_sip_object_data_set(dst, it->name, cloned_data, it->destroy_func); } list = list->next; } } struct belle_sip_object_foreach_data { void (*apply_func)(const char*, void*, void*); void* userdata; }; static void belle_sip_object_for_each_cb(void* data, void* pvdata) { struct belle_sip_object_data* it = (struct belle_sip_object_data*)data; struct belle_sip_object_foreach_data* fd = (struct belle_sip_object_foreach_data*)pvdata; if( it && fd->apply_func ){ fd->apply_func(it->name, it->data, fd->userdata); } } void belle_sip_object_data_foreach( const belle_sip_object_t* obj, void (*apply_func)(const char* key, void* data, void* userdata), void* userdata) { struct belle_sip_object_foreach_data fd = { apply_func, userdata }; belle_sip_list_for_each2(obj->data_store, belle_sip_object_for_each_cb, &fd); } void *belle_sip_object_cast(belle_sip_object_t *obj, belle_sip_type_id_t id, const char *castname, const char *file, int fileno){ if (obj!=NULL){ if (has_type(obj,id)==0){ belle_sip_fatal("Bad cast to %s at %s:%i",castname,file,fileno); return NULL; } } return obj; } void *belle_sip_object_get_interface_methods(belle_sip_object_t *obj, belle_sip_interface_id_t ifid){ if (obj!=NULL){ belle_sip_object_vptr_t *vptr; for (vptr=obj->vptr;vptr!=NULL;vptr=vptr->get_parent()){ belle_sip_interface_desc_t **ifaces=vptr->interfaces; if (ifaces!=NULL){ for(;*ifaces!=0;++ifaces){ if ((*ifaces)->id==ifid){ return *ifaces; } } } } } return NULL; } int belle_sip_object_implements(belle_sip_object_t *obj, belle_sip_interface_id_t id){ return belle_sip_object_get_interface_methods(obj,id)!=NULL; } void *belle_sip_object_interface_cast(belle_sip_object_t *obj, belle_sip_interface_id_t ifid, const char *castname, const char *file, int fileno){ if (obj!=NULL){ if (belle_sip_object_get_interface_methods(obj,ifid)==0){ belle_sip_fatal("Bad cast to interface %s at %s:%i",castname,file,fileno); return NULL; } } return obj; } void belle_sip_object_set_name(belle_sip_object_t* object,const char* name) { if (object->name) { belle_sip_free(object->name); object->name=NULL; } if (name) object->name=belle_sip_strdup(name); } const char* belle_sip_object_get_name(belle_sip_object_t* object) { return object->name; } static belle_sip_error_code checked_marshal(belle_sip_object_vptr_t *vptr, belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset){ size_t tmp_buf_size=buff_size*2; char *p=(char*)belle_sip_malloc0(tmp_buf_size); size_t i; size_t initial_offset=*offset; belle_sip_error_code error=vptr->marshal(obj,p,buff_size,offset); size_t written; for (i=initial_offset;itype_name,(int)(*offset-initial_offset)); } else if (error!=BELLE_SIP_OK){ belle_sip_error("Object of type %s produced an error during marshalling: %i", vptr->type_name,error); } if (written!=(*offset-initial_offset) && written!=(buff_size-initial_offset-1)){ /*this is because snprintf won't allow you to write a non null character at the end of the buffer*/ belle_sip_fatal("Object of type %s marshalled %i bytes but said it marshalled %i bytes !", vptr->type_name,(int)written,(int)(*offset-initial_offset)); } memcpy(buff+initial_offset,p+initial_offset,*offset-initial_offset); belle_sip_free(p); return error; } belle_sip_error_code belle_sip_object_marshal(belle_sip_object_t* obj, char* buff, size_t buff_size, size_t *offset) { belle_sip_object_vptr_t *vptr=obj->vptr; while (vptr != NULL) { if (vptr->marshal != NULL) { if (_belle_sip_object_marshal_check_enabled == TRUE) return checked_marshal(vptr,obj,buff,buff_size,offset); else return vptr->marshal(obj,buff,buff_size,offset); } else { vptr=vptr->get_parent(); } } return BELLE_SIP_NOT_IMPLEMENTED; /*no implementation found*/ } static char * belle_sip_object_to_alloc_string(belle_sip_object_t *obj, int size_hint){ char *buf=belle_sip_malloc(size_hint); size_t offset=0; belle_sip_error_code error = belle_sip_object_marshal(obj,buf,size_hint-1,&offset); obj->vptr->tostring_bufsize_hint=size_hint; if (error==BELLE_SIP_BUFFER_OVERFLOW){ belle_sip_message("belle_sip_object_to_alloc_string(): hint buffer was too short while doing to_string() for %s, retrying", obj->vptr->type_name); belle_sip_free(buf); return belle_sip_object_to_alloc_string(obj,2*size_hint); } buf=belle_sip_realloc(buf,offset+1); buf[offset]='\0'; return buf; } static int get_hint_size(int size){ if (size<128) return 128; return size; } char* belle_sip_object_to_string(void* _obj) { belle_sip_object_t *obj=BELLE_SIP_OBJECT(_obj); if (obj->vptr->tostring_bufsize_hint!=0){ return belle_sip_object_to_alloc_string(obj,obj->vptr->tostring_bufsize_hint); }else{ char buff[BELLE_SIP_MAX_TO_STRING_SIZE]; size_t offset=0; belle_sip_error_code error = belle_sip_object_marshal(obj,buff,sizeof(buff),&offset); if (error==BELLE_SIP_BUFFER_OVERFLOW){ belle_sip_message("belle_sip_object_to_string(): temporary buffer is too short while doing to_string() for %s, retrying", obj->vptr->type_name); return belle_sip_object_to_alloc_string(obj,get_hint_size(2*offset)); } buff[offset]='\0'; obj->vptr->tostring_bufsize_hint=get_hint_size(2*offset); return belle_sip_strdup(buff); } } char * _belle_sip_object_describe_type(belle_sip_object_vptr_t *vptr){ const int maxbufsize=2048; char *ret=belle_sip_malloc(maxbufsize); belle_sip_object_vptr_t *it; size_t pos=0; belle_sip_list_t *l=NULL,*elem; belle_sip_snprintf(ret,maxbufsize,&pos,"Ownership:\n"); belle_sip_snprintf(ret,maxbufsize,&pos,"\t%s is created initially %s\n",vptr->type_name, vptr->initially_unowned ? "unowned" : "owned"); belle_sip_snprintf(ret,maxbufsize,&pos,"\nInheritance diagram:\n"); for(it=vptr;it!=NULL;it=it->get_parent()){ l=belle_sip_list_prepend(l,it); } for(elem=l;elem!=NULL;elem=elem->next){ it=(belle_sip_object_vptr_t*)elem->data; belle_sip_snprintf(ret,maxbufsize,&pos,"\t%s\n",it->type_name); if (elem->next) belle_sip_snprintf(ret,maxbufsize,&pos,"\t |\n"); } belle_sip_list_free(l); belle_sip_snprintf(ret,maxbufsize,&pos,"\nImplemented interfaces:\n"); for(it=vptr;it!=NULL;it=it->get_parent()){ belle_sip_interface_desc_t **desc=it->interfaces; if (desc!=NULL){ for(;*desc!=NULL;desc++){ belle_sip_snprintf(ret,maxbufsize,&pos,"\t* %s\n",(*desc)->ifname); } } } return ret; } char *belle_sip_object_describe(void *obj){ belle_sip_object_t *o=BELLE_SIP_OBJECT(obj); return _belle_sip_object_describe_type(o->vptr); } #if !defined(WIN32) #include char *belle_sip_object_describe_type_from_name(const char *name){ char *vptr_name; void *handle; void *symbol; belle_sip_object_get_vptr_t vptr_getter; handle=dlopen(NULL,RTLD_LAZY); if (handle==NULL){ belle_sip_error("belle_sip_object_describe_type_from_name: dlopen() failed: %s",dlerror()); return NULL; } vptr_name=belle_sip_strdup_printf("%s_vptr_get",name); symbol=dlsym(handle,vptr_name); belle_sip_free(vptr_name); dlclose(handle); if (symbol==NULL){ belle_sip_error("belle_sip_object_describe_type_from_name: could not find vptr for type %s",name); return NULL; } vptr_getter=(belle_sip_object_get_vptr_t)symbol; return _belle_sip_object_describe_type(vptr_getter()); } #else char *belle_sip_object_describe_type_from_name(const char *name){ return belle_sip_strdup_printf("Sorry belle_sip_object_describe_type_from_name() is not implemented on this platform."); } #endif struct belle_sip_object_pool{ belle_sip_object_t base; belle_sip_list_t *objects; unsigned long thread_id; }; static void belle_sip_object_pool_destroy(belle_sip_object_pool_t *pool){ belle_sip_object_pool_clean(pool); _belle_sip_object_pool_remove_from_stack(pool); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_object_pool_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_object_pool_t,belle_sip_object_t,belle_sip_object_pool_destroy,NULL,NULL,FALSE); belle_sip_object_pool_t *belle_sip_object_pool_new(void){ belle_sip_object_pool_t *pool=belle_sip_object_new(belle_sip_object_pool_t); pool->thread_id=belle_sip_thread_self_id(); return pool; } void belle_sip_object_pool_add(belle_sip_object_pool_t *pool, belle_sip_object_t *obj){ if (obj->pool!=NULL){ belle_sip_fatal("It is not possible to add an object to multiple pools."); } pool->objects=belle_sip_list_prepend(pool->objects,obj); obj->pool_iterator=pool->objects; obj->pool=pool; } void belle_sip_object_pool_remove(belle_sip_object_pool_t *pool, belle_sip_object_t *obj){ unsigned long tid=belle_sip_thread_self_id(); if (obj->pool!=pool){ belle_sip_fatal("Attempting to remove object from an incorrect pool: obj->pool=%p, pool=%p",obj->pool,pool); return; } if (tid!=pool->thread_id){ belle_sip_fatal("It is forbidden (and unsafe()) to ref()/unref() an unowned object outside of the thread that created it."); return; } pool->objects=belle_sip_list_delete_link(pool->objects,obj->pool_iterator); obj->pool_iterator=NULL; obj->pool=NULL; } int belle_sip_object_pool_cleanable(belle_sip_object_pool_t *pool){ return pool->thread_id!=0 && belle_sip_thread_self_id()==pool->thread_id; } void belle_sip_object_pool_clean(belle_sip_object_pool_t *pool){ belle_sip_list_t *elem,*next; if (!belle_sip_object_pool_cleanable(pool)){ belle_sip_warning("Thread pool [%p] cannot be cleaned from thread [%lu] because it was created for thread [%lu]", pool,belle_sip_thread_self_id(),(unsigned long)pool->thread_id); return; } for(elem=pool->objects;elem!=NULL;elem=next){ belle_sip_object_t *obj=(belle_sip_object_t*)elem->data; if (obj->ref==0){ belle_sip_message("Garbage collecting unowned object of type %s",obj->vptr->type_name); obj->ref=-1; belle_sip_object_delete(obj); next=elem->next; belle_sip_free(elem); }else { belle_sip_fatal("Object %p is in unowned list but with ref count %i, bug.",obj,obj->ref); next=elem->next; } } pool->objects=NULL; } static void belle_sip_object_pool_detach_from_thread(belle_sip_object_pool_t *pool){ belle_sip_object_pool_clean(pool); pool->thread_id=(unsigned long)0; } static void cleanup_pool_stack(void *data){ belle_sip_list_t **pool_stack=(belle_sip_list_t**)data; if (*pool_stack){ /* * We would expect the pool_stack to be empty when the thread terminates. * Otherwise that means the management of object pool is not properly done by the application. * Since the object pools might be still referenced by the application, we can't destroy them. * Instead, we mark them as detached, so that when the thread that will attempt to destroy them will do it, * we'll accept (since anyway these object pool are no longer needed. */ belle_sip_warning("There were still [%i] object pools for thread [%lu] while the thread exited. ", belle_sip_list_size(*pool_stack),belle_sip_thread_self_id()); belle_sip_list_free_with_data(*pool_stack,(void (*)(void*)) belle_sip_object_pool_detach_from_thread); } *pool_stack=NULL; belle_sip_free(pool_stack); } static belle_sip_list_t** get_current_pool_stack(int *first_time){ static belle_sip_thread_key_t pools_key; static int pools_key_created=0; belle_sip_list_t **pool_stack; if (first_time) *first_time=0; if (!pools_key_created){ pools_key_created=1; if (belle_sip_thread_key_create(&pools_key, cleanup_pool_stack)!=0){ return NULL; } } pool_stack=(belle_sip_list_t**)belle_sip_thread_getspecific(pools_key); if (pool_stack==NULL){ pool_stack=belle_sip_new(belle_sip_list_t*); *pool_stack=NULL; belle_sip_thread_setspecific(pools_key,pool_stack); if (first_time) *first_time=1; } return pool_stack; } static void _belle_sip_object_pool_remove_from_stack(belle_sip_object_pool_t *pool){ belle_sip_list_t **pools=get_current_pool_stack(NULL); unsigned long tid=belle_sip_thread_self_id(); if (tid!=pool->thread_id){ belle_sip_fatal("It is forbidden to destroy a pool outside the thread that created it."); return; } if (pools==NULL) { belle_sip_fatal("Not possible to pop a pool."); return; } if (*pools==NULL){ belle_sip_fatal("There is no current pool in stack."); return; } *pools=belle_sip_list_remove(*pools,pool); } belle_sip_object_pool_t * belle_sip_object_pool_push(void){ belle_sip_list_t **pools=get_current_pool_stack(NULL); belle_sip_object_pool_t *pool; if (pools==NULL) { belle_sip_error("Not possible to create a pool."); return NULL; } pool=belle_sip_object_pool_new(); *pools=belle_sip_list_prepend(*pools,pool); return pool; } belle_sip_object_pool_t *belle_sip_object_pool_get_current(void){ int first_time; belle_sip_list_t **pools=get_current_pool_stack(&first_time); if (pools==NULL) return NULL; if (*pools==NULL ){ if (first_time) { belle_sip_warning("There is no object pool created in thread [%lu]. " "Use belle_sip_object_pool_push() to create one. Unowned objects not unref'd will be leaked.", belle_sip_thread_self_id()); } return NULL; } return (belle_sip_object_pool_t*)(*pools)->data; } belle-sip-1.4.1/src/belle_sip_parameters.c000066400000000000000000000142211252242224000205000ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/belle-sip.h" #include "belle-sip/parameters.h" #include "belle_sip_internal.h" #include "belle-sip/headers.h" void belle_sip_parameters_init(belle_sip_parameters_t *obj){ } void belle_sip_parameters_clean(belle_sip_parameters_t* params) { if (params->param_list) belle_sip_list_free_with_data (params->param_list, (void (*)(void*))belle_sip_param_pair_destroy); if (params->paramnames_list) belle_sip_list_free(params->paramnames_list); params->paramnames_list=NULL; params->param_list=NULL; } static void belle_sip_parameters_destroy(belle_sip_parameters_t* params) { belle_sip_parameters_clean(params); } void belle_sip_parameters_copy_parameters_from(belle_sip_parameters_t *params, const belle_sip_parameters_t *orig){ belle_sip_list_t* list=orig->param_list; for(;list!=NULL;list=list->next){ belle_sip_param_pair_t* container = (belle_sip_param_pair_t* )(list->data); belle_sip_parameters_set_parameter( params,container->name,container->value); } } static void belle_sip_parameters_clone(belle_sip_parameters_t *params, const belle_sip_parameters_t *orig){ belle_sip_parameters_copy_parameters_from(params,orig); } belle_sip_error_code belle_sip_parameters_marshal(const belle_sip_parameters_t* params, char* buff, size_t buff_size, size_t *offset) { belle_sip_list_t* list=params->param_list; belle_sip_error_code error=BELLE_SIP_OK; for(;list!=NULL;list=list->next){ belle_sip_param_pair_t* container = (belle_sip_param_pair_t* )(list->data); if (container->value) { error=belle_sip_snprintf(buff,buff_size,offset,";%s=%s", container->name, container->value); } else { error=belle_sip_snprintf(buff,buff_size,offset,";%s", container->name); } if (error!=BELLE_SIP_OK) return error; } return error; } BELLE_SIP_NEW_HEADER(parameters,header,"parameters") const belle_sip_list_t *belle_sip_parameters_get_parameters(const belle_sip_parameters_t* obj) { return obj->param_list; } const char* belle_sip_parameters_get_parameter_base(const belle_sip_parameters_t* params,const char* name,belle_sip_compare_func func) { belle_sip_list_t * lResult = belle_sip_list_find_custom(params->param_list, func, name); if (lResult) { return ((belle_sip_param_pair_t*)(lResult->data))->value; } else { return NULL; } } const char* belle_sip_parameters_get_parameter(const belle_sip_parameters_t* params,const char* name) { return belle_sip_parameters_get_parameter_base(params,name,(belle_sip_compare_func)belle_sip_param_pair_comp_func); } const char* belle_sip_parameters_get_case_parameter(const belle_sip_parameters_t* params,const char* name) { return belle_sip_parameters_get_parameter_base(params,name,(belle_sip_compare_func)belle_sip_param_pair_case_comp_func); } unsigned int belle_sip_parameters_has_parameter(const belle_sip_parameters_t* params,const char* name) { return belle_sip_list_find_custom(params->param_list, (belle_sip_compare_func)belle_sip_param_pair_comp_func, name) != NULL; } void belle_sip_parameters_set_parameter(belle_sip_parameters_t* params,const char* name,const char* value) { /*1 check if present*/ belle_sip_param_pair_t* lNewpair; belle_sip_list_t * lResult = belle_sip_list_find_custom(params->paramnames_list, (belle_sip_compare_func)strcmp, name); /* first remove from header names list*/ if (lResult) { params->paramnames_list=belle_sip_list_delete_link(params->paramnames_list,lResult); } /* next from header list*/ lResult = belle_sip_list_find_custom(params->param_list, (belle_sip_compare_func)belle_sip_param_pair_comp_func, name); if (lResult) { belle_sip_param_pair_destroy(lResult->data); params->param_list=belle_sip_list_delete_link(params->param_list,lResult); } /* 2 insert*/ lNewpair = belle_sip_param_pair_new(name,value); params->param_list=belle_sip_list_append(params->param_list,lNewpair); params->paramnames_list=belle_sip_list_append(params->paramnames_list,lNewpair->name); } void belle_sip_parameters_set(belle_sip_parameters_t *parameters, const char* params){ belle_sip_parameters_clean(parameters); if (params && *params!='\0'){ char *tmp=belle_sip_strdup(params); char *end_of_param; char *current=tmp; char *equal; char *next; do{ end_of_param=strchr(current,';'); equal=strchr(current,'='); if (!end_of_param) { end_of_param=current+strlen(current); next=end_of_param; }else{ *end_of_param='\0'; next=end_of_param+1; } if (equal && equalparamnames_list:NULL; } void belle_sip_parameters_remove_parameter(belle_sip_parameters_t* params,const char* name) { /*1 check if present*/ belle_sip_list_t * lResult = belle_sip_list_find_custom(params->paramnames_list, (belle_sip_compare_func)strcmp, name); /* first remove from header names list*/ if (lResult) { params->paramnames_list=belle_sip_list_delete_link(params->paramnames_list,lResult); /*next remove node*/ lResult = belle_sip_list_find_custom(params->param_list, (belle_sip_compare_func)belle_sip_param_pair_comp_func, name); if (lResult) { belle_sip_param_pair_destroy(lResult->data); params->param_list=belle_sip_list_delete_link(params->param_list,lResult); } } } belle-sip-1.4.1/src/belle_sip_resolver.c000066400000000000000000001157401252242224000202060ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include "dns.h" #include #ifdef __APPLE__ #include "TargetConditionals.h" #endif #define DNS_EAGAIN EAGAIN typedef struct belle_sip_simple_resolver_context belle_sip_simple_resolver_context_t; #define BELLE_SIP_SIMPLE_RESOLVER_CONTEXT(obj) BELLE_SIP_CAST(obj,belle_sip_simple_resolver_context_t) typedef struct belle_sip_combined_resolver_context belle_sip_combined_resolver_context_t; #define BELLE_SIP_COMBINED_RESOLVER_CONTEXT(obj) BELLE_SIP_CAST(obj,belle_sip_combined_resolver_context_t) typedef struct belle_sip_dual_resolver_context belle_sip_dual_resolver_context_t; #define BELLE_SIP_DUAL_RESOLVER_CONTEXT(obj) BELLE_SIP_CAST(obj,belle_sip_dual_resolver_context_t) struct belle_sip_dns_srv{ belle_sip_object_t base; unsigned short priority; unsigned short weight; unsigned short port; unsigned char a_done; unsigned char pad; int cumulative_weight; /*used only temporarily*/ char *target; belle_sip_combined_resolver_context_t *root_resolver;/* used internally to combine SRV and A queries*/ belle_sip_resolver_context_t *a_resolver; /* used internally to combine SRV and A queries*/ struct addrinfo *a_results; /* used internally to combine SRV and A queries*/ }; static void belle_sip_dns_srv_destroy(belle_sip_dns_srv_t *obj){ if (obj->target) { belle_sip_free(obj->target); obj->target=NULL; } if (obj->a_resolver){ belle_sip_resolver_context_cancel(obj->a_resolver); obj->a_resolver=NULL; } if (obj->a_results){ belle_sip_freeaddrinfo(obj->a_results); obj->a_results=NULL; } } belle_sip_dns_srv_t *belle_sip_dns_srv_create(struct dns_srv *srv){ belle_sip_dns_srv_t *obj=belle_sip_object_new(belle_sip_dns_srv_t); obj->priority=srv->priority; obj->weight=srv->weight; obj->port=srv->port; obj->target=belle_sip_strdup(srv->target); return obj; } const char *belle_sip_dns_srv_get_target(const belle_sip_dns_srv_t *obj){ return obj->target; } unsigned short belle_sip_dns_srv_get_priority(const belle_sip_dns_srv_t *obj){ return obj->priority; } unsigned short belle_sip_dns_srv_get_weight(const belle_sip_dns_srv_t *obj){ return obj->weight; } unsigned short belle_sip_dns_srv_get_port(const belle_sip_dns_srv_t *obj){ return obj->port; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_dns_srv_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_dns_srv_t, belle_sip_object_t,belle_sip_dns_srv_destroy, NULL, NULL,TRUE); struct belle_sip_resolver_context{ belle_sip_source_t source; belle_sip_stack_t *stack; uint8_t done; uint8_t pad[3]; }; struct belle_sip_simple_resolver_context{ belle_sip_resolver_context_t base; belle_sip_resolver_callback_t cb; belle_sip_resolver_srv_callback_t srv_cb; void *cb_data; void *srv_cb_data; struct dns_resolv_conf *resconf; struct dns_hosts *hosts; struct dns_resolver *R; enum dns_type type; char *name; int port; struct addrinfo *ai_list; belle_sip_list_t *srv_list; /*list of belle_sip_dns_srv_t*/ int family; int flags; uint64_t start_time; #ifdef USE_GETADDRINFO_FALLBACK belle_sip_source_t *getaddrinfo_source; belle_sip_thread_t getaddrinfo_thread; belle_sip_mutex_t getaddrinfo_mutex; unsigned char getaddrinfo_done; unsigned char getaddrinfo_cancelled; unsigned char getaddrinfo_notified; #ifdef WIN32 HANDLE ctlevent; #else int ctlpipe[2]; #endif #endif }; struct belle_sip_combined_resolver_context{ belle_sip_resolver_context_t base; belle_sip_resolver_callback_t cb; void *cb_data; char *name; int port; int family; struct addrinfo *final_results; belle_sip_list_t *srv_results; belle_sip_resolver_context_t *srv_ctx; belle_sip_resolver_context_t *a_fallback_ctx; }; struct belle_sip_dual_resolver_context{ belle_sip_resolver_context_t base; belle_sip_resolver_callback_t cb; void *cb_data; char *name; belle_sip_resolver_context_t *a_ctx; belle_sip_resolver_context_t *aaaa_ctx; struct addrinfo *a_results; struct addrinfo *aaaa_results; unsigned char a_done; unsigned char aaaa_done; }; void belle_sip_resolver_context_init(belle_sip_resolver_context_t *obj, belle_sip_stack_t *stack){ obj->stack=stack; belle_sip_init_sockets(); /* Need to be called for DNS resolution to work on Windows platform. */ } static struct dns_resolv_conf *resconf(belle_sip_simple_resolver_context_t *ctx) { const char *path; int error; if (ctx->resconf) return ctx->resconf; if (!(ctx->resconf = dns_resconf_open(&error))) { belle_sip_error("%s dns_resconf_open error: %s", __FUNCTION__, dns_strerror(error)); return NULL; } path=belle_sip_stack_get_dns_resolv_conf_file(ctx->base.stack); if (!path){ #if defined(USE_FIXED_NAMESERVERS) error = dns_resconf_load_fixed_nameservers(ctx->resconf); if (error) { belle_sip_error("%s dns_resconf_load_fixed_nameservers error", __FUNCTION__); } #elif defined(USE_STRUCT_RES_STATE_NAMESERVERS) error = dns_resconf_load_struct_res_state_nameservers(ctx->resconf); if (error) { belle_sip_error("%s dns_resconf_load_struct_res_state_nameservers error", __FUNCTION__); } #elif defined(_WIN32) error = dns_resconf_loadwin(ctx->resconf); if (error) { belle_sip_error("%s dns_resconf_loadwin error", __FUNCTION__); } #elif defined(ANDROID) error = dns_resconf_loadandroid(ctx->resconf); if (error) { belle_sip_error("%s dns_resconf_loadandroid error", __FUNCTION__); } #elif defined(HAVE_RESINIT) /*#elif HAVE_RESINIT && TARGET_OS_IPHONE*/ error = dns_resconf_loadfromresolv(ctx->resconf); if (error) { belle_sip_error("%s dns_resconf_loadfromresolv error", __FUNCTION__); } #else path = "/etc/resolv.conf"; error = dns_resconf_loadpath(ctx->resconf, path); if (error) { belle_sip_error("%s dns_resconf_loadpath error [%s]: %s", __FUNCTION__, path, dns_strerror(error)); return NULL; } path = "/etc/nsswitch.conf"; error = dns_nssconf_loadpath(ctx->resconf, path); if (error) { belle_sip_message("%s dns_nssconf_loadpath error [%s]: %s", __FUNCTION__, path, dns_strerror(error)); } #endif }else{ error = dns_resconf_loadpath(ctx->resconf, path); if (error) { belle_sip_error("%s dns_resconf_loadpath() of custom file error [%s]: %s", __FUNCTION__, path, dns_strerror(error)); return NULL; } } if (error==0){ char ip[64]; char serv[10]; int using_ipv6=FALSE; int i; belle_sip_message("Resolver is using DNS server(s):"); for(i=0;iresconf->nameserver)/sizeof(ctx->resconf->nameserver[0]);++i){ struct sockaddr *ns_addr=(struct sockaddr*)&ctx->resconf->nameserver[i]; if (ns_addr->sa_family==AF_UNSPEC) break; getnameinfo(ns_addr,ns_addr->sa_family==AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr) ,ip,sizeof(ip),serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV); belle_sip_message("\t%s",ip); if (ns_addr->sa_family==AF_INET6) using_ipv6=TRUE; } ctx->resconf->iface.ss_family=using_ipv6 ? AF_INET6 : AF_INET; if (i==0) { belle_sip_error("- no DNS servers available - resolution aborted."); return NULL; } }else{ belle_sip_error("Error loading dns server addresses."); return NULL; } return ctx->resconf; } static struct dns_hosts *hosts(belle_sip_simple_resolver_context_t *ctx) { int error; if (ctx->hosts) return ctx->hosts; if (!(ctx->hosts = dns_hosts_local(&error))) { belle_sip_warning("%s dns_hosts_local error: %s", __FUNCTION__, dns_strerror(error)); /*in case of failure, create an empty host object to make further processing happy, knowing that we can live without /etc/hosts.*/ ctx->hosts=dns_hosts_open(&error); } if (ctx->base.stack->dns_user_hosts_file) { error = dns_hosts_loadpath(ctx->hosts, ctx->base.stack->dns_user_hosts_file); if (error) { belle_sip_error("%s dns_hosts_loadfile(\"%s\"): %s", __FUNCTION__,ctx->base.stack->dns_user_hosts_file,dns_strerror(error)); } } return ctx->hosts; } struct dns_cache *cache(belle_sip_simple_resolver_context_t *ctx) { return NULL; } static struct addrinfo * ai_list_append(struct addrinfo *ai_list, struct addrinfo *ai_to_append) { struct addrinfo *ai_current = ai_list; if (ai_to_append == NULL) return ai_list; if (ai_list == NULL) return ai_to_append; while (ai_current->ai_next != NULL) { ai_current = ai_current->ai_next; } ai_current->ai_next = ai_to_append; return ai_list; } static int srv_compare_prio(const void *psrv1, const void *psrv2){ belle_sip_dns_srv_t *srv1=(belle_sip_dns_srv_t*)psrv1; belle_sip_dns_srv_t *srv2=(belle_sip_dns_srv_t*)psrv2; if (srv1->priority < srv2->priority) return -1; if (srv1->priority == srv2->priority) return 0; return 1; } /* * see https://www.ietf.org/rfc/rfc2782.txt * 0 weighted must just appear first. **/ static int srv_sort_weight(const void *psrv1, const void *psrv2){ belle_sip_dns_srv_t *srv1=(belle_sip_dns_srv_t*)psrv1; if (srv1->weight==0) return -1; return 1; } static belle_sip_dns_srv_t *srv_elect_one(belle_sip_list_t *srv_list){ int sum=0; belle_sip_list_t *elem; belle_sip_dns_srv_t *srv; int rand_number; for(elem=srv_list;elem!=NULL;elem=elem->next){ srv=(belle_sip_dns_srv_t*)elem->data; sum+=srv->weight; srv->cumulative_weight=sum; } /*no weights given, return the first one*/ if (sum==0) return (belle_sip_dns_srv_t*)srv_list->data; rand_number=belle_sip_random() % sum; /*random number choosen in the range of the sum of weights*/ for(elem=srv_list;elem!=NULL;elem=elem->next){ srv=(belle_sip_dns_srv_t*)elem->data; if (rand_number>=srv->cumulative_weight) return srv; } return (belle_sip_dns_srv_t*)srv_list->data; } /* * Order an SRV list with entries having the same priority according to their weight */ static belle_sip_list_t *srv_elect(belle_sip_list_t **srv_list) { belle_sip_list_t *result = NULL; while (*srv_list != NULL) { belle_sip_list_t *it; belle_sip_dns_srv_t *entry = srv_elect_one(*srv_list); result = belle_sip_list_append(result, belle_sip_object_ref(entry)); it = belle_sip_list_find(*srv_list, entry); if (it) { *srv_list = belle_sip_list_remove_link(*srv_list, it); belle_sip_free(it); } } return result; } /* * this function will return a list of SRV, with only one SRV record per priority. */ static belle_sip_list_t *srv_select_by_weight(belle_sip_list_t *srv_list){ belle_sip_list_t *same_prio=NULL; belle_sip_list_t *elem; belle_sip_dns_srv_t *prev_srv=NULL; belle_sip_list_t *result=NULL; for (elem=srv_list;elem!=NULL;elem=elem->next){ belle_sip_dns_srv_t *srv=(belle_sip_dns_srv_t*)elem->data; if (prev_srv){ if (prev_srv->priority==srv->priority){ if (!same_prio){ same_prio=belle_sip_list_append(same_prio,prev_srv); } same_prio=belle_sip_list_insert_sorted(same_prio,srv,srv_sort_weight); }else{ if (same_prio){ result=belle_sip_list_concat(result,srv_elect(&same_prio)); } } } prev_srv=srv; } if (same_prio){ result=belle_sip_list_concat(result,srv_elect(&same_prio)); } if (result){ belle_sip_list_free_with_data(srv_list,belle_sip_object_unref); return result; } return srv_list;/*no weight election was necessary, return original list*/ } static void notify_results(belle_sip_simple_resolver_context_t *ctx){ ctx->base.done=TRUE; if ((ctx->type == DNS_T_A) || (ctx->type == DNS_T_AAAA)) { ctx->cb(ctx->cb_data, ctx->name, ctx->ai_list); } else if (ctx->type == DNS_T_SRV) { ctx->srv_list=srv_select_by_weight(ctx->srv_list); ctx->srv_cb(ctx->srv_cb_data, ctx->name, ctx->srv_list); } } static void append_dns_result(belle_sip_simple_resolver_context_t *ctx, struct sockaddr *addr, socklen_t addrlen){ char host[NI_MAXHOST + 1]; int gai_err; int family=ctx->family; if ((gai_err=getnameinfo(addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST)) != 0){ belle_sip_error("append_dns_result(): getnameinfo() failed: %s",gai_strerror(gai_err)); return; } if (ctx->flags & AI_V4MAPPED) family=AF_INET6; #ifdef USE_GETADDRINFO_FALLBACK belle_sip_mutex_lock(&ctx->getaddrinfo_mutex); #endif ctx->ai_list = ai_list_append(ctx->ai_list, belle_sip_ip_address_to_addrinfo(family, host, ctx->port)); #ifdef USE_GETADDRINFO_FALLBACK belle_sip_mutex_unlock(&ctx->getaddrinfo_mutex); #endif belle_sip_message("%s resolved to %s", ctx->name, host); } static int resolver_process_data(belle_sip_simple_resolver_context_t *ctx, unsigned int revents) { struct dns_packet *ans; struct dns_rr_i *I; struct dns_rr_i dns_rr_it; int error; unsigned char simulated_timeout=0; int timeout=belle_sip_stack_get_dns_timeout(ctx->base.stack); /*Setting timeout to 0 can be used to simulate DNS timeout*/ if ((revents!=0) && timeout==0){ belle_sip_warning("Simulating DNS timeout"); simulated_timeout=1; } if (simulated_timeout || ((revents & BELLE_SIP_EVENT_TIMEOUT) && (belle_sip_time_ms()-ctx->start_time>=timeout))) { belle_sip_error("%s timed-out", __FUNCTION__); #ifdef USE_GETADDRINFO_FALLBACK if (!ctx->getaddrinfo_notified) { notify_results(ctx); } #else notify_results(ctx); #endif return BELLE_SIP_STOP; } /*belle_sip_message("resolver_process_data(): revents=%i",revents);*/ error = dns_res_check(ctx->R); if (!error) { struct dns_rr rr; union dns_any any; enum dns_section section = DNS_S_AN; ans = dns_res_fetch(ctx->R, &error); memset(&dns_rr_it, 0, sizeof dns_rr_it); I = dns_rr_i_init(&dns_rr_it, ans); while (dns_rr_grep(&rr, 1, I, ans, &error)) { if (rr.section == section) { if ((error = dns_any_parse(dns_any_init(&any, sizeof(any)), &rr, ans))) { belle_sip_error("%s dns_any_parse error: %s", __FUNCTION__, dns_strerror(error)); break; } if ((ctx->type == DNS_T_AAAA) && (rr.class == DNS_C_IN) && (rr.type == DNS_T_AAAA)) { struct dns_aaaa *aaaa = &any.aaaa; struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof(sin6)); memcpy(&sin6.sin6_addr, &aaaa->addr, sizeof(sin6.sin6_addr)); sin6.sin6_family = AF_INET6; sin6.sin6_port = ctx->port; append_dns_result(ctx,(struct sockaddr*)&sin6,sizeof(sin6)); } else if ((ctx->type == DNS_T_A) && (rr.class == DNS_C_IN) && (rr.type == DNS_T_A)) { struct dns_a *a = &any.a; struct sockaddr_in sin; memset(&sin, 0, sizeof(sin)); memcpy(&sin.sin_addr, &a->addr, sizeof(sin.sin_addr)); sin.sin_family = AF_INET; sin.sin_port = ctx->port; append_dns_result(ctx,(struct sockaddr*)&sin,sizeof(sin)); } else if ((ctx->type == DNS_T_SRV) && (rr.class == DNS_C_IN) && (rr.type == DNS_T_SRV)) { char host[NI_MAXHOST + 1]; struct dns_srv *srv = &any.srv; belle_sip_dns_srv_t * b_srv=belle_sip_dns_srv_create(srv); snprintf(host, sizeof(host), "[target:%s port:%d prio:%d weight:%d]", srv->target, srv->port, srv->priority, srv->weight); ctx->srv_list = belle_sip_list_insert_sorted(ctx->srv_list, belle_sip_object_ref(b_srv), srv_compare_prio); belle_sip_message("SRV %s resolved to %s", ctx->name, host); } } } free(ans); #ifdef USE_GETADDRINFO_FALLBACK if (!ctx->getaddrinfo_notified) { notify_results(ctx); } ctx->getaddrinfo_cancelled = TRUE; #else notify_results(ctx); #endif return BELLE_SIP_STOP; } if (error != DNS_EAGAIN) { belle_sip_error("%s dns_res_check() error: %s (%d)", __FUNCTION__, dns_strerror(error), error); #ifdef USE_GETADDRINFO_FALLBACK if (ctx->getaddrinfo_done) { return BELLE_SIP_STOP; } else { // Wait for the getaddrinfo result return BELLE_SIP_CONTINUE; } #else notify_results(ctx); return BELLE_SIP_STOP; #endif } else { #ifdef USE_GETADDRINFO_FALLBACK if (ctx->getaddrinfo_done) { return BELLE_SIP_STOP; } else #endif { belle_sip_message("%s dns_res_check() in progress", __FUNCTION__); } } return BELLE_SIP_CONTINUE; } #ifdef USE_GETADDRINFO_FALLBACK static void * _resolver_getaddrinfo_thread(void *ptr) { belle_sip_simple_resolver_context_t *ctx = (belle_sip_simple_resolver_context_t *)ptr; struct addrinfo *res = NULL; struct addrinfo hints = { 0 }; char serv[10]; int err; belle_sip_message("Resolver getaddrinfo thread started."); snprintf(serv, sizeof(serv), "%i", ctx->port); hints.ai_family = ctx->family; hints.ai_flags = AI_NUMERICSERV; err = getaddrinfo(ctx->name, serv, &hints, &res); if (err != 0) { belle_sip_error("getaddrinfo DNS resolution of %s failed: %s", ctx->name, gai_strerror(err)); } else if (!ctx->getaddrinfo_cancelled) { append_dns_result(ctx, res->ai_addr, res->ai_addrlen); } if (res) freeaddrinfo(res); ctx->getaddrinfo_done = TRUE; #ifdef WIN32 SetEvent(ctx->ctlevent); #else if (write(ctx->ctlpipe[1], "q", 1) == -1) { belle_sip_error("_resolver_getaddrinfo_thread(): Fail to write on pipe."); } #endif return NULL; } static int _resolver_getaddrinfo_callback(belle_sip_simple_resolver_context_t *ctx, unsigned int revents) { if (!ctx->getaddrinfo_cancelled && !ctx->getaddrinfo_notified) { notify_results(ctx); ctx->getaddrinfo_notified = TRUE; } belle_sip_object_unref(ctx); return BELLE_SIP_STOP; } static void _resolver_getaddrinfo_start(belle_sip_simple_resolver_context_t *ctx) { belle_sip_fd_t fd = (belle_sip_fd_t)-1; belle_sip_object_ref(ctx); #ifdef WIN32 ctx->ctlevent = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); fd = (HANDLE)ctx->ctlevent; #else if (pipe(ctx->ctlpipe) == -1) { belle_sip_fatal("pipe() failed: %s", strerror(errno)); } fd = ctx->ctlpipe[0]; #endif belle_sip_thread_create(&ctx->getaddrinfo_thread, NULL, _resolver_getaddrinfo_thread, ctx); ctx->getaddrinfo_source = belle_sip_fd_source_new((belle_sip_source_func_t)_resolver_getaddrinfo_callback, ctx, fd, BELLE_SIP_EVENT_READ, -1); belle_sip_main_loop_add_source(ctx->base.stack->ml, ctx->getaddrinfo_source); } #endif static int _resolver_send_query(belle_sip_simple_resolver_context_t *ctx) { int error = 0; if (!ctx->base.stack->resolver_send_error) { error = dns_res_submit(ctx->R, ctx->name, ctx->type, DNS_C_IN); if (error) belle_sip_error("%s dns_res_submit error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error)); } else { /* Error simulation */ error = ctx->base.stack->resolver_send_error; belle_sip_error("%s dns_res_submit error [%s]: simulated error %d", __FUNCTION__, ctx->name, error); } if (error < 0) { return -1; } if (resolver_process_data(ctx, 0) == BELLE_SIP_CONTINUE) { ctx->start_time=belle_sip_time_ms(); belle_sip_message("DNS resolution awaiting response, queued to main loop"); /*only init source if res inprogress*/ /*the timeout set to the source is 1 s, this is to allow dns.c to send request retransmissions*/ belle_sip_socket_source_init((belle_sip_source_t*)ctx, (belle_sip_source_func_t)resolver_process_data, ctx, dns_res_pollfd(ctx->R), BELLE_SIP_EVENT_READ | BELLE_SIP_EVENT_TIMEOUT, 1000); #ifdef USE_GETADDRINFO_FALLBACK if ((ctx->type == DNS_T_A) || (ctx->type == DNS_T_AAAA)) { _resolver_getaddrinfo_start(ctx); } #endif } return 0; } static int resolver_process_data_delayed(belle_sip_simple_resolver_context_t *ctx, unsigned int revents) { int err=_resolver_send_query(ctx); if (err==0) return BELLE_SIP_CONTINUE; return BELLE_SIP_STOP; } static int _resolver_start_query(belle_sip_simple_resolver_context_t *ctx) { struct dns_hints *(*hints)() = &dns_hints_local; struct dns_options opts; int error; struct dns_resolv_conf *conf; if (!ctx->name) return -1; conf=resconf(ctx); if (conf){ conf->options.recurse = 0; conf->options.timeout=2; conf->options.attempts=5; }else return -1; if (!hosts(ctx)) return -1; memset(&opts, 0, sizeof opts); if (!(ctx->R = dns_res_open(ctx->resconf, ctx->hosts, dns_hints_mortal(hints(ctx->resconf, &error)), cache(ctx), &opts, &error))) { belle_sip_error("%s dns_res_open error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error)); return -1; } error=0; if (ctx->base.stack->resolver_tx_delay > 0) { belle_sip_socket_source_init((belle_sip_source_t*)ctx, (belle_sip_source_func_t)resolver_process_data_delayed, ctx, -1, BELLE_SIP_EVENT_TIMEOUT, ctx->base.stack->resolver_tx_delay + 1000); belle_sip_message("%s DNS resolution delayed by %d ms", __FUNCTION__, ctx->base.stack->resolver_tx_delay); } else { error=_resolver_send_query(ctx); } if (error==0 && !ctx->base.done) belle_sip_main_loop_add_source(ctx->base.stack->ml,(belle_sip_source_t*)ctx); return error; } static belle_sip_simple_resolver_context_t * resolver_start_query(belle_sip_simple_resolver_context_t *ctx){ int error=_resolver_start_query(ctx); if (error==0){ if (!ctx->base.done){ /* the resolution could not be done synchronously, return the context*/ return ctx; } /*else resolution could be done synchronously*/ }else{ /*An error occured. We must notify the app.*/ notify_results(ctx); } /*If it is failed or result could be found immediately, the context is now useless, we don't have to return it.*/ belle_sip_object_unref(ctx); return NULL; } int belle_sip_addrinfo_to_ip(const struct addrinfo *ai, char *ip, size_t ip_size, int *port){ char serv[16]; int err=getnameinfo(ai->ai_addr,ai->ai_addrlen,ip,ip_size,serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV); if (err!=0){ belle_sip_error("getnameinfo() error: %s",gai_strerror(err)); strncpy(ip,"",ip_size); } if (port) *port=atoi(serv); return 0; } struct addrinfo * belle_sip_ip_address_to_addrinfo(int family, const char *ipaddress, int port){ struct addrinfo *res=NULL; struct addrinfo hints={0}; char serv[10]; int err; snprintf(serv,sizeof(serv),"%i",port); hints.ai_family=family; hints.ai_flags=AI_NUMERICSERV|AI_NUMERICHOST; hints.ai_socktype=SOCK_STREAM; //not used but it's needed to specify it because otherwise getaddrinfo returns one struct addrinfo per socktype. if (family==AF_INET6 && strchr(ipaddress,':')==NULL) { hints.ai_flags|=AI_V4MAPPED; } err=belle_sip_getaddrinfo(ipaddress,serv,&hints,&res); if (err!=0){ if (err!=EAI_NONAME) belle_sip_error("belle_sip_ip_address_to_addrinfo(): getaddrinfo() error: %s",gai_strerror(err)); return NULL; } return res; } static void belle_sip_combined_resolver_context_destroy(belle_sip_combined_resolver_context_t *obj){ if (obj->name != NULL) { belle_sip_free(obj->name); obj->name = NULL; } if (obj->srv_ctx){ belle_sip_object_unref(obj->srv_ctx); obj->srv_ctx=NULL; } if (obj->a_fallback_ctx){ belle_sip_object_unref(obj->a_fallback_ctx); obj->a_fallback_ctx=NULL; } } static void belle_sip_simple_resolver_context_destroy(belle_sip_simple_resolver_context_t *ctx){ /* Do not free elements of ctx->ai_list with belle_sip_freeaddrinfo(). Let the caller do it, otherwise it will not be able to use them after the resolver has been destroyed. */ #ifdef USE_GETADDRINFO_FALLBACK if (ctx->getaddrinfo_thread != 0) { belle_sip_thread_join(ctx->getaddrinfo_thread, NULL); } belle_sip_mutex_destroy(&ctx->getaddrinfo_mutex); #ifdef WIN32 if (ctx->ctlevent != (belle_sip_fd_t)-1) CloseHandle(ctx->ctlevent); #else close(ctx->ctlpipe[0]); close(ctx->ctlpipe[1]); #endif #endif if (ctx->name != NULL) { belle_sip_free(ctx->name); ctx->name = NULL; } if (ctx->R != NULL) { dns_res_close(ctx->R); ctx->R = NULL; } if (ctx->hosts != NULL) { dns_hosts_close(ctx->hosts); ctx->hosts = NULL; } if (ctx->resconf != NULL) { free(ctx->resconf); ctx->resconf = NULL; } } static void belle_sip_dual_resolver_context_destroy(belle_sip_dual_resolver_context_t *obj){ if (obj->a_ctx){ belle_sip_object_unref(obj->a_ctx); obj->a_ctx=NULL; } if (obj->aaaa_ctx){ belle_sip_object_unref(obj->aaaa_ctx); obj->aaaa_ctx=NULL; } if (obj->a_results){ belle_sip_freeaddrinfo(obj->a_results); obj->a_results=NULL; } if (obj->aaaa_results){ belle_sip_freeaddrinfo(obj->aaaa_results); obj->aaaa_results=NULL; } if (obj->name){ belle_sip_free(obj->name); obj->name=NULL; } } static void simple_resolver_cancel(belle_sip_resolver_context_t *obj){ belle_sip_main_loop_remove_source(obj->stack->ml,(belle_sip_source_t*)obj); belle_sip_object_unref(obj); } static void combined_resolver_cancel(belle_sip_resolver_context_t *p){ belle_sip_combined_resolver_context_t *obj=(belle_sip_combined_resolver_context_t*)p; if (obj->srv_ctx){ belle_sip_resolver_context_cancel(obj->srv_ctx); obj->srv_ctx=NULL; } if (obj->a_fallback_ctx){ belle_sip_resolver_context_cancel(obj->a_fallback_ctx); obj->a_fallback_ctx=NULL; } belle_sip_list_free_with_data(obj->srv_results,belle_sip_object_unref); obj->srv_results=NULL; belle_sip_object_unref(obj); } static void dual_resolver_cancel(belle_sip_resolver_context_t *p){ belle_sip_dual_resolver_context_t *obj=(belle_sip_dual_resolver_context_t*)p; if (obj->a_ctx){ belle_sip_resolver_context_cancel(obj->a_ctx); obj->a_ctx=NULL; } if (obj->aaaa_ctx){ belle_sip_resolver_context_cancel(obj->aaaa_ctx); obj->aaaa_ctx=NULL; } belle_sip_object_unref(p); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_resolver_context_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_resolver_context_t) { BELLE_SIP_VPTR_INIT(belle_sip_resolver_context_t,belle_sip_source_t,TRUE), (belle_sip_object_destroy_t) NULL, NULL, NULL }, NULL BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_simple_resolver_context_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_simple_resolver_context_t) { { BELLE_SIP_VPTR_INIT(belle_sip_simple_resolver_context_t,belle_sip_resolver_context_t,TRUE), (belle_sip_object_destroy_t) belle_sip_simple_resolver_context_destroy, NULL, NULL }, simple_resolver_cancel } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_dual_resolver_context_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_dual_resolver_context_t) { { BELLE_SIP_VPTR_INIT(belle_sip_dual_resolver_context_t,belle_sip_resolver_context_t,TRUE), (belle_sip_object_destroy_t) belle_sip_dual_resolver_context_destroy, NULL, NULL }, dual_resolver_cancel } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_combined_resolver_context_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_combined_resolver_context_t) { { BELLE_SIP_VPTR_INIT(belle_sip_combined_resolver_context_t,belle_sip_resolver_context_t,TRUE), (belle_sip_object_destroy_t) belle_sip_combined_resolver_context_destroy, NULL, NULL }, combined_resolver_cancel } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END static char * srv_prefix_from_transport(const char *transport) { char *prefix = ""; if (strcasecmp(transport, "udp") == 0) { prefix = "_sip._udp."; } else if (strcasecmp(transport, "tcp") == 0) { prefix = "_sip._tcp."; } else if (strcasecmp(transport, "tls") == 0) { prefix = "_sips._tcp."; } else { prefix = "_sip._udp."; } return prefix; } static void combined_notify_results(belle_sip_combined_resolver_context_t *obj){ obj->base.done=TRUE; obj->cb(obj->cb_data,obj->name,obj->final_results); obj->final_results=NULL; /*clean everything (cancel() does it very well)*/ combined_resolver_cancel((belle_sip_resolver_context_t*)obj); } static void process_a_fallback_result(void *data, const char *name, struct addrinfo *ai_list){ belle_sip_combined_resolver_context_t *ctx=(belle_sip_combined_resolver_context_t *)data; ctx->final_results=ai_list; combined_notify_results(ctx); } static void combined_resolver_context_check_finished(belle_sip_combined_resolver_context_t *obj){ belle_sip_list_t *elem; struct addrinfo *final=NULL; unsigned char finished=TRUE; for(elem=obj->srv_results;elem!=NULL;elem=elem->next){ belle_sip_dns_srv_t *srv=(belle_sip_dns_srv_t*)elem->data; if (!srv->a_done) { finished=FALSE; break; } } if (finished){ belle_sip_message("All A/AAAA results for combined resolution have arrived."); for(elem=obj->srv_results;elem!=NULL;elem=elem->next){ belle_sip_dns_srv_t *srv=(belle_sip_dns_srv_t*)elem->data; final=ai_list_append(final,srv->a_results); srv->a_results=NULL; } belle_sip_list_free_with_data(obj->srv_results,belle_sip_object_unref); obj->srv_results=NULL; obj->final_results=final; combined_notify_results(obj); } } static void process_a_from_srv(void *data, const char *name, struct addrinfo *ai_list){ belle_sip_dns_srv_t *srv=(belle_sip_dns_srv_t*)data; srv->a_results=ai_list; srv->a_done=TRUE; belle_sip_message("A query finished for srv result [%s]",srv->target); combined_resolver_context_check_finished(srv->root_resolver); } static void srv_resolve_a(belle_sip_combined_resolver_context_t *obj, belle_sip_dns_srv_t *srv){ belle_sip_message("Starting A/AAAA query for srv result [%s]",srv->target); srv->root_resolver=obj; /* take a ref of the srv object because the A resolution may terminate synchronously and destroy the srv object before to store the returned value of belle_sip_stack_resole_a(). That would lead to an invalid write */ belle_sip_object_ref(srv); srv->a_resolver=belle_sip_stack_resolve_a(obj->base.stack,srv->target,srv->port,obj->family,process_a_from_srv,srv); if (srv->a_resolver){ belle_sip_object_ref(srv->a_resolver); } belle_sip_object_unref(srv); } static void process_srv_results(void *data, const char *name, belle_sip_list_t *srv_results){ belle_sip_combined_resolver_context_t *ctx=(belle_sip_combined_resolver_context_t *)data; /*take a ref here, because the A resolution might succeed synchronously and terminate the context before exiting this function*/ belle_sip_object_ref(ctx); if (srv_results){ belle_sip_list_t *elem; /* take a ref of each srv_results because the last A resolution may terminate synchronously and destroy the list before the loop terminate */ ctx->srv_results = belle_sip_list_copy(srv_results); belle_sip_list_for_each(srv_results, (void(*)(void *))belle_sip_object_ref); for(elem=srv_results;elem!=NULL;elem=elem->next){ belle_sip_dns_srv_t *srv=(belle_sip_dns_srv_t*)elem->data; srv_resolve_a(ctx,srv); } srv_results = belle_sip_list_free_with_data(srv_results, belle_sip_object_unref); }else{ /*no SRV results, perform A query */ belle_sip_message("No SRV result for [%s], trying A/AAAA.",name); ctx->a_fallback_ctx=belle_sip_stack_resolve_a(ctx->base.stack,ctx->name,ctx->port,ctx->family,process_a_fallback_result,ctx); if (ctx->a_fallback_ctx) belle_sip_object_ref(ctx->a_fallback_ctx); } belle_sip_object_unref(ctx); } /** * Perform combined SRV + A / AAAA resolution. **/ belle_sip_resolver_context_t * belle_sip_stack_resolve(belle_sip_stack_t *stack, const char *transport, const char *name, int port, int family, belle_sip_resolver_callback_t cb, void *data) { struct addrinfo *res = belle_sip_ip_address_to_addrinfo(family, name, port); if (res == NULL) { /* First perform asynchronous DNS SRV query */ belle_sip_combined_resolver_context_t *ctx = belle_sip_object_new(belle_sip_combined_resolver_context_t); belle_sip_resolver_context_init((belle_sip_resolver_context_t*)ctx,stack); belle_sip_object_ref(ctx);/*we don't want the object to be destroyed until the end of this function*/ ctx->cb=cb; ctx->cb_data = data; ctx->name = belle_sip_strdup(name); ctx->port=port; if (family == 0) family = AF_UNSPEC; ctx->family = family; /*take a ref for the entire duration of the DNS procedure, it will be released when it is finished*/ belle_sip_object_ref(ctx); ctx->srv_ctx=belle_sip_stack_resolve_srv(stack,transport,name,process_srv_results,ctx); if (ctx->srv_ctx) belle_sip_object_ref(ctx->srv_ctx); if (ctx->base.done){ belle_sip_object_unref(ctx); return NULL; } belle_sip_object_unref(ctx); return BELLE_SIP_RESOLVER_CONTEXT(ctx); } else { /* There is no resolve to be done */ cb(data, name, res); return NULL; } } static belle_sip_resolver_context_t * belle_sip_stack_resolve_single(belle_sip_stack_t *stack, const char *name, int port, int family, int flags, belle_sip_resolver_callback_t cb , void *data){ /* Then perform asynchronous DNS A or AAAA query */ belle_sip_simple_resolver_context_t *ctx = belle_sip_object_new(belle_sip_simple_resolver_context_t); belle_sip_resolver_context_init((belle_sip_resolver_context_t*)ctx,stack); ctx->cb_data = data; ctx->cb = cb; ctx->name = belle_sip_strdup(name); ctx->port = port; ctx->flags = flags; if (family == 0) family = AF_UNSPEC; ctx->family = family; ctx->type = (ctx->family == AF_INET6) ? DNS_T_AAAA : DNS_T_A; #ifdef USE_GETADDRINFO_FALLBACK belle_sip_mutex_init(&ctx->getaddrinfo_mutex, NULL); #ifdef WIN32 ctx->ctlevent = (belle_sip_fd_t)-1; #endif #endif return (belle_sip_resolver_context_t*)resolver_start_query(ctx); } static void notify_dual_results(belle_sip_dual_resolver_context_t *ctx){ if (ctx->a_done && ctx->aaaa_done){ struct addrinfo *results=ctx->aaaa_results; results=ai_list_append(results,ctx->a_results); ctx->a_results=NULL; ctx->aaaa_results=NULL; ctx->base.done=TRUE; ctx->cb(ctx->cb_data,ctx->name,results); belle_sip_object_unref(ctx); } } static void on_ipv4_results(void *data, const char *name, struct addrinfo *ai_list){ belle_sip_dual_resolver_context_t *ctx=(belle_sip_dual_resolver_context_t *)data; ctx->a_done=TRUE; ctx->a_results=ai_list; notify_dual_results(ctx); } static void on_ipv6_results(void *data, const char *name, struct addrinfo *ai_list){ belle_sip_dual_resolver_context_t *ctx=(belle_sip_dual_resolver_context_t *)data; ctx->aaaa_done=TRUE; ctx->aaaa_results=ai_list; notify_dual_results(ctx); } static belle_sip_resolver_context_t * belle_sip_stack_resolve_dual(belle_sip_stack_t *stack, const char *name, int port, belle_sip_resolver_callback_t cb , void *data){ /* Then perform asynchronous DNS A or AAAA query */ belle_sip_dual_resolver_context_t *ctx = belle_sip_object_new(belle_sip_dual_resolver_context_t); belle_sip_resolver_context_init((belle_sip_resolver_context_t*)ctx,stack); belle_sip_object_ref(ctx);/*we don't want the object to be destroyed until the end of this function*/ ctx->cb_data = data; ctx->cb = cb; ctx->name = belle_sip_strdup(name); /*take a ref for the entire duration of the DNS procedure, it will be released when it is finished*/ belle_sip_object_ref(ctx); ctx->a_ctx=belle_sip_stack_resolve_single(stack,name,port,AF_INET, AI_V4MAPPED, on_ipv4_results,ctx); if (ctx->a_ctx) belle_sip_object_ref(ctx->a_ctx); ctx->aaaa_ctx=belle_sip_stack_resolve_single(stack, name, port, AF_INET6, 0, on_ipv6_results, ctx); if (ctx->aaaa_ctx) belle_sip_object_ref(ctx->aaaa_ctx); if (ctx->base.done){ /*all results were found synchronously*/ belle_sip_object_unref(ctx); ctx=NULL; }else belle_sip_object_unref(ctx); return BELLE_SIP_RESOLVER_CONTEXT(ctx); } belle_sip_resolver_context_t * belle_sip_stack_resolve_a(belle_sip_stack_t *stack, const char *name, int port, int family, belle_sip_resolver_callback_t cb , void *data) { struct addrinfo *res = belle_sip_ip_address_to_addrinfo(family, name, port); if (res == NULL) { switch(family){ case AF_UNSPEC: family=AF_INET6; case AF_INET6: return belle_sip_stack_resolve_dual(stack,name,port,cb,data); break; case AF_INET: return belle_sip_stack_resolve_single(stack,name,port,AF_INET,0,cb,data); break; default: belle_sip_error("belle_sip_stack_resolve_a(): unsupported address family [%i]",family); } } else { /* There is no resolve to be done */ cb(data, name, res); } return NULL; } belle_sip_resolver_context_t * belle_sip_stack_resolve_srv(belle_sip_stack_t *stack, const char *transport, const char *name, belle_sip_resolver_srv_callback_t cb, void *data) { belle_sip_simple_resolver_context_t *ctx = belle_sip_object_new(belle_sip_simple_resolver_context_t); belle_sip_resolver_context_init((belle_sip_resolver_context_t*)ctx,stack); ctx->srv_cb_data = data; ctx->srv_cb = cb; ctx->name = belle_sip_concat(srv_prefix_from_transport(transport), name, NULL); ctx->type = DNS_T_SRV; return (belle_sip_resolver_context_t*)resolver_start_query(ctx); } void belle_sip_resolver_context_cancel(belle_sip_resolver_context_t *obj){ BELLE_SIP_OBJECT_VPTR(obj,belle_sip_resolver_context_t)->cancel(obj); } /* This function does the connect() method to get local ip address suitable to reach a given destination. It works on all platform except for windows using ipv6 sockets. TODO: find a workaround for win32+ipv6 socket */ void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen, int local_port){ int af_type=dest->sa_family; int sock=socket(af_type,SOCK_DGRAM,IPPROTO_UDP); belle_sip_message("belle_sip_get_src_addr_for(): af_inet6=%i",af_type==AF_INET6); if (sock==(belle_sip_socket_t)-1){ belle_sip_fatal("Could not create socket: %s",belle_sip_get_socket_error_string()); goto fail; } if (af_type==AF_INET6 && (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)dest)->sin6_addr))){ /*this is actually required only for windows, who is enable to provide an ipv4 mapped local address if the remote is ipv4 mapped, and unable to provide a correct local address if the remote address is true ipv6 address when in dual stack mode*/ belle_sip_socket_enable_dual_stack(sock); } if (connect(sock,dest,destlen)==-1){ belle_sip_error("belle_sip_get_src_addr_for: connect() failed: %s",belle_sip_get_socket_error_string()); goto fail; } if (getsockname(sock,src,srclen)==-1){ belle_sip_error("belle_sip_get_src_addr_for: getsockname() failed: %s",belle_sip_get_socket_error_string()); goto fail; } if (af_type==AF_INET6){ struct sockaddr_in6 *sin6=(struct sockaddr_in6*)src; sin6->sin6_port=htons(local_port); }else{ struct sockaddr_in *sin=(struct sockaddr_in*)src; sin->sin_port=htons(local_port); } close_socket(sock); return; fail: { struct addrinfo *res = belle_sip_ip_address_to_addrinfo(af_type, af_type == AF_INET ? "127.0.0.1" : "::1", local_port); if (res != NULL) { memcpy(src,res->ai_addr,MIN((size_t)*srclen,res->ai_addrlen)); *srclen=res->ai_addrlen; belle_sip_freeaddrinfo(res); } else { belle_sip_fatal("belle_sip_get_src_addr_for(): belle_sip_ip_address_to_addrinfo() failed"); } } if (sock!=(belle_sip_socket_t)-1) close_socket(sock); } #ifndef IN6_GET_ADDR_V4MAPPED #define IN6_GET_ADDR_V4MAPPED(sin6_addr) *(unsigned int*)((unsigned char*)(sin6_addr)+12) #endif void belle_sip_address_remove_v4_mapping(const struct sockaddr *v6, struct sockaddr *result, socklen_t *result_len){ if (v6->sa_family==AF_INET6){ struct sockaddr_in6 *in6=(struct sockaddr_in6*)v6; if (IN6_IS_ADDR_V4MAPPED(&in6->sin6_addr)){ struct sockaddr_in *in=(struct sockaddr_in*)result; result->sa_family=AF_INET; in->sin_addr.s_addr = IN6_GET_ADDR_V4MAPPED(&in6->sin6_addr); in->sin_port=in6->sin6_port; *result_len=sizeof(struct sockaddr_in); }else{ if (v6!=result) memcpy(result,v6,sizeof(struct sockaddr_in6)); *result_len=sizeof(struct sockaddr_in6); } }else{ *result_len=sizeof(struct sockaddr_in); if (v6!=result) memcpy(result,v6,sizeof(struct sockaddr_in)); } } belle-sip-1.4.1/src/belle_sip_uri_impl.c000066400000000000000000000457141252242224000201700ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/sip-uri.h" #include "belle-sip/parameters.h" #include #include #include #include "grammars/belle_sip_messageParser.h" #include "grammars/belle_sip_messageLexer.h" #include "belle_sip_internal.h" #include "listeningpoint_internal.h" #define SIP_URI_GET_SET_STRING(attribute) GET_SET_STRING(belle_sip_uri,attribute) #define SIP_URI_GET_SET_STRING_PARAM(attribute) GET_SET_STRING_PARAM2(belle_sip_uri,attribute,attribute##_param) #define SIP_URI_GET_SET_UINT(attribute) GET_SET_INT(belle_sip_uri,attribute,unsigned int) #define SIP_URI_GET_SET_INT(attribute) GET_SET_INT(belle_sip_uri,attribute,int) #define SIP_URI_GET_SET_INT_PARAM(attribute) GET_SET_INT_PARAM2(belle_sip_uri,attribute,int,attribute##_param) #define SIP_URI_GET_SET_BOOL(attribute) GET_SET_BOOL(belle_sip_uri,attribute,is) #define SIP_URI_HAS_SET_BOOL(attribute) GET_SET_BOOL(belle_sip_uri,attribute,has) #define SIP_URI_HAS_SET_BOOL_PARAM(attribute) GET_SET_BOOL_PARAM2(belle_sip_uri,attribute,has,attribute##_param) struct _belle_sip_uri { belle_sip_parameters_t params; unsigned int secure; char* user; char* user_password; char* host; int port; belle_sip_parameters_t * header_list; }; static void belle_sip_uri_destroy(belle_sip_uri_t* uri) { if (uri->user) belle_sip_free (uri->user); if (uri->host) belle_sip_free (uri->host); if (uri->user_password) belle_sip_free (uri->user_password); belle_sip_object_unref(BELLE_SIP_OBJECT(uri->header_list)); } static void belle_sip_uri_clone(belle_sip_uri_t* uri, const belle_sip_uri_t *orig){ uri->secure=orig->secure; uri->user=orig->user?belle_sip_strdup(orig->user):NULL; uri->user_password=orig->user_password?belle_sip_strdup(orig->user_password):NULL; uri->host=orig->host?belle_sip_strdup(orig->host):NULL; uri->port=orig->port; if (orig->header_list){ uri->header_list=(belle_sip_parameters_t*)belle_sip_object_clone(BELLE_SIP_OBJECT(orig->header_list)); belle_sip_object_ref(uri->header_list); } } static void encode_params(belle_sip_param_pair_t* container, belle_sip_list_t** newlist) { char *escapedName = belle_sip_uri_to_escaped_parameter(container->name); char *escapedValue = container->value? belle_sip_uri_to_escaped_parameter(container->value) : NULL; *newlist = belle_sip_list_append(*newlist, belle_sip_param_pair_new(escapedName, escapedValue)); if (escapedName) free(escapedName); if (escapedValue) free(escapedValue); } static void encode_headers(belle_sip_param_pair_t* container, belle_sip_list_t** newlist) { char *escapedName = belle_sip_uri_to_escaped_header(container->name); char *escapedValue = container->value? belle_sip_uri_to_escaped_header(container->value) : NULL; *newlist = belle_sip_list_append(*newlist, belle_sip_param_pair_new(escapedName, escapedValue)); if (escapedName) free(escapedName); if (escapedValue) free(escapedValue); } belle_sip_error_code belle_sip_uri_marshal(const belle_sip_uri_t* uri, char* buff, size_t buff_size, size_t *offset) { const belle_sip_list_t* list; belle_sip_error_code error=BELLE_SIP_OK; error=belle_sip_snprintf(buff,buff_size,offset,"%s:",uri->secure?"sips":"sip"); if (error!=BELLE_SIP_OK) return error; if (uri->user && uri->user[0]!='\0') { char* escaped_username=belle_sip_uri_to_escaped_username(uri->user); error=belle_sip_snprintf(buff,buff_size,offset,"%s",escaped_username); belle_sip_free(escaped_username); if (error!=BELLE_SIP_OK) return error; if (uri->user_password) { char* escaped_password=belle_sip_uri_to_escaped_userpasswd(uri->user_password); error=belle_sip_snprintf(buff,buff_size,offset,":%s",escaped_password); belle_sip_free(escaped_password); if (error!=BELLE_SIP_OK) return error; } error=belle_sip_snprintf(buff,buff_size,offset,"@"); if (error!=BELLE_SIP_OK) return error; } if (uri->host) { if (strchr(uri->host,':')) { /*ipv6*/ error=belle_sip_snprintf(buff,buff_size,offset,"[%s]",uri->host); } else { error=belle_sip_snprintf(buff,buff_size,offset,"%s",uri->host); } if (error!=BELLE_SIP_OK) return error; } else { belle_sip_warning("no host found in this uri"); } if (uri->port!=0) { error=belle_sip_snprintf(buff,buff_size,offset,":%i",uri->port); if (error!=BELLE_SIP_OK) return error; } { belle_sip_parameters_t *encparams = belle_sip_parameters_new(); belle_sip_list_for_each2(uri->params.param_list, (void (*)(void *, void *))encode_params, &encparams->param_list); error=belle_sip_parameters_marshal(encparams,buff,buff_size,offset); belle_sip_object_unref(encparams); if (error!=BELLE_SIP_OK) return error; } { belle_sip_list_t * encheaders = NULL; belle_sip_list_for_each2(uri->header_list->param_list, (void (*)(void *, void *))encode_headers, &encheaders); for(list=encheaders;list!=NULL;list=list->next){ belle_sip_param_pair_t* container = list->data; if (list == encheaders) { //first case error=belle_sip_snprintf(buff,buff_size,offset,"?%s=%s",container->name,container->value?container->value:""); } else { //subsequent headers error=belle_sip_snprintf(buff,buff_size,offset,"&%s=%s",container->name,container->value?container->value:""); } if (error!=BELLE_SIP_OK) break; } belle_sip_list_free_with_data(encheaders,(void (*)(void*))belle_sip_param_pair_destroy); } return error; } BELLE_SIP_PARSE(uri); BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_uri_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_uri_t,belle_sip_parameters_t,belle_sip_uri_destroy,belle_sip_uri_clone,belle_sip_uri_marshal,TRUE); belle_sip_uri_t* belle_sip_uri_new () { belle_sip_uri_t* l_object = belle_sip_object_new(belle_sip_uri_t); belle_sip_parameters_init((belle_sip_parameters_t*)l_object); /*super*/ l_object->header_list = belle_sip_parameters_new(); belle_sip_object_ref(l_object->header_list); return l_object; } belle_sip_uri_t* belle_sip_uri_create (const char* username,const char* host) { belle_sip_uri_t* uri = belle_sip_uri_new(); belle_sip_uri_set_user(uri,username); belle_sip_uri_set_host(uri,host); return uri; } char* belle_sip_uri_to_string(const belle_sip_uri_t* uri) { return belle_sip_object_to_string(BELLE_SIP_OBJECT(uri)); } const char* belle_sip_uri_get_header(const belle_sip_uri_t* uri,const char* name) { return belle_sip_parameters_get_parameter(uri->header_list,name); } void belle_sip_uri_set_header(belle_sip_uri_t* uri,const char* name,const char* value) { belle_sip_parameters_set_parameter(uri->header_list,name,value); } void belle_sip_uri_remove_header(belle_sip_uri_t *uri, const char *name){ belle_sip_parameters_remove_parameter(uri->header_list,name); } const belle_sip_list_t* belle_sip_uri_get_header_names(const belle_sip_uri_t* uri) { return belle_sip_parameters_get_parameter_names(uri->header_list); } int belle_sip_uri_get_listening_port(const belle_sip_uri_t *uri){ int port=belle_sip_uri_get_port(uri); const char *transport=belle_sip_uri_get_transport_param(uri); if (!transport) { transport=belle_sip_uri_is_secure(uri)?"tls":"udp"; } if (port==0) port=belle_sip_listening_point_get_well_known_port(transport); return port; } void belle_sip_uri_fix(belle_sip_uri_t *uri){ /*nop, to be removed*/ } SIP_URI_GET_SET_BOOL(secure) SIP_URI_GET_SET_STRING(user) SIP_URI_GET_SET_STRING(user_password) SIP_URI_GET_SET_STRING(host) SIP_URI_GET_SET_INT(port) SIP_URI_GET_SET_STRING_PARAM(transport) SIP_URI_GET_SET_STRING_PARAM(user) SIP_URI_GET_SET_STRING_PARAM(method) SIP_URI_GET_SET_STRING_PARAM(maddr) SIP_URI_GET_SET_INT_PARAM(ttl) SIP_URI_HAS_SET_BOOL_PARAM(lr) const belle_sip_parameters_t* belle_sip_uri_get_headers(const belle_sip_uri_t* uri) { return uri->header_list; } void belle_sip_uri_headers_clean(belle_sip_uri_t* uri) { belle_sip_parameters_clean(uri->header_list); } static int uri_strncmp_common(const char*a,const char*b,size_t n,int case_sensitive) { int result=0; size_t index_a=0,index_b=0; char char_a,char_b; while (a[index_a]!='\0'&&b[index_b]!='\0'&&index_a0x60) char_a-=0x20; if (!case_sensitive && char_b<0x7B && char_b>0x60) char_b-=0x20; result+=(char_a!=char_b); } return result; } static int uri_strncmp(const char*a,const char*b,size_t n) { return uri_strncmp_common(a,b,n,1); } static int uri_strncasecmp(const char*a,const char*b,size_t n) { return uri_strncmp_common(a,b,n,0); } #define IS_EQUAL(a,b) uri_strncmp(a,b,MIN(strlen(a),strlen(b)))!=0 #define IS_EQUAL_CASE(a,b) uri_strncasecmp(a,b,MIN(strlen(a),strlen(b)))!=0 #define PARAM_CASE_CMP(uri_a,uri_b,param) \ a_param=belle_sip_parameters_get_case_parameter((belle_sip_parameters_t*) uri_a,param); \ b_param=belle_sip_parameters_get_case_parameter((belle_sip_parameters_t*) uri_b,param);\ if (a_param && b_param) { \ if (IS_EQUAL_CASE(a_param,b_param)) return 0; \ } else if (a_param != b_param) {\ return 0;\ } /* * RFC 3261 SIP: Session Initiation Protocol June 2002 * 19.1.4 URI Comparison Some operations in this specification require determining whether two SIP or SIPS URIs are equivalent. In this specification, registrars need to compare bindings in Contact URIs in REGISTER requests (see Section 10.3.). SIP and SIPS URIs are compared for equality according to the following rules: */ int belle_sip_uri_equals(const belle_sip_uri_t* uri_a,const belle_sip_uri_t* uri_b) { const belle_sip_list_t * params; const char* b_param; const char* a_param; /* o A SIP and SIPS URI are never equivalent. */ if (belle_sip_uri_is_secure(uri_a)!=belle_sip_uri_is_secure(uri_b)) { return 0; } /* o Comparison of the userinfo of SIP and SIPS URIs is case- sensitive. This includes userinfo containing passwords or formatted as telephone-subscribers. Comparison of all other components of the URI is case-insensitive unless explicitly defined otherwise. */ if (uri_a->user && uri_b->user) { if (IS_EQUAL(uri_a->user,uri_b->user)) return 0; } else if (uri_a->user != uri_a->user) { return 0; } /* o The ordering of parameters and header fields is not significant in comparing SIP and SIPS URIs. o Characters other than those in the "reserved" set (see RFC 2396 [5]) are equivalent to their ""%" HEX HEX" encoding. o An IP address that is the result of a DNS lookup of a host name does not match that host name. o For two URIs to be equal, the user, password, host, and port components must match. */ if (!uri_a->host || !uri_b->host) { return 0; } else if (IS_EQUAL_CASE(uri_a->host,uri_b->host)) { return 0; } if (uri_a->port !=uri_b->port) return 0; /* A URI omitting the user component will not match a URI that includes one. A URI omitting the password component will not match a URI that includes one. A URI omitting any component with a default value will not match a URI explicitly containing that component with its default value. For instance, a URI omitting the optional port component will not match a URI explicitly declaring port 5060. The same is true for the transport-parameter, ttl-parameter, user-parameter, and method components. Defining sip:user@host to not be equivalent to sip:user@host:5060 is a change from RFC 2543. When deriving addresses from URIs, equivalent addresses are expected from equivalent URIs. The URI sip:user@host:5060 will always resolve to port 5060. The URI sip:user@host may resolve to other ports through the DNS SRV mechanisms detailed in [4]. o URI uri-parameter components are compared as follows: - Any uri-parameter appearing in both URIs must match. */ /* * - A user, ttl, or method uri-parameter appearing in only one URI never matches, even if it contains the default value. - A URI that includes an maddr parameter will not match a URI that contains no maddr parameter. * */ PARAM_CASE_CMP(uri_a,uri_b,"transport") PARAM_CASE_CMP(uri_a,uri_b,"user") PARAM_CASE_CMP(uri_a,uri_b,"ttl") PARAM_CASE_CMP(uri_a,uri_b,"method") PARAM_CASE_CMP(uri_a,uri_b,"maddr") for(params=belle_sip_parameters_get_parameters((belle_sip_parameters_t*) uri_a);params!=NULL;params=params->next) { if ((b_param=belle_sip_parameters_get_parameter((belle_sip_parameters_t*) uri_b,(const char*)params->data)) !=NULL) { if (IS_EQUAL_CASE(b_param,(const char*)params->data)) return 0; } } /* - All other uri-parameters appearing in only one URI are ignored when comparing the URIs. */ /* *fixme ignored for now*/ /* o URI header components are never ignored. Any present header component MUST be present in both URIs and match for the URIs to match. The matching rules are defined for each header field in Section 20. */ return 1; } /*uri checker*/ /* * From 19.1.1 SIP and SIPS URI Components * dialog reg./redir. Contact/ default Req.-URI To From Contact R-R/Route external user -- o o o o o o password -- o o o o o o host -- m m m m m m port (1) o - - o o o user-param ip o o o o o o method INVITE - - - - - o maddr-param -- o - - o o o ttl-param 1 o - - o - o transp.-param (2) o - - o o o lr-param -- o - - - o o other-param -- o o o o o o headers -- - - - o - o (1): The default port value is transport and scheme dependent. The default is 5060 for sip: using UDP, TCP, or SCTP. The default is 5061 for sip: using TLS over TCP and sips: over TCP. (2): The default transport is scheme dependent. For sip:, it is UDP. For sips:, it is TCP. Table 1: Use and default values of URI components for SIP header field values, Request-URI and references*/ typedef enum { m /*mandotory*/ , o /*optionnal*/ , na /*not allowd*/ } mark; static const char* mark_to_string(mark value) { switch (value) { case o: return "optionnal"; case m: return "mandatory"; case na: return "not allowed"; } return "unknown"; } typedef struct uri_components { const char * name; mark user; mark password; mark host; mark port; mark user_param; mark method; mark maddr_param; mark ttl_param; mark transp_param; mark lr_param; mark other_param; mark headers; } uri_components_t; /*belle sip allows contact header without host because stack will auutomatically put host if missing*/ static uri_components_t uri_component_use_for_request = {"Req.-URI" ,o ,o ,m ,o ,o ,na ,o ,o ,o ,o ,o ,na}; static uri_components_t uri_component_use_for_header_to = {"Header To" ,o ,o ,m ,na ,o ,na ,na ,na ,na ,na ,o ,na}; static uri_components_t uri_component_use_for_header_from = {"Header From" ,o ,o ,m ,na ,o ,na ,na ,na ,na ,na ,o ,na}; static uri_components_t uri_component_use_for_contact_in_reg = {"Contact in REG" ,o ,o ,/*m*/o ,o ,o ,na ,o ,o ,o ,na ,o ,o}; static uri_components_t uri_component_use_for_dialog_ct_rr_ro = {"Dialog Contact/R-R/Route" ,o ,o ,/*m*/o ,o ,o ,na ,o ,na ,o ,o ,o ,na}; static uri_components_t uri_component_use_for_external = {"External" ,o ,o ,m ,o ,o ,o ,o ,o ,o ,o ,o ,o}; static int check_component(int is_present,mark requirement) { switch (requirement) { case o: return TRUE; case m: return is_present; case na: return !is_present; } return 0; } #define CHECK_URI_COMPONENT(uri_component,uri_component_name,component_use_rule,component_use_rule_name) \ if (!check_component(uri_component,component_use_rule)) {\ belle_sip_error("Uri component [%s] does not follow reqs [%s] for context [%s]", uri_component_name,mark_to_string(component_use_rule),component_use_rule_name);\ return FALSE;\ } static int check_uri_components(const belle_sip_uri_t* uri, const uri_components_t* components_use) { CHECK_URI_COMPONENT(uri->user!=NULL,"user",components_use->user,components_use->name) CHECK_URI_COMPONENT(uri->host!=NULL,"host",components_use->host,components_use->name) CHECK_URI_COMPONENT(uri->port>0,"port",components_use->port,components_use->name) CHECK_URI_COMPONENT(belle_sip_parameters_has_parameter(&uri->params,"maddr"),"maddr-param",components_use->maddr_param,components_use->name) CHECK_URI_COMPONENT(belle_sip_parameters_has_parameter(&uri->params,"ttl"),"ttl-param",components_use->ttl_param,components_use->name) CHECK_URI_COMPONENT(belle_sip_parameters_has_parameter(&uri->params,"transport"),"transp.-param",components_use->transp_param,components_use->name) CHECK_URI_COMPONENT(belle_sip_parameters_has_parameter(&uri->params,"lr"),"lr-param",components_use->lr_param,components_use->name) /*..*/ CHECK_URI_COMPONENT(belle_sip_list_size(belle_sip_parameters_get_parameters(uri->header_list))>0,"headers",components_use->headers,components_use->name) return TRUE; } /*return 0 if not compliant*/ int belle_sip_uri_check_components_from_request_uri(const belle_sip_uri_t* uri) { return check_uri_components(uri,&uri_component_use_for_request); } int belle_sip_uri_check_components_from_context(const belle_sip_uri_t* uri,const char* method,const char* header_name) { if (strcasecmp(BELLE_SIP_FROM,header_name)==0) return check_uri_components(uri,&uri_component_use_for_header_from); else if (strcasecmp(BELLE_SIP_TO,header_name)==0) return check_uri_components(uri,&uri_component_use_for_header_to); else if (strcasecmp(BELLE_SIP_CONTACT,header_name)==0 && method && strcasecmp("REGISTER",method)==0) return check_uri_components(uri,&uri_component_use_for_contact_in_reg); else if (strcasecmp(BELLE_SIP_CONTACT,header_name)==0 || strcasecmp(BELLE_SIP_RECORD_ROUTE,header_name)==0 || strcasecmp(BELLE_SIP_ROUTE,header_name)==0) return check_uri_components(uri,&uri_component_use_for_dialog_ct_rr_ro); else return check_uri_components(uri,&uri_component_use_for_external); } belle-sip-1.4.1/src/belle_sip_utils.c000066400000000000000000001026601252242224000175020ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define _CRT_RAND_S #include #include #include #include "belle_sip_internal.h" #include "clock_gettime.h" /*for apple*/ #ifndef WIN32 #include #include /*for gettimeofday*/ #include /* available on POSIX system only */ #else #include #endif static FILE *__log_file=0; /** *@param file a FILE pointer where to output the belle logs. * **/ void belle_sip_set_log_file(FILE *file) { __log_file=file; } static void __belle_sip_logv_out(belle_sip_log_level lev, const char *fmt, va_list args); belle_sip_log_function_t belle_sip_logv_out=__belle_sip_logv_out; /** *@param func: your logging function, compatible with the OrtpLogFunc prototype. * **/ void belle_sip_set_log_handler(belle_sip_log_function_t func){ belle_sip_logv_out=func; } belle_sip_log_function_t belle_sip_get_log_handler(){ return belle_sip_logv_out; } unsigned int __belle_sip_log_mask=BELLE_SIP_LOG_WARNING|BELLE_SIP_LOG_ERROR|BELLE_SIP_LOG_FATAL; /** * @ param level: either BELLE_SIP_LOG_DEBUG, BELLE_SIP_LOG_MESSAGE, BELLE_SIP_LOG_WARNING, BELLE_SIP_LOG_ERROR * BELLE_SIP_LOG_FATAL . **/ void belle_sip_set_log_level(int level){ __belle_sip_log_mask=(level<<1)-1; } char * belle_sip_strdup_vprintf(const char *fmt, va_list ap) { /* Guess we need no more than 100 bytes. */ int n, size = 200; char *p,*np; #ifndef WIN32 va_list cap;/*copy of our argument list: a va_list cannot be re-used (SIGSEGV on linux 64 bits)*/ #endif if ((p = (char *) malloc (size)) == NULL) return NULL; while (1) { /* Try to print in the allocated space. */ #ifndef WIN32 va_copy(cap,ap); n = vsnprintf (p, size, fmt, cap); va_end(cap); #else /*this works on 32 bits, luckily*/ n = vsnprintf (p, size, fmt, ap); #endif /* If that worked, return the string. */ if (n > -1 && n < size) return p; //printf("Reallocing space.\n"); /* Else try again with more space. */ if (n > -1) /* glibc 2.1 */ size = n + 1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ if ((np = (char *) realloc (p, size)) == NULL) { free(p); return NULL; } else { p = np; } } } char *belle_sip_strdup_printf(const char *fmt,...){ char *ret; va_list args; va_start (args, fmt); ret=belle_sip_strdup_vprintf(fmt, args); va_end (args); return ret; } char * belle_sip_strcat_vprintf(char* dst, const char *fmt, va_list ap){ char *ret; unsigned long dstlen, retlen; ret=belle_sip_strdup_vprintf(fmt, ap); dstlen = strlen(dst); retlen = strlen(ret); if ((dst = belle_sip_realloc(dst, dstlen+retlen+1)) != NULL){ strncat(dst,ret,retlen); dst[dstlen+retlen] = '\0'; belle_sip_free(ret); return dst; } else { belle_sip_free(ret); return NULL; } } char *belle_sip_strcat_printf(char* dst, const char *fmt,...){ char *ret; va_list args; va_start (args, fmt); ret=belle_sip_strcat_vprintf(dst, fmt, args); va_end (args); return ret; } belle_sip_error_code belle_sip_snprintf(char *buff, size_t buff_size, size_t *offset, const char *fmt, ...) { belle_sip_error_code ret; va_list args; va_start(args, fmt); ret = belle_sip_snprintf_valist(buff, buff_size, offset, fmt, args); va_end(args); return ret; } belle_sip_error_code belle_sip_snprintf_valist(char *buff, size_t buff_size, size_t *offset, const char *fmt, va_list args) { int ret; belle_sip_error_code error = BELLE_SIP_OK; ret = vsnprintf(buff + *offset, buff_size - *offset, fmt, args); if ((ret < 0) || (ret >= (buff_size - *offset))) { error = BELLE_SIP_BUFFER_OVERFLOW; *offset = buff_size; } else { *offset += ret; } return error; } #if defined(WIN32) || defined(_WIN32_WCE) #define ENDLINE "\r\n" #else #define ENDLINE "\n" #endif #if defined(WIN32) || defined(_WIN32_WCE) void belle_sip_logv(int level, const char *fmt, va_list args) { if (belle_sip_logv_out!=NULL && belle_sip_log_level_enabled(level)) belle_sip_logv_out(level,fmt,args); if ((level)==BELLE_SIP_LOG_FATAL) abort(); } #endif #ifdef WIN32 static int belle_sip_gettimeofday (struct timeval *tv, void* tz) { union { __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ FILETIME fileTime; } now; GetSystemTimeAsFileTime (&now.fileTime); tv->tv_usec = (long) ((now.ns100 / 10LL) % 1000000LL); tv->tv_sec = (long) ((now.ns100 - 116444736000000000LL) / 10000000LL); return 0; } #else #define belle_sip_gettimeofday gettimeofday #endif static void __belle_sip_logv_out(belle_sip_log_level lev, const char *fmt, va_list args){ const char *lname="undef"; char *msg; struct timeval tp; struct tm *lt; #ifndef WIN32 struct tm tmstorage; #endif time_t curtime; belle_sip_gettimeofday(&tp,NULL); curtime=tp.tv_sec; #ifdef WIN32 lt = localtime(&curtime); #else lt = localtime_r(&curtime,&tmstorage); #endif if (__log_file==NULL) __log_file=stderr; switch(lev){ case BELLE_SIP_LOG_DEBUG: lname="debug"; break; case BELLE_SIP_LOG_MESSAGE: lname="message"; break; case BELLE_SIP_LOG_WARNING: lname="warning"; break; case BELLE_SIP_LOG_ERROR: lname="error"; break; case BELLE_SIP_LOG_FATAL: lname="fatal"; break; default: belle_sip_fatal("Bad level !"); } msg=belle_sip_strdup_vprintf(fmt,args); #if defined(_MSC_VER) && !defined(_WIN32_WCE) #ifndef _UNICODE OutputDebugStringA(msg); OutputDebugStringA("\r\n"); #else { int len=strlen(msg); wchar_t *tmp=(wchar_t*)belle_sip_malloc((len+1)*sizeof(wchar_t)); mbstowcs(tmp,msg,len); OutputDebugStringW(tmp); OutputDebugStringW(L"\r\n"); belle_sip_free(tmp); } #endif #endif fprintf(__log_file,"%i-%.2i-%.2i %.2i:%.2i:%.2i:%.3i belle-sip-%s-%s" ENDLINE,1900+lt->tm_year,lt->tm_mon+1,lt->tm_mday,lt->tm_hour,lt->tm_min,lt->tm_sec,(int)(tp.tv_usec/1000), lname,msg); fflush(__log_file); free(msg); } belle_sip_list_t* belle_sip_list_new(void *data){ belle_sip_list_t* new_elem=belle_sip_new0(belle_sip_list_t); new_elem->data=data; return new_elem; } belle_sip_list_t* belle_sip_list_append_link(belle_sip_list_t* elem,belle_sip_list_t *new_elem){ belle_sip_list_t* it=elem; if (elem==NULL) return new_elem; if (new_elem==NULL) return elem; while (it->next!=NULL) it=belle_sip_list_next(it); it->next=new_elem; new_elem->prev=it; return elem; } belle_sip_list_t* belle_sip_list_append(belle_sip_list_t* elem, void * data){ belle_sip_list_t* new_elem=belle_sip_list_new(data); return belle_sip_list_append_link(elem,new_elem); } belle_sip_list_t* belle_sip_list_prepend(belle_sip_list_t* elem, void *data){ belle_sip_list_t* new_elem=belle_sip_list_new(data); if (elem!=NULL) { new_elem->next=elem; elem->prev=new_elem; } return new_elem; } belle_sip_list_t * belle_sip_list_last_elem(const belle_sip_list_t *l){ if (l==NULL) return NULL; while(l->next){ l=l->next; } return (belle_sip_list_t*)l; } belle_sip_list_t* belle_sip_list_concat(belle_sip_list_t* first, belle_sip_list_t* second){ belle_sip_list_t* it=first; if (it==NULL) return second; if (second==NULL) return first; while(it->next!=NULL) it=belle_sip_list_next(it); it->next=second; second->prev=it; return first; } belle_sip_list_t* belle_sip_list_free(belle_sip_list_t* list){ belle_sip_list_t* elem = list; belle_sip_list_t* tmp; if (list==NULL) return NULL; while(elem->next!=NULL) { tmp = elem; elem = elem->next; belle_sip_free(tmp); } belle_sip_free(elem); return NULL; } belle_sip_list_t * belle_sip_list_free_with_data(belle_sip_list_t *list, void (*freefunc)(void*)){ belle_sip_list_t* elem = list; belle_sip_list_t* tmp; if (list==NULL) return NULL; while(elem->next!=NULL) { tmp = elem; elem = elem->next; freefunc(tmp->data); belle_sip_free(tmp); } freefunc(elem->data); belle_sip_free(elem); return NULL; } belle_sip_list_t* _belle_sip_list_remove(belle_sip_list_t* first, void *data, int warn_if_not_found){ belle_sip_list_t* it; it=belle_sip_list_find(first,data); if (it) return belle_sip_list_delete_link(first,it); else if (warn_if_not_found){ belle_sip_warning("belle_sip_list_remove: no element with %p data was in the list", data); } return first; } belle_sip_list_t* belle_sip_list_remove(belle_sip_list_t* first, void *data){ return _belle_sip_list_remove(first, data, TRUE); } int belle_sip_list_size(const belle_sip_list_t* first){ int n=0; while(first!=NULL){ ++n; first=first->next; } return n; } void belle_sip_list_for_each(const belle_sip_list_t* list, void (*func)(void *)){ for(;list!=NULL;list=list->next){ func(list->data); } } void belle_sip_list_for_each2(const belle_sip_list_t* list, void (*func)(void *, void *), void *user_data){ for(;list!=NULL;list=list->next){ func(list->data,user_data); } } belle_sip_list_t * belle_sip_list_pop_front(belle_sip_list_t *list, void **front_data){ belle_sip_list_t *front_elem=list; if (front_elem==NULL){ *front_data=NULL; return NULL; } *front_data=front_elem->data; list=belle_sip_list_remove_link(list,front_elem); belle_sip_free(front_elem); return list; } belle_sip_list_t* belle_sip_list_remove_link(belle_sip_list_t* list, belle_sip_list_t* elem){ belle_sip_list_t* ret; if (elem==list){ ret=elem->next; elem->prev=NULL; elem->next=NULL; if (ret!=NULL) ret->prev=NULL; return ret; } elem->prev->next=elem->next; if (elem->next!=NULL) elem->next->prev=elem->prev; elem->next=NULL; elem->prev=NULL; return list; } belle_sip_list_t * belle_sip_list_delete_link(belle_sip_list_t* list, belle_sip_list_t* elem){ belle_sip_list_t *ret=belle_sip_list_remove_link(list,elem); belle_sip_free(elem); return ret; } belle_sip_list_t* belle_sip_list_find(belle_sip_list_t* list, void *data){ for(;list!=NULL;list=list->next){ if (list->data==data) return list; } return NULL; } belle_sip_list_t* belle_sip_list_find_custom(const belle_sip_list_t* list, belle_sip_compare_func compare_func, const void *user_data){ for(;list!=NULL;list=list->next){ if (compare_func(list->data,user_data)==0) return (belle_sip_list_t *)list; } return NULL; } belle_sip_list_t *belle_sip_list_delete_custom(belle_sip_list_t *list, belle_sip_compare_func compare_func, const void *user_data){ belle_sip_list_t *elem=belle_sip_list_find_custom(list,compare_func,user_data); if (elem!=NULL){ list=belle_sip_list_delete_link(list,elem); } return list; } void * belle_sip_list_nth_data(const belle_sip_list_t* list, int index){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (i==index) return list->data; } belle_sip_error("belle_sip_list_nth_data: no such index in list."); return NULL; } int belle_sip_list_position(const belle_sip_list_t* list, belle_sip_list_t* elem){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (elem==list) return i; } belle_sip_error("belle_sip_list_position: no such element in list."); return -1; } int belle_sip_list_index(const belle_sip_list_t* list, void *data){ int i; for(i=0;list!=NULL;list=list->next,++i){ if (data==list->data) return i; } belle_sip_error("belle_sip_list_index: no such element in list."); return -1; } belle_sip_list_t* belle_sip_list_insert_sorted(belle_sip_list_t* list, void *data, int (*compare_func)(const void *, const void*)){ belle_sip_list_t* it,*previt=NULL; belle_sip_list_t* nelem; belle_sip_list_t* ret=list; if (list==NULL) return belle_sip_list_append(list,data); else{ nelem=belle_sip_list_new(data); for(it=list;it!=NULL;it=it->next){ previt=it; if (compare_func(data,it->data)<=0){ nelem->prev=it->prev; nelem->next=it; if (it->prev!=NULL) it->prev->next=nelem; else{ ret=nelem; } it->prev=nelem; return ret; } } previt->next=nelem; nelem->prev=previt; } return ret; } belle_sip_list_t* belle_sip_list_insert(belle_sip_list_t* list, belle_sip_list_t* before, void *data){ belle_sip_list_t* elem; if (list==NULL || before==NULL) return belle_sip_list_append(list,data); for(elem=list;elem!=NULL;elem=belle_sip_list_next(elem)){ if (elem==before){ if (elem->prev==NULL) return belle_sip_list_prepend(list,data); else{ belle_sip_list_t* nelem=belle_sip_list_new(data); nelem->prev=elem->prev; nelem->next=elem; elem->prev->next=nelem; elem->prev=nelem; } } } return list; } belle_sip_list_t* belle_sip_list_copy(const belle_sip_list_t* list){ belle_sip_list_t* copy=NULL; const belle_sip_list_t* iter; for(iter=list;iter!=NULL;iter=belle_sip_list_next(iter)){ copy=belle_sip_list_append(copy,iter->data); } return copy; } belle_sip_list_t* belle_sip_list_copy_with_data(const belle_sip_list_t* list, void* (*copyfunc)(void*)){ belle_sip_list_t* copy=NULL; const belle_sip_list_t* iter; for(iter=list;iter!=NULL;iter=belle_sip_list_next(iter)){ copy=belle_sip_list_append(copy,copyfunc(iter->data)); } return copy; } char * belle_sip_concat (const char *str, ...) { va_list ap; size_t allocated = 100; char *result = (char *) malloc (allocated); if (result != NULL) { char *newp; char *wp; const char* s; va_start (ap, str); wp = result; for (s = str; s != NULL; s = va_arg (ap, const char *)) { size_t len = strlen (s); /* Resize the allocated memory if necessary. */ if (wp + len + 1 > result + allocated) { allocated = (allocated + len) * 2; newp = (char *) realloc (result, allocated); if (newp == NULL) { free (result); return NULL; } wp = newp + (wp - result); result = newp; } memcpy (wp, s, len); wp +=len; } /* Terminate the result string. */ *wp++ = '\0'; /* Resize memory to the optimal size. */ newp = realloc (result, wp - result); if (newp != NULL) result = newp; va_end (ap); } return result; } void *belle_sip_malloc(size_t size){ return malloc(size); } void *belle_sip_malloc0(size_t size){ void *p=malloc(size); memset(p,0,size); return p; } void *belle_sip_realloc(void *ptr, size_t size){ return realloc(ptr,size); } void belle_sip_free(void *ptr){ free(ptr); } char * belle_sip_strdup(const char *s){ return strdup(s); } #ifndef WIN32 static int find_best_clock_id () { struct timespec ts; static int clock_id=-1; #ifndef ANDROID #define DEFAULT_CLOCK_MODE CLOCK_MONOTONIC #else #define DEFAULT_CLOCK_MODE CLOCK_REALTIME /*monotonic clock stop during sleep mode*/ #endif if (clock_id==-1) { if (clock_gettime(DEFAULT_CLOCK_MODE,&ts)!=1){ clock_id=DEFAULT_CLOCK_MODE; } else if (clock_gettime(CLOCK_REALTIME,&ts)!=1){ clock_id=CLOCK_REALTIME; } else { belle_sip_fatal("Cannot find suitable clock mode"); } } return clock_id; } uint64_t belle_sip_time_ms(void){ struct timespec ts; if (clock_gettime(find_best_clock_id(),&ts)==-1){ belle_sip_error("clock_gettime() error for clock_id=%i: %s",find_best_clock_id(),strerror(errno)); return 0; } return (ts.tv_sec*1000LL) + (ts.tv_nsec/1000000LL); } #else uint64_t belle_sip_time_ms(void){ #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) return GetTickCount(); #else return GetTickCount64(); #endif } #endif /** * parser parameter pair */ belle_sip_param_pair_t* belle_sip_param_pair_new(const char* name,const char* value) { belle_sip_param_pair_t* lPair = (belle_sip_param_pair_t*)belle_sip_new0(belle_sip_param_pair_t); lPair->name=name?belle_sip_strdup(name):NULL; lPair->value=value?belle_sip_strdup(value):NULL; return lPair; } void belle_sip_param_pair_destroy(belle_sip_param_pair_t* pair) { if (pair->name) belle_sip_free(pair->name); if (pair->value) belle_sip_free(pair->value); belle_sip_free(pair); } int belle_sip_param_pair_comp_func(const belle_sip_param_pair_t *a, const char*b) { return strcmp(a->name,b); } int belle_sip_param_pair_case_comp_func(const belle_sip_param_pair_t *a, const char*b) { return strcasecmp(a->name,b); } char* _belle_sip_str_dup_and_unquote_string(const char* quoted_string) { size_t value_size = strlen(quoted_string); char* unquoted_string = belle_sip_malloc0(value_size-2+1); strncpy(unquoted_string,quoted_string+1,value_size-2); return unquoted_string; } char *belle_sip_unquote_strdup(const char *str){ const char *p; if (str==NULL) return NULL; for(p=str;*p!='\0';++p){ switch(*p){ case ' ': case '\t': break; case '"': return _belle_sip_str_dup_and_unquote_string(p); default: return belle_sip_strdup(str); break; } } return belle_sip_strdup(str); } #if defined(WIN32) && !defined(_MSC_VER) #include static int belle_sip_wincrypto_random(unsigned int *rand_number){ static HCRYPTPROV hProv=(HCRYPTPROV)-1; static int initd=0; if (!initd){ if (!CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){ belle_sip_error("Could not acquire a windows crypto context"); return -1; } initd=TRUE; } if (hProv==(HCRYPTPROV)-1) return -1; if (!CryptGenRandom(hProv,4,(BYTE*)rand_number)){ belle_sip_error("CryptGenRandom() failed."); return -1; } return 0; } #endif unsigned int belle_sip_random(void){ #if defined(__linux) || defined(__APPLE__) static int fd=-1; if (fd==-1) fd=open("/dev/urandom",O_RDONLY); if (fd!=-1){ unsigned int tmp; if (read(fd,&tmp,4)!=4){ belle_sip_error("Reading /dev/urandom failed."); }else return tmp; }else belle_sip_error("Could not open /dev/urandom"); #elif defined(WIN32) static int initd=0; unsigned int ret; #ifdef _MSC_VER /*rand_s() is pretty nice and simple function but is not wrapped by mingw.*/ if (rand_s(&ret)==0){ return ret; } #else if (belle_sip_wincrypto_random(&ret)==0){ return ret; } #endif /* Windows's rand() is unsecure but is used as a fallback*/ if (!initd) { srand((unsigned int)belle_sip_time_ms()); initd=1; belle_sip_warning("Random generator is using rand(), this is unsecure !"); } return rand()<<16 | rand(); #endif /*fallback to UNIX random()*/ #ifndef WIN32 return (unsigned int) random(); #endif } static const char *symbols="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-~"; /** * Write a random text token of supplied size. **/ char * belle_sip_random_token(char *ret, size_t size){ unsigned int val=0; unsigned int i; for(i=0;i>6; } ret[i]=0; return ret; } /** * Write random bytes of supplied size. **/ unsigned char * belle_sip_random_bytes(unsigned char *ret, size_t size){ unsigned int val=0; unsigned int i; for(i=0;i>8; } return ret; } typedef struct bits_reader{ const uint8_t *buffer; size_t buf_size; int bit_index; }bits_reader_t; static void bits_reader_init(bits_reader_t *reader, const uint8_t *buffer, size_t bufsize){ reader->buffer=buffer; reader->buf_size=bufsize; reader->bit_index=0; } static int bits_reader_read(bits_reader_t *reader, int count, unsigned int *ret){ unsigned int tmp; size_t byte_index=reader->bit_index/8; size_t bit_index=reader->bit_index % 8; int shift=32-bit_index-count; if (count>=24){ belle_sip_error("This bit reader cannot read more than 24 bits at once."); return -1; } if (byte_indexbuf_size) tmp=((unsigned int)reader->buffer[byte_index++])<<24; else{ belle_sip_error("Bit reader goes end of stream."); return -1; } if (byte_indexbuf_size) tmp|=((unsigned int)reader->buffer[byte_index++])<<16; if (byte_indexbuf_size) tmp|=((unsigned int)reader->buffer[byte_index++])<<8; if (byte_indexbuf_size) tmp|=((unsigned int)reader->buffer[byte_index++]); tmp=tmp>>shift; tmp=tmp & ((1<bit_index+=count; *ret=tmp; return 0; } char * belle_sip_octets_to_text(const uint8_t *hash, size_t hash_len, char *ret, size_t size){ int i; bits_reader_t bitctx; bits_reader_init(&bitctx,hash,hash_len); for(i=0;i<(int)size-1;++i){ unsigned int val=0; if (bits_reader_read(&bitctx,6,&val)==0){ ret[i]=symbols[val]; }else break; } ret[i]=0; return ret; } void belle_sip_util_copy_headers(belle_sip_message_t *orig, belle_sip_message_t *dest, const char*header, int multiple){ const belle_sip_list_t *elem; elem=belle_sip_message_get_headers(orig,header); for (;elem!=NULL;elem=elem->next){ belle_sip_header_t *ref_header=(belle_sip_header_t*)elem->data; if (ref_header){ ref_header=(belle_sip_header_t*)belle_sip_object_clone((belle_sip_object_t*)ref_header); if (!multiple){ belle_sip_message_set_header(dest,ref_header); break; }else belle_sip_message_add_header(dest,ref_header); } } } int belle_sip_get_char (const char*a,int n,char*out) { if (*a=='%' && n>2) { unsigned int tmp; sscanf(a+1,"%02x",&tmp); *out=(char)tmp; return 3; } else { *out=*a; return 1; } } char* belle_sip_to_unescaped_string(const char* buff) { char *output_buff=belle_sip_malloc(strlen(buff)+1); unsigned int i; unsigned int out_buff_index=0; for(i=0; buff[i]!='\0'; out_buff_index++) { i+=belle_sip_get_char(buff+i,3,output_buff+out_buff_index); } output_buff[out_buff_index]='\0'; return output_buff; } #define BELLE_SIP_NO_ESCAPES_SIZE 257 static void noescapes_add_list(char noescapes[BELLE_SIP_NO_ESCAPES_SIZE], const char *allowed) { while (*allowed) { noescapes[(unsigned int) *allowed] = 1; ++allowed; } } static void noescapes_add_range(char noescapes[BELLE_SIP_NO_ESCAPES_SIZE], char first, char last) { memset(noescapes + (unsigned int)first, 1, last-first+1); } static void noescapes_add_alfanums(char noescapes[BELLE_SIP_NO_ESCAPES_SIZE]) { noescapes_add_range(noescapes, '0', '9'); noescapes_add_range(noescapes, 'A', 'Z'); noescapes_add_range(noescapes, 'a', 'z'); } /* static void print_noescapes_map(char noescapes[BELLE_SIP_NO_ESCAPES_SIZE], const char *name) { unsigned int i; printf("Noescapes %s :", name); for (i=' '; i <= '~'; ++i) { if (noescapes[i] == 1) printf ("%c", i); //if (noescapes[i] == 1) printf ("%c %d - %d\n", i, (char)i, noescapes[i]); } printf ("init: %d\n", noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1]); } */ static const char *get_sip_uri_username_noescapes() { static char noescapes[BELLE_SIP_NO_ESCAPES_SIZE] = {0}; if (noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1] == 0) { // concurrent initialization should not be an issue /*user = 1*( unreserved / escaped / user-unreserved ) unreserved = alphanum / mark mark = "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")" user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/" */ noescapes_add_alfanums(noescapes); /*mark*/ noescapes_add_list(noescapes, "-_.!~*'()"); /*user-unreserved*/ noescapes_add_list(noescapes, "&=+$,;?/"); noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1] = 1; // initialized // print_noescapes_map(noescapes, "uri_username"); } return noescapes; } /* * * password = *( unreserved / escaped / "&" / "=" / "+" / "$" / "," ) * */ static const char *get_sip_uri_userpasswd_noescapes() { static char noescapes[BELLE_SIP_NO_ESCAPES_SIZE] = {0}; if (noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1] == 0) { // unreserved noescapes_add_alfanums(noescapes); noescapes_add_list(noescapes, "-_.!~*'()"); noescapes_add_list(noescapes, "&=+$,"); noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1] = 1; // initialized } return noescapes; } static const char *get_sip_uri_parameter_noescapes() { static char noescapes[BELLE_SIP_NO_ESCAPES_SIZE] = {0}; if (noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1] == 0) { /* other-param = pname [ "=" pvalue ] pname = 1*paramchar pvalue = 1*paramchar paramchar = param-unreserved / unreserved / escaped param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$" unreserved = alphanum / mark mark = "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")" escaped = "%" HEXDIG HEXDIG token = 1*(alphanum / "-" / "." / "!" / "%" / "*" / "_" / "+" / "`" / "'" / "~" ) */ //param-unreserved = noescapes_add_list(noescapes,"[]/:&+$"); // token noescapes_add_alfanums(noescapes); noescapes_add_list(noescapes, "-.!%*_+`'~"); // unreserved noescapes_add_list(noescapes, "-_.!~*'()"); noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1] = 1; // initialized // print_noescapes_map(noescapes, "uri_parameter"); } return noescapes; } static const char *get_sip_uri_header_noescapes() { static char noescapes[BELLE_SIP_NO_ESCAPES_SIZE] = {0}; if (noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1] == 0) { /* unreserved = alphanum / mark mark = "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")" escaped = "%" HEXDIG HEXDIG //.... header = hname "=" hvalue hname = 1*( hnv-unreserved / unreserved / escaped ) hvalue = *( hnv-unreserved / unreserved / escaped ) hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$" */ // unreserved //alphanum noescapes_add_alfanums(noescapes); //mark noescapes_add_list(noescapes, "-_.!~*'()"); noescapes_add_list(noescapes, "[]/?:+$"); //hnv-unreserved noescapes[BELLE_SIP_NO_ESCAPES_SIZE-1] = 1; // initialized // print_noescapes_map(noescapes, "uri_parameter"); } return noescapes; } static char* belle_sip_escape(const char* buff, const char *noescapes) { size_t outbuf_size=strlen(buff); size_t orig_size=outbuf_size; char *output_buff=(char*)belle_sip_malloc(outbuf_size+1); int i; int out_buff_index=0; for(i=0; buff[i] != '\0'; i++) { int c = ((unsigned char*)buff)[i]; if (outbuf_sized_name+strlen(ent->d_name)-strlen(file_type), file_type, strlen(file_type))==0) ) { char *name_with_path=belle_sip_strdup_printf("%s/%s",path,ent->d_name); file_list = belle_sip_list_append(file_list, name_with_path); } res = readdir_r(dir, ent, &result); } if (res != 0) { belle_sip_error("Error while reading the [%s] directory: %s.", path, strerror(errno)); } free(ent); closedir(dir); #endif return file_list; } int belle_sip_mkdir(const char *path) { #ifdef WIN32 return _mkdir(path); #else return mkdir(path, 0700); #endif } belle-sip-1.4.1/src/bodyhandler.c000066400000000000000000000462041252242224000166200ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2014 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" /* * Body handler base class implementation */ struct belle_sip_body_handler{ belle_sip_object_t base; belle_sip_body_handler_progress_callback_t progress_cb; size_t expected_size; /* 0 if unknown*/ size_t transfered_size; belle_sip_list_t *headers; /**> used when this body is part of a multipart message to store the header of this part */ char *headerStringBuffer; /**> buffer populated with a string created from marshaling the headers */ void *user_data; }; void belle_sip_body_handler_add_header(belle_sip_body_handler_t *obj, belle_sip_header_t *header) { if (header != NULL) { obj->headers=belle_sip_list_append(obj->headers,belle_sip_object_ref(header)); } } static void belle_sip_body_handler_clone(belle_sip_body_handler_t *obj, const belle_sip_body_handler_t *orig){ obj->progress_cb=orig->progress_cb; obj->user_data=orig->user_data; obj->expected_size=orig->expected_size; obj->transfered_size=orig->transfered_size; obj->headers=belle_sip_list_copy_with_data(orig->headers,(void *(*)(void*))belle_sip_object_clone_and_ref); if (orig->headerStringBuffer!=NULL) { obj->headerStringBuffer = strdup(orig->headerStringBuffer); } } static void belle_sip_body_handler_destroy(belle_sip_body_handler_t *obj){ belle_sip_list_free_with_data(obj->headers,belle_sip_object_unref); belle_sip_free(obj->headerStringBuffer); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_body_handler_t) { BELLE_SIP_VPTR_INIT(belle_sip_body_handler_t,belle_sip_object_t,TRUE), (belle_sip_object_destroy_t) belle_sip_body_handler_destroy, (belle_sip_object_clone_t) belle_sip_body_handler_clone, NULL,/*no marshal*/ }, NULL, /*chunk_recv*/ NULL /*chunk_send*/ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END void belle_sip_body_handler_init(belle_sip_body_handler_t *obj, belle_sip_body_handler_progress_callback_t progress_cb, void *user_data){ obj->user_data=user_data; obj->progress_cb=progress_cb; obj->headers = NULL; /* header is not used in most of the case, set it using a dedicated function if needed */ obj->headerStringBuffer = NULL; /* header string buffer is set when adding a body handler to a multipart body handler */ } size_t belle_sip_body_handler_get_size(const belle_sip_body_handler_t *obj){ return obj->expected_size; } void belle_sip_body_handler_set_size(belle_sip_body_handler_t *obj, size_t size){ obj->expected_size=size; } size_t belle_sip_body_handler_get_transfered_size(const belle_sip_body_handler_t *obj){ return obj->transfered_size; } static void update_progress(belle_sip_body_handler_t *obj, belle_sip_message_t *msg){ if (obj->progress_cb) obj->progress_cb(obj,msg,obj->user_data,obj->transfered_size,obj->expected_size); } void belle_sip_body_handler_begin_transfer(belle_sip_body_handler_t *obj){ obj->transfered_size=0; } void belle_sip_body_handler_recv_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, const uint8_t *buf, size_t size){ BELLE_SIP_OBJECT_VPTR(obj,belle_sip_body_handler_t)->chunk_recv(obj,msg,obj->transfered_size,buf,size); obj->transfered_size+=size; update_progress(obj,msg); } int belle_sip_body_handler_send_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, uint8_t *buf, size_t *size){ int ret; if (obj->expected_size!=0){ *size=MIN(*size,obj->expected_size-obj->transfered_size); } ret=BELLE_SIP_OBJECT_VPTR(obj,belle_sip_body_handler_t)->chunk_send(obj,msg,obj->transfered_size,buf,size); obj->transfered_size+=*size; update_progress(obj,msg); if (obj->expected_size!=0){ if (obj->transfered_size==obj->expected_size) return BELLE_SIP_STOP; if (ret==BELLE_SIP_STOP && obj->transfered_sizeexpected_size){ belle_sip_error("body handler [%p] transfered only [%i] bytes while [%i] were expected",obj, (int)obj->transfered_size,(int)obj->expected_size); } } return ret; } void belle_sip_body_handler_end_transfer(belle_sip_body_handler_t *obj){ if (obj->expected_size==0) obj->expected_size=obj->transfered_size; } /* * memory body handler implementation. **/ struct belle_sip_memory_body_handler{ belle_sip_body_handler_t base; uint8_t *buffer; }; static void belle_sip_memory_body_handler_destroy(belle_sip_memory_body_handler_t *obj){ if (obj->buffer) belle_sip_free(obj->buffer); } static void belle_sip_memory_body_handler_clone(belle_sip_memory_body_handler_t *obj, const belle_sip_memory_body_handler_t *orig){ if (orig->buffer) { obj->buffer=belle_sip_malloc(orig->base.expected_size+1); memcpy(obj->buffer,orig->buffer,orig->base.expected_size); obj->buffer[orig->base.expected_size]='\0'; } } static void belle_sip_memory_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, const uint8_t *buf, size_t size){ belle_sip_memory_body_handler_t *obj=(belle_sip_memory_body_handler_t*)base; obj->buffer=belle_sip_realloc(obj->buffer,offset+size+1); memcpy(obj->buffer+offset,buf,size); obj->buffer[offset+size]='\0'; } static int belle_sip_memory_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, uint8_t *buf, size_t *size){ belle_sip_memory_body_handler_t *obj=(belle_sip_memory_body_handler_t*)base; size_t to_send=MIN(*size,obj->base.expected_size-offset); memcpy(buf,obj->buffer+offset,to_send); *size=to_send; return (obj->base.expected_size-offset==*size) ? BELLE_SIP_STOP : BELLE_SIP_CONTINUE; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_memory_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_memory_body_handler_t) { { BELLE_SIP_VPTR_INIT(belle_sip_memory_body_handler_t,belle_sip_body_handler_t,TRUE), (belle_sip_object_destroy_t) belle_sip_memory_body_handler_destroy, (belle_sip_object_clone_t)belle_sip_memory_body_handler_clone, NULL }, belle_sip_memory_body_handler_recv_chunk, belle_sip_memory_body_handler_send_chunk } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END const void *belle_sip_memory_body_handler_get_buffer(const belle_sip_memory_body_handler_t *obj){ return obj->buffer; } belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new(belle_sip_body_handler_progress_callback_t cb, void *user_data){ belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data); return obj; } belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new_from_buffer(void *buffer, size_t bufsize, belle_sip_body_handler_progress_callback_t cb, void *user_data){ belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data); obj->buffer=(uint8_t*)buffer; obj->base.expected_size=bufsize; return obj; } belle_sip_memory_body_handler_t *belle_sip_memory_body_handler_new_copy_from_buffer(const void *buffer, size_t bufsize, belle_sip_body_handler_progress_callback_t cb, void *user_data){ belle_sip_memory_body_handler_t *obj=belle_sip_object_new(belle_sip_memory_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,cb,user_data); obj->buffer=(uint8_t*)belle_sip_malloc(bufsize+1); obj->buffer[bufsize]='\0'; obj->base.expected_size=bufsize; memcpy(obj->buffer,buffer,bufsize); return obj; } /* * User body handler implementation */ struct belle_sip_user_body_handler{ belle_sip_body_handler_t base; belle_sip_user_body_handler_recv_callback_t recv_cb; belle_sip_user_body_handler_send_callback_t send_cb; }; static void belle_sip_user_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, const uint8_t *buf, size_t size){ belle_sip_user_body_handler_t *obj=(belle_sip_user_body_handler_t*)base; if (obj->recv_cb) obj->recv_cb((belle_sip_user_body_handler_t*)base, msg, base->user_data, offset, buf, size); else belle_sip_warning("belle_sip_user_body_handler_t ignoring received chunk."); } static int belle_sip_user_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, uint8_t *buf, size_t *size){ belle_sip_user_body_handler_t *obj=(belle_sip_user_body_handler_t*)base; if (obj->send_cb) return obj->send_cb((belle_sip_user_body_handler_t*)base, msg, base->user_data, offset, buf, size); else belle_sip_warning("belle_sip_user_body_handler_t ignoring send chunk."); *size=0; return BELLE_SIP_STOP; } static void belle_sip_user_body_handler_clone(belle_sip_user_body_handler_t *obj, const belle_sip_user_body_handler_t *orig){ obj->recv_cb=orig->recv_cb; obj->send_cb=orig->send_cb; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_user_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_user_body_handler_t) { { BELLE_SIP_VPTR_INIT(belle_sip_user_body_handler_t,belle_sip_body_handler_t,TRUE), (belle_sip_object_destroy_t) NULL, (belle_sip_object_clone_t)belle_sip_user_body_handler_clone, NULL }, belle_sip_user_body_handler_recv_chunk, belle_sip_user_body_handler_send_chunk } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_user_body_handler_t *belle_sip_user_body_handler_new( size_t total_size, belle_sip_body_handler_progress_callback_t progress_cb, belle_sip_user_body_handler_recv_callback_t recv_cb, belle_sip_user_body_handler_send_callback_t send_cb, void *data){ belle_sip_user_body_handler_t * obj=belle_sip_object_new(belle_sip_user_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,progress_cb,data); obj->base.expected_size=total_size; obj->recv_cb=recv_cb; obj->send_cb=send_cb; return obj; } /** * File body handler implementation **/ struct belle_sip_file_body_handler{ belle_sip_body_handler_t base; char *filepath; }; static void belle_sip_file_body_handler_destroy(belle_sip_file_body_handler_t *obj) { if (obj->filepath) belle_sip_free(obj->filepath); } static void belle_sip_file_body_handler_clone(belle_sip_file_body_handler_t *obj, const belle_sip_file_body_handler_t *orig) { obj->filepath = belle_sip_strdup(orig->filepath); } static void belle_sip_file_body_handler_recv_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, const uint8_t *buf, size_t size) { FILE *f; int ret; belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base; if (obj->filepath == NULL) return; f = fopen(obj->filepath, "ab"); if (f == NULL) return; ret = fwrite(buf, 1, size, f); if (ret != size) { fclose(f); return; } fclose(f); } static int belle_sip_file_body_handler_send_chunk(belle_sip_body_handler_t *base, belle_sip_message_t *msg, size_t offset, uint8_t *buf, size_t *size) { FILE *f; int ret; belle_sip_file_body_handler_t *obj = (belle_sip_file_body_handler_t *)base; size_t to_send = MIN(*size, obj->base.expected_size - offset); if (obj->filepath == NULL) return BELLE_SIP_STOP; f = fopen(obj->filepath, "rb"); if (f == NULL) return BELLE_SIP_STOP; ret = fseek(f, offset, SEEK_SET); if (ret < 0) { fclose(f); return BELLE_SIP_STOP; } ret = fread(buf, 1, to_send, f); if (ret < 0) { fclose(f); return BELLE_SIP_STOP; } *size = ret; fclose(f); return (((obj->base.expected_size - offset) == *size) || (*size == 0)) ? BELLE_SIP_STOP : BELLE_SIP_CONTINUE; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_file_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_file_body_handler_t) { { BELLE_SIP_VPTR_INIT(belle_sip_file_body_handler_t,belle_sip_body_handler_t,TRUE), (belle_sip_object_destroy_t) belle_sip_file_body_handler_destroy, (belle_sip_object_clone_t)belle_sip_file_body_handler_clone, NULL }, belle_sip_file_body_handler_recv_chunk, belle_sip_file_body_handler_send_chunk } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_file_body_handler_t *belle_sip_file_body_handler_new(const char *filepath, belle_sip_body_handler_progress_callback_t progress_cb, void *data) { struct stat statbuf; belle_sip_file_body_handler_t *obj = belle_sip_object_new(belle_sip_file_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj, progress_cb, data); obj->filepath = belle_sip_strdup(filepath); if (stat(obj->filepath, &statbuf) == 0) { obj->base.expected_size = statbuf.st_size; } return obj; } /* * Multipart body handler implementation * TODO **/ #define MULTIPART_SEPARATOR "--" BELLESIP_MULTIPART_BOUNDARY "\r\n" #define MULTIPART_END "\r\n--" BELLESIP_MULTIPART_BOUNDARY "--\r\n" struct belle_sip_multipart_body_handler{ belle_sip_body_handler_t base; belle_sip_list_t *parts; }; static void belle_sip_multipart_body_handler_destroy(belle_sip_multipart_body_handler_t *obj){ belle_sip_list_free_with_data(obj->parts,belle_sip_object_unref); } static void belle_sip_multipart_body_handler_clone(belle_sip_multipart_body_handler_t *obj){ obj->parts=belle_sip_list_copy_with_data(obj->parts,(void *(*)(void*))belle_sip_object_clone_and_ref); } static void belle_sip_multipart_body_handler_recv_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, size_t offset, const uint8_t *buffer, size_t size){ /*TODO*/ } static int belle_sip_multipart_body_handler_send_chunk(belle_sip_body_handler_t *obj, belle_sip_message_t *msg, size_t offset, uint8_t *buffer, size_t *size){ belle_sip_multipart_body_handler_t *obj_multipart=(belle_sip_multipart_body_handler_t*)obj; if (obj_multipart->parts->data) { /* we have a part, get its content from handler */ int retval = BELLE_SIP_STOP; size_t offsetSize = 0; /* used to store size of data added by this function and not given by the body handler of current part */ belle_sip_body_handler_t *current_part = (belle_sip_body_handler_t *)obj_multipart->parts->data; *size -= strlen(MULTIPART_END); /* just in case it will be the end of the message, ask for less characters than possible in order to be able to add the multipart message termination */ if (current_part->transfered_size == 0) { /* Nothing transfered yet on this part, include a separator and the header if exists */ size_t headersSize = 0; offsetSize = strlen(MULTIPART_SEPARATOR); if (current_part->headerStringBuffer != NULL) { headersSize = strlen(current_part->headerStringBuffer); } /* check if buffer is large enough to get the whole header + separtor and at least a byte of data */ if (*size < headersSize+offsetSize+1) { return BELLE_SIP_BUFFER_OVERFLOW; } /* insert separator */ memcpy(buffer, MULTIPART_SEPARATOR, offsetSize); /* insert part header */ if (headersSize!=0) { memcpy(buffer+offsetSize, current_part->headerStringBuffer, headersSize); offsetSize += headersSize; } *size -=offsetSize; /* decrease data length requested to the current part handler */ } retval = belle_sip_body_handler_send_chunk(current_part, msg, buffer+offsetSize, size); /* add offsetSize to the buffer address in order to point at the begining of free space (after header if included) */ *size +=offsetSize; /* restore total of data given including potential separator and header */ if (retval == BELLE_SIP_CONTINUE) { return BELLE_SIP_CONTINUE; /* there is still data to be sent, continue */ } else { /* this part has reach the end, pass to next one if there is one */ if (obj_multipart->parts->next!=NULL) { /* there is an other part to be sent */ obj_multipart->parts = belle_sip_list_next(obj_multipart->parts); return BELLE_SIP_CONTINUE; } else { /* there is nothing else, close the message and return STOP */ memcpy(buffer+*size, MULTIPART_END, strlen(MULTIPART_END)); *size+=strlen(MULTIPART_END); return BELLE_SIP_STOP; } } } return BELLE_SIP_STOP; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_multipart_body_handler_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_multipart_body_handler_t) { { BELLE_SIP_VPTR_INIT(belle_sip_multipart_body_handler_t,belle_sip_body_handler_t,TRUE), (belle_sip_object_destroy_t) belle_sip_multipart_body_handler_destroy, (belle_sip_object_clone_t)belle_sip_multipart_body_handler_clone, NULL }, belle_sip_multipart_body_handler_recv_chunk, belle_sip_multipart_body_handler_send_chunk } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_multipart_body_handler_t *belle_sip_multipart_body_handler_new(belle_sip_body_handler_progress_callback_t progress_cb, void *data, belle_sip_body_handler_t *first_part){ belle_sip_multipart_body_handler_t *obj=belle_sip_object_new(belle_sip_multipart_body_handler_t); belle_sip_body_handler_init((belle_sip_body_handler_t*)obj,progress_cb,data); obj->base.expected_size = strlen(MULTIPART_END); /* body's length will be part length(including boundary) + multipart end */ if (first_part) belle_sip_multipart_body_handler_add_part(obj,first_part); return obj; } #define DEFAULT_HEADER_STRING_SIZE 512 void belle_sip_multipart_body_handler_add_part(belle_sip_multipart_body_handler_t *obj, belle_sip_body_handler_t *part){ obj->base.expected_size+=part->expected_size+strlen(MULTIPART_SEPARATOR); /* add the separator length to the body length as each part start with a separator */ if (part->headers != NULL) { /* there is a declared header for this part, add its length to the expected total length */ size_t headerStringBufferSize = DEFAULT_HEADER_STRING_SIZE; size_t offset = 0; belle_sip_list_t *headerList = part->headers; part->headerStringBuffer = (char *)belle_sip_malloc(DEFAULT_HEADER_STRING_SIZE); while (headerList != NULL) { size_t offsetBackup=offset; /* we must backup the offset as it will be messed up by the marshal function in case of failure */ belle_sip_error_code returnCode = belle_sip_object_marshal(headerList->data, part->headerStringBuffer, headerStringBufferSize-5, &offset); /* -5 to leave room for carriage returns */ if (returnCode == BELLE_SIP_BUFFER_OVERFLOW) { /* increase buffer size */ offset=offsetBackup; /* restore the offset, no data were written to the buffer */ headerStringBufferSize+=DEFAULT_HEADER_STRING_SIZE; part->headerStringBuffer = (char *)belle_sip_realloc(part->headerStringBuffer, headerStringBufferSize); } else if (returnCode == BELLE_SIP_OK) { /* add the carriage return chars */ part->headerStringBuffer[offset++]='\r'; part->headerStringBuffer[offset++]='\n'; headerList = belle_sip_list_next(headerList); } } part->headerStringBuffer[offset++]='\r'; part->headerStringBuffer[offset++]='\n'; obj->base.expected_size += offset; part->headerStringBuffer[offset++]='\0'; /* null terminate the buffer in order to be able to get it length later using strlen */ } obj->parts=belle_sip_list_append(obj->parts,belle_sip_object_ref(part)); } belle-sip-1.4.1/src/channel.c000066400000000000000000001410731252242224000157350ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include #include #ifdef ANDROID #include "wakelock_internal.h" #endif static void channel_prepare_continue(belle_sip_channel_t *obj); static void channel_process_queue(belle_sip_channel_t *obj); static void channel_begin_send_background_task(belle_sip_channel_t *obj); static void channel_end_send_background_task(belle_sip_channel_t *obj); static void channel_begin_recv_background_task(belle_sip_channel_t *obj); static void channel_end_recv_background_task(belle_sip_channel_t *obj); static void channel_process_queue(belle_sip_channel_t *obj); static char *make_logbuf(belle_sip_log_level level, const char *buffer, size_t size); static void channel_remove_listener(belle_sip_channel_t *obj, belle_sip_channel_listener_t *l); static void free_ewouldblock_buffer(belle_sip_channel_t *obj); const char *belle_sip_channel_state_to_string(belle_sip_channel_state_t state){ switch(state){ case BELLE_SIP_CHANNEL_INIT: return "INIT"; case BELLE_SIP_CHANNEL_RES_IN_PROGRESS: return "RES_IN_PROGRESS"; case BELLE_SIP_CHANNEL_RES_DONE: return "RES_DONE"; case BELLE_SIP_CHANNEL_CONNECTING: return "CONNECTING"; case BELLE_SIP_CHANNEL_RETRY: return "RETRY"; case BELLE_SIP_CHANNEL_READY: return "READY"; case BELLE_SIP_CHANNEL_ERROR: return "ERROR"; case BELLE_SIP_CHANNEL_DISCONNECTED: return "DISCONNECTED"; } return "BAD"; } static belle_sip_list_t * for_each_weak_unref_free(belle_sip_list_t *l, belle_sip_object_destroy_notify_t notify, void *ptr){ belle_sip_list_t *elem,*next; for(elem=l;elem!=NULL;elem=next){ next=elem->next; belle_sip_object_weak_unref(elem->data,notify,ptr); belle_sip_free(elem); } return NULL; } static void belle_sip_channel_destroy(belle_sip_channel_t *obj){ if (obj->peer_list) belle_sip_freeaddrinfo(obj->peer_list); if (obj->peer_cname) belle_sip_free(obj->peer_cname); belle_sip_free(obj->peer_name); if (obj->local_ip) belle_sip_free(obj->local_ip); obj->listeners=for_each_weak_unref_free(obj->listeners,(belle_sip_object_destroy_notify_t)channel_remove_listener,obj); if (obj->resolver_ctx>0) belle_sip_resolver_context_cancel(obj->resolver_ctx); if (obj->inactivity_timer){ belle_sip_main_loop_remove_source(obj->stack->ml,obj->inactivity_timer); belle_sip_object_unref(obj->inactivity_timer); } if (obj->public_ip) belle_sip_free(obj->public_ip); if (obj->outgoing_messages) belle_sip_list_free_with_data(obj->outgoing_messages,belle_sip_object_unref); free_ewouldblock_buffer(obj); if (obj->cur_out_message){ belle_sip_object_unref(obj->cur_out_message); obj->cur_out_message=NULL; } channel_end_send_background_task(obj); channel_end_recv_background_task(obj); /*normally this should do nothing because it sould have been terminated already, however leaving a background task open is so dangerous that we have to be paranoid*/ belle_sip_message("Channel [%p] destroyed",obj); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_channel_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_channel_t) { BELLE_SIP_VPTR_INIT(belle_sip_channel_t,belle_sip_source_t,FALSE), (belle_sip_object_destroy_t)belle_sip_channel_destroy, NULL, /*clone*/ NULL, /*marshal*/ } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END static void fix_incoming_via(belle_sip_request_t *msg, const struct addrinfo* origin){ char received[NI_MAXHOST]; char rport[NI_MAXSERV]; belle_sip_header_via_t *via; int err; struct sockaddr_storage saddr; socklen_t slen=sizeof(saddr); if (!origin) { belle_sip_warning("cannot fix via for message [%p], probably a test",msg); return; } belle_sip_address_remove_v4_mapping(origin->ai_addr, (struct sockaddr*)&saddr, &slen); err=getnameinfo((struct sockaddr*)&saddr,slen,received,sizeof(received), rport,sizeof(rport),NI_NUMERICHOST|NI_NUMERICSERV); if (err!=0){ belle_sip_error("fix_via: getnameinfo() failed: %s",gai_strerror(errno)); return; } via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)msg,"via")); if (via){ const char* host = belle_sip_header_via_get_host(via); if (strcmp(host,received)!=0) belle_sip_header_via_set_received(via,received); if (belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(via),"rport")){ int port = belle_sip_header_via_get_listening_port(via); int rport_int=atoi(rport); if (rport_int!=port) belle_sip_header_via_set_rport(via,atoi(rport)); } } } /*token = 1*(alphanum / "-" / "." / "!" / "%" / "*" / "_" / "+" / "`" / "'" / "~" ) * * */ static int is_token(const char* buff,size_t bufflen ) { int i; for (i=0; i='0' && buff[i]<='9') || (buff[i]>='A' && buff[i]<='Z') || (buff[i]>='a' && buff[i]<='z') || (buff[i]=='\0')) continue; else return 0; } } return 1; } static int get_message_start_pos(char *buff, size_t bufflen) { /*FIXME still to optimize and better test, specially REQUEST PATH and error path*/ int i; int res=0; int status_code; char method[17]={0}; char saved_char1; char sip_version[10]={0}; int saved_char1_index; for(i=0; i<(int)bufflen-12;i++) { /*9=strlen( SIP/2.0\r\n)*/ switch (buff[i]) { /*to avoid this character to be ignored by scanf*/ case '\r': case '\n': case ' ' : case '\t': continue; default: break; } saved_char1_index=bufflen-1; saved_char1=buff[saved_char1_index]; /*make sure buff is null terminated*/ buff[saved_char1_index]='\0'; res=sscanf(buff+i,"SIP/2.0 %d ",&status_code); if (res!=1) res=sscanf(buff+i,"HTTP/1.%*i %d ",&status_code); /*might be HTTP ?*/ if (res!=1) { res= sscanf(buff+i,"%16s %*s %9s\r\n",method,sip_version)==2 && is_token(method,sizeof(method)) && (strcmp("SIP/2.0",sip_version)==0 || strncmp("HTTP/1.",sip_version,strlen("HTTP/1."))==0); } buff[saved_char1_index]=saved_char1; if (res==1) return i; } return -1; } static void belle_sip_channel_input_stream_rewind(belle_sip_channel_input_stream_t* input_stream){ int remaining; remaining=input_stream->write_ptr-input_stream->read_ptr; if (remaining>0){ /* copy remaning bytes at top of buffer*/ memmove(input_stream->buff,input_stream->read_ptr,remaining); input_stream->read_ptr=input_stream->buff; input_stream->write_ptr=input_stream->buff+remaining; *input_stream->write_ptr='\0'; }else{ input_stream->read_ptr=input_stream->write_ptr=input_stream->buff; } } static void belle_sip_channel_input_stream_reset(belle_sip_channel_input_stream_t* input_stream) { belle_sip_channel_input_stream_rewind(input_stream); input_stream->state=WAITING_MESSAGE_START; input_stream->msg=NULL; input_stream->chuncked_mode=FALSE; input_stream->content_length=-1; } static size_t belle_sip_channel_input_stream_get_buff_length(belle_sip_channel_input_stream_t* input_stream) { return sizeof(input_stream->buff) - (input_stream->write_ptr-input_stream->buff); } char *belle_sip_channel_get_public_ip_port(belle_sip_channel_t *obj){ if (obj->public_ip){ return belle_sip_strdup_printf("%s:%d", obj->public_ip, obj->public_port); } return NULL; } void belle_sip_channel_set_public_ip_port(belle_sip_channel_t *obj, const char *public_ip, int port){ if (obj->public_ip){ int ip_changed=0; int port_changed=0; if (public_ip && strcmp(obj->public_ip,public_ip)!=0){ ip_changed=1; } if (port!=obj->public_port){ port_changed=1; } if (ip_changed || port_changed){ belle_sip_warning("channel [%p]: public ip is changed from [%s:%i] to [%s:%i]",obj,obj->public_ip,obj->public_port,public_ip,port); } belle_sip_free(obj->public_ip); obj->public_ip=NULL; }else if (public_ip){ belle_sip_message("channel [%p]: discovered public ip and port are [%s:%i]",obj,public_ip,port); } if (public_ip){ obj->public_ip=belle_sip_strdup(public_ip); } obj->public_port=port; } static void belle_sip_channel_learn_public_ip_port(belle_sip_channel_t *obj, belle_sip_response_t *resp){ belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(resp,belle_sip_header_via_t); const char *received; int rport; if (!via){ belle_sip_error("channel [%p]: no via in response.",obj); return; } if (!(received=belle_sip_header_via_get_received(via))) { /*use address from via*/; received=belle_sip_header_via_get_host(via); } rport=belle_sip_header_via_get_rport(via); if (rport<=0){ /* no rport, the via port might be good then*/ rport=belle_sip_header_via_get_listening_port(via); } belle_sip_channel_set_public_ip_port(obj,received,rport); obj->learnt_ip_port=TRUE; } static void belle_sip_channel_message_ready(belle_sip_channel_t *obj){ belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); if (bh) belle_sip_body_handler_end_transfer(bh); if (belle_sip_message_is_response(msg)) belle_sip_channel_learn_public_ip_port(obj,BELLE_SIP_RESPONSE(msg)); obj->incoming_messages=belle_sip_list_append(obj->incoming_messages,msg); belle_sip_channel_input_stream_reset(&obj->input_stream); } static void feed_body(belle_sip_channel_t *obj, size_t len){ belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); belle_sip_body_handler_recv_chunk(bh,msg,(uint8_t*)obj->input_stream.read_ptr,len); obj->input_stream.read_ptr+=len; belle_sip_channel_input_stream_rewind(&obj->input_stream); } /*returns TRUE if a body is expected, and initialize a few things in the input stream context*/ static int check_body(belle_sip_channel_t *obj){ belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_header_content_length_t* content_length_header = belle_sip_message_get_header_by_type(msg,belle_sip_header_content_length_t); int expect_body=FALSE; obj->input_stream.content_length= content_length_header ? belle_sip_header_content_length_get_content_length(content_length_header) : 0; if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_sip_response_t) || BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_sip_request_t)){ expect_body=obj->input_stream.content_length>0; }else{/*http*/ if (belle_sip_message_get_header_by_type(msg, belle_sip_header_content_type_t)!=NULL){ belle_sip_header_t *transfer_encoding=belle_sip_message_get_header(msg,"Transfer-Encoding"); if (transfer_encoding){ const char *value=belle_sip_header_get_unparsed_value(transfer_encoding); if (strstr(value,"chunked")!=0){ obj->input_stream.chuncked_mode=1; obj->input_stream.content_length=0; obj->input_stream.chunk_size=-1; obj->input_stream.chunk_read_size=0; } } expect_body=TRUE; } } if (expect_body){ belle_sip_body_handler_t *bh; /*should notify the listeners*/ BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2(obj->listeners,belle_sip_channel_listener_t,on_message_headers,obj,msg); /*check if the listener has setup a body handler, otherwise create a default one*/ if ((bh=belle_sip_message_get_body_handler(msg))==NULL){ belle_sip_message_set_body_handler(msg,(bh=(belle_sip_body_handler_t*)belle_sip_memory_body_handler_new(NULL,NULL))); } belle_sip_body_handler_begin_transfer(bh); } return expect_body; } static int acquire_body_simple(belle_sip_channel_t *obj, int end_of_stream){ int content_length=obj->input_stream.content_length; size_t to_read=obj->input_stream.write_ptr-obj->input_stream.read_ptr; belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); size_t cursize=belle_sip_body_handler_get_transfered_size(bh); if ((cursize == 0) && (to_read == 0)) { /** * No data has been received yet, so do not call feed_body() with a size * of 0 that is meaning that the transfer is finished. */ } else { to_read=MIN(content_length-cursize, to_read); feed_body(obj,to_read); } if (end_of_stream || belle_sip_body_handler_get_transfered_size(bh)>=content_length){ /*great body completed*/ belle_sip_message("channel [%p] read [%i] bytes of body from [%s:%i]" ,obj ,content_length ,obj->peer_name ,obj->peer_port); belle_sip_channel_message_ready(obj); return BELLE_SIP_CONTINUE; } /*body is not finished, we need more data*/ return BELLE_SIP_STOP; } static int acquire_chuncked_body(belle_sip_channel_t *obj){ belle_sip_channel_input_stream_t *st=&obj->input_stream; int readsize; do{ if (st->chunk_size==-1){ char *tmp; /*belle_sip_message("seeing: %s",st->read_ptr);*/ while ( (tmp=strstr(st->read_ptr,"\r\n"))==st->read_ptr){/*skip \r\n*/ st->read_ptr+=2; } if (tmp!=NULL){ /*the chunk length is there*/ long chunksize=strtol(st->read_ptr,NULL,16); if (chunksize>=0 && chunksize!=LONG_MAX){ if (chunksize==0){ belle_sip_message("Got end of chunked body"); st->read_ptr=tmp+4; /*last chunk indicator finishes with two \r\n*/ if (st->read_ptr>st->write_ptr) st->read_ptr=st->write_ptr; belle_sip_channel_message_ready(obj); return BELLE_SIP_CONTINUE; }else{ belle_sip_message("Will get a chunk of %i bytes",(int)chunksize); st->chunk_size=chunksize; st->chunk_read_size=0; st->read_ptr=tmp+2; } }else{ belle_sip_error("Chunk parse error"); belle_sip_channel_input_stream_reset(st); return BELLE_SIP_CONTINUE; } }else{ /*need more data*/ return BELLE_SIP_STOP; } } readsize=MIN(st->write_ptr-st->read_ptr,st->chunk_size-st->chunk_read_size); if (readsize>0){ feed_body(obj,readsize); st->chunk_read_size+=readsize; } if (st->chunk_size==st->chunk_read_size){ /*we have a chunk completed*/ st->content_length+=st->chunk_size; belle_sip_message("Chunk of [%i] bytes completed",st->chunk_size); st->chunk_size=-1;/*wait for next chunk indicator*/ }else{ /*need more data*/ return BELLE_SIP_STOP; } }while(st->write_ptr-st->read_ptr>0); /*no need to continue if nothing to read*/ return BELLE_SIP_STOP; } static int acquire_body(belle_sip_channel_t *obj, int end_of_stream){ if (obj->input_stream.chuncked_mode) return acquire_chuncked_body(obj); else return acquire_body_simple(obj,end_of_stream); } static void notify_incoming_messages(belle_sip_channel_t *obj){ belle_sip_list_t *elem,*l_it; belle_sip_list_t *listeners=belle_sip_list_copy_with_data(obj->listeners,(void *(*)(void*))belle_sip_object_ref); for(l_it=listeners;l_it!=NULL;l_it=l_it->next){ belle_sip_channel_listener_t *listener=(belle_sip_channel_listener_t*)l_it->data; for(elem=obj->incoming_messages;elem!=NULL;elem=elem->next){ belle_sip_message_t *msg=(belle_sip_message_t*)elem->data; BELLE_SIP_INTERFACE_METHODS_TYPE(belle_sip_channel_listener_t) *methods; methods=BELLE_SIP_INTERFACE_GET_METHODS(listener,belle_sip_channel_listener_t); if (methods->on_message) methods->on_message(listener,obj,msg); } } belle_sip_list_free_with_data(listeners,belle_sip_object_unref); belle_sip_list_free_with_data(obj->incoming_messages,belle_sip_object_unref); obj->incoming_messages=NULL; } void belle_sip_channel_parse_stream(belle_sip_channel_t *obj, int end_of_stream){ int offset; size_t read_size=0; int num; while ((num=(obj->input_stream.write_ptr-obj->input_stream.read_ptr))>0){ if (obj->input_stream.state == WAITING_MESSAGE_START) { int i; /*first, make sure there is \r\n in the buffer, otherwise, micro parser cannot conclude, because we need a complete request or response line somewhere*/ for (i=0;iinput_stream.read_ptr[i]=='\r' && obj->input_stream.read_ptr[i+1]=='\n') || belle_sip_channel_input_stream_get_buff_length(&obj->input_stream) <= 1 /*1 because null terminated*/ /*if buffer full try to parse in any case*/) { /*good, now we can start searching for request/response*/ if ((offset=get_message_start_pos(obj->input_stream.read_ptr,num)) >=0 ) { /*message found !*/ if (offset>0) { belle_sip_warning("trashing [%i] bytes in front of sip message on channel [%p]",offset,obj); obj->input_stream.read_ptr+=offset; } obj->input_stream.state=MESSAGE_AQUISITION; } else { belle_sip_debug("Unexpected [%s] received on channel [%p], trashing",obj->input_stream.read_ptr,obj); obj->input_stream.read_ptr=obj->input_stream.write_ptr; belle_sip_channel_input_stream_reset(&obj->input_stream); continue; } break; } } if (i >= num-1) { belle_sip_debug("[%s] received on channel [%p], cannot determine if expected or not, waiting for new data",obj->input_stream.read_ptr,obj); break; } } if (obj->input_stream.state==MESSAGE_AQUISITION) { /*search for \r\n\r\n*/ char* end_of_message=NULL; if ((end_of_message=strstr(obj->input_stream.read_ptr,"\r\n\r\n"))){ int bytes_to_parse; char tmp; /*end of message found*/ end_of_message+=4;/*add \r\n\r\n*/ bytes_to_parse=end_of_message-obj->input_stream.read_ptr; tmp=*end_of_message; *end_of_message='\0';/*this is in order for the following log to print the message only to its end.*/ /*belle_sip_message("channel [%p] read message of [%i] bytes:\n%.40s...",obj, bytes_to_parse, obj->input_stream.read_ptr);*/ obj->input_stream.msg=belle_sip_message_parse_raw(obj->input_stream.read_ptr ,bytes_to_parse ,&read_size); *end_of_message=tmp; obj->input_stream.read_ptr+=read_size; if (obj->input_stream.msg && read_size > 0){ belle_sip_message("channel [%p] [%i] bytes parsed",obj,(int)read_size); belle_sip_object_ref(obj->input_stream.msg); if (belle_sip_message_is_request(obj->input_stream.msg)) fix_incoming_via(BELLE_SIP_REQUEST(obj->input_stream.msg),obj->current_peer); /*check for body*/ if (check_body(obj)){ obj->input_stream.state=BODY_AQUISITION; } else { /*no body*/ belle_sip_channel_message_ready(obj); continue; } }else{ belle_sip_error("Could not parse [%s], on channel [%p] skipping to [%s]",obj->input_stream.read_ptr ,obj ,end_of_message); obj->input_stream.read_ptr=end_of_message; obj->input_stream.state=WAITING_MESSAGE_START; continue; } }else break; /*The message isn't finished to be receive, we need more data*/ } if (obj->input_stream.state==BODY_AQUISITION) { if (acquire_body(obj,end_of_stream)==BELLE_SIP_STOP) break; } } } static void belle_sip_channel_process_stream(belle_sip_channel_t *obj, int eos){ belle_sip_channel_parse_stream(obj,eos); if (obj->incoming_messages) notify_incoming_messages(obj); } static int belle_sip_channel_process_read_data(belle_sip_channel_t *obj){ int num; int ret=BELLE_SIP_CONTINUE; /*prevent system to suspend the process until we have finish reading everything from the socket and notified the upper layer*/ if (obj->input_stream.state == WAITING_MESSAGE_START) channel_begin_recv_background_task(obj); if (obj->simulated_recv_return>0) { num=belle_sip_channel_recv(obj,obj->input_stream.write_ptr,belle_sip_channel_input_stream_get_buff_length(&obj->input_stream)-1); } else { belle_sip_message("channel [%p]: simulating recv() returning %i",obj,obj->simulated_recv_return); num=obj->simulated_recv_return; } if (num>0){ char *begin=obj->input_stream.write_ptr; char *logbuf=make_logbuf(BELLE_SIP_LOG_MESSAGE,begin,num); obj->input_stream.write_ptr+=num; /*first null terminate the read buff*/ *obj->input_stream.write_ptr='\0'; if (num>20) /*to avoid tracing server based keep alives*/ belle_sip_message("channel [%p]: received [%i] new bytes from [%s://%s:%i]:\n%s", obj, num, belle_sip_channel_get_transport_name(obj), obj->peer_name, obj->peer_port, logbuf); belle_sip_free(logbuf); belle_sip_channel_process_stream(obj,FALSE); } else if (num == 0) { /*before closing the channel, check if there was a pending message to receive, whose body acquisition is to be finished.*/ belle_sip_channel_process_stream(obj,TRUE); channel_set_state(obj,BELLE_SIP_CHANNEL_DISCONNECTED); ret=BELLE_SIP_STOP; } else if (belle_sip_error_code_is_would_block(-num)){ belle_sip_message("channel [%p]: recv() EWOULDBLOCK",obj); ret=BELLE_SIP_CONTINUE; }else{ belle_sip_error("Receive error on channel [%p]",obj); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); ret=BELLE_SIP_STOP; } if (obj->input_stream.state == WAITING_MESSAGE_START) channel_end_recv_background_task(obj); return ret; } int belle_sip_channel_process_data(belle_sip_channel_t *obj,unsigned int revents){ int ret=BELLE_SIP_CONTINUE; if (revents & BELLE_SIP_EVENT_READ) { int rret=belle_sip_channel_process_read_data(obj); if (rret==BELLE_SIP_STOP) ret=BELLE_SIP_STOP; } if (revents & BELLE_SIP_EVENT_WRITE){ /*if we are here, this is because we had an EWOULDBLOCK while sending a message*/ /*continue to send pending messages but before check the channel is still alive because it may have been closed by belle_sip_channel_process_read_data() above.*/ if (obj->state == BELLE_SIP_CHANNEL_READY){ channel_process_queue(obj); } } return ret; } static int channel_inactive_timeout(void *data, unsigned int event){ belle_sip_channel_t *obj=(belle_sip_channel_t *)data; belle_sip_message("Channel [%p]: inactivity timeout reached.",obj); channel_set_state(obj,BELLE_SIP_CHANNEL_DISCONNECTED); return BELLE_SIP_STOP; } static void update_inactivity_timer(belle_sip_channel_t *obj, int from_recv){ int inactive_timeout=belle_sip_stack_get_inactive_transport_timeout(obj->stack)*1000; if (inactive_timeout>0){ if (!obj->inactivity_timer ){ obj->inactivity_timer=belle_sip_main_loop_create_timeout(obj->stack->ml,channel_inactive_timeout,obj,inactive_timeout,"Channel inactivity timer"); }else{ /*restart the timer for new period*/ belle_sip_source_set_timeout(obj->inactivity_timer,inactive_timeout); } }else{ if (obj->inactivity_timer){ belle_sip_main_loop_remove_source(obj->stack->ml,obj->inactivity_timer); belle_sip_object_unref(obj->inactivity_timer); obj->inactivity_timer=NULL; } } if (from_recv) obj->last_recv_time=belle_sip_time_ms(); } /*constructor for channels creating an outgoing connection * bindip local ip address to bind on, typically 0.0.0.0 or ::0 * locaport locaport to use for binding, can be set to 0 if port doesn't matter * peer_cname canonical name of remote host, used for TLS verification * peername peer's hostname, either ip address or DNS name * pee_port peer's port to connect to. */ void belle_sip_channel_init(belle_sip_channel_t *obj, belle_sip_stack_t *stack,const char *bindip,int localport,const char *peer_cname, const char *peername, int peer_port){ /*to initialize our base class:*/ belle_sip_channel_set_socket(obj,-1,NULL); /*then initialize members*/ obj->ai_family=AF_INET; obj->peer_cname=peer_cname ? belle_sip_strdup(peer_cname) : NULL; obj->peer_name=belle_sip_strdup(peername); obj->peer_port=peer_port; obj->stack=stack; if (bindip){ if (strcmp(bindip,"::0")!=0 && strcmp(bindip,"0.0.0.0")!=0) obj->local_ip=belle_sip_strdup(bindip); if (strchr(bindip,':')!=NULL) obj->ai_family=AF_INET6; } obj->local_port=localport; obj->simulated_recv_return=1;/*not set*/ if (peername){ /*check if we are given a real dns name or just an ip address*/ struct addrinfo *ai=belle_sip_ip_address_to_addrinfo(AF_UNSPEC,peername,peer_port); if (ai) belle_sip_freeaddrinfo(ai); else obj->has_name=TRUE; } belle_sip_channel_input_stream_reset(&obj->input_stream); update_inactivity_timer(obj,FALSE); } /*constructor for channels created by incoming connections*/ void belle_sip_channel_init_with_addr(belle_sip_channel_t *obj, belle_sip_stack_t *stack, const char *bindip, int localport, const struct sockaddr *peer_addr, socklen_t addrlen){ char remoteip[64]; struct addrinfo ai; int peer_port; memset(&ai,0,sizeof(ai)); ai.ai_family=peer_addr->sa_family; ai.ai_addr=(struct sockaddr*)peer_addr; ai.ai_addrlen=addrlen; belle_sip_addrinfo_to_ip(&ai,remoteip,sizeof(remoteip),&peer_port); belle_sip_channel_init(obj,stack,bindip,localport,NULL,remoteip,peer_port); obj->peer_list=obj->current_peer=belle_sip_ip_address_to_addrinfo(ai.ai_family, obj->peer_name,obj->peer_port); obj->ai_family=ai.ai_family; } void belle_sip_channel_set_socket(belle_sip_channel_t *obj, belle_sip_socket_t sock, belle_sip_source_func_t datafunc){ belle_sip_socket_source_init((belle_sip_source_t*)obj , datafunc , obj , sock , BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_WRITE , -1); } static void channel_remove_listener(belle_sip_channel_t *obj, belle_sip_channel_listener_t *l){ obj->listeners=belle_sip_list_remove(obj->listeners,l); } void belle_sip_channel_add_listener(belle_sip_channel_t *obj, belle_sip_channel_listener_t *l){ obj->listeners=belle_sip_list_append(obj->listeners, belle_sip_object_weak_ref(l, (belle_sip_object_destroy_notify_t)channel_remove_listener,obj)); } void belle_sip_channel_remove_listener(belle_sip_channel_t *obj, belle_sip_channel_listener_t *l){ belle_sip_object_weak_unref(l,(belle_sip_object_destroy_notify_t)channel_remove_listener,obj); channel_remove_listener(obj,l); } int belle_sip_channel_matches(const belle_sip_channel_t *obj, const belle_sip_hop_t *hop, const struct addrinfo *addr){ if (hop && strcmp(hop->host,obj->peer_name)==0 && (hop->port==obj->peer_port || obj->srv_overrides_port)){ if (hop->cname && obj->peer_cname && strcmp(hop->cname,obj->peer_cname)!=0) return 0; /*cname mismatch*/ return 1; } if (addr && obj->current_peer) return addr->ai_addrlen==obj->current_peer->ai_addrlen && memcmp(addr->ai_addr,obj->current_peer->ai_addr,addr->ai_addrlen)==0; return 0; } const char *belle_sip_channel_get_local_address(belle_sip_channel_t *obj, int *port){ if (port) *port=obj->local_port; return obj->local_ip; } belle_sip_uri_t *belle_sip_channel_create_routable_uri(belle_sip_channel_t *chan) { const char *transport = belle_sip_channel_get_transport_name_lower_case(chan); belle_sip_uri_t* uri = belle_sip_uri_new(); unsigned char natted = chan->public_ip && strcmp(chan->public_ip,chan->local_ip)!=0; if (natted) { belle_sip_uri_set_host(uri, chan->public_ip); belle_sip_uri_set_port(uri, chan->public_port); } else { belle_sip_uri_set_host(uri, chan->local_ip); // With streamed protocols listening port is what we want if (chan->lp) belle_sip_uri_set_port(uri, belle_sip_uri_get_port(chan->lp->listening_uri)); else belle_sip_uri_set_port(uri,chan->local_port); } belle_sip_uri_set_transport_param(uri, transport); belle_sip_uri_set_lr_param(uri, TRUE); return uri; } int belle_sip_channel_is_reliable(const belle_sip_channel_t *obj){ return BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->reliable; } const char * belle_sip_channel_get_transport_name_lower_case(const belle_sip_channel_t *obj){ const char* transport = belle_sip_channel_get_transport_name(obj); if (strcasecmp("udp",transport)==0) return "udp"; else if (strcasecmp("tcp",transport)==0) return "tcp"; else if (strcasecmp("tls",transport)==0) return "tls"; else if (strcasecmp("dtls",transport)==0) return "dtls"; else { belle_sip_message("Cannot convert [%s] to lower case",transport); return transport; } } const char * belle_sip_channel_get_transport_name(const belle_sip_channel_t *obj){ return BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->transport; } int belle_sip_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen){ update_inactivity_timer(obj,FALSE); return BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->channel_send(obj,buf,buflen); } int belle_sip_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen){ update_inactivity_timer(obj,TRUE); return BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->channel_recv(obj,buf,buflen); } void belle_sip_channel_close(belle_sip_channel_t *obj){ if (BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->close) BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->close(obj); /*udp channel doesn't have close function*/ belle_sip_main_loop_remove_source(obj->stack->ml,(belle_sip_source_t*)obj); belle_sip_source_uninit((belle_sip_source_t*)obj); } const struct addrinfo * belle_sip_channel_get_peer(belle_sip_channel_t *obj){ return obj->current_peer; } static void channel_on_send_background_task_ended(belle_sip_channel_t *obj){ belle_sip_warning("channel [%p]: send background task has to be ended now, but work isn't finished.",obj); channel_end_send_background_task(obj); } static void channel_begin_send_background_task(belle_sip_channel_t *obj){ if (obj->bg_task_id==0){ obj->bg_task_id=belle_sip_begin_background_task("belle-sip send channel",(void (*)(void*))channel_on_send_background_task_ended, obj); if (obj->bg_task_id) belle_sip_message("channel [%p]: starting send background task with id=[%lx].",obj,obj->bg_task_id); } } static void channel_end_send_background_task(belle_sip_channel_t *obj){ if (obj->bg_task_id){ belle_sip_message("channel [%p]: ending send background task with id=[%lx].",obj,obj->bg_task_id); belle_sip_end_background_task(obj->bg_task_id); obj->bg_task_id=0; } } static void channel_on_recv_background_task_ended(belle_sip_channel_t *obj){ belle_sip_warning("channel [%p]: recv background task has to be ended now, but work isn't finished.",obj); channel_end_recv_background_task(obj); } static void channel_begin_recv_background_task(belle_sip_channel_t *obj){ if (obj->recv_bg_task_id==0){ obj->recv_bg_task_id=belle_sip_begin_background_task("belle-sip recv channel",(void (*)(void*))channel_on_recv_background_task_ended, obj); if (obj->recv_bg_task_id) belle_sip_message("channel [%p]: starting recv background task with id=[%lx].",obj,obj->recv_bg_task_id); } } static void channel_end_recv_background_task(belle_sip_channel_t *obj){ if (obj->recv_bg_task_id){ belle_sip_message("channel [%p]: ending recv background task with id=[%lx].",obj,obj->recv_bg_task_id); belle_sip_end_background_task(obj->recv_bg_task_id); obj->recv_bg_task_id=0; } } static void channel_invoke_state_listener(belle_sip_channel_t *obj){ if (obj->state==BELLE_SIP_CHANNEL_DISCONNECTED || obj->state==BELLE_SIP_CHANNEL_ERROR){ belle_sip_channel_close(obj); } BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2(obj->listeners,belle_sip_channel_listener_t,on_state_changed,obj,obj->state); } static void channel_invoke_state_listener_defered(belle_sip_channel_t *obj){ channel_invoke_state_listener(obj); belle_sip_object_unref(obj); } static void channel_connect_next(belle_sip_channel_t *obj){ belle_sip_channel_connect(obj); belle_sip_object_unref(obj); } static void belle_sip_channel_handle_error(belle_sip_channel_t *obj){ if (obj->state!=BELLE_SIP_CHANNEL_READY){ /* Previous connection attempts were failed (channel could not get ready).*/ /* See if you can retry on an alternate ip address.*/ if (obj->current_peer && obj->current_peer->ai_next){ /*obj->current_peer may be null in case of dns error*/ obj->current_peer=obj->current_peer->ai_next; channel_set_state(obj,BELLE_SIP_CHANNEL_RETRY); belle_sip_channel_close(obj); belle_sip_main_loop_do_later(obj->stack->ml,(belle_sip_callback_t)channel_connect_next,belle_sip_object_ref(obj)); return; }/*else we have already tried all the ip addresses, so give up and notify the error*/ }/*else the channel was previously working good with the current ip address but now fails, so let's notify the error*/ obj->state=BELLE_SIP_CHANNEL_ERROR; channel_end_send_background_task(obj); /*Because error notification will in practice trigger the destruction of possible transactions and this channel, * it is safer to invoke the listener outside the current call stack. * Indeed the channel encounters network errors while being called for transmiting by a transaction. */ belle_sip_main_loop_do_later(obj->stack->ml,(belle_sip_callback_t)channel_invoke_state_listener_defered,belle_sip_object_ref(obj)); } int belle_sip_channel_notify_timeout(belle_sip_channel_t *obj){ const int too_long=60; if (belle_sip_time_ms() - obj->last_recv_time>=(too_long * 1000)){ belle_sip_message("A timeout related to this channel occured and no message received during last %i seconds. This channel is suspect, moving to error state",too_long); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); return TRUE; } return FALSE; } void channel_set_state(belle_sip_channel_t *obj, belle_sip_channel_state_t state) { belle_sip_message("channel %p: state %s",obj,belle_sip_channel_state_to_string(state)); if (state==BELLE_SIP_CHANNEL_ERROR){ belle_sip_channel_handle_error(obj); }else{ obj->state=state; if (state==BELLE_SIP_CHANNEL_DISCONNECTED){ channel_end_send_background_task(obj); } channel_invoke_state_listener(obj); } } static void free_ewouldblock_buffer(belle_sip_channel_t *obj){ if (obj->ewouldblock_buffer){ belle_sip_free(obj->ewouldblock_buffer); obj->ewouldblock_buffer=NULL; obj->ewouldblock_size=0; obj->ewouldblock_offset=0; } } static void handle_ewouldblock(belle_sip_channel_t *obj, const char *buffer, size_t size){ belle_sip_source_set_events((belle_sip_source_t*)obj,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_WRITE|BELLE_SIP_EVENT_ERROR); free_ewouldblock_buffer(obj); obj->ewouldblock_buffer=belle_sip_malloc(size); obj->ewouldblock_size=size; memcpy(obj->ewouldblock_buffer,buffer,size); } static size_t find_non_printable(const char *buffer, size_t size){ size_t i; for(i=0;i 255)) return i; #endif if (!isprint(buffer[i]) && !isspace(buffer[i])) return i; } return size; } /* * this function is to avoid logging too much or non-ascii data received. */ static char *make_logbuf(belle_sip_log_level level, const char *buffer, size_t size){ char *logbuf; char truncate_msg[128]={0}; int limit=7000; /*big message when many ice candidates*/ if (!belle_sip_log_level_enabled(level)){ return belle_sip_malloc0(1); } limit=find_non_printable(buffer,MIN(size,limit)); if (limit==0){ snprintf(truncate_msg,sizeof(truncate_msg)-1,"... (binary data)"); } else if (size>limit){ snprintf(truncate_msg,sizeof(truncate_msg)-1,"... (first %i bytes shown)",limit); size=limit; } if (truncate_msg[0]!=0){ size+=sizeof(truncate_msg); } logbuf=belle_sip_malloc(size+1); strncpy(logbuf,buffer,limit); if (truncate_msg[0]!=0){ strncpy(logbuf+limit,truncate_msg,sizeof(truncate_msg)); } logbuf[size]='\0'; return logbuf; } static int send_buffer(belle_sip_channel_t *obj, const char *buffer, size_t size){ int ret=0; char *logbuf=NULL; if (obj->stack->send_error == 0){ ret=belle_sip_channel_send(obj,buffer,size); }else if (obj->stack->send_error<0){ /*for testing purpose only */ ret=obj->stack->send_error; } else { ret=size; /*to silently discard message*/ } if (ret<0){ if (!belle_sip_error_code_is_would_block(-ret)){ belle_sip_error("channel [%p]: could not send [%i] bytes from [%s://%s:%i] to [%s:%i]" ,obj ,(int)size ,belle_sip_channel_get_transport_name(obj) ,obj->local_ip ,obj->local_port ,obj->peer_name ,obj->peer_port); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); }/*ewouldblock error has to be handled by caller*/ }else if (size==(size_t)ret){ logbuf=make_logbuf(BELLE_SIP_LOG_MESSAGE, buffer,size); belle_sip_message("channel [%p]: message %s to [%s://%s:%i], size: [%i] bytes\n%s" ,obj ,obj->stack->send_error==0?"sent":"silently discarded" ,belle_sip_channel_get_transport_name(obj) ,obj->peer_name ,obj->peer_port ,ret ,logbuf); }else{ logbuf=make_logbuf(BELLE_SIP_LOG_MESSAGE,buffer,ret); belle_sip_message("channel [%p]: message partly sent to [%s://%s:%i], sent: [%i/%i] bytes:\n%s" ,obj ,belle_sip_channel_get_transport_name(obj) ,obj->peer_name ,obj->peer_port ,ret ,(int)size ,logbuf); } if (logbuf) belle_sip_free(logbuf); return ret; } static void check_content_length(belle_sip_message_t *msg, size_t body_len){ belle_sip_header_content_length_t *ctlen=belle_sip_message_get_header_by_type(msg,belle_sip_header_content_length_t); unsigned int value=ctlen ? belle_sip_header_content_length_get_content_length(ctlen) : 0; if (body_len){ if (ctlen==NULL){ belle_sip_message("message [%p] has body of size [%i] but no Content-Length, adding it.",msg,(int)body_len); belle_sip_message_add_header(msg, (belle_sip_header_t*)belle_sip_header_content_length_create((int)body_len) ); }else{ if (value!=(unsigned int)body_len){ belle_sip_warning("message [%p] has Content-Length [%u] and body size [%i] which are inconsistent, fixing it.", msg, value, (int)body_len); belle_sip_header_content_length_set_content_length(ctlen,(int)value); } } }else{ /*no body, or undetermined size body*/ if (ctlen && value!=0){ belle_sip_error("message [%p] has Content-Length [%u], but without body or body with undetermined size. Fix your app.", msg,value); } } } static void _send_message(belle_sip_channel_t *obj){ char buffer[belle_sip_send_network_buffer_size]; size_t len=0; belle_sip_error_code error=BELLE_SIP_OK; belle_sip_message_t *msg=obj->cur_out_message; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); size_t body_len=bh ? belle_sip_body_handler_get_size(bh) : 0; int sendret; size_t off; int ret; while (obj->ewouldblock_buffer){ sendret=send_buffer(obj,(const char*)obj->ewouldblock_buffer+obj->ewouldblock_offset,obj->ewouldblock_size-obj->ewouldblock_offset); if (sendret>0){ obj->ewouldblock_offset+=sendret; if (obj->ewouldblock_offset==obj->ewouldblock_size){ free_ewouldblock_buffer(obj); } /* continue to expedite the ewouldblock error until we it is completed or get a new ewouldblock*/ }else if (belle_sip_error_code_is_would_block(-sendret)) { /*we got an ewouldblock again. Nothing to do, we'll be called later in order to retry*/ return; }else {/*error or disconnection case*/ goto done; } } if (obj->out_state==OUTPUT_STREAM_SENDING_HEADERS){ BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2(obj->listeners,belle_sip_channel_listener_t,on_sending,obj,msg); check_content_length(msg,body_len); error=belle_sip_object_marshal((belle_sip_object_t*)msg,buffer,sizeof(buffer)-1,&len); if (error!=BELLE_SIP_OK) { belle_sip_error("channel [%p] _send_message: marshaling failed.",obj); goto done; } /*send the headers and eventually the body if it fits in our buffer*/ if (bh){ size_t max_body_len=sizeof(buffer)-1-len; if (body_len>0 && body_len<=max_body_len){ /*if size is known and fits into our buffer, send together with headers*/ belle_sip_body_handler_begin_transfer(bh); do{ max_body_len=sizeof(buffer)-1-len; ret=belle_sip_body_handler_send_chunk(bh,msg,(uint8_t*)buffer+len,&max_body_len); len+=max_body_len; }while(ret==BELLE_SIP_CONTINUE); belle_sip_body_handler_end_transfer(bh); }else{ if (body_len==0){ belle_sip_fatal("Sending bodies whose size is not known must be done in chunked mode, which is not supported yet."); } belle_sip_body_handler_begin_transfer(bh); obj->out_state=OUTPUT_STREAM_SENDING_BODY; } } off=0; do{ sendret=send_buffer(obj,buffer+off,len-off); if (sendret>0){ off+=sendret; if (off==len){ break; } }else if (belle_sip_error_code_is_would_block(-sendret)) { handle_ewouldblock(obj,buffer+off,len-off); return; }else {/*error or disconnection case*/ goto done; } }while(1); } if (obj->out_state==OUTPUT_STREAM_SENDING_BODY){ do{ size_t chunk_len=sizeof(buffer)-1; ret=belle_sip_body_handler_send_chunk(bh,msg,(uint8_t*)buffer,&chunk_len); if (chunk_len!=0){ off=0; do{ sendret=send_buffer(obj,buffer+off,chunk_len-off); if (sendret>0){ off+=sendret; if (off==chunk_len){ break; } }else if (belle_sip_error_code_is_would_block(-sendret)) { handle_ewouldblock(obj,buffer+off,chunk_len-off); return; }else {/*error or disconnection case*/ goto done; } }while(1); } }while(ret==BELLE_SIP_CONTINUE); belle_sip_body_handler_end_transfer(bh); } done: /*we get ready to send another message*/ belle_sip_source_set_events((belle_sip_source_t*)obj,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR); free_ewouldblock_buffer(obj); obj->out_state=OUTPUT_STREAM_IDLE; belle_sip_object_unref(obj->cur_out_message); obj->cur_out_message=NULL; } static void send_message(belle_sip_channel_t *obj, belle_sip_message_t *msg){ obj->cur_out_message=(belle_sip_message_t*)belle_sip_object_ref(msg); obj->out_state=OUTPUT_STREAM_SENDING_HEADERS; _send_message(obj); } void belle_sip_channel_prepare(belle_sip_channel_t *obj){ channel_prepare_continue(obj); } static void channel_push_outgoing(belle_sip_channel_t *obj, belle_sip_message_t *msg){ obj->outgoing_messages=belle_sip_list_append(obj->outgoing_messages,msg); } static belle_sip_message_t *channel_pop_outgoing(belle_sip_channel_t *obj){ belle_sip_message_t *msg=NULL; if (obj->outgoing_messages){ msg=(belle_sip_message_t*)obj->outgoing_messages->data; obj->outgoing_messages=belle_sip_list_delete_link(obj->outgoing_messages,obj->outgoing_messages); } return msg; } static void channel_prepare_continue(belle_sip_channel_t *obj){ switch(obj->state){ case BELLE_SIP_CHANNEL_INIT: channel_begin_send_background_task(obj); belle_sip_channel_resolve(obj); break; case BELLE_SIP_CHANNEL_RES_DONE: belle_sip_channel_connect(obj); break; case BELLE_SIP_CHANNEL_READY: channel_process_queue(obj); break; default: break; } } static void channel_process_queue(belle_sip_channel_t *obj){ belle_sip_message_t *msg; belle_sip_object_ref(obj);/* we need to ref ourself because code below may trigger our destruction*/ if (obj->out_state!=OUTPUT_STREAM_IDLE) _send_message(obj); while((msg=channel_pop_outgoing(obj))!=NULL && obj->state==BELLE_SIP_CHANNEL_READY && obj->out_state==OUTPUT_STREAM_IDLE) { send_message(obj, msg); belle_sip_object_unref(msg); } belle_sip_object_unref(obj); } void belle_sip_channel_set_ready(belle_sip_channel_t *obj, const struct sockaddr *addr, socklen_t slen){ char name[NI_MAXHOST]; char serv[NI_MAXSERV]; if (obj->local_ip==NULL){ struct sockaddr_storage saddr; socklen_t slen2=sizeof(saddr); int err; belle_sip_address_remove_v4_mapping(addr,(struct sockaddr*) &saddr,&slen2); err=getnameinfo((struct sockaddr*)&saddr,slen2,name,sizeof(name),serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV); if (err!=0){ belle_sip_error("belle_sip_channel_set_ready(): getnameinfo() failed: %s",gai_strerror(err)); }else{ obj->local_ip=belle_sip_strdup(name); obj->local_port=atoi(serv); belle_sip_message("Channel has local address %s:%s",name,serv); } } channel_set_state(obj,BELLE_SIP_CHANNEL_READY); channel_process_queue(obj); channel_end_send_background_task(obj); } static void channel_res_done(void *data, const char *name, struct addrinfo *ai_list){ belle_sip_channel_t *obj=(belle_sip_channel_t*)data; if (obj->resolver_ctx){ belle_sip_object_unref(obj->resolver_ctx); obj->resolver_ctx=NULL; } if (ai_list){ obj->peer_list=obj->current_peer=ai_list; channel_set_state(obj,BELLE_SIP_CHANNEL_RES_DONE); channel_prepare_continue(obj); }else{ belle_sip_error("%s: DNS resolution failed", __FUNCTION__); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); } } void belle_sip_channel_resolve(belle_sip_channel_t *obj){ channel_set_state(obj,BELLE_SIP_CHANNEL_RES_IN_PROGRESS); if (belle_sip_stack_dns_srv_enabled(obj->stack) && obj->lp!=NULL) obj->resolver_ctx=belle_sip_stack_resolve(obj->stack, belle_sip_channel_get_transport_name_lower_case(obj), obj->peer_name, obj->peer_port, obj->ai_family, channel_res_done, obj); else obj->resolver_ctx=belle_sip_stack_resolve_a(obj->stack, obj->peer_name, obj->peer_port, obj->ai_family, channel_res_done, obj); if (obj->resolver_ctx){ belle_sip_object_ref(obj->resolver_ctx); } return ; } void belle_sip_channel_connect(belle_sip_channel_t *obj){ char ip[64]; int port=obj->peer_port; channel_set_state(obj,BELLE_SIP_CHANNEL_CONNECTING); belle_sip_addrinfo_to_ip(obj->current_peer,ip,sizeof(ip),&port); /* update peer_port as it may have been overriden by SRV resolution*/ if (port!=obj->peer_port){ /*the SRV resolution provided a port number that must be used*/ obj->srv_overrides_port=TRUE; obj->peer_port=port; } belle_sip_message("Trying to connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),ip,obj->peer_port); if(BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->connect(obj,obj->current_peer)) { belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),obj->peer_name,obj->peer_port); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); } return; } static void queue_message(belle_sip_channel_t *obj, belle_sip_message_t *msg){ belle_sip_object_ref(msg); channel_push_outgoing(obj,msg); if (obj->state==BELLE_SIP_CHANNEL_INIT){ belle_sip_channel_prepare(obj); }else if (obj->state==BELLE_SIP_CHANNEL_READY) { channel_process_queue(obj); } } typedef struct delay_send{ belle_sip_channel_t *chan; belle_sip_message_t *msg; }delay_send_t; /* just to emulate network transmission delay */ static int on_delayed_send_do(delay_send_t *ctx){ belle_sip_message("on_delayed_send_do(): sending now"); if (ctx->chan->state!=BELLE_SIP_CHANNEL_ERROR && ctx->chan->state!=BELLE_SIP_CHANNEL_DISCONNECTED){ queue_message(ctx->chan,ctx->msg); } belle_sip_object_unref(ctx->chan); belle_sip_object_unref(ctx->msg); belle_sip_free(ctx); return FALSE; } static void queue_message_delayed(belle_sip_channel_t *obj, belle_sip_message_t *msg){ delay_send_t *ctx=belle_sip_malloc(sizeof(delay_send_t)); ctx->chan=(belle_sip_channel_t*)belle_sip_object_ref(obj); ctx->msg=(belle_sip_message_t*)belle_sip_object_ref(msg); belle_sip_main_loop_add_timeout(obj->stack->ml,(belle_sip_source_func_t)on_delayed_send_do,ctx,obj->stack->tx_delay); belle_sip_message("channel %p: message sending delayed by %i ms",obj,obj->stack->tx_delay); } int belle_sip_channel_queue_message(belle_sip_channel_t *obj, belle_sip_message_t *msg){ if (obj->stack->tx_delay>0){ queue_message_delayed(obj,msg); }else queue_message(obj,msg); return 0; } void belle_sip_channel_force_close(belle_sip_channel_t *obj){ obj->force_close=1; channel_set_state(obj,BELLE_SIP_CHANNEL_DISCONNECTED); } belle_sip_channel_t *belle_sip_channel_find_from_list_with_addrinfo(belle_sip_list_t *l, const belle_sip_hop_t *hop, const struct addrinfo *addr){ belle_sip_list_t *elem; belle_sip_channel_t *chan; for(elem=l;elem!=NULL;elem=elem->next){ chan=(belle_sip_channel_t*)elem->data; if (!chan->about_to_be_closed && belle_sip_channel_matches(chan,hop,addr)){ return chan; } } return NULL; } /* search a matching channel from a list according to supplied hop. The ai_family tells which address family is supported by the list of channels*/ belle_sip_channel_t *belle_sip_channel_find_from_list(belle_sip_list_t *l, int ai_family, const belle_sip_hop_t *hop){ struct addrinfo *res=NULL; struct addrinfo hints={0}; char portstr[20]; belle_sip_channel_t *chan; hints.ai_family=ai_family; hints.ai_flags=AI_NUMERICHOST|AI_NUMERICSERV; hints.ai_socktype=SOCK_STREAM; // needed on some platforms that return an error otherwise (QNX) if (ai_family==AF_INET6) hints.ai_flags|=AI_V4MAPPED|AI_ALL; snprintf(portstr,sizeof(portstr),"%i",hop->port); belle_sip_getaddrinfo(hop->host,portstr,&hints,&res); chan=belle_sip_channel_find_from_list_with_addrinfo(l,hop,res); if (res) belle_sip_freeaddrinfo(res); return chan; } #ifdef ANDROID unsigned long belle_sip_begin_background_task(const char *name, belle_sip_background_task_end_callback_t cb, void *data){ return wake_lock_acquire(name); } void belle_sip_end_background_task(unsigned long id){ wake_lock_release(id); } #elif !TARGET_OS_IPHONE && !defined(__APPLE__) /*defines stubs*/ unsigned long belle_sip_begin_background_task(const char *name, belle_sip_background_task_end_callback_t cb, void *data){ return 0; } void belle_sip_end_background_task(unsigned long id){ return; } #endif belle-sip-1.4.1/src/channel.h000066400000000000000000000220511252242224000157340ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BELLE_SIP_CHANNEL_H #define BELLE_SIP_CHANNEL_H #ifndef WIN32 #include #include #else #endif #define belle_sip_network_buffer_size 65535 #define belle_sip_send_network_buffer_size 16384 typedef enum belle_sip_channel_state{ BELLE_SIP_CHANNEL_INIT, BELLE_SIP_CHANNEL_RES_IN_PROGRESS, BELLE_SIP_CHANNEL_RES_DONE, BELLE_SIP_CHANNEL_CONNECTING, BELLE_SIP_CHANNEL_RETRY, BELLE_SIP_CHANNEL_READY, BELLE_SIP_CHANNEL_ERROR, BELLE_SIP_CHANNEL_DISCONNECTED }belle_sip_channel_state_t; const char * belle_sip_channel_state_to_string(belle_sip_channel_state_t state); /** * belle_sip_channel_t is an object representing a single communication channel ( socket or file descriptor), * unlike the belle_sip_listening_point_t that can owns several channels for TCP or TLS (incoming server child sockets or * outgoing client sockets). **/ typedef struct belle_sip_channel belle_sip_channel_t; BELLE_SIP_DECLARE_INTERFACE_BEGIN(belle_sip_channel_listener_t) void (*on_state_changed)(belle_sip_channel_listener_t *l, belle_sip_channel_t *, belle_sip_channel_state_t state); void (*on_message_headers)(belle_sip_channel_listener_t *l, belle_sip_channel_t *obj, belle_sip_message_t *msg); void (*on_message)(belle_sip_channel_listener_t *l, belle_sip_channel_t *obj, belle_sip_message_t *msg); void (*on_sending)(belle_sip_channel_listener_t *l, belle_sip_channel_t *obj, belle_sip_message_t *msg); int (*on_auth_requested)(belle_sip_channel_listener_t *l, belle_sip_channel_t *obj, const char* distinghised_name); BELLE_SIP_DECLARE_INTERFACE_END #define BELLE_SIP_CHANNEL_LISTENER(obj) BELLE_SIP_INTERFACE_CAST(obj,belle_sip_channel_listener_t) typedef enum input_stream_state { WAITING_MESSAGE_START, MESSAGE_AQUISITION, BODY_AQUISITION }input_stream_state_t; typedef enum output_stream_state{ OUTPUT_STREAM_IDLE, OUTPUT_STREAM_SENDING_HEADERS, OUTPUT_STREAM_SENDING_BODY }output_stream_state_t; typedef struct belle_sip_channel_input_stream{ input_stream_state_t state; char buff[belle_sip_network_buffer_size]; char* read_ptr; char* write_ptr; belle_sip_message_t *msg; int content_length; int chuncked_mode; int chunk_size; int chunk_read_size; }belle_sip_channel_input_stream_t; typedef struct belle_sip_stream_channel belle_sip_stream_channel_t; typedef struct belle_sip_tls_channel belle_sip_tls_channel_t; struct belle_sip_channel{ belle_sip_source_t base; belle_sip_stack_t *stack; belle_sip_listening_point_t *lp; /*the listening point that owns this channel*/ belle_sip_channel_state_t state; belle_sip_list_t *listeners; int ai_family; char *peer_cname; char *peer_name; int peer_port; char *local_ip; int local_port; char *public_ip; int public_port; belle_sip_resolver_context_t* resolver_ctx; struct addrinfo *peer_list; struct addrinfo *current_peer; belle_sip_list_t *outgoing_messages; belle_sip_message_t *cur_out_message; output_stream_state_t out_state; uint8_t *ewouldblock_buffer; size_t ewouldblock_size; size_t ewouldblock_offset; belle_sip_channel_input_stream_t input_stream; belle_sip_list_t* incoming_messages; belle_sip_source_t *inactivity_timer; uint64_t last_recv_time; int simulated_recv_return; /* used to simulate network error. 0= no data (disconnected) >0= do nothing -1= network error*/ unsigned long bg_task_id; unsigned long recv_bg_task_id; unsigned char force_close; /* when channel is intentionnaly disconnected, in order to prevent looping notifications*/ unsigned char learnt_ip_port; unsigned char has_name; /*set when the name of the peer is known, which is not the case of inboud connections*/ unsigned char about_to_be_closed; unsigned char srv_overrides_port; /*set when this channel was connected to destination port provided by SRV resolution*/ }; #define BELLE_SIP_CHANNEL(obj) BELLE_SIP_CAST(obj,belle_sip_channel_t) BELLE_SIP_BEGIN_DECLS void belle_sip_channel_add_listener(belle_sip_channel_t *chan, belle_sip_channel_listener_t *l); void belle_sip_channel_remove_listener(belle_sip_channel_t *obj, belle_sip_channel_listener_t *l); int belle_sip_channel_matches(const belle_sip_channel_t *obj, const belle_sip_hop_t *hop, const struct addrinfo *addr); void belle_sip_channel_resolve(belle_sip_channel_t *obj); void belle_sip_channel_connect(belle_sip_channel_t *obj); void belle_sip_channel_prepare(belle_sip_channel_t *obj); void belle_sip_channel_close(belle_sip_channel_t *obj); /** * * returns number of send byte or <0 in case of error */ int belle_sip_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen); int belle_sip_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen); /*only used by channels implementation*/ void belle_sip_channel_set_ready(belle_sip_channel_t *obj, const struct sockaddr *addr, socklen_t slen); void belle_sip_channel_init(belle_sip_channel_t *obj, belle_sip_stack_t *stack, const char *bindip,int localport, const char *peer_cname, const char *peername, int peer_port); void belle_sip_channel_init_with_addr(belle_sip_channel_t *obj, belle_sip_stack_t *stack, const char *bindip, int localport, const struct sockaddr *peer_addr, socklen_t addrlen); void belle_sip_channel_set_socket(belle_sip_channel_t *obj, belle_sip_socket_t sock, belle_sip_source_func_t datafunc); /*end of channel implementations*/ /** * Get a received message from the receive queue. This caller takes the ownership of the message. */ belle_sip_message_t* belle_sip_channel_pick_message(belle_sip_channel_t *obj); int belle_sip_channel_queue_message(belle_sip_channel_t *obj, belle_sip_message_t *msg); int belle_sip_channel_is_reliable(const belle_sip_channel_t *obj); const char * belle_sip_channel_get_transport_name(const belle_sip_channel_t *obj); const char * belle_sip_channel_get_transport_name_lower_case(const belle_sip_channel_t *obj); char *belle_sip_channel_get_public_ip_port(belle_sip_channel_t *obj); const struct addrinfo * belle_sip_channel_get_peer(belle_sip_channel_t *obj); const char *belle_sip_channel_get_local_address(belle_sip_channel_t *obj, int *port); /* * Returns a sip-uri suitable for using in record-route. * If the channel is not natted, it will return the listening port of the listening point corresponding to the channel. **/ belle_sip_uri_t *belle_sip_channel_create_routable_uri(belle_sip_channel_t *chan); #define belle_sip_channel_get_state(chan) ((chan)->state) void channel_set_state(belle_sip_channel_t *obj, belle_sip_channel_state_t state); /*just invokes the listeners to process data*/ int belle_sip_channel_process_data(belle_sip_channel_t *obj,unsigned int revents); /*this function is to be used only in belle_sip_listening_point_clean_channels()*/ void belle_sip_channel_force_close(belle_sip_channel_t *obj); /*this function is for transactions to report that a channel seems non working because a timeout occured for example. It results in the channel possibly entering error state, so that it gets cleaned. Next transactions will re-open a new one and get a better chance of receiving an answer. Returns TRUE if the channel enters error state, 0 otherwise (channel is given a second chance) */ int belle_sip_channel_notify_timeout(belle_sip_channel_t *obj); BELLE_SIP_END_DECLS BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_channel_t,belle_sip_source_t) const char *transport; int reliable; int (*connect)(belle_sip_channel_t *obj, const struct addrinfo *ai); int (*channel_send)(belle_sip_channel_t *obj, const void *buf, size_t buflen); int (*channel_recv)(belle_sip_channel_t *obj, void *buf, size_t buflen); void (*close)(belle_sip_channel_t *obj); BELLE_SIP_DECLARE_CUSTOM_VPTR_END /* * tls client certificate authentication. might be relevant for both tls and dtls channels.Only implemented in tls channel for now */ void belle_sip_tls_channel_set_client_certificates_chain(belle_sip_tls_channel_t *obj, belle_sip_certificates_chain_t* cert_chain); void belle_sip_tls_channel_set_client_certificate_key(belle_sip_tls_channel_t *obj, belle_sip_signing_key_t* key); belle_sip_channel_t *belle_sip_channel_find_from_list_with_addrinfo(belle_sip_list_t *l, const belle_sip_hop_t *hop, const struct addrinfo *addr); belle_sip_channel_t *belle_sip_channel_find_from_list(belle_sip_list_t *l, int ai_family, const belle_sip_hop_t *hop); #define BELLE_SIP_TLS_CHANNEL(obj) BELLE_SIP_CAST(obj,belle_sip_tls_channel_t) struct belle_tls_verify_policy{ belle_sip_object_t base; char *root_ca; int exception_flags; }; #endif belle-sip-1.4.1/src/clock_gettime.c000066400000000000000000000101321252242224000171250ustar00rootroot00000000000000/* * Copyright (c), MM Weiss * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the MM Weiss nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * clock_gettime_stub.c * gcc -Wall -c clock_gettime_stub.c * posix realtime functions; MacOS user space glue */ /* @comment * other possible implementation using intel builtin rdtsc * rdtsc-workaround: http://www.mcs.anl.gov/~kazutomo/rdtsc.html * * we could get the ticks by doing this * * __asm __volatile("mov %%ebx, %%esi\n\t" * "cpuid\n\t" * "xchg %%esi, %%ebx\n\t" * "rdtsc" * : "=a" (a), * "=d" (d) * ); * we could even replace our tricky sched_yield call by assembly code to get a better accurency, * anyway the following C stub will satisfy 99% of apps using posix clock_gettime call, * moreover, the setter version (clock_settime) could be easly written using mach primitives: * http://www.opensource.apple.com/source/xnu/xnu-${VERSION}/osfmk/man/ (clock_[set|get]_time) * * hackers don't be crackers, don't you use a flush toilet? * * * @see draft: ./posix-realtime-stub/posix-realtime-stub.c * */ #ifdef __APPLE__ #pragma weak clock_gettime #include #include #include #include #include #include #include #include #include "clock_gettime.h" static mach_timebase_info_data_t __clock_gettime_inf; int clock_gettime(clockid_t clk_id, struct timespec *tp) { kern_return_t ret; clock_serv_t clk; clock_id_t clk_serv_id; mach_timespec_t tm; uint64_t start, end, delta, nano; int retval = -1; switch (clk_id) { case CLOCK_REALTIME: case CLOCK_MONOTONIC: clk_serv_id = clk_id == CLOCK_REALTIME ? CALENDAR_CLOCK : SYSTEM_CLOCK; if (KERN_SUCCESS == (ret = host_get_clock_service(mach_host_self(), clk_serv_id, &clk))) { if (KERN_SUCCESS == (ret = clock_get_time(clk, &tm))) { tp->tv_sec = tm.tv_sec; tp->tv_nsec = tm.tv_nsec; retval = 0; } } if (KERN_SUCCESS != ret) { errno = EINVAL; retval = -1; } break; case CLOCK_PROCESS_CPUTIME_ID: case CLOCK_THREAD_CPUTIME_ID: start = mach_absolute_time(); if (clk_id == CLOCK_PROCESS_CPUTIME_ID) { getpid(); } else { sched_yield(); } end = mach_absolute_time(); delta = end - start; if (0 == __clock_gettime_inf.denom) { mach_timebase_info(&__clock_gettime_inf); } nano = delta * __clock_gettime_inf.numer / __clock_gettime_inf.denom; tp->tv_sec = nano * 1e-9; tp->tv_nsec = nano - (tp->tv_sec * 1e9); retval = 0; break; default: errno = EINVAL; retval = -1; } return retval; } #endif // __APPLE__ /* EOF */ belle-sip-1.4.1/src/clock_gettime.h000066400000000000000000000020111252242224000171270ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef CLOCK_GETTIME_H_ #define CLOCK_GETTIME_H_ #ifdef __APPLE__ typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID } clockid_t; int clock_gettime(clockid_t clk_id, struct timespec *tp) ; #endif #endif /* CLOCK_GETTIME_H_ */ belle-sip-1.4.1/src/dialog.c000066400000000000000000001104351252242224000155620ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" static void belle_sip_dialog_init_200Ok_retrans(belle_sip_dialog_t *obj, belle_sip_response_t *resp); static void belle_sip_dialog_stop_200Ok_retrans(belle_sip_dialog_t *obj); static int belle_sip_dialog_handle_200Ok(belle_sip_dialog_t *obj, belle_sip_response_t *msg); static void belle_sip_dialog_process_queue(belle_sip_dialog_t* dialog); static belle_sip_request_t *create_request(belle_sip_dialog_t *obj, const char *method, int full); static void belle_sip_dialog_uninit(belle_sip_dialog_t *obj){ if (obj->route_set) belle_sip_list_free_with_data(obj->route_set,belle_sip_object_unref); if (obj->remote_target) belle_sip_object_unref(obj->remote_target); if (obj->call_id) belle_sip_object_unref(obj->call_id); if (obj->local_party) belle_sip_object_unref(obj->local_party); if (obj->remote_party) belle_sip_object_unref(obj->remote_party); if (obj->local_tag) belle_sip_free(obj->local_tag); if (obj->remote_tag) belle_sip_free(obj->remote_tag); if (obj->last_out_invite) belle_sip_object_unref(obj->last_out_invite); if (obj->last_out_ack) belle_sip_object_unref(obj->last_out_ack); if (obj->last_transaction) belle_sip_object_unref(obj->last_transaction); if(obj->privacy) belle_sip_object_unref(obj->privacy); /* if(obj->preferred_identity) belle_sip_object_unref(obj->preferred_identity);*/ } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_dialog_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_dialog_t) BELLE_SIP_VPTR_INIT(belle_sip_dialog_t, belle_sip_object_t,TRUE), (belle_sip_object_destroy_t)belle_sip_dialog_uninit, NULL, NULL BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END const char* belle_sip_dialog_state_to_string(const belle_sip_dialog_state_t state) { switch(state) { case BELLE_SIP_DIALOG_NULL: return "BELLE_SIP_DIALOG_NULL"; case BELLE_SIP_DIALOG_EARLY: return "BELLE_SIP_DIALOG_EARLY"; case BELLE_SIP_DIALOG_CONFIRMED: return "BELLE_SIP_DIALOG_CONFIRMED"; case BELLE_SIP_DIALOG_TERMINATED: return "BELLE_SIP_DIALOG_TERMINATED"; default: return "Unknown state"; } } static void set_state(belle_sip_dialog_t *obj,belle_sip_dialog_state_t state) { obj->previous_state=obj->state; obj->state=state; } static void set_to_tag(belle_sip_dialog_t *obj, belle_sip_header_to_t *to){ const char *to_tag=belle_sip_header_to_get_tag(to); if (obj->is_server){ if (to_tag && !obj->local_tag) obj->local_tag=belle_sip_strdup(to_tag); }else{ if (to_tag && !obj->remote_tag) obj->remote_tag=belle_sip_strdup(to_tag); } } static void check_route_set(belle_sip_list_t *rs){ if (rs){ belle_sip_header_route_t *r=(belle_sip_header_route_t*)rs->data; if (!belle_sip_uri_has_lr_param(belle_sip_header_address_get_uri((belle_sip_header_address_t*)r))){ belle_sip_warning("top uri of route set does not contain 'lr', not really supported."); } } } static int belle_sip_dialog_init_as_uas(belle_sip_dialog_t *obj, belle_sip_request_t *req, belle_sip_response_t *resp){ const belle_sip_list_t *elem; belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(resp,belle_sip_header_to_t); belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t); belle_sip_uri_t *requri=belle_sip_request_get_uri(req); if (!ct){ belle_sip_error("No contact in request."); return -1; } if (!to){ belle_sip_error("No to in response."); return -1; } if (!cseq){ belle_sip_error("No cseq in request."); return -1; } if (!via){ belle_sip_error("No via in request."); return -1; } if (strcasecmp(belle_sip_header_via_get_protocol(via),"TLS")==0 && belle_sip_uri_is_secure(requri)){ obj->is_secure=TRUE; } /* 12.1.1 *The route set MUST be set to the list of URIs in the Record-Route * header field from the request, taken in order and preserving all URI * parameters. If no Record-Route header field is present in the *request, the route set MUST be set to the empty set. */ obj->route_set=belle_sip_list_free_with_data(obj->route_set,belle_sip_object_unref); for(elem=belle_sip_message_get_headers((belle_sip_message_t*)req,BELLE_SIP_RECORD_ROUTE);elem!=NULL;elem=elem->next){ obj->route_set=belle_sip_list_append(obj->route_set,belle_sip_object_ref(belle_sip_header_route_create( (belle_sip_header_address_t*)elem->data))); } check_route_set(obj->route_set); obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct); obj->remote_cseq=belle_sip_header_cseq_get_seq_number(cseq); /*call id already set */ /*remote party already set */ obj->local_party=(belle_sip_header_address_t*)belle_sip_object_ref(to); return 0; } static void set_last_out_invite(belle_sip_dialog_t *obj, belle_sip_request_t *req){ if (obj->last_out_invite) belle_sip_object_unref(obj->last_out_invite); obj->last_out_invite=(belle_sip_request_t*)belle_sip_object_ref(req); } static int belle_sip_dialog_init_as_uac(belle_sip_dialog_t *obj, belle_sip_request_t *req, belle_sip_response_t *resp){ const belle_sip_list_t *elem; belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(resp,belle_sip_header_contact_t); belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(resp,belle_sip_header_to_t); belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t); belle_sip_uri_t *requri=belle_sip_request_get_uri(req); if (!to){ belle_sip_error("No to in response."); return -1; } if (!cseq){ belle_sip_error("No cseq in request."); return -1; } if (!via){ belle_sip_error("No via in request."); return -1; } if (strcasecmp(belle_sip_header_via_get_protocol(via),"TLS")==0 && belle_sip_uri_is_secure(requri)){ obj->is_secure=TRUE; } /**12.1.2 * The route set MUST be set to the list of URIs in the Record-Route *header field from the response, taken in reverse order and preserving *all URI parameters. If no Record-Route header field is present in *the response, the route set MUST be set to the empty set. **/ obj->route_set=belle_sip_list_free_with_data(obj->route_set,belle_sip_object_unref); for(elem=belle_sip_message_get_headers((belle_sip_message_t*)resp,BELLE_SIP_RECORD_ROUTE);elem!=NULL;elem=elem->next){ obj->route_set=belle_sip_list_prepend(obj->route_set,belle_sip_object_ref(belle_sip_header_route_create( (belle_sip_header_address_t*)elem->data))); } check_route_set(obj->route_set); /*contact might be provided later*/ if (ct) obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct); obj->local_cseq=belle_sip_header_cseq_get_seq_number(cseq); /*call id is already set */ /*local_tag is already set*/ obj->remote_party=(belle_sip_header_address_t*)belle_sip_object_ref(to); /*local party is already set*/ if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){ set_last_out_invite(obj,req); } return 0; } int belle_sip_dialog_establish_full(belle_sip_dialog_t *obj, belle_sip_request_t *req, belle_sip_response_t *resp){ belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(resp,belle_sip_header_contact_t); belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(resp,belle_sip_header_to_t); if (strcmp(belle_sip_request_get_method(req),"INVITE")==0) obj->needs_ack=TRUE; if (obj->is_server && strcmp(belle_sip_request_get_method(req),"INVITE")==0){ belle_sip_dialog_init_200Ok_retrans(obj,resp); } else if (!obj->is_server ) { if (!ct && !obj->remote_target) { belle_sip_error("Missing contact header in resp [%p] cannot set remote target for dialog [%p]",resp,obj); return -1; } if (ct) { /*remote Contact header may have changed between early dialog to confirmed*/ if (obj->remote_target) belle_sip_object_unref(obj->remote_target); obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct); } } /*update to tag*/ set_to_tag(obj,to); set_state(obj,BELLE_SIP_DIALOG_CONFIRMED); return 0; } int belle_sip_dialog_establish(belle_sip_dialog_t *obj, belle_sip_request_t *req, belle_sip_response_t *resp){ belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(resp,belle_sip_header_to_t); belle_sip_header_call_id_t *call_id=belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t); int err; if (obj->state != BELLE_SIP_DIALOG_NULL) { belle_sip_error("Dialog [%p] already established.",obj); return -1; } if (!call_id){ belle_sip_error("No call-id in response."); return -1; } obj->call_id=(belle_sip_header_call_id_t*)belle_sip_object_ref(call_id); if (obj->is_server) err= belle_sip_dialog_init_as_uas(obj,req,resp); else err= belle_sip_dialog_init_as_uac(obj,req,resp); if (err) return err; set_to_tag(obj,to); return 0; } int belle_sip_dialog_check_incoming_request_ordering(belle_sip_dialog_t *obj, belle_sip_request_t *req){ belle_sip_header_cseq_t *cseqh=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); unsigned int cseq=belle_sip_header_cseq_get_seq_number(cseqh); if (obj->remote_cseq==0){ obj->remote_cseq=cseq; }else if (cseq>obj->remote_cseq){ return 0; } belle_sip_warning("Ignoring request because cseq is inconsistent."); return -1; } static int dialog_on_200Ok_timer(belle_sip_dialog_t *dialog){ /*reset the timer */ const belle_sip_timer_config_t *cfg=belle_sip_stack_get_timer_config(dialog->provider->stack); unsigned int prev_timeout=belle_sip_source_get_timeout(dialog->timer_200Ok); belle_sip_source_set_timeout(dialog->timer_200Ok,MIN(2*prev_timeout,(unsigned int)cfg->T2)); belle_sip_message("Dialog sending retransmission of 200Ok"); belle_sip_provider_send_response(dialog->provider,dialog->last_200Ok); return BELLE_SIP_CONTINUE; } static int dialog_on_200Ok_end(belle_sip_dialog_t *dialog){ belle_sip_request_t *bye; belle_sip_client_transaction_t *trn; belle_sip_dialog_stop_200Ok_retrans(dialog); belle_sip_error("Dialog [%p] was not ACK'd within T1*64 seconds, it is going to be terminated.",dialog); dialog->state=BELLE_SIP_DIALOG_CONFIRMED; bye=belle_sip_dialog_create_request(dialog,"BYE"); trn=belle_sip_provider_create_client_transaction(dialog->provider,bye); BELLE_SIP_TRANSACTION(trn)->is_internal=1; /*don't bother user with this transaction*/ belle_sip_client_transaction_send_request(trn); return BELLE_SIP_STOP; } static void belle_sip_dialog_init_200Ok_retrans(belle_sip_dialog_t *obj, belle_sip_response_t *resp){ const belle_sip_timer_config_t *cfg=belle_sip_stack_get_timer_config(obj->provider->stack); obj->timer_200Ok=belle_sip_timeout_source_new((belle_sip_source_func_t)dialog_on_200Ok_timer,obj,cfg->T1); belle_sip_object_set_name((belle_sip_object_t*)obj->timer_200Ok,"dialog_200Ok_timer"); belle_sip_main_loop_add_source(obj->provider->stack->ml,obj->timer_200Ok); obj->timer_200Ok_end=belle_sip_timeout_source_new((belle_sip_source_func_t)dialog_on_200Ok_end,obj,cfg->T1*64); belle_sip_object_set_name((belle_sip_object_t*)obj->timer_200Ok_end,"dialog_200Ok_timer_end"); belle_sip_main_loop_add_source(obj->provider->stack->ml,obj->timer_200Ok_end); obj->last_200Ok=(belle_sip_response_t*)belle_sip_object_ref(resp); } static void belle_sip_dialog_stop_200Ok_retrans(belle_sip_dialog_t *obj){ belle_sip_main_loop_t *ml=obj->provider->stack->ml; if (obj->timer_200Ok){ belle_sip_main_loop_remove_source(ml,obj->timer_200Ok); belle_sip_object_unref(obj->timer_200Ok); obj->timer_200Ok=NULL; } if (obj->timer_200Ok_end){ belle_sip_main_loop_remove_source(ml,obj->timer_200Ok_end); belle_sip_object_unref(obj->timer_200Ok_end); obj->timer_200Ok_end=NULL; } if (obj->last_200Ok){ belle_sip_object_unref(obj->last_200Ok); obj->last_200Ok=NULL; } } /* * return 0 if message should be delivered to the next listener, otherwise, its a retransmision, just keep it * */ int belle_sip_dialog_update(belle_sip_dialog_t *obj, belle_sip_transaction_t* transaction, int as_uas){ int is_retransmition=FALSE; int delete_dialog=FALSE; belle_sip_request_t *req=belle_sip_transaction_get_request(transaction); belle_sip_response_t *resp=belle_sip_transaction_get_response(transaction); int code=0; belle_sip_message("Dialog [%p]: now updated by transaction [%p].",obj, transaction); belle_sip_object_ref(transaction); if (obj->last_transaction) belle_sip_object_unref(obj->last_transaction); obj->last_transaction=transaction; if (!as_uas){ belle_sip_header_privacy_t *privacy_header=belle_sip_message_get_header_by_type(req,belle_sip_header_privacy_t); SET_OBJECT_PROPERTY(obj,privacy,privacy_header); } if (resp) code=belle_sip_response_get_status_code(resp); /*first update local/remote cseq*/ if (as_uas) { belle_sip_header_cseq_t* cseq=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_cseq_t); obj->remote_cseq=belle_sip_header_cseq_get_seq_number(cseq); } switch (obj->state){ case BELLE_SIP_DIALOG_NULL: /*alway establish a dialog*/ if (code>100 && code<300 && (strcmp(belle_sip_request_get_method(req),"INVITE")==0 || strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0)) { belle_sip_dialog_establish(obj,req,resp); if (code<200){ set_state(obj,BELLE_SIP_DIALOG_EARLY); break; }/* no break for code >200 because need to call belle_sip_dialog_establish_full*/ }/* no break*/ case BELLE_SIP_DIALOG_EARLY: /*don't terminate dialog for UPDATE*/ if (code>=300 && (strcmp(belle_sip_request_get_method(req),"INVITE")==0 || strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0)) { /*12.3 Termination of a Dialog Independent of the method, if a request outside of a dialog generates a non-2xx final response, any early dialogs created through provisional responses to that request are terminated. The mechanism for terminating confirmed dialogs is method specific.*/ delete_dialog=TRUE; break; } if (code>=200 && code<300 && (strcmp(belle_sip_request_get_method(req),"INVITE")==0 || strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0)) belle_sip_dialog_establish_full(obj,req,resp); break; case BELLE_SIP_DIALOG_CONFIRMED: if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){ if (code>=200 && code<300){ /*refresh the remote_target*/ belle_sip_header_contact_t *ct; if (as_uas){ ct=belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); }else{ set_last_out_invite(obj,req); ct=belle_sip_message_get_header_by_type(resp,belle_sip_header_contact_t); } if (ct){ belle_sip_object_unref(obj->remote_target); obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct); } /*handle possible retransmission of 200Ok */ if (!as_uas && (is_retransmition=(belle_sip_dialog_handle_200Ok(obj,resp)==0))) { return is_retransmition; } else { obj->needs_ack=TRUE; /*REINVITE case, ack needed by both uas and uac*/ } }else if (code>=300){ /*final response, ack will be automatically sent by transaction layer*/ obj->needs_ack=FALSE; } } else if (strcmp(belle_sip_request_get_method(req),"BYE")==0){ /*15.1.1 UAC Behavior A BYE request is constructed as would any other request within a dialog, as described in Section 12. Once the BYE is constructed, the UAC core creates a new non-INVITE client transaction, and passes it the BYE request. The UAC MUST consider the session terminated (and therefore stop sending or listening for media) as soon as the BYE request is passed to the client transaction. If the response for the BYE is a 481 (Call/Transaction Does Not Exist) or a 408 (Request Timeout) or no response at all is received for the BYE (that is, a timeout is returned by the client transaction), the UAC MUST consider the session and the dialog terminated. */ /*what should we do with other reponse >300 ?? */ if (code>=200 || (code==0 && belle_sip_transaction_get_state(transaction)==BELLE_SIP_TRANSACTION_TERMINATED)){ obj->needs_ack=FALSE; /*no longuer need ACK*/ if (obj->terminate_on_bye) delete_dialog=TRUE; } } break; case BELLE_SIP_DIALOG_TERMINATED: /*ignore*/ break; } if (delete_dialog) belle_sip_dialog_delete(obj); else { belle_sip_dialog_process_queue(obj); } return 0; } belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){ belle_sip_dialog_t *obj; belle_sip_header_from_t *from; const char *from_tag; belle_sip_header_to_t *to; const char *to_tag=NULL; from=belle_sip_message_get_header_by_type(t->request,belle_sip_header_from_t); if (from==NULL){ belle_sip_error("belle_sip_dialog_new(): no from!"); return NULL; } from_tag=belle_sip_header_from_get_tag(from); if (from_tag==NULL){ belle_sip_error("belle_sip_dialog_new(): no from tag!"); return NULL; } if (t->last_response) { to=belle_sip_message_get_header_by_type(t->last_response,belle_sip_header_to_t); if (to==NULL){ belle_sip_error("belle_sip_dialog_new(): no to!"); return NULL; } to_tag=belle_sip_header_to_get_tag(to); } obj=belle_sip_object_new(belle_sip_dialog_t); obj->terminate_on_bye=1; obj->provider=t->provider; if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t)){ obj->remote_tag=belle_sip_strdup(from_tag); obj->local_tag=to_tag?belle_sip_strdup(to_tag):NULL; /*might be null at dialog creation*/ obj->remote_party=(belle_sip_header_address_t*)belle_sip_object_ref(from); obj->is_server=TRUE; }else{ const belle_sip_list_t *predefined_routes=NULL; obj->local_tag=belle_sip_strdup(from_tag); obj->remote_tag=to_tag?belle_sip_strdup(to_tag):NULL; /*might be null at dialog creation*/ obj->local_party=(belle_sip_header_address_t*)belle_sip_object_ref(from); obj->is_server=FALSE; for(predefined_routes=belle_sip_message_get_headers((belle_sip_message_t*)t->request,BELLE_SIP_ROUTE); predefined_routes!=NULL;predefined_routes=predefined_routes->next){ obj->route_set=belle_sip_list_append(obj->route_set,belle_sip_object_ref(predefined_routes->data)); } } belle_sip_message("New %s dialog [%p] , local tag [%s], remote tag [%s]" ,obj->is_server?"server":"client" ,obj ,obj->local_tag?obj->local_tag:"" ,obj->remote_tag?obj->remote_tag:""); set_state(obj,BELLE_SIP_DIALOG_NULL); return obj; } belle_sip_request_t *belle_sip_dialog_create_ack(belle_sip_dialog_t *obj, unsigned int cseq){ belle_sip_header_cseq_t *cseqh; belle_sip_request_t *invite=obj->last_out_invite; belle_sip_request_t *ack; if (!invite){ belle_sip_error("No INVITE to ACK."); return NULL; } cseqh=belle_sip_message_get_header_by_type(invite,belle_sip_header_cseq_t); if (belle_sip_header_cseq_get_seq_number(cseqh)!=cseq){ belle_sip_error("No INVITE with cseq %i to create ack for.",cseq); return NULL; } ack=create_request(obj,"ACK",TRUE); /* 22 Usage of HTTP Authentication 22.1 Framework While a server can legitimately challenge most SIP requests, there are two requests defined by this document that require special handling for authentication: ACK and CANCEL. Under an authentication scheme that uses responses to carry values used to compute nonces (such as Digest), some problems come up for any requests that take no response, including ACK. For this reason, any credentials in the INVITE that were accepted by a server MUST be accepted by that server for the ACK. UACs creating an ACK message will duplicate all of the Authorization and Proxy-Authorization header field values that appeared in the INVITE to which the ACK corresponds. Servers MUST NOT attempt to challenge an ACK. */ if (ack){ const belle_sip_list_t *aut=belle_sip_message_get_headers((belle_sip_message_t*)obj->last_out_invite,"Authorization"); const belle_sip_list_t *prx_aut=belle_sip_message_get_headers((belle_sip_message_t*)obj->last_out_invite,"Proxy-Authorization"); if (aut) belle_sip_message_add_headers((belle_sip_message_t*)ack,aut); if (prx_aut) belle_sip_message_add_headers((belle_sip_message_t*)ack,prx_aut); /*the ack is sent statelessly, the transaction layer doesn't need the dialog information*/ belle_sip_request_set_dialog(ack,NULL); } return ack; } static belle_sip_request_t *create_request(belle_sip_dialog_t *obj, const char *method, int full){ belle_sip_request_t *req; req=belle_sip_request_create(belle_sip_header_address_get_uri(obj->remote_target), method, obj->call_id, belle_sip_header_cseq_create(obj->local_cseq,method), belle_sip_header_from_create(obj->local_party,NULL), belle_sip_header_to_create(obj->remote_party,NULL), belle_sip_header_via_new(), 0); if (full && obj->route_set) { belle_sip_message_add_headers((belle_sip_message_t*)req,obj->route_set); } if (obj->privacy) { /*repeat the last privacy set in new request. I could not find any requirement for this, but this might be safer * as proxies don't store information about dialogs*/ belle_sip_message_add_header((belle_sip_message_t*)req,BELLE_SIP_HEADER(obj->privacy)); } belle_sip_request_set_dialog(req,obj); return req; } belle_sip_request_t * belle_sip_dialog_create_queued_request(belle_sip_dialog_t *obj, const char *method){ belle_sip_request_t *req; if (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0){ /*we don't allow requests that can update the dialog's state to be sent asynchronously*/ belle_sip_error("belle_sip_dialog_create_queued_request([%p]): [%s] requests are forbidden using this method.",obj,method); return NULL; } req=create_request(obj,method,FALSE); req->dialog_queued=TRUE; return req; } static void belle_sip_dialog_update_local_cseq(belle_sip_dialog_t *obj, const char *method){ if (obj->local_cseq==0) obj->local_cseq=110; if (strcmp(method,"ACK")!=0) obj->local_cseq++; } belle_sip_request_t *belle_sip_dialog_create_request(belle_sip_dialog_t *obj, const char *method){ belle_sip_request_t *req; if (obj->state != BELLE_SIP_DIALOG_CONFIRMED && obj->state != BELLE_SIP_DIALOG_EARLY) { belle_sip_error("belle_sip_dialog_create_request(): cannot create [%s] request from dialog [%p] in state [%s]",method,obj,belle_sip_dialog_state_to_string(obj->state)); return NULL; } /*don't prevent to send a BYE in any case */ if (strcmp(method,"BYE")!=0 && obj->last_transaction && belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state(obj->last_transaction))){ if (obj->state != BELLE_SIP_DIALOG_EARLY && strcmp(method,"UPDATE")!=0) { belle_sip_error("belle_sip_dialog_create_request(): cannot create [%s] request from dialog [%p] while pending [%s] transaction in state [%s]",method,obj,belle_sip_transaction_get_method(obj->last_transaction), belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(obj->last_transaction))); return NULL; } /*else UPDATE transaction can be send in // */ } belle_sip_dialog_update_local_cseq(obj,method); req=create_request(obj,method,TRUE); return req; } static unsigned int is_system_header(belle_sip_header_t* header) { const char* name=belle_sip_header_get_name(header); return strcasecmp(BELLE_SIP_VIA,name) ==0 || strcasecmp(BELLE_SIP_FROM,name) ==0 || strcasecmp(BELLE_SIP_TO,name) ==0 || strcasecmp(BELLE_SIP_CSEQ,name) ==0 || strcasecmp(BELLE_SIP_CALL_ID,name) ==0 || strcasecmp(BELLE_SIP_PROXY_AUTHORIZATION,name) == 0 || strcasecmp(BELLE_SIP_AUTHORIZATION,name) == 0 || strcasecmp(BELLE_SIP_MAX_FORWARDS,name) == 0 || strcasecmp(BELLE_SIP_ALLOW,name) ==0 || strcasecmp(BELLE_SIP_ROUTE,name) ==0; } static void copy_non_system_headers(belle_sip_header_t* header,belle_sip_request_t* req ) { if (!is_system_header(header)) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),header); } } static belle_sip_request_t *_belle_sip_dialog_create_request_from(belle_sip_dialog_t *obj, const belle_sip_request_t *initial_req, int queued){ belle_sip_request_t* req; const char *method=belle_sip_request_get_method(initial_req); belle_sip_header_content_length_t* content_lenth; belle_sip_list_t* headers; if (queued) req=belle_sip_dialog_create_queued_request(obj,method); else req=belle_sip_dialog_create_request(obj,method); if (req==NULL) return NULL; content_lenth = belle_sip_message_get_header_by_type(initial_req,belle_sip_header_content_length_t); /*first copy non system headers*/ headers = belle_sip_message_get_all_headers(BELLE_SIP_MESSAGE(initial_req)); belle_sip_list_for_each2(headers,(void (*)(void *, void *))copy_non_system_headers,req); belle_sip_list_free(headers); /*replicate via user parameters, if any, useful for 'alias' parameter in SUBSCRIBE requests*/ { belle_sip_header_via_t *orig_via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(initial_req),belle_sip_header_via_t); belle_sip_header_via_t *new_via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_via_t); belle_sip_parameters_copy_parameters_from(BELLE_SIP_PARAMETERS(new_via),BELLE_SIP_PARAMETERS(orig_via)); } /*copy body*/ if (content_lenth && belle_sip_header_content_length_get_content_length(content_lenth)>0) { belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),belle_sip_message_get_body(BELLE_SIP_MESSAGE(initial_req)),belle_sip_header_content_length_get_content_length(content_lenth)); } return req; } belle_sip_request_t *belle_sip_dialog_create_request_from(belle_sip_dialog_t *obj, const belle_sip_request_t *initial_req){ return _belle_sip_dialog_create_request_from(obj,initial_req,FALSE); } belle_sip_request_t *belle_sip_dialog_create_queued_request_from(belle_sip_dialog_t *obj, const belle_sip_request_t *initial_req){ return _belle_sip_dialog_create_request_from(obj,initial_req,TRUE); } void belle_sip_dialog_delete(belle_sip_dialog_t *obj){ int dropped_transactions; belle_sip_message("dialog [%p] deleted.",obj); belle_sip_dialog_stop_200Ok_retrans(obj); /*if any*/ set_state(obj,BELLE_SIP_DIALOG_TERMINATED); dropped_transactions=belle_sip_list_size(obj->queued_ct); if (dropped_transactions>0) belle_sip_warning("dialog [%p]: leaves %i queued transaction aborted.",obj,dropped_transactions); belle_sip_list_for_each(obj->queued_ct,(void(*)(void*))belle_sip_transaction_terminate); obj->queued_ct=belle_sip_list_free_with_data(obj->queued_ct,belle_sip_object_unref); belle_sip_provider_remove_dialog(obj->provider,obj); } void *belle_sip_dialog_get_application_data(const belle_sip_dialog_t *dialog){ return dialog->appdata; } void belle_sip_dialog_set_application_data(belle_sip_dialog_t *dialog, void *data){ dialog->appdata=data; } const belle_sip_header_call_id_t *belle_sip_dialog_get_call_id(const belle_sip_dialog_t *dialog){ return dialog->call_id; } const char *belle_sip_dialog_get_dialog_id(const belle_sip_dialog_t *dialog){ return NULL; } const belle_sip_header_address_t *belle_sip_dialog_get_local_party(const belle_sip_dialog_t *dialog){ return dialog->local_party; } const belle_sip_header_address_t *belle_sip_dialog_get_remote_party(const belle_sip_dialog_t *dialog){ return dialog->remote_party; } unsigned int belle_sip_dialog_get_local_seq_number(const belle_sip_dialog_t *dialog){ return dialog->local_cseq; } unsigned int belle_sip_dialog_get_remote_seq_number(const belle_sip_dialog_t *dialog){ return dialog->remote_cseq; } const char *belle_sip_dialog_get_local_tag(const belle_sip_dialog_t *dialog){ return dialog->local_tag; } const char *belle_sip_dialog_get_remote_tag(const belle_sip_dialog_t *dialog){ return dialog->remote_tag; } const belle_sip_header_address_t *belle_sip_dialog_get_remote_target(belle_sip_dialog_t *dialog){ return dialog->remote_target; } const belle_sip_list_t* belle_sip_dialog_get_route_set(belle_sip_dialog_t *dialog){ return dialog->route_set; } belle_sip_dialog_state_t belle_sip_dialog_get_state(const belle_sip_dialog_t *dialog){ return dialog->state; } belle_sip_dialog_state_t belle_sip_dialog_get_previous_state(const belle_sip_dialog_t *dialog) { return dialog->previous_state; } int belle_sip_dialog_is_server(const belle_sip_dialog_t *dialog){ return dialog->is_server; } int belle_sip_dialog_is_secure(const belle_sip_dialog_t *dialog){ return dialog->is_secure; } void belle_sip_dialog_send_ack(belle_sip_dialog_t *obj, belle_sip_request_t *request){ if (obj->needs_ack){ obj->needs_ack=FALSE; if (obj->last_out_ack) belle_sip_object_unref(obj->last_out_ack); obj->last_out_ack=(belle_sip_request_t*)belle_sip_object_ref(request); belle_sip_provider_send_request(obj->provider,request); belle_sip_dialog_process_queue(obj); }else{ belle_sip_error("Why do you want to send an ACK ?"); } } void belle_sip_dialog_terminate_on_bye(belle_sip_dialog_t *obj, int val){ obj->terminate_on_bye=val; } /*returns 1 if message belongs to the dialog, 0 otherwise */ int belle_sip_dialog_match(belle_sip_dialog_t *obj, belle_sip_message_t *msg, int as_uas){ belle_sip_header_call_id_t *call_id=belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t); belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t); belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t); const char *from_tag; const char *to_tag; const char *call_id_value; if (call_id==NULL || from==NULL || to==NULL) return 0; call_id_value=belle_sip_header_call_id_get_call_id(call_id); from_tag=belle_sip_header_from_get_tag(from); to_tag=belle_sip_header_to_get_tag(to); return _belle_sip_dialog_match(obj,call_id_value,as_uas ? to_tag : from_tag, as_uas ? from_tag : to_tag); } int _belle_sip_dialog_match(belle_sip_dialog_t *obj, const char *call_id, const char *local_tag, const char *remote_tag){ const char *dcid; if (obj->state==BELLE_SIP_DIALOG_NULL) belle_sip_fatal("_belle_sip_dialog_match() must not be used for dialog in null state."); dcid=belle_sip_header_call_id_get_call_id(obj->call_id); return strcmp(dcid,call_id)==0 && strcmp(obj->local_tag,local_tag)==0 && obj->remote_tag /* handle 180 without to tag */ && strcmp(obj->remote_tag,remote_tag)==0; } void belle_sip_dialog_check_ack_sent(belle_sip_dialog_t*obj){ belle_sip_client_transaction_t* client_trans; if (obj->needs_ack){ belle_sip_request_t *req; belle_sip_error("Your listener did not ACK'd the 200Ok for your INVITE request. The dialog will be terminated."); req=belle_sip_dialog_create_request(obj,"BYE"); client_trans=belle_sip_provider_create_client_transaction(obj->provider,req); BELLE_SIP_TRANSACTION(client_trans)->is_internal=TRUE; /*internal transaction, don't bother user with 200ok*/ belle_sip_client_transaction_send_request(client_trans); /*call dialog terminated*/ } } /* * return 0 if dialog handle the 200ok * */ static int belle_sip_dialog_handle_200Ok(belle_sip_dialog_t *obj, belle_sip_response_t *msg){ if (obj->last_out_ack){ belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(msg,belle_sip_header_cseq_t); if (cseq){ belle_sip_header_cseq_t *ack_cseq=belle_sip_message_get_header_by_type(obj->last_out_ack,belle_sip_header_cseq_t); if (belle_sip_header_cseq_get_seq_number(cseq)==belle_sip_header_cseq_get_seq_number(ack_cseq)){ /*pass for retransmission*/ belle_sip_message("Dialog retransmitting last ack automatically"); belle_sip_provider_send_request(obj->provider,obj->last_out_ack); return 0; }else belle_sip_message("No already created ACK matching 200Ok for dialog [%p]",obj); } } return -1; } int belle_sip_dialog_handle_ack(belle_sip_dialog_t *obj, belle_sip_request_t *ack){ belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(ack,belle_sip_header_cseq_t); if (obj->needs_ack && belle_sip_header_cseq_get_seq_number(cseq)==obj->remote_cseq){ belle_sip_message("Incoming INVITE has ACK, dialog is happy"); obj->needs_ack=FALSE; belle_sip_dialog_stop_200Ok_retrans(obj); belle_sip_dialog_process_queue(obj); return 0; } belle_sip_message("Dialog ignoring incoming ACK (surely a retransmission)"); return -1; } belle_sip_transaction_t* belle_sip_dialog_get_last_transaction(const belle_sip_dialog_t *dialog) { return dialog->last_transaction; } int belle_sip_dialog_request_pending(const belle_sip_dialog_t *dialog){ return dialog->last_transaction ? belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state(dialog->last_transaction)) : FALSE; } /* for notify exception As per RFC 3265; 3.3.4. Dialog creation and termination If an initial SUBSCRIBE request is not sent on a pre-existing dialog, the subscriber will wait for a response to the SUBSCRIBE request or a matching NOTIFY. ... ... If an initial SUBSCRIBE is sent on a pre-existing dialog, a matching 200-class response or successful NOTIFY request merely creates a new subscription associated with that dialog. */ int belle_sip_dialog_is_authorized_transaction(const belle_sip_dialog_t *dialog,const char* method) { if (belle_sip_dialog_request_pending(dialog)){ const char* last_transaction_request; if (strcasecmp(method,"BYE")==0) return TRUE; /*don't reject a BYE*/ last_transaction_request = belle_sip_request_get_method(belle_sip_transaction_get_request(dialog->last_transaction)); if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(dialog->last_transaction,belle_sip_client_transaction_t) && strcmp(last_transaction_request,"SUBSCRIBE")==0 && strcmp(method,"NOTIFY")==0){ /*stupid as it is, you have to accept a NOTIFY for a SUBSCRIBE for which no answer is received yet...*/ return TRUE; } if (strcmp(last_transaction_request,"INVITE")==0 && (strcmp(method,"PRACK")==0 || strcmp(method,"UPDATE")==0)){ /*PRACK /UPDATE needs to be sent or received during reINVITEs.*/ return TRUE; } return FALSE; } else { return TRUE; } } void belle_sip_dialog_queue_client_transaction(belle_sip_dialog_t *dialog, belle_sip_client_transaction_t *tr){ dialog->queued_ct=belle_sip_list_append(dialog->queued_ct, belle_sip_object_ref(tr)); } static void _belle_sip_dialog_process_queue(belle_sip_dialog_t* dialog){ belle_sip_client_transaction_t *tr=NULL; if (dialog->state==BELLE_SIP_DIALOG_TERMINATED || belle_sip_dialog_request_pending(dialog) || dialog->needs_ack) goto end; dialog->queued_ct=belle_sip_list_pop_front(dialog->queued_ct,(void**)&tr); if (tr){ belle_sip_message("Dialog [%p]: sending queued request.",dialog); tr->base.sent_by_dialog_queue=TRUE; belle_sip_client_transaction_send_request(tr); belle_sip_object_unref(tr); } end: belle_sip_object_unref(dialog); } void belle_sip_dialog_process_queue(belle_sip_dialog_t* dialog){ /*process queue does not process synchronously. * This is to let the application handle responses and eventually submit new requests without being blocked. * Typically when a reINVITE is challenged, we want a chance to re-submit an authenticated request before processing * queued requests*/ belle_sip_main_loop_do_later(dialog->provider->stack->ml,(belle_sip_callback_t)_belle_sip_dialog_process_queue,belle_sip_object_ref(dialog)); } void belle_sip_dialog_update_request(belle_sip_dialog_t *dialog, belle_sip_request_t *req){ belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_dialog_update_local_cseq(dialog,belle_sip_request_get_method(req)); if (dialog->route_set) belle_sip_message_add_headers((belle_sip_message_t*)req,dialog->route_set); belle_sip_request_set_uri(req,belle_sip_header_address_get_uri(dialog->remote_target)); belle_sip_header_cseq_set_seq_number(cseq,dialog->local_cseq); } belle-sip-1.4.1/src/dns.c000066400000000000000000006215031252242224000151120ustar00rootroot00000000000000/* ========================================================================== * dns.c - Recursive, Reentrant DNS Resolver. * -------------------------------------------------------------------------- * Copyright (c) 2008, 2009, 2010 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #if !defined(__FreeBSD__) && !defined(__sun) #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif #undef _DEFAULT_SOURCE #define _DEFAULT_SOURCE #undef _BSD_SOURCE #define _BSD_SOURCE #undef _DARWIN_C_SOURCE #define _DARWIN_C_SOURCE #undef _NETBSD_SOURCE #define _NETBSD_SOURCE #endif #include /* offsetof() */ #ifdef _WIN32 #define uint32_t unsigned int #else #include /* uint32_t */ #endif #include /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */ #include /* FILE fopen(3) fclose(3) getc(3) rewind(3) */ #include /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */ #ifdef _MSC_VER #define strcasecmp _stricmp #define strncasecmp _strnicmp #else #include /* strcasecmp(3) strncasecmp(3) */ #endif #include /* isspace(3) isdigit(3) */ #include /* time_t time(2) difftime(3) */ #include /* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */ #include /* errno EINVAL ENOENT */ #undef NDEBUG #include /* assert(3) */ #if _WIN32 #ifndef FD_SETSIZE #define FD_SETSIZE 2048 #endif #include #include #ifndef USE_FIXED_NAMESERVERS #include #pragma comment(lib, "IPHLPAPI.lib") #endif #ifndef IPV6_V6ONLY #define IPV6_V6ONLY 27 #endif #else #include /* FD_SETSIZE socklen_t */ #include /* FD_ZERO FD_SET fd_set select(2) */ #include /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */ #if defined(AF_UNIX) #include /* struct sockaddr_un */ #endif #include /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */ #include /* _POSIX_THREADS gethostname(3) close(2) */ #include /* POLLIN POLLOUT */ #include /* struct sockaddr_in struct sockaddr_in6 */ #include /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */ #include /* struct addrinfo */ #endif #ifdef ANDROID #include #endif #include "dns.h" #if defined(HAVE_RESINIT) || defined(USE_STRUCT_RES_STATE_NAMESERVERS) #include #endif //#define DNS_DEBUG 1 /* * C O M P I L E R A N N O T A T I O N S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if __GNUC__ #define DNS_NOTUSED __attribute__((unused)) #else #define DNS_NOTUSED #endif #if __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" #elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif /* * S T A N D A R D M A C R O S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef MIN #define MIN(a, b) (((a) < (b))? (a) : (b)) #endif #ifndef MAX #define MAX(a, b) (((a) > (b))? (a) : (b)) #endif #ifndef lengthof #define lengthof(a) (sizeof (a) / sizeof (a)[0]) #endif #ifndef endof #define endof(a) (&(a)[lengthof((a))]) #endif /* * M I S C E L L A N E O U S C O M P A T * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if _WIN32 || _WIN64 #define PRIuZ "Iu" #else #define PRIuZ "zu" #endif #ifndef DNS_THREAD_SAFE #if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0 #define DNS_THREAD_SAFE 1 #else #define DNS_THREAD_SAFE 0 #endif #endif /* * D E B U G M A C R O S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int dns_debug = 2; #if DNS_DEBUG #undef DNS_DEBUG #define DNS_DEBUG dns_debug #define DNS_SAY_(fmt, ...) \ do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0) #define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n") #define DNS_HAI DNS_SAY("HAI") #define DNS_SHOW_(P, fmt, ...) do { \ if (DNS_DEBUG > 1) { \ fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \ fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \ dns_p_dump((P), stderr); \ fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \ } \ } while (0) #define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "") #else /* !DNS_DEBUG */ #undef DNS_DEBUG #define DNS_DEBUG 0 #define DNS_SAY(...) #define DNS_HAI #define DNS_SHOW(...) #endif /* DNS_DEBUG */ /* * V E R S I O N R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ const char *dns_vendor(void) { return DNS_VENDOR; } /* dns_vendor() */ int dns_v_rel(void) { return DNS_V_REL; } /* dns_v_rel() */ int dns_v_abi(void) { return DNS_V_ABI; } /* dns_v_abi() */ int dns_v_api(void) { return DNS_V_API; } /* dns_v_api() */ /* * E R R O R R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if _WIN32 #define DNS_EINTR WSAEINTR #define DNS_EINPROGRESS WSAEINPROGRESS #define DNS_EISCONN WSAEISCONN #define DNS_EWOULDBLOCK WSAEWOULDBLOCK #define DNS_EALREADY WSAEALREADY #define DNS_EAGAIN EAGAIN #define DNS_ETIMEDOUT WSAETIMEDOUT #define dns_syerr() ((int)GetLastError()) #define dns_soerr() ((int)WSAGetLastError()) #else #define DNS_EINTR EINTR #define DNS_EINPROGRESS EINPROGRESS #define DNS_EISCONN EISCONN #define DNS_EWOULDBLOCK EWOULDBLOCK #define DNS_EALREADY EALREADY #define DNS_EAGAIN EAGAIN #define DNS_ETIMEDOUT ETIMEDOUT #define dns_syerr() errno #define dns_soerr() errno #endif const char *dns_strerror(int error) { switch (error) { case DNS_ENOBUFS: return "DNS packet buffer too small"; case DNS_EILLEGAL: return "Illegal DNS RR name or data"; case DNS_EORDER: return "Attempt to push RR out of section order"; case DNS_ESECTION: return "Invalid section specified"; case DNS_EUNKNOWN: return "Unknown DNS error"; case DNS_EADDRESS: return "Invalid textual address form"; default: return strerror(error); } /* switch() */ } /* dns_strerror() */ /* * A T O M I C R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ DNS_NOTUSED static void dns_atomic_fence(void) { return; } /* dns_atomic_fence() */ static unsigned dns_atomic_inc(dns_atomic_t *i) { return (*i)++; } /* dns_atomic_inc() */ static unsigned dns_atomic_dec(dns_atomic_t *i) { return (*i)--; } /* dns_atomic_dec() */ static unsigned dns_atomic_load(dns_atomic_t *i) { return *i; } /* dns_atomic_load() */ DNS_NOTUSED static unsigned dns_atomic_store(dns_atomic_t *i, unsigned n) { unsigned o; o = dns_atomic_load(i); *i = n; return o; } /* dns_atomic_store() */ /* * C R Y P T O R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * P R N G */ #ifndef DNS_RANDOM #if defined(HAVE_ARC4RANDOM) \ || defined(__OpenBSD__) \ || defined(__FreeBSD__) \ || defined(__NetBSD__) \ || defined(__APPLE__) #define DNS_RANDOM arc4random #elif __linux #define DNS_RANDOM random #else #define DNS_RANDOM rand #endif #endif #define DNS_RANDOM_arc4random 1 #define DNS_RANDOM_random 2 #define DNS_RANDOM_rand 3 #define DNS_RANDOM_RAND_bytes 4 #define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM)) #if DNS_RANDOM_OPENSSL #include #endif static unsigned dns_random_(void) { #if DNS_RANDOM_OPENSSL unsigned r; assert(1 == RAND_bytes((unsigned char *)&r, sizeof r)); return r; #else return DNS_RANDOM(); #endif } /* dns_random_() */ #ifdef _MSC_VER unsigned (*dns_random)(void) = &dns_random_; #else unsigned (*dns_random)(void) __attribute__((weak)) = &dns_random_; #endif /* * P E R M U T A T I O N G E N E R A T O R */ #define DNS_K_TEA_KEY_SIZE 16 #define DNS_K_TEA_BLOCK_SIZE 8 #define DNS_K_TEA_CYCLES 32 #define DNS_K_TEA_MAGIC 0x9E3779B9U struct dns_k_tea { uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)]; unsigned cycles; }; /* struct dns_k_tea */ static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) { memcpy(tea->key, key, sizeof tea->key); tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES; } /* dns_k_tea_init() */ static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) { uint32_t y, z, sum, n; y = v[0]; z = v[1]; sum = 0; for (n = 0; n < tea->cycles; n++) { sum += DNS_K_TEA_MAGIC; y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]); z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]); } w[0] = y; w[1] = z; return /* void */; } /* dns_k_tea_encrypt() */ /* * Permutation generator, based on a Luby-Rackoff Feistel construction. * * Specifically, this is a generic balanced Feistel block cipher using TEA * (another block cipher) as the pseudo-random function, F. At best it's as * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or * perhaps Bernstein's Salsa20 core; I am naively trying to keep things * simple. * * The generator can create a permutation of any set of numbers, as long as * the size of the set is an even power of 2. This limitation arises either * out of an inherent property of balanced Feistel constructions, or by my * own ignorance. I'll tackle an unbalanced construction after I wrap my * head around Schneier and Kelsey's paper. * * CAVEAT EMPTOR. IANAC. */ #define DNS_K_PERMUTOR_ROUNDS 8 struct dns_k_permutor { unsigned stepi, length, limit; unsigned shift, mask, rounds; struct dns_k_tea tea; }; /* struct dns_k_permutor */ static DNS_INLINE unsigned dns_k_permutor_powof(unsigned n) { unsigned m, i = 0; for (m = 1; m < n; m <<= 1, i++) ;; return i; } /* dns_k_permutor_powof() */ static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) { uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)]; unsigned width, i; p->stepi = 0; p->length = (high - low) + 1; p->limit = high; width = dns_k_permutor_powof(p->length); width += width % 2; p->shift = width / 2; p->mask = (1U << p->shift) - 1; p->rounds = DNS_K_PERMUTOR_ROUNDS; for (i = 0; i < lengthof(key); i++) key[i] = dns_random(); dns_k_tea_init(&p->tea, key, 0); return /* void */; } /* dns_k_permutor_init() */ static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) { uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)]; memset(in, '\0', sizeof in); in[0] = k; in[1] = x; dns_k_tea_encrypt(&p->tea, in, out); return p->mask & out[0]; } /* dns_k_permutor_F() */ static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) { unsigned l[2], r[2]; unsigned i; i = 0; l[i] = p->mask & (n >> p->shift); r[i] = p->mask & (n >> 0); do { l[(i + 1) % 2] = r[i % 2]; r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]); i++; } while (i < p->rounds - 1); return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0); } /* dns_k_permutor_E() */ DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) { unsigned l[2], r[2]; unsigned i; i = p->rounds - 1; l[i % 2] = p->mask & (n >> p->shift); r[i % 2] = p->mask & (n >> 0); do { i--; r[i % 2] = l[(i + 1) % 2]; l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]); } while (i > 0); return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0); } /* dns_k_permutor_D() */ static unsigned dns_k_permutor_step(struct dns_k_permutor *p) { unsigned n; do { n = dns_k_permutor_E(p, p->stepi++); } while (n >= p->length); return n + (p->limit + 1 - p->length); } /* dns_k_permutor_step() */ /* * Simple permutation box. Useful for shuffling rrsets from an iterator. * Uses AES s-box to provide good diffusion. * * Seems to pass muster under runs test. * * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }' * library(lawstat) * runs.test(scan(file="/tmp/out")) * EOF */ static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) { static const unsigned char sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; unsigned char a, b; unsigned i; a = 0xff & (n >> 0); b = 0xff & (n >> 8); for (i = 0; i < 4; i++) { a ^= 0xff & s; a = sbox[a] ^ b; b = sbox[b] ^ a; s >>= 8; } return ((0xff00 & (a << 8)) | (0x00ff & (b << 0))); } /* dns_k_shuffle16() */ /* * U T I L I T Y R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_MAXINTERVAL 300 struct dns_clock { time_t sample, elapsed; }; /* struct dns_clock */ static void dns_begin(struct dns_clock *clk) { clk->sample = time(0); clk->elapsed = 0; } /* dns_begin() */ static time_t dns_elapsed(struct dns_clock *clk) { time_t curtime; if ((time_t)-1 == time(&curtime)) return clk->elapsed; if (curtime > clk->sample) clk->elapsed += (time_t)MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL); clk->sample = curtime; return clk->elapsed; } /* dns_elapsed() */ static size_t dns_af_len(int af) { static size_t table[AF_MAX] = { 0 }; table[AF_INET6] = sizeof (struct sockaddr_in6); table[AF_INET] = sizeof (struct sockaddr_in); #if defined(AF_UNIX) && !defined(_WIN32) table[AF_UNIX] = sizeof (struct sockaddr_un); #endif return table[af]; } /* dns_af_len() */ #define dns_sa_family(sa) (((struct sockaddr_storage *)(sa))->ss_family) #define dns_sa_len(sa) dns_af_len(dns_sa_family(sa)) #define DNS_SA_NOPORT &dns_sa_noport static unsigned short dns_sa_noport; static unsigned short *dns_sa_port(int af, void *sa) { switch (af) { case AF_INET6: return &((struct sockaddr_in6 *)sa)->sin6_port; case AF_INET: return &((struct sockaddr_in *)sa)->sin_port; default: return DNS_SA_NOPORT; } } /* dns_sa_port() */ static void *dns_sa_addr(int af, void *sa) { switch (af) { case AF_INET6: return &((struct sockaddr_in6 *)sa)->sin6_addr; case AF_INET: return &((struct sockaddr_in *)sa)->sin_addr; default: return 0; } } /* dns_sa_addr() */ #if _WIN32 static int dns_inet_pton(int af, const void *src, void *dst) { union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u; wchar_t wsrc[MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1]; int size_of_u = sizeof u; u.sin.sin_family = af; mbstowcs(wsrc, (const char *)src, sizeof(wsrc)); if (0 != WSAStringToAddressW(wsrc, af, (void *)0, (struct sockaddr *)&u, &size_of_u)) return -1; switch (af) { case AF_INET6: *(struct in6_addr *)dst = u.sin6.sin6_addr; return 1; case AF_INET: *(struct in_addr *)dst = u.sin.sin_addr; return 1; default: return 0; } } /* dns_inet_pton() */ static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) { union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u; wchar_t wdst[MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1]; /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */ memset(&u, 0, sizeof u); u.sin.sin_family = af; switch (af) { case AF_INET6: u.sin6.sin6_addr = *(struct in6_addr *)src; break; case AF_INET: u.sin.sin_addr = *(struct in_addr *)src; break; default: return 0; } if (0 != WSAAddressToStringW((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, wdst, &lim)) return 0; wcstombs((char *)dst, wdst, lim); return dst; } /* dns_inet_ntop() */ #else #define dns_inet_pton(...) inet_pton(__VA_ARGS__) #define dns_inet_ntop(...) inet_ntop(__VA_ARGS__) #endif static dns_error_t dns_pton(int af, const void *src, void *dst) { switch (dns_inet_pton(af, src, dst)) { case 1: return 0; case -1: return dns_soerr(); default: return DNS_EADDRESS; } } /* dns_pton() */ static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) { return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr(); } /* dns_ntop() */ size_t dns_strlcpy(char *dst, const char *src, size_t lim) { char *d = dst; char *e = &dst[lim]; const char *s = src; if (d < e) { do { if ('\0' == (*d++ = *s++)) return s - src - 1; } while (d < e); d[-1] = '\0'; } while (*s++ != '\0') ;; return s - src - 1; } /* dns_strlcpy() */ size_t dns_strlcat(char *dst, const char *src, size_t lim) { char *d = memchr(dst, '\0', lim); char *e = &dst[lim]; const char *s = src; const char *p; if (d && d < e) { do { if ('\0' == (*d++ = *s++)) return d - dst - 1; } while (d < e); d[-1] = '\0'; } p = s; while (*s++ != '\0') ;; return lim + (s - p - 1); } /* dns_strlcat() */ #if _WIN32 static char *dns_strsep(char **sp, const char *delim) { char *p; if (!(p = *sp)) return 0; *sp += strcspn(p, delim); if (**sp != '\0') { **sp = '\0'; ++*sp; } else *sp = NULL; return p; } /* dns_strsep() */ #else #define dns_strsep(...) strsep(__VA_ARGS__) #endif #if _WIN32 #ifndef strcasecmp #define strcasecmp(...) _stricmp(__VA_ARGS__) #endif #ifndef strncasecmp #define strncasecmp(...) _strnicmp(__VA_ARGS__) #endif #endif static int dns_poll(int fd, short events, int timeout) { /* For our usage in belle sip, we are called by the main loop when something is to read on the dns socket. * As a result there is no need to perform a blocking select. **/ #if 0 fd_set rset, wset; struct timeval tv = { timeout, 0 }; return 0; if (!events) return 0; assert(fd >= 0 && (unsigned)fd < FD_SETSIZE); FD_ZERO(&rset); FD_ZERO(&wset); if (events & DNS_POLLIN) FD_SET(fd, &rset); if (events & DNS_POLLOUT) FD_SET(fd, &wset); select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &tv : NULL); #endif return 0; } /* dns_poll() */ #if !_WIN32 DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) { #if DNS_THREAD_SAFE return pthread_sigmask(how, set, oset); #else return (0 == sigprocmask(how, set, oset))? 0 : errno; #endif } /* dns_sigmask() */ #endif static long dns_send(int fd, const void *src, size_t lim, int flags) { #if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE return send(fd, src, lim, flags); #elif defined MSG_NOSIGNAL return send(fd, src, lim, flags|MSG_NOSIGNAL); #elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */ /* * SIGPIPE handling similar to the approach described in * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html */ sigset_t pending, blocked, piped; long count; int saved, error; sigemptyset(&pending); sigpending(&pending); if (!sigismember(&pending, SIGPIPE)) { sigemptyset(&piped); sigaddset(&piped, SIGPIPE); sigemptyset(&blocked); if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked))) goto error; } count = send(fd, src, lim, flags); if (!sigismember(&pending, SIGPIPE)) { saved = errno; if (count == -1 && errno == EPIPE) { while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR) ;; } if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL))) goto error; errno = saved; } return count; error: errno = error; return -1; #else #error "unable to suppress SIGPIPE" return send(fd, src, lim, flags); #endif } /* dns_send() */ /* * P A C K E T R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ unsigned dns_p_count(struct dns_packet *P, enum dns_section section) { unsigned count; switch (section) { case DNS_S_QD: return ntohs(dns_header(P)->qdcount); case DNS_S_AN: return ntohs(dns_header(P)->ancount); case DNS_S_NS: return ntohs(dns_header(P)->nscount); case DNS_S_AR: return ntohs(dns_header(P)->arcount); default: count = 0; if (section & DNS_S_QD) count += ntohs(dns_header(P)->qdcount); if (section & DNS_S_AN) count += ntohs(dns_header(P)->ancount); if (section & DNS_S_NS) count += ntohs(dns_header(P)->nscount); if (section & DNS_S_AR) count += ntohs(dns_header(P)->arcount); return count; } } /* dns_p_count() */ struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) { if (!P) return 0; assert(size >= offsetof(struct dns_packet, data) + 12); memset(P, 0, sizeof *P); P->size = size - offsetof(struct dns_packet, data); P->end = 12; memset(P->data, '\0', 12); return P; } /* dns_p_init() */ static unsigned short dns_p_qend(struct dns_packet *P) { unsigned short qend = 12; unsigned i, count = dns_p_count(P, DNS_S_QD); for (i = 0; i < count && qend < P->end; i++) { if (P->end == (qend = dns_d_skip(qend, P))) goto invalid; if (P->end - qend < 4) goto invalid; qend += 4; } return MIN(qend, P->end); invalid: return P->end; } /* dns_p_qend() */ struct dns_packet *dns_p_make(size_t len, int *error) { struct dns_packet *P; size_t size = dns_p_calcsize(len); if (!(P = dns_p_init(malloc(size), size))) *error = dns_syerr(); return P; } /* dns_p_make() */ int dns_p_grow(struct dns_packet **P) { struct dns_packet *tmp; size_t size; int error; if (!*P) { if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error))) return error; return 0; } size = dns_p_sizeof(*P); size |= size >> 1; size |= size >> 2; size |= size >> 4; size |= size >> 8; size++; if (size > 65536) return DNS_ENOBUFS; if (!(tmp = realloc(*P, dns_p_calcsize(size)))) return dns_syerr(); tmp->size = size; *P = tmp; return 0; } /* dns_p_grow() */ struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) { if (!P) return 0; P->end = MIN(P->size, P0->end); memcpy(P->data, P0->data, P->end); return P; } /* dns_p_copy() */ struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) { size_t bufsiz = MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0)); struct dns_packet *M; enum dns_section section; struct dns_rr rr, mr; int error, copy; struct dns_rr_i dns_rr_it; int dns_grep_error; if (!A && B) { A = B; Amask = Bmask; B = 0; } merge: if (!(M = dns_p_make(bufsiz, &error))) goto error; for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) { if (A && (section & Amask)) { dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.section = section; dns_rr_i_init(&dns_rr_it, A); for (; dns_rr_grep(&rr, 1, &dns_rr_it, A, &dns_grep_error); ) { if ((error = dns_rr_copy(M, &rr, A))) goto error; } } if (B && (section & Bmask)) { dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.section = section; dns_rr_i_init(&dns_rr_it, B); for (; dns_rr_grep(&rr, 1, &dns_rr_it, B, &dns_grep_error); ) { copy = 1; dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.type = rr.type; dns_rr_it.section = DNS_S_ALL; dns_rr_i_init(&dns_rr_it, M); for (; dns_rr_grep(&rr, 1, &dns_rr_it, M, &dns_grep_error); ) { if (!(copy = dns_rr_cmp(&rr, B, &mr, M))) break; } if (copy && (error = dns_rr_copy(M, &rr, B))) goto error; } } } return M; error: free(M); M = 0; if (error == DNS_ENOBUFS && bufsiz < 65535) { bufsiz = MIN(65535, bufsiz * 2); goto merge; } *error_ = error; return 0; } /* dns_p_merge() */ static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t); void dns_p_dictadd(struct dns_packet *P, unsigned short dn) { unsigned short lp, lptr, i; lp = dn; while (lp < P->end) { if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) { lptr = ((0x3f & P->data[lp + 0]) << 8) | ((0xff & P->data[lp + 1]) << 0); for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) { if (P->dict[i] == lptr) { P->dict[i] = dn; return; } } } lp = dns_l_skip(lp, P->data, P->end); } for (i = 0; i < lengthof(P->dict); i++) { if (!P->dict[i]) { P->dict[i] = dn; break; } } } /* dns_p_dictadd() */ int dns_p_push(struct dns_packet *P, enum dns_section section, const void *dn, size_t dnlen, enum dns_type type, enum dns_class class, unsigned ttl, const void *any) { size_t end = P->end; int error; if ((error = dns_d_push(P, dn, dnlen))) goto error; if (P->size - P->end < 4) goto nobufs; P->data[P->end++] = 0xff & (type >> 8); P->data[P->end++] = 0xff & (type >> 0); P->data[P->end++] = 0xff & (class >> 8); P->data[P->end++] = 0xff & (class >> 0); if (section == DNS_S_QD) goto update; if (P->size - P->end < 6) goto nobufs; P->data[P->end++] = 0x7f & (ttl >> 24); P->data[P->end++] = 0xff & (ttl >> 16); P->data[P->end++] = 0xff & (ttl >> 8); P->data[P->end++] = 0xff & (ttl >> 0); if ((error = dns_any_push(P, (union dns_any *)any, type))) goto error; update: switch (section) { case DNS_S_QD: if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR)) goto order; if (!P->qd.base && (error = dns_p_study(P))) goto error; dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1); P->qd.end = P->end; P->an.base = P->end; P->an.end = P->end; P->ns.base = P->end; P->ns.end = P->end; P->ar.base = P->end; P->ar.end = P->end; break; case DNS_S_AN: if (dns_p_count(P, DNS_S_NS|DNS_S_AR)) goto order; if (!P->an.base && (error = dns_p_study(P))) goto error; dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1); P->an.end = P->end; P->ns.base = P->end; P->ns.end = P->end; P->ar.base = P->end; P->ar.end = P->end; break; case DNS_S_NS: if (dns_p_count(P, DNS_S_AR)) goto order; if (!P->ns.base && (error = dns_p_study(P))) goto error; dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1); P->ns.end = P->end; P->ar.base = P->end; P->ar.end = P->end; break; case DNS_S_AR: if (!P->ar.base && (error = dns_p_study(P))) goto error; dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1); P->ar.end = P->end; break; default: error = DNS_ESECTION; goto error; } /* switch() */ return 0; nobufs: error = DNS_ENOBUFS; goto error; order: error = DNS_EORDER; goto error; error: P->end = end; return error; } /* dns_p_push() */ static void dns_s_unstudy(struct dns_s_memo *m) { m->base = 0; m->end = 0; } static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) { enum dns_section section; struct dns_rr rr; int error; union dns_any any; char pretty[sizeof any * 2]; size_t len; fputs(";; [HEADER]\n", fp); fprintf(fp, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr); fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode); fprintf(fp, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa); fprintf(fp, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc); fprintf(fp, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd); fprintf(fp, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra); fprintf(fp, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode); section = 0; while (dns_rr_grep(&rr, 1, I, P, &error)) { if (section != rr.section) { char strsection[DNS_STRMAXLEN + 1] = { 0 }; fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section, strsection, DNS_STRMAXLEN + 1), dns_p_count(P, rr.section)); } dns_s_unstudy(&P->an); dns_s_unstudy(&P->ns); if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error))) fprintf(fp, "%s\n", pretty); section = rr.section; } } /* dns_p_dump3() */ void dns_p_dump(struct dns_packet *P, FILE *fp) { struct dns_rr_i dns_rr_it; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_i_init(&dns_rr_it, P); dns_p_dump3(P, &dns_rr_it, fp); } /* dns_p_dump() */ static void dns_p_unstudy(struct dns_packet *P) { dns_s_unstudy(&P->qd); dns_s_unstudy(&P->ar); } /* dns_p_unstudy() */ static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned base, struct dns_packet *P) { unsigned short count, rp; count = dns_p_count(P, section); for (rp = base; count && rp < P->end; count--) rp = dns_rr_skip(rp, P); m->base = base; m->end = rp; return 0; } /* dns_s_study() */ int dns_p_study(struct dns_packet *P) { int error; if ((error = dns_s_study(&P->qd, DNS_S_QD, 12, P))) goto error; if ((error = dns_s_study(&P->an, DNS_S_AN, P->qd.end, P))) goto error; if ((error = dns_s_study(&P->ns, DNS_S_NS, P->an.end, P))) goto error; if ((error = dns_s_study(&P->ar, DNS_S_AR, P->ns.end, P))) goto error; return 0; error: dns_p_unstudy(P); return error; } /* dns_p_study() */ /* * D O M A I N N A M E R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifndef DNS_D_MAXPTRS #define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */ #endif static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) { unsigned short len; unsigned nptrs = 0; retry: if (src >= end) goto invalid; switch (0x03 & (data[src] >> 6)) { case 0x00: len = (0x3f & (data[src++])); if (end - src < len) goto invalid; if (lim > 0) { memcpy(dst, &data[src], MIN(lim, len)); dst[MIN(lim - 1, len)] = '\0'; } *nxt = src + len; return len; case 0x01: goto invalid; case 0x02: goto invalid; case 0x03: if (++nptrs > DNS_D_MAXPTRS) goto invalid; if (end - src < 2) goto invalid; src = ((0x3f & data[src + 0]) << 8) | ((0xff & data[src + 1]) << 0); goto retry; } /* switch() */ /* NOT REACHED */ invalid: *nxt = end; return 0; } /* dns_l_expand() */ static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) { unsigned short len; if (src >= end) goto invalid; switch (0x03 & (data[src] >> 6)) { case 0x00: len = (0x3f & (data[src++])); if (end - src < len) goto invalid; return (len)? src + len : end; case 0x01: goto invalid; case 0x02: goto invalid; case 0x03: return end; } /* switch() */ /* NOT REACHED */ invalid: return end; } /* dns_l_skip() */ size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) { unsigned char *dst = dst_; const unsigned char *src = src_; size_t dp = 0, sp = 0; int lc; /* trim any leading dot(s) */ while (sp < len && src[sp] == '.') sp++; for (lc = 0; sp < len; lc = src[sp]) { if (dp < lim) dst[dp] = src[sp]; sp++; dp++; /* trim extra dot(s) */ while (sp < len && src[sp] == '.') sp++; } if ((flags & DNS_D_ANCHOR) && lc != '.') { if (dp < lim) dst[dp] = '.'; dp++; } if (lim > 0) dst[MIN(dp, lim - 1)] = '\0'; return dp; } /* dns_d_trim() */ char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) { if (flags & DNS_D_TRIM) { dns_d_trim(dst, lim, src, len, flags); } if (flags & DNS_D_ANCHOR) { dns_d_anchor(dst, lim, src, len); } else { memmove(dst, src, MIN(lim, len)); if (lim > 0) ((char *)dst)[MIN(len, lim - 1)] = '\0'; } return dst; } /* dns_d_init() */ size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) { if (len == 0) return 0; memmove(dst, src, MIN(lim, len)); if (((const char *)src)[len - 1] != '.') { if (len < lim) ((char *)dst)[len] = '.'; len++; } if (lim > 0) ((char *)dst)[MIN(lim - 1, len)] = '\0'; return len; } /* dns_d_anchor() */ size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) { const char *dot; /* XXX: Skip any leading dot. Handles cleaving root ".". */ if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1))) return 0; len -= dot - (const char *)src; /* XXX: Unless root, skip the label's trailing dot. */ if (len > 1) { src = ++dot; len--; } else src = dot; memmove(dst, src, MIN(lim, len)); if (lim > 0) ((char *)dst)[MIN(lim - 1, len)] = '\0'; return len; } /* dns_d_cleave() */ size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error) { struct { unsigned char *b; size_t p, x; } dst, src; unsigned char ch = '.'; dst.b = dst_; dst.p = 0; dst.x = 1; src.b = (unsigned char *)src_; src.p = 0; src.x = 0; while (src.x < len) { ch = src.b[src.x]; if (ch == '.') { if (dst.p < lim) dst.b[dst.p] = (0x3f & (src.x - src.p)); dst.p = dst.x++; src.p = ++src.x; } else { if (dst.x < lim) dst.b[dst.x] = ch; dst.x++; src.x++; } } /* while() */ if (src.x > src.p) { if (dst.p < lim) dst.b[dst.p] = (0x3f & (src.x - src.p)); dst.p = dst.x; } if (dst.p > 1) { if (dst.p < lim) dst.b[dst.p] = 0x00; dst.p++; } #if 1 if (dst.p < lim) { struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b; unsigned i; a.p = 0; while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) { for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) { b.p = P->dict[i]; while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) { a.y = a.x; b.y = b.x; while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) { a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim); b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end); } if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) { dst.b[a.p++] = 0xc0 | (0x3f & (b.p >> 8)); dst.b[a.p++] = (0xff & (b.p >> 0)); return a.p; } b.p = b.x; } /* while() */ } /* for() */ a.p = a.x; } /* while() */ } /* if () */ #endif return dst.p; } /* dns_d_comp() */ unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) { unsigned short len; while (src < P->end) { switch (0x03 & (P->data[src] >> 6)) { case 0x00: /* FOLLOWS */ len = (0x3f & P->data[src++]); if (0 == len) { /* success ==> */ return src; } else if (P->end - src > len) { src += len; break; } else goto invalid; /* NOT REACHED */ case 0x01: /* RESERVED */ goto invalid; case 0x02: /* RESERVED */ goto invalid; case 0x03: /* POINTER */ if (P->end - src < 2) goto invalid; src += 2; /* success ==> */ return src; } /* switch() */ } /* while() */ invalid: //assert(0); return P->end; } /* dns_d_skip() */ #include size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) { size_t dstp = 0; unsigned nptrs = 0; unsigned char len; while (src < P->end) { switch ((0x03 & (P->data[src] >> 6))) { case 0x00: /* FOLLOWS */ len = (0x3f & P->data[src]); if (0 == len) { if (dstp == 0) { if (dstp < lim) ((unsigned char *)dst)[dstp] = '.'; dstp++; } /* NUL terminate */ if (lim > 0) ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0'; /* success ==> */ return dstp; } src++; if (P->end - src < len) goto toolong; if (dstp < lim) memcpy(&((unsigned char *)dst)[dstp], &P->data[src], MIN(len, lim - dstp)); src += len; dstp += len; if (dstp < lim) ((unsigned char *)dst)[dstp] = '.'; dstp++; nptrs = 0; continue; case 0x01: /* RESERVED */ goto reserved; case 0x02: /* RESERVED */ goto reserved; case 0x03: /* POINTER */ if (++nptrs > DNS_D_MAXPTRS) goto toolong; if (P->end - src < 2) goto toolong; src = ((0x3f & P->data[src + 0]) << 8) | ((0xff & P->data[src + 1]) << 0); continue; } /* switch() */ } /* while() */ toolong: *error = DNS_EILLEGAL; if (lim > 0) ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0'; return 0; reserved: *error = DNS_EILLEGAL; if (lim > 0) ((unsigned char *)dst)[MIN(dstp, lim - 1)] = '\0'; return 0; } /* dns_d_expand() */ int dns_d_push(struct dns_packet *P, const void *dn, size_t len) { size_t lim = P->size - P->end; unsigned dp = P->end; int error; len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error); if (len == 0) return error; if (len > lim) return DNS_ENOBUFS; P->end += len; dns_p_dictadd(P, dp); return 0; } /* dns_d_push() */ size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) { char host[DNS_D_MAXNAME + 1]; struct dns_rr_i i; struct dns_rr rr; unsigned depth; int error; if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len)) { error = ENAMETOOLONG; goto error; } for (depth = 0; depth < 7; depth++) { dns_rr_i_init(memset(&i, 0, sizeof i), P); i.section = DNS_S_ALL & ~DNS_S_QD; i.name = host; i.type = DNS_T_CNAME; if (!dns_rr_grep(&rr, 1, &i, P, &error)) break; if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P))) goto error; } return dns_strlcpy(dst, host, lim); error: *error_ = error; return 0; } /* dns_d_cname() */ /* * R E S O U R C E R E C O R D R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) { unsigned char dn[DNS_D_MAXNAME + 1]; union dns_any any; size_t len; int error; if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error))) return error; else if (len >= sizeof dn) return DNS_EILLEGAL; if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q))) return error; return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any); } /* dns_rr_copy() */ int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) { unsigned short p = src; if (src >= P->end) goto invalid; rr->dn.p = p; rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p; if (P->end - p < 4) goto invalid; rr->type = ((0xff & P->data[p + 0]) << 8) | ((0xff & P->data[p + 1]) << 0); rr->class = ((0xff & P->data[p + 2]) << 8) | ((0xff & P->data[p + 3]) << 0); p += 4; if (src < dns_p_qend(P)) { rr->section = DNS_S_QUESTION; rr->ttl = 0; rr->rd.p = 0; rr->rd.len = 0; return 0; } if (P->end - p < 4) goto invalid; rr->ttl = ((0x7f & P->data[p + 0]) << 24) | ((0xff & P->data[p + 1]) << 16) | ((0xff & P->data[p + 2]) << 8) | ((0xff & P->data[p + 3]) << 0); p += 4; if (P->end - p < 2) goto invalid; rr->rd.len = ((0xff & P->data[p + 0]) << 8) | ((0xff & P->data[p + 1]) << 0); rr->rd.p = p + 2; p += 2; if (P->end - p < rr->rd.len) goto invalid; return 0; invalid: //assert(0); return DNS_EILLEGAL; } /* dns_rr_parse() */ static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) { unsigned short rp, rdlen; rp = dns_d_skip(src, P); if (P->end - rp < 4) return P->end - src; rp += 4; /* TYPE, CLASS */ if (rp <= dns_p_qend(P)) return rp - src; if (P->end - rp < 6) return P->end - src; rp += 6; /* TTL, RDLEN */ rdlen = ((0xff & P->data[rp - 2]) << 8) | ((0xff & P->data[rp - 1]) << 0); if (P->end - rp < rdlen) return P->end - src; rp += rdlen; return rp - src; } /* dns_rr_len() */ unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) { return src + dns_rr_len(src, P); } /* dns_rr_skip() */ static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) { enum dns_section section; unsigned count, index; unsigned short rp; if (src >= P->qd.base && src < P->qd.end) return DNS_S_QD; if (src >= P->an.base && src < P->an.end) return DNS_S_AN; if (src >= P->ns.base && src < P->ns.end) return DNS_S_NS; if (src >= P->ar.base && src < P->ar.end) return DNS_S_AR; /* NOTE: Possibly bad memoization. Try it the hard-way. */ for (rp = 12, index = 0; rp < src && rp < P->end; index++) rp = dns_rr_skip(rp, P); section = DNS_S_QD; count = dns_p_count(P, section); while (index >= count && section <= DNS_S_AR) { section <<= 1; count += dns_p_count(P, section); } return DNS_S_ALL & section; } /* dns_rr_section() */ static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) { struct dns_rr rr; int error; if ((error = dns_rr_parse(&rr, src, P))) return 0; return rr.type; } /* dns_rr_type() */ int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) { char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1]; union dns_any any0, any1; int cmp, error; size_t len; if ((cmp = r0->type - r1->type)) return cmp; if ((cmp = r0->class - r1->class)) return cmp; /* * FIXME: Do label-by-label comparison to handle illegally long names? */ if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error)) || len >= sizeof host0) return -1; if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error)) || len >= sizeof host1) return 1; if ((cmp = strcasecmp(host0, host1))) return cmp; if (DNS_S_QD & (r0->section | r1->section)) { if (r0->section == r1->section) return 0; return (r0->section == DNS_S_QD)? -1 : 1; } if ((error = dns_any_parse(&any0, r0, P0))) return -1; if ((error = dns_any_parse(&any1, r1, P1))) return 1; return dns_any_cmp(&any0, r0->type, &any1, r1->type); } /* dns_rr_cmp() */ static DNSBool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) { struct dns_rr rr1; struct dns_rr_i dns_rr_it; int dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.type = rr0->type; dns_rr_it.section = rr0->section; dns_rr_i_init(&dns_rr_it, P1); for (; dns_rr_grep(&rr1, 1, &dns_rr_it, P1, &dns_grep_error); ) { if (0 == dns_rr_cmp(rr0, P0, &rr1, P1)) return 1; } return 0; } /* dns_rr_exists() */ static unsigned short dns_rr_offset(struct dns_rr *rr) { return rr->dn.p; } /* dns_rr_offset() */ static DNSBool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) { if (i->section && !(rr->section & i->section)) return 0; if (i->type && rr->type != i->type && i->type != DNS_T_ALL) return 0; if (i->class && rr->class != i->class && i->class != DNS_C_ANY) return 0; if (i->name) { char dn[DNS_D_MAXNAME + 1]; size_t len; int error; if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error)) || len >= sizeof dn) return 0; if (0 != strcasecmp(dn, i->name)) return 0; } if (i->data && i->type && rr->section > DNS_S_QD) { union dns_any rd; int error; if ((error = dns_any_parse(&rd, rr, P))) return 0; if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type)) return 0; } return 1; } /* dns_rr_i_match() */ static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) { unsigned short rp; struct dns_rr r0, rr; int error; if ((i->section & DNS_S_QD) && P->qd.base) rp = P->qd.base; else if ((i->section & DNS_S_AN) && P->an.base) rp = P->an.base; else if ((i->section & DNS_S_NS) && P->ns.base) rp = P->ns.base; else if ((i->section & DNS_S_AR) && P->ar.base) rp = P->ar.base; else rp = 12; for (; rp < P->end; rp = dns_rr_skip(rp, P)) { if ((error = dns_rr_parse(&rr, rp, P))) continue; rr.section = dns_rr_section(rp, P); if (!dns_rr_i_match(&rr, i, P)) continue; r0 = rr; goto lower; } return P->end; lower: if (i->sort == &dns_rr_i_packet) return dns_rr_offset(&r0); while ((rp = dns_rr_skip(rp, P)) < P->end) { if ((error = dns_rr_parse(&rr, rp, P))) continue; rr.section = dns_rr_section(rp, P); if (!dns_rr_i_match(&rr, i, P)) continue; if (i->sort(&rr, &r0, i, P) < 0) r0 = rr; } return dns_rr_offset(&r0); } /* dns_rr_i_start() */ static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) { struct dns_rr r0, r1, rr; int error; if ((error = dns_rr_parse(&r0, rp, P))) return P->end; r0.section = dns_rr_section(rp, P); rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12; for (; rp < P->end; rp = dns_rr_skip(rp, P)) { if ((error = dns_rr_parse(&rr, rp, P))) continue; rr.section = dns_rr_section(rp, P); if (!dns_rr_i_match(&rr, i, P)) continue; if (i->sort(&rr, &r0, i, P) <= 0) continue; r1 = rr; goto lower; } return P->end; lower: if (i->sort == &dns_rr_i_packet) return dns_rr_offset(&r1); while ((rp = dns_rr_skip(rp, P)) < P->end) { if ((error = dns_rr_parse(&rr, rp, P))) continue; rr.section = dns_rr_section(rp, P); if (!dns_rr_i_match(&rr, i, P)) continue; if (i->sort(&rr, &r0, i, P) <= 0) continue; if (i->sort(&rr, &r1, i, P) >= 0) continue; r1 = rr; } return dns_rr_offset(&r1); } /* dns_rr_i_skip() */ int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { return (int)a->dn.p - (int)b->dn.p; } /* dns_rr_i_packet() */ int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { int cmp; if ((cmp = a->section - b->section)) return cmp; if (a->type != b->type) return (int)a->dn.p - (int)b->dn.p; return dns_rr_cmp(a, P, b, P); } /* dns_rr_i_order() */ int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { int cmp; while (!i->state.regs[0]) i->state.regs[0] = dns_random(); if ((cmp = a->section - b->section)) return cmp; return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]); } /* dns_rr_i_shuffle() */ struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) { static const struct dns_rr_i i_initializer; i->state = i_initializer.state; i->saved = i->state; return i; } /* dns_rr_i_init() */ unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) { unsigned count = 0; int error; switch (i->state.exec) { case 0: if (!i->sort) i->sort = &dns_rr_i_packet; i->state.next = dns_rr_i_start(i, P); i->state.exec++; /* FALL THROUGH */ case 1: while (count < lim && i->state.next < P->end) { if ((error = dns_rr_parse(rr, i->state.next, P))) goto error; rr->section = dns_rr_section(i->state.next, P); rr++; count++; i->state.count++; i->state.next = dns_rr_i_skip(i->state.next, i, P); } /* while() */ break; } /* switch() */ return count; error: *error_ = error; return count; } /* dns_rr_grep() */ static size_t dns__printchar(void *dst, size_t lim, size_t cp, unsigned char ch) { if (cp < lim) ((unsigned char *)dst)[cp] = ch; return 1; } /* dns__printchar() */ static size_t dns__printstring(void *dst, size_t lim, size_t cp, const void *src, size_t len) { if (cp < lim) memcpy(&((unsigned char *)dst)[cp], src, MIN(len, lim - cp)); return len; } /* dns__printstring() */ static void dns__printnul(void *dst, size_t lim, size_t off) { if (lim > 0) ((unsigned char *)dst)[MIN(off, lim - 1)] = '\0'; } /* dns__printnul() */ static size_t dns__print10(void *dst, size_t lim, size_t off, unsigned n, unsigned pad) { unsigned char tmp[32]; unsigned dp = off; unsigned cp = 0; unsigned d = 1000000000; unsigned ch; pad = MAX(1, pad); while (d) { if ((ch = n / d) || cp > 0) { n -= ch * d; tmp[cp] = '0' + ch; cp++; } d /= 10; } while (cp < pad) { dp += dns__printchar(dst, lim, dp, '0'); pad--; } dp += dns__printstring(dst, lim, dp, tmp, cp); return dp - off; } /* dns__print10() */ size_t dns_rr_print(void *dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *error_) { union dns_any any; size_t cp, n, rdlen; void *rd; int error; cp = 0; if (rr->section == DNS_S_QD) cp += dns__printchar(dst, lim, cp, ';'); if (!(n = dns_d_expand(&((unsigned char *)dst)[cp], (cp < lim)? lim - cp : 0, rr->dn.p, P, &error))) goto error; cp += n; if (rr->section != DNS_S_QD) { cp += dns__printchar(dst, lim, cp, ' '); cp += dns__print10(dst, lim, cp, rr->ttl, 0); } cp += dns__printchar(dst, lim, cp, ' '); { char strclass[DNS_STRMAXLEN + 1] = { 0 }; dns_strclass(rr->class, strclass, DNS_STRMAXLEN + 1); cp += dns__printstring(dst, lim, cp, strclass, strlen(strclass)); } cp += dns__printchar(dst, lim, cp, ' '); { char strtype[DNS_STRMAXLEN + 1] = { 0 }; dns_strtype(rr->type, strtype, DNS_STRMAXLEN + 1); cp += dns__printstring(dst, lim, cp, strtype, strlen(strtype)); } if (rr->section == DNS_S_QD) goto epilog; cp += dns__printchar(dst, lim, cp, ' '); if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P))) goto error; if (cp < lim) { rd = &((unsigned char *)dst)[cp]; rdlen = lim - cp; } else { rd = 0; rdlen = 0; } cp += dns_any_print(rd, rdlen, &any, rr->type); epilog: dns__printnul(dst, lim, cp); return cp; error: *error_ = error; return 0; } /* dns_rr_print() */ int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) { unsigned long addr; if (rr->rd.len != 4) return DNS_EILLEGAL; addr = ((0xff & P->data[rr->rd.p + 0]) << 24) | ((0xff & P->data[rr->rd.p + 1]) << 16) | ((0xff & P->data[rr->rd.p + 2]) << 8) | ((0xff & P->data[rr->rd.p + 3]) << 0); a->addr.s_addr = htonl(addr); return 0; } /* dns_a_parse() */ int dns_a_push(struct dns_packet *P, struct dns_a *a) { unsigned long addr; if (P->size - P->end < 6) return DNS_ENOBUFS; P->data[P->end++] = 0x00; P->data[P->end++] = 0x04; addr = ntohl(a->addr.s_addr); P->data[P->end++] = 0xff & (addr >> 24); P->data[P->end++] = 0xff & (addr >> 16); P->data[P->end++] = 0xff & (addr >> 8); P->data[P->end++] = 0xff & (addr >> 0); return 0; } /* dns_a_push() */ size_t dns_a_arpa(void *dst, size_t lim, const struct dns_a *a) { unsigned long a4 = ntohl(a->addr.s_addr); size_t cp = 0; unsigned i; for (i = 4; i > 0; i--) { cp += dns__print10(dst, lim, cp, (0xff & a4), 0); cp += dns__printchar(dst, lim, cp, '.'); a4 >>= 8; } cp += dns__printstring(dst, lim, cp, "in-addr.arpa.", 13); dns__printnul(dst, lim, cp); return cp; } /* dns_a_arpa() */ int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) { if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr)) return -1; if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr)) return 1; return 0; } /* dns_a_cmp() */ size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) { char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0"; size_t len; dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr); dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr, strlen(addr)))); return len; } /* dns_a_print() */ int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) { if (rr->rd.len != sizeof aaaa->addr.s6_addr) return DNS_EILLEGAL; memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr); return 0; } /* dns_aaaa_parse() */ int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) { if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr) return DNS_ENOBUFS; P->data[P->end++] = 0x00; P->data[P->end++] = 0x10; memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr); P->end += sizeof aaaa->addr.s6_addr; return 0; } /* dns_aaaa_push() */ int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) { unsigned i; int cmp; for (i = 0; i < lengthof(a->addr.s6_addr); i++) { if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i]))) return cmp; } return 0; } /* dns_aaaa_cmp() */ size_t dns_aaaa_arpa(void *dst, size_t lim, const struct dns_aaaa *aaaa) { static const unsigned char hex[16] = "0123456789abcdef"; size_t cp = 0; unsigned nyble; int i, j; for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) { nyble = aaaa->addr.s6_addr[i]; for (j = 0; j < 2; j++) { cp += dns__printchar(dst, lim, cp, hex[0x0f & nyble]); cp += dns__printchar(dst, lim, cp, '.'); nyble >>= 4; } } cp += dns__printstring(dst, lim, cp, "ip6.arpa.", 9); dns__printnul(dst, lim, cp); return cp; } /* dns_aaaa_arpa() */ size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) { char addr[INET6_ADDRSTRLEN + 1] = "::"; size_t len; dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr); dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr, strlen(addr)))); return len; } /* dns_aaaa_print() */ int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) { size_t len; int error; if (rr->rd.len < 3) return DNS_EILLEGAL; mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8)) | (0x00ff & (P->data[rr->rd.p + 1] << 0)); if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error))) return error; else if (len >= sizeof mx->host) return DNS_EILLEGAL; return 0; } /* dns_mx_parse() */ int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) { size_t end, len; int error; if (P->size - P->end < 5) return DNS_ENOBUFS; end = P->end; P->end += 2; P->data[P->end++] = 0xff & (mx->preference >> 8); P->data[P->end++] = 0xff & (mx->preference >> 0); if ((error = dns_d_push(P, mx->host, strlen(mx->host)))) goto error; len = P->end - end - 2; P->data[end + 0] = 0xff & (len >> 8); P->data[end + 1] = 0xff & (len >> 0); return 0; error: P->end = end; return error; } /* dns_mx_push() */ int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) { int cmp; if ((cmp = a->preference - b->preference)) return cmp; return strcasecmp(a->host, b->host); } /* dns_mx_cmp() */ size_t dns_mx_print(void *dst, size_t lim, struct dns_mx *mx) { size_t cp = 0; cp += dns__print10(dst, lim, cp, mx->preference, 0); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__printstring(dst, lim, cp, mx->host, strlen(mx->host)); dns__printnul(dst, lim, cp); return cp; } /* dns_mx_print() */ size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) { return dns_strlcpy(dst, mx->host, lim); } /* dns_mx_cname() */ int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) { size_t len; int error; if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error))) return error; else if (len >= sizeof ns->host) return DNS_EILLEGAL; return 0; } /* dns_ns_parse() */ int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) { size_t end, len; int error; if (P->size - P->end < 3) return DNS_ENOBUFS; end = P->end; P->end += 2; if ((error = dns_d_push(P, ns->host, strlen(ns->host)))) goto error; len = P->end - end - 2; P->data[end + 0] = 0xff & (len >> 8); P->data[end + 1] = 0xff & (len >> 0); return 0; error: P->end = end; return error; } /* dns_ns_push() */ int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) { return strcasecmp(a->host, b->host); } /* dns_ns_cmp() */ size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) { size_t cp; cp = dns__printstring(dst, lim, 0, ns->host, strlen(ns->host)); dns__printnul(dst, lim, cp); return cp; } /* dns_ns_print() */ size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) { return dns_strlcpy(dst, ns->host, lim); } /* dns_ns_cname() */ int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) { return dns_ns_parse((struct dns_ns *)cname, rr, P); } /* dns_cname_parse() */ int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) { return dns_ns_push(P, (struct dns_ns *)cname); } /* dns_cname_push() */ int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) { return strcasecmp(a->host, b->host); } /* dns_cname_cmp() */ size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) { return dns_ns_print(dst, lim, (struct dns_ns *)cname); } /* dns_cname_print() */ size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) { return dns_strlcpy(dst, cname->host, lim); } /* dns_cname_cname() */ int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) { struct { void *dst; size_t lim; } dn[] = { { soa->mname, sizeof soa->mname }, { soa->rname, sizeof soa->rname } }; unsigned *ts[] = { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum }; unsigned short rp; unsigned i, j, n; int error; /* MNAME / RNAME */ if ((rp = rr->rd.p) >= P->end) return DNS_EILLEGAL; for (i = 0; i < lengthof(dn); i++) { if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error))) return error; else if (n >= dn[i].lim) return DNS_EILLEGAL; if ((rp = dns_d_skip(rp, P)) >= P->end) return DNS_EILLEGAL; } /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */ for (i = 0; i < lengthof(ts); i++) { for (j = 0; j < 4; j++, rp++) { if (rp >= P->end) return DNS_EILLEGAL; *ts[i] <<= 8; *ts[i] |= (0xff & P->data[rp]); } } return 0; } /* dns_soa_parse() */ int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) { void *dn[] = { soa->mname, soa->rname }; unsigned ts[] = { (0xffffffff & soa->serial), (0x7fffffff & soa->refresh), (0x7fffffff & soa->retry), (0x7fffffff & soa->expire), (0xffffffff & soa->minimum) }; unsigned i, j; size_t end, len; int error; end = P->end; if ((P->end += 2) >= P->size) goto toolong; /* MNAME / RNAME */ for (i = 0; i < lengthof(dn); i++) { if ((error = dns_d_push(P, dn[i], strlen(dn[i])))) goto error; } /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */ for (i = 0; i < lengthof(ts); i++) { if ((P->end += 4) >= P->size) goto toolong; for (j = 1; j <= 4; j++) { P->data[P->end - j] = (0xff & ts[i]); ts[i] >>= 8; } } len = P->end - end - 2; P->data[end + 0] = (0xff & (len >> 8)); P->data[end + 1] = (0xff & (len >> 0)); return 0; toolong: error = DNS_ENOBUFS; /* FALL THROUGH */ error: P->end = end; return error; } /* dns_soa_push() */ int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) { int cmp; if ((cmp = strcasecmp(a->mname, b->mname))) return cmp; if ((cmp = strcasecmp(a->rname, b->rname))) return cmp; if (a->serial > b->serial) return -1; else if (a->serial < b->serial) return 1; if (a->refresh > b->refresh) return -1; else if (a->refresh < b->refresh) return 1; if (a->retry > b->retry) return -1; else if (a->retry < b->retry) return 1; if (a->expire > b->expire) return -1; else if (a->expire < b->expire) return 1; if (a->minimum > b->minimum) return -1; else if (a->minimum < b->minimum) return 1; return 0; } /* dns_soa_cmp() */ size_t dns_soa_print(void *dst, size_t lim, struct dns_soa *soa) { size_t cp = 0; cp += dns__printstring(dst, lim, cp, soa->mname, strlen(soa->mname)); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__printstring(dst, lim, cp, soa->rname, strlen(soa->rname)); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__print10(dst, lim, cp, soa->serial, 0); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__print10(dst, lim, cp, soa->refresh, 0); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__print10(dst, lim, cp, soa->retry, 0); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__print10(dst, lim, cp, soa->expire, 0); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__print10(dst, lim, cp, soa->minimum, 0); dns__printnul(dst, lim, cp); return cp; } /* dns_soa_print() */ int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) { unsigned short rp; unsigned i; size_t n; int error; memset(srv, '\0', sizeof *srv); rp = rr->rd.p; if (P->size - P->end < 6) return DNS_EILLEGAL; for (i = 0; i < 2; i++, rp++) { srv->priority <<= 8; srv->priority |= (0xff & P->data[rp]); } for (i = 0; i < 2; i++, rp++) { srv->weight <<= 8; srv->weight |= (0xff & P->data[rp]); } for (i = 0; i < 2; i++, rp++) { srv->port <<= 8; srv->port |= (0xff & P->data[rp]); } if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error))) return error; else if (n >= sizeof srv->target) return DNS_EILLEGAL; return 0; } /* dns_srv_parse() */ int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) { size_t end, len; int error; end = P->end; if (P->size - P->end < 2) goto toolong; P->end += 2; if (P->size - P->end < 6) goto toolong; P->data[P->end++] = 0xff & (srv->priority >> 8); P->data[P->end++] = 0xff & (srv->priority >> 0); P->data[P->end++] = 0xff & (srv->weight >> 8); P->data[P->end++] = 0xff & (srv->weight >> 0); P->data[P->end++] = 0xff & (srv->port >> 8); P->data[P->end++] = 0xff & (srv->port >> 0); if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error))) goto error; else if (P->size - P->end < len) goto toolong; P->end += len; if (P->end > 65535) goto toolong; len = P->end - end - 2; P->data[end + 0] = 0xff & (len >> 8); P->data[end + 1] = 0xff & (len >> 0); return 0; toolong: error = DNS_ENOBUFS; /* FALL THROUGH */ error: P->end = end; return error; } /* dns_srv_push() */ int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) { int cmp; if ((cmp = a->priority - b->priority)) return cmp; /* * FIXME: We need some sort of random seed to implement the dynamic * weighting required by RFC 2782. */ if ((cmp = a->weight - b->weight)) return cmp; if ((cmp = a->port - b->port)) return cmp; return strcasecmp(a->target, b->target); } /* dns_srv_cmp() */ size_t dns_srv_print(void *dst, size_t lim, struct dns_srv *srv) { size_t cp = 0; cp += dns__print10(dst, lim, cp, srv->priority, 0); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__print10(dst, lim, cp, srv->weight, 0); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__print10(dst, lim, cp, srv->port, 0); cp += dns__printchar(dst, lim, cp, ' '); cp += dns__printstring(dst, lim, cp, srv->target, strlen(srv->target)); dns__printnul(dst, lim, cp); return cp; } /* dns_srv_print() */ size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) { return dns_strlcpy(dst, srv->target, lim); } /* dns_srv_cname() */ unsigned int dns_opt_ttl(const struct dns_opt *opt) { unsigned int ttl = 0; ttl |= (0xffU & opt->rcode) << 24U; ttl |= (0xffU & opt->version) << 16U; return ttl; } /* dns_opt_ttl() */ unsigned short dns_opt_class(const struct dns_opt *opt) { return opt->maxsize; } /* dns_opt_class() */ struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) { assert(size >= offsetof(struct dns_opt, data)); opt->size = size - offsetof(struct dns_opt, data); opt->len = 0; opt->rcode = 0; opt->version = 0; opt->maxsize = 512; return opt; } /* dns_opt_init() */ int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) { opt->len = 0; return 0; } /* dns_opt_parse() */ int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) { return 0; } /* dns_opt_push() */ int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) { return 0; } /* dns_opt_cmp() */ size_t dns_opt_print(void *dst, size_t lim, struct dns_opt *opt) { size_t p = 0, src; p += dns__printchar(dst, lim, p, '"'); for (src = 0; src < opt->len; src++) { p += dns__printchar(dst, lim, p, '\\'); p += dns__print10(dst, lim, p, opt->data[src], 3); } p += dns__printchar(dst, lim, p, '"'); dns__printnul(dst, lim, p); return p; } /* dns_opt_print() */ int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) { return dns_ns_parse((struct dns_ns *)ptr, rr, P); } /* dns_ptr_parse() */ int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) { return dns_ns_push(P, (struct dns_ns *)ptr); } /* dns_ptr_push() */ size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) { unsigned len = (af == AF_INET6) ? dns_aaaa_arpa(dst, lim, addr) : dns_a_arpa(dst, lim, addr); dns__printnul(dst, lim, len); return len; } /* dns_ptr_qname() */ int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) { return strcasecmp(a->host, b->host); } /* dns_ptr_cmp() */ size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) { return dns_ns_print(dst, lim, (struct dns_ns *)ptr); } /* dns_ptr_print() */ size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) { return dns_strlcpy(dst, ptr->host, lim); } /* dns_ptr_cname() */ int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) { unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len; if (pe - p < 2) return DNS_EILLEGAL; fp->algo = P->data[p++]; fp->type = P->data[p++]; switch (fp->type) { case DNS_SSHFP_SHA1: if (pe - p < sizeof fp->digest.sha1) return DNS_EILLEGAL; memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1); break; default: break; } /* switch() */ return 0; } /* dns_sshfp_parse() */ int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) { unsigned p = P->end, pe = P->size, n; if (pe - p < 4) return DNS_ENOBUFS; p += 2; P->data[p++] = 0xff & fp->algo; P->data[p++] = 0xff & fp->type; switch (fp->type) { case DNS_SSHFP_SHA1: if (pe - p < sizeof fp->digest.sha1) return DNS_ENOBUFS; memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1); p += sizeof fp->digest.sha1; break; default: return DNS_EILLEGAL; } /* switch() */ n = p - P->end - 2; P->data[P->end++] = 0xff & (n >> 8); P->data[P->end++] = 0xff & (n >> 0); P->end = p; return 0; } /* dns_sshfp_push() */ int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) { int cmp; if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type)) return cmp; switch (a->type) { case DNS_SSHFP_SHA1: return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1); default: return 0; } /* switch() */ /* NOT REACHED */ } /* dns_sshfp_cmp() */ size_t dns_sshfp_print(void *dst, size_t lim, struct dns_sshfp *fp) { static const unsigned char hex[16] = "0123456789abcdef"; size_t i, p = 0; p += dns__print10(dst, lim, p, fp->algo, 0); p += dns__printchar(dst, lim, p, ' '); p += dns__print10(dst, lim, p, fp->type, 0); p += dns__printchar(dst, lim, p, ' '); switch (fp->type) { case DNS_SSHFP_SHA1: for (i = 0; i < sizeof fp->digest.sha1; i++) { p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 4)]); p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 0)]); } break; default: p += dns__printchar(dst, lim, p, '0'); break; } /* switch() */ dns__printnul(dst, lim, p); return p; } /* dns_sshfp_print() */ struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) { assert(size > offsetof(struct dns_txt, data)); txt->size = size - offsetof(struct dns_txt, data); txt->len = 0; return txt; } /* dns_txt_init() */ int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) { struct { unsigned char *b; size_t p, end; } dst, src; unsigned n; dst.b = txt->data; dst.p = 0; dst.end = txt->size; src.b = P->data; src.p = rr->rd.p; src.end = src.p + rr->rd.len; while (src.p < src.end) { n = 0xff & P->data[src.p++]; if (src.end - src.p < n || dst.end - dst.p < n) return DNS_EILLEGAL; memcpy(&dst.b[dst.p], &src.b[src.p], n); dst.p += n; src.p += n; } txt->len = dst.p; return 0; } /* dns_txt_parse() */ int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) { struct { unsigned char *b; size_t p, end; } dst, src; unsigned n; dst.b = P->data; dst.p = P->end; dst.end = P->size; src.b = txt->data; src.p = 0; src.end = txt->len; if (dst.end - dst.p < 2) return DNS_ENOBUFS; n = txt->len + ((txt->len + 254) / 255); dst.b[dst.p++] = 0xff & (n >> 8); dst.b[dst.p++] = 0xff & (n >> 0); while (src.p < src.end) { n = MIN(255, src.end - src.p); if (dst.p >= dst.end) return DNS_ENOBUFS; dst.b[dst.p++] = n; if (dst.end - dst.p < n) return DNS_ENOBUFS; memcpy(&dst.b[dst.p], &src.b[src.p], n); dst.p += n; src.p += n; } P->end = dst.p; return 0; } /* dns_txt_push() */ int dns_txt_cmp(const struct dns_txt *a, const struct dns_txt *b) { return -1; } /* dns_txt_cmp() */ size_t dns_txt_print(void *dst_, size_t lim, struct dns_txt *txt) { struct { unsigned char *b; size_t p, end; } dst, src; unsigned ch; dst.b = dst_; dst.end = lim; dst.p = 0; src.b = txt->data; src.end = txt->len; src.p = 0; dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); while (src.p < src.end) { ch = src.b[src.p]; if (0 == (src.p++ % 255) && src.p != 1) { dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); dst.p += dns__printchar(dst.b, dst.end, dst.p, ' '); dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); } if (ch < 32 || ch > 126 || ch == '"' || ch == '\\') { dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\'); dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3); } else { dst.p += dns__printchar(dst.b, dst.end, dst.p, ch); } } dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); dns__printnul(dst.b, dst.end, dst.p); return dst.p; } /* dns_txt_print() */ static const struct { enum dns_type type; const char *name; int (*parse)(); int (*push)(); int (*cmp)(); size_t (*print)(); size_t (*cname)(); } dns_rrtypes[] = { { DNS_T_A, "A", &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0 }, { DNS_T_AAAA, "AAAA", &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0 }, { DNS_T_MX, "MX", &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname }, { DNS_T_NS, "NS", &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname }, { DNS_T_CNAME, "CNAME", &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname }, { DNS_T_SOA, "SOA", &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0 }, { DNS_T_SRV, "SRV", &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname }, { DNS_T_OPT, "OPT", &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0 }, { DNS_T_PTR, "PTR", &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname }, { DNS_T_TXT, "TXT", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 }, { DNS_T_SPF, "SPF", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 }, { DNS_T_SSHFP, "SSHFP", &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0 }, }; /* dns_rrtypes[] */ union dns_any *dns_any_init(union dns_any *any, size_t size) { return (union dns_any *)dns_txt_init(&any->rdata, size); } /* dns_any_init() */ int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) { unsigned i; for (i = 0; i < lengthof(dns_rrtypes); i++) { if (dns_rrtypes[i].type == rr->type) return dns_rrtypes[i].parse(any, rr, P); } if (rr->rd.len > any->rdata.size) return DNS_EILLEGAL; memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len); any->rdata.len = rr->rd.len; return 0; } /* dns_any_parse() */ int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) { unsigned i; for (i = 0; i < lengthof(dns_rrtypes); i++) { if (dns_rrtypes[i].type == type) return dns_rrtypes[i].push(P, any); } if (P->size - P->end < any->rdata.len + 2) return DNS_ENOBUFS; P->data[P->end++] = 0xff & (any->rdata.len >> 8); P->data[P->end++] = 0xff & (any->rdata.len >> 0); memcpy(&P->data[P->end], any->rdata.data, any->rdata.len); P->end += any->rdata.len; return 0; } /* dns_any_push() */ int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) { unsigned i; int cmp; if ((cmp = x - y)) return cmp; for (i = 0; i < lengthof(dns_rrtypes); i++) { if (dns_rrtypes[i].type == x) return dns_rrtypes[i].cmp(a, b); } return -1; } /* dns_any_cmp() */ size_t dns_any_print(void *dst_, size_t lim, union dns_any *any, enum dns_type type) { struct { unsigned char *b; size_t p, end; } dst, src; unsigned i, ch; for (i = 0; i < lengthof(dns_rrtypes); i++) { if (dns_rrtypes[i].type == type) return dns_rrtypes[i].print(dst_, lim, any); } dst.b = dst_; dst.end = lim; dst.p = 0; src.b = any->rdata.data; src.end = any->rdata.len; src.p = 0; dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); while (src.p < src.end) { ch = src.b[src.p++]; dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\'); dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3); } dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); dns__printnul(dst.b, dst.end, dst.p); return dst.p; } /* dns_any_print() */ size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) { unsigned i; for (i = 0; i < lengthof(dns_rrtypes); i++) { if (dns_rrtypes[i].type == type) return (dns_rrtypes[i].cname)? dns_rrtypes[i].cname(dst, lim, any) : 0; } return 0; } /* dns_any_cname() */ /* * H O S T S R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_hosts { struct dns_hosts_entry { char host[DNS_D_MAXNAME + 1]; char arpa[73 + 1]; int af; union { struct in_addr a4; struct in6_addr a6; } addr; DNSBool alias; struct dns_hosts_entry *next; } *head, **tail; dns_atomic_t refcount; }; /* struct dns_hosts */ struct dns_hosts *dns_hosts_open(int *error) { static struct dns_hosts hosts_initializer = { 0 }; static DNSBool initialized = 0; struct dns_hosts *hosts; if (!initialized) { hosts_initializer.refcount = 1; initialized = 1; } if (!(hosts = malloc(sizeof *hosts))) goto syerr; *hosts = hosts_initializer; hosts->tail = &hosts->head; return hosts; syerr: *error = dns_syerr(); free(hosts); return 0; } /* dns_hosts_open() */ void dns_hosts_close(struct dns_hosts *hosts) { struct dns_hosts_entry *ent, *xnt; if (!hosts || 1 != dns_hosts_release(hosts)) return; for (ent = hosts->head; ent; ent = xnt) { xnt = ent->next; free(ent); } free(hosts); return; } /* dns_hosts_close() */ unsigned dns_hosts_acquire(struct dns_hosts *hosts) { return dns_atomic_inc(&hosts->refcount); } /* dns_hosts_acquire() */ unsigned dns_hosts_release(struct dns_hosts *hosts) { return dns_atomic_dec(&hosts->refcount); } /* dns_hosts_release() */ struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) { if (hosts) dns_hosts_release(hosts); return hosts; } /* dns_hosts_mortal() */ #ifdef WINAPI_FAMILY_PHONE_APP static int dns_hosts_add_localhost(struct dns_hosts *hosts) { struct dns_hosts_entry ent; memset(&ent, '\0', sizeof(ent)); ent.af = AF_INET; dns_inet_pton(ent.af, "127.0.0.1", &ent.addr); dns_d_anchor(ent.host, sizeof(ent.host), "localhost", 9); dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, 0); memset(&ent, '\0', sizeof(ent)); ent.af = AF_INET6; dns_inet_pton(ent.af, "::1", &ent.addr); dns_d_anchor(ent.host, sizeof(ent.host), "localhost", 9); dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, 1); return 0; } #endif struct dns_hosts *dns_hosts_local(int *error_) { struct dns_hosts *hosts; int error; if (!(hosts = dns_hosts_open(&error))) goto error; #ifdef _WIN32 #ifdef WINAPI_FAMILY_PHONE_APP if ((error = dns_hosts_add_localhost(hosts))) #else if ((error = dns_hosts_loadpath(hosts, "C:/Windows/System32/drivers/etc/hosts"))) #endif #else if ((error = dns_hosts_loadpath(hosts, "/etc/hosts"))) #endif goto error; return hosts; error: *error_ = error; dns_hosts_close(hosts); return 0; } /* dns_hosts_local() */ #define dns_hosts_issep(ch) (isspace(ch)) #define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';') int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) { struct dns_hosts_entry ent; char word[MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1]; unsigned wp, wc, skip; int ch, error; rewind(fp); do { memset(&ent, '\0', sizeof ent); wc = 0; skip = 0; do { memset(word, '\0', sizeof word); wp = 0; while (EOF != (ch = fgetc(fp)) && ch != '\n') { skip |= !!dns_hosts_iscom(ch); if (skip) continue; if (dns_hosts_issep(ch)) break; if (wp < sizeof word - 1) word[wp] = ch; wp++; } if (!wp) continue; wc++; switch (wc) { case 0: break; case 1: ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET; // Normalize some strange IPv4 addresses, eg. 127.1 --> 127.0.0.1 if (ent.af == AF_INET) { int nbdots = 0; char *p = word; while ((p = strchr(p, '.')) != NULL) { nbdots++; p++; } if (nbdots == 1) { p = strchr(word, '.'); p++; memmove(p + 4, p, strlen(p)); memcpy(p, "0.0.", 4); } } skip = (1 != dns_inet_pton(ent.af, word, &ent.addr)); break; default: if (!wp) break; dns_d_anchor(ent.host, sizeof ent.host, word, wp); if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2)))) return error; break; } /* switch() */ } while (ch != EOF && ch != '\n'); } while (ch != EOF); return 0; } /* dns_hosts_loadfile() */ int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) { FILE *fp; int error; if (!(fp = fopen(path, "r"))) return dns_syerr(); error = dns_hosts_loadfile(hosts, fp); fclose(fp); return error; } /* dns_hosts_loadpath() */ int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) { struct dns_hosts_entry *ent, *xnt; char addr[INET6_ADDRSTRLEN + 1]; unsigned i; for (ent = hosts->head; ent; ent = xnt) { xnt = ent->next; dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr); fputs(addr, fp); for (i = strlen(addr); i < INET_ADDRSTRLEN; i++) fputc(' ', fp); fputc(' ', fp); fputs(ent->host, fp); fputc('\n', fp); } return 0; } /* dns_hosts_dump() */ int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, DNSBool alias) { struct dns_hosts_entry *ent; int error; if (!(ent = malloc(sizeof *ent))) goto syerr; dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host)); switch ((ent->af = af)) { case AF_INET6: memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6); dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr); break; case AF_INET: memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4); dns_a_arpa(ent->arpa, sizeof ent->arpa, addr); break; default: error = EINVAL; goto error; } /* switch() */ ent->alias = alias; ent->next = 0; *hosts->tail = ent; hosts->tail = &ent->next; return 0; syerr: error = dns_syerr(); error: free(ent); return error; } /* dns_hosts_insert() */ struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) { union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } dns_packet_union = { { 0 } }; struct dns_packet *P = (struct dns_packet *)&dns_packet_union; struct dns_packet *A = 0; struct dns_rr rr; struct dns_hosts_entry *ent; int error, af; char qname[DNS_D_MAXNAME + 1]; size_t qlen; dns_p_init(P, dns_p_calcsize((512))); if ((error = dns_rr_parse(&rr, 12, Q))) goto error; if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error))) goto error; else if (qlen >= sizeof qname) goto toolong; if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0))) goto error; switch (rr.type) { case DNS_T_PTR: for (ent = hosts->head; ent; ent = ent->next) { if (ent->alias || 0 != strcasecmp(qname, ent->arpa)) continue; if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host))) goto error; } break; case DNS_T_AAAA: af = AF_INET6; goto loop; case DNS_T_A: af = AF_INET; loop: for (ent = hosts->head; ent; ent = ent->next) { if (ent->af != af || 0 != strcasecmp(qname, ent->host)) continue; if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr))) goto error; } break; default: break; } /* switch() */ if (!(A = dns_p_copy(dns_p_make(P->end, &error), P))) goto error; return A; toolong: error = DNS_EILLEGAL; error: *error_ = error; free(A); return 0; } /* dns_hosts_query() */ /* * R E S O L V . C O N F R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_resolv_conf *dns_resconf_open(int *error) { static struct dns_resolv_conf resconf_initializer; static DNSBool initialized = 0; struct dns_resolv_conf *resconf; struct sockaddr_in *sin; if (!initialized) { memset(&resconf_initializer, 0, sizeof resconf_initializer); strcpy(resconf_initializer.lookup, "fb"); resconf_initializer.options.ndots = 1; resconf_initializer.options.timeout = 5; resconf_initializer.options.attempts = 2; resconf_initializer.options.tcp = DNS_RESCONF_TCP_ENABLE; resconf_initializer.iface.ss_family = AF_INET; initialized = 1; } if (!(resconf = malloc(sizeof *resconf))) goto syerr; *resconf = resconf_initializer; sin = (struct sockaddr_in *)&resconf->nameserver[0]; sin->sin_family = AF_INET; sin->sin_addr.s_addr = INADDR_ANY; sin->sin_port = htons(53); #if defined(SA_LEN) sin->sin_len = sizeof *sin; #endif if (0 != gethostname(resconf->search[0], sizeof resconf->search[0])) goto syerr; dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0])); dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0])); /* * XXX: If gethostname() returned a string without any label * separator, then search[0][0] should be NUL. */ dns_resconf_acquire(resconf); return resconf; syerr: *error = dns_syerr(); free(resconf); return 0; } /* dns_resconf_open() */ void dns_resconf_close(struct dns_resolv_conf *resconf) { if (!resconf || 1 != dns_resconf_release(resconf)) return /* void */; free(resconf); } /* dns_resconf_close() */ unsigned dns_resconf_acquire(struct dns_resolv_conf *resconf) { return dns_atomic_inc(&resconf->_.refcount); } /* dns_resconf_acquire() */ unsigned dns_resconf_release(struct dns_resolv_conf *resconf) { return dns_atomic_dec(&resconf->_.refcount); } /* dns_resconf_release() */ struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) { if (resconf) dns_resconf_release(resconf); return resconf; } /* dns_resconf_mortal() */ struct dns_resolv_conf *dns_resconf_local(int *error_) { struct dns_resolv_conf *resconf; int error; if (!(resconf = dns_resconf_open(&error))) goto error; if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) goto error; if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) { if (error != ENOENT) goto error; } return resconf; error: *error_ = error; dns_resconf_close(resconf); return 0; } /* dns_resconf_local() */ struct dns_resolv_conf *dns_resconf_root(int *error) { struct dns_resolv_conf *resconf; if ((resconf = dns_resconf_local(error))) resconf->options.recurse = 1; return resconf; } /* dns_resconf_root() */ enum dns_resconf_keyword { DNS_RESCONF_NAMESERVER, DNS_RESCONF_DOMAIN, DNS_RESCONF_SEARCH, DNS_RESCONF_LOOKUP, DNS_RESCONF_FILE, DNS_RESCONF_BIND, DNS_RESCONF_CACHE, DNS_RESCONF_OPTIONS, DNS_RESCONF_EDNS0, DNS_RESCONF_NDOTS, DNS_RESCONF_TIMEOUT, DNS_RESCONF_ATTEMPTS, DNS_RESCONF_ROTATE, DNS_RESCONF_RECURSE, DNS_RESCONF_SMART, DNS_RESCONF_TCP, DNS_RESCONF_TCPx, DNS_RESCONF_INTERFACE, DNS_RESCONF_ZERO, DNS_RESCONF_ONE, DNS_RESCONF_ENABLE, DNS_RESCONF_ONLY, DNS_RESCONF_DISABLE, }; /* enum dns_resconf_keyword */ static enum dns_resconf_keyword dns_resconf_keyword(const char *word) { static char *words[] = { "nameserver", /* DNS_RESCONF_NAMESERVER */ "domain", /* DNS_RESCONF_DOMAIN */ "search", /* DNS_RESCONF_SEARCH */ "lookup", /* DNS_RESCONF_LOOKUP */ "file", /* DNS_RESCONF_FILE */ "bind", /* DNS_RESCONF_BIND */ "cache", /* DNS_RESCONF_CACHE */ "options", /* DNS_RESCONF_OPTIONS */ "edns0", /* DNS_RESCONF_EDNS0 */ NULL, /* DNS_RESCONF_NDOTS */ NULL, /* DNS_RESCONF_TIMEOUT */ NULL, /* DNS_RESCONF_ATTEMPTS */ "rotate", /* DNS_RESCONF_ROTATE */ "recurse", /* DNS_RESCONF_RECURSE */ "smart", /* DNS_RESCONF_SMART */ "tcp", /* DNS_RESCONF_TCP */ NULL, /* DNS_RESCONF_TCPx */ "interface", /* DNS_RESCONF_INTERFACE */ "0", /* DNS_RESCONF_ZERO */ "1", /* DNS_RESCONF_ONE */ "enable", /* DNS_RESCONF_ENABLE */ "only", /* DNS_RESCONF_ONLY */ "disable" /* DNS_RESCONF_DISABLE */ }; unsigned i; for (i = 0; i < lengthof(words); i++) { if (words[i] && 0 == strcasecmp(words[i], word)) return i; } if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1)) return DNS_RESCONF_NDOTS; if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1)) return DNS_RESCONF_TIMEOUT; if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1)) return DNS_RESCONF_ATTEMPTS; if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1)) return DNS_RESCONF_TCPx; return -1; } /* dns_resconf_keyword() */ /** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */ static int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) { struct { char buf[128], *p; } addr = { "", addr.buf }; unsigned short port = 0; int ch, af = AF_INET, error; while ((ch = *src++)) { switch (ch) { case ' ': /* FALL THROUGH */ case '\t': break; case '[': break; case ']': while ((ch = *src++)) { if (isdigit((unsigned char)ch)) { port *= 10; port += ch - '0'; } } goto inet; case ':': af = AF_INET6; /* FALL THROUGH */ default: if (addr.p < endof(addr.buf) - 1) *addr.p++ = ch; break; } /* switch() */ } /* while() */ inet: if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss)))) return error; port = (!port)? 53 : port; *dns_sa_port(af, ss) = htons(port); dns_sa_family(ss) = af; return 0; } /* dns_resconf_pton() */ #define dns_resconf_issep(ch) (isspace(ch) || (ch) == ',') #define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';') int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) { unsigned sa_count = 0; char words[6][DNS_D_MAXNAME + 1]; unsigned wp, wc, i, j, n; int ch, error; rewind(fp); do { memset(words, '\0', sizeof words); wp = 0; wc = 0; while (EOF != (ch = getc(fp)) && ch != '\n') { if (dns_resconf_issep(ch)) { if (wp > 0) { wp = 0; if (++wc >= lengthof(words)) goto skip; } } else if (dns_resconf_iscom(ch)) { skip: do { ch = getc(fp); } while (ch != EOF && ch != '\n'); break; } else { dns__printchar(words[wc], sizeof words[wc], wp, ch); wp++; } } if (wp > 0) wc++; if (wc < 2) continue; switch (dns_resconf_keyword(words[0])) { case DNS_RESCONF_NAMESERVER: if (sa_count >= lengthof(resconf->nameserver)) continue; if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1]))) continue; sa_count++; break; case DNS_RESCONF_DOMAIN: case DNS_RESCONF_SEARCH: memset(resconf->search, '\0', sizeof resconf->search); for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++) dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i])); break; case DNS_RESCONF_LOOKUP: for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) { switch (dns_resconf_keyword(words[i])) { case DNS_RESCONF_FILE: resconf->lookup[j++] = 'f'; break; case DNS_RESCONF_BIND: resconf->lookup[j++] = 'b'; break; case DNS_RESCONF_CACHE: resconf->lookup[j++] = 'c'; break; default: break; } /* switch() */ } /* for() */ break; case DNS_RESCONF_OPTIONS: for (i = 1; i < wc; i++) { switch (dns_resconf_keyword(words[i])) { case DNS_RESCONF_EDNS0: resconf->options.edns0 = 1; break; case DNS_RESCONF_NDOTS: for (j = sizeof "ndots:" - 1, n = 0; isdigit((int)words[i][j]); j++) { n *= 10; n += words[i][j] - '0'; } /* for() */ resconf->options.ndots = n; break; case DNS_RESCONF_TIMEOUT: for (j = sizeof "timeout:" - 1, n = 0; isdigit((int)words[i][j]); j++) { n *= 10; n += words[i][j] - '0'; } /* for() */ resconf->options.timeout = n; break; case DNS_RESCONF_ATTEMPTS: for (j = sizeof "attempts:" - 1, n = 0; isdigit((int)words[i][j]); j++) { n *= 10; n += words[i][j] - '0'; } /* for() */ resconf->options.attempts = n; break; case DNS_RESCONF_ROTATE: resconf->options.rotate = 1; break; case DNS_RESCONF_RECURSE: resconf->options.recurse = 1; break; case DNS_RESCONF_SMART: resconf->options.smart = 1; break; case DNS_RESCONF_TCP: resconf->options.tcp = DNS_RESCONF_TCP_ONLY; break; case DNS_RESCONF_TCPx: switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) { case DNS_RESCONF_ENABLE: resconf->options.tcp = DNS_RESCONF_TCP_ENABLE; break; case DNS_RESCONF_ONE: case DNS_RESCONF_ONLY: resconf->options.tcp = DNS_RESCONF_TCP_ONLY; break; case DNS_RESCONF_ZERO: case DNS_RESCONF_DISABLE: resconf->options.tcp = DNS_RESCONF_TCP_DISABLE; break; default: break; } /* switch() */ break; default: break; } /* switch() */ } /* for() */ break; case DNS_RESCONF_INTERFACE: for (i = 0, n = 0; isdigit((int)words[2][i]); i++) { n *= 10; n += words[2][i] - '0'; } dns_resconf_setiface(resconf, words[1], n); break; default: break; } /* switch() */ } while (ch != EOF); return 0; } /* dns_resconf_loadfile() */ int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) { FILE *fp; int error; if (!(fp = fopen(path, "r"))) return dns_syerr(); error = dns_resconf_loadfile(resconf, fp); fclose(fp); return error; } /* dns_resconf_loadpath() */ #ifdef USE_FIXED_NAMESERVERS int dns_resconf_load_fixed_nameservers(struct dns_resolv_conf *resconf) { const char * const nameservers[] = { "8.8.8.8", "8.8.4.4" }; int i; int error = 0; for (i = 0; !error && (i < lengthof(nameservers)); i++) { error = dns_resconf_pton(&resconf->nameserver[i], nameservers[i]); } return error; } #endif /* USE_FIXED_NAMESERVERS */ #ifdef USE_STRUCT_RES_STATE_NAMESERVERS int dns_resconf_load_struct_res_state_nameservers(struct dns_resolv_conf *resconf) { int i; struct __res_state *rs = __res_get_state(); for (i = 0; i < rs->nscount; i++) { memcpy(&resconf->nameserver[i], (struct sockaddr_storage *)&rs->nsaddr_list[i], sizeof(struct sockaddr_in)); } return 0; } #endif /* USE_STRUCT_RES_STATE_NAMESERVERS */ #if defined(_WIN32) && !defined(USE_FIXED_NAMESERVERS) int dns_resconf_loadwin(struct dns_resolv_conf *resconf) { FIXED_INFO *pFixedInfo; ULONG ulOutBufLen; DWORD dwRetVal; IP_ADDR_STRING *pIPAddr; unsigned int sa_count = 0; int error = -1; pFixedInfo = (FIXED_INFO *) malloc(sizeof(FIXED_INFO)); if (pFixedInfo == NULL) { return error; } ulOutBufLen = sizeof(FIXED_INFO); if (GetNetworkParams(pFixedInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) { free(pFixedInfo); pFixedInfo = (FIXED_INFO *) malloc(ulOutBufLen); if (pFixedInfo == NULL) { return error; } } if ((dwRetVal = GetNetworkParams(pFixedInfo, &ulOutBufLen)) == NO_ERROR) { memset(resconf->search, '\0', sizeof resconf->search); memcpy(resconf->search[0], pFixedInfo->DomainName, sizeof pFixedInfo->DomainName); pIPAddr = &pFixedInfo->DnsServerList; do { error = dns_resconf_pton(&resconf->nameserver[sa_count], pIPAddr->IpAddress.String); pIPAddr = pIPAddr->Next; sa_count++; } while (!error && pIPAddr && (sa_count < lengthof(resconf->nameserver))); } return error; } /* dns_resconf_loadwin() */ #endif #ifdef ANDROID int dns_resconf_loadandroid(struct dns_resolv_conf *resconf) { char dns[PROP_VALUE_MAX]; char prop_name[PROP_NAME_MAX]; unsigned int sa_count = 0; int error = 0; int i; for (i = 1; !error && (i <= lengthof(resconf->nameserver)); i++, sa_count++) { snprintf(prop_name, sizeof(prop_name), "net.dns%d", i); if (__system_property_get(prop_name, dns) > 0) { error = dns_resconf_pton(&resconf->nameserver[sa_count], dns); } } if (sa_count == 0) { /* No net.dnsX property found, return an error. */ error = -1; } return error; } /* dns_resconf_loadandroid */ #endif #ifdef HAVE_RESINIT int dns_resconf_loadfromresolv(struct dns_resolv_conf *resconf) { struct __res_state res; union res_sockaddr_union addresses[3]; int i,error; if ((error = res_ninit(&res))) { return error; } error=res_getservers(&res,addresses,3); if (error>0){ for (i = 0; inameserver[i],&addresses[i],sizeof(union res_sockaddr_union)); } error=0; }else error=-1; res_ndestroy(&res); return error; } #endif /*HAVE_RESINIT*/ struct dns_anyconf { char *token[16]; unsigned count; char buffer[1024], *tp, *cp; }; /* struct dns_anyconf */ static void dns_anyconf_reset(struct dns_anyconf *cf) { cf->count = 0; cf->tp = cf->cp = cf->buffer; } /* dns_anyconf_reset() */ static int dns_anyconf_push(struct dns_anyconf *cf) { if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token))) return ENOMEM; *cf->cp++ = '\0'; cf->token[cf->count++] = cf->tp; cf->tp = cf->cp; return 0; } /* dns_anyconf_push() */ static void dns_anyconf_pop(struct dns_anyconf *cf) { if (cf->count > 0) { --cf->count; cf->tp = cf->cp = cf->token[cf->count]; cf->token[cf->count] = 0; } } /* dns_anyconf_pop() */ static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) { if (!(cf->cp < endof(cf->buffer))) return ENOMEM; *cf->cp++ = ch; return 0; } /* dns_anyconf_addc() */ static DNSBool dns_anyconf_match(const char *pat, int mc) { DNSBool match; int pc; if (*pat == '^') { match = 0; ++pat; } else { match = 1; } while ((pc = *(const unsigned char *)pat++)) { switch (pc) { case '%': if (!(pc = *(const unsigned char *)pat++)) return !match; switch (pc) { case 'a': if (isalpha(mc)) return match; break; case 'd': if (isdigit(mc)) return match; break; case 'w': if (isalnum(mc)) return match; break; case 's': if (isspace(mc)) return match; break; default: if (mc == pc) return match; break; } /* switch() */ break; default: if (mc == pc) return match; break; } /* switch() */ } /* while() */ return !match; } /* dns_anyconf_match() */ static int dns_anyconf_peek(FILE *fp) { int ch; ch = getc(fp); ungetc(ch, fp); return ch; } /* dns_anyconf_peek() */ static size_t dns_anyconf_skip(const char *pat, FILE *fp) { size_t count = 0; int ch; while (EOF != (ch = getc(fp))) { if (dns_anyconf_match(pat, ch)) { count++; continue; } ungetc(ch, fp); break; } return count; } /* dns_anyconf_skip() */ static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) { size_t len; int ch; while (EOF != (ch = getc(fp))) { if (dns_anyconf_match(pat, ch)) { if ((*error = dns_anyconf_addc(cf, ch))) return 0; continue; } else { ungetc(ch, fp); break; } } if ((len = cf->cp - cf->tp)) { if ((*error = dns_anyconf_push(cf))) return 0; return len; } else { *error = 0; return 0; } } /* dns_anyconf_scan() */ DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) { unsigned i; fprintf(fp, "tokens:"); for (i = 0; i < cf->count; i++) { fprintf(fp, " %s", cf->token[i]); } fputc('\n', fp); } /* dns_anyconf_dump() */ enum dns_nssconf_keyword { DNS_NSSCONF_INVALID = 0, DNS_NSSCONF_HOSTS = 1, DNS_NSSCONF_SUCCESS, DNS_NSSCONF_NOTFOUND, DNS_NSSCONF_UNAVAIL, DNS_NSSCONF_TRYAGAIN, DNS_NSSCONF_CONTINUE, DNS_NSSCONF_RETURN, DNS_NSSCONF_FILES, DNS_NSSCONF_DNS, DNS_NSSCONF_MDNS, DNS_NSSCONF_LAST, }; /* enum dns_nssconf_keyword */ static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) { static char *list[] = { NULL, /* DNS_NSSCONF_INVALID */ "hosts", /* DNS_NSSCONF_HOSTS */ "success", /* DNS_NSSCONF_SUCCESS */ "notfound", /* DNS_NSSCONF_NOTFOUND */ "unavail", /* DNS_NSSCONF_UNAVAIL */ "tryagain", /* DNS_NSSCONF_TRYAGAIN */ "continue", /* DNS_NSSCONF_CONTINUE */ "return", /* DNS_NSSCONF_RETURN */ "files", /* DNS_NSSCONF_FILES */ "dns", /* DNS_NSSCONF_DNS */ "mdns" /* DNS_NSSCONF_MDNS */ }; unsigned i; for (i = 1; i < lengthof(list); i++) { if (list[i] && 0 == strcasecmp(list[i], word)) return i; } return DNS_NSSCONF_INVALID; } /* dns_nssconf_keyword() */ static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) { static char map['m'+1] = { 0 }; map['S'] = DNS_NSSCONF_SUCCESS; map['N'] = DNS_NSSCONF_NOTFOUND; map['U'] = DNS_NSSCONF_UNAVAIL; map['T'] = DNS_NSSCONF_TRYAGAIN; map['C'] = DNS_NSSCONF_CONTINUE; map['R'] = DNS_NSSCONF_RETURN; map['f'] = DNS_NSSCONF_FILES; map['F'] = DNS_NSSCONF_FILES; map['d'] = DNS_NSSCONF_DNS; map['D'] = DNS_NSSCONF_DNS; map['b'] = DNS_NSSCONF_DNS; map['B'] = DNS_NSSCONF_DNS; map['m'] = DNS_NSSCONF_MDNS; map['M'] = DNS_NSSCONF_MDNS; return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID; } /* dns_nssconf_c2k() */ DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET static int dns_nssconf_k2c(int k) { static char map[DNS_NSSCONF_LAST] = { 0 }; map[DNS_NSSCONF_SUCCESS] = 'S'; map[DNS_NSSCONF_NOTFOUND] = 'N'; map[DNS_NSSCONF_UNAVAIL] = 'U'; map[DNS_NSSCONF_TRYAGAIN] = 'T'; map[DNS_NSSCONF_CONTINUE] = 'C'; map[DNS_NSSCONF_RETURN] = 'R'; map[DNS_NSSCONF_FILES] = 'f'; map[DNS_NSSCONF_DNS] = 'b'; map[DNS_NSSCONF_MDNS] = 'm'; return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?'; } /* dns_nssconf_k2c() */ static const char *dns_nssconf_k2s(int k) { static char *map[] = { NULL, /* DNS_NSSCONF_INVALID */ NULL, /* DNS_NSSCONF_HOSTS */ "SUCCESS", /* DNS_NSSCONF_SUCCESS */ "NOTFOUND", /* DNS_NSSCONF_NOTFOUND */ "UNAVAIL", /* DNS_NSSCONF_UNAVAIL */ "TRYAGAIN", /* DNS_NSSCONF_TRYAGAIN */ "continue", /* DNS_NSSCONF_CONTINUE */ "return", /* DNS_NSSCONF_RETURN */ "files", /* DNS_NSSCONF_FILES */ "dns", /* DNS_NSSCONF_DNS */ "mdns" /* DNS_NSSCONF_MDNS */ }; return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : ""; } /* dns_nssconf_k2s() */ DNS_PRAGMA_POP int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) { enum dns_nssconf_keyword source, status, action; char lookup[sizeof resconf->lookup] = "", *lp; struct dns_anyconf cf; size_t i; int error; while (!feof(fp) && !ferror(fp)) { dns_anyconf_reset(&cf); dns_anyconf_skip("%s", fp); if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) goto nextent; if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0])) goto nextent; dns_anyconf_pop(&cf); if (!dns_anyconf_skip(": \t", fp)) goto nextent; *(lp = lookup) = '\0'; while (dns_anyconf_scan(&cf, "%w_", fp, &error)) { dns_anyconf_skip(" \t", fp); if ('[' == dns_anyconf_peek(fp)) { dns_anyconf_skip("[ \t", fp); while (dns_anyconf_scan(&cf, "%w_", fp, &error)) { dns_anyconf_skip("= \t", fp); if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) { dns_anyconf_pop(&cf); /* discard status */ dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */ break; } dns_anyconf_skip(" \t", fp); } dns_anyconf_skip("] \t", fp); } if ((unsigned int)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */ goto nextsrc; source = dns_nssconf_keyword(cf.token[0]); switch (source) { case DNS_NSSCONF_DNS: case DNS_NSSCONF_MDNS: case DNS_NSSCONF_FILES: *lp++ = dns_nssconf_k2c(source); break; default: goto nextsrc; } for (i = 1; i + 1 < cf.count; i += 2) { status = dns_nssconf_keyword(cf.token[i]); action = dns_nssconf_keyword(cf.token[i + 1]); switch (status) { case DNS_NSSCONF_SUCCESS: case DNS_NSSCONF_NOTFOUND: case DNS_NSSCONF_UNAVAIL: case DNS_NSSCONF_TRYAGAIN: *lp++ = dns_nssconf_k2c(status); break; default: continue; } switch (action) { case DNS_NSSCONF_CONTINUE: case DNS_NSSCONF_RETURN: break; default: action = (status == DNS_NSSCONF_SUCCESS) ? DNS_NSSCONF_RETURN : DNS_NSSCONF_CONTINUE; break; } *lp++ = dns_nssconf_k2c(action); } nextsrc: *lp = '\0'; dns_anyconf_reset(&cf); } nextent: dns_anyconf_skip("^\n", fp); } if (*lookup) strncpy(resconf->lookup, lookup, sizeof resconf->lookup); return 0; } /* dns_nssconf_loadfile() */ int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) { FILE *fp; int error; if (!(fp = fopen(path, "r"))) return dns_syerr(); error = dns_nssconf_loadfile(resconf, fp); fclose(fp); return error; } /* dns_nssconf_loadpath() */ struct dns_nssconf_source { enum dns_nssconf_keyword source, success, notfound, unavail, tryagain; }; /* struct dns_nssconf_source */ typedef unsigned dns_nssconf_i; static DNS_INLINE int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) { return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0; } /* dns_nssconf_peek() */ static DNSBool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) { int source, status, action; src->source = DNS_NSSCONF_INVALID; src->success = DNS_NSSCONF_RETURN; src->notfound = DNS_NSSCONF_CONTINUE; src->unavail = DNS_NSSCONF_CONTINUE; src->tryagain = DNS_NSSCONF_CONTINUE; while ((source = dns_nssconf_peek(resconf, *state))) { source = dns_nssconf_c2k(source); ++*state; switch (source) { case DNS_NSSCONF_FILES: case DNS_NSSCONF_DNS: case DNS_NSSCONF_MDNS: src->source = source; break; default: continue; } while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) { status = dns_nssconf_c2k(status); action = dns_nssconf_c2k(action); switch (action) { case DNS_NSSCONF_RETURN: case DNS_NSSCONF_CONTINUE: break; default: goto done; } switch (status) { case DNS_NSSCONF_SUCCESS: src->success = action; break; case DNS_NSSCONF_NOTFOUND: src->notfound = action; break; case DNS_NSSCONF_UNAVAIL: src->unavail = action; break; case DNS_NSSCONF_TRYAGAIN: src->tryagain = action; break; default: goto done; } *state += 2; } break; } done: return src->source != DNS_NSSCONF_INVALID; } /* dns_nssconf_next() */ static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) { switch (status) { case DNS_NSSCONF_SUCCESS: if (action == DNS_NSSCONF_RETURN) return 0; break; default: if (action == DNS_NSSCONF_CONTINUE) return 0; break; } fputc(' ', fp); if (!*count) fputc('[', fp); fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action)); ++*count; return 0; } /* dns_nssconf_dump_status() */ int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) { struct dns_nssconf_source src; dns_nssconf_i i = 0; fputs("hosts:", fp); while (dns_nssconf_next(&src, resconf, &i)) { unsigned n = 0; fprintf(fp, " %s", dns_nssconf_k2s(src.source)); dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp); dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp); dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp); dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp); if (n) fputc(']', fp); } fputc('\n', fp); return 0; } /* dns_nssconf_dump() */ int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) { int af = (strchr(addr, ':'))? AF_INET6 : AF_INET; int error; if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface)))) return error; *dns_sa_port(af, &resconf->iface) = htons(port); resconf->iface.ss_family = af; return 0; } /* dns_resconf_setiface() */ size_t dns_resconf_search(void *dst, size_t lim, const void *qname, size_t qlen, struct dns_resolv_conf *resconf, dns_resconf_i_t *state) { unsigned srchi = 0xff & (*state >> 8); unsigned ndots = 0xff & (*state >> 16); unsigned slen, len = 0; const char *qp, *qe; // assert(0xff > lengthof(resconf->search)); switch (0xff & *state) { case 0: qp = qname; qe = qp + qlen; while ((qp = memchr(qp, '.', qe - qp))) { ndots++; qp++; } ++*state; if (ndots >= resconf->options.ndots) { len = dns_d_anchor(dst, lim, qname, qlen); break; } /* FALL THROUGH */ case 1: if (srchi < lengthof(resconf->search) && (slen = strlen(resconf->search[srchi]))) { len = dns__printstring(dst, lim, 0, qname, qlen); len = dns_d_anchor(dst, lim, dst, len); len += dns__printstring(dst, lim, len, resconf->search[srchi], slen); srchi++; break; } ++*state; /* FALL THROUGH */ case 2: ++*state; if (ndots < resconf->options.ndots) { len = dns_d_anchor(dst, lim, qname, qlen); break; } /* FALL THROUGH */ default: break; } /* switch() */ dns__printnul(dst, lim, len); *state = ((0xff & *state) << 0) | ((0xff & srchi) << 8) | ((0xff & ndots) << 16); return len; } /* dns_resconf_search() */ int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) { unsigned i; int af; for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) { char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]"; unsigned short port; dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i]), addr, sizeof addr); port = ntohs(*dns_sa_port(af, &resconf->nameserver[i])); if (port == 53) fprintf(fp, "nameserver %s\n", addr); else fprintf(fp, "nameserver [%s]:%hu\n", addr, port); } fprintf(fp, "search"); for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++) fprintf(fp, " %s", resconf->search[i]); fputc('\n', fp); fputs("; ", fp); dns_nssconf_dump(resconf, fp); fprintf(fp, "lookup"); for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) { switch (resconf->lookup[i]) { case 'b': fprintf(fp, " bind"); break; case 'f': fprintf(fp, " file"); break; case 'c': fprintf(fp, " cache"); break; } } fputc('\n', fp); fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts); if (resconf->options.edns0) fprintf(fp, " edns0"); if (resconf->options.rotate) fprintf(fp, " rotate"); if (resconf->options.recurse) fprintf(fp, " recurse"); if (resconf->options.smart) fprintf(fp, " smart"); switch (resconf->options.tcp) { case DNS_RESCONF_TCP_ENABLE: break; case DNS_RESCONF_TCP_ONLY: fprintf(fp, " tcp"); break; case DNS_RESCONF_TCP_DISABLE: fprintf(fp, " tcp:disable"); break; } fputc('\n', fp); if ((af = resconf->iface.ss_family) != AF_UNSPEC) { char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]"; dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface), addr, sizeof addr); fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface))); } return 0; } /* dns_resconf_dump() */ /* * H I N T S E R V E R R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_hints_soa { unsigned char zone[DNS_D_MAXNAME + 1]; struct { struct sockaddr_storage ss; unsigned priority; } addrs[16]; unsigned count; struct dns_hints_soa *next; }; /* struct dns_hints_soa */ struct dns_hints { dns_atomic_t refcount; struct dns_hints_soa *head; }; /* struct dns_hints */ struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) { static const struct dns_hints H_initializer; struct dns_hints *H; if (!(H = malloc(sizeof *H))) goto syerr; *H = H_initializer; dns_hints_acquire(H); return H; syerr: *error = dns_syerr(); free(H); return 0; } /* dns_hints_open() */ void dns_hints_close(struct dns_hints *H) { struct dns_hints_soa *soa, *nxt; if (!H || 1 != dns_hints_release(H)) return /* void */; for (soa = H->head; soa; soa = nxt) { nxt = soa->next; free(soa); } free(H); return /* void */; } /* dns_hints_close() */ unsigned dns_hints_acquire(struct dns_hints *H) { return dns_atomic_inc(&H->refcount); } /* dns_hints_acquire() */ unsigned dns_hints_release(struct dns_hints *H) { return dns_atomic_dec(&H->refcount); } /* dns_hints_release() */ struct dns_hints *dns_hints_mortal(struct dns_hints *hints) { if (hints) dns_hints_release(hints); return hints; } /* dns_hints_mortal() */ struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) { struct dns_hints *hints = 0; int error; if (resconf) dns_resconf_acquire(resconf); else if (!(resconf = dns_resconf_local(&error))) goto error; if (!(hints = dns_hints_open(resconf, &error))) goto error; error = 0; if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error) goto error; dns_resconf_close(resconf); return hints; error: *error_ = error; dns_resconf_close(resconf); dns_hints_close(hints); return 0; } /* dns_hints_local() */ struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) { static const struct { int af; char addr[INET6_ADDRSTRLEN]; } root_hints[] = { { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */ { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */ { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */ { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */ { AF_INET, "128.8.10.90" }, /* D.ROOT-SERVERS.NET. */ { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */ { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */ { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */ { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */ { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */ { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */ { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */ { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */ { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */ }; struct dns_hints *hints = 0; struct sockaddr_storage ss; unsigned i; int error, af; if (!(hints = dns_hints_open(resconf, &error))) goto error; for (i = 0; i < lengthof(root_hints); i++) { af = root_hints[i].af; if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss)))) goto error; *dns_sa_port(af, &ss) = htons(53); ss.ss_family = af; if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1))) goto error; } return hints; error: *error_ = error; dns_hints_close(hints); return 0; } /* dns_hints_root() */ static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) { struct dns_hints_soa *soa; for (soa = H->head; soa; soa = soa->next) { if (0 == strcasecmp(zone, (char *)soa->zone)) return soa; } return 0; } /* dns_hints_fetch() */ int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) { static const struct dns_hints_soa soa_initializer; struct dns_hints_soa *soa; unsigned i; if (!(soa = dns_hints_fetch(H, zone))) { if (!(soa = malloc(sizeof *soa))) return dns_syerr(); *soa = soa_initializer; dns__printstring(soa->zone, sizeof soa->zone, 0, zone, strlen(zone)); soa->next = H->head; H->head = soa; } i = soa->count % lengthof(soa->addrs); memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa)); soa->addrs[i].priority = MAX(1, priority); if (soa->count < lengthof(soa->addrs)) soa->count++; return 0; } /* dns_hints_insert() */ unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) { unsigned i, n, p; int error; for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) { if ((error = dns_hints_insert(H, zone, (struct sockaddr *)&resconf->nameserver[i], p))) goto error; p += !resconf->options.rotate; } return n; error: *error_ = error; return n; } /* dns_hints_insert_resconf() */ static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) { int cmp; if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority)) return cmp; return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed); } /* dns_hints_i_cmp() */ static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) { unsigned p0, p; p0 = 0; for (p = 1; p < soa->count; p++) { if (dns_hints_i_cmp(p, p0, i, soa) < 0) p0 = p; } return p0; } /* dns_hints_i_start() */ static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) { unsigned pZ, p; for (pZ = 0; pZ < soa->count; pZ++) { if (dns_hints_i_cmp(pZ, p0, i, soa) > 0) goto cont; } return soa->count; cont: for (p = pZ + 1; p < soa->count; p++) { if (dns_hints_i_cmp(p, p0, i, soa) <= 0) continue; if (dns_hints_i_cmp(p, pZ, i, soa) >= 0) continue; pZ = p; } return pZ; } /* dns_hints_i_skip() */ struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) { static const struct dns_hints_i i_initializer; struct dns_hints_soa *soa; i->state = i_initializer.state; do { i->state.seed = dns_random(); } while (0 == i->state.seed); if ((soa = dns_hints_fetch(hints, i->zone))) { i->state.next = dns_hints_i_start(i, soa); } return i; } /* dns_hints_i_init() */ unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) { struct dns_hints_soa *soa; unsigned n; if (!(soa = dns_hints_fetch(H, i->zone))) return 0; n = 0; while (i->state.next < soa->count && n < lim) { *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss; *sa_len = dns_sa_len(*sa); sa++; sa_len++; n++; i->state.next = dns_hints_i_skip(i->state.next, i, soa); } return n; } /* dns_hints_grep() */ struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) { struct dns_packet *A, *P; struct dns_rr rr; char zone[DNS_D_MAXNAME + 1]; size_t zlen; struct dns_hints_i i; struct sockaddr *sa; socklen_t slen; int error; union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } dns_packet_union = { { 0 } }; struct dns_rr_i dns_rr_it; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_i_init(&dns_rr_it, Q); dns_rr_it.section = DNS_S_QUESTION; if (!dns_rr_grep(&rr, 1, &dns_rr_it, Q, &error)) goto error; if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error))) goto error; else if (zlen >= sizeof zone) goto toolong; P = (struct dns_packet *)&dns_packet_union; dns_p_init(P, dns_p_calcsize((512))); dns_header(P)->qr = 1; if ((error = dns_rr_copy(P, &rr, Q))) goto error; if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local."))) goto error; do { i.zone = zone; dns_hints_i_init(&i, hints); while (dns_hints_grep(&sa, &slen, 1, &i, hints)) { int af = sa->sa_family; int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A; if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa)))) goto error; } } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen))); if (!(A = dns_p_copy(dns_p_make(P->end, &error), P))) goto error; return A; toolong: error = DNS_EILLEGAL; error: *error_ = error; return 0; } /* dns_hints_query() */ /** ugly hack to support specifying ports other than 53 in resolv.conf. */ static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) { struct dns_hints_soa *soa; unsigned short port; unsigned i; for (soa = hints->head; soa; soa = soa->next) { for (i = 0; i < soa->count; i++) { if (af != soa->addrs[i].ss.ss_family) continue; if (memcmp(addr, dns_sa_addr(af, &soa->addrs[i].ss), (af == AF_INET6)? sizeof (struct in6_addr) : sizeof (struct in_addr))) continue; port = *dns_sa_port(af, &soa->addrs[i].ss); return (port)? port : htons(53); } } return htons(53); } /* dns_hints_port() */ int dns_hints_dump(struct dns_hints *hints, FILE *fp) { struct dns_hints_soa *soa; char addr[INET6_ADDRSTRLEN]; unsigned i; int af, error; for (soa = hints->head; soa; soa = soa->next) { fprintf(fp, "ZONE \"%s\"\n", soa->zone); for (i = 0; i < soa->count; i++) { af = soa->addrs[i].ss.ss_family; if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss), addr, sizeof addr))) return error; fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss))); } } return 0; } /* dns_hints_dump() */ /* * C A C H E R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static dns_atomic_t dns_cache_acquire(struct dns_cache *cache) { return 0; } /* dns_cache_acquire() */ static dns_atomic_t dns_cache_release(struct dns_cache *cache) { return 0; } /* dns_cache_release() */ static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) { return 0; } /* dns_cache_submit() */ static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) { return 0; } /* dns_cache_submit() */ static int dns_cache_check(struct dns_cache *cache) { return 0; } /* dns_cache_check() */ static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) { return 0; } /* dns_cache_fetch() */ static int dns_cache_pollfd(struct dns_cache *cache) { return -1; } /* dns_cache_pollfd() */ static short dns_cache_events(struct dns_cache *cache) { return 0; } /* dns_cache_events() */ static void dns_cache_clear(struct dns_cache *cache) { return; } /* dns_cache_clear() */ struct dns_cache *dns_cache_init(struct dns_cache *cache) { static struct dns_cache c_init = { 0 }; c_init.acquire = &dns_cache_acquire; c_init.release = &dns_cache_release; c_init.query = &dns_cache_query; c_init.submit = &dns_cache_submit; c_init.check = &dns_cache_check; c_init.fetch = &dns_cache_fetch; c_init.pollfd = &dns_cache_pollfd; c_init.events = &dns_cache_events; c_init.clear = &dns_cache_clear; *cache = c_init; return cache; } /* dns_cache_init() */ void dns_cache_close(struct dns_cache *cache) { if (cache) cache->release(cache); } /* dns_cache_close() */ /* * S O C K E T R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void dns_socketclose(int *fd) { if (*fd != -1) { #if _WIN32 closesocket(*fd); #else close(*fd); #endif *fd = -1; } } /* dns_socketclose() */ #define DNS_SO_MAXTRY 7 static int dns_socket(struct sockaddr *local, int type, int *error_) { int error, fd = -1; #if defined(O_NONBLOCK) int flags; #elif defined(FIONBIO) unsigned long opt; #endif if (-1 == (fd = socket(local->sa_family, type, 0))) goto soerr; #if defined(F_SETFD) if (-1 == fcntl(fd, F_SETFD, 1)) goto syerr; #endif #if defined(O_NONBLOCK) if (-1 == (flags = fcntl(fd, F_GETFL))) goto syerr; if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK)) goto syerr; #elif defined(FIONBIO) opt = 1; if (0 != ioctlsocket(fd, FIONBIO, &opt)) goto soerr; #endif #if defined(SO_NOSIGPIPE) if (type == SOCK_DGRAM) { if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int))) goto soerr; } #endif if (local->sa_family != AF_INET && local->sa_family != AF_INET6) return fd; if (type != SOCK_DGRAM) return fd; if (*dns_sa_port(local->sa_family, local) == 0) { /*let the system find a random port*/ return fd; } if (0 == bind(fd, local, dns_sa_len(local))) return fd; /* FALL THROUGH */ soerr: error = dns_soerr(); goto error; #if defined(F_SETFD) || defined(O_NONBLOCK) syerr: error = dns_syerr(); goto error; #endif error: *error_ = error; dns_socketclose(&fd); return -1; } /* dns_socket() */ enum { DNS_SO_UDP_INIT = 1, DNS_SO_UDP_CONN, DNS_SO_UDP_SEND, DNS_SO_UDP_RECV, DNS_SO_UDP_DONE, DNS_SO_TCP_INIT, DNS_SO_TCP_CONN, DNS_SO_TCP_SEND, DNS_SO_TCP_RECV, DNS_SO_TCP_DONE, }; struct dns_socket { struct dns_options opts; int udp; int tcp; int *old; unsigned onum, olim; int type; struct sockaddr_storage local, remote; struct dns_k_permutor qids; struct dns_stat stat; /* * NOTE: dns_so_reset() zeroes everything from here down. */ int state; unsigned short qid; char qname[DNS_D_MAXNAME + 1]; size_t qlen; enum dns_type qtype; enum dns_class qclass; struct dns_packet *query; size_t qout; struct dns_clock elapsed; struct dns_packet *answer; size_t alen, apos; }; /* struct dns_socket() */ /* * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have * a chance to recognize a state change after installing a persistent event * and where sequential descriptors with the same integer value returned * from _pollfd() would be ambiguous. See dns_so_closefds(). */ static int dns_so_closefd(struct dns_socket *so, int *fd) { int error; if (*fd == -1) return 0; if (so->opts.closefd.cb) { if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) { return error; } else if (*fd == -1) return 0; } if (!(so->onum < so->olim)) { unsigned olim = MAX(4, so->olim * 2); void *old; if (!(old = realloc(so->old, sizeof so->old[0] * olim))) return dns_syerr(); so->old = old; so->olim = olim; } so->old[so->onum++] = *fd; *fd = -1; return 0; } /* dns_so_closefd() */ #define DNS_SO_CLOSE_UDP 0x01 #define DNS_SO_CLOSE_TCP 0x02 #define DNS_SO_CLOSE_OLD 0x04 #define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD) static void dns_so_closefds(struct dns_socket *so, int which) { if (DNS_SO_CLOSE_UDP & which) dns_socketclose(&so->udp); if (DNS_SO_CLOSE_TCP & which) dns_socketclose(&so->tcp); if (DNS_SO_CLOSE_OLD & which) { unsigned i; for (i = 0; i < so->onum; i++) dns_socketclose(&so->old[i]); so->onum = 0; free(so->old); so->old = 0; so->olim = 0; } } /* dns_so_closefds() */ static void dns_so_destroy(struct dns_socket *); static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) { static struct dns_socket so_initializer; static DNSBool initialized = 0; int value=0; if (!initialized) { memset(&so_initializer, 0, sizeof so_initializer); so_initializer.opts.closefd.arg = 0; so_initializer.opts.closefd.cb = 0; so_initializer.opts.events = 0; so_initializer.udp = -1; so_initializer.tcp = -1; initialized = 1; } *so = so_initializer; so->type = type; if (opts) so->opts = *opts; if (local) memcpy(&so->local, local, dns_sa_len(local)); if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error))) goto error; value=0; setsockopt(so->udp, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&value, sizeof(value)); dns_k_permutor_init(&so->qids, 1, 65535); return so; error: dns_so_destroy(so); return 0; } /* dns_so_init() */ struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) { struct dns_socket *so; if (!(so = malloc(sizeof *so))) goto syerr; if (!dns_so_init(so, local, type, opts, error)) goto error; return so; syerr: *error = dns_syerr(); error: dns_so_close(so); return 0; } /* dns_so_open() */ static void dns_so_destroy(struct dns_socket *so) { dns_so_reset(so); dns_so_closefds(so, DNS_SO_CLOSE_ALL); } /* dns_so_destroy() */ void dns_so_close(struct dns_socket *so) { if (!so) return; dns_so_destroy(so); free(so); } /* dns_so_close() */ void dns_so_reset(struct dns_socket *so) { if (so->answer) { free(so->answer); so->answer=NULL; } memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state)); } /* dns_so_reset() */ unsigned short dns_so_mkqid(struct dns_socket *so) { return dns_k_permutor_step(&so->qids); } /* dns_so_mkqid() */ #define DNS_SO_MINBUF 768 static int dns_so_newanswer(struct dns_socket *so, size_t len) { size_t size = offsetof(struct dns_packet, data) + MAX(len, DNS_SO_MINBUF); void *p; if (!(p = realloc(so->answer, size))) return dns_syerr(); so->answer = dns_p_init(p, size); return 0; } /* dns_so_newanswer() */ int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) { struct dns_rr rr; int error = -1; dns_so_reset(so); if ((error = dns_rr_parse(&rr, 12, Q))) goto error; if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error))) goto error; /* * NOTE: don't bail if expansion is too long; caller may be * intentionally sending long names. However, we won't be able to * verify it on return. */ so->qtype = rr.type; so->qclass = rr.class; if ((error = dns_so_newanswer(so, DNS_SO_MINBUF))) goto syerr; if (so->local.ss_family==AF_INET6 && host->sa_family==AF_INET){ uint32_t *addr=(uint32_t*)dns_sa_addr(AF_INET6,&so->remote); /* add v4mapping*/ so->remote.ss_family=AF_INET6; addr[0]=0; addr[1]=0; addr[2]=ntohl(0xffff); addr[3]=((struct sockaddr_in*)host)->sin_addr.s_addr; *dns_sa_port(AF_INET6,&so->remote)=((struct sockaddr_in*)host)->sin_port; }else memcpy(&so->remote, host, dns_sa_len(host)); so->query = Q; so->qout = 0; dns_begin(&so->elapsed); if (dns_header(so->query)->qid == 0) dns_header(so->query)->qid = dns_so_mkqid(so); so->qid = dns_header(so->query)->qid; so->state = (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT; so->stat.queries++; return 0; syerr: error = dns_syerr(); error: dns_so_reset(so); return error; } /* dns_so_submit() */ static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) { char qname[DNS_D_MAXNAME + 1]; size_t qlen; struct dns_rr rr; int error = -1; if (so->qid != dns_header(so->answer)->qid) return DNS_EUNKNOWN; if (!dns_p_count(so->answer, DNS_S_QD)) return DNS_EUNKNOWN; if (0 != dns_rr_parse(&rr, 12, so->answer)) return DNS_EUNKNOWN; if (rr.type != so->qtype || rr.class != so->qclass) return DNS_EUNKNOWN; if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error))) return error; else if (qlen >= sizeof qname || qlen != so->qlen) return DNS_EUNKNOWN; if (0 != strcasecmp(so->qname, qname)) return DNS_EUNKNOWN; return 0; } /* dns_so_verify() */ #if defined __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warray-bounds" #endif static int dns_so_tcp_send(struct dns_socket *so) { unsigned char *qsrc; size_t qend; long n; so->query->data[-2] = 0xff & (so->query->end >> 8); so->query->data[-1] = 0xff & (so->query->end >> 0); qsrc = &so->query->data[-2] + so->qout; qend = so->query->end + 2; while (so->qout < qend) { if (0 > (n = dns_send(so->tcp, (void *)&qsrc[so->qout], qend - so->qout, 0))) return dns_soerr(); so->qout += n; so->stat.tcp.sent.bytes += n; } so->stat.tcp.sent.count++; return 0; } /* dns_so_tcp_send() */ static int dns_so_tcp_recv(struct dns_socket *so) { unsigned char *asrc; size_t aend, alen; int error; long n; aend = so->alen + 2; while (so->apos < aend) { asrc = &so->answer->data[-2]; if (0 > (n = recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0))) return dns_soerr(); else if (n == 0) return DNS_EUNKNOWN; /* FIXME */ so->apos += n; so->stat.tcp.rcvd.bytes += n; if (so->alen == 0 && so->apos >= 2) { alen = ((0xff & so->answer->data[-2]) << 8) | ((0xff & so->answer->data[-1]) << 0); if ((error = dns_so_newanswer(so, alen))) return error; so->alen = alen; aend = alen + 2; } } so->answer->end = so->alen; so->stat.tcp.rcvd.count++; return 0; } /* dns_so_tcp_recv() */ #if __clang__ #pragma clang diagnostic pop #endif #define USE_CONNECT 0 int dns_so_check(struct dns_socket *so) { int error; long n; #if !USE_CONNECT struct sockaddr_storage saddr; socklen_t slen=sizeof(saddr); #endif retry: switch (so->state) { case DNS_SO_UDP_INIT: so->state++; case DNS_SO_UDP_CONN: #if USE_CONNECT if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) goto soerr; #endif so->state++; case DNS_SO_UDP_SEND: #if USE_CONNECT if (0 > (n = send(so->udp, (void *)so->query->data, so->query->end, 0))) goto soerr; #else if (0 > (n = sendto(so->udp, (void *)so->query->data, so->query->end, 0, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote)))) goto soerr; #endif so->stat.udp.sent.bytes += n; so->stat.udp.sent.count++; so->state++; case DNS_SO_UDP_RECV: #if USE_CONNECT if (0 > (n = recv(so->udp, (void *)so->answer->data, so->answer->size, 0))) goto soerr; #else if (0 > (n = recvfrom(so->udp, (void *)so->answer->data, so->answer->size, 0, (struct sockaddr*)&saddr,&slen))) goto soerr; /*TODO check if saddr matches one of the DNS server we previously sent a question, for security*/ #endif so->stat.udp.rcvd.bytes += n; so->stat.udp.rcvd.count++; if ((so->answer->end = n) < 12) goto trash; if ((error = dns_so_verify(so, so->answer))) goto trash; so->state++; case DNS_SO_UDP_DONE: if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM) return 0; so->state++; case DNS_SO_TCP_INIT: if ((error = dns_so_closefd(so, &so->tcp))) goto error; if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error))) goto error; so->state++; case DNS_SO_TCP_CONN: if (0 != connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) { if (dns_soerr() != DNS_EISCONN) goto soerr; } so->state++; case DNS_SO_TCP_SEND: if ((error = dns_so_tcp_send(so))) goto error; so->state++; case DNS_SO_TCP_RECV: if ((error = dns_so_tcp_recv(so))) goto error; so->state++; case DNS_SO_TCP_DONE: if ((error = dns_so_closefd(so, &so->tcp))) goto error; if (so->answer->end < 12) return DNS_EILLEGAL; if ((error = dns_so_verify(so, so->answer))) goto error; return 0; default: error = DNS_EUNKNOWN; goto error; } /* switch() */ trash: goto retry; soerr: error = dns_soerr(); goto error; error: switch (error) { case DNS_EINTR: goto retry; case DNS_EINPROGRESS: /* FALL THROUGH */ case DNS_EALREADY: /* FALL THROUGH */ #if DNS_EWOULDBLOCK != DNS_EAGAIN case DNS_EWOULDBLOCK: /* FALL THROUGH */ #endif error = DNS_EAGAIN; break; } /* switch() */ return error; } /* dns_so_check() */ struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) { struct dns_packet *answer; switch (so->state) { case DNS_SO_UDP_DONE: case DNS_SO_TCP_DONE: answer = so->answer; so->answer = 0; return answer; default: *error = DNS_EUNKNOWN; return 0; } } /* dns_so_fetch() */ struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) { struct dns_packet *A; int error; if (!so->state) { if ((error = dns_so_submit(so, Q, host))) goto error; } if ((error = dns_so_check(so))) goto error; if (!(A = dns_so_fetch(so, &error))) goto error; dns_so_reset(so); return A; error: *error_ = error; return 0; } /* dns_so_query() */ time_t dns_so_elapsed(struct dns_socket *so) { return dns_elapsed(&so->elapsed); } /* dns_so_elapsed() */ void dns_so_clear(struct dns_socket *so) { dns_so_closefds(so, DNS_SO_CLOSE_OLD); } /* dns_so_clear() */ static int dns_so_events2(struct dns_socket *so, enum dns_events type) { int events = 0; switch (so->state) { case DNS_SO_UDP_CONN: case DNS_SO_UDP_SEND: events |= DNS_POLLOUT; break; case DNS_SO_UDP_RECV: events |= DNS_POLLIN; break; case DNS_SO_TCP_CONN: case DNS_SO_TCP_SEND: events |= DNS_POLLOUT; break; case DNS_SO_TCP_RECV: events |= DNS_POLLIN; break; } /* switch() */ switch (type) { case DNS_LIBEVENT: return DNS_POLL2EV(events); default: return events; } /* switch() */ } /* dns_so_events2() */ int dns_so_events(struct dns_socket *so) { return dns_so_events2(so, so->opts.events); } /* dns_so_events() */ int dns_so_pollfd(struct dns_socket *so) { switch (so->state) { case DNS_SO_UDP_CONN: case DNS_SO_UDP_SEND: case DNS_SO_UDP_RECV: return so->udp; case DNS_SO_TCP_CONN: case DNS_SO_TCP_SEND: case DNS_SO_TCP_RECV: return so->tcp; } /* switch() */ return -1; } /* dns_so_pollfd() */ int dns_so_poll(struct dns_socket *so, int timeout) { return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout); } /* dns_so_poll() */ const struct dns_stat *dns_so_stat(struct dns_socket *so) { return &so->stat; } /* dns_so_stat() */ /* * R E S O L V E R R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ enum dns_res_state { DNS_R_INIT, DNS_R_GLUE, DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */ DNS_R_FILE, /* Lookup in local hosts database */ DNS_R_CACHE, /* Lookup in application cache */ DNS_R_SUBMIT, DNS_R_CHECK, DNS_R_FETCH, DNS_R_BIND, /* Lookup in the network */ DNS_R_SEARCH, DNS_R_HINTS, DNS_R_ITERATE, DNS_R_FOREACH_NS, DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */ DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */ DNS_R_FOREACH_A, DNS_R_QUERY_A, DNS_R_CNAME0_A, DNS_R_CNAME1_A, DNS_R_FINISH, DNS_R_SMART0_A, DNS_R_SMART1_A, DNS_R_DONE, DNS_R_SERVFAIL, }; /* enum dns_res_state */ #define DNS_R_MAXDEPTH 8 #define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1) struct dns_resolver { struct dns_socket so; struct dns_resolv_conf *resconf; struct dns_hosts *hosts; struct dns_hints *hints; struct dns_cache *cache; dns_atomic_t refcount; /* Reset zeroes everything below here. */ char qname[DNS_D_MAXNAME + 1]; size_t qlen; enum dns_type qtype; enum dns_class qclass; struct dns_clock elapsed; dns_resconf_i_t search; struct dns_rr_i smart; struct dns_res_frame { enum dns_res_state state; int error; int which; /* (B)IND, (F)ILE; index into resconf->lookup */ unsigned attempts; struct dns_packet *query, *answer, *hints; struct dns_rr_i hints_i, hints_j; struct dns_rr hints_ns, ans_cname; } stack[DNS_R_MAXDEPTH]; unsigned sp; }; /* struct dns_resolver */ static int dns_res_tcp2type(int tcp) { switch (tcp) { case DNS_RESCONF_TCP_ONLY: return SOCK_STREAM; case DNS_RESCONF_TCP_DISABLE: return SOCK_DGRAM; default: return 0; } } /* dns_res_tcp2type() */ struct dns_resolver *dns_res_open(struct dns_resolv_conf *resconf, struct dns_hosts *hosts, struct dns_hints *hints, struct dns_cache *cache, const struct dns_options *opts, int *_error) { static struct dns_resolver R_initializer; static DNSBool initialized = 0; struct dns_resolver *R = 0; int type, error; if (!initialized) { memset(&R_initializer, 0, sizeof R_initializer); R_initializer.refcount = 1; initialized = 1; } /* * Grab ref count early because the caller may have passed us a mortal * reference, and we want to do the right thing if we return early * from an error. */ if (resconf) dns_resconf_acquire(resconf); if (hosts) dns_hosts_acquire(hosts); if (hints) dns_hints_acquire(hints); if (cache) dns_cache_acquire(cache); /* * Don't try to load it ourselves because a NULL object might be an * error from, say, dns_resconf_root(), and loading * dns_resconf_local() by default would create undesirable surpises. */ if (!resconf || !hosts || !hints) goto _error; if (!(R = malloc(sizeof *R))) goto syerr; *R = R_initializer; type = dns_res_tcp2type(resconf->options.tcp); if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error)) goto error; R->resconf = resconf; R->hosts = hosts; R->hints = hints; R->cache = cache; return R; syerr: error = dns_syerr(); error: *_error = error; _error: dns_res_close(R); dns_resconf_close(resconf); dns_hosts_close(hosts); dns_hints_close(hints); dns_cache_close(cache); return 0; } /* dns_res_open() */ struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) { struct dns_resolv_conf *resconf = 0; struct dns_hosts *hosts = 0; struct dns_hints *hints = 0; struct dns_resolver *res = 0; if (!(resconf = dns_resconf_local(error))) goto epilog; if (!(hosts = dns_hosts_local(error))) goto epilog; if (!(hints = dns_hints_local(resconf, error))) goto epilog; if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error))) goto epilog; epilog: dns_resconf_close(resconf); dns_hosts_close(hosts); dns_hints_close(hints); return res; } /* dns_res_stub() */ static void dns_res_reset_frame(struct dns_resolver *R, struct dns_res_frame *frame) { free(frame->query); free(frame->answer); free(frame->hints); memset(frame, '\0', sizeof *frame); } /* dns_res_reset_frame() */ void dns_res_reset(struct dns_resolver *R) { unsigned i; dns_so_reset(&R->so); for (i = 0; i < lengthof(R->stack); i++) dns_res_reset_frame(R, &R->stack[i]); memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname)); } /* dns_res_reset() */ void dns_res_close(struct dns_resolver *R) { if (!R || 1 < dns_res_release(R)) return; dns_res_reset(R); dns_so_destroy(&R->so); dns_hints_close(R->hints); dns_hosts_close(R->hosts); dns_resconf_close(R->resconf); dns_cache_close(R->cache); free(R); } /* dns_res_close() */ unsigned dns_res_acquire(struct dns_resolver *R) { return dns_atomic_inc(&R->refcount); } /* dns_res_acquire() */ unsigned dns_res_release(struct dns_resolver *R) { return dns_atomic_dec(&R->refcount); } /* dns_res_release() */ struct dns_resolver *dns_res_mortal(struct dns_resolver *res) { if (res) dns_res_release(res); return res; } /* dns_res_mortal() */ static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) { size_t bufsiz = P0->end + P1->end; struct dns_packet *P[3] = { P0, P1, 0 }; struct dns_rr rr[3]; int error, copy, i; enum dns_section section; struct dns_rr_i dns_rr_it, dns_rr_it2; int dns_grep_error, dns_grep_error2; retry: if (!(P[2] = dns_p_make(bufsiz, &error))) goto error; dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.section = DNS_S_QD; dns_rr_i_init(&dns_rr_it, P[0]); for (; dns_rr_grep(&rr[0], 1, &dns_rr_it, P[0], &dns_grep_error); ) { if ((error = dns_rr_copy(P[2], &rr[0], P[0]))) goto error; } for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) { for (i = 0; i < 2; i++) { dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.section = section; dns_rr_i_init(&dns_rr_it, P[i]); for (; dns_rr_grep(&rr[i], 1, &dns_rr_it, P[i], &dns_grep_error); ) { copy = 1; dns_grep_error2 = 0; memset(&dns_rr_it2, 0, sizeof dns_rr_it2); dns_rr_it2.type = rr[i].type; dns_rr_it2.section = (DNS_S_ALL & ~DNS_S_QD); dns_rr_i_init(&dns_rr_it2, P[2]); for (; dns_rr_grep(&rr[2], 1, &dns_rr_it2, P[2], &dns_grep_error2); ) { if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) { copy = 0; break; } } if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) { if (error == DNS_ENOBUFS && bufsiz < 65535) { free(P[2]); P[2] = 0; bufsiz = MAX(65535, bufsiz * 2); goto retry; } goto error; } } /* foreach(rr) */ } /* foreach(packet) */ } /* foreach(section) */ return P[2]; error: *error_ = error; free(P[2]); return 0; } /* dns_res_merge() */ static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) { union { unsigned char b[dns_p_calcsize((512))]; struct dns_packet p; } dns_packet_union = { { 0 } }; struct dns_packet *P = (struct dns_packet *)&dns_packet_union; char qname[DNS_D_MAXNAME + 1]; size_t qlen; enum dns_type qtype; struct dns_rr rr; unsigned sp; int error; struct dns_rr_i dns_rr_it; int dns_grep_error; dns_p_init(P, dns_p_calcsize((512))); if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error)) || qlen >= sizeof qname) return 0; if (!(qtype = dns_rr_type(12, Q))) return 0; if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0))) return 0; for (sp = 0; sp <= R->sp; sp++) { if (!R->stack[sp].answer) continue; dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.name = qname; dns_rr_it.type = qtype; dns_rr_it.section = (DNS_S_ALL & ~DNS_S_QD); dns_rr_i_init(&dns_rr_it, R->stack[sp].answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, R->stack[sp].answer, &dns_grep_error); ) { rr.section = DNS_S_AN; if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer))) return 0; } } if (dns_p_count(P, DNS_S_AN) > 0) goto copy; /* Otherwise, look for a CNAME */ for (sp = 0; sp <= R->sp; sp++) { if (!R->stack[sp].answer) continue; dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.name = qname; dns_rr_it.type = DNS_T_CNAME; dns_rr_it.section = (DNS_S_ALL & ~DNS_S_QD); dns_rr_i_init(&dns_rr_it, R->stack[sp].answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, R->stack[sp].answer, &dns_grep_error); ) { rr.section = DNS_S_AN; if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer))) return 0; } } if (!dns_p_count(P, DNS_S_AN)) return 0; copy: return dns_p_copy(dns_p_make(P->end, &error), P); } /* dns_res_glue() */ static struct dns_packet *dns_res_mkquery(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass, int *error_) { struct dns_packet *Q = 0; int error; if (!(Q = dns_p_init(malloc(DNS_P_QBUFSIZ), DNS_P_QBUFSIZ))) goto syerr; if ((error = dns_p_push(Q, DNS_S_QD, qname, strlen(qname), qtype, qclass, 0, 0))) goto error; dns_header(Q)->rd = !R->resconf->options.recurse; return Q; syerr: error = dns_syerr(); error: free(Q); *error_ = error; return 0; } /* dns_res_mkquery() */ /* * Sort NS records by three criteria: * * 1) Whether glue is present. * 2) Whether glue record is original or of recursive lookup. * 3) Randomly shuffle records which share the above criteria. * * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will * be added during an iteration. * * FIXME: Only groks A glue, not AAAA glue. */ static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { DNSBool glued[2] = { 0 }; struct dns_ns ns; struct dns_rr x, y; int cmp, error; struct dns_rr_i dns_rr_it; if (!(error = dns_ns_parse(&ns, a, P))) { memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.section = (DNS_S_ALL & ~DNS_S_QD); dns_rr_it.name = ns.host; dns_rr_it.type = DNS_T_A; dns_rr_i_init(&dns_rr_it, P); if (!(glued[0] = !!dns_rr_grep(&x, 1, &dns_rr_it, P, &error))) x.dn.p = 0; } if (!(error = dns_ns_parse(&ns, b, P))) { memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.section = (DNS_S_ALL & ~DNS_S_QD); dns_rr_it.name = ns.host; dns_rr_it.type = DNS_T_A; dns_rr_i_init(&dns_rr_it, P); if (!(glued[1] = !!dns_rr_grep(&y, 1, &dns_rr_it, P, &error))) x.dn.p = 0; } if ((cmp = glued[1] - glued[0])) return cmp; else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) return cmp; else return dns_rr_i_shuffle(a, b, i, P); } /* dns_res_nameserv_cmp() */ #define goto(sp, i) \ do { R->stack[(sp)].state = (i); goto exec; } while (0) static int dns_res_exec(struct dns_resolver *R) { struct dns_res_frame *F; struct dns_packet *P; char host[DNS_D_MAXNAME + 1]; size_t len; struct dns_rr rr; struct sockaddr_storage saddr={0}; int error; struct dns_rr_i dns_rr_it; int dns_grep_error; exec: F = &R->stack[R->sp]; switch (F->state) { case DNS_R_INIT: F->state++; case DNS_R_GLUE: if (R->sp == 0) goto(R->sp, DNS_R_SWITCH); assert(F->query); if (!(F->answer = dns_res_glue(R, F->query))) goto(R->sp, DNS_R_SWITCH); if (!(len = dns_d_expand(host, sizeof host, 12, F->query, &error))) goto error; else if (len >= sizeof host) goto toolong; dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.name = host; dns_rr_it.type = dns_rr_type(12, F->query); dns_rr_it.section = DNS_S_AN; dns_rr_i_init(&dns_rr_it, F->answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, F->answer, &dns_grep_error); ) { goto(R->sp, DNS_R_FINISH); } dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.name = host; dns_rr_it.type = DNS_T_CNAME; dns_rr_it.section = DNS_S_AN; dns_rr_i_init(&dns_rr_it, F->answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, F->answer, &dns_grep_error); ) { F->ans_cname = rr; goto(R->sp, DNS_R_CNAME0_A); } F->state++; case DNS_R_SWITCH: while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) { switch (R->resconf->lookup[F->which++]) { case 'b': case 'B': goto(R->sp, DNS_R_BIND); case 'f': case 'F': goto(R->sp, DNS_R_FILE); case 'c': case 'C': if (R->cache) goto(R->sp, DNS_R_CACHE); break; default: break; } } goto(R->sp, DNS_R_SERVFAIL); /* FIXME: Right behavior? */ case DNS_R_FILE: if (R->sp > 0) { free(F->answer); if (!(F->answer = dns_hosts_query(R->hosts, F->query, &error))) goto error; if (dns_p_count(F->answer, DNS_S_AN) > 0) goto(R->sp, DNS_R_FINISH); free(F->answer); F->answer = 0; } else { R->search = 0; while ((len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search))) { /* * FIXME: Some sort of bug, either with this code or with GCC 3.3.5 on * OpenBSD 4.4, overwites the stack guard. If the bug is in this file, it * appears to be localized somewhere around here. It can also be mitigated * in dns_hosts_query(). In any event, the bug manifests only when using * compound literals. alloca(), malloc(), calloc(), etc, all work fine. * Valgrind (tested on Linux) cannot detect any issues, but stack issues are * not Valgrind's forte. Neither can I spot anything in the assembly, but * that's not my forte. */ #if __OpenBSD__ && __GNUC__ struct dns_packet *query = __builtin_alloca(DNS_P_QBUFSIZ); dns_p_init(query, DNS_P_QBUFSIZ); #else union { unsigned char b[dns_p_calcsize((DNS_P_QBUFSIZ))]; struct dns_packet p; } dns_packet_union = { { 0 } }; struct dns_packet *query = (struct dns_packet *)&dns_packet_union; dns_p_init(query, dns_p_calcsize((DNS_P_QBUFSIZ))); #endif if ((error = dns_p_push(query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0))) goto error; free(F->answer); if (!(F->answer = dns_hosts_query(R->hosts, query, &error))) goto error; if (dns_p_count(F->answer, DNS_S_AN) > 0) goto(R->sp, DNS_R_FINISH); free(F->answer); F->answer = 0; } } goto(R->sp, DNS_R_SWITCH); case DNS_R_CACHE: error = 0; if (!F->query && !(F->query = dns_res_mkquery(R, R->qname, R->qtype, R->qclass, &error))) goto error; free(F->answer); if ((F->answer = R->cache->query(F->query, R->cache, &error))) { if (dns_p_count(F->answer, DNS_S_AN) > 0) goto(R->sp, DNS_R_FINISH); free(F->answer); F->answer = 0; goto(R->sp, DNS_R_SWITCH); } else if (error) goto error; F->state++; case DNS_R_SUBMIT: if ((error = R->cache->submit(F->query, R->cache))) goto error; F->state++; case DNS_R_CHECK: if ((error = R->cache->check(R->cache))) goto error; F->state++; case DNS_R_FETCH: error = 0; free(F->answer); if ((F->answer = R->cache->fetch(R->cache, &error))) { if (dns_p_count(F->answer, DNS_S_AN) > 0) goto(R->sp, DNS_R_FINISH); free(F->answer); F->answer = 0; goto(R->sp, DNS_R_SWITCH); } else if (error) goto error; goto(R->sp, DNS_R_SWITCH); case DNS_R_BIND: if (R->sp > 0) { assert(F->query); goto(R->sp, DNS_R_HINTS); } R->search = 0; F->state++; case DNS_R_SEARCH: if (!(len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search))) goto(R->sp, DNS_R_SWITCH); if (!(P = dns_p_make(DNS_P_QBUFSIZ, &error))) goto error; dns_header(P)->rd = !R->resconf->options.recurse; free(F->query); F->query = P; if ((error = dns_p_push(F->query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0))) goto error; F->state++; case DNS_R_HINTS: free(F->hints); if (!(F->hints = dns_hints_query(R->hints, F->query, &error))) goto error; F->state++; case DNS_R_ITERATE: dns_rr_i_init(&F->hints_i, F->hints); F->hints_i.section = DNS_S_AUTHORITY; F->hints_i.type = DNS_T_NS; F->hints_i.sort = &dns_res_nameserv_cmp; F->hints_i.args[0] = F->hints->end; F->state++; case DNS_R_FOREACH_NS: dns_rr_i_save(&F->hints_i); /* Load our next nameserver host. */ if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) { if (++F->attempts < R->resconf->options.attempts) goto(R->sp, DNS_R_ITERATE); goto(R->sp, DNS_R_SWITCH); } dns_rr_i_init(&F->hints_j, F->hints); /* Assume there are glue records */ goto(R->sp, DNS_R_FOREACH_A); case DNS_R_RESOLV0_NS: /* Have we reached our max depth? */ if (&F[1] >= endof(R->stack)) goto(R->sp, DNS_R_FOREACH_NS); dns_res_reset_frame(R, &F[1]); if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error))) goto error; if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints))) goto error; if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), DNS_T_A, DNS_C_IN, 0, 0))) goto error; F->state++; goto(++R->sp, DNS_R_INIT); case DNS_R_RESOLV1_NS: if (!(len = dns_d_expand(host, sizeof host, 12, F[1].query, &error))) goto error; else if (len >= sizeof host) goto toolong; dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.name = host; dns_rr_it.type = DNS_T_A; dns_rr_it.section = (DNS_S_ALL & ~DNS_S_QD); dns_rr_i_init(&dns_rr_it, F[1].answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, F[1].answer, &dns_grep_error); ) { rr.section = DNS_S_AR; if ((error = dns_rr_copy(F->hints, &rr, F[1].answer))) goto error; dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */ } goto(R->sp, DNS_R_FOREACH_NS); case DNS_R_FOREACH_A: /* * NOTE: Iterator initialized in DNS_R_FOREACH_NS because * this state is re-entrant, but we need to reset * .name to a valid pointer each time. */ if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints))) goto error; F->hints_j.name = host; F->hints_j.type = DNS_T_ALL; F->hints_j.section = DNS_S_ALL & ~DNS_S_QD; if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) { if (!dns_rr_i_count(&F->hints_j)) goto(R->sp, DNS_R_RESOLV0_NS); goto(R->sp, DNS_R_FOREACH_NS); } saddr.ss_family = rr.type==DNS_T_AAAA ? AF_INET6 : AF_INET; if (saddr.ss_family==AF_INET){ if ((error = dns_a_parse((struct dns_a *)dns_sa_addr(saddr.ss_family, &saddr), &rr, F->hints))) goto error; }else{ if ((error = dns_aaaa_parse((struct dns_aaaa *)dns_sa_addr(saddr.ss_family, &saddr), &rr, F->hints))) goto error; } *dns_sa_port(saddr.ss_family, &saddr) = (R->sp == 0) ? dns_hints_port(R->hints, saddr.ss_family, (struct sockaddr *)&saddr) : htons(53); if (DNS_DEBUG) { char addr[INET_ADDRSTRLEN + 1]; if (saddr.ss_family==AF_INET) dns_a_print(addr, sizeof addr, (struct dns_a *)dns_sa_addr(saddr.ss_family, &saddr)); else dns_aaaa_print(addr, sizeof addr, (struct dns_aaaa *)dns_sa_addr(saddr.ss_family, &saddr)); DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", host, addr, R->sp); } if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&saddr))) goto error; F->state++; case DNS_R_QUERY_A: if (dns_so_elapsed(&R->so) >= (time_t)R->resconf->options.timeout) goto(R->sp, DNS_R_FOREACH_A); if ((error = dns_so_check(&R->so))) goto error; free(F->answer); if (!(F->answer = dns_so_fetch(&R->so, &error))) goto error; if (DNS_DEBUG) { DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp); } if ((error = dns_rr_parse(&rr, 12, F->query))) goto error; if (!(len = dns_d_expand(host, sizeof host, rr.dn.p, F->query, &error))) goto error; else if (len >= sizeof host) goto toolong; dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.name = host; dns_rr_it.type = rr.type; dns_rr_it.section = DNS_S_AN; dns_rr_i_init(&dns_rr_it, F->answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, F->answer, &dns_grep_error); ) { goto(R->sp, DNS_R_FINISH); /* Found */ } dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.name = host; dns_rr_it.type = DNS_T_CNAME; dns_rr_it.section = DNS_S_AN; dns_rr_i_init(&dns_rr_it, F->answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, F->answer, &dns_grep_error); ) { F->ans_cname = rr; goto(R->sp, DNS_R_CNAME0_A); } if (!R->resconf->options.recurse) goto(R->sp, DNS_R_SEARCH); dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.type = DNS_T_NS; dns_rr_it.section = DNS_S_NS; dns_rr_i_init(&dns_rr_it, F->answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, F->answer, &dns_grep_error); ) { free(F->hints); F->hints = F->answer; F->answer = 0; goto(R->sp, DNS_R_ITERATE); } /* XXX: Should this go further up? */ if (dns_header(F->answer)->aa) goto(R->sp, DNS_R_FINISH); goto(R->sp, DNS_R_FOREACH_A); case DNS_R_CNAME0_A: if (&F[1] >= endof(R->stack)) goto(R->sp, DNS_R_FINISH); if ((error = dns_cname_parse((struct dns_cname *)host, &F->ans_cname, F->answer))) goto error; dns_res_reset_frame(R, &F[1]); if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error))) goto error; if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), dns_rr_type(12, F->query), DNS_C_IN, 0, 0))) goto error; F->state++; goto(++R->sp, DNS_R_INIT); case DNS_R_CNAME1_A: if (!(P = dns_res_merge(F->answer, F[1].answer, &error))) goto error; free(F->answer); F->answer = P; goto(R->sp, DNS_R_FINISH); case DNS_R_FINISH: assert(F->answer); if (!R->resconf->options.smart || R->sp > 0) goto(R->sp, DNS_R_DONE); R->smart.section = DNS_S_AN; R->smart.type = R->qtype; dns_rr_i_init(&R->smart, F->answer); F->state++; case DNS_R_SMART0_A: if (&F[1] >= endof(R->stack)) goto(R->sp, DNS_R_DONE); while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) { union { struct dns_ns ns; struct dns_mx mx; struct dns_srv srv; } rd; const char *qname; enum dns_type qtype; enum dns_class qclass; switch (rr.type) { case DNS_T_NS: if ((error = dns_ns_parse(&rd.ns, &rr, F->answer))) goto error; qname = rd.ns.host; qtype = DNS_T_A; qclass = DNS_C_IN; break; case DNS_T_MX: if ((error = dns_mx_parse(&rd.mx, &rr, F->answer))) goto error; qname = rd.mx.host; qtype = DNS_T_A; qclass = DNS_C_IN; break; case DNS_T_SRV: if ((error = dns_srv_parse(&rd.srv, &rr, F->answer))) goto error; qname = rd.srv.target; qtype = DNS_T_A; qclass = DNS_C_IN; break; default: continue; } /* switch() */ dns_res_reset_frame(R, &F[1]); if (!(F[1].query = dns_res_mkquery(R, qname, qtype, qclass, &error))) goto error; F->state++; goto(++R->sp, DNS_R_INIT); } /* while() */ /* * NOTE: SMTP specification says to fallback to A record. * * XXX: Should we add a mock MX answer? */ if (R->qtype == DNS_T_MX && R->smart.state.count == 0) { dns_res_reset_frame(R, &F[1]); if (!(F[1].query = dns_res_mkquery(R, R->qname, DNS_T_A, DNS_C_IN, &error))) goto error; R->smart.state.count++; F->state++; goto(++R->sp, DNS_R_INIT); } goto(R->sp, DNS_R_DONE); case DNS_R_SMART1_A: assert(F[1].answer); /* * FIXME: For CNAME chains (which are typically illegal in * this context), we should rewrite the record host name * to the original smart qname. All the user cares about * is locating that A/AAAA record. */ dns_grep_error = 0; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.type = DNS_T_A; dns_rr_it.section = DNS_S_AN; dns_rr_i_init(&dns_rr_it, F[1].answer); for (; dns_rr_grep(&rr, 1, &dns_rr_it, F[1].answer, &dns_grep_error); ) { rr.section = DNS_S_AR; if (dns_rr_exists(&rr, F[1].answer, F->answer)) continue; while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) { if (error != DNS_ENOBUFS) goto error; if ((error = dns_p_grow(&F->answer))) goto error; } } goto(R->sp, DNS_R_SMART0_A); case DNS_R_DONE: assert(F->answer); if (R->sp > 0) goto(--R->sp, F[-1].state); break; case DNS_R_SERVFAIL: free(F->answer); if (!(F->answer = dns_p_make(DNS_P_QBUFSIZ, &error))) goto error; dns_header(F->answer)->qr = 1; dns_header(F->answer)->rcode = DNS_RC_SERVFAIL; if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0))) goto error; goto(R->sp, DNS_R_DONE); default: error = EINVAL; goto error; } /* switch () */ return 0; toolong: error = DNS_EILLEGAL; error: return error; } /* dns_res_exec() */ #undef goto void dns_res_clear(struct dns_resolver *R) { switch (R->stack[R->sp].state) { case DNS_R_CHECK: R->cache->clear(R->cache); break; default: dns_so_clear(&R->so); break; } } /* dns_res_clear() */ static int dns_res_events2(struct dns_resolver *R, enum dns_events type) { int events; switch (R->stack[R->sp].state) { case DNS_R_CHECK: events = R->cache->events(R->cache); return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events; default: return dns_so_events2(&R->so, type); } } /* dns_res_events2() */ int dns_res_events(struct dns_resolver *R) { return dns_res_events2(R, R->so.opts.events); } /* dns_res_events() */ int dns_res_pollfd(struct dns_resolver *R) { switch (R->stack[R->sp].state) { case DNS_R_CHECK: return R->cache->pollfd(R->cache); default: return dns_so_pollfd(&R->so); } } /* dns_res_pollfd() */ time_t dns_res_elapsed(struct dns_resolver *R) { return dns_elapsed(&R->elapsed); } /* dns_res_elapsed() */ int dns_res_poll(struct dns_resolver *R, int timeout) { return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout); } /* dns_res_poll() */ int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) { dns_res_reset(R); /* Don't anchor; that can conflict with searchlist generation. */ dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = strlen(qname)), 0); R->qtype = qtype; R->qclass = qclass; dns_begin(&R->elapsed); return 0; } /* dns_res_submit() */ int dns_res_check(struct dns_resolver *R) { int error; if ((error = dns_res_exec(R))) return error; return 0; } /* dns_res_check() */ struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *error) { struct dns_packet *answer; if (R->stack[0].state != DNS_R_DONE) { *error = DNS_EUNKNOWN; return 0; } answer = R->stack[0].answer; R->stack[0].answer = 0; return answer; } /* dns_res_fetch() */ struct dns_packet *dns_res_query(struct dns_resolver *res, const char *qname, enum dns_type qtype, enum dns_class qclass, int timeout, int *error_) { int error; if ((error = dns_res_submit(res, qname, qtype, qclass))) goto error; while ((error = dns_res_check(res))) { if (dns_res_elapsed(res) > timeout) error = DNS_ETIMEDOUT; if (error != DNS_EAGAIN) goto error; if ((error = dns_res_poll(res, 1))) goto error; } return dns_res_fetch(res, error_); error: *error_ = error; return 0; } /* dns_res_query() */ const struct dns_stat *dns_res_stat(struct dns_resolver *res) { return dns_so_stat(&res->so); } /* dns_res_stat() */ /* * A D D R I N F O R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_addrinfo { struct addrinfo hints; struct dns_resolver *res; char qname[DNS_D_MAXNAME + 1]; enum dns_type qtype; unsigned short qport, port; struct dns_packet *answer; struct dns_packet *glue; struct dns_rr_i i, g; struct dns_rr rr; char cname[DNS_D_MAXNAME + 1]; int state; }; /* struct dns_addrinfo */ struct dns_addrinfo *dns_ai_open(const char *host, const char *serv, enum dns_type qtype, const struct addrinfo *hints, struct dns_resolver *res, int *error_) { static const struct dns_addrinfo ai_initializer; struct dns_addrinfo *ai; int error; if (!res) return 0; dns_res_acquire(res); if (!(ai = malloc(sizeof *ai))) goto syerr; *ai = ai_initializer; ai->hints = *hints; ai->res = res; res = 0; if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname)) { error = ENAMETOOLONG; goto error; } ai->qtype = qtype; ai->qport = 0; if (serv) { while (isdigit((unsigned char)*serv)) { ai->qport *= 10; ai->qport += *serv++ - '0'; } } ai->port = ai->qport; return ai; syerr: error = dns_syerr(); error: *error_ = error; dns_ai_close(ai); dns_res_close(res); return 0; } /* dns_ai_open() */ void dns_ai_close(struct dns_addrinfo *ai) { if (!ai) return; dns_res_close(ai->res); if (ai->answer != ai->glue) free(ai->glue); free(ai->answer); free(ai); } /* dns_ai_close() */ static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) { struct sockaddr *saddr; struct sockaddr_in sin; struct sockaddr_in6 sin6; const char *cname; size_t clen; switch (type) { case DNS_T_A: saddr = memset(&sin, '\0', sizeof sin); sin.sin_family = AF_INET; sin.sin_port = htons(ai->port); memcpy(&sin.sin_addr, any, sizeof sin.sin_addr); break; case DNS_T_AAAA: saddr = memset(&sin6, '\0', sizeof sin6); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(ai->port); memcpy(&sin6.sin6_addr, any, sizeof sin6.sin6_addr); break; default: return EINVAL; } /* switch() */ if (ai->hints.ai_flags & AI_CANONNAME) { cname = (*ai->cname)? ai->cname : ai->qname; clen = strlen(cname); } else { cname = NULL; clen = 0; } if (!(*ent = malloc(sizeof **ent + dns_sa_len(saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0)))) return dns_syerr(); memset(*ent, '\0', sizeof **ent); (*ent)->ai_family = saddr->sa_family; (*ent)->ai_socktype = ai->hints.ai_socktype; (*ent)->ai_protocol = ai->hints.ai_protocol; (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, saddr, dns_sa_len(saddr)); (*ent)->ai_addrlen = dns_sa_len(saddr); if (ai->hints.ai_flags & AI_CANONNAME) (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(saddr), cname, clen + 1); return 0; } /* dns_ai_setent() */ enum dns_ai_state { DNS_AI_S_INIT, DNS_AI_S_NUMERIC, DNS_AI_S_SUBMIT, DNS_AI_S_CHECK, DNS_AI_S_FETCH, DNS_AI_S_FOREACH_I, DNS_AI_S_FOREACH_G, DNS_AI_S_SUBMIT_G, DNS_AI_S_CHECK_G, DNS_AI_S_FETCH_G, DNS_AI_S_DONE, }; /* enum dns_ai_state */ #define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0) int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) { struct dns_packet *ans, *glue; struct dns_rr rr; char qname[DNS_D_MAXNAME + 1]; union dns_any any; size_t len; int error; *ent = 0; exec: switch (ai->state) { case DNS_AI_S_INIT: ai->state++; case DNS_AI_S_NUMERIC: if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) { ai->state = DNS_AI_S_DONE; return dns_ai_setent(ent, &any, DNS_T_A, ai); } if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) { ai->state = DNS_AI_S_DONE; return dns_ai_setent(ent, &any, DNS_T_AAAA, ai); } if (ai->hints.ai_flags & AI_NUMERICHOST) dns_ai_goto(DNS_AI_S_DONE); ai->state++; case DNS_AI_S_SUBMIT: if ((error = dns_res_submit(ai->res, ai->qname, ai->qtype, DNS_C_IN))) return error; ai->state++; case DNS_AI_S_CHECK: if ((error = dns_res_check(ai->res))) return error; ai->state++; case DNS_AI_S_FETCH: if (!(ai->answer = dns_res_fetch(ai->res, &error))) return error; if ((error = dns_p_study(ai->answer))) return error; ai->glue = ai->answer; dns_rr_i_init(&ai->i, ai->answer); ai->i.section = DNS_S_AN; ai->i.type = ai->qtype; ai->i.sort = &dns_rr_i_order; ai->state++; case DNS_AI_S_FOREACH_I: /* Search generator may have changed our qname. */ if (!(len = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error))) return error; else if (len >= sizeof qname) return DNS_EILLEGAL; if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, strlen(qname), ai->answer, &error)) return error; ai->i.name = ai->cname; if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error)) dns_ai_goto(DNS_AI_S_DONE); if ((error = dns_any_parse(&any, &rr, ai->answer))) return error; ai->port = ai->qport; switch (rr.type) { case DNS_T_A: case DNS_T_AAAA: return dns_ai_setent(ent, &any, rr.type, ai); default: if (!dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)) dns_ai_goto(DNS_AI_S_FOREACH_I); /* * Find the "real" canonical name. Some authorities * publish aliases where an RFC defines a canonical * name. We trust that the resolver followed any * CNAME chains on it's own, regardless of whether * the "smart" option is enabled. */ if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->answer, &error)) return error; if (rr.type == DNS_T_SRV) ai->port = any.srv.port; break; } /* switch() */ dns_rr_i_init(&ai->g, ai->glue); ai->g.section = DNS_S_ALL & ~DNS_S_QD; ai->g.name = ai->cname; ai->g.type = (ai->hints.ai_family == AF_INET6)? DNS_T_AAAA : DNS_T_A; ai->state++; case DNS_AI_S_FOREACH_G: if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) { if (dns_rr_i_count(&ai->g) > 0) dns_ai_goto(DNS_AI_S_FOREACH_I); else dns_ai_goto(DNS_AI_S_SUBMIT_G); } if ((error = dns_any_parse(&any, &rr, ai->glue))) return error; return dns_ai_setent(ent, &any, rr.type, ai); case DNS_AI_S_SUBMIT_G: { struct dns_rr_i dns_rr_it; memset(&dns_rr_it, 0, sizeof dns_rr_it); dns_rr_it.section = DNS_S_QD; dns_rr_it.name = ai->g.name; dns_rr_it.type = ai->g.type; dns_rr_i_init(&dns_rr_it, ai->glue); if (dns_rr_grep(&rr, 1, &dns_rr_it, ai->glue, &error)) dns_ai_goto(DNS_AI_S_FOREACH_I); } if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN))) return error; ai->state++; case DNS_AI_S_CHECK_G: if ((error = dns_res_check(ai->res))) return error; ai->state++; case DNS_AI_S_FETCH_G: if (!(ans = dns_res_fetch(ai->res, &error))) return error; dns_p_study(ans); glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error); free(ans); if (!glue) return error; if (ai->glue != ai->answer) free(ai->glue); ai->glue = glue; dns_rr_i_init(&ai->g, ai->glue); /* ai->g.name should already point to ai->cname */ if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->glue, &error)) dns_ai_goto(DNS_AI_S_FOREACH_I); /* NOTE: Keep all the other iterator filters */ dns_ai_goto(DNS_AI_S_FOREACH_G); case DNS_AI_S_DONE: return ENOENT; default: return EINVAL; } /* switch() */ } /* dns_ai_nextent() */ time_t dns_ai_elapsed(struct dns_addrinfo *ai) { return dns_res_elapsed(ai->res); } /* dns_ai_elapsed() */ void dns_ai_clear(struct dns_addrinfo *ai) { dns_res_clear(ai->res); } /* dns_ai_clear() */ int dns_ai_events(struct dns_addrinfo *ai) { return dns_res_events(ai->res); } /* dns_ai_events() */ int dns_ai_pollfd(struct dns_addrinfo *ai) { return dns_res_pollfd(ai->res); } /* dns_ai_pollfd() */ int dns_ai_poll(struct dns_addrinfo *ai, int timeout) { return dns_res_poll(ai->res, timeout); } /* dns_ai_poll() */ size_t dns_ai_print(void *dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) { char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; size_t cp = 0; { char strtype[DNS_STRMAXLEN + 1] = { 0 }; dns_strtype(ai->qtype, strtype, DNS_STRMAXLEN + 1); cp += dns__printstring(dst, lim, cp, "[ ", 2); cp += dns__printstring(dst, lim, cp, ai->qname, strlen(ai->qname)); cp += dns__printstring(dst, lim, cp, " IN ", 4); cp += dns__printstring(dst, lim, cp, strtype, strlen(strtype)); cp += dns__printstring(dst, lim, cp, " ]\n", 3); cp += dns__printstring(dst, lim, cp, ".ai_family = ", 16); } switch (ent->ai_family) { case AF_INET: cp += dns__printstring(dst, lim, cp, "AF_INET", 7); break; case AF_INET6: cp += dns__printstring(dst, lim, cp, "AF_INET6", 8); break; default: cp += dns__print10(dst, lim, cp, ent->ai_family, 0); break; } cp += dns__printchar(dst, lim, cp, '\n'); cp += dns__printstring(dst, lim, cp, ".ai_socktype = ", 16); switch (ent->ai_socktype) { case SOCK_STREAM: cp += dns__printstring(dst, lim, cp, "SOCK_STREAM", 11); break; case SOCK_DGRAM: cp += dns__printstring(dst, lim, cp, "SOCK_DGRAM", 10); break; default: cp += dns__print10(dst, lim, cp, ent->ai_socktype, 0); break; } cp += dns__printchar(dst, lim, cp, '\n'); cp += dns__printstring(dst, lim, cp, ".ai_addr = [", 17); dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr), addr, sizeof addr); cp += dns__printstring(dst, lim, cp, addr, strlen(addr)); cp += dns__printstring(dst, lim, cp, "]:", 2); cp += dns__print10(dst, lim, cp, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0); cp += dns__printchar(dst, lim, cp, '\n'); cp += dns__printstring(dst, lim, cp, ".ai_canonname = ", 16); if (ent->ai_canonname) cp += dns__printstring(dst, lim, cp, ent->ai_canonname, strlen(ent->ai_canonname)); else cp += dns__printstring(dst, lim, cp, "[NULL]", 6); cp += dns__printchar(dst, lim, cp, '\n'); dns__printnul(dst, lim, cp); return cp; } /* dns_ai_print() */ const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) { return dns_res_stat(ai->res); } /* dns_ai_stat() */ /* * M I S C E L L A N E O U S R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static const struct { char name[16]; enum dns_section type; } dns_sections[] = { { "QUESTION", DNS_S_QUESTION }, { "QD", DNS_S_QUESTION }, { "ANSWER", DNS_S_ANSWER }, { "AN", DNS_S_ANSWER }, { "AUTHORITY", DNS_S_AUTHORITY }, { "NS", DNS_S_AUTHORITY }, { "ADDITIONAL", DNS_S_ADDITIONAL }, { "AR", DNS_S_ADDITIONAL }, }; const char *(dns_strsection)(enum dns_section section, void *dst, size_t lim) { unsigned i, p = 0; for (i = 0; i < lengthof(dns_sections); i++) { if (dns_sections[i].type & section) { if (p > 0) p += dns__printchar(dst, lim, p, '|'); p += dns__printstring(dst, lim, p, dns_sections[i].name, strlen(dns_sections[i].name)); section &= ~dns_sections[i].type; } } if (!p) p += dns__print10(dst, lim, 0, (0xffff & section), 0); dns__printnul(dst, lim, p); return dst; } /* dns_strsection() */ enum dns_section dns_isection(const char *src) { enum dns_section section = 0; char sbuf[128]; char *name, *next; unsigned i; dns_strlcpy(sbuf, src, sizeof sbuf); next = sbuf; while ((name = dns_strsep(&next, "|+, \t"))) { for (i = 0; i < lengthof(dns_sections); i++) { if (!strcasecmp(dns_sections[i].name, name)) { section |= dns_sections[i].type; break; } } } return section; } /* dns_isection() */ static const struct { char name[8]; enum dns_class type; } dns_classes[] = { { "IN", DNS_C_IN }, }; const char *(dns_strclass)(enum dns_class type, void *dst, size_t lim) { unsigned i; for (i = 0; i < lengthof(dns_classes); i++) { if (dns_classes[i].type == type) { dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_classes[i].name, strlen(dns_classes[i].name))); return dst; } } dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0)); return dst; } /* dns_strclass() */ enum dns_class dns_iclass(const char *name) { unsigned i; for (i = 0; i < lengthof(dns_classes); i++) { if (!strcasecmp(dns_classes[i].name, name)) return dns_classes[i].type; } return 0; } /* dns_iclass() */ const char *(dns_strtype)(enum dns_type type, void *dst, size_t lim) { unsigned i; for (i = 0; i < lengthof(dns_rrtypes); i++) { if (dns_rrtypes[i].type == type) { dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_rrtypes[i].name, strlen(dns_rrtypes[i].name))); return dst; } } dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0)); return dst; } /* dns_strtype() */ enum dns_type dns_itype(const char *type) { unsigned i; for (i = 0; i < lengthof(dns_rrtypes); i++) { if (!strcasecmp(dns_rrtypes[i].name, type)) return dns_rrtypes[i].type; } return 0; } /* dns_itype() */ static char dns_opcodes[16][16] = { "QUERY", /* DNS_OP_QUERY */ "IQUERY", /* DNS_OP_IQUERY */ "STATUS", /* DNS_OP_STATUS */ "NOTIFY", /* DNS_OP_NOTIFY */ "UPDATE" /* DNS_OP_UPDATE */ }; const char *dns_stropcode(enum dns_opcode opcode) { opcode &= 0xf; if ('\0' == dns_opcodes[opcode][0]) dns__printnul(dns_opcodes[opcode], sizeof dns_opcodes[opcode], dns__print10(dns_opcodes[opcode], sizeof dns_opcodes[opcode], 0, opcode, 0)); return dns_opcodes[opcode]; } /* dns_stropcode() */ enum dns_opcode dns_iopcode(const char *name) { unsigned opcode; for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) { if (!strcasecmp(name, dns_opcodes[opcode])) return opcode; } return lengthof(dns_opcodes) - 1; } /* dns_iopcode() */ static char dns_rcodes[16][16] = { "NOERROR", /* DNS_RC_NOERROR */ "FORMERR", /* DNS_RC_FORMERR */ "SERVFAIL", /* DNS_RC_SERVFAIL */ "NXDOMAIN", /* DNS_RC_NXDOMAIN */ "NOTIMP", /* DNS_RC_NOTIMP */ "REFUSED", /* DNS_RC_REFUSED */ "YXDOMAIN", /* DNS_RC_YXDOMAIN */ "YXRRSET", /* DNS_RC_YXRRSET */ "NXRRSET", /* DNS_RC_NXRRSET */ "NOTAUTH", /* DNS_RC_NOTAUTH */ "NOTZONE" /* DNS_RC_NOTZONE */ }; const char *dns_strrcode(enum dns_rcode rcode) { rcode &= 0xf; if ('\0' == dns_rcodes[rcode][0]) dns__printnul(dns_rcodes[rcode], sizeof dns_rcodes[rcode], dns__print10(dns_rcodes[rcode], sizeof dns_rcodes[rcode], 0, rcode, 0)); return dns_rcodes[rcode]; } /* dns_strrcode() */ enum dns_rcode dns_ircode(const char *name) { unsigned rcode; for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) { if (!strcasecmp(name, dns_rcodes[rcode])) return rcode; } return lengthof(dns_rcodes) - 1; } /* dns_ircode() */ /* * C O M M A N D - L I N E / R E G R E S S I O N R O U T I N E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if DNS_MAIN #include #include #include #include #if _WIN32 #include #endif #if !_WIN32 #include #endif struct { struct { const char *path[8]; unsigned count; } resconf, nssconf, hosts, cache; const char *qname; enum dns_type qtype; int (*sort)(); int verbose; } MAIN = { .sort = &dns_rr_i_packet, }; void hexdump(const unsigned char *src, size_t len, FILE *fp) { static const unsigned char hex[] = "0123456789abcdef"; static const unsigned char tmpl[] = " | |\n"; unsigned char ln[sizeof tmpl]; const unsigned char *sp, *se; unsigned char *h, *g; unsigned i, n; sp = src; se = sp + len; while (sp < se) { memcpy(ln, tmpl, sizeof ln); h = &ln[2]; g = &ln[53]; for (n = 0; n < 2; n++) { for (i = 0; i < 8 && se - sp > 0; i++, sp++) { h[0] = hex[0x0f & (*sp >> 4)]; h[1] = hex[0x0f & (*sp >> 0)]; h += 3; *g++ = (isgraph(*sp))? *sp : '.'; } h++; } fputs((char *)ln, fp); } return /* void */; } /* hexdump() */ static void panic(const char *fmt, ...) { va_list ap; va_start(ap, fmt); #if _WIN32 vfprintf(stderr, fmt, ap); exit(EXIT_FAILURE); #else verrx(EXIT_FAILURE, fmt, ap); #endif } /* panic() */ #define panic_(fn, ln, fmt, ...) \ panic(fmt "%0s", (fn), (ln), __VA_ARGS__) #define panic(...) \ panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "") static void *grow(unsigned char *p, size_t size) { void *tmp; if (!(tmp = realloc(p, size))) panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno)); return tmp; } /* grow() */ static size_t add(size_t a, size_t b) { if (~a < b) panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b); return a + b; } /* add() */ static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) { size_t size = add(osize, len); *dst = grow(*dst, size); memcpy(*dst + osize, src, len); return size; } /* append() */ static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) { size_t size = osize; unsigned char buf[1024]; size_t count; while ((count = fread(buf, 1, sizeof buf, fp))) size = append(dst, size, buf, count); if (ferror(fp)) panic("%s: %s", path, dns_strerror(errno)); return size; } /* slurp() */ static struct dns_resolv_conf *resconf(void) { static struct dns_resolv_conf *resconf; const char *path; unsigned i; int error; if (resconf) return resconf; if (!(resconf = dns_resconf_open(&error))) panic("dns_resconf_open: %s", dns_strerror(error)); if (!MAIN.resconf.count) MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf"; for (i = 0; i < MAIN.resconf.count; i++) { path = MAIN.resconf.path[i]; if (0 == strcmp(path, "-")) error = dns_resconf_loadfile(resconf, stdin); else error = dns_resconf_loadpath(resconf, path); if (error) panic("%s: %s", path, dns_strerror(error)); } for (i = 0; i < MAIN.nssconf.count; i++) { path = MAIN.nssconf.path[i]; if (0 == strcmp(path, "-")) error = dns_nssconf_loadfile(resconf, stdin); else error = dns_nssconf_loadpath(resconf, path); if (error) panic("%s: %s", path, dns_strerror(error)); } if (!MAIN.nssconf.count) { path = "/etc/nsswitch.conf"; if (!(error = dns_nssconf_loadpath(resconf, path))) MAIN.nssconf.path[MAIN.nssconf.count++] = path; else if (error != ENOENT) panic("%s: %s", path, dns_strerror(error)); } return resconf; } /* resconf() */ static struct dns_hosts *hosts(void) { static struct dns_hosts *hosts; const char *path; unsigned i; int error; if (hosts) return hosts; if (!MAIN.hosts.count) { MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts"; /* Explicitly test dns_hosts_local() */ if (!(hosts = dns_hosts_local(&error))) panic("%s: %s", "/etc/hosts", dns_strerror(error)); return hosts; } if (!(hosts = dns_hosts_open(&error))) panic("dns_hosts_open: %s", dns_strerror(error)); for (i = 0; i < MAIN.hosts.count; i++) { path = MAIN.hosts.path[i]; if (0 == strcmp(path, "-")) error = dns_hosts_loadfile(hosts, stdin); else error = dns_hosts_loadpath(hosts, path); if (error) panic("%s: %s", path, dns_strerror(error)); } return hosts; } /* hosts() */ #if DNS_CACHE #include "cache.h" struct dns_cache *cache(void) { static struct cache *cache; const char *path; unsigned i; int error; if (cache) return cache_resi(cache); if (!MAIN.cache.count) return NULL; if (!(cache = cache_open(&error))) panic("%s: %s", MAIN.cache.path[0], dns_strerror(error)); for (i = 0; i < MAIN.cache.count; i++) { path = MAIN.cache.path[i]; if (!strcmp(path, "-")) { if ((error = cache_loadfile(cache, stdin, NULL, 0))) panic("%s: %s", path, dns_strerror(error)); } else if ((error = cache_loadpath(cache, path, NULL, 0))) panic("%s: %s", path, dns_strerror(error)); } return cache_resi(cache); } /* cache() */ #else struct dns_cache *cache(void) { return NULL; } #endif static void print_packet(struct dns_packet *P, FILE *fp) { dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp); if (MAIN.verbose > 2) hexdump(P->data, P->end, fp); } /* print_packet() */ static int parse_packet(int argc, char *argv[]) { struct dns_packet *P = dns_p_new(512); struct dns_packet *Q = dns_p_new(512); enum dns_section section; struct dns_rr rr; int error; union dns_any any; char pretty[sizeof any * 2]; size_t len; P->end = fread(P->data, 1, P->size, stdin); fputs(";; [HEADER]\n", stdout); fprintf(stdout, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr); fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode); fprintf(stdout, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa); fprintf(stdout, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc); fprintf(stdout, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd); fprintf(stdout, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra); fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode); section = 0; dns_rr_foreach(&rr, P, .sort = MAIN.sort) { if (section != rr.section) fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section)); if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error))) fprintf(stdout, "%s\n", pretty); dns_rr_copy(Q, &rr, P); section = rr.section; } fputs("; ; ; ; ; ; ; ;\n\n", stdout); section = 0; #if 0 dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") { #else struct dns_rr rrset[32]; struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort); unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error); for (unsigned i = 0; i < rrcount; i++) { rr = rrset[i]; #endif if (section != rr.section) fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section)); if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error))) fprintf(stdout, "%s\n", pretty); section = rr.section; } if (MAIN.verbose > 1) { fprintf(stderr, "orig:%"PRIuZ"\n", P->end); hexdump(P->data, P->end, stdout); fprintf(stderr, "copy:%"PRIuZ"\n", Q->end); hexdump(Q->data, Q->end, stdout); } return 0; } /* parse_packet() */ static int parse_domain(int argc, char *argv[]) { char *dn; dn = (argc > 1)? argv[1] : "f.l.google.com"; printf("[%s]\n", dn); dn = dns_d_new(dn); do { puts(dn); } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn))); return 0; } /* parse_domain() */ static int expand_domain(int argc, char *argv[]) { unsigned short rp = 0; unsigned char *src = NULL; unsigned char *dst; struct dns_packet *pkt; size_t lim = 0, len; int error; if (argv[1]) rp = atoi(argv[1]); len = slurp(&src, 0, stdin, "-"); if (!(pkt = dns_p_make(len, &error))) panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error)); memcpy(pkt->data, src, len); pkt->end = len; lim = 1; dst = grow(NULL, lim); while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) { lim = add(len, 1); dst = grow(dst, lim); } if (!len) panic("expand: %s", dns_strerror(error)); fwrite(dst, 1, len, stdout); fflush(stdout); free(src); free(dst); free(pkt); return 0; } /* expand_domain() */ static int show_resconf(int argc, char *argv[]) { unsigned i; resconf(); /* load it */ fputs("; SOURCES\n", stdout); for (i = 0; i < MAIN.resconf.count; i++) fprintf(stdout, "; %s\n", MAIN.resconf.path[i]); for (i = 0; i < MAIN.nssconf.count; i++) fprintf(stdout, "; %s\n", MAIN.nssconf.path[i]); fputs(";\n", stdout); dns_resconf_dump(resconf(), stdout); return 0; } /* show_resconf() */ static int show_nssconf(int argc, char *argv[]) { unsigned i; resconf(); fputs("# SOURCES\n", stdout); for (i = 0; i < MAIN.resconf.count; i++) fprintf(stdout, "# %s\n", MAIN.resconf.path[i]); for (i = 0; i < MAIN.nssconf.count; i++) fprintf(stdout, "# %s\n", MAIN.nssconf.path[i]); fputs("#\n", stdout); dns_nssconf_dump(resconf(), stdout); return 0; } /* show_nssconf() */ static int show_hosts(int argc, char *argv[]) { unsigned i; hosts(); fputs("# SOURCES\n", stdout); for (i = 0; i < MAIN.hosts.count; i++) fprintf(stdout, "# %s\n", MAIN.hosts.path[i]); fputs("#\n", stdout); dns_hosts_dump(hosts(), stdout); return 0; } /* show_hosts() */ static int query_hosts(int argc, char *argv[]) { struct dns_packet *Q = dns_p_new(512); struct dns_packet *A; char qname[DNS_D_MAXNAME + 1]; size_t qlen; int error; if (!MAIN.qname) MAIN.qname = (argc > 1)? argv[1] : "localhost"; if (!MAIN.qtype) MAIN.qtype = DNS_T_A; hosts(); if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) { union { struct in_addr a; struct in6_addr a6; } addr; int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET; if ((error = dns_pton(af, MAIN.qname, &addr))) panic("%s: %s", MAIN.qname, dns_strerror(error)); qlen = dns_ptr_qname(qname, sizeof qname, af, &addr); } else qlen = dns__printstring(qname, sizeof qname, 0, MAIN.qname); if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0))) panic("%s: %s", qname, dns_strerror(error)); if (!(A = dns_hosts_query(hosts(), Q, &error))) panic("%s: %s", qname, dns_strerror(error)); print_packet(A, stdout); free(A); return 0; } /* query_hosts() */ static int search_list(int argc, char *argv[]) { const char *qname = (argc > 1)? argv[1] : "f.l.google.com"; unsigned long i = 0; char name[DNS_D_MAXNAME + 1]; printf("[%s]\n", qname); while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i)) puts(name); return 0; } /* search_list() */ int permute_set(int argc, char *argv[]) { unsigned lo, hi, i; struct dns_k_permutor p; hi = (--argc > 0)? atoi(argv[argc]) : 8; lo = (--argc > 0)? atoi(argv[argc]) : 0; fprintf(stderr, "[%u .. %u]\n", lo, hi); dns_k_permutor_init(&p, lo, hi); for (i = lo; i <= hi; i++) fprintf(stdout, "%u\n", dns_k_permutor_step(&p)); // printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i))); return 0; } /* permute_set() */ int shuffle_16(int argc, char *argv[]) { unsigned n, r; if (--argc > 0) { n = 0xffff & atoi(argv[argc]); r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random(); fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r)); } else { r = dns_random(); for (n = 0; n < 65536; n++) fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r)); } return 0; } /* shuffle_16() */ int dump_random(int argc, char *argv[]) { unsigned char b[32]; unsigned i, j, n, r; n = (argc > 1)? atoi(argv[1]) : 32; while (n) { i = 0; do { r = dns_random(); for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) { b[i] = 0xff & r; r >>= 8; } } while (i < n && i < sizeof b); hexdump(b, i, stdout); n -= i; } return 0; } /* dump_random() */ static int send_query(int argc, char *argv[]) { struct dns_packet *A, *Q = dns_p_new(512); char host[INET6_ADDRSTRLEN + 1]; struct sockaddr_storage ss; struct dns_socket *so; int error, type; if (argc > 1) { ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET; if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss)))) panic("%s: %s", argv[1], dns_strerror(error)); *dns_sa_port(ss.ss_family, &ss) = htons(53); } else memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0])); if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss), host, sizeof host)) panic("bad host address, or none provided"); if (!MAIN.qname) MAIN.qname = "ipv6.google.com"; if (!MAIN.qtype) MAIN.qtype = DNS_T_AAAA; if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0))) panic("dns_p_push: %s", dns_strerror(error)); dns_header(Q)->rd = 1; if (strstr(argv[0], "udp")) type = SOCK_DGRAM; else if (strstr(argv[0], "tcp")) type = SOCK_STREAM; else type = dns_res_tcp2type(resconf()->options.tcp); fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype)); if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error))) panic("dns_so_open: %s", dns_strerror(error)); while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) { if (error != DNS_EAGAIN) panic("dns_so_query: %s (%d)", dns_strerror(error), error); if (dns_so_elapsed(so) > 10) panic("query timed-out"); dns_so_poll(so, 1); } print_packet(A, stdout); dns_so_close(so); return 0; } /* send_query() */ static int print_arpa(int argc, char *argv[]) { const char *ip = (argc > 1)? argv[1] : "::1"; int af = (strchr(ip, ':'))? AF_INET6 : AF_INET; union { struct in_addr a4; struct in6_addr a6; } addr; char host[DNS_D_MAXNAME + 1]; if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr)) panic("%s: invalid address", ip); fprintf(stdout, "%s\n", host); return 0; } /* print_arpa() */ static int show_hints(int argc, char *argv[]) { struct dns_hints *(*load)(struct dns_resolv_conf *, int *); const char *which, *how, *who; struct dns_hints *hints; int error; which = (argc > 1)? argv[1] : "local"; how = (argc > 2)? argv[2] : "plain"; who = (argc > 3)? argv[3] : "google.com"; load = (0 == strcmp(which, "local")) ? &dns_hints_local : &dns_hints_root; if (!(hints = load(resconf(), &error))) panic("%s: %s", argv[0], dns_strerror(error)); if (0 == strcmp(how, "plain")) { dns_hints_dump(hints, stdout); } else { struct dns_packet *query, *answer; query = dns_p_new(512); if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0))) panic("%s: %s", who, dns_strerror(error)); if (!(answer = dns_hints_query(hints, query, &error))) panic("%s: %s", who, dns_strerror(error)); print_packet(answer, stdout); free(answer); } dns_hints_close(hints); return 0; } /* show_hints() */ static int resolve_query(int argc, char *argv[]) { struct dns_hints *(*hints)() = (strstr(argv[0], "recurse"))? &dns_hints_root : &dns_hints_local; struct dns_resolver *R; struct dns_packet *ans; const struct dns_stat *st; int error; if (!MAIN.qname) MAIN.qname = "www.google.com"; if (!MAIN.qtype) MAIN.qtype = DNS_T_A; resconf()->options.recurse = (0 != strstr(argv[0], "recurse")); if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error))) panic("%s: %s", MAIN.qname, dns_strerror(error)); if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN))) panic("%s: %s", MAIN.qname, dns_strerror(error)); while ((error = dns_res_check(R))) { if (error != DNS_EAGAIN) panic("dns_res_check: %s (%d)", dns_strerror(error), error); if (dns_res_elapsed(R) > 30) panic("query timed-out"); dns_res_poll(R, 1); } ans = dns_res_fetch(R, &error); print_packet(ans, stdout); free(ans); st = dns_res_stat(R); putchar('\n'); printf(";; queries: %"PRIuZ"\n", st->queries); printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes); printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes); printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes); printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes); dns_res_close(R); return 0; } /* resolve_query() */ static int resolve_addrinfo(int argc, char *argv[]) { struct dns_hints *(*hints)() = (strstr(argv[0], "recurse"))? &dns_hints_root : &dns_hints_local; struct dns_resolver *res = 0; struct dns_addrinfo *ai = 0; struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME }; struct addrinfo *ent; char pretty[512]; int error; if (!MAIN.qname) MAIN.qname = "www.google.com"; if (!MAIN.qtype) MAIN.qtype = DNS_T_A; resconf()->options.recurse = (0 != strstr(argv[0], "recurse")); if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error))) panic("%s: %s", MAIN.qname, dns_strerror(error)); if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error))) panic("%s: %s", MAIN.qname, dns_strerror(error)); do { switch (error = dns_ai_nextent(&ent, ai)) { case 0: dns_ai_print(pretty, sizeof pretty, ent, ai); fputs(pretty, stdout); free(ent); break; case ENOENT: break; case DNS_EAGAIN: if (dns_ai_elapsed(ai) > 30) panic("query timed-out"); dns_ai_poll(ai, 1); break; default: panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error); } } while (error != ENOENT); dns_res_close(res); dns_ai_close(ai); return 0; } /* resolve_addrinfo() */ static int echo_port(int argc, char *argv[]) { union { struct sockaddr sa; struct sockaddr_in sin; } port; int fd; memset(&port, 0, sizeof port); port.sin.sin_family = AF_INET; port.sin.sin_port = htons(5354); port.sin.sin_addr.s_addr = inet_addr("127.0.0.1"); if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0))) panic("socket: %s", strerror(errno)); if (0 != bind(fd, &port.sa, sizeof port.sa)) panic("127.0.0.1:5353: %s", dns_strerror(errno)); for (;;) { struct dns_packet *pkt = dns_p_new(512); struct sockaddr_storage ss; socklen_t slen = sizeof ss; ssize_t count; #if defined(MSG_WAITALL) /* MinGW issue */ int rflags = MSG_WAITALL; #else int rflags = 0; #endif count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen); if (!count || count < 0) panic("recvfrom: %s", strerror(errno)); pkt->end = count; dns_p_dump(pkt, stdout); (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen); } return 0; } /* echo_port() */ static int isection(int argc, char *argv[]) { const char *name = (argv[1])? argv[1] : ""; int type; type = dns_isection(name); name = dns_strsection(type); printf("%s (%d)\n", name, type); return 0; } /* isection() */ static int iclass(int argc, char *argv[]) { const char *name = (argv[1])? argv[1] : ""; int type; type = dns_iclass(name); name = dns_strclass(type); printf("%s (%d)\n", name, type); return 0; } /* iclass() */ static int itype(int argc, char *argv[]) { const char *name = (argv[1])? argv[1] : ""; int type; type = dns_itype(name); name = dns_strtype(type); printf("%s (%d)\n", name, type); return 0; } /* itype() */ static int iopcode(int argc, char *argv[]) { const char *name = (argv[1])? argv[1] : ""; int type; type = dns_iopcode(name); name = dns_stropcode(type); printf("%s (%d)\n", name, type); return 0; } /* iopcode() */ static int ircode(int argc, char *argv[]) { const char *name = (argv[1])? argv[1] : ""; int type; type = dns_ircode(name); name = dns_strrcode(type); printf("%s (%d)\n", name, type); return 0; } /* ircode() */ #define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) } #define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__) #define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__) #define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__) #define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) static int sizes(int argc, char *argv[]) { static const struct { const char *name; size_t size; } type[] = { SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i), SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns), SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv), SIZE(struct dns_sshfp, struct dns_txt, union dns_any), SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i), SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo), SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long) }; unsigned i, max; for (i = 0, max = 0; i < lengthof(type); i++) max = MAX(max, strlen(type[i].name)); for (i = 0; i < lengthof(type); i++) printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size); return 0; } /* sizes() */ static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = { { "parse-packet", &parse_packet, "parse binary packet from stdin" }, { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" }, { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" }, { "show-resconf", &show_resconf, "show resolv.conf data" }, { "show-hosts", &show_hosts, "show hosts data" }, { "show-nssconf", &show_nssconf, "show nsswitch.conf data" }, { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" }, { "search-list", &search_list, "generate query search list from domain" }, { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" }, { "shuffle-16", &shuffle_16, "simple 16-bit permutation" }, { "dump-random", &dump_random, "generate random bytes" }, { "send-query", &send_query, "send query to host" }, { "send-query-udp", &send_query, "send udp query to host" }, { "send-query-tcp", &send_query, "send tcp query to host" }, { "print-arpa", &print_arpa, "print arpa. zone name of address" }, { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" }, { "resolve-stub", &resolve_query, "resolve as stub resolver" }, { "resolve-recurse", &resolve_query, "resolve as recursive resolver" }, { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" }, { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" }, /* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */ { "echo", &echo_port, "server echo mode, for nmap fuzzing" }, { "isection", &isection, "parse section string" }, { "iclass", &iclass, "parse class string" }, { "itype", &itype, "parse type string" }, { "iopcode", &iopcode, "parse opcode string" }, { "ircode", &ircode, "parse rcode string" }, { "sizes", &sizes, "print data structure sizes" }, }; static void print_usage(const char *progname, FILE *fp) { static const char *usage = " [OPTIONS] COMMAND [ARGS]\n" " -c PATH Path to resolv.conf\n" " -n PATH Path to nsswitch.conf\n" " -l PATH Path to local hosts\n" " -z PATH Path to zone cache\n" " -q QNAME Query name\n" " -t QTYPE Query type\n" " -s HOW Sort records\n" " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n" " -V Print version info\n" " -h Print this usage message\n" "\n"; unsigned i, n, m; fputs(progname, fp); fputs(usage, fp); for (i = 0, m = 0; i < lengthof(cmds); i++) { if (strlen(cmds[i].cmd) > m) m = strlen(cmds[i].cmd); } for (i = 0; i < lengthof(cmds); i++) { fprintf(fp, " %s ", cmds[i].cmd); for (n = strlen(cmds[i].cmd); n < m; n++) putc(' ', fp); fputs(cmds[i].help, fp); putc('\n', fp); } fputs("\nReport bugs to William Ahern \n", fp); } /* print_usage() */ static void print_version(const char *progname, FILE *fp) { fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel()); fprintf(fp, "vendor %s\n", dns_vendor()); fprintf(fp, "release %.8X\n", dns_v_rel()); fprintf(fp, "abi %.8X\n", dns_v_abi()); fprintf(fp, "api %.8X\n", dns_v_api()); } /* print_version() */ int main(int argc, char **argv) { extern int optind; extern char *optarg; const char *progname = argv[0]; unsigned i; int ch; while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:vVh"))) { switch (ch) { case 'c': assert(MAIN.resconf.count < lengthof(MAIN.resconf.path)); MAIN.resconf.path[MAIN.resconf.count++] = optarg; break; case 'n': assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path)); MAIN.nssconf.path[MAIN.nssconf.count++] = optarg; break; case 'l': assert(MAIN.hosts.count < lengthof(MAIN.hosts.path)); MAIN.hosts.path[MAIN.hosts.count++] = optarg; break; case 'z': assert(MAIN.cache.count < lengthof(MAIN.cache.path)); MAIN.cache.path[MAIN.cache.count++] = optarg; break; case 'q': MAIN.qname = optarg; break; case 't': for (i = 0; i < lengthof(dns_rrtypes); i++) { if (0 == strcasecmp(dns_rrtypes[i].name, optarg)) { MAIN.qtype = dns_rrtypes[i].type; break; } } if (MAIN.qtype) break; for (i = 0; isdigit((int)optarg[i]); i++) { MAIN.qtype *= 10; MAIN.qtype += optarg[i] - '0'; } if (!MAIN.qtype) panic("%s: invalid query type", optarg); break; case 's': if (0 == strcasecmp(optarg, "packet")) MAIN.sort = &dns_rr_i_packet; else if (0 == strcasecmp(optarg, "shuffle")) MAIN.sort = &dns_rr_i_shuffle; else if (0 == strcasecmp(optarg, "order")) MAIN.sort = &dns_rr_i_order; else panic("%s: invalid sort method", optarg); break; case 'v': dns_debug = ++MAIN.verbose; break; case 'V': print_version(progname, stdout); return 0; case 'h': print_usage(progname, stdout); return 0; default: print_usage(progname, stderr); return EXIT_FAILURE; } /* switch() */ } /* while() */ argc -= optind; argv += optind; for (i = 0; i < lengthof(cmds) && argv[0]; i++) { if (0 == strcmp(cmds[i].cmd, argv[0])) return cmds[i].run(argc, argv); } print_usage(progname, stderr); return EXIT_FAILURE; } /* main() */ #endif /* DNS_MAIN */ /* * pop file-scoped compiler annotations */ #if __clang__ #pragma clang diagnostic pop #elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 #pragma GCC diagnostic pop #endif belle-sip-1.4.1/src/dns.h000066400000000000000000000745151252242224000151240ustar00rootroot00000000000000/* ========================================================================== * dns.h - Recursive, Reentrant DNS Resolver. * -------------------------------------------------------------------------- * Copyright (c) 2009, 2010, 2012 William Ahern * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * ========================================================================== */ #ifndef DNS_H #define DNS_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* size_t offsetof() */ #include /* FILE */ #include /* strlen(3) */ #include /* time_t */ #if _WIN32 #include #include #else #include /* BYTE_ORDER BIG_ENDIAN _BIG_ENDIAN */ #include /* socklen_t */ #include /* struct socket */ #include /* POLLIN POLLOUT */ #include /* struct in_addr struct in6_addr */ #include /* struct addrinfo */ #endif typedef unsigned char DNSBool; #ifdef _MSC_VER #define DNS_INLINE __inline #else #define DNS_INLINE inline #endif /* * V E R S I O N * * Vendor: Entity for which versions numbers are relevant. (If forking * change DNS_VENDOR to avoid confusion.) * * Three versions: * * REL Official "release"--bug fixes, new features, etc. * ABI Changes to existing object sizes or parameter types. * API Changes that might effect application source. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_VENDOR "william@25thandClement.com" #define DNS_V_REL 0x20121023 #define DNS_V_ABI 0x20120806 #define DNS_V_API 0x20120806 const char *dns_vendor(void); int dns_v_rel(void); int dns_v_abi(void); int dns_v_api(void); /* * E R R O R S * * Errors and exceptions are always returned through an int. This should * hopefully make integration easier in the majority of circumstances, and * also cut down on useless compiler warnings. * * System and library errors are returned together. POSIX guarantees that * all system errors are positive integers. Library errors are always * negative integers in the range DNS_EBASE to DNS_ELAST, with the high bits * set to the three magic ASCII characters "dns". * * dns_strerror() returns static English string descriptions of all known * errors, and punts the remainder to strerror(3). * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_EBASE -(('d' << 24) | ('n' << 16) | ('s' << 8) | 64) #define dns_error_t int /* for documentation only */ enum dns_errno { DNS_ENOBUFS = DNS_EBASE, DNS_EILLEGAL, DNS_EORDER, DNS_ESECTION, DNS_EUNKNOWN, DNS_EADDRESS, DNS_ELAST, }; /* dns_errno */ const char *dns_strerror(dns_error_t); extern int dns_debug; /* * C O M P I L E R A N N O T A T I O N S * * GCC with -Wextra, and clang by default, complain about overrides in * initializer lists. Overriding previous member initializers is well * defined behavior in C. dns.c relies on this behavior to define default, * overrideable member values when instantiating configuration objects. * * dns_quietinit() guards a compound literal expression with pragmas to * silence these shrill warnings. This alleviates the burden of requiring * third-party projects to adjust their compiler flags. * * NOTE: If you take the address of the compound literal, take the address * of the transformed expression, otherwise the compound literal lifetime is * tied to the scope of the GCC statement expression. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if defined __clang__ #define DNS_PRAGMA_PUSH _Pragma("clang diagnostic push") #define DNS_PRAGMA_QUIET _Pragma("clang diagnostic ignored \"-Winitializer-overrides\"") #define DNS_PRAGMA_POP _Pragma("clang diagnostic pop") #define dns_quietinit(...) \ DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__ DNS_PRAGMA_POP #elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 #define DNS_PRAGMA_PUSH _Pragma("GCC diagnostic push") #define DNS_PRAGMA_QUIET _Pragma("GCC diagnostic ignored \"-Woverride-init\"") #define DNS_PRAGMA_POP _Pragma("GCC diagnostic pop") /* GCC parses the _Pragma operator less elegantly than clang. */ #define dns_quietinit(...) \ ({ DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__; DNS_PRAGMA_POP }) #else #define DNS_PRAGMA_PUSH #define DNS_PRAGMA_QUIET #define DNS_PRAGMA_POP #define dns_quietinit(...) __VA_ARGS__ #endif /* * E V E N T S I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #if defined(POLLIN) #define DNS_POLLIN POLLIN #else #define DNS_POLLIN 1 #endif #if defined(POLLOUT) #define DNS_POLLOUT POLLOUT #else #define DNS_POLLOUT 2 #endif /* * See Application Interface below for configuring libevent bitmasks instead * of poll(2) bitmasks. */ #define DNS_EVREAD 2 #define DNS_EVWRITE 4 #define DNS_POLL2EV(set) \ (((set) & DNS_POLLIN)? DNS_EVREAD : 0) | (((set) & DNS_POLLOUT)? DNS_EVWRITE : 0) #define DNS_EV2POLL(set) \ (((set) & DNS_EVREAD)? DNS_POLLIN : 0) | (((set) & DNS_EVWRITE)? DNS_POLLOUT : 0) /* * E N U M E R A T I O N I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ enum dns_section { DNS_S_QD = 0x01, #define DNS_S_QUESTION DNS_S_QD DNS_S_AN = 0x02, #define DNS_S_ANSWER DNS_S_AN DNS_S_NS = 0x04, #define DNS_S_AUTHORITY DNS_S_NS DNS_S_AR = 0x08, #define DNS_S_ADDITIONAL DNS_S_AR DNS_S_ALL = 0x0f }; /* enum dns_section */ enum dns_class { DNS_C_IN = 1, DNS_C_ANY = 255 }; /* enum dns_class */ enum dns_type { DNS_T_A = 1, DNS_T_NS = 2, DNS_T_CNAME = 5, DNS_T_SOA = 6, DNS_T_PTR = 12, DNS_T_MX = 15, DNS_T_TXT = 16, DNS_T_AAAA = 28, DNS_T_SRV = 33, DNS_T_OPT = 41, DNS_T_SSHFP = 44, DNS_T_SPF = 99, DNS_T_ALL = 255 }; /* enum dns_type */ enum dns_opcode { DNS_OP_QUERY = 0, DNS_OP_IQUERY = 1, DNS_OP_STATUS = 2, DNS_OP_NOTIFY = 4, DNS_OP_UPDATE = 5, }; /* dns_opcode */ enum dns_rcode { DNS_RC_NOERROR = 0, DNS_RC_FORMERR = 1, DNS_RC_SERVFAIL = 2, DNS_RC_NXDOMAIN = 3, DNS_RC_NOTIMP = 4, DNS_RC_REFUSED = 5, DNS_RC_YXDOMAIN = 6, DNS_RC_YXRRSET = 7, DNS_RC_NXRRSET = 8, DNS_RC_NOTAUTH = 9, DNS_RC_NOTZONE = 10, }; /* dns_rcode */ /* * NOTE: These string functions need a small buffer in case the literal * integer value needs to be printed and returned. UNLESS this buffer is * SPECIFIED, the returned string has ONLY BLOCK SCOPE. */ #define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */ const char *dns_strsection(enum dns_section, void *, size_t); #ifdef HAVE_C99 #define dns_strsection3(a, b, c) \ dns_strsection((a), (b), (c)) #define dns_strsection1(a) dns_strsection((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) #define dns_strsection(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strsection, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) #endif enum dns_section dns_isection(const char *); const char *dns_strclass(enum dns_class, void *, size_t); #ifdef HAVE_C99 #define dns_strclass3(a, b, c) dns_strclass((a), (b), (c)) #define dns_strclass1(a) dns_strclass((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) #define dns_strclass(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strclass, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) #endif enum dns_class dns_iclass(const char *); const char *dns_strtype(enum dns_type, void *, size_t); #ifdef HAVE_C99 #define dns_strtype3(a, b, c) dns_strtype((a), (b), (c)) #define dns_strtype1(a) dns_strtype((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) #define dns_strtype(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strtype, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) #endif enum dns_type dns_itype(const char *); const char *dns_stropcode(enum dns_opcode); enum dns_opcode dns_iopcode(const char *); const char *dns_strrcode(enum dns_rcode); enum dns_rcode dns_ircode(const char *); /* * A T O M I C I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ typedef unsigned long dns_atomic_t; /* * C R Y P T O I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ extern unsigned (*dns_random)(void); /* * P A C K E T I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_header { unsigned qid:16; #if (defined BYTE_ORDER && BYTE_ORDER == BIG_ENDIAN) || (defined __sun && defined _BIG_ENDIAN) unsigned qr:1; unsigned opcode:4; unsigned aa:1; unsigned tc:1; unsigned rd:1; unsigned ra:1; unsigned unused:3; unsigned rcode:4; #else unsigned rd:1; unsigned tc:1; unsigned aa:1; unsigned opcode:4; unsigned qr:1; unsigned rcode:4; unsigned unused:3; unsigned ra:1; #endif unsigned qdcount:16; unsigned ancount:16; unsigned nscount:16; unsigned arcount:16; }; /* struct dns_header */ #define dns_header(p) (&(p)->header) #ifndef DNS_P_QBUFSIZ #define DNS_P_QBUFSIZ dns_p_calcsize(256 + 4) #endif #ifndef DNS_P_DICTSIZE #define DNS_P_DICTSIZE 16 #endif #ifndef HAVE_C99 struct dns_s_memo { unsigned short base, end; }; #endif struct dns_packet { unsigned short dict[DNS_P_DICTSIZE]; #ifdef HAVE_C99 struct dns_s_memo { unsigned short base, end; } qd, an, ns, ar; #else struct dns_s_memo qd, an, ns, ar; #endif struct { struct dns_packet *cqe_next, *cqe_prev; } cqe; size_t size, end; int:16; /* tcp padding */ union { struct dns_header header; unsigned char data[1]; }; }; /* struct dns_packet */ #define dns_p_calcsize(n) (offsetof(struct dns_packet, data) + DNS_PP_MAX(12, (n))) #define dns_p_sizeof(P) dns_p_calcsize((P)->end) /** takes size of maximum desired payload */ #define dns_p_new(n) (dns_p_init((struct dns_packet *)&(union { unsigned char b[dns_p_calcsize((n))]; struct dns_packet p; }){ { 0 } }, dns_p_calcsize((n)))) /** takes size of entire packet structure as allocated */ struct dns_packet *dns_p_init(struct dns_packet *, size_t); /** takes size of maximum desired payload */ struct dns_packet *dns_p_make(size_t, int *); int dns_p_grow(struct dns_packet **); struct dns_packet *dns_p_copy(struct dns_packet *, const struct dns_packet *); #define dns_p_opcode(P) (dns_header(P)->opcode) #define dns_p_rcode(P) (dns_header(P)->rcode) unsigned dns_p_count(struct dns_packet *, enum dns_section); int dns_p_push(struct dns_packet *, enum dns_section, const void *, size_t, enum dns_type, enum dns_class, unsigned, const void *); void dns_p_dictadd(struct dns_packet *, unsigned short); struct dns_packet *dns_p_merge(struct dns_packet *, enum dns_section, struct dns_packet *, enum dns_section, int *); void dns_p_dump(struct dns_packet *, FILE *); int dns_p_study(struct dns_packet *); /* * D O M A I N N A M E I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_D_MAXLABEL 63 /* + 1 '\0' */ #define DNS_D_MAXNAME 255 /* + 1 '\0' */ #define DNS_D_ANCHOR 1 /* anchor domain w/ root "." */ #define DNS_D_CLEAVE 2 /* cleave sub-domain */ #define DNS_D_TRIM 4 /* remove superfluous dots */ #define dns_d_new3(a, b, f) dns_d_init(&(char[DNS_D_MAXNAME + 1]){ 0 }, DNS_D_MAXNAME + 1, (a), (b), (f)) #define dns_d_new2(a, f) dns_d_new3((a), strlen((a)), (f)) #define dns_d_new1(a) dns_d_new3((a), strlen((a)), DNS_D_ANCHOR) #define dns_d_new(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_d_new, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) char *dns_d_init(void *, size_t, const void *, size_t, int); size_t dns_d_anchor(void *, size_t, const void *, size_t); size_t dns_d_cleave(void *, size_t, const void *, size_t); size_t dns_d_comp(void *, size_t, const void *, size_t, struct dns_packet *, int *); size_t dns_d_expand(void *, size_t, unsigned short, struct dns_packet *, int *); unsigned short dns_d_skip(unsigned short, struct dns_packet *); int dns_d_push(struct dns_packet *, const void *, size_t); size_t dns_d_cname(void *, size_t, const void *, size_t, struct dns_packet *, int *error); /* * R E S O U R C E R E C O R D I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_rr { enum dns_section section; struct { unsigned short p; unsigned short len; } dn; enum dns_type type; enum dns_class class; unsigned ttl; struct { unsigned short p; unsigned short len; } rd; }; /* struct dns_rr */ int dns_rr_copy(struct dns_packet *, struct dns_rr *, struct dns_packet *); int dns_rr_parse(struct dns_rr *, unsigned short, struct dns_packet *); unsigned short dns_rr_skip(unsigned short, struct dns_packet *); int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *, struct dns_packet *); size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *); #define dns_rr_i_new(P, ...) \ dns_rr_i_init(&dns_quietinit((struct dns_rr_i){ 0, __VA_ARGS__ }), (P)) struct dns_rr_i { enum dns_section section; const void *name; enum dns_type type; enum dns_class class; const void *data; int follow; int (*sort)(); unsigned args[2]; struct { unsigned short next; unsigned short count; unsigned exec; unsigned regs[2]; } state, saved; }; /* struct dns_rr_i */ int dns_rr_i_packet(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *); #define dns_rr_i_save(i) ((i)->saved = (i)->state) #define dns_rr_i_rewind(i) ((i)->state = (i)->saved) #define dns_rr_i_count(i) ((i)->state.count) unsigned dns_rr_grep(struct dns_rr *, unsigned, struct dns_rr_i *, struct dns_packet *, int *); #define dns_rr_foreach_(rr, P, ...) \ for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = *dns_rr_i_new((P), __VA_ARGS__); dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), &(int){ 0 }); ) #define dns_rr_foreach(...) dns_rr_foreach_(__VA_ARGS__) /* * A R E S O U R C E R E C O R D */ struct dns_a { struct in_addr addr; }; /* struct dns_a */ int dns_a_parse(struct dns_a *, struct dns_rr *, struct dns_packet *); int dns_a_push(struct dns_packet *, struct dns_a *); int dns_a_cmp(const struct dns_a *, const struct dns_a *); size_t dns_a_print(void *, size_t, struct dns_a *); /* * AAAA R E S O U R C E R E C O R D */ struct dns_aaaa { struct in6_addr addr; }; /* struct dns_aaaa */ int dns_aaaa_parse(struct dns_aaaa *, struct dns_rr *, struct dns_packet *); int dns_aaaa_push(struct dns_packet *, struct dns_aaaa *); int dns_aaaa_cmp(const struct dns_aaaa *, const struct dns_aaaa *); size_t dns_aaaa_print(void *, size_t, struct dns_aaaa *); /* * MX R E S O U R C E R E C O R D */ struct dns_mx { unsigned short preference; char host[DNS_D_MAXNAME + 1]; }; /* struct dns_mx */ int dns_mx_parse(struct dns_mx *, struct dns_rr *, struct dns_packet *); int dns_mx_push(struct dns_packet *, struct dns_mx *); int dns_mx_cmp(const struct dns_mx *, const struct dns_mx *); size_t dns_mx_print(void *, size_t, struct dns_mx *); size_t dns_mx_cname(void *, size_t, struct dns_mx *); /* * NS R E S O U R C E R E C O R D */ struct dns_ns { char host[DNS_D_MAXNAME + 1]; }; /* struct dns_ns */ int dns_ns_parse(struct dns_ns *, struct dns_rr *, struct dns_packet *); int dns_ns_push(struct dns_packet *, struct dns_ns *); int dns_ns_cmp(const struct dns_ns *, const struct dns_ns *); size_t dns_ns_print(void *, size_t, struct dns_ns *); size_t dns_ns_cname(void *, size_t, struct dns_ns *); /* * CNAME R E S O U R C E R E C O R D */ struct dns_cname { char host[DNS_D_MAXNAME + 1]; }; /* struct dns_cname */ int dns_cname_parse(struct dns_cname *, struct dns_rr *, struct dns_packet *); int dns_cname_push(struct dns_packet *, struct dns_cname *); int dns_cname_cmp(const struct dns_cname *, const struct dns_cname *); size_t dns_cname_print(void *, size_t, struct dns_cname *); size_t dns_cname_cname(void *, size_t, struct dns_cname *); /* * SOA R E S O U R C E R E C O R D */ struct dns_soa { char mname[DNS_D_MAXNAME + 1]; char rname[DNS_D_MAXNAME + 1]; unsigned serial, refresh, retry, expire, minimum; }; /* struct dns_soa */ int dns_soa_parse(struct dns_soa *, struct dns_rr *, struct dns_packet *); int dns_soa_push(struct dns_packet *, struct dns_soa *); int dns_soa_cmp(const struct dns_soa *, const struct dns_soa *); size_t dns_soa_print(void *, size_t, struct dns_soa *); /* * PTR R E S O U R C E R E C O R D */ struct dns_ptr { char host[DNS_D_MAXNAME + 1]; }; /* struct dns_ptr */ int dns_ptr_parse(struct dns_ptr *, struct dns_rr *, struct dns_packet *); int dns_ptr_push(struct dns_packet *, struct dns_ptr *); int dns_ptr_cmp(const struct dns_ptr *, const struct dns_ptr *); size_t dns_ptr_print(void *, size_t, struct dns_ptr *); size_t dns_ptr_cname(void *, size_t, struct dns_ptr *); /* * SRV R E S O U R C E R E C O R D */ struct dns_srv { unsigned short priority; unsigned short weight; unsigned short port; char target[DNS_D_MAXNAME + 1]; }; /* struct dns_srv */ int dns_srv_parse(struct dns_srv *, struct dns_rr *, struct dns_packet *); int dns_srv_push(struct dns_packet *, struct dns_srv *); int dns_srv_cmp(const struct dns_srv *, const struct dns_srv *); size_t dns_srv_print(void *, size_t, struct dns_srv *); size_t dns_srv_cname(void *, size_t, struct dns_srv *); /* * OPT R E S O U R C E R E C O R D */ #define DNS_OPT_MINDATA 512 #define DNS_OPT_BADVERS 16 struct dns_opt { size_t size, len; unsigned char rcode, version; unsigned short maxsize; unsigned char data[DNS_OPT_MINDATA]; }; /* struct dns_opt */ unsigned int dns_opt_ttl(const struct dns_opt *); unsigned short dns_opt_class(const struct dns_opt *); struct dns_opt *dns_opt_init(struct dns_opt *, size_t); int dns_opt_parse(struct dns_opt *, struct dns_rr *, struct dns_packet *); int dns_opt_push(struct dns_packet *, struct dns_opt *); int dns_opt_cmp(const struct dns_opt *, const struct dns_opt *); size_t dns_opt_print(void *, size_t, struct dns_opt *); /* * SSHFP R E S O U R C E R E C O R D */ struct dns_sshfp { enum dns_sshfp_key { DNS_SSHFP_RSA = 1, DNS_SSHFP_DSA = 2, } algo; enum dns_sshfp_digest { DNS_SSHFP_SHA1 = 1, } type; union { unsigned char sha1[20]; } digest; }; /* struct dns_sshfp */ int dns_sshfp_parse(struct dns_sshfp *, struct dns_rr *, struct dns_packet *); int dns_sshfp_push(struct dns_packet *, struct dns_sshfp *); int dns_sshfp_cmp(const struct dns_sshfp *, const struct dns_sshfp *); size_t dns_sshfp_print(void *, size_t, struct dns_sshfp *); /* * TXT R E S O U R C E R E C O R D */ #ifndef DNS_TXT_MINDATA #define DNS_TXT_MINDATA 1024 #endif struct dns_txt { size_t size, len; unsigned char data[DNS_TXT_MINDATA]; }; /* struct dns_txt */ struct dns_txt *dns_txt_init(struct dns_txt *, size_t); int dns_txt_parse(struct dns_txt *, struct dns_rr *, struct dns_packet *); int dns_txt_push(struct dns_packet *, struct dns_txt *); int dns_txt_cmp(const struct dns_txt *, const struct dns_txt *); size_t dns_txt_print(void *, size_t, struct dns_txt *); /* * ANY R E S O U R C E R E C O R D */ union dns_any { struct dns_a a; struct dns_aaaa aaaa; struct dns_mx mx; struct dns_ns ns; struct dns_cname cname; struct dns_soa soa; struct dns_ptr ptr; struct dns_srv srv; struct dns_opt opt; struct dns_sshfp sshfp; struct dns_txt txt, spf, rdata; }; /* union dns_any */ #define DNS_ANY_INIT(any) { .rdata = { .size = sizeof *(any) } } union dns_any *dns_any_init(union dns_any *, size_t); int dns_any_parse(union dns_any *, struct dns_rr *, struct dns_packet *); int dns_any_push(struct dns_packet *, union dns_any *, enum dns_type); int dns_any_cmp(const union dns_any *, enum dns_type, const union dns_any *, enum dns_type); size_t dns_any_print(void *, size_t, union dns_any *, enum dns_type); size_t dns_any_cname(void *, size_t, union dns_any *, enum dns_type); /* * H O S T S I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_hosts; struct dns_hosts *dns_hosts_open(int *); void dns_hosts_close(struct dns_hosts *); unsigned dns_hosts_acquire(struct dns_hosts *); unsigned dns_hosts_release(struct dns_hosts *); struct dns_hosts *dns_hosts_mortal(struct dns_hosts *); struct dns_hosts *dns_hosts_local(int *); int dns_hosts_loadfile(struct dns_hosts *, FILE *); int dns_hosts_loadpath(struct dns_hosts *, const char *); int dns_hosts_dump(struct dns_hosts *, FILE *); int dns_hosts_insert(struct dns_hosts *, int, const void *, const void *, DNSBool); struct dns_packet *dns_hosts_query(struct dns_hosts *, struct dns_packet *, int *); /* * R E S O L V . C O N F I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_resolv_conf { struct sockaddr_storage nameserver[3]; char search[4][DNS_D_MAXNAME + 1]; /* (f)ile, (b)ind, (c)ache */ char lookup[4 * (1 + (4 * 2))]; struct { DNSBool edns0; unsigned ndots; unsigned timeout; unsigned attempts; DNSBool rotate; DNSBool recurse; DNSBool smart; enum { DNS_RESCONF_TCP_ENABLE, DNS_RESCONF_TCP_ONLY, DNS_RESCONF_TCP_DISABLE, } tcp; } options; struct sockaddr_storage iface; struct { /* PRIVATE */ dns_atomic_t refcount; } _; }; /* struct dns_resolv_conf */ struct dns_resolv_conf *dns_resconf_open(int *); void dns_resconf_close(struct dns_resolv_conf *); unsigned dns_resconf_acquire(struct dns_resolv_conf *); unsigned dns_resconf_release(struct dns_resolv_conf *); struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *); struct dns_resolv_conf *dns_resconf_local(int *); struct dns_resolv_conf *dns_resconf_root(int *); int dns_resconf_loadfile(struct dns_resolv_conf *, FILE *); int dns_resconf_loadpath(struct dns_resolv_conf *, const char *); #ifdef USE_FIXED_NAMESERVERS int dns_resconf_load_fixed_nameservers(struct dns_resolv_conf *resconf); #endif /* USE_FIXED_NAMESERVERS */ #ifdef USE_STRUCT_RES_STATE_NAMESERVERS int dns_resconf_load_struct_res_state_nameservers(struct dns_resolv_conf *resconf); #endif /* USE_STRUCT_RES_STATE_NAMESERVERS */ #ifdef _WIN32 int dns_resconf_loadwin(struct dns_resolv_conf *); #endif #ifdef ANDROID int dns_resconf_loadandroid(struct dns_resolv_conf *resconf); #endif #ifdef HAVE_RESINIT int dns_resconf_loadfromresolv(struct dns_resolv_conf *resconf); #endif /*HAVE_RESINIT*/ int dns_nssconf_loadfile(struct dns_resolv_conf *, FILE *); int dns_nssconf_loadpath(struct dns_resolv_conf *, const char *); int dns_resconf_dump(struct dns_resolv_conf *, FILE *); int dns_nssconf_dump(struct dns_resolv_conf *, FILE *); int dns_resconf_setiface(struct dns_resolv_conf *, const char *, unsigned short); typedef unsigned long dns_resconf_i_t; size_t dns_resconf_search(void *, size_t, const void *, size_t, struct dns_resolv_conf *, dns_resconf_i_t *); /* * H I N T S E R V E R I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_hints; struct dns_hints *dns_hints_open(struct dns_resolv_conf *, int *); void dns_hints_close(struct dns_hints *); unsigned dns_hints_acquire(struct dns_hints *); unsigned dns_hints_release(struct dns_hints *); struct dns_hints *dns_hints_mortal(struct dns_hints *); int dns_hints_insert(struct dns_hints *, const char *, const struct sockaddr *, unsigned); unsigned dns_hints_insert_resconf(struct dns_hints *, const char *, const struct dns_resolv_conf *, int *); struct dns_hints *dns_hints_local(struct dns_resolv_conf *, int *); struct dns_hints *dns_hints_root(struct dns_resolv_conf *, int *); struct dns_hints_i { const char *zone; struct { unsigned next; unsigned seed; } state; }; /* struct dns_hints_i */ #define dns_hints_i_new(...) (&(struct dns_hints_i){ __VA_ARGS__ }) unsigned dns_hints_grep(struct sockaddr **, socklen_t *, unsigned, struct dns_hints_i *, struct dns_hints *); /* * C A C H E I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_cache { void *state; dns_atomic_t (*acquire)(struct dns_cache *); dns_atomic_t (*release)(struct dns_cache *); struct dns_packet *(*query)(struct dns_packet *, struct dns_cache *, int *); int (*submit)(struct dns_packet *, struct dns_cache *); int (*check)(struct dns_cache *); struct dns_packet *(*fetch)(struct dns_cache *, int *); int (*pollfd)(struct dns_cache *); short (*events)(struct dns_cache *); void (*clear)(struct dns_cache *); union { long i; void *p; } arg[3]; }; /* struct dns_cache */ struct dns_cache *dns_cache_init(struct dns_cache *); void dns_cache_close(struct dns_cache *); /* * A P P L I C A T I O N I N T E R F A C E * * Options to change the behavior of the API. Applies across all the * different components. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_OPTS_INITIALIZER_ { 0, 0 }, 0 #define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ } #define DNS_OPTS_INIT(...) { DNS_OPTS_INITIALIZER_, __VA_ARGS__ } #define dns_opts(...) (&dns_quietinit((struct dns_options)DNS_OPTS_INIT(__VA_ARGS__))) struct dns_options { /* * If the callback closes *fd, it must set it to -1. Otherwise, the * descriptor is queued and lazily closed at object destruction or * by an explicit call to _clear(). This allows safe use of * kqueue(2), epoll(2), et al -style persistent events. */ struct { void *arg; int (*cb)(int *fd, void *arg); } closefd; /* bitmask for _events() routines */ enum dns_events { DNS_SYSPOLL, DNS_LIBEVENT, } events; }; /* struct dns_options */ /* * S T A T S I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_stat { size_t queries; struct { struct { size_t count, bytes; } sent, rcvd; } udp, tcp; }; /* struct dns_stat */ /* * S O C K E T I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_socket; struct dns_socket *dns_so_open(const struct sockaddr *, int, const struct dns_options *, int *error); void dns_so_close(struct dns_socket *); void dns_so_reset(struct dns_socket *); unsigned short dns_so_mkqid(struct dns_socket *so); struct dns_packet *dns_so_query(struct dns_socket *, struct dns_packet *, struct sockaddr *, int *); int dns_so_submit(struct dns_socket *, struct dns_packet *, struct sockaddr *); int dns_so_check(struct dns_socket *); struct dns_packet *dns_so_fetch(struct dns_socket *, int *); time_t dns_so_elapsed(struct dns_socket *); void dns_so_clear(struct dns_socket *); int dns_so_events(struct dns_socket *); int dns_so_pollfd(struct dns_socket *); int dns_so_poll(struct dns_socket *, int); const struct dns_stat *dns_so_stat(struct dns_socket *); /* * R E S O L V E R I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_resolver; struct dns_resolver *dns_res_open(struct dns_resolv_conf *, struct dns_hosts *hosts, struct dns_hints *, struct dns_cache *, const struct dns_options *, int *); struct dns_resolver *dns_res_stub(const struct dns_options *, int *); void dns_res_reset(struct dns_resolver *); void dns_res_close(struct dns_resolver *); unsigned dns_res_acquire(struct dns_resolver *); unsigned dns_res_release(struct dns_resolver *); struct dns_resolver *dns_res_mortal(struct dns_resolver *); int dns_res_submit(struct dns_resolver *, const char *, enum dns_type, enum dns_class); int dns_res_check(struct dns_resolver *); struct dns_packet *dns_res_fetch(struct dns_resolver *, int *); time_t dns_res_elapsed(struct dns_resolver *); void dns_res_clear(struct dns_resolver *); int dns_res_events(struct dns_resolver *); int dns_res_pollfd(struct dns_resolver *); int dns_res_poll(struct dns_resolver *, int); struct dns_packet *dns_res_query(struct dns_resolver *, const char *, enum dns_type, enum dns_class, int, int *); const struct dns_stat *dns_res_stat(struct dns_resolver *); /* * A D D R I N F O I N T E R F A C E * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ struct dns_addrinfo; struct dns_addrinfo *dns_ai_open(const char *, const char *, enum dns_type, const struct addrinfo *, struct dns_resolver *, int *); void dns_ai_close(struct dns_addrinfo *); int dns_ai_nextent(struct addrinfo **, struct dns_addrinfo *); size_t dns_ai_print(void *, size_t, struct addrinfo *, struct dns_addrinfo *); time_t dns_ai_elapsed(struct dns_addrinfo *); void dns_ai_clear(struct dns_addrinfo *); int dns_ai_events(struct dns_addrinfo *); int dns_ai_pollfd(struct dns_addrinfo *); int dns_ai_poll(struct dns_addrinfo *, int); const struct dns_stat *dns_ai_stat(struct dns_addrinfo *); /* * U T I L I T Y I N T E R F A C E S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ size_t dns_strlcpy(char *, const char *, size_t); size_t dns_strlcat(char *, const char *, size_t); /* * M A C R O M A G I C S * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define DNS_PP_MAX(a, b) (((a) > (b))? (a) : (b)) #define DNS_PP_NARG_(a, b, c, d, e, f, g, h, i, j, k, N,...) N #define DNS_PP_NARG(...) DNS_PP_NARG_(__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define DNS_PP_CALL(F, ...) F(__VA_ARGS__) #define DNS_PP_PASTE(x, y) x##y #define DNS_PP_XPASTE(x, y) DNS_PP_PASTE(x, y) #define DNS_PP_STRINGIFY_(s) #s #define DNS_PP_STRINGIFY(s) DNS_PP_STRINGIFY_(s) #define DNS_PP_D1 0 #define DNS_PP_D2 1 #define DNS_PP_D3 2 #define DNS_PP_D4 3 #define DNS_PP_D5 4 #define DNS_PP_D6 5 #define DNS_PP_D7 6 #define DNS_PP_D8 7 #define DNS_PP_D9 8 #define DNS_PP_D10 9 #define DNS_PP_D11 10 #define DNS_PP_DEC(N) DNS_PP_XPASTE(DNS_PP_D, N) #endif /* DNS_H */ belle-sip-1.4.1/src/generic-uri.c000066400000000000000000000110071252242224000165270ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL, Grenoble, France This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "grammars/belle_sip_messageLexer.h" #include "grammars/belle_sip_messageParser.h" #include "belle-sip/generic-uri.h" #include "belle-sip/parameters.h" #include "belle_sip_internal.h" struct _belle_generic_uri { belle_sip_object_t object; char* scheme; char* user; char* user_password; char* host; int port; char* path; char* query; char* opaque_part; }; void belle_generic_uri_init(belle_generic_uri_t *uri) { uri->port=-1; } static void belle_generic_uri_destroy(belle_generic_uri_t* uri) { DESTROY_STRING(uri,scheme) DESTROY_STRING(uri,user) DESTROY_STRING(uri,user_password) DESTROY_STRING(uri,host) DESTROY_STRING(uri,path) DESTROY_STRING(uri,query) DESTROY_STRING(uri,opaque_part) } static void belle_generic_uri_clone(belle_generic_uri_t* uri, const belle_generic_uri_t *orig){ CLONE_STRING(belle_generic_uri,scheme,uri,orig) CLONE_STRING(belle_generic_uri,user,uri,orig) CLONE_STRING(belle_generic_uri,user_password,uri,orig) CLONE_STRING(belle_generic_uri,host,uri,orig) uri->port=orig->port; CLONE_STRING(belle_generic_uri,path,uri,orig) CLONE_STRING(belle_generic_uri,query,uri,orig) CLONE_STRING(belle_generic_uri,opaque_part,uri,orig) } belle_sip_error_code belle_generic_uri_marshal(const belle_generic_uri_t* uri, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=BELLE_SIP_OK; if (uri->scheme) { error=belle_sip_snprintf(buff,buff_size,offset,"%s:",uri->scheme); if (error!=BELLE_SIP_OK) return error; } if (uri->opaque_part) { error=belle_sip_snprintf(buff,buff_size,offset,"%s",uri->opaque_part); if (error!=BELLE_SIP_OK) return error; } else { if (uri->host) { error=belle_sip_snprintf(buff,buff_size,offset,"//"); if (error!=BELLE_SIP_OK) return error; } if (uri->user) { char* escaped_username=belle_sip_uri_to_escaped_username(uri->user); error=belle_sip_snprintf(buff,buff_size,offset,"%s",escaped_username); belle_sip_free(escaped_username); if (error!=BELLE_SIP_OK) return error; if (uri->user_password) { char* escaped_password=belle_sip_uri_to_escaped_userpasswd(uri->user_password); error=belle_sip_snprintf(buff,buff_size,offset,":%s",escaped_password); belle_sip_free(escaped_password); if (error!=BELLE_SIP_OK) return error; } error=belle_sip_snprintf(buff,buff_size,offset,"@"); if (error!=BELLE_SIP_OK) return error; } if (uri->host) { if (strchr(uri->host,':')) { /*ipv6*/ error=belle_sip_snprintf(buff,buff_size,offset,"[%s]",uri->host); } else { error=belle_sip_snprintf(buff,buff_size,offset,"%s",uri->host); } if (error!=BELLE_SIP_OK) return error; } if (uri->port>0) { error=belle_sip_snprintf(buff,buff_size,offset,":%i",uri->port); if (error!=BELLE_SIP_OK) return error; } if (uri->path) { char* escaped_path=belle_generic_uri_to_escaped_path(uri->path); error=belle_sip_snprintf(buff,buff_size,offset,"%s",escaped_path); belle_sip_free(escaped_path); if (error!=BELLE_SIP_OK) return error; } if (uri->query) { char* escaped_query=belle_generic_uri_to_escaped_query(uri->query); error=belle_sip_snprintf(buff,buff_size,offset,"?%s",escaped_query); belle_sip_free(escaped_query); if (error!=BELLE_SIP_OK) return error; } } return BELLE_SIP_OK; } GET_SET_STRING(belle_generic_uri,scheme); GET_SET_STRING(belle_generic_uri,user); GET_SET_STRING(belle_generic_uri,user_password); GET_SET_STRING(belle_generic_uri,host); GET_SET_STRING(belle_generic_uri,path); GET_SET_STRING(belle_generic_uri,query); GET_SET_STRING(belle_generic_uri,opaque_part); GET_SET_INT(belle_generic_uri,port,int) BELLE_NEW(belle_generic_uri,belle_sip_object) BELLE_PARSE(belle_sip_messageParser,belle_,generic_uri) char* belle_generic_uri_to_string(belle_generic_uri_t* uri) { return belle_sip_object_to_string(uri); } belle-sip-1.4.1/src/grammars/000077500000000000000000000000001252242224000157645ustar00rootroot00000000000000belle-sip-1.4.1/src/grammars/.gitignore000066400000000000000000000000211252242224000177450ustar00rootroot00000000000000*.c *.h *.tokens belle-sip-1.4.1/src/grammars/Makefile.am000077500000000000000000000021141252242224000200210ustar00rootroot00000000000000 noinst_LTLIBRARIES=libbellesip_generated.la libbellesip_generated_la_CFLAGS=$(LIBBELLESIP_CFLAGS) $(ANTLR_CFLAGS) $(STRICT_OPTIONS) $(STRICT_OPTIONS_CC) nodist_libbellesip_generated_la_SOURCES= \ belle_sip_messageParser.c belle_sip_messageParser.h \ belle_sip_messageLexer.c belle_sip_messageLexer.h \ belle_sdpParser.c belle_sdpParser.h \ belle_sdpLexer.c belle_sdpLexer.h $(builddir)/belle_sip_messageParser.c $(builddir)/belle_sip_messageParser.h \ $(builddir)/belle_sip_messageLexer.c $(builddir)/belle_sip_messageLexer.h : belle_sip_message.g $(ANTLR) -make -Xmultithreaded -Xconversiontimeout 10000 -fo $(builddir) $(srcdir)/belle_sip_message.g $(builddir)/belle_sdpLexer.c \ $(builddir)/belle_sdpParser.c \ $(builddir)/belle_sdpLexer.h \ $(builddir)/belle_sdpParser.h : $(srcdir)/belle_sdp.g $(ANTLR) -make -Xmultithreaded -Xconversiontimeout 10000 -fo $(builddir) $< AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/src EXTRA_DIST= belle_sdp.g belle_sip_message.g CLEANFILES=$(nodist_libbellesip_generated_la_SOURCES) *.tokens .NOTPARALLEL: belle-sip-1.4.1/src/grammars/belle_sdp.g000066400000000000000000000622231252242224000200720ustar00rootroot00000000000000/* belle-sdp - SDP (RFC4566) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ grammar belle_sdp; options { language = C; output=AST; } @lexer::header { /* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma GCC diagnostic ignored "-Wparentheses" #pragma GCC diagnostic ignored "-Wunused" #ifdef __clang__ #pragma GCC diagnostic ignored "-Wtautological-compare" #endif #ifndef __clang__ #pragma GCC diagnostic ignored "-Wunused-variable" #endif } @parser::header { /* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma GCC diagnostic ignored "-Wparentheses" #pragma GCC diagnostic ignored "-Wunused" #ifndef __clang__ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-function" #endif } @rulecatch { if (HASEXCEPTION()) { // This is ugly. We set the exception type to ANTLR3_RECOGNITION_EXCEPTION so we can always // catch them. //PREPORTERROR(); EXCEPTION->type = ANTLR3_RECOGNITION_EXCEPTION; } } @includes { #include "belle-sip/defs.h" #include "belle-sip/types.h" #include "belle-sip/belle-sdp.h" #include "parserutils.h" } session_description returns [belle_sdp_session_description_t* ret] scope { belle_sdp_session_description_t* current; } @init {$session_description::current = belle_sdp_session_description_new(); $ret=$session_description::current; } : version CR LF origin {belle_sdp_session_description_set_origin($session_description::current,$origin.ret);}CR LF session_name CR LF (info CR LF)? (uri_field CR LF)? (email CR LF)* phone_field* (connection {belle_sdp_session_description_set_connection($session_description::current,$connection.ret);} CR LF)? (bandwidth {belle_sdp_session_description_add_bandwidth($session_description::current,$bandwidth.ret);} CR LF)* time_field CR LF (repeat_time CR LF)* (zone_adjustments CR LF)? (key_field CR LF)? (attribute {belle_sdp_session_description_add_attribute($session_description::current,$attribute.ret);} CR LF)* (media_description {belle_sdp_session_description_add_media_description($session_description::current,$media_description.ret);}) *; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($session_description::current); $ret=NULL; } version: {IS_TOKEN(v)}?alpha_num EQUAL v=DIGIT+ {belle_sdp_version_t* version =belle_sdp_version_new(); belle_sdp_version_set_version(version,atoi((const char*)$v.text->chars)); belle_sdp_session_description_set_version($session_description::current,version);}; // ;this memo describes version 0 origin returns [belle_sdp_origin_t* ret] scope { belle_sdp_origin_t* current; } @init {$origin::current = belle_sdp_origin_new(); $ret=$origin::current; } : {IS_TOKEN(o)}?alpha_num EQUAL username {belle_sdp_origin_set_username($origin::current,(const char*)$username.text->chars);} SPACE sess_id {if ($sess_id.text->chars) belle_sdp_origin_set_session_id($origin::current,atoi((const char*)$sess_id.text->chars));} SPACE sess_version {if ($sess_version.text->chars) belle_sdp_origin_set_session_version($origin::current,atoi((const char*)$sess_version.text->chars));} SPACE nettype {belle_sdp_origin_set_network_type($origin::current,(const char*)$nettype.text->chars);} SPACE addrtype {belle_sdp_origin_set_address_type($origin::current,(const char*)$addrtype.text->chars);} SPACE addr {belle_sdp_origin_set_address($origin::current,(const char*)$addr.text->chars);} ; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($origin::current); $ret=NULL; } session_name: {IS_TOKEN(s)}? alpha_num EQUAL text {belle_sdp_session_name_t* session_name =belle_sdp_session_name_new(); belle_sdp_session_name_set_value(session_name,(const char*)$text.text->chars); belle_sdp_session_description_set_session_name($session_description::current,session_name);}; info returns [belle_sdp_info_t* ret] scope { belle_sdp_info_t* current; } @init {$info::current = belle_sdp_info_new(); $ret=$info::current; } : {IS_TOKEN(i)}? alpha_num EQUAL info_value {belle_sdp_info_set_value($info::current,(const char*) $info_value.text->chars);} ; info_value options { greedy = false; }: ~(CR|LF)*; uri_field: {IS_TOKEN(u)}?alpha_num EQUAL uri ; email returns [belle_sdp_email_t* ret] scope { belle_sdp_email_t* current; } @init {$email::current = belle_sdp_email_new(); $ret=$email::current; } : {IS_TOKEN(e)}?alpha_num EQUAL email_address {belle_sdp_email_set_value($email::current,(const char*)$email_address.text->chars);}; phone_field: {IS_TOKEN(p)}?alpha_num EQUAL phone_number CR LF; connection returns [belle_sdp_connection_t* ret] scope { belle_sdp_connection_t* current; } @init {$connection::current = belle_sdp_connection_new(); $ret=$connection::current; } : {IS_TOKEN(c)}?alpha_num EQUAL nettype { belle_sdp_connection_set_network_type($connection::current,(const char*)$nettype.text->chars);} SPACE addrtype{ belle_sdp_connection_set_address_type($connection::current,(const char*)$addrtype.text->chars);} SPACE connection_address ; //;a connection field must be present //;in every media description or at the //;session-level catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($ret); $ret=NULL; } bandwidth returns [belle_sdp_bandwidth_t* ret] scope { belle_sdp_bandwidth_t* current; } @init {$bandwidth::current = belle_sdp_bandwidth_new(); $ret=$bandwidth::current; } : {IS_TOKEN(b)}?alpha_num EQUAL bwtype {belle_sdp_bandwidth_set_type($bandwidth::current,(const char*)$bwtype.text->chars); } COLON bandwidth_value {belle_sdp_bandwidth_set_value($bandwidth::current,atoi((const char*)$bandwidth_value.text->chars));}; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($ret); $ret=NULL; } time_field: {IS_TOKEN(t)}?alpha_num EQUAL start_time SPACE stop_time {belle_sdp_time_description_t* time_description =belle_sdp_time_description_new(); belle_sdp_time_t* time_value =belle_sdp_time_new(); belle_sip_list_t* time_description_list; belle_sdp_time_set_start(time_value,atoi((const char*)$start_time.text->chars)); belle_sdp_time_set_stop(time_value,atoi((const char*)$stop_time.text->chars)); belle_sdp_time_description_set_time(time_description,time_value); time_description_list = belle_sip_list_append(NULL,time_description); belle_sdp_session_description_set_time_descriptions($session_description::current,time_description_list);}; repeat_time: {IS_TOKEN(r)}?alpha_num EQUAL repeat_interval (SPACE typed_time)+; zone_adjustments: {IS_TOKEN(z)}? alpha_num EQUAL sdp_time SPACE '-'? typed_time (SPACE sdp_time SPACE '-'? typed_time)*; key_field: {IS_TOKEN(k)}?alpha_num EQUAL key_value ; key_value options { greedy = false; }: (~(CR|LF))*; //key_type: {IS_TOKEN(prompt)}? alpha_num* /*'prompt'*/ | // {IS_TOKEN(clear)}? alpha_num* /*'clear'*/ COLON key_data | // {IS_TOKEN(base64)}? alpha_num* /*'base64*/ COLON key_data | // {IS_TOKEN(base64)}? alpha_num* /*'uri*/ COLON uri; // //key_data: email_safe; attribute returns [belle_sdp_attribute_t* ret] scope {int has_value;} @init {$ret=NULL;} : {IS_TOKEN(a)}?alpha_num EQUAL attribute_content{$ret=$attribute_content.ret;}; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); if ($ret) belle_sip_object_unref($ret); $ret=NULL; } attribute_content returns [belle_sdp_attribute_t* ret] @init {$ret=NULL; } : attribute_name (COLON val=attribute_value {$ret=belle_sdp_attribute_create((const char*)$attribute_name.text->chars,(const char*)$attribute_value.text->chars);})? { if (!val.tree) $ret=belle_sdp_attribute_create((const char*)$attribute_name.text->chars,NULL); }; rtcp_xr_attribute returns [belle_sdp_rtcp_xr_attribute_t* ret] scope { belle_sdp_rtcp_xr_attribute_t* current; } @init { $rtcp_xr_attribute::current = belle_sdp_rtcp_xr_attribute_new();$ret = $rtcp_xr_attribute::current;} : {IS_TOKEN(a)}?alpha_num EQUAL {IS_TOKEN(rtcp-xr)}? attribute_name /*'rtcp-xr'*/ (COLON rtcp_xr_attribute_value (SPACE rtcp_xr_attribute_value)*)?; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($ret); $ret=NULL; } rtcp_xr_attribute_value : (pkt_loss_rle)=> pkt_loss_rle | (pkt_dup_rle)=> pkt_dup_rle | (pkt_rcpt_times)=> pkt_rcpt_times | (rcvr_rtt)=> rcvr_rtt | (stat_summary)=> stat_summary | (voip_metrics)=> voip_metrics; pkt_loss_rle : {IS_TOKEN(pkt-loss-rle)}? rtcp_xr_attribute_name /*'pkt-loss-rle'*/ (EQUAL rtcp_xr_max_size)? ; pkt_dup_rle : {IS_TOKEN(pkt-dup-rle)}? rtcp_xr_attribute_name /*'pkt-dup-rle'*/ (EQUAL rtcp_xr_max_size)? ; pkt_rcpt_times : {IS_TOKEN(pkt-rcpt-times)}? rtcp_xr_attribute_name /*'pkt-rcpt-times'*/ (EQUAL rtcp_xr_max_size)? ; rcvr_rtt : {IS_TOKEN(rcvr-rtt)}? rtcp_xr_attribute_name /*'rcvr-rtt'*/ EQUAL {IS_TOKEN(all) || IS_TOKEN(sender)}? rtcp_xr_rcvr_rtt_mode (COLON val=rtcp_xr_max_size)? { belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_mode($rtcp_xr_attribute::current,(const char*)$rtcp_xr_rcvr_rtt_mode.text->chars); if (val.tree) belle_sdp_rtcp_xr_attribute_set_rcvr_rtt_max_size($rtcp_xr_attribute::current,atoi((const char*)$rtcp_xr_max_size.text->chars)); }; stat_summary : {IS_TOKEN(stat-summary)}? rtcp_xr_attribute_name /*'stat-summary'*/ { belle_sdp_rtcp_xr_attribute_set_stat_summary($rtcp_xr_attribute::current,1); } (EQUAL rtcp_xr_stat_summary_flag (COMMA rtcp_xr_stat_summary_flag)*)?; voip_metrics : {IS_TOKEN(voip-metrics)}? rtcp_xr_attribute_name /*'voip-metrics'*/ { belle_sdp_rtcp_xr_attribute_set_voip_metrics($rtcp_xr_attribute::current,1); }; rtcp_xr_stat_summary_flag : {IS_TOKEN(loss) || IS_TOKEN(dup) || IS_TOKEN(jitt) || IS_TOKEN(TTL) || IS_TOKEN(HL)}?rtcp_xr_stat_summary_flag_value { belle_sdp_rtcp_xr_attribute_add_stat_summary_flag($rtcp_xr_attribute::current,(const char*)$rtcp_xr_stat_summary_flag_value.text->chars); }; rtcp_xr_max_size : DIGIT+; rtcp_fb_attribute returns [belle_sdp_rtcp_fb_attribute_t* ret] scope { belle_sdp_rtcp_fb_attribute_t* current; } @init { $rtcp_fb_attribute::current = belle_sdp_rtcp_fb_attribute_new();$ret = $rtcp_fb_attribute::current;} : {IS_TOKEN(a)}?alpha_num EQUAL {IS_TOKEN(rtcp-fb)}? attribute_name /*'rtcp-fb'*/ COLON rtcp_fb_pt SPACE rtcp_fb_val; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($ret); $ret=NULL; } rtcp_fb_pt: STAR { belle_sdp_rtcp_fb_attribute_set_id($rtcp_fb_attribute::current,-1); } | integer { belle_sdp_rtcp_fb_attribute_set_id($rtcp_fb_attribute::current,atoi((const char*)$integer.text->chars)); }; rtcp_fb_val : (rtcp_fb_ack_val)=>rtcp_fb_ack_val | (rtcp_fb_nack_val)=>rtcp_fb_nack_val | (rtcp_fb_trr_int_val)=>rtcp_fb_trr_int_val | (rtcp_fb_ccm_val)=>rtcp_fb_ccm_val | (rtcp_fb_id_val)=>rtcp_fb_id_val; rtcp_fb_ack_val: {IS_TOKEN(ack)}? rtcp_fb_attribute_name /*'ack'*/ (SPACE rtcp_fb_ack_param)? { belle_sdp_rtcp_fb_attribute_set_type($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_ACK); }; rtcp_fb_nack_val: {IS_TOKEN(nack)}? rtcp_fb_attribute_name /*'nack'*/ (SPACE rtcp_fb_nack_param)? { belle_sdp_rtcp_fb_attribute_set_type($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_NACK); }; rtcp_fb_trr_int_val: {IS_TOKEN(trr-int)}? rtcp_fb_attribute_name /*'trr-int'*/ SPACE integer { belle_sdp_rtcp_fb_attribute_set_type($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_TRR_INT); belle_sdp_rtcp_fb_attribute_set_trr_int($rtcp_fb_attribute::current,(uint16_t)atoi((const char*)$integer.text->chars)); }; rtcp_fb_ccm_val: {IS_TOKEN(ccm)}? rtcp_fb_attribute_name /*'ccm'*/ (SPACE rtcp_fb_ccm_param)? { /* TODO: rtcp_fb_ccm_param should be mandatory */ belle_sdp_rtcp_fb_attribute_set_type($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_CCM); }; rtcp_fb_id_val: rtcp_fb_attribute_name (SPACE rtcp_fb_param)?; rtcp_fb_param: (rtcp_fb_app_param)=>rtcp_fb_app_param | (rtcp_fb_token_param)=>rtcp_fb_token_param; rtcp_fb_ack_param: (rtcp_fb_rpsi_param)=>rtcp_fb_rpsi_param | (rtcp_fb_app_param)=>rtcp_fb_app_param | (rtcp_fb_token_param)=>rtcp_fb_token_param; rtcp_fb_nack_param: (rtcp_fb_pli_param)=>rtcp_fb_pli_param | (rtcp_fb_sli_param)=>rtcp_fb_sli_param | (rtcp_fb_rpsi_param)=>rtcp_fb_rpsi_param | (rtcp_fb_app_param)=>rtcp_fb_app_param | (rtcp_fb_token_param)=>rtcp_fb_token_param; rtcp_fb_pli_param: {IS_TOKEN(pli)}? rtcp_fb_attribute_name /*'pli'*/ { belle_sdp_rtcp_fb_attribute_set_param($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_PLI); }; rtcp_fb_sli_param: {IS_TOKEN(sli)}? rtcp_fb_attribute_name /*'sli'*/ { belle_sdp_rtcp_fb_attribute_set_param($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_SLI); }; rtcp_fb_rpsi_param: {IS_TOKEN(rpsi)}? rtcp_fb_attribute_name /*'rpsi'*/ { belle_sdp_rtcp_fb_attribute_set_param($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_RPSI); }; rtcp_fb_app_param: {IS_TOKEN(app)}? rtcp_fb_attribute_name /*'app'*/ (SPACE byte_string) { belle_sdp_rtcp_fb_attribute_set_param($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_APP); }; rtcp_fb_ccm_param: (rtcp_fb_fir_param)=>rtcp_fb_fir_param | (rtcp_fb_tmmbr_param)=>rtcp_fb_tmmbr_param | (rtcp_fb_token_param)=>rtcp_fb_token_param; rtcp_fb_fir_param: {IS_TOKEN(fir)}? rtcp_fb_attribute_name /*'fir'*/ { belle_sdp_rtcp_fb_attribute_set_param($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_FIR); }; rtcp_fb_tmmbr_param: {IS_TOKEN(tmmbr)}? rtcp_fb_attribute_name /*'tmmbr'*/ (SPACE rtcp_fb_tmmbr_smaxpr_param)? { belle_sdp_rtcp_fb_attribute_set_param($rtcp_fb_attribute::current,BELLE_SDP_RTCP_FB_TMMBR); }; rtcp_fb_tmmbr_smaxpr_param: {IS_TOKEN(smaxpr)}? rtcp_fb_attribute_name /*'smaxpr'*/ EQUAL val=rtcp_fb_tmmbr_smaxpr { if (val.tree) belle_sdp_rtcp_fb_attribute_set_smaxpr($rtcp_fb_attribute::current,atoi((const char*)$rtcp_fb_tmmbr_smaxpr.text->chars)); }; rtcp_fb_tmmbr_smaxpr : DIGIT+; rtcp_fb_token_param: rtcp_fb_attribute_name (SPACE byte_string)?; media_description returns [belle_sdp_media_description_t* ret] scope { belle_sdp_media_description_t* current; } @init {$media_description::current = belle_sdp_media_description_new(); $ret=$media_description::current; } : media CR LF {belle_sdp_media_description_set_media($media_description::current,$media.ret);} (info {belle_sdp_media_description_set_info($media_description::current,$info.ret);} CR LF)? (connection { belle_sdp_media_description_set_connection($media_description::current,$connection.ret);} CR LF)? (bandwidth {belle_sdp_media_description_add_bandwidth($media_description::current,$bandwidth.ret);} CR LF)* (key_field CR LF)? (attribute {if ($attribute.ret)belle_sdp_media_description_add_attribute($media_description::current,$attribute.ret);} CR LF)*; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($ret); $ret=NULL; } media returns [belle_sdp_media_t* ret] scope { belle_sdp_media_t* current; } @init {$media::current = belle_sdp_media_new(); $ret=$media::current; } : {IS_TOKEN(m)}?alpha_num EQUAL media_value {belle_sdp_media_set_media_type($media::current,(const char*)$media_value.text->chars);} SPACE port {belle_sdp_media_set_media_port($media::current,atoi((const char*)$port.text->chars));} (SLASH integer{belle_sdp_media_set_port_count($media::current,atoi((const char*)$integer.text->chars));})? SPACE proto {belle_sdp_media_set_protocol($media::current,(const char*)$proto.text->chars);} (SPACE fmt)+; catch [ANTLR3_MISMATCHED_TOKEN_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($ret); $ret=NULL; } media_value: alpha_num+; // ;typically "audio", "video", "application" // ;or "data" fmt scope { int is_number; } @init { $fmt::is_number=0;}: ((DIGIT+)=>(DIGIT+){$fmt::is_number=1;} | token ) {belle_sdp_media_set_media_formats($media::current ,belle_sip_list_append(belle_sdp_media_get_media_formats($media::current) ,(void*)($fmt::is_number?(void*)(long)atoi((const char*)$fmt.text->chars):$fmt.text->chars)));}; //;typically an RTP payload type for audio //;and video media proto options { greedy = false; }: ~(SPACE|CR|LF)*; //;typically "RTP/AVP" or "udp" for IP4 port: DIGIT+; // ;should in the range "1024" to "65535" inclusive // ;for UDP based media attribute_name: token; attribute_value options { greedy = false; }: ~(CR|LF)*; rtcp_xr_attribute_name: word; rtcp_xr_rcvr_rtt_mode: word; rtcp_xr_stat_summary_flag_value: word; rtcp_fb_attribute_name: word; sess_id: DIGIT+; // ;should be unique for this originating username/host sess_version: DIGIT+; //;0 is a new session connection_address: /*multicast_address |*/addr {belle_sdp_connection_set_address($connection::current,(const char*)$addr.text->chars);} multicast_part?; multicast_address: unicast_address '/' ttl; // (decimal_uchar DOT decimal_uchar DOT decimal_uchar DOT) decimal_uchar '/' ttl ( '/' integer )?; //;multicast addresses may be in the range //;224.0.0.0 to 239.255.255.255 ttl: decimal_uchar; start_time: DIGIT+ ; stop_time: DIGIT+ ; sdp_time: DIGIT+; // ;sufficient for 2 more centuries repeat_interval: typed_time; typed_time: DIGIT* fixed_len_time_unit?; fixed_len_time_unit: {IS_TOKEN(d)}? alpha_num | {IS_TOKEN(h)}? alpha_num | {IS_TOKEN(m)}? alpha_num | {IS_TOKEN(s)}? alpha_num; bwtype: alpha_num+; bandwidth_value: DIGIT+; username: email_safe; //;pretty wide definition, but doesn't include SPACE email_address options { greedy = false; }: ~(CR|LF)* ; //| email '(' email_safe ')' | //email_safe '<' email '>'; uri: text ;//defined in RFC1630 phone_number: phone;/*(phone '(') => (phone '(') email_safe ')' | (phone) => phone | email_safe LQUOTE phone RQUOTE;*/ phone: text;//'+' DIGIT*POS_DIGIT (SPACE | '-' | DIGIT)*; //;there must be a SPACE or hyphen between the //;international code and the rest of the number. nettype: alpha_num+;//'IN'; // ;list to be extended addrtype: alpha_num+ ; //'IP4' | 'IP6'; //;list to be extended addr: unicast_address ; multicast_part: (SLASH num+=integer { if (strcmp( belle_sdp_connection_get_address_type($connection::current),"IP6")==0) belle_sdp_connection_set_range($connection::current,atoi((const char*)$integer.text->chars)); else if ($num->count ==1) belle_sdp_connection_set_ttl($connection::current,atoi((const char*)$integer.text->chars)); else if ($num->count ==2) belle_sdp_connection_set_range($connection::current,atoi((const char*)$integer.text->chars)); })+; fqdn : ( domainlabel DOT )* toplabel DOT? ; domainlabel : alpha_num | (alpha_num ( alpha_num | DASH )* alpha_num) ; toplabel : alpha | (alpha ( alpha_num | DASH )* alpha_num) ; unicast_address : (alpha_num | DOT | COLON| DASH)*; /*might be better defined*/ /* ipv4_address |ipv6_address |fqdn*/ ipv4_address : decimal_uchar DOT decimal_uchar DOT decimal_uchar DOT decimal_uchar ; ipv6_address : (hexpart)=>hexpart ( COLON ipv4_address )? ; hexpart : hexseq | hexseq COLON COLON hexseq? | COLON COLON hexseq? ; hexseq : hex4 ( COLON hex4)* ; hex4 : hexdigit+; /* hexdigit hexdigit hexdigit ;*/ text : ~(CR|LF)* ; //default is to interpret this as IS0-10646 UTF8 //ISO 8859-1 requires a "a=charset:ISO-8859-1" //session-level attribute to be used byte_string options { greedy = false; }: (OCTET)* ; //any byte except NUL, CR or LF decimal_uchar: integer;// (d+=DIGIT+ {$d !=NULL && $d->count<=3}?) integer: DIGIT+; email_safe : ~(SPACE)*; token : (alpha_num | '!' | '#' | '$' |'&'| '%'| '\'' | '*' |'+' | DASH | DOT)+; alpha_num: (alpha | DIGIT) ; hexdigit: (HEX_CHAR | DIGIT) ; word: (alpha | DASH)+; alpha: COMMON_CHAR | HEX_CHAR; DIGIT: ZERO | POS_DIGIT; fragment ZERO: '0'; fragment POS_DIGIT : '1'..'9'; //ALPHA: 'a'..'z'|'A'..'Z'; COMMON_CHAR : 'g'..'z' | 'G'..'Z' ; HEX_CHAR: 'a'..'f' |'A'..'F'; SPACE: ' '; //CRLF : CR LF { USER1 = (int)(ctx->pLexer->input->currentLine - ctx->pLexer->input->data);}; LQUOTE: '<'; RQUOTE: '>'; CR:'\r'; LF:'\n'; DOT: '.'; EQUAL: '='; COLON: ':'; SLASH: '/'; DASH: '-'; COMMA: ','; STAR: '*'; OCTET : .; belle-sip-1.4.1/src/grammars/belle_sip_message.g000066400000000000000000002105421252242224000216020ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ grammar belle_sip_message; options { language = C; } @parser::header { /* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma GCC diagnostic ignored "-Wparentheses" #pragma GCC diagnostic ignored "-Wunused" #ifndef __clang__ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wunused-function" #endif } @lexer::header { /* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma GCC diagnostic ignored "-Wparentheses" #pragma GCC diagnostic ignored "-Wunused" } @includes { #include "belle-sip/defs.h" #include "belle-sip/types.h" #include "belle-sip/message.h" #include "belle-sip/http-message.h" #include "parserutils.h" BELLESIP_INTERNAL_EXPORT void belle_sip_header_address_set_quoted_displayname(belle_sip_header_address_t* address,const char* value); } @rulecatch { if (HASEXCEPTION()) { // This is ugly. We set the exception type to ANTLR3_RECOGNITION_EXCEPTION so we can always // catch them. //PREPORTERROR(); EXCEPTION->type = ANTLR3_RECOGNITION_EXCEPTION; } } message returns [belle_sip_message_t* ret] scope { size_t message_length; } @init {$ret=NULL;} : message_raw[&($message::message_length)] {$ret=$message_raw.ret;}; message_raw [size_t* length] returns [belle_sip_message_t* ret] scope { size_t* message_length; } @init {$message_raw::message_length=length;$ret=NULL;} : common_request {$ret = $common_request.ret;} | common_response {$ret = $common_response.ret;} ; request returns [belle_sip_request_t* ret=NULL] :common_request {$ret=BELLE_SIP_REQUEST($common_request.ret);}; common_request returns [belle_sip_message_t* ret] scope { belle_sip_message_t* current; } @init {$ret=$common_request::current=NULL; } : ( ( ~(CRLF)* sip_version CRLF) => request_line {$ret=$common_request::current=BELLE_SIP_MESSAGE($request_line.ret);} | ( ~(CRLF)* http_version CRLF) => http_request_line{$ret=$common_request::current=BELLE_SIP_MESSAGE($http_request_line.ret);}) message_header[BELLE_SIP_MESSAGE($common_request::current)]+ last_crlf=CRLF {*($message_raw::message_length)=$last_crlf->user1;} /*message_body ?*/ ; request_line returns [belle_sip_request_t* ret=NULL] scope { belle_sip_request_t* current; } @init {$request_line::current = belle_sip_request_new(); $ret=$request_line::current; } : method {belle_sip_request_set_method($request_line::current,(const char*)($method.text->chars));} SP ( uri {belle_sip_request_set_uri($request_line::current,$uri.ret);} | generic_uri {belle_sip_request_set_absolute_uri($request_line::current,$generic_uri.ret);} ) SP sip_version CRLF ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($request_line::current); $ret=NULL; } sip_version : {IS_TOKEN(SIP/)}? generic_version; // 'SIP/' DIGIT '.' DIGIT; generic_version: alpha+ SLASH DIGIT DOT DIGIT; message_header [belle_sip_message_t* message] : (/*accept // | accept_encoding // | accept_language // | alert_info // | allow // | authentication_info // | authorization // | header_call_id {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_call_id.ret));}/* // | call_info // | header_contact {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_contact.ret));} // | content_disposition // | content_encoding // | content_language*/ // | header_content_length {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_content_length.ret));} // | header_content_type {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_content_type.ret));} // | header_cseq {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_cseq.ret));}/* // | date // | error_info // | expires*/ // | header_from {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_from.ret));}/* // | in_reply_to // | max_forwards // | mime_version // | min_expires // | organization // | priority // | proxy_authenticate // | proxy_authorization // | proxy_require*/ // | header_record_route {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_record_route.ret));}/* // | reply_to // | require // | retry_after*/ // | header_route {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_route.ret));}/* // | server // | subject // | supported // | timestamp*/ // | header_to {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_to.ret));}/* // | unsupported // | user_agent*/ // | header_via {belle_sip_message_add_header(message,BELLE_SIP_HEADER($header_via.ret));}/* // | warning // | www_authenticate*/ header_extension_base[(BELLE_SIP_OBJECT_IS_INSTANCE_OF($message,belle_http_request_t) ||BELLE_SIP_OBJECT_IS_INSTANCE_OF($message,belle_http_response_t)) ] { belle_sip_header_t* lheader = BELLE_SIP_HEADER($header_extension_base.ret); do { if (lheader == NULL) break; /*sanity check*/ belle_sip_message_add_header(message,lheader); } while((lheader=belle_sip_header_get_next(lheader)) != NULL); } ) CRLF ; /* invitem : 'INVITE' ; //INVITE in caps ackm : 'ACK'; //ACK in caps optionsm: 'OPTION'; //OPTIONS in caps byem : 'BYE' ; //BYE in caps cancelm : 'CANCEL' ; //CANCEL in caps registerm : 'REGISTER' ; //REGISTER in caps optionm : 'OPTION'; */ method : /* invitem | ackm | optionm | byem | cancelm | registerm |*/extension_method ; extension_method : token; common_response returns [belle_sip_message_t* ret=NULL] : ( (sip_version ~(CRLF)* CRLF) => status_line {$ret=BELLE_SIP_MESSAGE($status_line.ret);} | (http_version ~(CRLF)* CRLF) => http_status_line{$ret=BELLE_SIP_MESSAGE($http_status_line.ret);}) (message_header[BELLE_SIP_MESSAGE($ret)]+ last_crlf=CRLF {*($message_raw::message_length)=$last_crlf->user1;} /*message_body*/)? ; response returns [belle_sip_response_t* ret=NULL] : common_response {$ret=BELLE_SIP_RESPONSE($common_response.ret);} ; status_line returns [belle_sip_response_t* ret=NULL] scope { belle_sip_response_t* current; } @init {$ret = belle_sip_response_new(); } : sip_version SP status_code {belle_sip_response_set_status_code($ret,atoi((char*)$status_code.text->chars));} SP reason_phrase {belle_sip_response_set_reason_phrase($ret,(char*)$reason_phrase.text->chars);} CRLF ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref( $ret); $ret=NULL; } status_code : extension_code; extension_code : DIGIT DIGIT DIGIT; reason_phrase : ~(CRLF)*; //****************http**********************/ /*Request-Line = Method SP Request-URI SP HTTP-Version CRLF*/ http_request returns [belle_http_request_t* ret=NULL] :common_request {$ret=BELLE_HTTP_REQUEST($common_request.ret);}; http_request_line returns [belle_http_request_t *ret=NULL] scope { belle_http_request_t* current; } @init {$http_request_line::current = belle_http_request_new(); $ret=$http_request_line::current; } : method {belle_http_request_set_method($http_request_line::current,(const char*)($method.text->chars));} SP (generic_uri)=>generic_uri {belle_http_request_set_uri($http_request_line::current,$generic_uri.ret);} SP http_version CRLF; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($http_request_line::current); $ret=NULL; } http_version: {IS_TOKEN(HTTP/)}? generic_version; http_response returns [belle_http_response_t* ret=NULL] : common_response {$ret=BELLE_HTTP_RESPONSE($common_response.ret);} ; http_status_line returns [belle_http_response_t* ret] @init {$ret = belle_http_response_new(); } : http_version SP status_code {belle_http_response_set_status_code($ret,atoi((char*)$status_code.text->chars));} SP reason_phrase {belle_http_response_set_reason_phrase($ret,(char*)$reason_phrase.text->chars);} CRLF ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref( $ret); $ret=NULL; } /* absoluteURI = scheme ":" ( hier_part | opaque_part ) hier_part = ( net_path | abs_path ) [ "?" query ] net_path = "//" authority [ abs_path ] abs_path = "/" path_segments */ /*comma, semicolon, or question mark*/ opaque_part_for_from_to_contact_addr_spec : uric_no_slash_for_from_to_contact_addr_spec uric_for_from_to_contact_addr_spec*; opaque_part : uric_no_slash uric*; uric_no_slash_for_from_to_contact_addr_spec : unreserved | escaped | COLON | AT| AND | EQUAL | PLUS | DOLLARD; uric_no_slash :COMMA | SEMI | QMARK | uric_no_slash_for_from_to_contact_addr_spec ; scheme: alpha ( alphanum | PLUS | DASH | DOT )*; /*remove hiearachy part because complex to handle the :comma, semicolon, or question markexception see rfc3261 section 20.10 Contact*/ generic_uri_for_from_to_contact_addr_spec returns [belle_generic_uri_t* ret=NULL] scope { belle_generic_uri_t* current; } @init { $generic_uri_for_from_to_contact_addr_spec::current = $ret = belle_generic_uri_new(); } : scheme {belle_generic_uri_set_scheme($generic_uri_for_from_to_contact_addr_spec::current,(const char*)$scheme.text->chars);} COLON opaque_part_for_from_to_contact_addr_spec {belle_generic_uri_set_opaque_part($generic_uri_for_from_to_contact_addr_spec::current,(const char*)$opaque_part_for_from_to_contact_addr_spec.text->chars) ;} ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($generic_uri::current); $ret=NULL; } generic_uri returns [belle_generic_uri_t* ret=NULL] scope { belle_generic_uri_t* current; } @init { $generic_uri::current = $ret = belle_generic_uri_new(); } : hier_part[$generic_uri::current] | (scheme {belle_generic_uri_set_scheme($generic_uri::current,(const char*)$scheme.text->chars);} COLON (opaque_part {belle_generic_uri_set_opaque_part($generic_uri::current,(const char*)$opaque_part.text->chars) ;} | hier_part[$generic_uri::current]) ) ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($generic_uri::current); $ret=NULL; } hier_part[belle_generic_uri_t* uri] returns [belle_generic_uri_t* ret=NULL] : ( (SLASH SLASH path_segments[NULL])=>( SLASH SLASH path_segments[uri]) | (SLASH SLASH authority[NULL] (path_segments[NULL])?)=>( SLASH SLASH authority[uri] (path_segments[uri])?) | ( path_segments[uri]) ) (QMARK query { char* unescaped_query; unescaped_query=belle_sip_to_unescaped_string((const char *)$query.text->chars); belle_generic_uri_set_query(uri,(const char*)unescaped_query); belle_sip_free(unescaped_query); }) ?; path_segments[belle_generic_uri_t* uri] : SLASH (segment ( SLASH segment )*) { char* unescaped_path; unescaped_path=belle_sip_to_unescaped_string((const char *)$path_segments.text->chars); belle_generic_uri_set_path(uri,(const char*)unescaped_path); belle_sip_free(unescaped_path); }; segment: pchar* ( SEMI param )*; param: pchar*; pchar: unreserved | escaped | COLON | AT | AND | EQUAL | PLUS | DOLLARD | COMMA; query: uric+; uric: reserved | unreserved | escaped; uric_for_from_to_contact_addr_spec: reserved_for_from_to_contact_addr_spec | unreserved | escaped; authority[belle_generic_uri_t* uri] : ((authority_userinfo[NULL]) =>authority_userinfo[uri] )? authority_hostport[uri] /*| authority_hostport[uri]*/ ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); } authority_userinfo[belle_generic_uri_t* uri] scope { belle_generic_uri_t* current; } @init {$authority_userinfo::current=uri;} : authority_user ( COLON authority_password )? AT ; authority_user : ( unreserved | escaped | user_unreserved )+ { char* unescaped_username; unescaped_username=belle_sip_to_unescaped_string((const char *)$text->chars); belle_generic_uri_set_user($authority_userinfo::current,unescaped_username); belle_sip_free(unescaped_username); }; authority_password : ( unreserved | escaped | AND | EQUAL | PLUS | DOLLARD | COMMA )* { char* unescaped_userpasswd; unescaped_userpasswd=belle_sip_to_unescaped_string((const char *)$text->chars); belle_generic_uri_set_user_password($authority_userinfo::current,unescaped_userpasswd); belle_sip_free(unescaped_userpasswd); }; authority_hostport[belle_generic_uri_t* uri] scope { belle_generic_uri_t* current; } @init {$authority_hostport::current=uri;} : host ( COLON port {belle_generic_uri_set_port($authority_hostport::current,$port.ret);})? {belle_generic_uri_set_host($authority_hostport::current,$host.ret);}; //****************http end**********************/ //****************SIP**********************/ generic_param [belle_sip_parameters_t* object] returns [belle_sip_param_pair_t* ret=NULL] scope{int is_value; char* gen_value_string;} @init { $generic_param::is_value=0; $generic_param::gen_value_string=NULL;} : token ( equal gen_value {$generic_param::gen_value_string=(char*)($gen_value.text->chars);} )? { if (object == NULL) { $ret=belle_sip_param_pair_new((const char*)($token.text->chars) ,$generic_param::gen_value_string); } else { belle_sip_parameters_set_parameter(object ,(const char*)($token.text->chars) ,$generic_param::gen_value_string); $ret=NULL; } }; gen_value : token | quoted_string; quoted_string options { greedy = false; } : DQUOTE (~(DQUOTE | BSLASH) | (BSLASH .))* DQUOTE ; /* accept_encoding : 'Accept-Encoding' HCOLON ( encoding (COMMA encoding)* ); encoding : codings (SEMI accept_param)*; codings : content_coding | '*'; content_coding : token; accept_language : 'Accept-Language' HCOLON ( language (COMMA language)* )?; language : language_range (SEMI accept_param)*; language_range : ( ( alpha alpha alpha alpha alpha alpha alpha alpha ( '-' alpha alpha alpha alpha alpha alpha alpha alpha )* ) | '*' ); alert_info : 'Alert-Info' HCOLON alert_param (COMMA alert_param)*; alert_param : LAQUOT absoluteURI RAQUOT ( SEMI generic_param )*; absoluteURI : token ':' token; */ header_allow returns [belle_sip_header_allow_t* ret] scope { belle_sip_header_allow_t* current; } @init {$header_allow::current = belle_sip_header_allow_new(); $ret=$header_allow::current; } : {IS_TOKEN(Allow)}? token /*'Allow'*/ hcolon methods {belle_sip_header_allow_set_method($header_allow::current,(const char*)($methods.text->chars));} ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_allow::current); $ret=NULL; } methods : /*LWS?*/ method (comma method)*; authorization_token: {IS_TOKEN(Authorization)}? token; digest_token: {IS_TOKEN(Digest)}? token; header_authorization returns [belle_sip_header_authorization_t* ret] scope { belle_sip_header_authorization_t* current; } @init {$header_authorization::current = belle_sip_header_authorization_new(); $ret=$header_authorization::current; } : authorization_token /*'Authorization'*/ hcolon credentials[$header_authorization::current]; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_authorization::current); $ret=NULL; } credentials [belle_sip_header_authorization_t* header_authorization_base] : (digest_token /*'Digest'*/ {belle_sip_header_authorization_set_scheme(header_authorization_base,"Digest");} lws digest_response[header_authorization_base]) | other_response[header_authorization_base]; digest_response [belle_sip_header_authorization_t* header_authorization_base] : dig_resp[header_authorization_base] (comma dig_resp[header_authorization_base])*; dig_resp [belle_sip_header_authorization_t* header_authorization_base] : username { belle_sip_header_authorization_set_username(header_authorization_base,$username.ret); belle_sip_free($username.ret); } | realm { belle_sip_header_authorization_set_realm(header_authorization_base,(char*)$realm.ret); belle_sip_free($realm.ret); } | nonce { belle_sip_header_authorization_set_nonce(header_authorization_base,(char*)$nonce.ret); belle_sip_free($nonce.ret); } | digest_uri[header_authorization_base] | dresponse { belle_sip_header_authorization_set_response(header_authorization_base,(char*)$dresponse.ret); belle_sip_free($dresponse.ret); } | algorithm { belle_sip_header_authorization_set_algorithm(header_authorization_base,(char*)$algorithm.ret); } | cnonce{ belle_sip_header_authorization_set_cnonce(header_authorization_base,(char*)$cnonce.ret); belle_sip_free($cnonce.ret); } | opaque { belle_sip_header_authorization_set_opaque(header_authorization_base,(char*)$opaque.ret); belle_sip_free($opaque.ret); } | message_qop{ belle_sip_header_authorization_set_qop(header_authorization_base,$message_qop.ret); } | nonce_count{ belle_sip_header_authorization_set_nonce_count(header_authorization_base,atoi((char*)$nonce_count.ret)); } | auth_param[header_authorization_base] ; username_token: {IS_TOKEN(username)}? token; username returns [char* ret=NULL] : username_token /*'username'*/ equal username_value { $ret = _belle_sip_str_dup_and_unquote_string((char*)$username_value.text->chars); }; username_value : quoted_string; uri_token: {IS_TOKEN(uri)}? token; digest_uri [belle_sip_header_authorization_t* header_authorization_base] : uri_token /*'uri'*/ equal DQUOTE uri DQUOTE {belle_sip_header_authorization_set_uri(header_authorization_base,$uri.ret); }; /* digest_uri_value : rquest_uri ; rquest_uri : uri; */ // Equal to request-uri as specified by HTTP/1.1 message_qop returns [const char* ret=NULL] : {IS_TOKEN(qop)}? token/*'qop'*/ equal qop_value {$ret = (const char*)$qop_value.text->chars;}; qop_value : token; cnonce returns [char* ret=NULL] : {IS_TOKEN(cnonce)}? token /*'cnonce'*/ equal cnonce_value { $ret = _belle_sip_str_dup_and_unquote_string((char*)$cnonce_value.text->chars); }; cnonce_value : nonce_value; nonce_count returns [const char* ret=NULL] : {IS_TOKEN(nc)}? token /*'nc'*/ equal nc_value {$ret=(char*)$nc_value.text->chars;}; nc_value : huit_lhex; dresponse returns [char* ret=NULL] : {IS_TOKEN(response)}? token /*'response'*/ equal request_digest{ $ret = _belle_sip_str_dup_and_unquote_string((char*)$request_digest.text->chars); }; request_digest : quoted_string ;/*sp_laquot_sp huit_lhex huit_lhex huit_lhex huit_lhex sp_raquot_sp; */ huit_lhex : hexdigit+; auth_param [belle_sip_header_authorization_t* header_authorization_base] : auth_param_name equal auth_param_value {belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(header_authorization_base) ,(char*)$auth_param_name.text->chars ,(char*)$auth_param_value.text->chars); } ; auth_param_value : token | quoted_string ; auth_param_name : token; other_response [belle_sip_header_authorization_t* header_authorization_base] : auth_scheme {belle_sip_header_authorization_set_scheme(header_authorization_base,(const char*)$auth_scheme.text->chars);} lws auth_param[header_authorization_base] (comma auth_param[header_authorization_base])*; auth_scheme : token; /* authentication_info : 'Authentication-Info' HCOLON ainfo (COMMA ainfo)*; ainfo : nextnonce | message_qop | response_auth | cnonce | nonce_count; nextnonce : 'nextnonce' EQUAL nonce_value; */ nonce_value : quoted_string; /* response_auth : 'rspauth' EQUAL response_digest; response_digest : LDQUOT hexdigit* RDQUOT; */ /*callid header*/ call_id_token: {IS_HEADER_NAMED(Call-ID,i)}? token; header_call_id returns [belle_sip_header_call_id_t* ret=NULL] scope { belle_sip_header_call_id_t* current; } @init {$header_call_id::current = belle_sip_header_call_id_new(); $ret=$header_call_id::current; } : call_id_token /*( 'Call-ID' | 'i' )*/ hcolon call_id{belle_sip_header_call_id_set_call_id($header_call_id::current,(const char*) $call_id.text->chars); }; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_call_id::current); $ret=NULL; } call_id : word ( AT word )? ; /* call_info : 'Call-Info' HCOLON info (COMMA info)*; info : LAQUOT absoluteURI RAQUOT ( SEMI info_param)*; info_param : ( 'purpose' EQUAL ( 'icon' | 'info' | 'card' | token ) ) | generic_param; */ /* contact header */ contact_token: {IS_HEADER_NAMED(Contact,m)}? token; header_contact returns [belle_sip_header_contact_t* ret] scope { belle_sip_header_contact_t* current; belle_sip_header_contact_t* first; } @init { $header_contact::current =NULL; $ret=NULL; } : (contact_token /*'Contact'*/ /*| 'm'*/ ) sp_tab_colon ( (lws? STAR) { $header_contact::current = belle_sip_header_contact_new(); belle_sip_header_contact_set_wildcard($header_contact::current,1);} | (contact_param ( COMMA contact_param)*)) {$ret = $header_contact::first; }; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); if ($ret) belle_sip_object_unref($ret); $ret=NULL; } contact_param scope { belle_sip_header_contact_t* prev;} @init { if ($header_contact::current == NULL) { $header_contact::current = belle_sip_header_contact_new(); $header_contact::first = $header_contact::current; $contact_param::prev=NULL; } else { $contact_param::prev=$header_contact::current; belle_sip_header_set_next(BELLE_SIP_HEADER($header_contact::current),(belle_sip_header_t*)belle_sip_header_contact_new()); $header_contact::current = (belle_sip_header_contact_t*)belle_sip_header_get_next(BELLE_SIP_HEADER($header_contact::current)); } } : ( name_addr[BELLE_SIP_HEADER_ADDRESS($header_contact::current)] | paramless_addr_spec[BELLE_SIP_HEADER_ADDRESS($header_contact::current)]) (SEMI lws? contact_params lws?)*; header_address returns [belle_sip_header_address_t* ret] @init { $ret=NULL; } : header_address_base[belle_sip_header_address_new()] {$ret=$header_address_base.ret;}; header_address_base[belle_sip_header_address_t* obj] returns [belle_sip_header_address_t* ret] @init { $ret=obj; } : name_addr_with_generic_uri[BELLE_SIP_HEADER_ADDRESS($ret)] | addr_spec_with_generic_uri[BELLE_SIP_HEADER_ADDRESS($ret)]; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_object_unref($ret); $ret=NULL; } name_addr[belle_sip_header_address_t* object] : (lws? display_name[object])? sp_laquot addr_spec[object] raquot_sp; name_addr_with_generic_uri[belle_sip_header_address_t* object] : (lws? display_name[object])? sp_laquot addr_spec_with_generic_uri[object] raquot_sp; addr_spec[belle_sip_header_address_t* object] : lws? uri {belle_sip_header_address_set_uri(object,$uri.ret);} lws?;//| absoluteURI; addr_spec_with_generic_uri[belle_sip_header_address_t* object] : lws? ( uri {belle_sip_header_address_set_uri(object,$uri.ret);} | generic_uri{belle_sip_header_address_set_absolute_uri(object,$generic_uri.ret);} ) lws?; paramless_addr_spec[belle_sip_header_address_t* object] : lws? paramless_uri {belle_sip_header_address_set_uri(object,$paramless_uri.ret);} lws? ;//| absoluteURI; paramless_addr_spec_with_generic_uri[belle_sip_header_address_t* object] : lws? ( paramless_uri {belle_sip_header_address_set_uri(object,$paramless_uri.ret);} | generic_uri_for_from_to_contact_addr_spec{belle_sip_header_address_set_absolute_uri(object,$generic_uri_for_from_to_contact_addr_spec.ret);} ) lws? ; display_name_tokens :token (lws token)* ; display_name[belle_sip_header_address_t* object] : display_name_tokens {belle_sip_header_address_set_displayname(object,(const char*)($display_name_tokens.text->chars));} | quoted_string { char* unescaped_char = belle_sip_string_to_backslash_less_unescaped_string((const char*)($quoted_string.text->chars)); belle_sip_header_address_set_quoted_displayname(object,(const char*)unescaped_char); belle_sip_free(unescaped_char); } ; contact_params : /*c_p_q | c_p_expires |*/ contact_extension; /*c_p_q : 'q' EQUAL qvalue; c_p_expires : 'expires' EQUAL delta_seconds;*/ contact_extension : generic_param [BELLE_SIP_PARAMETERS($header_contact::current)]; delta_seconds : DIGIT+; /* content_disposition : 'Content-Disposition' HCOLON disp_type ( SEMI disp_param )*; disp_type : 'render' | 'session' | 'icon' | 'alert' | disp_extension_token; disp_param : handling_param | generic_param; handling_param : 'handling' EQUAL ( 'optional' | 'required' | other_handling ); other_handling : token; disp_extension_token : token; content_encoding : ( 'Content-Encoding' | 'e' ) HCOLON content_coding (COMMA content_coding)*; content_language : 'Content-Language' HCOLON language_tag (COMMA language_tag)*; language_tag : primary_tag ( '-' subtag )*; primary_tag : huit_alpha; subtag : huit_alpha; huit_alpha : alpha+; ; */ /*content_length_token : {strcmp("Content-Length",(const char*)(INPUT->toStringTT(INPUT,LT(1),LT(14)))->chars) == 0}? token;*/ content_length_token : {IS_HEADER_NAMED(Content-Length,l)}? token; header_content_length returns [belle_sip_header_content_length_t* ret] scope { belle_sip_header_content_length_t* current; } @init {$header_content_length::current = belle_sip_header_content_length_new(); $ret=$header_content_length::current; } : content_length_token /*( 'Content-Length' | 'l' )*/ hcolon content_length {belle_sip_header_content_length_set_content_length($header_content_length::current,atoi((const char*)$content_length.text->chars));}; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_content_length::current); $ret=NULL; } content_length:DIGIT+; content_type_token : {IS_HEADER_NAMED(Content-Type,c)}? token; header_content_type returns [belle_sip_header_content_type_t* ret=NULL] scope { belle_sip_header_content_type_t* current;} @init { $header_content_type::current = belle_sip_header_content_type_new();$ret=$header_content_type::current; } : content_type_token/* ( 'Content-Type' | 'c' )*/ hcolon media_type; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_content_type::current); $ret=NULL; } media_type : m_type {belle_sip_header_content_type_set_type($header_content_type::current,(const char*)$m_type.text->chars);} slash m_subtype {belle_sip_header_content_type_set_subtype($header_content_type::current,(const char*)$m_subtype.text->chars);} (semi generic_param [BELLE_SIP_PARAMETERS($header_content_type::current)])*; m_type : token; /* discrete_type | composite_type; discrete_type : 'text' | 'image' | 'audio' | 'video' | 'application' | extension_token; composite_type : 'message' | 'multipart' | extension_token; extension_token : ietf_token | x_token; ietf_token : token; x_token : 'x-' token;*/ m_subtype : token ;/* extension_token | iana_token; iana_token : token; m_parameter : m_attribute EQUAL m_value; m_attribute : token; m_value : token | quoted_string; */ cseq_token : {IS_TOKEN(CSeq)}? token; header_cseq returns [belle_sip_header_cseq_t* ret] scope { belle_sip_header_cseq_t* current; } @init { $header_cseq::current = belle_sip_header_cseq_new();$ret = $header_cseq::current; } : cseq_token hcolon seq_number {belle_sip_header_cseq_set_seq_number($header_cseq::current,atoi((const char*)$seq_number.text->chars));} lws method {belle_sip_header_cseq_set_method($header_cseq::current,(const char*)$method.text->chars);} ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_cseq::current); $ret=NULL; } seq_number:DIGIT+; /*Date header*/ date_token: {IS_TOKEN(Date)}? token; header_date returns [belle_sip_header_date_t* ret] scope { belle_sip_header_date_t* current; } @init {$header_date::current = belle_sip_header_date_new(); $ret=$header_date::current; } : date_token /*( 'Date' )*/ hcolon sip_date{belle_sip_header_date_set_date($header_date::current,(const char*) $sip_date.text->chars); }; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_date::current); $ret=NULL; } date : sip_date; sip_date : /*wkday*/alpha alpha alpha COMMA SP /*date1*/DIGIT DIGIT SP alpha alpha alpha SP DIGIT DIGIT DIGIT DIGIT SP /*time*/DIGIT DIGIT COLON DIGIT DIGIT COLON DIGIT DIGIT SP /*GMTT*/alpha alpha alpha; /* // rfc1123-date //rfc1123-date = wkday "," SP date1 SP time SP "GMT" //date1 = 2DIGIT SP month SP 4DIGIT // ; day month year (e.g., 02 Jun 1982) //time = 2DIGIT ":" 2DIGIT ":" 2DIGIT // ; 00:00:00 - 23:59:59 //wkday = "Mon" / "Tue" / "Wed" // / "Thu" / "Fri" / "Sat" / "Sun" //month = "Jan" / "Feb" / "Mar" / "Apr" // / "May" / "Jun" / "Jul" / "Aug" // / "Sep" / "Oct" / "Nov" / "Dec" error_info : 'Error-Info' HCOLON error_uri (COMMA error_uri)*; error_uri : LAQUOT absoluteURI RAQUOT ( SEMI generic_param )*; */ header_expires returns [belle_sip_header_expires_t* ret] scope { belle_sip_header_expires_t* current; } @init { $header_expires::current = belle_sip_header_expires_new();$ret = $header_expires::current; } : {IS_TOKEN(Expires)}? token /*'Expires'*/ hcolon delta_seconds {belle_sip_header_expires_set_expires($header_expires::current,atoi((const char *)$delta_seconds.text->chars));}; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_expires::current); $ret=NULL; } from_token: {IS_HEADER_NAMED(From,f)}? token; header_from returns [belle_sip_header_from_t* ret] scope { belle_sip_header_from_t* current; } @init { $header_from::current = belle_sip_header_from_new();$ret = $header_from::current; } : from_token/* ( 'From' | 'f' )*/ sp_tab_colon from_spec ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_from::current); $ret=NULL; } from_spec : ( name_addr_with_generic_uri[BELLE_SIP_HEADER_ADDRESS($header_from::current)] | paramless_addr_spec_with_generic_uri[BELLE_SIP_HEADER_ADDRESS($header_from::current)] ) ( SEMI lws? from_param lws?)*; from_param : /*tag_param |*/ generic_param [BELLE_SIP_PARAMETERS($header_from::current)]; /* tag_param : 'tag' EQUAL token; */ /* in_reply_to : 'In-Reply-To' HCOLON callid (COMMA callid); */ header_max_forwards returns [belle_sip_header_max_forwards_t* ret] scope { belle_sip_header_max_forwards_t* current; } @init { $header_max_forwards::current = belle_sip_header_max_forwards_new();$ret = $header_max_forwards::current; } : {IS_TOKEN(Max-Forwards)}? token /*'Max-Forwards'*/ hcolon max_forwards {belle_sip_header_max_forwards_set_max_forwards($header_max_forwards::current,atoi((const char*)$max_forwards.text->chars));}; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_max_forwards::current); $ret=NULL; } max_forwards:DIGIT+; /* mime_version : 'MIME-Version' HCOLON DIGIT+ '.' DIGIT+; min_expires : 'Min-Expires' HCOLON delta_seconds; organization : 'Organization' HCOLON (text_utf8_trim)?; text_utf8_trim : ; priority : 'Priority' HCOLON priority_value; priority_value : 'emergency' | 'urgent' | 'normal' | 'non-urgent' | other_priority; other_priority : token; */ header_proxy_authenticate returns [belle_sip_header_proxy_authenticate_t* ret] scope { belle_sip_header_proxy_authenticate_t* current; } @init { $header_proxy_authenticate::current = belle_sip_header_proxy_authenticate_new();$ret = $header_proxy_authenticate::current; } : {IS_TOKEN(Proxy-Authenticate)}? token /*'Proxy-Authenticate'*/ hcolon challenge[BELLE_SIP_HEADER_WWW_AUTHENTICATE($header_proxy_authenticate::current)]; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_proxy_authenticate::current); $ret=NULL; } challenge [belle_sip_header_www_authenticate_t* www_authenticate] : ({IS_TOKEN(Digest)}? token /*'Digest'*/ {belle_sip_header_www_authenticate_set_scheme(www_authenticate,"Digest");} lws digest_cln[www_authenticate] (comma digest_cln[www_authenticate])*) | other_challenge [www_authenticate]; other_challenge [belle_sip_header_www_authenticate_t* www_authenticate] : auth_scheme {belle_sip_header_www_authenticate_set_scheme(www_authenticate,(char*)$auth_scheme.text->chars);} lws auth_param[NULL] (comma auth_param[NULL])*; digest_cln [belle_sip_header_www_authenticate_t* www_authenticate] : realm {belle_sip_header_www_authenticate_set_realm(www_authenticate,(char*)$realm.ret); belle_sip_free($realm.ret);} | nonce {belle_sip_header_www_authenticate_set_nonce(www_authenticate,(char*)$nonce.ret); belle_sip_free($nonce.ret);} | algorithm {belle_sip_header_www_authenticate_set_algorithm(www_authenticate,$algorithm.ret);} | opaque {belle_sip_header_www_authenticate_set_opaque(www_authenticate,$opaque.ret); belle_sip_free($opaque.ret);} | qop_opts {belle_sip_header_www_authenticate_set_qop(www_authenticate,$qop_opts.ret); /*belle_sip_free($qop_opts.ret);*/} | domain {belle_sip_header_www_authenticate_set_domain(www_authenticate,$domain.ret); belle_sip_free($domain.ret);} | stale { if (strcmp("true",$stale.ret)==0) { belle_sip_header_www_authenticate_set_stale(www_authenticate,1); } } | auth_param[(belle_sip_header_authorization_t*)www_authenticate]; /* the cast above is very BAD, but auth_param works on fields common to the two structures*/ realm returns [char* ret=NULL] : {IS_TOKEN(realm)}? token /*'realm'*/ equal realm_value { $ret = _belle_sip_str_dup_and_unquote_string((char*)$realm_value.text->chars); }; realm_value : quoted_string ; domain returns [char* ret=NULL] : {IS_TOKEN(domain)}? token /*'domain'*/ equal quoted_string { $ret = _belle_sip_str_dup_and_unquote_string((char*)$quoted_string.text->chars);}; /* LDQUOT uri ( SP+ uri )* RDQUOT; uri : absoluteURI | '/'.; */ nonce returns [char* ret=NULL] : {IS_TOKEN(nonce)}? token /*'nonce'*/ equal nonce_value{ $ret = _belle_sip_str_dup_and_unquote_string((char*)$nonce_value.text->chars); }; opaque returns [char* ret=NULL] : {IS_TOKEN(opaque)}? token /*'opaque'*/ equal quoted_string{ $ret = _belle_sip_str_dup_and_unquote_string((char*)$quoted_string.text->chars); }; stale returns [const char* ret=NULL] : {IS_TOKEN(stale)}? token /*'stale'*/ equal stale_value {$ret=(char*)$stale_value.text->chars;} /* ( 'true' | 'false' )*/; stale_value:token; algorithm returns [const char* ret=NULL] : {IS_TOKEN(algorithm)}? token /*'algorithm'*/ equal /* ( 'MD5' | 'MD5-sess' |*/ alg_value=token {$ret=(char*)$alg_value.text->chars;}/*)*/ ; qop_opts returns [belle_sip_list_t* ret=NULL] scope { belle_sip_list_t* list; } @init{$qop_opts::list=NULL;} : {IS_TOKEN(qop)}? token /*'qop'*/ equal /*ldquot*/DQUOTE qop_opts_value (COMMA qop_opts_value)* /*rdquot*/DQUOTE {$ret=$qop_opts::list;} ; qop_opts_value : lws? token lws? {$qop_opts::list=belle_sip_list_append($qop_opts::list,belle_sip_strdup((const char*)$token.text->chars));}; header_proxy_authorization returns [belle_sip_header_proxy_authorization_t* ret=NULL] scope { belle_sip_header_proxy_authorization_t* current; } @init { $header_proxy_authorization::current = belle_sip_header_proxy_authorization_new();$ret = $header_proxy_authorization::current; } : {IS_TOKEN(Proxy-Authorization)}? token /*'Proxy-Authorization'*/ hcolon credentials[(belle_sip_header_authorization_t*)$header_proxy_authorization::current]; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_proxy_authorization::current); $ret=NULL; } /* proxy_require : 'Proxy-Require' HCOLON option_tag (COMMA option_tag)*; option_tag : token; */ /*FIXME service-route = recorde-route = route, too many copy/past*/ service_route_token: {IS_TOKEN(Service-Route)}? token; header_service_route returns [belle_sip_header_service_route_t* ret=NULL] scope { belle_sip_header_service_route_t* current; belle_sip_header_service_route_t* first;} @init { $header_service_route::current = NULL;} : service_route_token /*'Service-Route'*/ sp_tab_colon srv_route (COMMA srv_route)* {$ret = $header_service_route::first;}; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); if ($ret) belle_sip_object_unref($ret); $ret=NULL; } srv_route scope { belle_sip_header_service_route_t* prev;} @init { if ($header_service_route::current == NULL) { $header_service_route::first = $header_service_route::current = belle_sip_header_service_route_new(); $srv_route::prev=NULL; } else { belle_sip_header_t* header = BELLE_SIP_HEADER($header_service_route::current); $srv_route::prev=$header_service_route::current; belle_sip_header_set_next(header,(belle_sip_header_t*)($header_service_route::current = belle_sip_header_service_route_new())); } } : name_addr[BELLE_SIP_HEADER_ADDRESS($header_service_route::current)] ( SEMI lws? sr_param lws?)*; sr_param : generic_param[BELLE_SIP_PARAMETERS($header_service_route::current)]; record_route_token: {IS_TOKEN(Record-Route)}? token; header_record_route returns [belle_sip_header_record_route_t* ret=NULL] scope { belle_sip_header_record_route_t* current; belle_sip_header_record_route_t* first;} @init { $header_record_route::current = NULL;} : record_route_token /*'Record-Route'*/ sp_tab_colon rec_route ( COMMA rec_route)* {$ret = $header_record_route::first;}; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); if ($ret) belle_sip_object_unref($ret); $ret=NULL; } rec_route scope { belle_sip_header_record_route_t* prev;} @init { if ($header_record_route::current == NULL) { $header_record_route::first = $header_record_route::current = belle_sip_header_record_route_new(); $rec_route::prev=NULL; } else { belle_sip_header_t* header = BELLE_SIP_HEADER($header_record_route::current); $rec_route::prev=$header_record_route::current; belle_sip_header_set_next(header,(belle_sip_header_t*)($header_record_route::current = belle_sip_header_record_route_new())); } } : name_addr[BELLE_SIP_HEADER_ADDRESS($header_record_route::current)] ( SEMI lws? rr_param lws? )*; rr_param : generic_param[BELLE_SIP_PARAMETERS($header_record_route::current)]; /* reply_to : 'Reply-To' HCOLON rplyto_spec; rplyto_spec : ( name_addr | addr_spec ) ( SEMI rplyto_param )*; rplyto_param : generic_param; require : 'Require' HCOLON option_tag (COMMA option_tag)*; retry_after : 'Retry-After' HCOLON delta_seconds comment? ( SEMI retry_param )*; */ comment : LPAREN . RPAREN; /* retry_param : ('duration' EQUAL delta_seconds) | generic_param; */ route_token: {IS_TOKEN(Route)}? token; header_route returns [belle_sip_header_route_t* ret=NULL] scope { belle_sip_header_route_t* current;belle_sip_header_route_t* first; } @init { $header_route::current = NULL; } : route_token /*'Route'*/ sp_tab_colon route_param ( COMMA route_param)*{$ret = $header_route::first;}; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); if ($ret) belle_sip_object_unref($ret); $ret=NULL; } route_param scope { belle_sip_header_route_t* prev;} @init { if ($header_route::current == NULL) { $header_route::first = $header_route::current = belle_sip_header_route_new(); $route_param::prev=NULL; } else { belle_sip_header_t* header = BELLE_SIP_HEADER($header_route::current); $route_param::prev=$header_route::current; belle_sip_header_set_next(header,(belle_sip_header_t*)($header_route::current = belle_sip_header_route_new())); } } : name_addr[BELLE_SIP_HEADER_ADDRESS($header_route::current)] ( SEMI lws? r_param lws?)*; r_param : generic_param[BELLE_SIP_PARAMETERS($header_route::current)]; /* server : 'Server' HCOLON server_val (lws server_val)*; */ /* subject : ( 'Subject' | 's' ) HCOLON (text_utf_huit)?; text_utf_huit : ; supported : ( 'Supported' | 'k' ) HCOLON (option_tag (COMMA option_tag)*)?; timestamp : 'Timestamp' HCOLON (DIGIT)+ ( '.' (DIGIT)* )? ( lws delay )?; delay : (DIGIT)* ( '.' (DIGIT)* )?; */ to_token: {IS_HEADER_NAMED(To,t)}? token; header_to returns [belle_sip_header_to_t* ret=NULL] scope { belle_sip_header_to_t* current; } @init { $header_to::current = belle_sip_header_to_new(); $ret = $header_to::current;} : to_token /*'To' ( 'To' | 't' )*/ sp_tab_colon to_spec; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_to::current); $ret=NULL; } to_spec : ( name_addr_with_generic_uri[BELLE_SIP_HEADER_ADDRESS($header_to::current)] | paramless_addr_spec_with_generic_uri[BELLE_SIP_HEADER_ADDRESS($header_to::current)] ) ( SEMI lws? to_param lws?)*; to_param : /*tag_param |*/ generic_param [BELLE_SIP_PARAMETERS($header_to::current)]; refer_to_token: {IS_TOKEN(Refer-To)}? token; header_refer_to returns [belle_sip_header_refer_to_t* ret=NULL] : refer_to_token /*'Refer-To'*/ sp_tab_colon refer_to_spec[BELLE_SIP_HEADER_ADDRESS(belle_sip_header_refer_to_new())] {$ret = BELLE_SIP_HEADER_REFER_TO($refer_to_spec.ret);}; referred_by_token: {IS_TOKEN(Referred-By)}? token; header_referred_by returns [belle_sip_header_referred_by_t* ret=NULL] : referred_by_token /*'Referred-By'*/ sp_tab_colon refer_to_spec[BELLE_SIP_HEADER_ADDRESS(belle_sip_header_referred_by_new())] {$ret = BELLE_SIP_HEADER_REFERRED_BY($refer_to_spec.ret);}; refer_to_spec [belle_sip_header_address_t* address] returns [belle_sip_header_address_t* ret] @init {$ret=address;} : (( name_addr[address] | paramless_addr_spec[address]) ( SEMI lws? generic_param [BELLE_SIP_PARAMETERS(address)] lws? )* ); catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref(address); $ret=NULL; } /* unsupported : 'Unsupported' HCOLON option_tag (COMMA option_tag)*; */ header_user_agent returns [belle_sip_header_user_agent_t* ret] scope { belle_sip_header_user_agent_t* current; } @init { $header_user_agent::current = belle_sip_header_user_agent_new();$ret = $header_user_agent::current;} : {IS_TOKEN(User-Agent)}? token /*'User-Agent'*/ hcolon server_val (lws server_val)*; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_user_agent::current); $ret=NULL; } server_val : word {belle_sip_header_user_agent_add_product($header_user_agent::current,(const char*)$word.text->chars); }; /*serval_item : product | comment ; product : token (SLASH product_version)?; product_version : token; */ via_token: {IS_HEADER_NAMED(Via,v)}? token; header_via returns [belle_sip_header_via_t* ret] scope { belle_sip_header_via_t* current; belle_sip_header_via_t* first; } @init { $header_via::current = NULL;$ret = NULL;} : via_token/* ( 'via' | 'v' )*/ hcolon via_parm (comma via_parm)* {$ret = $header_via::first;} ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); if ($ret) belle_sip_object_unref($ret); $ret=NULL; } via_parm scope { belle_sip_header_via_t* prev;} @init { if ($header_via::current == NULL) { $header_via::first = $header_via::current = belle_sip_header_via_new(); $via_parm::prev=NULL; } else { belle_sip_header_t* header; $via_parm::prev=$header_via::current; header = BELLE_SIP_HEADER($header_via::current); belle_sip_header_set_next(header,(belle_sip_header_t*)($header_via::current = belle_sip_header_via_new())); } } : sent_protocol lws sent_by ( semi via_params )*; via_params : /*via_ttl | via_maddr | via_branch | via_extension */ via_received[$header_via::current] | generic_param [BELLE_SIP_PARAMETERS($header_via::current)]; /*via_ttl : 'ttl' EQUAL ttl; via_maddr : 'maddr' EQUAL host;*/ via_received [belle_sip_header_via_t* object] : {IS_TOKEN(received)}? token EQUAL via_address {belle_sip_header_via_set_received(object,(const char*)$via_address.text->chars);}; via_address: ipv4address | ipv6address; /* via_branch : 'branch' EQUAL token; via_extension : generic_param;*/ sent_protocol : (protocol_name slash protocol_version) {belle_sip_header_via_set_protocol($header_via::current,(const char*)$text->chars);} slash transport {belle_sip_header_via_set_transport($header_via::current,(const char*)$transport.text->chars);} ; protocol_name : /*'SIP' |*/ token; protocol_version : token; transport : /* 'UDP' | 'TCP' | 'TLS' | 'SCTP' | */ other_transport; other_transport : token; sent_by : host {belle_sip_header_via_set_host($header_via::current,$host.ret);} ( COLON port {belle_sip_header_via_set_port($header_via::current,$port.ret);} )? ; /* warning : 'Warning' HCOLON warning_value (COMMA warning_value)*; warning_value : warn_code SP warn_agent SP warn_text; warn_code : DIGIT DIGIT DIGIT; warn_agent : hostport | pseudonym; // the name or pseudonym of the server adding // the Warning header, for use in debugging warn_text : quoted_string; pseudonym : token; */ header_www_authenticate returns [belle_sip_header_www_authenticate_t* ret] scope { belle_sip_header_www_authenticate_t* current; } @init { $header_www_authenticate::current = belle_sip_header_www_authenticate_new();$ret = $header_www_authenticate::current; } : {IS_TOKEN(WWW-Authenticate)}? token /*'WWW-Authenticate'*/ hcolon challenge[$header_www_authenticate::current]; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_www_authenticate::current); $ret=NULL; } state_value: token ; header_subscription_state returns [belle_sip_header_subscription_state_t* ret] scope { belle_sip_header_subscription_state_t* current; } @init { $header_subscription_state::current = belle_sip_header_subscription_state_new();$ret = $header_subscription_state::current; } : {IS_TOKEN(Subscription-State)}? token /*"Subscription-State"*/ hcolon state_value {belle_sip_header_subscription_state_set_state($header_subscription_state::current,(const char*)$state_value.text->chars);} (semi generic_param [BELLE_SIP_PARAMETERS($header_subscription_state::current)])* ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_subscription_state::current); $ret=NULL; } header_event returns [belle_sip_header_event_t* ret] scope { belle_sip_header_event_t* current; } @init { $header_event::current = belle_sip_header_event_new();$ret = $header_event::current; } : {IS_TOKEN(Event)}? token /*"Event"*/ hcolon event_package {belle_sip_header_event_set_package_name($header_event::current,(const char*)$event_package.text->chars);} (semi generic_param [BELLE_SIP_PARAMETERS($header_event::current)])* ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_event::current); $ret=NULL; } event_package : token; /* Replaces = "Replaces" HCOLON replaces-values *(COMMA replaces-values) replaces-values = callid *( SEMI replaces-param ) callid = token [ "@" token ] replaces-param = to-tag | from-tag | extension-param to-tag = "to-tag" EQUAL ( UUID | "*" ) from-tag = "from-tag" EQUAL UUID extension-param = token [ EQUAL ( token | quoted-string ) ] */ header_replaces returns [belle_sip_header_replaces_t* ret] scope { belle_sip_header_replaces_t* current; } @init { $header_replaces::current = belle_sip_header_replaces_new();$ret = $header_replaces::current; } : {IS_TOKEN(Replaces)}? token /*"Replaces"*/ hcolon call_id {belle_sip_header_replaces_set_call_id($header_replaces::current,(const char*)$call_id.text->chars);} (semi generic_param [BELLE_SIP_PARAMETERS($header_replaces::current)])* ; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($header_replaces::current); $ret=NULL; } //**********************************Privacy*******************************// header_p_preferred_identity returns [belle_sip_header_p_preferred_identity_t* ret] @init { $ret=NULL; } : {IS_TOKEN(P-Preferred-Identity)}? token /*"P-Preferred-Identity"*/ sp_tab_colon header_address_base[(belle_sip_header_address_t*)belle_sip_header_p_preferred_identity_new()] {$ret=(belle_sip_header_p_preferred_identity_t*)$header_address_base.ret;}; header_privacy returns [belle_sip_header_privacy_t* ret] scope { belle_sip_header_privacy_t* current; } @init { $header_privacy::current = belle_sip_header_privacy_new();$ret = $header_privacy::current;} : {IS_TOKEN(Privacy)}? token /*'Privacy'*/ hcolon privacy_val (semi privacy_val)*; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($ret); $ret=NULL; } privacy_val: token {belle_sip_header_privacy_add_privacy($header_privacy::current,(const char*)$token.text->chars);}; header returns [belle_sip_header_t* ret=NULL] : header_extension_base[FALSE] {$ret=$header_extension_base.ret;}; //********************************************************************************************// header_extension_base[ANTLR3_BOOLEAN is_http] returns [belle_sip_header_t* ret] scope {int as_value;} @init {$header_extension_base::as_value=0;$ret=NULL;} : (header_name hcolon /*sp_tab_colon*/ /*because LWS can be in both colon or header_value*/ (header_value[(const char*)$header_name.text->chars,$is_http ]{$header_extension_base::as_value=1;$ret=$header_value.ret;})?) { if (!$ret && !$header_extension_base::as_value) { /*to handle value parsing error*/ /*special case: header without value*/ $ret=belle_sip_header_create((const char*)$header_name.text->chars,NULL); } }; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); if ($ret) belle_sip_object_unref($ret); $ret=NULL; } header_name : token; header_value[const char* name, ANTLR3_BOOLEAN is_http] returns [belle_sip_header_t* ret] options { greedy = false; } @init {$ret=NULL;} : (~(SP|CRLF) ((CRLF SP) | ~CRLF)* ) { if ($is_http) { $ret=belle_http_header_create($name,(const char*)$header_value.text->chars); }else { $ret=belle_sip_header_create($name,(const char*)$header_value.text->chars); } } ; message_body options { greedy = false; } : OCTET+; paramless_uri returns [belle_sip_uri_t* ret=NULL] scope { belle_sip_uri_t* current; } @init { $paramless_uri::current = belle_sip_uri_new(); } : sip_schema[$paramless_uri::current] ( (userinfo[$paramless_uri::current]) =>(userinfo[$paramless_uri::current] hostport[$paramless_uri::current]) | hostport[$paramless_uri::current]) headers[$paramless_uri::current]? {$ret = $paramless_uri::current;}; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($paramless_uri::current); $ret=NULL; } uri returns [belle_sip_uri_t* ret=NULL] scope { belle_sip_uri_t* current; } @init { $uri::current = belle_sip_uri_new(); } : sip_schema[$uri::current] ( ((userinfo[NULL])=>userinfo[$uri::current] hostport[$uri::current]) | hostport[$uri::current] ) uri_parameters[$uri::current]? headers[$uri::current]? {$ret = $uri::current;}; catch [ANTLR3_RECOGNITION_EXCEPTION] { belle_sip_message("[\%s] reason [\%s]",(const char*)EXCEPTION->name,(const char*)EXCEPTION->message); belle_sip_object_unref($uri::current); $ret=NULL; } sip_token: {IS_TOKEN(sip)}? token; sips_token: {IS_TOKEN(sips)}? token; sip_schema[belle_sip_uri_t* uri] : (sips_token {belle_sip_uri_set_secure(uri,1);} | sip_token) COLON ; userinfo[belle_sip_uri_t* uri] scope { belle_sip_uri_t* current; } @init {$userinfo::current=uri;} : user ( COLON password )? AT; user : ( unreserved | escaped | user_unreserved )+ { char* unescaped_username; unescaped_username=belle_sip_to_unescaped_string((const char *)$text->chars); belle_sip_uri_set_user($userinfo::current,unescaped_username); belle_sip_free(unescaped_username); }; password : ( unreserved | escaped |AND | EQUAL | PLUS | DOLLARD | COMMA )* { char* unescaped_userpasswd; unescaped_userpasswd=belle_sip_to_unescaped_string((const char *)$text->chars); belle_sip_uri_set_user_password($userinfo::current,unescaped_userpasswd); belle_sip_free(unescaped_userpasswd); }; hostport[belle_sip_uri_t* uri] scope { belle_sip_uri_t* current; } @init {$hostport::current=uri;} : host ( COLON port {belle_sip_uri_set_port($hostport::current,$port.ret);})? {belle_sip_uri_set_host($hostport::current,$host.ret);}; uri_parameters[belle_sip_uri_t* uri] scope { belle_sip_uri_t* current; } @init {$uri_parameters::current=uri;} : ( (semi uri_parameter)|(lws? SEMI) )+; /*allow semi only teven if not in the rfc*/ uri_parameter //all parameters are considered as other : other_param ; other_param : pname { char* unescaped_parameters = belle_sip_to_unescaped_string((const char *) $pname.text->chars); belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS($uri_parameters::current) ,unescaped_parameters ,NULL); belle_sip_free(unescaped_parameters); } | (pname EQUAL pvalue) { char* unescaped_pname = belle_sip_to_unescaped_string((const char *) $pname.text->chars); char* unescaped_pvalue = belle_sip_to_unescaped_string((const char *) $pvalue.text->chars); belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS($uri_parameters::current) ,unescaped_pname ,unescaped_pvalue); belle_sip_free(unescaped_pname); belle_sip_free(unescaped_pvalue); } ; pname : paramchar+; pvalue : paramchar+; paramchar : (param_unreserved)=>param_unreserved | unreserved | escaped; param_unreserved : LSBRAQUET | RSBRAQUET | SLASH | COLON | AND | PLUS | DOLLARD | DOT; headers[belle_sip_uri_t* uri] scope { belle_sip_uri_t* current; int is_hvalue; } @init {$headers::current=uri; $headers::is_hvalue=0;} : QMARK uri_header ( AND uri_header )* ; uri_header scope {int is_hvalue; } @init {$uri_header::is_hvalue=0;} : hname EQUAL (hvalue{$uri_header::is_hvalue = 1;})? { char* unescaped_hname = belle_sip_to_unescaped_string((const char *)$hname.text->chars); char* unescaped_hvalue = ($uri_header::is_hvalue)?belle_sip_to_unescaped_string((const char *)$hvalue.text->chars):NULL; belle_sip_uri_set_header($headers::current,unescaped_hname,unescaped_hvalue); belle_sip_free(unescaped_hname); if (unescaped_hvalue) belle_sip_free(unescaped_hvalue); }; hname : ( hnv_unreserved | unreserved | escaped )+; hvalue : ( hnv_unreserved | unreserved | escaped )+; /*hnv-unreserved = "[" / "]" / "/" / "?" / ":" / "+" / "$"*/ hnv_unreserved : LSBRAQUET | RSBRAQUET | SLASH | QMARK | COLON | PLUS | DOLLARD ; //****************SIP end**********************/ //*************************common tokens*******************************/ user_unreserved : AND | EQUAL | PLUS | DOLLARD | COMMA | SEMI | QMARK | SLASH; host returns [const char* ret] scope { const char* current; } @init {$host::current=$ret=NULL;} : (hostname {$host::current=(const char *)$hostname.text->chars;} | ipv4address {$host::current=(const char *)$ipv4address.text->chars;} | ipv6reference ) {$ret=$host::current;}; hostname : ( domainlabel DOT )* (toplabel)=>toplabel DOT? ; domainlabel : alphanum | (alphanum ( alphanum | DASH )* alphanum) ; toplabel : alpha | (alpha ( DASH? alphanum)+) ; ipv4address : three_digit DOT three_digit DOT three_digit DOT three_digit ; ipv6reference : LSBRAQUET ipv6address RSBRAQUET {$host::current=(const char *)$ipv6address.text->chars;}; ipv6address : hexpart ( COLON ipv4address )? ; hexpart : hexseq | hexseq COLON COLON ( hexseq )? | COLON COLON ( hexseq )?; hexseq : hex4 ( COLON hex4)*; hex4 : hexdigit+;/* hexdigit hexdigit hexdigit ;*/ port returns [int ret] @init {$ret=-1;} : DIGIT+ { $ret=atoi((const char *)$text->chars); }; escaped : PERCENT hexdigit hexdigit; ttl : three_digit; three_digit: (DIGIT) => DIGIT | (DIGIT DIGIT) => (DIGIT DIGIT) | (DIGIT DIGIT DIGIT) =>(DIGIT DIGIT DIGIT) ; token : (alphanum | mark | PERCENT | PLUS | BQUOTE )+; reserved_for_from_to_contact_addr_spec: COLON | AT | AND | EQUAL | PLUS | DOLLARD | SLASH; reserved : SEMI | COMMA | QMARK | reserved_for_from_to_contact_addr_spec ; unreserved : alphanum |mark; alphanum : alpha | DIGIT ; hexdigit : HEX_CHAR|DIGIT; alpha : HEX_CHAR | COMMON_CHAR; word : (alphanum | mark | PERCENT | PLUS | BQUOTE | LAQUOT | RAQUOT | COLON | BSLASH | DQUOTE | SLASH | LSBRAQUET | RSBRAQUET | QMARK | LBRACE | RBRACE )+; mark : DASH | USCORE | DOT | EMARK | TILDE | STAR | SQUOTE | LPAREN | RPAREN ; sp_tab_colon :( SP | HTAB )* COLON ; hcolon : sp_tab_colon lws? //SWS; ;//|( SP | HTAB )* COLON LWS+; ldquot : lws? DQUOTE ; rdquot : DQUOTE lws?; semi: lws? SEMI lws?; comma : lws? COMMA lws?; sp_laquot : lws? LAQUOT ; raquot_sp : RAQUOT lws?; equal: lws? EQUAL lws?; slash : lws? SLASH lws?; lws : (SP* CRLF SP+) | SP+ ; //linear whitespace //*************************************common tokens*****************/ COMMON_CHAR : 'g'..'z' | 'G'..'Z' ; HEX_CHAR: 'a'..'f' |'A'..'F'; DIGIT : '0'..'9' ; AT: '@'; AND: '&'; DOLLARD: '$'; QMARK: '?'; EMARK: '!'; DASH: '-'; CRLF : '\r\n' { USER1 = (int)((char*)ctx->pLexer->input->currentLine - (char*)ctx->pLexer->input->data); /*GETCHARINDEX()*/;}; HTAB : ' '; OR : '|'; PERCENT: '%'; DQUOTE : '"'; SQUOTE : '\''; BQUOTE: '`'; BSLASH: '\\'; LBRACE: '{'; RBRACE: '}'; USCORE: '_'; TILDE: '~'; DOT: '.'; PLUS: '+'; COLON : ':' ; SEMI : ';' ; COMMA : ',' ; LAQUOT : '<' ; RAQUOT : '>' ; RPAREN : ')' ; LPAREN : '(' ; RSBRAQUET : ']' ; LSBRAQUET : '[' ; EQUAL : '=' ; SLASH : '/' ; STAR : '*' ; SP : ' ' ; OCTET : . ; belle-sip-1.4.1/src/http-listener.c000066400000000000000000000063221252242224000171240ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" typedef struct belle_http_callbacks belle_http_callbacks_t; struct belle_http_callbacks{ belle_sip_object_t base; belle_http_request_listener_callbacks_t cbs; void *user_ctx; }; static void process_response_headers(belle_http_request_listener_t *l, const belle_http_response_event_t *event){ belle_http_callbacks_t *obj=(belle_http_callbacks_t*)l; if (obj->cbs.process_response_headers) obj->cbs.process_response_headers(obj->user_ctx,event); } static void process_response_event(belle_http_request_listener_t *l, const belle_http_response_event_t *event){ belle_http_callbacks_t *obj=(belle_http_callbacks_t*)l; if (obj->cbs.process_response) obj->cbs.process_response(obj->user_ctx,event); } static void process_io_error(belle_http_request_listener_t *l, const belle_sip_io_error_event_t *event){ belle_http_callbacks_t *obj=(belle_http_callbacks_t*)l; if (obj->cbs.process_io_error) obj->cbs.process_io_error(obj->user_ctx,event); } static void process_timeout(belle_http_request_listener_t *l, const belle_sip_timeout_event_t *event){ belle_http_callbacks_t *obj=(belle_http_callbacks_t*)l; if (obj->cbs.process_timeout) obj->cbs.process_timeout(obj->user_ctx,event); } static void process_auth_requested(belle_http_request_listener_t *l, belle_sip_auth_event_t *event){ belle_http_callbacks_t *obj=(belle_http_callbacks_t*)l; if (obj->cbs.process_auth_requested) obj->cbs.process_auth_requested(obj->user_ctx,event); } /*BELLE_SIP_DECLARE_VPTR(belle_http_callbacks_t);*/ BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_http_callbacks_t,belle_http_request_listener_t) process_response_headers, process_response_event, process_io_error, process_timeout, process_auth_requested BELLE_SIP_IMPLEMENT_INTERFACE_END BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_http_callbacks_t,belle_http_request_listener_t); static void belle_http_callbacks_destroy(belle_http_callbacks_t *obj){ if (obj->cbs.listener_destroyed) obj->cbs.listener_destroyed(obj->user_ctx); } BELLE_SIP_INSTANCIATE_VPTR(belle_http_callbacks_t,belle_sip_object_t,belle_http_callbacks_destroy,NULL,NULL,FALSE); belle_http_request_listener_t *belle_http_request_listener_create_from_callbacks(const belle_http_request_listener_callbacks_t *callbacks, void *user_ctx){ belle_http_callbacks_t *obj=belle_sip_object_new(belle_http_callbacks_t); memcpy(&obj->cbs,callbacks,sizeof(belle_http_request_listener_callbacks_t)); obj->user_ctx=user_ctx; return BELLE_HTTP_REQUEST_LISTENER(obj); } belle-sip-1.4.1/src/http-message.c000066400000000000000000000141531252242224000167240ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "grammars/belle_sip_messageLexer.h" #include "grammars/belle_sip_messageParser.h" #include "belle_sip_internal.h" static void belle_http_request_init(belle_http_request_t *req){ /*nop*/ } static void belle_http_request_listener_destroyed(belle_http_request_t *req){ req->listener=NULL; } static void belle_http_request_destroy(belle_http_request_t *req){ if (req->req_uri) belle_sip_object_unref(req->req_uri); DESTROY_STRING(req,method) belle_http_request_set_listener(req,NULL); belle_http_request_set_channel(req,NULL); SET_OBJECT_PROPERTY(req,orig_uri,NULL); SET_OBJECT_PROPERTY(req,response,NULL); } static void belle_http_request_clone(belle_http_request_t *obj, const belle_http_request_t *orig){ if (orig->req_uri) obj->req_uri=(belle_generic_uri_t*)belle_sip_object_clone((belle_sip_object_t*)orig->req_uri); CLONE_STRING(belle_http_request,method,obj,orig) } static belle_sip_error_code belle_http_request_marshal(const belle_http_request_t* request, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_snprintf(buff,buff_size,offset,"%s ",belle_http_request_get_method(request)); if (error!=BELLE_SIP_OK) return error; error=belle_generic_uri_marshal(belle_http_request_get_uri(request),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset," %s","HTTP/1.1\r\n"); if (error!=BELLE_SIP_OK) return error; error=belle_sip_headers_marshal(BELLE_SIP_MESSAGE(request),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; return error; } GET_SET_STRING(belle_http_request,method); BELLE_NEW(belle_http_request,belle_sip_message) BELLE_PARSE(belle_sip_messageParser,belle_,http_request) belle_http_request_t *belle_http_request_create(const char *method, belle_generic_uri_t *url, ...){ va_list vl; belle_http_request_t *obj=belle_http_request_new(); belle_sip_header_t *header; obj->method=belle_sip_strdup(method); obj->req_uri=(belle_generic_uri_t*)belle_sip_object_ref(url); va_start(vl,url); while((header=va_arg(vl,belle_sip_header_t*))!=NULL){ belle_sip_message_add_header(BELLE_SIP_MESSAGE(obj),header); } va_end(vl); return obj; } int belle_http_request_is_cancelled(const belle_http_request_t *req) { return req->cancelled; } void belle_http_request_cancel(belle_http_request_t *req) { req->cancelled = TRUE; } void belle_http_request_set_listener(belle_http_request_t *req, belle_http_request_listener_t *l){ if (req->listener){ belle_sip_object_weak_unref(req->listener,(belle_sip_object_destroy_notify_t)belle_http_request_listener_destroyed,req); req->listener=NULL; } if (l){ belle_sip_object_weak_ref(l,(belle_sip_object_destroy_notify_t)belle_http_request_listener_destroyed,req); req->listener=l; } } static void notify_http_request_of_channel_destruction(belle_http_request_t *obj, belle_sip_channel_t *chan_being_destroyed){ obj->channel=NULL; } void belle_http_request_set_channel(belle_http_request_t *req, belle_sip_channel_t* chan){ if (req->channel){ belle_sip_object_weak_unref(req->channel, (belle_sip_object_destroy_notify_t)notify_http_request_of_channel_destruction, req); req->channel=NULL; } if (chan){ belle_sip_object_weak_ref(chan, (belle_sip_object_destroy_notify_t)notify_http_request_of_channel_destruction, req); req->channel=chan; } } belle_http_request_listener_t * belle_http_request_get_listener(const belle_http_request_t *req){ return req->listener; } belle_generic_uri_t *belle_http_request_get_uri(const belle_http_request_t *req){ return req->req_uri; } void belle_http_request_set_uri(belle_http_request_t* request, belle_generic_uri_t* uri) { SET_OBJECT_PROPERTY(request,req_uri,uri); } void belle_http_request_set_response(belle_http_request_t *req, belle_http_response_t *resp){ SET_OBJECT_PROPERTY(req,response,resp); } belle_http_response_t *belle_http_request_get_response(belle_http_request_t *req){ return req->response; } /*response*/ struct belle_http_response{ belle_sip_message_t base; char *http_version; int status_code; char *reason_phrase; }; void belle_http_response_destroy(belle_http_response_t *resp){ if (resp->http_version) belle_sip_free(resp->http_version); if (resp->reason_phrase) belle_sip_free(resp->reason_phrase); } static void belle_http_response_init(belle_http_response_t *resp){ } static void belle_http_response_clone(belle_http_response_t *resp, const belle_http_response_t *orig){ if (orig->http_version) resp->http_version=belle_sip_strdup(orig->http_version); resp->status_code=orig->status_code; if (orig->reason_phrase) resp->reason_phrase=belle_sip_strdup(orig->reason_phrase); } belle_sip_error_code belle_http_response_marshal(belle_http_response_t *resp, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_snprintf( buff ,buff_size ,offset ,"HTTP/1.1 %i %s\r\n" ,belle_http_response_get_status_code(resp) ,belle_http_response_get_reason_phrase(resp)?belle_http_response_get_reason_phrase(resp):""); if (error!=BELLE_SIP_OK) return error; error=belle_sip_headers_marshal(BELLE_SIP_MESSAGE(resp),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_NEW(belle_http_response,belle_sip_message) BELLE_PARSE(belle_sip_messageParser,belle_,http_response) GET_SET_STRING(belle_http_response,reason_phrase); GET_SET_INT(belle_http_response,status_code,int) belle-sip-1.4.1/src/http-provider.c000066400000000000000000000447201252242224000171350ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" typedef struct belle_http_channel_context belle_http_channel_context_t; #define BELLE_HTTP_CHANNEL_CONTEXT(obj) BELLE_SIP_CAST(obj,belle_http_channel_context_t) static void provider_remove_channel(belle_http_provider_t *obj, belle_sip_channel_t *chan); struct belle_http_channel_context{ belle_sip_object_t base; belle_http_provider_t *provider; belle_sip_list_t *pending_requests; }; struct belle_http_provider{ belle_sip_object_t base; belle_sip_stack_t *stack; char *bind_ip; int ai_family; belle_sip_list_t *tcp_channels; belle_sip_list_t *tls_channels; belle_tls_verify_policy_t *verify_ctx; }; #define BELLE_HTTP_REQUEST_INVOKE_LISTENER(obj,method,arg) \ obj->listener ? BELLE_SIP_INVOKE_LISTENER_ARG(obj->listener,belle_http_request_listener_t,method,arg) : 0 static int http_channel_context_handle_authentication(belle_http_channel_context_t *ctx, belle_http_request_t *req){ const char *realm=NULL; belle_sip_auth_event_t *ev=NULL; belle_http_response_t *resp=belle_http_request_get_response(req); const char *username=NULL; const char *passwd=NULL; const char *ha1=NULL; char computed_ha1[33]; belle_sip_header_www_authenticate_t* authenticate; int ret=0; if (req->auth_attempt_count>1){ req->auth_attempt_count=0; return -1; } if (resp == NULL ) { belle_sip_error("Missing response for req [%p], cannot authenticate", req); return -1; } if (!(authenticate = belle_sip_message_get_header_by_type(resp,belle_sip_header_www_authenticate_t))) { if (belle_sip_message_get_header_by_type(resp,belle_sip_header_proxy_authenticate_t)) { belle_sip_error("Proxy authentication not supported yet, cannot authenticate for resp [%p]", resp); } belle_sip_error("Missing auth header in response [%p], cannot authenticate", resp); return -1; } if (strcasecmp("Digest",belle_sip_header_www_authenticate_get_scheme(authenticate)) != 0) { belle_sip_error("Unsupported auth scheme [%s] in response [%p], cannot authenticate", belle_sip_header_www_authenticate_get_scheme(authenticate),resp); return -1; } /*find if username, passwd were already supplied in original request uri*/ if (req->orig_uri){ username=belle_generic_uri_get_user(req->orig_uri); passwd=belle_generic_uri_get_user_password(req->orig_uri); } realm = belle_sip_header_www_authenticate_get_realm(authenticate); if (!username || !passwd) { ev=belle_sip_auth_event_create((belle_sip_object_t*)ctx->provider,realm,NULL); BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_auth_requested,ev); username=ev->username; passwd=ev->passwd; ha1=ev->ha1; } if (!ha1 && username && passwd) { belle_sip_auth_helper_compute_ha1(username,realm,passwd, computed_ha1); ha1=computed_ha1; } else if (!ha1){ belle_sip_error("No auth info found for request [%p], cannot authenticate",req); ret=-1; } if (ha1) { belle_http_header_authorization_t* authorization; req->auth_attempt_count++; authorization = belle_http_auth_helper_create_authorization(authenticate); /*select first qop mode*/ belle_sip_header_authorization_set_qop(BELLE_SIP_HEADER_AUTHORIZATION(authorization),belle_sip_header_www_authenticate_get_qop_first(authenticate)); belle_sip_header_authorization_set_nonce_count(BELLE_SIP_HEADER_AUTHORIZATION(authorization),1); /*we don't store nonce count for now*/ belle_sip_header_authorization_set_username(BELLE_SIP_HEADER_AUTHORIZATION(authorization),username); belle_http_header_authorization_set_uri(authorization,belle_http_request_get_uri(req)); if (belle_sip_auth_helper_fill_authorization(BELLE_SIP_HEADER_AUTHORIZATION(authorization),belle_http_request_get_method(req),ha1)) { belle_sip_error("Cannot fill auth header for request [%p]",req); if (authorization) belle_sip_object_unref(authorization); ret=-1; } else { belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_HTTP_AUTHORIZATION); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(authorization)); belle_http_provider_send_request(ctx->provider,req,NULL); } } if (ev) belle_sip_auth_event_destroy(ev); return ret; } static void http_channel_context_handle_response_headers(belle_http_channel_context_t *ctx , belle_sip_channel_t *chan, belle_http_response_t *response){ belle_http_request_t *req=ctx->pending_requests ? (belle_http_request_t*) ctx->pending_requests->data : NULL; belle_http_response_event_t ev={0}; int code; if (req==NULL){ belle_sip_error("Receiving http response headers not matching any request."); return; } if (belle_http_request_is_cancelled(req)) { belle_sip_warning("Receiving http response headers for a cancelled request."); return; } code=belle_http_response_get_status_code(response); if (code!=401 && code!=407){ /*else notify the app about the response headers received*/ ev.source=(belle_sip_object_t*)ctx->provider; ev.request=req; ev.response=response; BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_response_headers,&ev); } } static void http_channel_context_handle_response(belle_http_channel_context_t *ctx , belle_sip_channel_t *chan, belle_http_response_t *response){ belle_http_request_t *req=NULL; belle_http_response_event_t ev={0}; int code; belle_sip_header_t *connection; /*pop the request matching this response*/ ctx->pending_requests=belle_sip_list_pop_front(ctx->pending_requests,(void**)&req); if (req==NULL){ belle_sip_error("Receiving http response not matching any request."); return; } if (belle_http_request_is_cancelled(req)) { belle_sip_warning("Receiving http response for a cancelled request."); return; } connection=belle_sip_message_get_header((belle_sip_message_t *)response,"Connection"); if (connection && strstr(belle_sip_header_get_unparsed_value(connection),"close")!=NULL) chan->about_to_be_closed=TRUE; belle_http_request_set_response(req,response); code=belle_http_response_get_status_code(response); if ((code==401 || code==407) && http_channel_context_handle_authentication(ctx,req)==0 ){ /*nothing to do, the request has been resubmitted with authentication*/ }else{ /*else notify the app about the response received*/ ev.source=(belle_sip_object_t*)ctx->provider; ev.request=req; ev.response=response; BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_response,&ev); if( req->background_task_id ){ belle_sip_warning("HTTP request finished: ending bg task id=[%x]", req->background_task_id); belle_sip_end_background_task(req->background_task_id); req->background_task_id = 0; } } belle_sip_object_unref(req); } static void http_channel_context_handle_io_error(belle_http_channel_context_t *ctx, belle_sip_channel_t *chan){ belle_http_request_t *req=NULL; belle_sip_io_error_event_t ev={0}; belle_sip_list_t *elem; /*if the error happens before attempting to send the message, the pending_requests is empty*/ if (ctx->pending_requests==NULL) elem=chan->outgoing_messages; else elem=ctx->pending_requests; /*pop the requests for which this error is reported*/ for(;elem!=NULL;elem=elem->next){ req=(belle_http_request_t *)elem->data; /*else notify the app about the response received*/ /*TODO: would be nice to put the message in the event*/ ev.source=(belle_sip_object_t*)ctx->provider; ev.host=chan->peer_cname; ev.port=chan->peer_port; ev.transport=belle_sip_channel_get_transport_name(chan); BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_io_error,&ev); if( req->background_task_id ){ belle_sip_warning("IO Error on HTTP request: ending bg task id=[%x]", req->background_task_id); belle_sip_end_background_task(req->background_task_id); req->background_task_id = 0; } } } /* we are called here by the channel when receiving a message for which a body is expected. * We can notify the application so that it can setup an appropriate body handler. */ static void channel_on_message_headers(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){ belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj); if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_http_response_t)){ http_channel_context_handle_response_headers(ctx,chan,(belle_http_response_t*)msg); }/*ignore requests*/ } static void channel_on_message(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){ belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj); if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg,belle_http_response_t)){ http_channel_context_handle_response(ctx,chan,(belle_http_response_t*)msg); }/*ignore requests*/ } static int channel_on_auth_requested(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, const char* distinguished_name){ belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj); if (BELLE_SIP_IS_INSTANCE_OF(chan,belle_sip_tls_channel_t)) { belle_sip_auth_event_t* auth_event = belle_sip_auth_event_create((belle_sip_object_t*)ctx->provider,NULL,NULL); belle_sip_tls_channel_t *tls_chan=BELLE_SIP_TLS_CHANNEL(chan); belle_http_request_t *req=(belle_http_request_t*)chan->outgoing_messages->data; auth_event->mode=BELLE_SIP_AUTH_MODE_TLS; belle_sip_auth_event_set_distinguished_name(auth_event,distinguished_name); BELLE_HTTP_REQUEST_INVOKE_LISTENER(req,process_auth_requested,auth_event); belle_sip_tls_channel_set_client_certificates_chain(tls_chan,auth_event->cert); belle_sip_tls_channel_set_client_certificate_key(tls_chan,auth_event->key); belle_sip_auth_event_destroy(auth_event); } return 0; } static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){ belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj); ctx->pending_requests=belle_sip_list_append(ctx->pending_requests,belle_sip_object_ref(msg)); } static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){ belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj); switch(state){ case BELLE_SIP_CHANNEL_INIT: case BELLE_SIP_CHANNEL_RES_IN_PROGRESS: case BELLE_SIP_CHANNEL_RES_DONE: case BELLE_SIP_CHANNEL_CONNECTING: case BELLE_SIP_CHANNEL_READY: case BELLE_SIP_CHANNEL_RETRY: break; case BELLE_SIP_CHANNEL_ERROR: http_channel_context_handle_io_error(ctx, chan); case BELLE_SIP_CHANNEL_DISCONNECTED: if (!chan->force_close) provider_remove_channel(ctx->provider,chan); break; } } static void belle_http_channel_context_uninit(belle_http_channel_context_t *obj){ belle_sip_list_free_with_data(obj->pending_requests,belle_sip_object_unref); } static void on_channel_destroyed(belle_http_channel_context_t *obj, belle_sip_channel_t *chan_being_destroyed){ belle_sip_channel_remove_listener(chan_being_destroyed,BELLE_SIP_CHANNEL_LISTENER(obj)); belle_sip_object_unref(obj); } /* * The http channel context stores pending requests so that they can be matched with response received. * It is associated with the channel when the channel is created, and automatically destroyed when the channel is destroyed. **/ belle_http_channel_context_t * belle_http_channel_context_new(belle_sip_channel_t *chan, belle_http_provider_t *prov){ belle_http_channel_context_t *obj=belle_sip_object_new(belle_http_channel_context_t); obj->provider=prov; belle_sip_channel_add_listener(chan,(belle_sip_channel_listener_t*)obj); belle_sip_object_weak_ref(chan,(belle_sip_object_destroy_notify_t)on_channel_destroyed,obj); return obj; } BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_http_channel_context_t,belle_sip_channel_listener_t) channel_state_changed, channel_on_message_headers, channel_on_message, channel_on_sending, channel_on_auth_requested BELLE_SIP_IMPLEMENT_INTERFACE_END BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_http_channel_context_t,belle_sip_channel_listener_t); BELLE_SIP_INSTANCIATE_VPTR(belle_http_channel_context_t,belle_sip_object_t,belle_http_channel_context_uninit,NULL,NULL,FALSE); static void http_provider_uninit(belle_http_provider_t *obj){ belle_sip_message("http provider destroyed."); belle_sip_free(obj->bind_ip); belle_sip_list_for_each(obj->tcp_channels,(void (*)(void*))belle_sip_channel_force_close); belle_sip_list_free_with_data(obj->tcp_channels,belle_sip_object_unref); belle_sip_list_for_each(obj->tls_channels,(void (*)(void*))belle_sip_channel_force_close); belle_sip_list_free_with_data(obj->tls_channels,belle_sip_object_unref); belle_sip_object_unref(obj->verify_ctx); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_http_provider_t); BELLE_SIP_INSTANCIATE_VPTR(belle_http_provider_t,belle_sip_object_t,http_provider_uninit,NULL,NULL,FALSE); belle_http_provider_t *belle_http_provider_new(belle_sip_stack_t *s, const char *bind_ip){ belle_http_provider_t *p=belle_sip_object_new(belle_http_provider_t); p->stack=s; p->bind_ip=belle_sip_strdup(bind_ip); p->ai_family=strchr(p->bind_ip,':') ? AF_INET6 : AF_INET; p->verify_ctx=belle_tls_verify_policy_new(); return p; } static void split_request_url(belle_http_request_t *req){ belle_generic_uri_t *uri=belle_http_request_get_uri(req); belle_generic_uri_t *new_uri; char *host_value; const char *path; if (belle_generic_uri_get_host(uri)==NULL && req->orig_uri!=NULL) return;/*already processed request uri*/ path=belle_generic_uri_get_path(uri); if (path==NULL) path="/"; new_uri=belle_generic_uri_new(); belle_generic_uri_set_path(new_uri,path); belle_generic_uri_set_query(new_uri, belle_generic_uri_get_query(uri)); if (belle_generic_uri_get_port(uri)>0) host_value=belle_sip_strdup_printf("%s:%i",belle_generic_uri_get_host(uri),belle_generic_uri_get_port(uri)); else host_value=belle_sip_strdup(belle_generic_uri_get_host(uri)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Host",host_value)); belle_sip_free(host_value); SET_OBJECT_PROPERTY(req,orig_uri,uri); belle_http_request_set_uri(req,new_uri); } static void fix_request(belle_http_request_t *req){ unsigned int size=belle_sip_message_get_body_size((belle_sip_message_t*)req); belle_sip_header_content_length_t *ctlen=belle_sip_message_get_header_by_type(req, belle_sip_header_content_length_t); if (size>0 && !ctlen){ belle_sip_message_add_header((belle_sip_message_t*)req,(belle_sip_header_t*)belle_sip_header_content_length_create((int)size)); } } static belle_sip_list_t **provider_get_channels(belle_http_provider_t *obj, const char *transport_name){ if (strcasecmp(transport_name,"tcp")==0) return &obj->tcp_channels; else if (strcasecmp(transport_name,"tls")==0) return &obj->tls_channels; else{ belle_sip_error("belle_http_provider_send_request(): unsupported transport %s",transport_name); return NULL; } } static void provider_remove_channel(belle_http_provider_t *obj, belle_sip_channel_t *chan){ belle_sip_list_t **channels=provider_get_channels(obj,belle_sip_channel_get_transport_name(chan)); *channels=belle_sip_list_remove(*channels,chan); belle_sip_message("channel [%p] removed from http provider.",obj); belle_sip_object_unref(chan); } static void belle_http_end_background_task(void* data) { belle_http_request_t *req = BELLE_HTTP_REQUEST(data); belle_sip_warning("Ending unfinished HTTP transfer background task id=[%x]", req->background_task_id); if( req->background_task_id ){ belle_sip_end_background_task(req->background_task_id); req->background_task_id = 0; } } int belle_http_provider_send_request(belle_http_provider_t *obj, belle_http_request_t *req, belle_http_request_listener_t *listener){ belle_sip_channel_t *chan; belle_sip_hop_t *hop=belle_sip_hop_new_from_generic_uri(req->orig_uri ? req->orig_uri : req->req_uri); belle_sip_list_t **channels=provider_get_channels(obj,hop->transport); if (listener) belle_http_request_set_listener(req,listener); chan=belle_sip_channel_find_from_list(*channels,obj->ai_family, hop); if (!chan){ if (strcasecmp(hop->transport,"tcp")==0){ chan=belle_sip_stream_channel_new_client(obj->stack,obj->bind_ip,0,hop->cname,hop->host,hop->port); } #ifdef HAVE_POLARSSL else if (strcasecmp(hop->transport,"tls")==0){ chan=belle_sip_channel_new_tls(obj->stack,obj->verify_ctx,obj->bind_ip,0,hop->cname,hop->host,hop->port); } #endif if (!chan){ belle_sip_error("belle_http_provider_send_request(): cannot create channel for [%s:%s:%i]",hop->transport,hop->cname,hop->port); belle_sip_object_unref(hop); return -1; } belle_http_channel_context_new(chan,obj); *channels=belle_sip_list_prepend(*channels,chan); } belle_sip_object_unref(hop); split_request_url(req); fix_request(req); belle_http_request_set_channel(req,chan); if( req->background_task_id != 0){ req->background_task_id = belle_sip_begin_background_task("belle-sip http", belle_http_end_background_task, req); } belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req)); return 0; } static void reenqueue_request(belle_http_request_t *req, belle_http_provider_t *prov){ belle_http_provider_send_request(prov,req,req->listener); } void belle_http_provider_cancel_request(belle_http_provider_t *obj, belle_http_request_t *req){ belle_sip_list_t *outgoing_messages; belle_http_request_cancel(req); if (req->channel){ // Keep the list of the outgoing messages of the channel... outgoing_messages = belle_sip_list_copy_with_data(req->channel->outgoing_messages,(void* (*)(void*))belle_sip_object_ref); /*protect the channel from being destroyed before removing it (removing it will unref it)*/ belle_sip_object_ref(req->channel); provider_remove_channel(obj, req->channel); // ... close the channel... belle_sip_channel_force_close(req->channel); belle_sip_object_unref(req->channel); // ... and reenqueue the previously queued outgoing messages into a new channel belle_sip_list_for_each2(outgoing_messages,(void (*)(void*,void*))reenqueue_request,obj); belle_sip_list_free_with_data(outgoing_messages,belle_sip_object_unref); } } int belle_http_provider_set_tls_verify_policy(belle_http_provider_t *obj, belle_tls_verify_policy_t *verify_ctx){ SET_OBJECT_PROPERTY(obj,verify_ctx,verify_ctx); return 0; } belle-sip-1.4.1/src/ict.c000066400000000000000000000170621252242224000151040ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * INVITE client transaction implementation. **/ #include "belle_sip_internal.h" static void on_ict_terminate(belle_sip_ict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; if (obj->timer_A){ belle_sip_transaction_stop_timer(base,obj->timer_A); belle_sip_object_unref(obj->timer_A); obj->timer_A=NULL; } if (obj->timer_B){ belle_sip_transaction_stop_timer(base,obj->timer_B); belle_sip_object_unref(obj->timer_B); obj->timer_B=NULL; } if (obj->timer_D){ belle_sip_transaction_stop_timer(base,obj->timer_D); belle_sip_object_unref(obj->timer_D); obj->timer_D=NULL; } if (obj->timer_M){ belle_sip_transaction_stop_timer(base,obj->timer_M); belle_sip_object_unref(obj->timer_M); obj->timer_M=NULL; } if (obj->ack){ belle_sip_object_unref(obj->ack); obj->ack=NULL; } } static void ict_destroy(belle_sip_ict_t *obj){ on_ict_terminate(obj); } static belle_sip_request_t *make_ack(belle_sip_ict_t *obj, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; if (obj->ack==NULL){ obj->ack=belle_sip_request_new(); belle_sip_object_ref(obj->ack); belle_sip_request_set_method(obj->ack,"ACK"); belle_sip_request_set_uri(obj->ack,belle_sip_request_get_uri(base->request)); belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_VIA,FALSE); belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_CALL_ID,FALSE); belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_FROM,FALSE); belle_sip_util_copy_headers((belle_sip_message_t*)resp,(belle_sip_message_t*)obj->ack,BELLE_SIP_TO,FALSE); belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_CONTACT,TRUE); belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_ROUTE,TRUE); belle_sip_util_copy_headers((belle_sip_message_t*)base->request,(belle_sip_message_t*)obj->ack,BELLE_SIP_MAX_FORWARDS,FALSE); belle_sip_message_add_header((belle_sip_message_t*)obj->ack, (belle_sip_header_t*)belle_sip_header_cseq_create( belle_sip_header_cseq_get_seq_number((belle_sip_header_cseq_t*)belle_sip_message_get_header((belle_sip_message_t*)base->request,BELLE_SIP_CSEQ)), "ACK")); } return obj->ack; } static int ict_on_timer_D(belle_sip_ict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; if (base->state==BELLE_SIP_TRANSACTION_COMPLETED){ belle_sip_transaction_terminate(base); } return BELLE_SIP_STOP; } static int ict_on_timer_M(belle_sip_ict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; if (base->state==BELLE_SIP_TRANSACTION_ACCEPTED){ belle_sip_transaction_terminate(base); } return BELLE_SIP_STOP; } static void ict_on_response(belle_sip_ict_t *obj, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; int code=belle_sip_response_get_status_code(resp); const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); switch (base->state){ case BELLE_SIP_TRANSACTION_CALLING: belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_PROCEEDING); /* no break*/ case BELLE_SIP_TRANSACTION_PROCEEDING: if (code>=300){ belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_COMPLETED); belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)make_ack(obj,resp)); belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp); obj->timer_D=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_D,obj,cfg->T1*64); belle_sip_transaction_start_timer(base,obj->timer_D); }else if (code>=200){ obj->timer_M=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_M,obj,cfg->T1*64); belle_sip_transaction_start_timer(base,obj->timer_M); belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_ACCEPTED); belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp); }else if (code>=100){ belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp); } break; case BELLE_SIP_TRANSACTION_ACCEPTED: if (code>=200 && code<300){ belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp); } break; case BELLE_SIP_TRANSACTION_COMPLETED: if (code>=300 && obj->ack){ belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)obj->ack); } break; default: break; } } static int ict_on_timer_A(belle_sip_ict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; switch(base->state){ case BELLE_SIP_TRANSACTION_CALLING: { /*reset the timer to twice the previous value, and retransmit */ unsigned int prev_timeout=belle_sip_source_get_timeout(obj->timer_A); belle_sip_source_set_timeout(obj->timer_A,2*prev_timeout); belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request); } break; default: break; } return BELLE_SIP_CONTINUE; } static int ict_on_timer_B(belle_sip_ict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; switch (base->state){ case BELLE_SIP_TRANSACTION_CALLING: belle_sip_transaction_notify_timeout(base); break; default: break; } return BELLE_SIP_STOP; } static void ict_send_request(belle_sip_ict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_CALLING); if (!belle_sip_channel_is_reliable(base->channel)){ obj->timer_A=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_A,obj,cfg->T1); belle_sip_transaction_start_timer(base,obj->timer_A); } obj->timer_B=belle_sip_timeout_source_new((belle_sip_source_func_t)ict_on_timer_B,obj,cfg->T1*64); belle_sip_transaction_start_timer(base,obj->timer_B); belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_ict_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_ict_t) { { { BELLE_SIP_VPTR_INIT(belle_sip_ict_t,belle_sip_client_transaction_t,TRUE), (belle_sip_object_destroy_t)ict_destroy, NULL, NULL }, (void (*)(belle_sip_transaction_t*))on_ict_terminate }, (void (*)(belle_sip_client_transaction_t*))ict_send_request, (void (*)(belle_sip_client_transaction_t*,belle_sip_response_t*))ict_on_response } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_ict_t *belle_sip_ict_new(belle_sip_provider_t *prov, belle_sip_request_t *req){ belle_sip_ict_t *obj=belle_sip_object_new(belle_sip_ict_t); belle_sip_client_transaction_init((belle_sip_client_transaction_t*)obj,prov,req); return obj; } belle-sip-1.4.1/src/ist.c000066400000000000000000000147611252242224000151270ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * INVITE server transaction implementation. **/ #include "belle_sip_internal.h" static void ist_on_terminate(belle_sip_ist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; /*timer pointers are set to NULL because they can be released later*/ if (obj->timer_G){ belle_sip_transaction_stop_timer(base,obj->timer_G); belle_sip_object_unref(obj->timer_G); obj->timer_G=NULL; } if (obj->timer_H){ belle_sip_transaction_stop_timer(base,obj->timer_H); belle_sip_object_unref(obj->timer_H); obj->timer_H=NULL; } if (obj->timer_I){ belle_sip_transaction_stop_timer(base,obj->timer_I); belle_sip_object_unref(obj->timer_I); obj->timer_I=NULL; } if (obj->timer_L){ belle_sip_transaction_stop_timer(base,obj->timer_L); belle_sip_object_unref(obj->timer_L); obj->timer_L=NULL; } } static void ist_destroy(belle_sip_ist_t *obj){ ist_on_terminate(obj); } static int ist_on_timer_G(belle_sip_ist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; if (base->state==BELLE_SIP_TRANSACTION_COMPLETED){ const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); int interval=belle_sip_source_get_timeout(obj->timer_G); belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->last_response); belle_sip_source_set_timeout(obj->timer_G,MIN(2*interval,cfg->T2)); return BELLE_SIP_CONTINUE; } return BELLE_SIP_STOP; } static int ist_on_timer_H(belle_sip_ist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; if (base->state==BELLE_SIP_TRANSACTION_COMPLETED){ belle_sip_transaction_terminate(base); /*FIXME: no ACK was received, should report the faillure */ } return BELLE_SIP_STOP; } static int ist_on_timer_I(belle_sip_ist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; belle_sip_transaction_terminate(base); return BELLE_SIP_STOP; } static int ist_on_timer_L(belle_sip_ist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; belle_sip_transaction_terminate(base); return BELLE_SIP_STOP; } int belle_sip_ist_process_ack(belle_sip_ist_t *obj, belle_sip_message_t *ack){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; int ret=-1; switch(base->state){ case BELLE_SIP_TRANSACTION_COMPLETED: /*clear timer G*/ if (obj->timer_G){ belle_sip_transaction_stop_timer(base,obj->timer_G); belle_sip_object_unref(obj->timer_G); obj->timer_G=NULL; } belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_CONFIRMED); if (!belle_sip_channel_is_reliable(base->channel)){ const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); obj->timer_I=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_I,obj,cfg->T4); belle_sip_transaction_start_timer(base,obj->timer_I); }else ist_on_timer_I(obj); break; case BELLE_SIP_TRANSACTION_ACCEPTED: ret=0; /*let the ACK be reported to TU */ break; default: break; } return ret; } static int ist_send_new_response(belle_sip_ist_t *obj, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; int code=belle_sip_response_get_status_code(resp); int ret=-1; switch(base->state){ case BELLE_SIP_TRANSACTION_PROCEEDING: { const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); ret=0; belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)resp); if (code>=200 && code<300){ belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_ACCEPTED); obj->timer_L=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_L,obj,64*cfg->T1); belle_sip_transaction_start_timer(base,obj->timer_L); }else if (code>=300){ belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_COMPLETED); if (!belle_sip_channel_is_reliable(base->channel)){ obj->timer_G=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_G,obj,cfg->T1); belle_sip_transaction_start_timer(base,obj->timer_G); } obj->timer_H=belle_sip_timeout_source_new((belle_sip_source_func_t)ist_on_timer_H,obj,64*cfg->T1); belle_sip_transaction_start_timer(base,obj->timer_H); } } break; case BELLE_SIP_TRANSACTION_ACCEPTED: if (code>=200 && code<300){ ret=0; /*let the response go to transport layer*/ } default: break; } return ret; } static void ist_on_request_retransmission(belle_sip_nist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; switch(base->state){ case BELLE_SIP_TRANSACTION_PROCEEDING: case BELLE_SIP_TRANSACTION_COMPLETED: belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->last_response); break; default: break; } } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_ist_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_ist_t) { { { BELLE_SIP_VPTR_INIT(belle_sip_ist_t,belle_sip_server_transaction_t,TRUE), (belle_sip_object_destroy_t)ist_destroy, NULL, NULL }, (void (*)(belle_sip_transaction_t *))ist_on_terminate }, (int (*)(belle_sip_server_transaction_t*, belle_sip_response_t *))ist_send_new_response, (void (*)(belle_sip_server_transaction_t*))ist_on_request_retransmission, } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_ist_t *belle_sip_ist_new(belle_sip_provider_t *prov, belle_sip_request_t *req){ belle_sip_ist_t *obj=belle_sip_object_new(belle_sip_ist_t); belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; belle_sip_response_t *resp; belle_sip_server_transaction_init((belle_sip_server_transaction_t*)obj,prov,req); belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_PROCEEDING); resp=belle_sip_response_create_from_request(req,100); belle_sip_server_transaction_send_response((belle_sip_server_transaction_t*)obj,resp); return obj; } belle-sip-1.4.1/src/listeningpoint.c000066400000000000000000000203321252242224000173650ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" void belle_sip_listening_point_init(belle_sip_listening_point_t *lp, belle_sip_stack_t *s, const char *address, int port){ char *tmp; belle_sip_init_sockets(); lp->stack=s; lp->listening_uri=belle_sip_uri_create(NULL,address); belle_sip_object_ref(lp->listening_uri); belle_sip_uri_set_port(lp->listening_uri,port); belle_sip_uri_set_transport_param(lp->listening_uri,BELLE_SIP_OBJECT_VPTR(lp,belle_sip_listening_point_t)->transport); tmp=belle_sip_object_to_string((belle_sip_object_t*)BELLE_SIP_LISTENING_POINT(lp)->listening_uri); if (strchr(address,':')) { lp->ai_family=AF_INET6; } else { lp->ai_family=AF_INET; } belle_sip_message("Creating listening point [%p] on [%s]",lp, tmp); belle_sip_free(tmp); } static void belle_sip_listening_point_uninit(belle_sip_listening_point_t *lp){ char *tmp=belle_sip_object_to_string((belle_sip_object_t*)BELLE_SIP_LISTENING_POINT(lp)->listening_uri); belle_sip_listening_point_clean_channels(lp); belle_sip_message("Listening point [%p] on [%s] destroyed",lp, tmp); belle_sip_object_unref(lp->listening_uri); belle_sip_free(tmp); lp->channel_listener=NULL; /*does not unref provider*/ belle_sip_uninit_sockets(); belle_sip_listening_point_set_keep_alive(lp,-1); } void belle_sip_listening_point_add_channel(belle_sip_listening_point_t *lp, belle_sip_channel_t *chan){ chan->lp=lp; belle_sip_channel_add_listener(chan,lp->channel_listener); /*add channel listener*/ /*channel is already owned, no ref needed - REVISIT: channel should be initally unowned probably.*/ /* The channel with names must be treated with higher priority by the get_channel() method so queued on front. * This is to prevent the UDP listening point to dispatch incoming messages to channels that were created by inbound connection * where name cannot be determined. When this arrives, there can be 2 channels for the same destination IP and strange problems can occur * where requests are sent through name qualified channel and response received through name unqualified channel. */ if (chan->has_name) lp->channels=belle_sip_list_prepend(lp->channels,chan); else lp->channels=belle_sip_list_append(lp->channels,chan); } belle_sip_channel_t *belle_sip_listening_point_create_channel(belle_sip_listening_point_t *obj, const belle_sip_hop_t *hop){ belle_sip_channel_t *chan=BELLE_SIP_OBJECT_VPTR(obj,belle_sip_listening_point_t)->create_channel(obj,hop); if (chan){ belle_sip_listening_point_add_channel(obj,chan); } return chan; } void belle_sip_listening_point_remove_channel(belle_sip_listening_point_t *lp, belle_sip_channel_t *chan){ belle_sip_channel_remove_listener(chan,lp->channel_listener); lp->channels=belle_sip_list_remove(lp->channels,chan); belle_sip_object_unref(chan); } void belle_sip_listening_point_clean_channels(belle_sip_listening_point_t *lp){ int existing_channels; belle_sip_list_t* iterator; if ((existing_channels=belle_sip_list_size(lp->channels)) > 0) { belle_sip_message("Listening point destroying [%i] channels",existing_channels); } for (iterator=lp->channels;iterator!=NULL;iterator=iterator->next) { belle_sip_channel_t *chan=(belle_sip_channel_t*)iterator->data; belle_sip_channel_force_close(chan); } lp->channels=belle_sip_list_free_with_data(lp->channels,(void (*)(void*))belle_sip_object_unref); } int belle_sip_listening_point_get_channel_count(const belle_sip_listening_point_t *lp){ return belle_sip_list_size(lp->channels); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_listening_point_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_listening_point_t) { BELLE_SIP_VPTR_INIT(belle_sip_listening_point_t, belle_sip_object_t,FALSE), (belle_sip_object_destroy_t)belle_sip_listening_point_uninit, NULL, NULL }, NULL, NULL BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END const char *belle_sip_listening_point_get_ip_address(const belle_sip_listening_point_t *lp){ return belle_sip_uri_get_host(lp->listening_uri); } int belle_sip_listening_point_get_port(const belle_sip_listening_point_t *lp){ return belle_sip_uri_get_listening_port(lp->listening_uri); } const char *belle_sip_listening_point_get_transport(const belle_sip_listening_point_t *lp){ return belle_sip_uri_get_transport_param(lp->listening_uri); } const belle_sip_uri_t* belle_sip_listening_point_get_uri(const belle_sip_listening_point_t *lp) { return lp->listening_uri; } int belle_sip_listening_point_get_well_known_port(const char *transport){ if (strcasecmp(transport,"UDP")==0 || strcasecmp(transport,"TCP")==0 ) return 5060; if (strcasecmp(transport,"DTLS")==0 || strcasecmp(transport,"TLS")==0 ) return 5061; belle_sip_error("No well known port for transport %s", transport); return -1; } belle_sip_channel_t *_belle_sip_listening_point_get_channel(belle_sip_listening_point_t *lp, const belle_sip_hop_t *hop, const struct addrinfo *addr){ return belle_sip_channel_find_from_list_with_addrinfo(lp->channels,hop,addr); } belle_sip_channel_t *belle_sip_listening_point_get_channel(belle_sip_listening_point_t *lp,const belle_sip_hop_t *hop){ return belle_sip_channel_find_from_list(lp->channels,lp->ai_family,hop); } static int send_keep_alive(belle_sip_channel_t* obj) { /*keep alive*/ const char* crlfcrlf = "\r\n\r\n"; int size=strlen(crlfcrlf); int err=belle_sip_channel_send(obj,crlfcrlf,size); if (err<=0 && !belle_sip_error_code_is_would_block(-err) && err!=-EINTR){ belle_sip_error("channel [%p]: could not send [%i] bytes of keep alive from [%s://%s:%i] to [%s:%i]" ,obj ,size ,belle_sip_channel_get_transport_name(obj) ,obj->local_ip ,obj->local_port ,obj->peer_name ,obj->peer_port); return -1; }else{ belle_sip_message("channel [%p]: keep alive sent to [%s://%s:%i]" ,obj ,belle_sip_channel_get_transport_name(obj) ,obj->peer_name ,obj->peer_port); return 0; } } static int keep_alive_timer_func(void *user_data, unsigned int events) { belle_sip_listening_point_t* lp=(belle_sip_listening_point_t*)user_data; belle_sip_list_t* iterator; belle_sip_channel_t* channel; belle_sip_list_t *to_be_closed=NULL; for (iterator=lp->channels;iterator!=NULL;iterator=iterator->next) { channel=(belle_sip_channel_t*)iterator->data; if (channel->state == BELLE_SIP_CHANNEL_READY && send_keep_alive(channel)==-1) { /*only send keep alive if ready*/ to_be_closed=belle_sip_list_append(to_be_closed,channel); } } for (iterator=to_be_closed;iterator!=NULL;iterator=iterator->next){ channel=(belle_sip_channel_t*)iterator->data; channel_set_state(channel,BELLE_SIP_CHANNEL_ERROR); belle_sip_channel_close(channel); } belle_sip_list_free(to_be_closed); return BELLE_SIP_CONTINUE_WITHOUT_CATCHUP; } void belle_sip_listening_point_set_keep_alive(belle_sip_listening_point_t *lp,int ms) { if (ms <=0) { if (lp->keep_alive_timer) { belle_sip_main_loop_remove_source(lp->stack->ml,lp->keep_alive_timer); belle_sip_object_unref(lp->keep_alive_timer); lp->keep_alive_timer=NULL; } return; } if (!lp->keep_alive_timer) { lp->keep_alive_timer = belle_sip_main_loop_create_timeout(lp->stack->ml , keep_alive_timer_func , lp , ms ,"keep alive") ; } else { belle_sip_source_set_timeout(lp->keep_alive_timer,ms); } return; } int belle_sip_listening_point_get_keep_alive(const belle_sip_listening_point_t *lp) { return lp->keep_alive_timer?belle_sip_source_get_timeout(lp->keep_alive_timer):-1; } void belle_sip_listening_point_set_channel_listener(belle_sip_listening_point_t *lp,belle_sip_channel_listener_t* channel_listener) { lp->channel_listener=channel_listener; } belle-sip-1.4.1/src/listeningpoint_internal.h000066400000000000000000000131231252242224000212660ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef LISTENINGPOINT_INTERNAL_H_ #define LISTENINGPOINT_INTERNAL_H_ BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_listening_point_t,belle_sip_object_t) const char *transport; belle_sip_channel_t * (*create_channel)(belle_sip_listening_point_t *, const belle_sip_hop_t *hop); BELLE_SIP_DECLARE_CUSTOM_VPTR_END #define BELLE_SIP_LISTENING_POINT(obj) BELLE_SIP_CAST(obj,belle_sip_listening_point_t) /* Listening points: base, udp */ struct belle_sip_listening_point{ belle_sip_object_t base; belle_sip_stack_t *stack; belle_sip_list_t *channels; belle_sip_uri_t* listening_uri; belle_sip_source_t* keep_alive_timer; belle_sip_channel_listener_t* channel_listener; /*initial channel listener used for channel creation, specially for socket server*/ int ai_family; /*AF_INET or AF_INET6*/ }; BELLE_SIP_BEGIN_DECLS void belle_sip_listening_point_init(belle_sip_listening_point_t *lp, belle_sip_stack_t *s, const char *address, int port); belle_sip_channel_t *_belle_sip_listening_point_get_channel(belle_sip_listening_point_t *lp,const belle_sip_hop_t *hop, const struct addrinfo *addr); belle_sip_channel_t *belle_sip_listening_point_create_channel(belle_sip_listening_point_t *ip, const belle_sip_hop_t *hop); void belle_sip_listening_point_remove_channel(belle_sip_listening_point_t *lp, belle_sip_channel_t *chan); int belle_sip_listening_point_get_well_known_port(const char *transport); belle_sip_channel_t *belle_sip_listening_point_get_channel(belle_sip_listening_point_t *lp, const belle_sip_hop_t *hop); void belle_sip_listening_point_add_channel(belle_sip_listening_point_t *lp, belle_sip_channel_t *chan); void belle_sip_listening_point_set_channel_listener(belle_sip_listening_point_t *lp,belle_sip_channel_listener_t* channel_listener); BELLE_SIP_END_DECLS /**udp*/ typedef struct belle_sip_udp_listening_point belle_sip_udp_listening_point_t; belle_sip_channel_t * belle_sip_channel_new_udp(belle_sip_stack_t *stack, int sock, const char *bindip, int localport, const char *peername, int peerport); belle_sip_channel_t * belle_sip_channel_new_udp_with_addr(belle_sip_stack_t *stack, int sock, const char *bindip, int localport, const struct addrinfo *ai); belle_sip_listening_point_t * belle_sip_udp_listening_point_new(belle_sip_stack_t *s, const char *ipaddress, int port); BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_udp_listening_point_t,belle_sip_listening_point_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END /*stream*/ typedef struct belle_sip_stream_listening_point belle_sip_stream_listening_point_t; struct belle_sip_stream_listening_point{ belle_sip_listening_point_t base; #ifdef ENABLE_SERVER_SOCKETS belle_sip_socket_t server_sock; belle_sip_source_t *source; #endif /* ENABLE_SERVER_SOCKETS */ }; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_stream_listening_point_t,belle_sip_listening_point_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END #ifdef ENABLE_SERVER_SOCKETS void belle_sip_stream_listening_point_setup_server_socket(belle_sip_stream_listening_point_t *obj, belle_sip_source_func_t on_new_connection_cb ); void belle_sip_stream_listening_point_destroy_server_socket(belle_sip_stream_listening_point_t *lp); void belle_sip_stream_listening_point_init(belle_sip_stream_listening_point_t *obj, belle_sip_stack_t *s, const char *ipaddress, int port, belle_sip_source_func_t on_new_connection_cb ); #else void belle_sip_stream_listening_point_init(belle_sip_stream_listening_point_t *obj, belle_sip_stack_t *s, const char *ipaddress, int port ); #endif /* ENABLE_SERVER_SOCKETS */ belle_sip_listening_point_t * belle_sip_stream_listening_point_new(belle_sip_stack_t *s, const char *ipaddress, int port); /*tls*/ struct belle_sip_tls_listening_point{ belle_sip_stream_listening_point_t base; belle_tls_verify_policy_t *verify_ctx; }; int belle_sip_tls_listening_point_available(void); BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_tls_listening_point_t,belle_sip_listening_point_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END #define BELLE_SIP_TLS_LISTENING_POINT(obj) BELLE_SIP_CAST(obj,belle_sip_tls_listening_point_t) belle_sip_listening_point_t * belle_sip_tls_listening_point_new(belle_sip_stack_t *s, const char *ipaddress, int port); belle_sip_channel_t * belle_sip_channel_new_tls(belle_sip_stack_t *s, belle_tls_verify_policy_t* verify_ctx, const char *bindip, int localport,const char *cname, const char *name, int port); /*tunnel*/ #ifdef HAVE_TUNNEL typedef struct belle_sip_tunnel_listening_point belle_sip_tunnel_listening_point_t; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_tunnel_listening_point_t,belle_sip_listening_point_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END #define BELLE_SIP_TUNNEL_LISTENING_POINT(obj) BELLE_SIP_CAST(obj,belle_sip_tunnel_listening_point_t) belle_sip_channel_t * belle_sip_channel_new_tunnel(belle_sip_stack_t *s, void *tunnelclient, const char *bindip, int localport, const char *name, int port); #endif #include "transports/stream_channel.h" #endif /* LISTENINGPOINT_INTERNAL_H_ */ belle-sip-1.4.1/src/md5.c000066400000000000000000000303041252242224000150040ustar00rootroot00000000000000/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #include #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void belle_sip_md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void belle_sip_md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void belle_sip_md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ belle_sip_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ belle_sip_md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } belle-sip-1.4.1/src/md5.h000066400000000000000000000065361252242224000150230ustar00rootroot00000000000000/* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ void belle_sip_md5_init(md5_state_t *pms); /* Append a string to the message. */ void belle_sip_md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ void belle_sip_md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ belle-sip-1.4.1/src/message.c000066400000000000000000001215161252242224000157510ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "grammars/belle_sip_messageLexer.h" #include "grammars/belle_sip_messageParser.h" #include "belle_sip_internal.h" typedef struct _headers_container { char* name; belle_sip_list_t* header_list; } headers_container_t; /*reference is * http://www.iana.org/assignments/sip-parameters/sip-parameters.xhtml#sip-parameters-2 */ static const char * expand_name(const char *name){ const char *full_name=NULL; if (strlen(name)>1) return name; switch(name[0]){ case 'a': full_name="Accept-Contact"; break; case 'u': full_name="Allow-Events"; break; case 'e': full_name="Content-Encoding"; break; case 'o': full_name="Event"; break; case 'y': full_name="Identity"; break; case 'n': full_name="Identity-Info"; break; case 'r': full_name="Refer-To"; break; case 'b': full_name="Referred-By"; break; case 'j': full_name="Reject-Contact"; break; case 'd': full_name="Request-Disposition"; break; case 'x': full_name="Session-Expires"; break; case 's': full_name="Subject"; break; case 'k': full_name="Supported"; break; default: full_name=name; } return full_name; } static headers_container_t* belle_sip_message_headers_container_new(const char* name) { headers_container_t* headers_container = belle_sip_new0(headers_container_t); headers_container->name = belle_sip_strdup(expand_name(name)); return headers_container; } static void belle_sip_headers_container_delete(headers_container_t *obj){ belle_sip_free(obj->name); belle_sip_list_free_with_data(obj->header_list,(void (*)(void*))belle_sip_object_unref); belle_sip_free(obj); } static void belle_sip_message_destroy(belle_sip_message_t *msg){ belle_sip_list_free_with_data(msg->header_list,(void (*)(void*))belle_sip_headers_container_delete); if (msg->body_handler) belle_sip_object_unref(msg->body_handler); } /*very sub-optimal clone method */ static void belle_sip_message_clone(belle_sip_message_t *obj, const belle_sip_message_t *orig){ headers_container_t *c; const belle_sip_list_t *l; for(l=orig->header_list;l!=NULL;l=l->next){ c=(headers_container_t*)l->data; if (c->header_list){ belle_sip_list_t * ll=belle_sip_list_copy_with_data(c->header_list,(void *(*)(void*))belle_sip_object_clone); belle_sip_message_add_headers(obj,ll); belle_sip_list_free(ll); } } } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_message_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_message_t,belle_sip_object_t,belle_sip_message_destroy,belle_sip_message_clone,NULL,TRUE); belle_sip_message_t* belle_sip_message_parse (const char* value) { size_t message_length; return belle_sip_message_parse_raw(value,strlen(value),&message_length); } belle_sip_message_t* belle_sip_message_parse_raw (const char* buff, size_t buff_length,size_t* message_length ) { \ pANTLR3_INPUT_STREAM input; pbelle_sip_messageLexer lex; pANTLR3_COMMON_TOKEN_STREAM tokens; pbelle_sip_messageParser parser; belle_sip_message_t* l_parsed_object; input = ANTLR_STREAM_NEW("message",buff,buff_length); lex = belle_sip_messageLexerNew (input); tokens = antlr3CommonTokenStreamSourceNew (1025, lex->pLexer->rec->state->tokSource); parser = belle_sip_messageParserNew (tokens); l_parsed_object = parser->message_raw(parser,message_length); /* if (*message_length < buff_length) {*/ /*there is a body*/ /* l_parsed_object->body_length=buff_length-*message_length; l_parsed_object->body = belle_sip_malloc(l_parsed_object->body_length+1); memcpy(l_parsed_object->body,buff+*message_length,l_parsed_object->body_length); l_parsed_object->body[l_parsed_object->body_length]='\0'; }*/ parser ->free(parser); tokens ->free(tokens); lex ->free(lex); input ->close(input); return l_parsed_object; } static int belle_sip_headers_container_comp_func(const headers_container_t *a, const char*b) { return strcasecmp(a->name,b); } void belle_sip_message_init(belle_sip_message_t *message){ } headers_container_t* belle_sip_headers_container_get(const belle_sip_message_t* message,const char* header_name) { belle_sip_list_t * result = belle_sip_list_find_custom( message->header_list , (belle_sip_compare_func)belle_sip_headers_container_comp_func , header_name); return result?(headers_container_t*)(result->data):NULL; } headers_container_t * get_or_create_container(belle_sip_message_t *message, const char *header_name){ // first check if already exist headers_container_t* headers_container = belle_sip_headers_container_get(message,header_name); if (headers_container == NULL) { headers_container = belle_sip_message_headers_container_new(header_name); message->header_list=belle_sip_list_append(message->header_list,headers_container); } return headers_container; } void belle_sip_message_add_first(belle_sip_message_t *message,belle_sip_header_t* header) { headers_container_t *headers_container=get_or_create_container(message,belle_sip_header_get_name(header)); headers_container->header_list=belle_sip_list_prepend(headers_container->header_list,belle_sip_object_ref(header)); } void belle_sip_message_add_header(belle_sip_message_t *message,belle_sip_header_t* header) { headers_container_t *headers_container=get_or_create_container(message,belle_sip_header_get_name(header)); headers_container->header_list=belle_sip_list_append(headers_container->header_list,belle_sip_object_ref(header)); } void belle_sip_message_add_headers(belle_sip_message_t *message, const belle_sip_list_t *header_list){ const char *hname; headers_container_t *headers_container; if (header_list == NULL) return; hname=belle_sip_header_get_name(BELLE_SIP_HEADER((header_list->data))); headers_container=get_or_create_container(message,hname); for(;header_list!=NULL;header_list=header_list->next){ belle_sip_header_t *h=BELLE_SIP_HEADER(header_list->data); if (strcmp(belle_sip_header_get_name(h),hname)!=0){ belle_sip_fatal("Bad use of belle_sip_message_add_headers(): all headers of the list must be of the same type."); return ; } headers_container->header_list=belle_sip_list_append(headers_container->header_list,belle_sip_object_ref(h)); } } void belle_sip_message_set_header(belle_sip_message_t *msg, belle_sip_header_t* header){ headers_container_t *headers_container=get_or_create_container(msg,belle_sip_header_get_name(header)); belle_sip_object_ref(header); headers_container->header_list=belle_sip_list_free_with_data(headers_container->header_list,belle_sip_object_unref); headers_container->header_list=belle_sip_list_append(headers_container->header_list,header); } const belle_sip_list_t* belle_sip_message_get_headers(const belle_sip_message_t *message,const char* header_name) { headers_container_t* headers_container = belle_sip_headers_container_get(message,header_name); return headers_container ? headers_container->header_list:NULL; } belle_sip_object_t *_belle_sip_message_get_header_by_type_id(const belle_sip_message_t *message, belle_sip_type_id_t id){ const belle_sip_list_t *e1; for(e1=message->header_list;e1!=NULL;e1=e1->next){ headers_container_t* headers_container=(headers_container_t*)e1->data; if (headers_container->header_list){ belle_sip_object_t *ret=headers_container->header_list->data; if (ret->vptr->id==id) return ret; } } return NULL; } void belle_sip_message_remove_first(belle_sip_message_t *msg, const char *header_name){ headers_container_t* headers_container = belle_sip_headers_container_get(msg,header_name); if (headers_container && headers_container->header_list){ belle_sip_list_t *to_be_removed=headers_container->header_list; headers_container->header_list=belle_sip_list_remove_link(headers_container->header_list,to_be_removed); belle_sip_list_free_with_data(to_be_removed,belle_sip_object_unref); } } void belle_sip_message_remove_last(belle_sip_message_t *msg, const char *header_name){ headers_container_t* headers_container = belle_sip_headers_container_get(msg,header_name); if (headers_container && headers_container->header_list){ belle_sip_list_t *to_be_removed=belle_sip_list_last_elem(headers_container->header_list); headers_container->header_list=belle_sip_list_remove_link(headers_container->header_list,to_be_removed); belle_sip_list_free_with_data(to_be_removed,belle_sip_object_unref); } } void belle_sip_message_remove_header(belle_sip_message_t *msg, const char *header_name){ headers_container_t* headers_container = belle_sip_headers_container_get(msg,header_name); if (headers_container){ belle_sip_list_remove(msg->header_list,headers_container); belle_sip_headers_container_delete(headers_container); } } /* belle_sip_error_code belle_sip_message_named_headers_marshal(belle_sip_message_t *message, const char* header_name, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=BELLE_SIP_OK; belle_sip_list_t* header_list = belle_sip_message_get_headers(message,header_name); if (!header_list) { belle_sip_error("headers [%s] not found",header_name); return 0; } for(;header_list!=NULL;header_list=header_list->next){ belle_sip_header_t *h=BELLE_SIP_HEADER(header_list->data); error=belle_sip_object_marshal(BELLE_SIP_OBJECT(h),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s","\r\n"); if (error!=BELLE_SIP_OK) return error; } return error; } #define MARSHAL_AND_CHECK_HEADER(header) \ if (current_offset == (current_offset+=(header))) {\ belle_sip_error("missing mandatory header");\ return current_offset;\ } else {\ current_offset+=snprintf(buff+current_offset,buff_size-current_offset,"%s","\r\n");\ } */ typedef void (*each_header_cb)(const belle_sip_header_t* header,void* userdata); static void belle_sip_message_for_each_header(const belle_sip_message_t *message,each_header_cb cb,void* user_data) { belle_sip_list_t* headers_list; belle_sip_list_t* header_list; for(headers_list=message->header_list;headers_list!=NULL;headers_list=headers_list->next){ for(header_list=((headers_container_t*)(headers_list->data))->header_list ;header_list!=NULL ;header_list=header_list->next) { cb(BELLE_SIP_HEADER(header_list->data),user_data); } } return; } static void append_header(const belle_sip_header_t* header,void* user_data) { *(belle_sip_list_t**)user_data=belle_sip_list_append((*(belle_sip_list_t**)user_data),(void*)header); } belle_sip_list_t* belle_sip_message_get_all_headers(const belle_sip_message_t *message) { belle_sip_list_t* headers=NULL; belle_sip_message_for_each_header(message,append_header,&headers); return headers; } belle_sip_error_code belle_sip_headers_marshal(belle_sip_message_t *message, char* buff, size_t buff_size, size_t *offset) { /*FIXME, replace this code by belle_sip_message_for_each_header*/ belle_sip_list_t* headers_list; belle_sip_list_t* header_list; belle_sip_error_code error=BELLE_SIP_OK; #ifdef BELLE_SIP_WORKAROUND_TECHNICOLOR_SIP_ALG_ROUTER_BUG belle_sip_header_t *content_length=NULL; #endif for(headers_list=message->header_list;headers_list!=NULL;headers_list=headers_list->next){ for(header_list=((headers_container_t*)(headers_list->data))->header_list ;header_list!=NULL ;header_list=header_list->next) { belle_sip_header_t *h=BELLE_SIP_HEADER(header_list->data); #ifdef BELLE_SIP_WORKAROUND_TECHNICOLOR_SIP_ALG_ROUTER_BUG if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_content_length_t)){ content_length=h; }else #endif { error=belle_sip_object_marshal(BELLE_SIP_OBJECT(h),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s","\r\n"); if (error!=BELLE_SIP_OK) return error; } } } #ifdef BELLE_SIP_WORKAROUND_TECHNICOLOR_SIP_ALG_ROUTER_BUG if (content_length){ error=belle_sip_object_marshal(BELLE_SIP_OBJECT(content_length),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset,"%s","\r\n"); if (error!=BELLE_SIP_OK) return error; } #endif error=belle_sip_snprintf(buff,buff_size,offset,"%s","\r\n"); if (error!=BELLE_SIP_OK) return error; return error; } static void belle_sip_request_destroy(belle_sip_request_t* request) { if (request->method) belle_sip_free(request->method); if (request->uri) belle_sip_object_unref(request->uri); if (request->absolute_uri) belle_sip_object_unref(request->absolute_uri); if (request->dialog) belle_sip_object_unref(request->dialog); if (request->rfc2543_branch) belle_sip_free(request->rfc2543_branch); } static void belle_sip_request_init(belle_sip_request_t *message){ } static void belle_sip_request_clone(belle_sip_request_t *request, const belle_sip_request_t *orig){ if (orig->method) request->method=belle_sip_strdup(orig->method); if (orig->uri) request->uri=(belle_sip_uri_t*)belle_sip_object_ref(belle_sip_object_clone((belle_sip_object_t*)orig->uri)); if (orig->absolute_uri) request->absolute_uri=(belle_generic_uri_t*)belle_sip_object_ref(belle_sip_object_clone((belle_sip_object_t*)orig->absolute_uri)); if (orig->rfc2543_branch) request->rfc2543_branch=belle_sip_strdup(orig->rfc2543_branch); } belle_sip_error_code belle_sip_request_marshal(belle_sip_request_t* request, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_snprintf(buff,buff_size,offset,"%s ",belle_sip_request_get_method(request)); if (error!=BELLE_SIP_OK) return error; if (request->uri) error=belle_sip_uri_marshal(belle_sip_request_get_uri(request),buff,buff_size,offset); else if (request->absolute_uri) error=belle_generic_uri_marshal(belle_sip_request_get_absolute_uri(request),buff,buff_size,offset); else { belle_sip_error("Missing uri for marshaling request [%p]",request); /*fixme better to have an error code*/ error=BELLE_SIP_OK; } if (error!=BELLE_SIP_OK) return error; error=belle_sip_snprintf(buff,buff_size,offset," %s","SIP/2.0\r\n"); if (error!=BELLE_SIP_OK) return error; error=belle_sip_headers_marshal(BELLE_SIP_MESSAGE(request),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW(request,message) BELLE_SIP_PARSE(request) GET_SET_STRING(belle_sip_request,method); GET_SET_STRING(belle_sip_request,rfc2543_branch); /*caching of the dialog in the request, used when creating a request in dialog to avoid dialog lookup*/ void belle_sip_request_set_dialog(belle_sip_request_t *req, belle_sip_dialog_t *dialog){ SET_OBJECT_PROPERTY(req,dialog,dialog); } void belle_sip_request_set_uri(belle_sip_request_t* request,belle_sip_uri_t* uri) { SET_OBJECT_PROPERTY(request,uri,uri); if (request->absolute_uri && uri) { belle_sip_warning("absolute uri [%p] already set for request [%p], cleaning it",request->absolute_uri, request); belle_sip_request_set_absolute_uri(request,NULL); } } belle_sip_uri_t * belle_sip_request_get_uri(const belle_sip_request_t *request){ return request->uri; } void belle_sip_request_set_absolute_uri(belle_sip_request_t* request,belle_generic_uri_t* absolute_uri) { SET_OBJECT_PROPERTY(request,absolute_uri,absolute_uri); if (request->uri && absolute_uri) { belle_sip_warning("sip uri [%p] already set for request [%p], cleaning it",request->uri, request); belle_sip_request_set_uri(request,NULL); } } belle_generic_uri_t * belle_sip_request_get_absolute_uri(const belle_sip_request_t *request){ return request->absolute_uri; } belle_sip_uri_t* belle_sip_request_extract_origin(const belle_sip_request_t* req) { belle_sip_header_via_t* via_header = belle_sip_message_get_header_by_type(req,belle_sip_header_via_t); belle_sip_uri_t* uri=NULL; const char* received = belle_sip_header_via_get_received(via_header); int rport = belle_sip_header_via_get_rport(via_header); uri = belle_sip_uri_new(); if (received!=NULL) { belle_sip_uri_set_host(uri,received); } else { belle_sip_uri_set_host(uri,belle_sip_header_via_get_host(via_header)); } if (rport>0) { belle_sip_uri_set_port(uri,rport); } else if (belle_sip_header_via_get_port(via_header)) { belle_sip_uri_set_port(uri,belle_sip_header_via_get_port(via_header)); } if (belle_sip_header_via_get_transport(via_header)) { belle_sip_uri_set_transport_param(uri,belle_sip_header_via_get_transport_lowercase(via_header)); } return uri; } int belle_sip_message_is_request(belle_sip_message_t *msg){ return BELLE_SIP_IS_INSTANCE_OF(BELLE_SIP_OBJECT(msg),belle_sip_request_t); } int belle_sip_message_is_response(const belle_sip_message_t *msg){ return BELLE_SIP_IS_INSTANCE_OF(BELLE_SIP_OBJECT(msg),belle_sip_response_t); } belle_sip_header_t *belle_sip_message_get_header(const belle_sip_message_t *msg, const char *header_name){ const belle_sip_list_t *l=belle_sip_message_get_headers(msg,header_name); if (l!=NULL) return (belle_sip_header_t*)l->data; return NULL; } char *belle_sip_message_to_string(belle_sip_message_t *msg){ return belle_sip_object_to_string(BELLE_SIP_OBJECT(msg)); } belle_sip_body_handler_t *belle_sip_message_get_body_handler(const belle_sip_message_t *msg){ return msg->body_handler; } void belle_sip_message_set_body_handler(belle_sip_message_t *msg, belle_sip_body_handler_t *body_handler){ /* In case of multipart message, we must add the message Content-Type header containing the boundary */ if (body_handler != NULL) { if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(body_handler, belle_sip_multipart_body_handler_t)){ char *content_type = belle_sip_strdup_printf("multipart/form-data; boundary=%s",BELLESIP_MULTIPART_BOUNDARY); belle_sip_message_add_header(BELLE_SIP_MESSAGE(msg), belle_sip_header_create("Content-type",content_type)); belle_sip_free(content_type); } } SET_OBJECT_PROPERTY(msg,body_handler,body_handler); } const char* belle_sip_message_get_body(belle_sip_message_t *msg) { if (msg->body_handler==NULL) return NULL; if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(msg->body_handler, belle_sip_memory_body_handler_t)){ return (const char*)belle_sip_memory_body_handler_get_buffer( BELLE_SIP_MEMORY_BODY_HANDLER(msg->body_handler) ); } belle_sip_error("belle_sip_message_get_body(): body cannot be returned as pointer."); return NULL; } size_t belle_sip_message_get_body_size(const belle_sip_message_t *msg){ if (msg->body_handler==NULL) return 0; return belle_sip_body_handler_get_size(msg->body_handler); } void belle_sip_message_set_body(belle_sip_message_t *msg, const char* body, unsigned int size) { belle_sip_body_handler_t *bh=NULL; if (body && size) bh=(belle_sip_body_handler_t*)belle_sip_memory_body_handler_new_copy_from_buffer(body,size,NULL,NULL); belle_sip_message_set_body_handler(msg,bh); } void belle_sip_message_assign_body(belle_sip_message_t *msg, char* body, unsigned int size) { belle_sip_body_handler_t *bh=(belle_sip_body_handler_t*)belle_sip_memory_body_handler_new_from_buffer(body,size,NULL,NULL); belle_sip_message_set_body_handler(msg,bh); } struct _belle_sip_response{ belle_sip_message_t base; char *sip_version; int status_code; char *reason_phrase; }; typedef struct code_phrase{ int code; const char *phrase; } code_phrase_t; static code_phrase_t well_known_codes[]={ { 100 , "Trying" }, { 101 , "Dialog establishment" }, { 180 , "Ringing" }, { 181 , "Call is being forwarded" }, { 182 , "Queued" }, { 183 , "Session progress" }, { 200 , "Ok" }, { 202 , "Accepted" }, { 300 , "Multiple choices" }, { 301 , "Moved permanently" }, { 302 , "Moved temporarily" }, { 305 , "Use proxy" }, { 380 , "Alternate contact" }, { 400 , "Bad request" }, { 401 , "Unauthorized" }, { 402 , "Payment required" }, { 403 , "Forbidden" }, { 404 , "Not found" }, { 405 , "Method not allowed" }, { 406 , "Not acceptable" }, { 407 , "Proxy authentication required" }, { 408 , "Request timeout" }, { 410 , "Gone" }, { 412 , "Conditional Request Failed" }, /*rfc3903*/ { 413 , "Request entity too large" }, { 414 , "Request-URI too long" }, { 415 , "Unsupported media type" }, { 416 , "Unsupported URI scheme" }, { 420 , "Bad extension" }, { 421 , "Extension required" }, { 423 , "Interval too brief" }, { 480 , "Temporarily unavailable" }, { 481 , "Call/transaction does not exist" }, { 482 , "Loop detected" }, { 483 , "Too many hops" }, { 484 , "Address incomplete" }, { 485 , "Ambiguous" }, { 486 , "Busy here" }, { 487 , "Request terminated" }, { 488 , "Not acceptable here" }, { 489 , "Bad Event" }, /*rfc3265*/ { 491 , "Request pending" }, { 493 , "Undecipherable" }, { 500 , "Server internal error" }, { 501 , "Not implemented" }, { 502 , "Bad gateway" }, { 503 , "Service unavailable" }, { 504 , "Server time-out" }, { 505 , "Version not supported" }, { 513 , "Message too large" }, { 600 , "Busy everywhere" }, { 603 , "Decline" }, { 604 , "Does not exist anywhere" }, { 606 , "Not acceptable" }, { 0 , NULL } }; const char *belle_sip_get_well_known_reason_phrase(int status_code){ int i; for(i=0;well_known_codes[i].code!=0;++i){ if (well_known_codes[i].code==status_code) return well_known_codes[i].phrase; } return "Unknown reason"; } void belle_sip_response_destroy(belle_sip_response_t *resp){ if (resp->sip_version) belle_sip_free(resp->sip_version); if (resp->reason_phrase) belle_sip_free(resp->reason_phrase); } static void belle_sip_response_init(belle_sip_response_t *resp){ } static void belle_sip_response_clone(belle_sip_response_t *resp, const belle_sip_response_t *orig){ if (orig->sip_version) resp->sip_version=belle_sip_strdup(orig->sip_version); if (orig->reason_phrase) resp->reason_phrase=belle_sip_strdup(orig->reason_phrase); } belle_sip_error_code belle_sip_response_marshal(belle_sip_response_t *resp, char* buff, size_t buff_size, size_t *offset) { belle_sip_error_code error=belle_sip_snprintf( buff ,buff_size ,offset ,"SIP/2.0 %i %s\r\n" ,belle_sip_response_get_status_code(resp) ,belle_sip_response_get_reason_phrase(resp)?belle_sip_response_get_reason_phrase(resp):""); if (error!=BELLE_SIP_OK) return error; error=belle_sip_headers_marshal(BELLE_SIP_MESSAGE(resp),buff,buff_size,offset); if (error!=BELLE_SIP_OK) return error; return error; } BELLE_SIP_NEW(response,message); BELLE_SIP_PARSE(response) GET_SET_STRING(belle_sip_response,reason_phrase); GET_SET_INT(belle_sip_response,status_code,int) static int is_authorized_uri_header(const char* header_name) { /*From, Call-ID, CSeq, Via, and Record-Route*/ /*Accept, Accept-Encoding, Accept-Language, Allow, Contact (in its dialog usage), Organization, Supported, and User-Agent*/ return (strcasecmp("From",header_name) != 0 && strcasecmp("Call-ID",header_name) != 0 && strcasecmp("CSeq",header_name) != 0 && strcasecmp("Via",header_name) != 0 && strcasecmp("Record-Route",header_name) != 0 && strcasecmp("Accept",header_name) != 0 && strcasecmp("Accept-Encoding",header_name) != 0 && strcasecmp("Accept-Language",header_name) != 0 && strcasecmp("Allow",header_name) != 0 && strcasecmp("Contact",header_name) != 0 && strcasecmp("Organization",header_name) != 0 && strcasecmp("Supported",header_name) != 0 && strcasecmp("User-Agent",header_name) != 0); } belle_sip_request_t* belle_sip_request_create(belle_sip_uri_t *requri, const char* method, belle_sip_header_call_id_t *callid, belle_sip_header_cseq_t * cseq, belle_sip_header_from_t *from, belle_sip_header_to_t *to, belle_sip_header_via_t *via, int max_forward) { belle_sip_request_t *ret=belle_sip_request_new(); belle_sip_header_max_forwards_t *mf=belle_sip_header_max_forwards_new(); belle_sip_list_t* iterator; if (max_forward==0) max_forward=70; belle_sip_header_max_forwards_set_max_forwards(mf,max_forward); belle_sip_request_set_method(ret,method); belle_sip_message_add_header((belle_sip_message_t*)ret,BELLE_SIP_HEADER(via)); belle_sip_message_add_header((belle_sip_message_t*)ret,BELLE_SIP_HEADER(from)); if (to) belle_sip_message_add_header((belle_sip_message_t*)ret,BELLE_SIP_HEADER(to)); /*to might be in header uri*/ belle_sip_message_add_header((belle_sip_message_t*)ret,BELLE_SIP_HEADER(cseq)); belle_sip_message_add_header((belle_sip_message_t*)ret,BELLE_SIP_HEADER(callid)); if (!belle_sip_message_get_header_by_type(ret,belle_sip_header_max_forwards_t)) belle_sip_message_add_header((belle_sip_message_t*)ret,BELLE_SIP_HEADER(mf)); else belle_sip_object_unref(mf); /* 19.1.5 Forming Requests from a URI An implementation needs to take care when forming requests directly from a URI. URIs from business cards, web pages, and even from sources inside the protocol such as registered contacts may contain inappropriate header fields or body parts. An implementation MUST include any provided transport, maddr, ttl, or user parameter in the Request-URI of the formed request. If the URI contains a method parameter, its value MUST be used as the method of the request. The method parameter MUST NOT be placed in the Request-URI. Unknown URI parameters MUST be placed in the message's Request-URI. An implementation SHOULD treat the presence of any headers or body parts in the URI as a desire to include them in the message, and choose to honor the request on a per-component basis. An implementation SHOULD NOT honor these obviously dangerous header fields: From, Call-ID, CSeq, Via, and Record-Route. An implementation SHOULD NOT honor any requested Route header field values in order to not be used as an unwitting agent in malicious attacks. An implementation SHOULD NOT honor requests to include header fields that may cause it to falsely advertise its location or capabilities. These include: Accept, Accept-Encoding, Accept-Language, Allow, Contact (in its dialog usage), Organization, Supported, and User- Agent. An implementation SHOULD verify the accuracy of any requested descriptive header fields, including: Content-Disposition, Content- Encoding, Content-Language, Content-Length, Content-Type, Date, Mime-Version, and Timestamp.*/ if (belle_sip_uri_get_header_names(requri)) { for (iterator=(belle_sip_list_t*)belle_sip_uri_get_header_names(requri);iterator!=NULL;iterator=iterator->next) { const char* header_name=(const char*)iterator->data; /*1 check header name*/ if (is_authorized_uri_header(header_name)) { belle_sip_header_extension_t* extended_header = belle_sip_header_extension_create(header_name, belle_sip_uri_get_header(requri, header_name)); if (extended_header) { belle_sip_message_add_header((belle_sip_message_t*)ret,BELLE_SIP_HEADER(extended_header)); } } else { belle_sip_warning("Skiping uri header [%s] for request [%p]",header_name,requri); } } } belle_sip_uri_headers_clean(requri); /*remove all headers*/ belle_sip_request_set_uri(ret,requri); return ret; } static void belle_sip_response_init_default(belle_sip_response_t *resp, int status_code, const char *phrase){ resp->status_code=status_code; resp->sip_version=belle_sip_strdup("SIP/2.0"); if (phrase==NULL) phrase=belle_sip_get_well_known_reason_phrase(status_code); resp->reason_phrase=belle_sip_strdup(phrase); } /* * note: we must not assume the request to be well formed because this function may be used to generate 400 Bad request response. */ belle_sip_response_t *belle_sip_response_create_from_request(belle_sip_request_t *req, int status_code){ belle_sip_response_t *resp=belle_sip_response_new(); belle_sip_header_t *h; belle_sip_header_to_t *to; const belle_sip_list_t *vias; belle_sip_response_init_default(resp,status_code,NULL); if (status_code==100 && (h=belle_sip_message_get_header((belle_sip_message_t*)req,"timestamp"))){ belle_sip_message_add_header((belle_sip_message_t*)resp,h); } vias=belle_sip_message_get_headers ((belle_sip_message_t*)req,"via"); belle_sip_message_add_headers((belle_sip_message_t*)resp,vias); h=belle_sip_message_get_header((belle_sip_message_t*)req,"from"); if (h) belle_sip_message_add_header((belle_sip_message_t*)resp,h); h=belle_sip_message_get_header((belle_sip_message_t*)req,"to"); if (h){ if (status_code!=100){ //so that to tag can be added to=(belle_sip_header_to_t*)belle_sip_object_clone((belle_sip_object_t*)h); }else{ to=(belle_sip_header_to_t*)h; } belle_sip_message_add_header((belle_sip_message_t*)resp,(belle_sip_header_t*)to); } h=belle_sip_message_get_header((belle_sip_message_t*)req,"call-id"); if (h) belle_sip_message_add_header((belle_sip_message_t*)resp,h); h=belle_sip_message_get_header((belle_sip_message_t*)req,"cseq"); if (h){ belle_sip_message_add_header((belle_sip_message_t*)resp,h); } return resp; } /* 12.1.1 UAS behavior When a UAS responds to a request with a response that establishes a dialog (such as a 2xx to INVITE), the UAS MUST copy all Record-Route header field values from the request into the response (including the URIs, URI parameters, and any Record-Route header field parameters, whether they are known or unknown to the UAS) and MUST maintain the order of those values. */ void belle_sip_response_fill_for_dialog(belle_sip_response_t *obj, belle_sip_request_t *req){ const belle_sip_list_t *rr=belle_sip_message_get_headers((belle_sip_message_t*)req,BELLE_SIP_RECORD_ROUTE); belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(obj,belle_sip_header_contact_t); belle_sip_message_remove_header((belle_sip_message_t*)obj,BELLE_SIP_RECORD_ROUTE); if (rr) belle_sip_message_add_headers((belle_sip_message_t*)obj,rr); if (belle_sip_response_get_status_code(obj)>=200 && belle_sip_response_get_status_code(obj)<300 && !ct){ const char *method=belle_sip_request_get_method(req); if (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0){ /*add a dummy contact to be filled by channel later*/ belle_sip_message_add_header((belle_sip_message_t*)obj,(belle_sip_header_t*)belle_sip_header_contact_new()); } } } belle_sip_hop_t* belle_sip_response_get_return_hop(belle_sip_response_t *msg){ belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header(BELLE_SIP_MESSAGE(msg),"via")); if (via){ const char *host=belle_sip_header_via_get_received(via) ? belle_sip_header_via_get_received(via) : belle_sip_header_via_get_host(via); int port=belle_sip_header_via_get_rport(via)>0 ? belle_sip_header_via_get_rport(via) : belle_sip_header_via_get_listening_port(via); return belle_sip_hop_new(belle_sip_header_via_get_transport_lowercase(via),NULL,host,port); } return NULL; } int belle_sip_response_fix_contact(const belle_sip_response_t* response,belle_sip_header_contact_t* contact) { belle_sip_header_via_t* via_header; belle_sip_uri_t* contact_uri; const char* received; int rport; int contact_port; /*first check received/rport*/ via_header= (belle_sip_header_via_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_VIA); received = belle_sip_header_via_get_received(via_header); rport = belle_sip_header_via_get_rport(via_header); contact_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact)); if (received) { /*need to update host*/ belle_sip_uri_set_host(contact_uri,received); } else { belle_sip_uri_set_host(contact_uri,belle_sip_header_via_get_host(via_header)); } contact_port = belle_sip_uri_get_port(contact_uri); if (rport>0 ) { /*need to update port*/ if ((rport+contact_port)!=5060) belle_sip_uri_set_port(contact_uri,rport); } else if ((belle_sip_header_via_get_port(via_header)+contact_port)!=5060) { belle_sip_uri_set_port(contact_uri,belle_sip_header_via_get_port(via_header)); } /*try to fix transport if needed (very unlikely)*/ if (strcasecmp(belle_sip_header_via_get_transport(via_header),"UDP")!=0) { if (!belle_sip_uri_get_transport_param(contact_uri) ||strcasecmp(belle_sip_uri_get_transport_param(contact_uri),belle_sip_header_via_get_transport(via_header))!=0) { belle_sip_uri_set_transport_param(contact_uri,belle_sip_header_via_get_transport_lowercase(via_header)); } } else { if (belle_sip_uri_get_transport_param(contact_uri)) { belle_sip_uri_set_transport_param(contact_uri,NULL); } } return 0; } belle_sip_request_t * belle_sip_request_clone_with_body(const belle_sip_request_t *initial_req) { belle_sip_request_t* req=BELLE_SIP_REQUEST(belle_sip_object_clone(BELLE_SIP_OBJECT(initial_req))); if (initial_req->base.body_handler) req->base.body_handler=BELLE_SIP_BODY_HANDLER(belle_sip_object_clone_and_ref( (belle_sip_object_t*)initial_req->base.body_handler)); return req; } typedef struct message_header_list { const char* method; const char* headers[10]; /*MAX headers*/ } message_header_list_t; /** RFC 3261 SIP: Session Initiation Protocol June 2002 Header field where proxy ACK BYE CAN INV OPT REG __________________________________________________________________ Accept R - o - o m* o Accept 2xx - - - o m* o Accept 415 - c - c c c Accept-Encoding R - o - o o o Accept-Encoding 2xx - - - o m* o Accept-Encoding 415 - c - c c c Accept-Language R - o - o o o Accept-Language 2xx - - - o m* o Accept-Language 415 - c - c c c Alert-Info R ar - - - o - - Alert-Info 180 ar - - - o - - Allow R - o - o o o Allow 2xx - o - m* m* o Allow r - o - o o o Allow 405 - m - m m m Authentication-Info 2xx - o - o o o Authorization R o o o o o o Call-ID c r m m m m m m Call-Info ar - - - o o o Contact R o - - m o o Contact 1xx - - - o - - Contact 2xx - - - m o o Contact 3xx d - o - o o o Contact 485 - o - o o o Content-Disposition o o - o o o Content-Encoding o o - o o o Content-Language o o - o o o Content-Length ar t t t t t t Content-Type * * - * * * CSeq c r m m m m m m Date a o o o o o o Error-Info 300-699 a - o o o o o Expires - - - o - o From c r m m m m m m In-Reply-To R - - - o - - Max-Forwards R amr m m m m m m Min-Expires 423 - - - - - m MIME-Version o o - o o o Organization ar - - - o o o Priority R ar - - - o - - Proxy-Authenticate 407 ar - m - m m m Proxy-Authenticate 401 ar - o o o o o Proxy-Authorization R dr o o - o o o Proxy-Require R ar - o - o o o Record-Route R ar o o o o o - Record-Route 2xx,18x mr - o o o o - Reply-To - - - o - - Require ar - c - c c c Retry-After 404,413,480,486 - o o o o o 500,503 - o o o o o 600,603 - o o o o o Route R adr c c c c c c Server r - o o o o o Subject R - - - o - - Supported R - o o m* o o Supported 2xx - o o m* m* o Timestamp o o o o o o To c(1) r m m m m m m Unsupported 420 - m - m m m User-Agent o o o o o o Via R amr m m m m m m Via rc dr m m m m m m Warning r - o o o o o WWW-Authenticate 401 ar - m - m m m WWW-Authenticate 407 ar - o - o o o Table 3: Summary of header fields, A--Z; (1): copied with possible addition of tag */ static message_header_list_t mandatory_headers[] = { {"REGISTER",{"Call-ID","CSeq","From", "Max-Forwards","To","Via",NULL}}, {"INVITE",{"Contact","Call-ID","CSeq","From", "Max-Forwards","To","Via",NULL}}, {"CANCEL",{"Call-ID","CSeq","From", "Max-Forwards","To","Via",NULL}}, {"BYE",{"Call-ID","CSeq","From", "Max-Forwards","To","Via",NULL}}, {"ACK",{"Call-ID","CSeq","From", "Max-Forwards","To","Via",NULL}}, {"*", { "To", "From", "CSeq", "Via", NULL}}, /* catch-all, these fields are required all the time. */ {NULL,{NULL}} }; /*static int belle_sip_message_is_mandatody_header(const char* method, const char* header_name) { int i; for (i=0;mandatory_headers[i].method!=NULL;i++) { if (strcasecmp(method,mandatory_headers[i].method)==0) { int j; for(j=0;mandatory_headers[i].headers[j]!=NULL;j++) { if (strcasecmp(header_name,mandatory_headers[i].headers[j])==0) { return 1; } } } } return 0; } */ int belle_sip_message_check_headers(const belle_sip_message_t* message) { if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(message,belle_sip_request_t)) { int i; belle_sip_header_via_t *via; const char * method = belle_sip_request_get_method(BELLE_SIP_REQUEST(message)); for (i=0;mandatory_headers[i].method!=NULL;i++) { if ( (strcasecmp(method,mandatory_headers[i].method)==0) || (mandatory_headers[i].method[0] == '*') ){ int j; for(j=0;mandatory_headers[i].headers[j]!=NULL;j++) { if (belle_sip_message_get_header(message,mandatory_headers[i].headers[j])==NULL) { belle_sip_error("Missing mandatory header [%s] for message [%s]",mandatory_headers[i].headers[j],method); return 0; } } return 1; } } via=belle_sip_message_get_header_by_type(message,belle_sip_header_via_t); if (!via || belle_sip_header_via_get_branch(via)==NULL) return 0; } /*else fixme should also check responses*/ return 1; } int belle_sip_request_check_uris_components(const belle_sip_request_t* request) { belle_sip_list_t* new_list = belle_sip_message_get_all_headers(BELLE_SIP_MESSAGE(request)); belle_sip_list_t* iterator = new_list; for (;iterator!=NULL;iterator=iterator->next) { belle_sip_header_t* header=(belle_sip_header_t*)iterator->data; if (BELLE_SIP_IS_INSTANCE_OF(header,belle_sip_header_address_t)) { belle_sip_uri_t* uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)); if (uri && !belle_sip_uri_check_components_from_context(uri,belle_sip_request_get_method(request),belle_sip_header_get_name(header))) { char* header_string=belle_sip_object_to_string(header); belle_sip_error("Malformed header [%s] for request [%p]",header_string,request); belle_sip_free(header_string); belle_sip_list_free(new_list); return FALSE; } } } belle_sip_list_free(new_list); return belle_sip_uri_check_components_from_request_uri(belle_sip_request_get_uri((const belle_sip_request_t*)request)); } belle-sip-1.4.1/src/nict.c000066400000000000000000000136171252242224000152640ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * non-INVITE client transaction implementation. **/ #include "belle_sip_internal.h" static int nict_on_timer_K(belle_sip_nict_t *obj){ belle_sip_transaction_terminate((belle_sip_transaction_t*)obj); return BELLE_SIP_STOP; } static void nict_set_completed(belle_sip_nict_t *obj, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_COMPLETED); if (obj->timer_K) belle_sip_fatal("Should never happen."); belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp); if (!belle_sip_channel_is_reliable(base->channel)){ obj->timer_K=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_K,obj,cfg->T4); belle_sip_object_set_name((belle_sip_object_t*)obj->timer_K,"timer_K"); belle_sip_transaction_start_timer(base,obj->timer_K); }else belle_sip_transaction_terminate(base); } static void nict_on_response(belle_sip_nict_t *obj, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; int code=belle_sip_response_get_status_code(resp); switch(base->state){ case BELLE_SIP_TRANSACTION_TRYING: if (code<200){ belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_PROCEEDING); belle_sip_client_transaction_notify_response((belle_sip_client_transaction_t*)obj,resp); } else { nict_set_completed(obj,resp); } break; case BELLE_SIP_TRANSACTION_PROCEEDING: if (code>=200){ nict_set_completed(obj,resp); } break; default: break; } } static void nict_on_terminate(belle_sip_nict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; if (obj->timer_F){ belle_sip_transaction_stop_timer(base,obj->timer_F); belle_sip_object_unref(obj->timer_F); obj->timer_F=NULL; } if (obj->timer_E){ belle_sip_transaction_stop_timer(base,obj->timer_E); belle_sip_object_unref(obj->timer_E); obj->timer_E=NULL; } if (obj->timer_K){ belle_sip_transaction_stop_timer(base,obj->timer_K); belle_sip_object_unref(obj->timer_K); obj->timer_K=NULL; } } static int nict_on_timer_F(belle_sip_nict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; switch (base->state){ case BELLE_SIP_TRANSACTION_TRYING: case BELLE_SIP_TRANSACTION_PROCEEDING: belle_sip_transaction_notify_timeout(base); break; default: break; } return BELLE_SIP_STOP; } static int nict_on_timer_E(belle_sip_nict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); switch(base->state){ case BELLE_SIP_TRANSACTION_TRYING: { /*reset the timer */ unsigned int prev_timeout=belle_sip_source_get_timeout(obj->timer_E); belle_sip_source_set_timeout(obj->timer_E,MIN(2*prev_timeout,(unsigned int)cfg->T2)); belle_sip_message("nict_on_timer_E: sending retransmission"); belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request); } break; case BELLE_SIP_TRANSACTION_PROCEEDING: belle_sip_source_set_timeout(obj->timer_E,cfg->T2); belle_sip_message("nict_on_timer_E: sending retransmission"); belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request); break; default: /*if we are not in these cases, timer_E does nothing, so remove it*/ return BELLE_SIP_STOP; break; } return BELLE_SIP_CONTINUE; } static void nict_send_request(belle_sip_nict_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_TRYING); obj->timer_F=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_F,obj,cfg->T1*64); belle_sip_object_set_name((belle_sip_object_t*)obj->timer_F,"timer_F"); belle_sip_transaction_start_timer(base,obj->timer_F); if (!belle_sip_channel_is_reliable(base->channel)){ obj->timer_E=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_E,obj,cfg->T1); belle_sip_object_set_name((belle_sip_object_t*)obj->timer_E,"timer_E"); belle_sip_transaction_start_timer(base,obj->timer_E); } belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request); } static void nict_destroy(belle_sip_nict_t *obj){ nict_on_terminate(obj); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_nict_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_nict_t) { { { BELLE_SIP_VPTR_INIT(belle_sip_nict_t,belle_sip_client_transaction_t,TRUE), (belle_sip_object_destroy_t)nict_destroy, NULL, NULL }, (void (*)(belle_sip_transaction_t *))nict_on_terminate }, (void (*)(belle_sip_client_transaction_t*))nict_send_request, (void (*)(belle_sip_client_transaction_t*,belle_sip_response_t*))nict_on_response } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_nict_t *belle_sip_nict_new(belle_sip_provider_t *prov, belle_sip_request_t *req){ belle_sip_nict_t *obj=belle_sip_object_new(belle_sip_nict_t); belle_sip_client_transaction_init((belle_sip_client_transaction_t*)obj,prov,req); return obj; } belle-sip-1.4.1/src/nist.c000066400000000000000000000100521252242224000152720ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * non-INVITE server transaction implementation. **/ #include "belle_sip_internal.h" static void nist_on_terminate(belle_sip_nist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; if (obj->timer_J){ belle_sip_transaction_stop_timer(base,obj->timer_J); belle_sip_object_unref(obj->timer_J); obj->timer_J=NULL; } } static void nist_destroy(belle_sip_nist_t *obj){ nist_on_terminate(obj); } static int nist_on_timer_J(belle_sip_nist_t *obj){ belle_sip_transaction_terminate((belle_sip_transaction_t *)obj); return BELLE_SIP_STOP; } static void nist_set_completed(belle_sip_nist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base); int tval; if (!belle_sip_channel_is_reliable(base->channel)) tval=cfg->T1*64; else tval=0; obj->timer_J=belle_sip_timeout_source_new((belle_sip_source_func_t)nist_on_timer_J,obj,tval); belle_sip_transaction_start_timer(base,obj->timer_J); belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_COMPLETED); } static int nist_send_new_response(belle_sip_nist_t *obj, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; int code=belle_sip_response_get_status_code(resp); int ret=0; switch(base->state){ case BELLE_SIP_TRANSACTION_TRYING: if (code<200){ belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_PROCEEDING); belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)resp); break; } /* no break nist can directly pass from TRYING to PROCEEDING*/ case BELLE_SIP_TRANSACTION_PROCEEDING: if (code>=200){ nist_set_completed(obj); } belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)resp); break; case BELLE_SIP_TRANSACTION_COMPLETED: belle_sip_warning("nist_send_new_response(): not allowed to send a response while transaction is completed."); ret=-1; /*not allowed to send a response at this time*/ break; default: //ignore break; } return ret; } static void nist_on_request_retransmission(belle_sip_nist_t *obj){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; switch(base->state){ case BELLE_SIP_TRANSACTION_PROCEEDING: case BELLE_SIP_TRANSACTION_COMPLETED: belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->last_response); break; default: //ignore break; } } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_nist_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_nist_t) { { { BELLE_SIP_VPTR_INIT(belle_sip_nist_t,belle_sip_server_transaction_t,TRUE), (belle_sip_object_destroy_t)nist_destroy, NULL, NULL }, (void (*)(belle_sip_transaction_t *))nist_on_terminate }, (int (*)(belle_sip_server_transaction_t*, belle_sip_response_t *))nist_send_new_response, (void (*)(belle_sip_server_transaction_t*))nist_on_request_retransmission, } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_nist_t *belle_sip_nist_new(belle_sip_provider_t *prov, belle_sip_request_t *req){ belle_sip_nist_t *obj=belle_sip_object_new(belle_sip_nist_t); belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj; belle_sip_server_transaction_init((belle_sip_server_transaction_t*)obj,prov,req); belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_TRYING); return obj; } belle-sip-1.4.1/src/parserutils.h000066400000000000000000000042341252242224000167040ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_parserutils_h #define belle_sip_parserutils_h #include "port.h" #define IS_TOKEN(token) \ (INPUT->toStringTT(INPUT,LT(1),LT(strlen(#token)))->chars ?\ strcasecmp(#token,(const char*)(INPUT->toStringTT(INPUT,LT(1),LT(strlen(#token)))->chars)) == 0:0) #define IS_HEADER_NAMED(name,compressed_name) (IS_TOKEN(compressed_name) || IS_TOKEN(name)) #define STRCASECMP_HEADER_NAMED(name,compressed_name,value) \ (strcasecmp(compressed_name,(const char*)value) == 0 || strcasecmp(name,(const char*)value) == 0 ) BELLESIP_INTERNAL_EXPORT belle_sip_header_t* belle_sip_header_get_next(const belle_sip_header_t* headers); BELLESIP_INTERNAL_EXPORT void belle_sip_header_set_next(belle_sip_header_t* header,belle_sip_header_t* next); BELLESIP_INTERNAL_EXPORT char* belle_sip_to_unescaped_string(const char* buff); belle_sip_param_pair_t* belle_sip_param_pair_new(const char* name,const char* value); char* _belle_sip_str_dup_and_unquote_string(const char* quoted_string); /** * quoted-string = SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE qdtext = LWS / %x21 / %x23-5B / %x5D-7E / UTF8-NONASCII quoted-pair = "\" (%x00-09 / %x0B-0C / %x0E-7F) remove any \ * */ BELLESIP_INTERNAL_EXPORT char* belle_sip_string_to_backslash_less_unescaped_string(const char* buff); BELLESIP_INTERNAL_EXPORT char* belle_sip_display_name_to_backslashed_escaped_string(const char* buff); #endif belle-sip-1.4.1/src/port.c000066400000000000000000000235221252242224000153070ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #ifdef WIN32 #include #include #ifdef HAVE_COMPILER_TLS static __declspec(thread) const void *current_thread_data = NULL; #endif static int sockets_initd=0; int belle_sip_init_sockets(void){ if (sockets_initd==0){ WSADATA data; int err = WSAStartup(MAKEWORD(2,2), &data); if (err != 0) { belle_sip_error("WSAStartup failed with error: %d\n", err); return -1; } } sockets_initd++; return 0; } void belle_sip_uninit_sockets(void){ sockets_initd--; if (sockets_initd==0) WSACleanup(); } typedef struct thread_param { void * (*func)(void *); void * arg; } thread_param_t; static unsigned WINAPI thread_starter(void *data) { thread_param_t *params = (thread_param_t*)data; void *ret = params->func(params->arg); belle_sip_free(data); return (DWORD)ret; } int belle_sip_thread_create(belle_sip_thread_t *thread, void *attr, void * (*func)(void *), void *data) { thread_param_t *params = belle_sip_new(thread_param_t); params->func = func; params->arg = data; *thread = (HANDLE)_beginthreadex(NULL, 0, thread_starter, params, 0, NULL); return 0; } int belle_sip_thread_join(belle_sip_thread_t thread, void **unused) { if (thread != NULL) { WaitForSingleObjectEx(thread, INFINITE, FALSE); CloseHandle(thread); } return 0; } int belle_sip_mutex_init(belle_sip_mutex_t *mutex, void *attr) { #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) *mutex = CreateMutex(NULL, FALSE, NULL); #else InitializeSRWLock(mutex); #endif return 0; } int belle_sip_mutex_lock(belle_sip_mutex_t * hMutex) { #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) WaitForSingleObject(*hMutex, INFINITE); #else AcquireSRWLockExclusive(hMutex); #endif return 0; } int belle_sip_mutex_unlock(belle_sip_mutex_t * hMutex) { #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) ReleaseMutex(*hMutex); #else ReleaseSRWLockExclusive(hMutex); #endif return 0; } int belle_sip_mutex_destroy(belle_sip_mutex_t * hMutex) { #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) CloseHandle(*hMutex); #endif return 0; } int belle_sip_socket_set_nonblocking(belle_sip_socket_t sock) { unsigned long nonBlock = 1; return ioctlsocket(sock, FIONBIO , &nonBlock); } int belle_sip_socket_set_dscp(belle_sip_socket_t sock, int ai_family, int dscp){ belle_sip_warning("belle_sip_socket_set_dscp(): not implemented."); return -1; } const char *belle_sip_get_socket_error_string(){ return belle_sip_get_socket_error_string_from_code(WSAGetLastError()); } const char *belle_sip_get_socket_error_string_from_code(int code){ static TCHAR msgBuf[256]; #ifdef _UNICODE static WCHAR wMsgBuf[256]; int ret; FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, 0, // Default language (LPWSTR) &wMsgBuf, sizeof(wMsgBuf), NULL); ret = wcstombs(msgBuf, wMsgBuf, sizeof(msgBuf)); if (ret == sizeof(msgBuf)) msgBuf[sizeof(msgBuf) - 1] = '\0'; #else FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code, 0, // Default language (LPTSTR) &msgBuf, sizeof(msgBuf), NULL); /*FIXME: should convert from TCHAR to UTF8 */ #endif return (const char *)msgBuf; } int belle_sip_thread_key_create(belle_sip_thread_key_t *key, void (*destructor)(void*) ){ #ifdef HAVE_COMPILER_TLS *key = (belle_sip_thread_key_t)¤t_thread_data; #else *key=TlsAlloc(); if (*key==TLS_OUT_OF_INDEXES){ belle_sip_error("TlsAlloc(): TLS_OUT_OF_INDEXES."); return -1; } #endif return 0; } int belle_sip_thread_setspecific(belle_sip_thread_key_t key,const void *value){ #ifdef HAVE_COMPILER_TLS current_thread_data = value; return 0; #else return TlsSetValue(key,(void*)value) ? 0 : -1; #endif } const void* belle_sip_thread_getspecific(belle_sip_thread_key_t key){ #ifdef HAVE_COMPILER_TLS return current_thread_data; #else return TlsGetValue(key); #endif } int belle_sip_thread_key_delete(belle_sip_thread_key_t key){ #ifdef HAVE_COMPILER_TLS current_thread_data = NULL; return 0; #else return TlsFree(key) ? 0 : -1; #endif } #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) void belle_sip_sleep(unsigned int ms) { HANDLE sleepEvent = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); if (!sleepEvent) return; WaitForSingleObjectEx(sleepEvent, ms, FALSE); } #endif #else #include int belle_sip_init_sockets(){ signal(SIGPIPE,SIG_IGN); return 0; } void belle_sip_uninit_sockets(){ } int belle_sip_socket_set_nonblocking(belle_sip_socket_t sock){ return fcntl (sock, F_SETFL, fcntl(sock,F_GETFL) | O_NONBLOCK); } int belle_sip_socket_set_dscp(belle_sip_socket_t sock, int ai_family, int dscp){ int tos; int proto; int value_type; int retval; tos = (dscp << 2) & 0xFC; switch (ai_family) { case AF_INET: proto=IPPROTO_IP; value_type=IP_TOS; break; case AF_INET6: proto=IPPROTO_IPV6; #ifdef IPV6_TCLASS /*seems not defined by my libc*/ value_type=IPV6_TCLASS; #else value_type=IP_TOS; #endif break; default: belle_sip_error("Cannot set DSCP because socket family is unspecified."); return -1; } retval = setsockopt(sock, proto, value_type, (const char*)&tos, sizeof(tos)); if (retval==-1) belle_sip_error("Fail to set DSCP value on socket: %s",belle_sip_get_socket_error_string()); return retval; } #endif int belle_sip_socket_enable_dual_stack(belle_sip_socket_t sock){ int value=0; int err=setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&value, sizeof(value)); if (err==-1){ belle_sip_warning("belle_sip_socket_enable_dual_stack: setsockopt(IPV6_ONLY) failed: %s",belle_sip_get_socket_error_string()); } return err; } #if defined(ANDROID) || defined(WIN32) /* * SHAME !!! bionic's getaddrinfo does not implement the AI_V4MAPPED flag ! * It is declared in header file but rejected by the implementation. * The code below is to emulate a _compliant_ getaddrinfo for android. **/ /** * SHAME AGAIN !!! Win32's implementation of getaddrinfo is bogus ! * it is not able to return an IPv6 addrinfo from an IPv4 address when AI_V4MAPPED is set ! **/ struct addrinfo *_belle_sip_alloc_addrinfo(int ai_family, int socktype, int proto){ struct addrinfo *ai=(struct addrinfo*)belle_sip_malloc0(sizeof(struct addrinfo)); ai->ai_family=ai_family; ai->ai_socktype=socktype; ai->ai_protocol=proto; ai->ai_addrlen=AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); ai->ai_addr=(struct sockaddr *) belle_sip_malloc0(ai->ai_addrlen); return ai; } struct addrinfo *convert_to_v4mapped(const struct addrinfo *ai){ struct addrinfo *res=NULL; const struct addrinfo *it; struct addrinfo *v4m=NULL; struct addrinfo *last=NULL; for (it=ai;it!=NULL;it=it->ai_next){ struct sockaddr_in6 *sin6; struct sockaddr_in *sin; v4m=_belle_sip_alloc_addrinfo(AF_INET6, it->ai_socktype, it->ai_protocol); v4m->ai_flags|=AI_V4MAPPED; sin6=(struct sockaddr_in6*)v4m->ai_addr; sin=(struct sockaddr_in*)it->ai_addr; sin6->sin6_family=AF_INET6; ((uint8_t*)&sin6->sin6_addr)[10]=0xff; ((uint8_t*)&sin6->sin6_addr)[11]=0xff; memcpy(((uint8_t*)&sin6->sin6_addr)+12,&sin->sin_addr,4); sin6->sin6_port=sin->sin_port; if (last){ last->ai_next=v4m; }else{ res=v4m; } last=v4m; } return res; } struct addrinfo *addrinfo_concat(struct addrinfo *a1, struct addrinfo *a2){ struct addrinfo *it; struct addrinfo *last=NULL; for (it=a1;it!=NULL;it=it->ai_next){ last=it; } if (last){ last->ai_next=a2; return a1; }else return a2; } int belle_sip_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){ if (hints && hints->ai_family!=AF_INET && hints->ai_flags & AI_V4MAPPED){ struct addrinfo *res6=NULL; struct addrinfo *res4=NULL; struct addrinfo lhints={0}; int err; if (hints) memcpy(&lhints,hints,sizeof(lhints)); lhints.ai_flags &= ~(AI_ALL | AI_V4MAPPED); /*remove the unsupported flags*/ if (hints->ai_flags & AI_ALL){ lhints.ai_family=AF_INET6; err=getaddrinfo(node, service, &lhints, &res6); } lhints.ai_family=AF_INET; err=getaddrinfo(node, service, &lhints, &res4); if (err==0){ struct addrinfo *v4m=convert_to_v4mapped(res4); freeaddrinfo(res4); res4=v4m; } *res=addrinfo_concat(res6,res4); if (*res) err=0; return err; } return getaddrinfo(node, service, hints, res); } void _belle_sip_freeaddrinfo(struct addrinfo *res){ struct addrinfo *it,*next_it; for(it=res;it!=NULL;it=next_it){ next_it=it->ai_next; belle_sip_free(it->ai_addr); belle_sip_free(it); } } void belle_sip_freeaddrinfo(struct addrinfo *res){ struct addrinfo *it,*previt=NULL; struct addrinfo *allocated_by_belle_sip=NULL; for(it=res;it!=NULL;it=it->ai_next){ if (it->ai_flags & AI_V4MAPPED){ allocated_by_belle_sip=it; if (previt) previt->ai_next=NULL; break; } previt=it; } if (res!=allocated_by_belle_sip) freeaddrinfo(res); if (allocated_by_belle_sip) _belle_sip_freeaddrinfo(allocated_by_belle_sip); } #else int belle_sip_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){ return getaddrinfo(node, service, hints, res); } void belle_sip_freeaddrinfo(struct addrinfo *res){ freeaddrinfo(res); } #endif belle-sip-1.4.1/src/port.h000066400000000000000000000135411252242224000153140ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef belle_sip_port_h #define belle_sip_port_h #include #ifndef WIN32 #include #include #include #include #include #include #include #include #include #else #include #include #define strcasecmp _stricmp #ifdef _MSC_VER #define snprintf _snprintf #define vsnprintf _vsnprintf #define strdup _strdup #else #include #endif /*AI_NUMERICSERV is not defined for windows XP. Since it is not essential, we define it to 0 (does nothing)*/ #ifndef AI_NUMERICSERV #define AI_NUMERICSERV 0 #endif #endif #if defined(WIN32) || defined(__QNX__) /* Mingw32 does not define AI_V4MAPPED, however it is supported starting from Windows Vista. QNX also does not define AI_V4MAPPED. */ # ifndef AI_V4MAPPED # define AI_V4MAPPED 0x00000800 # endif # ifndef AI_ALL # define AI_ALL 0x00000100 # endif # ifndef IPV6_V6ONLY # define IPV6_V6ONLY 27 # endif #endif #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) #ifdef BELLESIP_INTERNAL_EXPORTS #define BELLESIP_INTERNAL_EXPORT __declspec(dllexport) #else #define BELLESIP_INTERNAL_EXPORT #endif #else #define BELLESIP_INTERNAL_EXPORT extern #endif /* * Socket abstraction layer */ BELLESIP_INTERNAL_EXPORT int belle_sip_init_sockets(void); BELLESIP_INTERNAL_EXPORT void belle_sip_uninit_sockets(void); int belle_sip_socket_set_nonblocking (belle_sip_socket_t sock); int belle_sip_socket_set_dscp(belle_sip_socket_t sock, int ai_family, int dscp); int belle_sip_socket_enable_dual_stack(belle_sip_socket_t sock); #if defined(WIN32) #if !defined(WINAPI_FAMILY_PARTITION) // Only use with x being WINAPI_PARTITION_DESKTOP to test if building on desktop #define WINAPI_FAMILY_PARTITION(x) 1 #endif typedef HANDLE belle_sip_thread_t; #define belle_sip_thread_self_id() (unsigned long)GetCurrentThreadId() #define belle_sip_thread_get_id(thread) (unsigned long)GetThreadId(thread) typedef DWORD belle_sip_thread_key_t; int belle_sip_thread_key_create(belle_sip_thread_key_t *key, void (*destructor)(void*) ); int belle_sip_thread_setspecific(belle_sip_thread_key_t key,const void *value); const void* belle_sip_thread_getspecific(belle_sip_thread_key_t key); int belle_sip_thread_key_delete(belle_sip_thread_key_t key); static BELLESIP_INLINE void close_socket(belle_sip_socket_t s){ closesocket(s); } static BELLESIP_INLINE int get_socket_error(void){ return WSAGetLastError(); } const char *belle_sip_get_socket_error_string(); const char *belle_sip_get_socket_error_string_from_code(int code); /* * Thread abstraction layer */ #ifdef WIN32 typedef HANDLE belle_sip_thread_t; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) typedef HANDLE belle_sip_mutex_t; #else typedef SRWLOCK belle_sip_mutex_t; #endif int belle_sip_thread_join(belle_sip_thread_t thread, void **retptr); int belle_sip_thread_create(belle_sip_thread_t *thread, void *attr, void * (*routine)(void*), void *arg); int belle_sip_mutex_init(belle_sip_mutex_t *m, void *attr_unused); int belle_sip_mutex_lock(belle_sip_mutex_t *mutex); int belle_sip_mutex_unlock(belle_sip_mutex_t *mutex); int belle_sip_mutex_destroy(belle_sip_mutex_t *mutex); #else #include typedef pthread_t belle_sip_thread_t; typedef pthread_mutex_t belle_sip_mutex_t; #define belle_sip_thread_join(thread, retptr) pthread_join(thread, retptr) #define belle_sip_thread_create(thread, attr, routine, arg) pthread_create(thread, attr, routine, arg) #define belle_sip_mutex_init pthread_mutex_init #define belle_sip_mutex_lock pthread_mutex_lock #define belle_sip_mutex_unlock pthread_mutex_unlock #define belle_sip_mutex_destroy pthread_mutex_destroy #endif #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) BELLESIP_INTERNAL_EXPORT void belle_sip_sleep(unsigned int ms); #else #define belle_sip_sleep Sleep #endif #define usleep(us) belle_sip_sleep((us)/1000) static BELLESIP_INLINE int inet_aton(const char *ip, struct in_addr *p){ *(long*)p=inet_addr(ip); return 0; } #define BELLESIP_EWOULDBLOCK WSAEWOULDBLOCK #define BELLESIP_EINPROGRESS WSAEINPROGRESS #else #define WINAPI_FAMILY_PARTITION(x) 1 typedef pthread_t belle_sip_thread_t; #define belle_sip_thread_self_id() (unsigned long)pthread_self() #define belle_sip_thread_get_id(thread) (unsigned long)thread typedef pthread_key_t belle_sip_thread_key_t; #define belle_sip_thread_key_create(key,destructor) pthread_key_create(key,destructor) #define belle_sip_thread_setspecific(key,value) pthread_setspecific(key,value) #define belle_sip_thread_getspecific(key) pthread_getspecific(key) #define belle_sip_thread_key_delete(key) pthread_key_delete(key) static BELLESIP_INLINE void close_socket(belle_sip_socket_t s){ close(s); } static BELLESIP_INLINE int get_socket_error(void){ return errno; } #define belle_sip_get_socket_error_string() strerror(errno) #define belle_sip_get_socket_error_string_from_code(code) strerror(code) #define BELLESIP_EWOULDBLOCK EWOULDBLOCK #define BELLESIP_EINPROGRESS EINPROGRESS #endif #define belle_sip_error_code_is_would_block(err) ((err)==BELLESIP_EWOULDBLOCK || (err)==BELLESIP_EINPROGRESS) #endif belle-sip-1.4.1/src/provider.c000066400000000000000000001460701252242224000161610ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include "listeningpoint_internal.h" #include "md5.h" #include "belle-sip/message.h" typedef struct authorization_context { belle_sip_header_call_id_t* callid; const char* scheme; const char* realm; const char* nonce; const char* qop; const char* opaque; const char* user_id; const char* algorithm; int nonce_count; int is_proxy; }authorization_context_t; GET_SET_STRING(authorization_context,realm) GET_SET_STRING(authorization_context,nonce) GET_SET_STRING(authorization_context,qop) GET_SET_STRING(authorization_context,scheme) GET_SET_STRING(authorization_context,opaque) GET_SET_STRING(authorization_context,user_id) GET_SET_STRING(authorization_context,algorithm) GET_SET_INT(authorization_context,nonce_count,int) static authorization_context_t* belle_sip_authorization_create(belle_sip_header_call_id_t* call_id) { authorization_context_t* result = malloc(sizeof(authorization_context_t)); memset(result,0,sizeof(authorization_context_t)); result->callid=call_id; belle_sip_object_ref(result->callid); return result; } static void belle_sip_authorization_destroy(authorization_context_t* object) { DESTROY_STRING(object,scheme); DESTROY_STRING(object,realm); DESTROY_STRING(object,nonce); DESTROY_STRING(object,qop); DESTROY_STRING(object,opaque); DESTROY_STRING(object,user_id); DESTROY_STRING(object,algorithm); belle_sip_object_unref(object->callid); belle_sip_free(object); } static void finalize_transaction(belle_sip_transaction_t *tr){ belle_sip_transaction_state_t state=belle_sip_transaction_get_state(tr); if (state!=BELLE_SIP_TRANSACTION_TERMINATED){ belle_sip_message("Transaction [%p] still in state [%s], will force termination.",tr,belle_sip_transaction_state_to_string(state)); belle_sip_transaction_terminate(tr); } } static void finalize_transactions(const belle_sip_list_t *l){ belle_sip_list_t *copy=belle_sip_list_copy(l); belle_sip_list_free_with_data(copy,(void (*)(void*))finalize_transaction); } static void belle_sip_provider_uninit(belle_sip_provider_t *p){ finalize_transactions(p->client_transactions); p->client_transactions=NULL; finalize_transactions(p->server_transactions); p->server_transactions=NULL; p->listeners=belle_sip_list_free(p->listeners); p->internal_listeners=belle_sip_list_free(p->internal_listeners); p->auth_contexts=belle_sip_list_free_with_data(p->auth_contexts,(void(*)(void*))belle_sip_authorization_destroy); p->dialogs=belle_sip_list_free_with_data(p->dialogs,belle_sip_object_unref); p->lps=belle_sip_list_free_with_data(p->lps,belle_sip_object_unref); } static void channel_state_changed(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_channel_state_t state){ belle_sip_io_error_event_t ev; belle_sip_provider_t* prov=BELLE_SIP_PROVIDER(obj); if (state == BELLE_SIP_CHANNEL_ERROR || state == BELLE_SIP_CHANNEL_DISCONNECTED) { ev.transport=belle_sip_channel_get_transport_name(chan); ev.port=chan->peer_port; ev.host=chan->peer_name; ev.source=BELLE_SIP_OBJECT(prov); BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_io_error,&ev); /*IO error is also relevant for internal listener like refreshers*/ BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->internal_listeners,process_io_error,&ev); if (!chan->force_close) belle_sip_provider_release_channel(prov,chan); } } static void belle_sip_provider_dispatch_request(belle_sip_provider_t* prov, belle_sip_request_t *req){ belle_sip_server_transaction_t *t; belle_sip_request_event_t ev; t=belle_sip_provider_find_matching_server_transaction(prov,req); if (t){ belle_sip_object_ref(t); belle_sip_server_transaction_on_request(t,req); belle_sip_object_unref(t); }else{ const char *method=belle_sip_request_get_method(req); ev.dialog=NULL; /* Should we limit to ACK ? */ /*Search for a dialog if exist */ ev.dialog=belle_sip_provider_find_dialog_from_message(prov,(belle_sip_message_t*)req,1/*request=uas*/); if (ev.dialog){ if (strcmp("ACK",method)==0){ if (belle_sip_dialog_handle_ack(ev.dialog,req)==-1){ /*absorbed ACK retransmission, ignore */ return; } }else if (!belle_sip_dialog_is_authorized_transaction(ev.dialog,method)){ belle_sip_server_transaction_t *tr=belle_sip_provider_create_server_transaction(prov,req); belle_sip_server_transaction_send_response(tr, belle_sip_response_create_from_request(req,491)); return; } } if (prov->unconditional_answer_enabled && strcmp("ACK",method)!=0) { /*always answer 480 in this case*/ belle_sip_server_transaction_t *tr=belle_sip_provider_create_server_transaction(prov,req); belle_sip_server_transaction_send_response(tr,belle_sip_response_create_from_request(req,480)); return; } else { ev.source=(belle_sip_object_t*)prov; ev.server_transaction=NULL; ev.request=req; BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_request_event,&ev); } } } static belle_sip_list_t* belle_sip_provider_get_auth_context_by_realm_or_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_uri_t *from_uri,const char* realm); static int belle_sip_auth_context_find_by_nonce(const void* elem, const void* nonce_value){ authorization_context_t * a = (authorization_context_t*)elem; return strcmp(a->nonce, (const char*)nonce_value); } static void belle_sip_provider_dispatch_response(belle_sip_provider_t* p, belle_sip_response_t *msg){ belle_sip_client_transaction_t *t; t=belle_sip_provider_find_matching_client_transaction(p,msg); /*good opportunity to cleanup auth context if answer = 401|407|403*/ switch (belle_sip_response_get_status_code(msg)) { case 401: case 403: case 407: { if (t!=NULL){ const char* nonce = NULL; belle_sip_message_t* req = BELLE_SIP_MESSAGE(belle_sip_transaction_get_request((belle_sip_transaction_t*)t)); belle_sip_header_authorization_t* authorization=BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type(req, belle_sip_header_proxy_authorization_t)); if (authorization==NULL) authorization=belle_sip_message_get_header_by_type(req, belle_sip_header_authorization_t); if (authorization!=NULL){ nonce = belle_sip_header_authorization_get_nonce(authorization); if (nonce != NULL){ belle_sip_list_t * auth_context_with_nonce = NULL; while ((auth_context_with_nonce = belle_sip_list_find_custom(p->auth_contexts, belle_sip_auth_context_find_by_nonce, nonce)) != NULL){ belle_sip_authorization_destroy(auth_context_with_nonce->data); p->auth_contexts = belle_sip_list_delete_link(p->auth_contexts, auth_context_with_nonce); } } } } } } /* * If a transaction is found, pass it to the transaction and let it decide what to do. * Else notifies directly. */ if (t){ /*since the add_response may indirectly terminate the transaction, we need to guarantee the transaction is not freed * until full completion*/ belle_sip_object_ref(t); belle_sip_client_transaction_add_response(t,msg); belle_sip_object_unref(t); }else{ belle_sip_response_event_t event; event.source=(belle_sip_object_t*)p; event.client_transaction=NULL; event.dialog=NULL; event.response=msg; BELLE_SIP_PROVIDER_INVOKE_LISTENERS(p->listeners,process_response_event,&event); } } void belle_sip_provider_dispatch_message(belle_sip_provider_t *prov, belle_sip_message_t *msg){ if (TRUE #ifndef BELLE_SIP_DONT_CHECK_HEADERS_IN_MESSAGE && belle_sip_message_check_headers(msg) #endif ){ if (belle_sip_message_is_request(msg)){ belle_sip_provider_dispatch_request(prov,(belle_sip_request_t*)msg); }else{ belle_sip_provider_dispatch_response(prov,(belle_sip_response_t*)msg); } }else{ /* incorrect message received, answer bad request if it was a request.*/ if (belle_sip_message_is_request(msg)){ belle_sip_response_t *resp=belle_sip_response_create_from_request(BELLE_SIP_REQUEST(msg),400); if (resp){ belle_sip_provider_send_response(prov,resp); } }/*otherwise what can we do ?*/ } belle_sip_object_unref(msg); } /* * takes example on 16.11 of RFC3261 */ static void compute_hash_from_invariants(belle_sip_message_t *msg, char *branchid, size_t branchid_size, const char *initial){ md5_state_t ctx; char tmp[256]={0}; uint8_t digest[16]; belle_sip_header_call_id_t* callid_hdr = belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t); belle_sip_header_cseq_t* cseq_hdr = belle_sip_message_get_header_by_type(msg,belle_sip_header_cseq_t); belle_sip_header_from_t* from_hdr = belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t); belle_sip_header_to_t* to_hdr = belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t); unsigned int cseq = cseq_hdr ? belle_sip_header_cseq_get_seq_number(cseq_hdr) : 0; const char *callid = callid_hdr ? belle_sip_header_call_id_get_call_id(callid_hdr) : ""; const char *from_tag = from_hdr ? belle_sip_header_from_get_tag(from_hdr) : ""; const char *to_tag = to_hdr ? belle_sip_header_to_get_tag(to_hdr) : ""; belle_sip_uri_t *requri=NULL; belle_sip_header_via_t *via=NULL; belle_sip_header_via_t *prev_via=NULL; const belle_sip_list_t *vias=belle_sip_message_get_headers(msg,"via"); int is_request=belle_sip_message_is_request(msg); if (vias){ via=(belle_sip_header_via_t*)vias->data; if (vias->next){ prev_via=(belle_sip_header_via_t*)vias->next->data; } } if (is_request){ requri=belle_sip_request_get_uri(BELLE_SIP_REQUEST(msg)); } belle_sip_md5_init(&ctx); if (initial) belle_sip_md5_append(&ctx,(uint8_t*)initial,strlen(initial)); if (requri){ size_t offset=0; belle_sip_object_marshal((belle_sip_object_t*)requri,tmp,sizeof(tmp)-1,&offset); belle_sip_md5_append(&ctx,(uint8_t*)tmp,strlen(tmp)); } if (from_tag) belle_sip_md5_append(&ctx,(uint8_t*)from_tag,strlen(from_tag)); if (to_tag) belle_sip_md5_append(&ctx,(uint8_t*)to_tag,strlen(to_tag)); belle_sip_md5_append(&ctx,(uint8_t*)callid,strlen(callid)); belle_sip_md5_append(&ctx,(uint8_t*)&cseq,sizeof(cseq)); if (is_request){ if (prev_via){ size_t offset=0; belle_sip_object_marshal((belle_sip_object_t*)prev_via,tmp,sizeof(tmp)-1,&offset); belle_sip_md5_append(&ctx,(uint8_t*)tmp,offset); } }else{ if (via){ size_t offset=0; belle_sip_object_marshal((belle_sip_object_t*)via,tmp,sizeof(tmp)-1,&offset); belle_sip_md5_append(&ctx,(uint8_t*)tmp,offset); } } belle_sip_md5_finish(&ctx,digest); belle_sip_octets_to_text(digest,sizeof(digest),branchid,branchid_size); } /* * RFC2543 10.1.2: * "Responses are mapped to requests by the matching To, From, Call-ID, * CSeq headers and the branch parameter of the first Via header." * * to-tag must not be used because an ACK will contain one while original INVITE will not. * Cseq's method is changed for CANCEL so we must not use it as well. **/ static char *compute_rfc2543_branch(belle_sip_request_t *req, char *branchid, size_t branchid_size){ md5_state_t ctx; unsigned int cseq=belle_sip_header_cseq_get_seq_number(belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t)); uint8_t digest[16]; const char* callid=belle_sip_header_call_id_get_call_id(belle_sip_message_get_header_by_type(req,belle_sip_header_call_id_t)); belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t); const char *v_branch=belle_sip_header_via_get_branch(via); belle_sip_header_from_t *from=belle_sip_message_get_header_by_type(req,belle_sip_header_from_t); char *from_str=belle_sip_object_to_string(from); belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(req,belle_sip_header_to_t); char *to_str=belle_sip_object_to_string(belle_sip_header_address_get_uri((belle_sip_header_address_t*)to)); belle_sip_md5_init(&ctx); belle_sip_md5_append(&ctx,(uint8_t*)from_str,strlen(from_str)); belle_sip_md5_append(&ctx,(uint8_t*)to_str,strlen(to_str)); belle_sip_md5_append(&ctx,(uint8_t*)callid,strlen(callid)); belle_sip_md5_append(&ctx,(uint8_t*)&cseq,sizeof(cseq)); belle_sip_free(from_str); belle_sip_free(to_str); if (v_branch) belle_sip_md5_append(&ctx,(uint8_t*)v_branch,strlen(v_branch)); belle_sip_md5_finish(&ctx,digest); belle_sip_octets_to_text(digest,sizeof(digest),branchid,branchid_size); return branchid; } static void fix_outgoing_via(belle_sip_provider_t *p, belle_sip_channel_t *chan, belle_sip_message_t *msg){ belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header(msg,"via")); if (p->rport_enabled) belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"rport",NULL); belle_sip_header_via_set_host(via,chan->local_ip); belle_sip_header_via_set_port(via,chan->local_port); belle_sip_header_via_set_protocol(via,"SIP/2.0"); belle_sip_header_via_set_transport(via,belle_sip_channel_get_transport_name(chan)); if (belle_sip_header_via_get_branch(via)==NULL){ /*branch id should not be set random here (stateless forwarding): but rather a hash of message invariants*/ char branchid[24]; char token[BELLE_SIP_BRANCH_ID_LENGTH]; compute_hash_from_invariants(msg,token,sizeof(token),NULL); snprintf(branchid,sizeof(branchid)-1,BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",token); belle_sip_header_via_set_branch(via,branchid); belle_sip_message("Computing branch id %s for message sent statelessly", branchid); } } static void channel_on_message_headers(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){ /*not used*/ } static void channel_on_message(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){ belle_sip_object_ref(msg); belle_sip_provider_dispatch_message(BELLE_SIP_PROVIDER(obj),msg); } static int channel_on_auth_requested(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, const char* distinguished_name){ if (BELLE_SIP_IS_INSTANCE_OF(chan,belle_sip_tls_channel_t)) { belle_sip_provider_t *prov=BELLE_SIP_PROVIDER(obj); belle_sip_auth_event_t* auth_event = belle_sip_auth_event_create((belle_sip_object_t*)prov,NULL,NULL); belle_sip_tls_channel_t *tls_chan=BELLE_SIP_TLS_CHANNEL(chan); auth_event->mode=BELLE_SIP_AUTH_MODE_TLS; belle_sip_auth_event_set_distinguished_name(auth_event,distinguished_name); BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov->listeners,process_auth_requested,auth_event); belle_sip_tls_channel_set_client_certificates_chain(tls_chan,auth_event->cert); belle_sip_tls_channel_set_client_certificate_key(tls_chan,auth_event->key); belle_sip_auth_event_destroy(auth_event); } return 0; } static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){ belle_sip_header_contact_t* contact; belle_sip_header_content_length_t* content_length = (belle_sip_header_content_length_t*)belle_sip_message_get_header(msg,"Content-Length"); belle_sip_uri_t* contact_uri; const belle_sip_list_t *contacts; const char *ip=NULL; int port=0; belle_sip_provider_t *prov=BELLE_SIP_PROVIDER(obj); if (belle_sip_message_is_request(msg)){ const belle_sip_list_t *rroutes; /*probably better to be in channel*/ fix_outgoing_via(prov, chan, msg); for (rroutes=belle_sip_message_get_headers(msg,"Record-Route");rroutes!=NULL;rroutes=rroutes->next){ belle_sip_header_record_route_t* rr=(belle_sip_header_record_route_t*)rroutes->data; if (belle_sip_header_record_route_get_auto_outgoing(rr)) { belle_sip_uri_t *rr_uri = belle_sip_channel_create_routable_uri(chan); belle_sip_header_address_set_uri((belle_sip_header_address_t*) rr, rr_uri); } } } for (contacts=belle_sip_message_get_headers(msg,"Contact");contacts!=NULL;contacts=contacts->next){ const char *transport; contact=(belle_sip_header_contact_t*)contacts->data; if (belle_sip_header_contact_is_wildcard(contact)) continue; /* fix the contact if in automatic mode or null uri (for backward compatibility)*/ if (!(contact_uri = belle_sip_header_address_get_uri((belle_sip_header_address_t*)contact))) { contact_uri = belle_sip_uri_new(); belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact,contact_uri); belle_sip_header_contact_set_automatic(contact,TRUE); }else if (belle_sip_uri_get_host(contact_uri)==NULL){ belle_sip_header_contact_set_automatic(contact,TRUE); } if (!belle_sip_header_contact_get_automatic(contact)) continue; if (ip==NULL){ if (prov->nat_helper){ ip=chan->public_ip ? chan->public_ip : chan->local_ip; port=chan->public_port ? chan->public_port : chan->local_port; belle_sip_header_contact_set_unknown(contact,!chan->learnt_ip_port); }else{ ip=chan->local_ip; port=chan->local_port; } } belle_sip_uri_set_host(contact_uri,ip); transport=belle_sip_channel_get_transport_name_lower_case(chan); if (strcmp(transport,"udp")==0){ belle_sip_parameters_remove_parameter(BELLE_SIP_PARAMETERS(contact_uri),"transport"); }else{ if (!belle_sip_uri_is_secure(contact_uri)) belle_sip_uri_set_transport_param(contact_uri,transport); } if (port!=belle_sip_listening_point_get_well_known_port(transport)) { belle_sip_uri_set_port(contact_uri,port); }else{ belle_sip_uri_set_port(contact_uri,0); } } /* * According to RFC3261, content-length is mandatory for stream based transport, but optional for datagram transport. * However some servers (opensips) are confused when they receive a SIP/UDP packet without Content-Length (they shouldn't). */ if (!content_length #ifndef BELLE_SIP_FORCE_CONTENT_LENGTH && strcasecmp("udp",belle_sip_channel_get_transport_name(chan))!=0 #endif ) { content_length = belle_sip_header_content_length_create(0); belle_sip_message_add_header(msg,(belle_sip_header_t*)content_length); } } BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_provider_t,belle_sip_channel_listener_t) channel_state_changed, channel_on_message_headers, channel_on_message, channel_on_sending, channel_on_auth_requested BELLE_SIP_IMPLEMENT_INTERFACE_END BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_sip_provider_t,belle_sip_channel_listener_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_provider_t,belle_sip_object_t,belle_sip_provider_uninit,NULL,NULL,FALSE); belle_sip_provider_t *belle_sip_provider_new(belle_sip_stack_t *s, belle_sip_listening_point_t *lp){ belle_sip_provider_t *p=belle_sip_object_new(belle_sip_provider_t); p->stack=s; p->rport_enabled=1; if (lp) belle_sip_provider_add_listening_point(p,lp); return p; } /* This function is used by a proxy to set its call side record route. * It must be called before adding any VIA header to the message. */ belle_sip_uri_t *belle_sip_provider_create_inbound_record_route(belle_sip_provider_t *p, belle_sip_request_t *req) { belle_sip_uri_t* origin = belle_sip_request_extract_origin(req); belle_sip_hop_t *hop = belle_sip_hop_new_from_uri(origin); belle_sip_channel_t *inChan = belle_sip_provider_get_channel(p, hop); return belle_sip_channel_create_routable_uri(inChan); } static belle_sip_channel_t* _belle_sip_provider_find_channel_using_routable(belle_sip_provider_t *p, const belle_sip_uri_t* routable_uri) { const char *transport; belle_sip_listening_point_t *lp; belle_sip_list_t *elem; belle_sip_channel_t *chan; belle_sip_uri_t* chan_uri; if (!routable_uri) return NULL; transport = belle_sip_uri_is_secure(routable_uri) ? "TLS" : belle_sip_uri_get_transport_param(routable_uri); lp = belle_sip_provider_get_listening_point(p, transport); if (!lp) return NULL; for(elem=lp->channels; elem ;elem=elem->next){ chan=(belle_sip_channel_t*)elem->data; chan_uri = belle_sip_channel_create_routable_uri(chan); if (belle_sip_uri_get_port(routable_uri) == belle_sip_uri_get_port(chan_uri) && 0 == strcmp(belle_sip_uri_get_host(routable_uri), belle_sip_uri_get_host(chan_uri))) { return chan; } } return NULL; } /* * This function is not efficient at all, REVISIT. * Its goal is to determine whether a routable (route or record route) matches the local provider instance. * In order to do that, we go through all the channels and ask them their routable uri, and see if it matches the uri passed in argument. * This creates a lot of temporary objects and iterates through a potentially long list of routables. * Some more efficient solutions could be: * 1- insert a magic cookie parameter in each routable created by the provider, so that recognition is immediate. * Drawback: use of non-standard, possibly conflicting parameter. * 2- check the listening point's uri first (but need to match the ip address to any local ip if it is INADDR_ANY), then use belle_sip_listening_point_get_channel() * to see if a channel is matching. * belle_sip_listening_point_get_channel() is not optimized currently but will have to be, so at least we leverage on something that will be optimized. **/ int belle_sip_provider_is_us(belle_sip_provider_t *p, belle_sip_uri_t* uri) { belle_sip_channel_t* chan = _belle_sip_provider_find_channel_using_routable(p, uri); return !!chan; } int belle_sip_provider_add_listening_point(belle_sip_provider_t *p, belle_sip_listening_point_t *lp){ if (lp == NULL) { belle_sip_error("Cannot add NULL lp to provider [%p]",p); return -1; } belle_sip_listening_point_set_channel_listener(lp,BELLE_SIP_CHANNEL_LISTENER(p)); p->lps=belle_sip_list_append(p->lps,belle_sip_object_ref(lp)); return 0; } void belle_sip_provider_remove_listening_point(belle_sip_provider_t *p, belle_sip_listening_point_t *lp) { p->lps=belle_sip_list_remove(p->lps,lp); belle_sip_object_unref(lp); return; } belle_sip_listening_point_t *belle_sip_provider_get_listening_point(belle_sip_provider_t *p, const char *transport){ belle_sip_list_t *l; for(l=p->lps;l!=NULL;l=l->next){ belle_sip_listening_point_t *lp=(belle_sip_listening_point_t*)l->data; if (strcasecmp(belle_sip_listening_point_get_transport(lp),transport)==0) return lp; } return NULL; } const belle_sip_list_t *belle_sip_provider_get_listening_points(belle_sip_provider_t *p){ return p->lps; } void belle_sip_provider_add_internal_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l, int prepend){ if (prepend) p->internal_listeners=belle_sip_list_prepend(p->internal_listeners,l); else p->internal_listeners=belle_sip_list_append(p->internal_listeners,l); } void belle_sip_provider_remove_internal_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l){ p->internal_listeners=belle_sip_list_remove(p->internal_listeners,l); } void belle_sip_provider_add_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l){ p->listeners=belle_sip_list_append(p->listeners,l); } void belle_sip_provider_remove_sip_listener(belle_sip_provider_t *p, belle_sip_listener_t *l){ p->listeners=belle_sip_list_remove(p->listeners,l); } belle_sip_header_call_id_t * belle_sip_provider_create_call_id(const belle_sip_provider_t *prov){ belle_sip_header_call_id_t *cid=belle_sip_header_call_id_new(); char tmp[11]; belle_sip_header_call_id_set_call_id(cid,belle_sip_random_token(tmp,sizeof(tmp))); return cid; } belle_sip_dialog_t * belle_sip_provider_create_dialog(belle_sip_provider_t *prov, belle_sip_transaction_t *t) { return belle_sip_provider_create_dialog_internal(prov,t,TRUE); } belle_sip_dialog_t * belle_sip_provider_create_dialog_internal(belle_sip_provider_t *prov, belle_sip_transaction_t *t,unsigned int check_last_resp){ belle_sip_dialog_t *dialog=NULL; if (check_last_resp && t->last_response){ int code=belle_sip_response_get_status_code(t->last_response); if (code>=200 && code<300){ belle_sip_fatal("You must not create dialog after sending the response that establish the dialog."); return NULL; } } dialog=belle_sip_dialog_new(t); if (dialog) { belle_sip_transaction_set_dialog(t,dialog); belle_sip_provider_add_dialog(prov,dialog); } return dialog; } /*find a dialog given the call id, from-tag and to-tag*/ belle_sip_dialog_t* belle_sip_provider_find_dialog(const belle_sip_provider_t *prov, const char* call_id, const char* from_tag, const char* to_tag) { belle_sip_list_t* iterator; for(iterator=prov->dialogs;iterator!=NULL;iterator=iterator->next) { belle_sip_dialog_t* dialog=(belle_sip_dialog_t*)iterator->data; if (belle_sip_dialog_get_state(dialog) != BELLE_SIP_DIALOG_NULL && strcmp(belle_sip_header_call_id_get_call_id(belle_sip_dialog_get_call_id(dialog)),call_id)==0) { const char* target_from; const char* target_to; if (belle_sip_dialog_is_server(dialog)) { target_to=belle_sip_dialog_get_local_tag(dialog); target_from=belle_sip_dialog_get_remote_tag(dialog); } else { target_from=belle_sip_dialog_get_local_tag(dialog); target_to=belle_sip_dialog_get_remote_tag(dialog); } if (strcmp(from_tag,target_from)==0 && strcmp(to_tag,target_to)==0) { return dialog; } } } return NULL; } /*finds an existing dialog for an outgoing or incoming message */ belle_sip_dialog_t *belle_sip_provider_find_dialog_from_message(belle_sip_provider_t *prov, belle_sip_message_t *msg, int as_uas){ belle_sip_dialog_t *returned_dialog=NULL,*dialog; belle_sip_header_call_id_t *call_id; belle_sip_header_from_t *from; belle_sip_header_to_t *to; belle_sip_list_t *elem; const char *from_tag; const char *to_tag; const char *call_id_value; const char *local_tag,*remote_tag; if (belle_sip_message_is_request(msg)){ belle_sip_request_t *req=BELLE_SIP_REQUEST(msg); if (req->dialog) return req->dialog; } to=belle_sip_message_get_header_by_type(msg,belle_sip_header_to_t); if (to==NULL || (to_tag=belle_sip_header_to_get_tag(to))==NULL){ /* a request without to tag cannot be part of a dialog */ return NULL; } call_id=belle_sip_message_get_header_by_type(msg,belle_sip_header_call_id_t); from=belle_sip_message_get_header_by_type(msg,belle_sip_header_from_t); if (call_id==NULL || from==NULL || (from_tag=belle_sip_header_from_get_tag(from))==NULL) return NULL; call_id_value=belle_sip_header_call_id_get_call_id(call_id); local_tag=as_uas ? to_tag : from_tag; remote_tag=as_uas ? from_tag : to_tag; for (elem=prov->dialogs;elem!=NULL;elem=elem->next){ dialog=(belle_sip_dialog_t*)elem->data; /*ignore dialog in state BELLE_SIP_DIALOG_NULL, is it really the correct things to do*/ if (belle_sip_dialog_get_state(dialog) != BELLE_SIP_DIALOG_NULL && _belle_sip_dialog_match(dialog,call_id_value,local_tag,remote_tag)) { if (!returned_dialog) returned_dialog=dialog; else belle_sip_fatal("More than 1 dialog is matching, check your app"); } } return returned_dialog; } void belle_sip_provider_add_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){ prov->dialogs=belle_sip_list_prepend(prov->dialogs,belle_sip_object_ref(dialog)); } static void notify_dialog_terminated(belle_sip_dialog_terminated_event_t* ev) { BELLE_SIP_PROVIDER_INVOKE_LISTENERS(((belle_sip_provider_t*)ev->source)->listeners,process_dialog_terminated,ev); belle_sip_object_unref(ev->dialog); belle_sip_free(ev); } void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){ belle_sip_dialog_terminated_event_t* ev=belle_sip_malloc(sizeof(belle_sip_dialog_terminated_event_t)); ev->source=prov; ev->dialog=dialog; prov->dialogs=belle_sip_list_remove(prov->dialogs,dialog); belle_sip_main_loop_do_later(belle_sip_stack_get_main_loop(prov->stack) ,(belle_sip_callback_t) notify_dialog_terminated , ev); } belle_sip_client_transaction_t *belle_sip_provider_create_client_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){ const char *method=belle_sip_request_get_method(req); belle_sip_client_transaction_t *t; belle_sip_client_transaction_t *inv_transaction; if (strcmp(method,"INVITE")==0) t=(belle_sip_client_transaction_t*)belle_sip_ict_new(prov,req); else if (strcmp(method,"ACK")==0){ belle_sip_error("belle_sip_provider_create_client_transaction() cannot be used for ACK requests."); return NULL; } else { t=(belle_sip_client_transaction_t*)belle_sip_nict_new(prov,req); if (strcmp(method,"CANCEL")==0){ /*force next hop*/ inv_transaction=belle_sip_provider_find_matching_client_transaction_from_req(prov,req); if (inv_transaction && inv_transaction->next_hop) { /*found corresponding ict, taking next hop*/ /*9.1 Client Behavior * The destination address, port, and transport for the CANCEL MUST be identical to those used to send the original request.*/ t->next_hop=(belle_sip_hop_t*)belle_sip_object_ref(inv_transaction->next_hop); } else { belle_sip_error ("No corresponding ict nor dest found for cancel request attached to transaction [%p]",t); } } } belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog_from_message(prov,(belle_sip_message_t*)req,FALSE)); belle_sip_request_set_dialog(req,NULL);/*get rid of the reference to the dialog, which is no longer needed in the message. This is to avoid circular references.*/ return t; } belle_sip_server_transaction_t *belle_sip_provider_create_server_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req){ belle_sip_server_transaction_t* t; if (strcmp(belle_sip_request_get_method(req),"INVITE")==0){ t=(belle_sip_server_transaction_t*)belle_sip_ist_new(prov,req); }else if (strcmp(belle_sip_request_get_method(req),"ACK")==0){ belle_sip_error("Creating a server transaction for an ACK is not a good idea, probably"); return NULL; }else t=(belle_sip_server_transaction_t*)belle_sip_nist_new(prov,req); belle_sip_transaction_set_dialog((belle_sip_transaction_t*)t,belle_sip_provider_find_dialog_from_message(prov,(belle_sip_message_t*)req,TRUE)); belle_sip_provider_add_server_transaction(prov,t); return t; } belle_sip_stack_t *belle_sip_provider_get_sip_stack(belle_sip_provider_t *p){ return p->stack; } belle_sip_channel_t * belle_sip_provider_get_channel(belle_sip_provider_t *p, const belle_sip_hop_t *hop){ belle_sip_list_t *l; belle_sip_listening_point_t *candidate=NULL,*lp; belle_sip_channel_t *chan; if (hop->transport!=NULL) { for(l=p->lps;l!=NULL;l=l->next){ lp=(belle_sip_listening_point_t*)l->data; if (strcasecmp(belle_sip_listening_point_get_transport(lp),hop->transport)==0){ chan=belle_sip_listening_point_get_channel(lp,hop); if (chan) return chan; candidate=lp; } } if (candidate){ chan=belle_sip_listening_point_create_channel(candidate,hop); if (!chan) belle_sip_error("Could not create channel to [%s://%s:%i]",hop->transport,hop->host,hop->port); return chan; } } belle_sip_error("No listening point matching for [%s://%s:%i]",hop->transport,hop->host,hop->port); return NULL; } void belle_sip_provider_release_channel(belle_sip_provider_t *p, belle_sip_channel_t *chan){ belle_sip_listening_point_remove_channel(chan->lp,chan); } void belle_sip_provider_clean_channels(belle_sip_provider_t *p){ belle_sip_list_t *l; belle_sip_listening_point_t *lp; for(l=p->lps;l!=NULL;l=l->next){ lp=(belle_sip_listening_point_t*)l->data; belle_sip_listening_point_clean_channels(lp); } } void belle_sip_provider_send_request(belle_sip_provider_t *p, belle_sip_request_t *req){ belle_sip_hop_t* hop; belle_sip_channel_t *chan; hop=belle_sip_stack_get_next_hop(p->stack,req); chan=belle_sip_provider_get_channel(p,hop); if (chan) { belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(req)); } } void belle_sip_provider_send_response(belle_sip_provider_t *p, belle_sip_response_t *resp){ belle_sip_hop_t* hop; belle_sip_channel_t *chan; belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to"); if (belle_sip_response_get_status_code(resp)!=100 && to && belle_sip_header_to_get_tag(to)==NULL){ char token[BELLE_SIP_TAG_LENGTH]; compute_hash_from_invariants((belle_sip_message_t*)resp,token,sizeof(token),"tag"); belle_sip_header_to_set_tag(to,token); } hop=belle_sip_response_get_return_hop(resp); if (hop){ chan=belle_sip_provider_get_channel(p,hop); if (chan) belle_sip_channel_queue_message(chan,BELLE_SIP_MESSAGE(resp)); belle_sip_object_unref(hop); } } /*private provider API*/ void belle_sip_provider_set_transaction_terminated(belle_sip_provider_t *p, belle_sip_transaction_t *t){ belle_sip_transaction_terminated_event_t ev; BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t); ev.source=t->provider; ev.transaction=t; ev.is_server_transaction=BELLE_SIP_IS_INSTANCE_OF(t,belle_sip_server_transaction_t); BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,process_transaction_terminated,&ev); if (!ev.is_server_transaction){ belle_sip_provider_remove_client_transaction(p,(belle_sip_client_transaction_t*)t); }else{ belle_sip_provider_remove_server_transaction(p,(belle_sip_server_transaction_t*)t); } } void belle_sip_provider_add_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t){ prov->client_transactions=belle_sip_list_prepend(prov->client_transactions,belle_sip_object_ref(t)); } struct client_transaction_matcher{ const char *branchid; const char *method; }; static int client_transaction_match(const void *p_tr, const void *p_matcher){ belle_sip_client_transaction_t *tr=(belle_sip_client_transaction_t*)p_tr; struct client_transaction_matcher *matcher=(struct client_transaction_matcher*)p_matcher; const char *req_method=belle_sip_request_get_method(tr->base.request); if (strcmp(matcher->branchid,tr->base.branch_id)==0 && strcmp(matcher->method,req_method)==0) return 0; return -1; } belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction(belle_sip_provider_t *prov, belle_sip_response_t *resp){ struct client_transaction_matcher matcher; belle_sip_header_via_t *via=(belle_sip_header_via_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"via"); belle_sip_header_cseq_t *cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"cseq"); belle_sip_client_transaction_t *ret=NULL; belle_sip_list_t *elem; if (via==NULL){ belle_sip_warning("Response has no via."); return NULL; } if (cseq==NULL){ belle_sip_warning("Response has no cseq."); return NULL; } matcher.branchid=belle_sip_header_via_get_branch(via); matcher.method=belle_sip_header_cseq_get_method(cseq); elem=belle_sip_list_find_custom(prov->client_transactions,client_transaction_match,&matcher); if (elem){ ret=(belle_sip_client_transaction_t*)elem->data; belle_sip_message("Found transaction matching response."); } return ret; } void belle_sip_provider_remove_client_transaction(belle_sip_provider_t *prov, belle_sip_client_transaction_t *t){ belle_sip_list_t* elem=belle_sip_list_find(prov->client_transactions,t); if (elem) { prov->client_transactions=belle_sip_list_delete_link(prov->client_transactions,elem); belle_sip_object_unref(t); } else { belle_sip_error("trying to remove transaction [%p] not part of provider [%p]",t,prov); } } void belle_sip_provider_add_server_transaction(belle_sip_provider_t *prov, belle_sip_server_transaction_t *t){ prov->server_transactions=belle_sip_list_prepend(prov->server_transactions,belle_sip_object_ref(t)); } struct transaction_matcher{ const char *branchid; const char *method; const char *sentby; int is_ack_or_cancel; }; static int transaction_match(const void *p_tr, const void *p_matcher){ belle_sip_transaction_t *tr=(belle_sip_transaction_t*)p_tr; struct transaction_matcher *matcher=(struct transaction_matcher*)p_matcher; const char *req_method=belle_sip_request_get_method(tr->request); if (strcmp(matcher->branchid,tr->branch_id)==0){ if (strcmp(matcher->method,req_method)==0) return 0; if (matcher->is_ack_or_cancel && strcmp(req_method,"INVITE")==0) return 0; } return -1; } belle_sip_transaction_t * belle_sip_provider_find_matching_transaction(belle_sip_list_t *transactions, belle_sip_request_t *req){ struct transaction_matcher matcher; belle_sip_header_via_t *via=(belle_sip_header_via_t*)belle_sip_message_get_header((belle_sip_message_t*)req,"via"); belle_sip_transaction_t *ret=NULL; belle_sip_list_t *elem=NULL; const char *branch; char token[BELLE_SIP_BRANCH_ID_LENGTH]; matcher.method=belle_sip_request_get_method(req); matcher.is_ack_or_cancel=(strcmp(matcher.method,"ACK")==0 || strcmp(matcher.method,"CANCEL")==0); if (via!=NULL && (branch=belle_sip_header_via_get_branch(via))!=NULL && strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))==0){ matcher.branchid=branch; }else{ /*this request comes from an old equipment, we need to compute our own branch for this request.*/ matcher.branchid=compute_rfc2543_branch(req,token,sizeof(token)); belle_sip_request_set_rfc2543_branch(req,token); belle_sip_message("Message from old RFC2543 stack, computed branch is %s", token); } elem=belle_sip_list_find_custom(transactions,transaction_match,&matcher); if (elem){ ret=(belle_sip_transaction_t*)elem->data; belle_sip_message("Found transaction [%p] matching request.",ret); } return ret; } belle_sip_server_transaction_t * belle_sip_provider_find_matching_server_transaction(belle_sip_provider_t *prov, belle_sip_request_t *req) { belle_sip_transaction_t *ret=belle_sip_provider_find_matching_transaction(prov->server_transactions,req); return ret?BELLE_SIP_SERVER_TRANSACTION(ret):NULL; } belle_sip_client_transaction_t * belle_sip_provider_find_matching_client_transaction_from_req(belle_sip_provider_t *prov, belle_sip_request_t *req) { belle_sip_transaction_t *ret=belle_sip_provider_find_matching_transaction(prov->client_transactions,req); return ret?BELLE_SIP_CLIENT_TRANSACTION(ret):NULL; } void belle_sip_provider_remove_server_transaction(belle_sip_provider_t *prov, belle_sip_server_transaction_t *t){ prov->server_transactions=belle_sip_list_remove(prov->server_transactions,t); belle_sip_object_unref(t); } static void authorization_context_fill_from_auth(authorization_context_t* auth_context,belle_sip_header_www_authenticate_t* authenticate,belle_sip_uri_t *from_uri) { authorization_context_set_realm(auth_context,belle_sip_header_www_authenticate_get_realm(authenticate)); if (auth_context->nonce && strcmp(belle_sip_header_www_authenticate_get_nonce(authenticate),auth_context->nonce)!=0) { /*new nonce, resetting nounce_count*/ auth_context->nonce_count=0; } authorization_context_set_nonce(auth_context,belle_sip_header_www_authenticate_get_nonce(authenticate)); authorization_context_set_algorithm(auth_context,belle_sip_header_www_authenticate_get_algorithm(authenticate)); authorization_context_set_qop(auth_context,belle_sip_header_www_authenticate_get_qop_first(authenticate)); authorization_context_set_scheme(auth_context,belle_sip_header_www_authenticate_get_scheme(authenticate)); authorization_context_set_opaque(auth_context,belle_sip_header_www_authenticate_get_opaque(authenticate)); authorization_context_set_user_id(auth_context, from_uri?belle_sip_uri_get_user(from_uri):NULL); if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(authenticate,belle_sip_header_proxy_authenticate_t)) { auth_context->is_proxy=1; } } static belle_sip_list_t* belle_sip_provider_get_auth_context_by_realm_or_call_id(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_uri_t *from_uri,const char* realm) { belle_sip_list_t* auth_context_lst=NULL; belle_sip_list_t* result=NULL; authorization_context_t* auth_context; for (auth_context_lst=p->auth_contexts;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) { auth_context=(authorization_context_t*)auth_context_lst->data; if (belle_sip_header_call_id_equals(auth_context->callid,call_id) ) { result=belle_sip_list_append(result,auth_context_lst->data); } } /* According to the RFC3261 22.3, if the outbound proxy realm is set, we could reuse its nonce value: * "If a UA receives a Proxy-Authenticate header field value in a 401/407 * response to a request with a particular Call-ID, it should * incorporate credentials for that realm in all subsequent requests * that contain the same Call-ID. These credentials MUST NOT be cached * across dialogs; however, if a UA is configured with the realm of its * local outbound proxy, when one exists, then the UA MAY cache * credentials for that realm across dialogs." */ if (result == NULL){ const char * from_user=from_uri?belle_sip_uri_get_user(from_uri):NULL; belle_sip_debug("belle_sip_provider_auth: no auth context registered with [call_id=%s], looking for realm..." , call_id?belle_sip_header_call_id_get_call_id(call_id):"(null)"); for (auth_context_lst=p->auth_contexts;auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) { auth_context=(authorization_context_t*)auth_context_lst->data; belle_sip_debug("belle_sip_provider_auth: \t[realm=%s] [user_id=%s] [call_id=%s]", auth_context->realm?auth_context->realm:"(null)", auth_context->user_id?auth_context->user_id:"(null)", auth_context->callid?belle_sip_header_call_id_get_call_id(auth_context->callid):"(null)" ); /* We also verify that user matches in case of multi-account to avoid use nonce from another account. For a * single user, from_uri user id and realm user id COULD be different but we assume here that this is not the case * in order to avoid adding another field in auth_context struct. **/ if ((realm && strcmp(auth_context->realm,realm)==0) && (from_user && auth_context->user_id && strcmp(auth_context->user_id,from_user)==0)) { result=belle_sip_list_append(result,auth_context_lst->data); belle_sip_debug("belle_sip_provider_auth: found a MATCHING realm auth context!"); } } } return result; } static void belle_sip_provider_update_or_create_auth_context(belle_sip_provider_t *p,belle_sip_header_call_id_t* call_id,belle_sip_header_www_authenticate_t* authenticate,belle_sip_uri_t *from_uri,const char* realm) { belle_sip_list_t* auth_context_lst = NULL; authorization_context_t* auth_context; for (auth_context_lst=belle_sip_provider_get_auth_context_by_realm_or_call_id(p,call_id,from_uri,realm);auth_context_lst!=NULL;auth_context_lst=auth_context_lst->next) { auth_context=(authorization_context_t*)auth_context_lst->data; if (strcmp(auth_context->realm,belle_sip_header_www_authenticate_get_realm(authenticate))==0) { authorization_context_fill_from_auth(auth_context,authenticate,from_uri); if (auth_context_lst) belle_sip_free(auth_context_lst); return; /*only one realm is supposed to be found for now*/ } } /*no auth context found, creating one*/ auth_context=belle_sip_authorization_create(call_id); belle_sip_debug("belle_sip_provider_auth: no matching auth context, creating one for [realm=%s][user_id=%s][call_id=%s]" , belle_sip_header_www_authenticate_get_realm(authenticate)?belle_sip_header_www_authenticate_get_realm(authenticate):"(null)" , from_uri?belle_sip_uri_get_user(from_uri):"(null)" , call_id?belle_sip_header_call_id_get_call_id(call_id):"(null)"); authorization_context_fill_from_auth(auth_context,authenticate,from_uri); p->auth_contexts=belle_sip_list_append(p->auth_contexts,auth_context); if (auth_context_lst) belle_sip_free(auth_context_lst); return; } int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_request_t* request, belle_sip_response_t *resp, belle_sip_uri_t *from_uri, belle_sip_list_t** auth_infos, const char* realm) { belle_sip_header_call_id_t* call_id; belle_sip_list_t* auth_context_iterator; belle_sip_list_t* authenticate_lst; belle_sip_list_t* head; belle_sip_header_www_authenticate_t* authenticate; belle_sip_header_authorization_t* authorization; belle_sip_header_from_t* from; belle_sip_auth_event_t* auth_event; authorization_context_t* auth_context; const char* ha1; char computed_ha1[33]; int result=0; const char* request_method; /*check params*/ if (!p || !request) { belle_sip_error("belle_sip_provider_add_authorization bad parameters"); return-1; } request_method=belle_sip_request_get_method(request); /*22 Usage of HTTP Authentication 22.1 Framework While a server can legitimately challenge most SIP requests, there are two requests defined by this document that require special handling for authentication: ACK and CANCEL. Under an authentication scheme that uses responses to carry values used to compute nonces (such as Digest), some problems come up for any requests that take no response, including ACK. For this reason, any credentials in the INVITE that were accepted by a server MUST be accepted by that server for the ACK. UACs creating an ACK message will duplicate all of the Authorization and Proxy-Authorization header field values that appeared in the INVITE to which the ACK corresponds. Servers MUST NOT attempt to challenge an ACK. Although the CANCEL method does take a response (a 2xx), servers MUST NOT attempt to challenge CANCEL requests since these requests cannot be resubmitted. Generally, a CANCEL request SHOULD be accepted by a server if it comes from the same hop that sent the request being canceled (provided that some sort of transport or network layer security association, as described in Section 26.2.1, is in place). */ if (strcmp("CANCEL",request_method)==0 || strcmp("ACK",request_method)==0) { belle_sip_debug("no authorization header needed for method [%s]",request_method); return 0; } if (from_uri==NULL){ from = belle_sip_message_get_header_by_type(request,belle_sip_header_from_t); from_uri=belle_sip_header_address_get_uri((belle_sip_header_address_t*)from); } /*get authenticates value from response*/ if (resp) { belle_sip_list_t *it; call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(resp),belle_sip_header_call_id_t); /*searching for authentication headers*/ authenticate_lst = belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_WWW_AUTHENTICATE)); /*search for proxy authenticate*/ authenticate_lst=belle_sip_list_concat(authenticate_lst,belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_PROXY_AUTHENTICATE))); /*update auth contexts with authenticate headers from response*/ for (it=authenticate_lst;it!=NULL;it=it->next) { authenticate=BELLE_SIP_HEADER_WWW_AUTHENTICATE(it->data); belle_sip_provider_update_or_create_auth_context(p,call_id,authenticate,from_uri,realm); } belle_sip_list_free(authenticate_lst); } /*put authorization header if passwd found*/ call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_call_id_t); belle_sip_debug("belle_sip_provider_auth: looking an auth context for [method=%s][realm=%s][user_id=%s][call_id=%s]" , request_method , realm?realm:"(null)" , from_uri?belle_sip_uri_get_user(from_uri):"(null)" , call_id?belle_sip_header_call_id_get_call_id(call_id):"(null)" ); head=belle_sip_provider_get_auth_context_by_realm_or_call_id(p,call_id,from_uri,realm); /*we assume there no existing auth headers*/ for (auth_context_iterator=head;auth_context_iterator!=NULL;auth_context_iterator=auth_context_iterator->next) { /*clear auth info*/ auth_context=(authorization_context_t*)auth_context_iterator->data; auth_event = belle_sip_auth_event_create((belle_sip_object_t*)p,auth_context->realm,from_uri); /*put data*/ /*call listener*/ BELLE_SIP_PROVIDER_INVOKE_LISTENERS(p->listeners,process_auth_requested,auth_event); if (auth_event->passwd || auth_event->ha1) { if (!auth_event->userid) { /*if no userid, username = userid*/ belle_sip_auth_event_set_userid(auth_event,auth_event->username); } belle_sip_message("Auth info found for [%s] realm [%s]",auth_event->userid,auth_event->realm); if (auth_context->is_proxy || (!belle_sip_header_call_id_equals(call_id,auth_context->callid) &&realm &&strcmp(realm,auth_context->realm)==0 &&from_uri &&strcmp(auth_event->username,belle_sip_uri_get_user(from_uri))==0 &&strcmp("REGISTER",request_method)!=0)) /* Relying on method name for choosing between authorization and proxy-authorization is not very strong but I don't see any better solution as we don't know all the time what type of challange we will have*/{ authorization=BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_header_proxy_authorization_new()); } else { authorization=belle_sip_header_authorization_new(); } belle_sip_header_authorization_set_scheme(authorization,auth_context->scheme); belle_sip_header_authorization_set_realm(authorization,auth_context->realm); belle_sip_header_authorization_set_username(authorization,auth_event->userid); belle_sip_header_authorization_set_nonce(authorization,auth_context->nonce); belle_sip_header_authorization_set_qop(authorization,auth_context->qop); belle_sip_header_authorization_set_opaque(authorization,auth_context->opaque); belle_sip_header_authorization_set_algorithm(authorization,auth_context->algorithm); belle_sip_header_authorization_set_uri(authorization,(belle_sip_uri_t*)belle_sip_request_get_uri(request)); if (auth_context->qop){ ++auth_context->nonce_count; belle_sip_header_authorization_set_nonce_count(authorization,auth_context->nonce_count); } if (auth_event->ha1) { ha1=auth_event->ha1; } else { belle_sip_auth_helper_compute_ha1(auth_event->userid,auth_context->realm,auth_event->passwd, computed_ha1); ha1=computed_ha1; } if (belle_sip_auth_helper_fill_authorization(authorization ,belle_sip_request_get_method(request) ,ha1)) { belle_sip_object_unref(authorization); } else belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(authorization)); result=1; } else { belle_sip_message("No auth info found for call id [%s]",belle_sip_header_call_id_get_call_id(call_id)); } /*provides auth info in any cases, usefull even if found because auth info can contain wrong password*/ if (auth_infos) { /*stored to give user information on realm/username which requires authentications*/ *auth_infos=belle_sip_list_append(*auth_infos,auth_event); } else { belle_sip_auth_event_destroy(auth_event); } } belle_sip_list_free(head); return result; } void belle_sip_provider_set_recv_error(belle_sip_provider_t *prov, int recv_error) { belle_sip_list_t *lps; belle_sip_list_t *channels; for(lps=prov->lps;lps!=NULL;lps=lps->next){ for(channels=((belle_sip_listening_point_t*)lps->data)->channels;channels!=NULL;channels=channels->next){ ((belle_sip_channel_t*)channels->data)->simulated_recv_return=recv_error; ((belle_sip_source_t*)channels->data)->notify_required=(recv_error<=0); } } } void belle_sip_provider_enable_rport(belle_sip_provider_t *prov, int enable) { prov->rport_enabled=enable; } int belle_sip_provider_is_rport_enabled(belle_sip_provider_t *prov) { return prov->rport_enabled; } void belle_sip_provider_enable_nat_helper(belle_sip_provider_t *prov, int enabled){ prov->nat_helper=enabled; } int belle_sip_provider_nat_helper_enabled(const belle_sip_provider_t *prov){ return prov->nat_helper; } void belle_sip_provider_enable_unconditional_answer(belle_sip_provider_t *prov, int enable) { prov->unconditional_answer_enabled=enable; } belle-sip-1.4.1/src/refresher.c000066400000000000000000000743011252242224000163110ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2012 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include "belle-sip/refresher.h" #define DEFAULT_RETRY_AFTER 60000 #define DEFAULT_INITIAL_RETRY_AFTER_ON_IO_ERROR 500 static void belle_sip_refresher_stop_internal(belle_sip_refresher_t* refresher,int cancel_pending_transaction) ; typedef enum belle_sip_refresher_state { started, stopped }belle_sip_refresher_state_t; typedef enum timer_purpose{ NORMAL_REFRESH, RETRY }timer_purpose_t; struct belle_sip_refresher { belle_sip_object_t obj; belle_sip_refresher_listener_t listener; belle_sip_source_t* timer; belle_sip_client_transaction_t* transaction; char* realm; int target_expires; int obtained_expires; belle_sip_refresher_state_t state; void* user_data; int retry_after; belle_sip_list_t* auth_events; int auth_failures; int on_io_error; /*flag to avoid multiple error notification*/ int number_of_retry; /*counter to count number of unsuccesfull retry, used to know when to retry*/ timer_purpose_t timer_purpose; unsigned char manual; }; static int set_expires_from_trans(belle_sip_refresher_t* refresher); static int timer_cb(void *user_data, unsigned int events) ; static int belle_sip_refresher_refresh_internal(belle_sip_refresher_t* refresher,int expires,int auth_mandatory, belle_sip_list_t** auth_infos, belle_sip_uri_t *requri); static void cancel_retry(belle_sip_refresher_t* refresher) { if (refresher->timer){ belle_sip_main_loop_remove_source(belle_sip_stack_get_main_loop(refresher->transaction->base.provider->stack),refresher->timer); belle_sip_object_unref(refresher->timer); refresher->timer=NULL; } } static void schedule_timer_at(belle_sip_refresher_t* refresher,int delay, timer_purpose_t purpose) { belle_sip_message("Refresher: scheduling next timer in %i ms",delay); refresher->timer_purpose=purpose; /*cancel timer if any*/ cancel_retry(refresher); refresher->timer=belle_sip_timeout_source_new(timer_cb,refresher,delay); belle_sip_object_set_name((belle_sip_object_t*)refresher->timer,"Refresher timeout"); belle_sip_main_loop_add_source(belle_sip_stack_get_main_loop(refresher->transaction->base.provider->stack),refresher->timer); } static void retry_later(belle_sip_refresher_t* refresher) { refresher->number_of_retry++; schedule_timer_at(refresher,refresher->retry_after,RETRY); } static void retry_later_on_io_error(belle_sip_refresher_t* refresher) { /*if first retry, sent it in 500 ms*/ if (refresher->number_of_retry < 1) { schedule_timer_at(refresher,DEFAULT_INITIAL_RETRY_AFTER_ON_IO_ERROR,RETRY); refresher->number_of_retry++; } else { retry_later(refresher); } } static void schedule_timer(belle_sip_refresher_t* refresher) { schedule_timer_at(refresher,refresher->obtained_expires*900,NORMAL_REFRESH); } static void process_dialog_terminated(belle_sip_listener_t *user_ctx, const belle_sip_dialog_terminated_event_t *event){ /*nop*/ } static void process_io_error(belle_sip_listener_t *user_ctx, const belle_sip_io_error_event_t *event){ belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx; belle_sip_client_transaction_t*client_transaction; if (refresher->on_io_error==1) { return; /*refresher already on error*/ } if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),belle_sip_client_transaction_t)) { client_transaction=BELLE_SIP_CLIENT_TRANSACTION(belle_sip_io_error_event_get_source(event)); if (!refresher || (refresher && ((refresher->state==stopped && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction)) != BELLE_SIP_TRANSACTION_TRYING && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction)) != BELLE_SIP_TRANSACTION_INIT /*to cover dns or certificate error*/) || client_transaction !=refresher->transaction ))) return; /*not for me or no longuer involved*/ if (refresher->target_expires==0 && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction)) != BELLE_SIP_TRANSACTION_TRYING && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction)) != BELLE_SIP_TRANSACTION_INIT ) { return; /*not for me or no longuer involved because expire=0*/ } if (refresher->state==started) retry_later_on_io_error(refresher); if (refresher->listener) refresher->listener(refresher,refresher->user_data,503, "io error"); return; } else if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(belle_sip_io_error_event_get_source(event),belle_sip_provider_t)) { /*something went wrong on this provider, checking if my channel is still up*/ if (refresher->state==started /*refresher started or trying to refresh */ && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction)) == BELLE_SIP_TRANSACTION_TERMINATED /*else we are notified by transaction error*/ && refresher->transaction->base.channel /*transaction may not have any channel*/ && (belle_sip_channel_get_state(refresher->transaction->base.channel) == BELLE_SIP_CHANNEL_DISCONNECTED ||belle_sip_channel_get_state(refresher->transaction->base.channel) == BELLE_SIP_CHANNEL_ERROR)) { belle_sip_message("refresher [%p] has channel [%p] in state [%s], reporting error" ,refresher ,refresher->transaction->base.channel ,belle_sip_channel_state_to_string(belle_sip_channel_get_state(refresher->transaction->base.channel))); if (refresher->state==started) retry_later_on_io_error(refresher); if (refresher->listener) refresher->listener(refresher,refresher->user_data,503, "io error"); refresher->on_io_error=1; } return; }else { /*belle_sip_error("Refresher process_io_error not implemented yet for non transaction/provider source");*/ /*nop, because already handle at transaction layer*/ } } belle_sip_header_contact_t* get_first_contact_in_unknown_state(belle_sip_request_t *req){ /*check if automatic contacts could be set by provider, if not resubmit the request immediately.*/ belle_sip_header_contact_t *contact; const belle_sip_list_t *l; for (l=belle_sip_message_get_headers((belle_sip_message_t*)req,"Contact");l!=NULL;l=l->next){ contact=(belle_sip_header_contact_t*)l->data; if (belle_sip_header_contact_is_unknown(contact)){ return contact; } } return NULL; } static int is_contact_address_acurate(const belle_sip_refresher_t* refresher,belle_sip_request_t* request) { belle_sip_header_contact_t* contact; if ((contact = get_first_contact_in_unknown_state(request))){ /*check if contact ip/port is consistant with public channel ip/port*/ int channel_public_port = refresher->transaction->base.channel->public_port; int contact_port = belle_sip_uri_get_listening_port(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact))); const char* channel_public_ip = refresher->transaction->base.channel->public_ip; const char* contact_ip = belle_sip_uri_get_host(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact))); if (channel_public_port == contact_port && channel_public_ip && contact_ip && strcmp(channel_public_ip,contact_ip) == 0) { /*nothing to do contact is accurate*/ belle_sip_header_contact_set_unknown(contact,FALSE); return TRUE; } else { belle_sip_message("Refresher [%p]: contact address [%s:%i] does not match channel address[%s:%i]." ,refresher ,contact_ip ,contact_port ,channel_public_ip ,channel_public_port); return FALSE; } } else { belle_sip_message("Refresher [%p]: has no contact for request [%p].", refresher,request); return TRUE; } } static void process_response_event(belle_sip_listener_t *user_ctx, const belle_sip_response_event_t *event){ belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); belle_sip_response_t* response = belle_sip_response_event_get_response(event); belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)); int response_code = belle_sip_response_get_status_code(response); belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx; belle_sip_header_contact_t *contact; if (refresher && (client_transaction !=refresher->transaction)) return; /*not for me*/ /*success case:*/ if (response_code>=200 && response_code<300){ refresher->auth_failures=0; refresher->number_of_retry=0; /*great, success*/ if (strcmp(belle_sip_request_get_method(request),"PUBLISH")==0) { /*search for etag*/ belle_sip_header_t* etag=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"SIP-ETag"); if (etag) { belle_sip_header_t* sip_if_match = belle_sip_header_create("SIP-If-Match",belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(etag))); /*update request for next refresh*/ belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),"SIP-If-Match"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),sip_if_match); } else { belle_sip_warning("Refresher [%p] receive 200ok to a publish without etag",refresher); } } /*update expire if needed*/ set_expires_from_trans(refresher); if (refresher->target_expires<=0) { belle_sip_refresher_stop(refresher); /*doesn't not make sense to refresh if expire =0;*/ } if (refresher->state==started) { if (is_contact_address_acurate(refresher,request)) { schedule_timer(refresher); /*re-arm timer*/ } else { belle_sip_message("belle_sip_refresher_start(): refresher [%p] is resubmitting request because contact sent was not correct in original request.",refresher); belle_sip_refresher_refresh(refresher,refresher->target_expires); return; } } else belle_sip_message("Refresher [%p] not scheduling next refresh, because it was stopped",refresher); }else{/*special error cases*/ switch (response_code) { case 301: case 302: contact=belle_sip_message_get_header_by_type(response,belle_sip_header_contact_t); if (contact){ belle_sip_uri_t *uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact)); if (uri && belle_sip_refresher_refresh_internal(refresher,refresher->target_expires,TRUE,&refresher->auth_events,uri)==0) return; } break; case 401: case 407: refresher->auth_failures++; if (refresher->auth_failures>1){ /*avoid looping with 407 or 401 */ belle_sip_warning("Authentication is failing constantly, %s",(refresher->target_expires>0)? "will retry later":"giving up."); if (refresher->target_expires>0) retry_later(refresher); refresher->auth_failures=0; /*reset auth failure*/ break; } if (refresher->auth_events) { refresher->auth_events=belle_sip_list_free_with_data(refresher->auth_events,(void (*)(void*))belle_sip_auth_event_destroy); } if (belle_sip_refresher_refresh_internal(refresher,refresher->target_expires,TRUE,&refresher->auth_events,NULL)==0) return; /*ok, keep 401 internal*/ break; /*Else notify user of registration failure*/ case 403: /*In case of 403, we will retry later, just in case*/ if (refresher->target_expires>0) retry_later(refresher); break; case 423:{ belle_sip_header_extension_t *min_expires=BELLE_SIP_HEADER_EXTENSION(belle_sip_message_get_header((belle_sip_message_t*)response,"Min-Expires")); if (min_expires){ const char *value=belle_sip_header_extension_get_value(min_expires); if (value){ int new_expires=atoi(value); if (new_expires>0 && refresher->state==started){ refresher->target_expires=new_expires; belle_sip_refresher_refresh(refresher,refresher->target_expires); return; } } }else belle_sip_warning("Receiving 423 but no min-expires header."); break; } case 505: case 501: /*irrecoverable errors, probably no need to retry later*/ break; default: /*for all other errors, retry later*/ if (refresher->target_expires>0) retry_later(refresher); break; } } if (refresher->listener) refresher->listener(refresher,refresher->user_data,response_code, belle_sip_response_get_reason_phrase(response)); } static void process_timeout(belle_sip_listener_t *user_ctx, const belle_sip_timeout_event_t *event) { belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx; belle_sip_client_transaction_t*client_transaction =belle_sip_timeout_event_get_client_transaction(event); if (refresher && (client_transaction !=refresher->transaction)) return; /*not for me*/ if (refresher->state==started) { /*retry in 2 seconds but not immediately to let the current transaction be cleaned*/ schedule_timer_at(refresher,2000,RETRY); } if (refresher->listener) refresher->listener(refresher,refresher->user_data,408, "timeout"); } static void process_transaction_terminated(belle_sip_listener_t *user_ctx, const belle_sip_transaction_terminated_event_t *event) { /*belle_sip_message("process_transaction_terminated Transaction terminated [%p]",event);*/ } static void process_auth_requested(belle_sip_listener_t *l, belle_sip_auth_event_t *event){ } static void process_request_event(belle_sip_listener_t *user_ctx, const belle_sip_request_event_t *event){ } static void destroy(belle_sip_refresher_t *refresher){ belle_sip_refresher_stop(refresher); belle_sip_provider_remove_internal_sip_listener(refresher->transaction->base.provider,BELLE_SIP_LISTENER(refresher)); belle_sip_object_unref(refresher->transaction); refresher->transaction=NULL; if (refresher->realm) belle_sip_free(refresher->realm); if (refresher->auth_events) refresher->auth_events=belle_sip_list_free_with_data(refresher->auth_events,(void (*)(void*))belle_sip_auth_event_destroy); } BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_refresher_t,belle_sip_listener_t) process_dialog_terminated, process_io_error, process_request_event, process_response_event, process_timeout, process_transaction_terminated, process_auth_requested BELLE_SIP_IMPLEMENT_INTERFACE_END BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_sip_refresher_t, belle_sip_listener_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_refresher_t, belle_sip_object_t,destroy, NULL, NULL,FALSE); void belle_sip_refresher_set_listener(belle_sip_refresher_t* refresher, belle_sip_refresher_listener_t listener,void* user_pointer) { refresher->listener=listener; refresher->user_data=user_pointer; } int belle_sip_refresher_refresh(belle_sip_refresher_t* refresher,int expires) { /*first cancel any current retry*/ cancel_retry(refresher); refresher->auth_failures=0;/*reset the auth_failures to get a chance to authenticate again*/ return belle_sip_refresher_refresh_internal(refresher,expires,FALSE,NULL,NULL); } static int unfilled_auth_info(const void* info,const void* userptr) { belle_sip_auth_event_t* auth_info = (belle_sip_auth_event_t*)info; return auth_info->passwd || auth_info->ha1; } static int belle_sip_refresher_refresh_internal(belle_sip_refresher_t* refresher, int expires, int auth_mandatory, belle_sip_list_t** auth_infos, belle_sip_uri_t *requri) { belle_sip_request_t*old_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(refresher->transaction)); belle_sip_response_t*old_response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(refresher->transaction)); belle_sip_dialog_t* dialog = belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(refresher->transaction)); belle_sip_client_transaction_t* client_transaction; belle_sip_request_t* request; belle_sip_header_expires_t* expires_header; belle_sip_uri_t* preset_route=refresher->transaction->preset_route; belle_sip_provider_t* prov=refresher->transaction->base.provider; belle_sip_header_contact_t* contact; /*first remove timer if any*/ if (expires >=0) { refresher->target_expires=expires; } else { /*-1 keep last value*/ } if (!dialog) { const belle_sip_transaction_state_t state=belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction)); /*create new request*/ if (belle_sip_transaction_state_is_transient(state)) { /*operation pending, cannot update authorization headers*/ belle_sip_header_cseq_t* cseq; belle_sip_message("Refresher [%p] already has transaction [%p] in state [%s]" ,refresher ,refresher->transaction ,belle_sip_transaction_state_to_string(state)); request=belle_sip_request_clone_with_body(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(refresher->transaction))); cseq=belle_sip_message_get_header_by_type(request,belle_sip_header_cseq_t); belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); } else { request=belle_sip_client_transaction_create_authenticated_request(refresher->transaction,auth_infos,refresher->realm); } if (requri){ /*case where we are redirected*/ belle_sip_request_set_uri(request,requri); /*remove auth headers, they are not valid for new destination*/ belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION); } } else if (dialog && belle_sip_dialog_get_state(dialog)==BELLE_SIP_DIALOG_CONFIRMED) { if (belle_sip_dialog_request_pending(dialog)){ belle_sip_message("Cannot refresh now, there is a pending request in the dialog."); return -1; } request=belle_sip_dialog_create_request_from(dialog,old_request); if (strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0) { /*put expire header*/ if (!(expires_header = belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t))) { expires_header = belle_sip_header_expires_new(); belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header)); } } belle_sip_provider_add_authorization(prov,request,old_response,NULL,auth_infos,refresher->realm); } else { belle_sip_error("Unexpected dialog state [%s] for dialog [%p], cannot refresh [%s]" ,belle_sip_dialog_state_to_string(belle_sip_dialog_get_state(dialog)) ,dialog ,belle_sip_request_get_method(old_request)); return -1; } if (auth_mandatory && auth_infos && belle_sip_list_find_custom(*auth_infos, unfilled_auth_info, NULL)) { belle_sip_message("Auth info not found for this refresh operation on [%p]",refresher); if (request) belle_sip_object_unref(request); return -1; } refresher->on_io_error=0; /*reset this flag*/ /*update expires in any cases*/ expires_header = belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t); if (expires_header) belle_sip_header_expires_set_expires(expires_header,refresher->target_expires); contact=belle_sip_message_get_header_by_type(request,belle_sip_header_contact_t); if (contact && belle_sip_header_contact_get_expires(contact)>=0) belle_sip_header_contact_set_expires(contact,refresher->target_expires); /*update the Date header if it exists*/ { belle_sip_header_date_t *date=belle_sip_message_get_header_by_type(request,belle_sip_header_date_t); if (date){ time_t curtime=time(NULL); belle_sip_header_date_set_time(date,&curtime); } } client_transaction = belle_sip_provider_create_client_transaction(prov,request); client_transaction->base.is_internal=1; belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),refresher); switch (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction))) { case BELLE_SIP_TRANSACTION_INIT: case BELLE_SIP_TRANSACTION_CALLING: case BELLE_SIP_TRANSACTION_TRYING: /*very early state, we can assume nobody will answer, stop retransmiting*/ belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(refresher->transaction)); break; default: /*we preserve the transaction "as is"*/ break; } /*update reference transaction for next refresh*/ belle_sip_object_unref(refresher->transaction); refresher->transaction=client_transaction; belle_sip_object_ref(refresher->transaction); if (belle_sip_client_transaction_send_request_to(client_transaction,requri?requri:preset_route)) { /*send imediatly to requri in case of redirect*/ belle_sip_error("Cannot send refresh method [%s] for refresher [%p]" ,belle_sip_request_get_method(request) ,refresher); return -1; } if (expires==0) belle_sip_refresher_stop_internal(refresher,0); /*unregister transaction must be preserved*/ return 0; } static int timer_cb(void *user_data, unsigned int events) { belle_sip_refresher_t* refresher = (belle_sip_refresher_t*)user_data; if (refresher->timer_purpose==NORMAL_REFRESH && refresher->manual) { belle_sip_message("Refresher [%p] is in manual mode, skipping refresh.",refresher); /*call listener with special code 0 to indicate request is about to expire*/ if (refresher->listener) refresher->listener(refresher,refresher->user_data,0, "about to expire"); return BELLE_SIP_STOP; } if (belle_sip_refresher_refresh(refresher,refresher->target_expires)==-1){ retry_later(refresher); } return BELLE_SIP_STOP; } static belle_sip_header_contact_t* get_matching_contact(const belle_sip_transaction_t* transaction) { belle_sip_request_t*request=belle_sip_transaction_get_request(transaction); belle_sip_response_t*response=transaction->last_response; const belle_sip_list_t* contact_header_list; belle_sip_header_contact_t* unfixed_local_contact; belle_sip_header_contact_t* fixed_local_contact; char* tmp_string; char* tmp_string2; if (!response) return NULL; /*we assume, there is only one contact in request*/ unfixed_local_contact= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t); fixed_local_contact= BELLE_SIP_HEADER_CONTACT(belle_sip_object_clone(BELLE_SIP_OBJECT(unfixed_local_contact))); /*first fix contact using received/rport*/ belle_sip_response_fix_contact(response,fixed_local_contact); contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); if (contact_header_list) { contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list ,(belle_sip_compare_func)belle_sip_header_contact_not_equals , (const void*)fixed_local_contact); if (!contact_header_list) { /*reset header list*/ contact_header_list = belle_sip_message_get_headers(BELLE_SIP_MESSAGE(response),BELLE_SIP_CONTACT); contact_header_list = belle_sip_list_find_custom((belle_sip_list_t*)contact_header_list ,(belle_sip_compare_func)belle_sip_header_contact_not_equals ,unfixed_local_contact); } if (!contact_header_list) { tmp_string=belle_sip_object_to_string(BELLE_SIP_OBJECT(fixed_local_contact)); tmp_string2=belle_sip_object_to_string(BELLE_SIP_OBJECT(unfixed_local_contact)); belle_sip_message("No matching contact neither for [%s] nor [%s]", tmp_string, tmp_string2); belle_sip_free(tmp_string); belle_sip_free(tmp_string2); return NULL; } else { return BELLE_SIP_HEADER_CONTACT(contact_header_list->data); } } else { return NULL; } } static int set_expires_from_trans(belle_sip_refresher_t* refresher) { belle_sip_transaction_t* transaction = BELLE_SIP_TRANSACTION(refresher->transaction); belle_sip_response_t*response=transaction->last_response; belle_sip_request_t*request=belle_sip_transaction_get_request(transaction); belle_sip_header_expires_t* expires_header=belle_sip_message_get_header_by_type(request,belle_sip_header_expires_t); belle_sip_header_contact_t* contact_header; refresher->obtained_expires=-1; if (strcmp("REGISTER",belle_sip_request_get_method(request))==0 || expires_header /*if request has an expire header, refresher can always work*/) { if (expires_header) refresher->target_expires = belle_sip_header_expires_get_expires(expires_header); /*An "expires" parameter on the "Contact" header has no semantics for * SUBSCRIBE and is explicitly not equivalent to an "Expires" header in * a SUBSCRIBE request or response. */ if (strcmp("REGISTER",belle_sip_request_get_method(request))==0){ if (!expires_header && (contact_header=belle_sip_message_get_header_by_type((belle_sip_message_t*)request,belle_sip_header_contact_t))){ int ct_expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header)); if (ct_expires!=-1) refresher->target_expires=ct_expires; } /*check in response also to get the obtained expires*/ if ((contact_header=get_matching_contact(transaction))!=NULL){ /*matching contact, check for its possible expires param*/ refresher->obtained_expires=belle_sip_header_contact_get_expires(BELLE_SIP_HEADER_CONTACT(contact_header)); } } if (refresher->obtained_expires==-1){ /*no contact with expire or not relevant, looking for Expires header*/ if (response && (expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),BELLE_SIP_EXPIRES))) { refresher->obtained_expires = belle_sip_header_expires_get_expires(expires_header); } } if (refresher->obtained_expires==-1) { belle_sip_message("Neither Expires header nor corresponding Contact header found, checking from original request"); refresher->obtained_expires=refresher->target_expires; }else if (refresher->target_expires>0 && refresher->obtained_expires==0){ /*check this case because otherwise we are going to loop fast in sending refresh requests.*/ belle_sip_warning("Server replied with 0 expires, what does this mean ?"); /*suppose it's a server bug and assume our target_expires is understood.*/ refresher->obtained_expires=refresher->target_expires; } } else if (strcmp("INVITE",belle_sip_request_get_method(request))==0) { belle_sip_error("Refresher does not support INVITE yet"); return -1; } else { belle_sip_error("Refresher does not support [%s] yet",belle_sip_request_get_method(request)); return -1; } return 0; } int belle_sip_refresher_start(belle_sip_refresher_t* refresher) { if(refresher->state==started) { belle_sip_warning("Refresher [%p] already started",refresher); } else { if (refresher->target_expires>0) { belle_sip_request_t* request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(refresher->transaction)); refresher->state=started; if (is_contact_address_acurate(refresher,request)) { schedule_timer(refresher); /*re-arm timer*/ } else { belle_sip_message("belle_sip_refresher_start(): refresher [%p] is resubmitting request because contact sent was not correct in original request.",refresher); belle_sip_refresher_refresh(refresher,refresher->target_expires); return 0; } belle_sip_message("Refresher [%p] started, next refresh in [%i] s",refresher,refresher->obtained_expires); }else{ belle_sip_message("Refresher [%p] stopped, expires=%i",refresher,refresher->target_expires); refresher->state=stopped; } } return 0; } void belle_sip_refresher_stop(belle_sip_refresher_t* refresher) { belle_sip_refresher_stop_internal(refresher, 1); } static void belle_sip_refresher_stop_internal(belle_sip_refresher_t* refresher,int cancel_pending_transaction) { belle_sip_message("Refresher [%p] stopped.",refresher); if (refresher->timer){ belle_sip_main_loop_remove_source(belle_sip_stack_get_main_loop(refresher->transaction->base.provider->stack), refresher->timer); belle_sip_object_unref(refresher->timer); refresher->timer=NULL; } if (cancel_pending_transaction && refresher->transaction && belle_sip_transaction_state_is_transient(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(refresher->transaction)))) { belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(refresher->transaction)); /*refresher cancelled, no need to continue to retransmit*/ } refresher->state=stopped; } belle_sip_refresher_t* belle_sip_refresher_new(belle_sip_client_transaction_t* transaction) { belle_sip_refresher_t* refresher; belle_sip_transaction_state_t state=belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(transaction)); belle_sip_request_t* request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(transaction)); int is_register=strcmp("REGISTER",belle_sip_request_get_method(request))==0; refresher = (belle_sip_refresher_t*)belle_sip_object_new(belle_sip_refresher_t); refresher->transaction=transaction; refresher->state=stopped; refresher->number_of_retry=0; belle_sip_object_ref(transaction); refresher->retry_after=DEFAULT_RETRY_AFTER; belle_sip_provider_add_internal_sip_listener(transaction->base.provider,BELLE_SIP_LISTENER(refresher), is_register); if (set_expires_from_trans(refresher)==-1){ belle_sip_error("Unable to extract refresh value from transaction [%p]",transaction); } if (belle_sip_transaction_state_is_transient(state)) { belle_sip_message("Refresher [%p] takes ownership of transaction [%p]",refresher,transaction); transaction->base.is_internal=1; refresher->state=started; }else{ belle_sip_refresher_start(refresher); } return refresher; } int belle_sip_refresher_get_expires(const belle_sip_refresher_t* refresher) { return refresher->target_expires; } int belle_sip_refresher_get_retry_after(const belle_sip_refresher_t* refresher){ return refresher->retry_after; } void belle_sip_refresher_set_retry_after(belle_sip_refresher_t* refresher, int delay_ms) { refresher->retry_after=delay_ms; } const char* belle_sip_refresher_get_realm(const belle_sip_refresher_t* refresher){ return refresher->realm; } void belle_sip_refresher_set_realm(belle_sip_refresher_t* refresher, const char* realm) { if (refresher->realm){ belle_sip_free(refresher->realm); refresher->realm = NULL; } if (realm!=NULL){ refresher->realm=belle_sip_strdup(realm); } } const belle_sip_client_transaction_t* belle_sip_refresher_get_transaction(const belle_sip_refresher_t* refresher) { return refresher->transaction; } const belle_sip_list_t* belle_sip_refresher_get_auth_events(const belle_sip_refresher_t* refresher) { return refresher->auth_events; } void belle_sip_refresher_enable_manual_mode(belle_sip_refresher_t *refresher, int enabled){ refresher->manual=enabled; } char *belle_sip_refresher_get_public_uri(belle_sip_refresher_t* refresher) { return belle_sip_channel_get_public_ip_port(refresher->transaction->base.channel); } belle-sip-1.4.1/src/siplistener.c000066400000000000000000000137531252242224000166710ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" belle_sip_response_t* belle_sip_response_event_get_response(const belle_sip_response_event_t* event) { return event->response; } belle_sip_client_transaction_t *belle_sip_response_event_get_client_transaction(const belle_sip_response_event_t* event){ return event->client_transaction; } belle_sip_dialog_t *belle_sip_response_event_get_dialog(const belle_sip_response_event_t* event){ return event->dialog; } belle_sip_request_t* belle_sip_request_event_get_request(const belle_sip_request_event_t* event){ return event->request; } belle_sip_server_transaction_t *belle_sip_request_event_get_server_transaction(const belle_sip_request_event_t* event){ return event->server_transaction; } belle_sip_dialog_t *belle_sip_request_event_get_dialog(const belle_sip_request_event_t* event){ return event->dialog; } belle_sip_dialog_t* belle_sip_dialog_terminated_event_get_dialog(const belle_sip_dialog_terminated_event_t *event) { return event->dialog; } const char* belle_sip_io_error_event_get_host(const belle_sip_io_error_event_t* event) { return event->host; } const char* belle_sip_io_error_event_get_transport(const belle_sip_io_error_event_t* event) { return event->transport; } unsigned int belle_sip_io_error_event_port(const belle_sip_io_error_event_t* event) { return event->port; } belle_sip_object_t* belle_sip_io_error_event_get_source(const belle_sip_io_error_event_t* event) { return event->source; } typedef struct belle_sip_callbacks belle_sip_callbacks_t; struct belle_sip_callbacks{ belle_sip_object_t base; belle_sip_listener_callbacks_t cbs; void *user_ctx; }; static void process_dialog_terminated(belle_sip_listener_t *l, const belle_sip_dialog_terminated_event_t *event){ belle_sip_callbacks_t *obj=(belle_sip_callbacks_t*)l; if (obj->cbs.process_dialog_terminated) obj->cbs.process_dialog_terminated(obj->user_ctx,event); } static void process_io_error(belle_sip_listener_t *l, const belle_sip_io_error_event_t *event){ belle_sip_callbacks_t *obj=(belle_sip_callbacks_t*)l; if (obj->cbs.process_io_error) obj->cbs.process_io_error(obj->user_ctx,event); } static void process_request_event(belle_sip_listener_t *l, const belle_sip_request_event_t *event){ belle_sip_callbacks_t *obj=(belle_sip_callbacks_t*)l; if (obj->cbs.process_request_event) obj->cbs.process_request_event(obj->user_ctx,event); } static void process_response_event(belle_sip_listener_t *l, const belle_sip_response_event_t *event){ belle_sip_callbacks_t *obj=(belle_sip_callbacks_t*)l; if (obj->cbs.process_response_event) obj->cbs.process_response_event(obj->user_ctx,event); } static void process_timeout(belle_sip_listener_t *l, const belle_sip_timeout_event_t *event){ belle_sip_callbacks_t *obj=(belle_sip_callbacks_t*)l; if (obj->cbs.process_timeout) obj->cbs.process_timeout(obj->user_ctx,event); } static void process_transaction_terminated(belle_sip_listener_t *l, const belle_sip_transaction_terminated_event_t *event){ belle_sip_callbacks_t *obj=(belle_sip_callbacks_t*)l; if (obj->cbs.process_transaction_terminated) obj->cbs.process_transaction_terminated(obj->user_ctx,event); } static void process_auth_requested(belle_sip_listener_t *l, belle_sip_auth_event_t *event){ belle_sip_callbacks_t *obj=(belle_sip_callbacks_t*)l; if (obj->cbs.process_auth_requested) obj->cbs.process_auth_requested(obj->user_ctx,event); } BELLE_SIP_DECLARE_VPTR(belle_sip_callbacks_t); BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_callbacks_t,belle_sip_listener_t) process_dialog_terminated, process_io_error, process_request_event, process_response_event, process_timeout, process_transaction_terminated, process_auth_requested BELLE_SIP_IMPLEMENT_INTERFACE_END BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_sip_callbacks_t,belle_sip_listener_t); static void belle_sip_callbacks_destroy(belle_sip_callbacks_t *obj){ if (obj->cbs.listener_destroyed) obj->cbs.listener_destroyed(obj->user_ctx); } BELLE_SIP_INSTANCIATE_VPTR(belle_sip_callbacks_t,belle_sip_object_t,belle_sip_callbacks_destroy,NULL,NULL,FALSE); belle_sip_listener_t *belle_sip_listener_create_from_callbacks(const belle_sip_listener_callbacks_t *callbacks, void *user_ctx){ belle_sip_callbacks_t *obj=belle_sip_object_new(belle_sip_callbacks_t); memcpy(&obj->cbs,callbacks,sizeof(belle_sip_listener_callbacks_t)); obj->user_ctx=user_ctx; return BELLE_SIP_LISTENER(obj); } belle_sip_client_transaction_t *belle_sip_transaction_terminated_event_get_client_transaction(const belle_sip_transaction_terminated_event_t* event) { return event->is_server_transaction ? NULL:BELLE_SIP_CLIENT_TRANSACTION(event->transaction); } belle_sip_server_transaction_t *belle_sip_transaction_terminated_event_get_server_transaction(const belle_sip_transaction_terminated_event_t* event) { return event->is_server_transaction ? BELLE_SIP_SERVER_TRANSACTION(event->transaction):NULL; } belle_sip_client_transaction_t *belle_sip_timeout_event_get_client_transaction(const belle_sip_timeout_event_t* event) { return event->is_server_transaction ? NULL:BELLE_SIP_CLIENT_TRANSACTION(event->transaction); } belle_sip_server_transaction_t *belle_sip_timeout_event_get_server_transaction(const belle_sip_timeout_event_t* event) { return event->is_server_transaction ? BELLE_SIP_SERVER_TRANSACTION(event->transaction):NULL; } belle-sip-1.4.1/src/sipstack.c000066400000000000000000000214771252242224000161530ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include "listeningpoint_internal.h" belle_sip_hop_t* belle_sip_hop_new(const char* transport, const char *cname, const char* host,int port) { belle_sip_hop_t* hop = belle_sip_object_new(belle_sip_hop_t); if (transport) hop->transport=belle_sip_strdup(transport); if (host) hop->host=belle_sip_strdup(host); if (cname) hop->cname=belle_sip_strdup(cname); hop->port=port; return hop; } belle_sip_hop_t* belle_sip_hop_new_from_uri(const belle_sip_uri_t *uri){ const char *host; const char *cname=NULL; const char * transport=belle_sip_uri_get_transport_param(uri); if (!transport) { transport=belle_sip_uri_is_secure(uri)?"tls":"udp"; } host=belle_sip_uri_get_maddr_param(uri); if (!host) host=belle_sip_uri_get_host(uri); else cname=belle_sip_uri_get_host(uri); return belle_sip_hop_new( transport, cname, host, belle_sip_uri_get_listening_port(uri)); } belle_sip_hop_t* belle_sip_hop_new_from_generic_uri(const belle_generic_uri_t *uri){ const char *host; const char * transport="TCP"; const char *scheme=belle_generic_uri_get_scheme(uri); int port=belle_generic_uri_get_port(uri); int well_known_port=0; host=belle_generic_uri_get_host(uri); if (strcasecmp(scheme,"http")==0) { transport="TCP"; well_known_port=80; }else if (strcasecmp(scheme,"https")==0) { transport="TLS"; well_known_port=443; } return belle_sip_hop_new(transport, host, host, port > 0 ? port : well_known_port); } static void belle_sip_hop_destroy(belle_sip_hop_t *hop){ if (hop->host) { belle_sip_free(hop->host); hop->host=NULL; } if (hop->cname){ belle_sip_free(hop->cname); hop->cname=NULL; } if (hop->transport){ belle_sip_free(hop->transport); hop->transport=NULL; } } static void belle_sip_hop_clone(belle_sip_hop_t *hop, const belle_sip_hop_t *orig){ if (orig->host) hop->host=belle_sip_strdup(orig->host); if (orig->cname) hop->cname=belle_sip_strdup(orig->cname); if (orig->transport) hop->transport=belle_sip_strdup(orig->transport); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_hop_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_hop_t,belle_sip_object_t,belle_sip_hop_destroy,belle_sip_hop_clone,NULL,TRUE); static void belle_sip_stack_destroy(belle_sip_stack_t *stack){ belle_sip_message("stack [%p] destroyed.",stack); if (stack->dns_user_hosts_file) belle_sip_free(stack->dns_user_hosts_file); if (stack->dns_resolv_conf) belle_sip_free(stack->dns_resolv_conf); belle_sip_object_unref(stack->ml); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_stack_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_stack_t,belle_sip_object_t,belle_sip_stack_destroy,NULL,NULL,FALSE); belle_sip_stack_t * belle_sip_stack_new(const char *properties){ belle_sip_stack_t *stack=belle_sip_object_new(belle_sip_stack_t); stack->ml=belle_sip_main_loop_new (); stack->timer_config.T1=500; stack->timer_config.T2=4000; stack->timer_config.T4=5000; stack->transport_timeout=63000; stack->dns_timeout=15000; stack->dns_srv_enabled=TRUE; stack->inactive_transport_timeout=3600; /*one hour*/ return stack; } const belle_sip_timer_config_t *belle_sip_stack_get_timer_config(const belle_sip_stack_t *stack){ return &stack->timer_config; } void belle_sip_stack_set_timer_config(belle_sip_stack_t *stack,const belle_sip_timer_config_t *timer_config){ belle_sip_message("Setting timer config to T1 [%i], T2 [%i], T3 [%i], T4 [%i] on stack [%p]", timer_config->T1 , timer_config->T2 , timer_config->T3 , timer_config->T4 , stack); stack->timer_config=*timer_config; } void belle_sip_stack_set_transport_timeout(belle_sip_stack_t *stack, int timeout_ms){ stack->transport_timeout=timeout_ms; } int belle_sip_stack_get_transport_timeout(const belle_sip_stack_t *stack){ return stack->transport_timeout; } int belle_sip_stack_get_dns_timeout(const belle_sip_stack_t *stack) { return stack->dns_timeout; } void belle_sip_stack_set_dns_timeout(belle_sip_stack_t *stack, int timeout) { stack->dns_timeout = timeout; } unsigned char belle_sip_stack_dns_srv_enabled(const belle_sip_stack_t *stack) { return stack->dns_srv_enabled; } void belle_sip_stack_enable_dns_srv(belle_sip_stack_t *stack, unsigned char enable) { stack->dns_srv_enabled = enable; } belle_sip_listening_point_t *belle_sip_stack_create_listening_point(belle_sip_stack_t *s, const char *ipaddress, int port, const char *transport){ belle_sip_listening_point_t *lp=NULL; if (strcasecmp(transport,"UDP")==0) { lp=belle_sip_udp_listening_point_new(s,ipaddress,port); } else if (strcasecmp(transport,"TCP") == 0) { lp=belle_sip_stream_listening_point_new(s,ipaddress,port); }else if (strcasecmp(transport,"TLS") == 0) { lp=belle_sip_tls_listening_point_new(s,ipaddress,port); } else { belle_sip_fatal("Unsupported transport %s",transport); } return lp; } void belle_sip_stack_delete_listening_point(belle_sip_stack_t *s, belle_sip_listening_point_t *lp){ belle_sip_object_unref(lp); } belle_sip_provider_t *belle_sip_stack_create_provider(belle_sip_stack_t *s, belle_sip_listening_point_t *lp){ belle_sip_provider_t *p=belle_sip_provider_new(s,lp); return p; } belle_http_provider_t *belle_sip_stack_create_http_provider(belle_sip_stack_t *s, const char *bind_ip){ belle_http_provider_t *p=belle_http_provider_new(s, bind_ip); return p; } void belle_sip_stack_delete_provider(belle_sip_stack_t *s, belle_sip_provider_t *p){ belle_sip_object_unref(p); } belle_sip_main_loop_t * belle_sip_stack_get_main_loop(belle_sip_stack_t *stack){ return stack->ml; } void belle_sip_stack_main(belle_sip_stack_t *stack){ belle_sip_main_loop_run(stack->ml); } void belle_sip_stack_sleep(belle_sip_stack_t *stack, unsigned int milliseconds){ belle_sip_main_loop_sleep (stack->ml,milliseconds); } belle_sip_hop_t * belle_sip_stack_get_next_hop(belle_sip_stack_t *stack, belle_sip_request_t *req) { belle_sip_header_route_t *route=BELLE_SIP_HEADER_ROUTE(belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"route")); belle_sip_uri_t *uri; if (route!=NULL){ uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(route)); }else{ uri=belle_sip_request_get_uri(req); } return belle_sip_hop_new_from_uri(uri); } void belle_sip_stack_set_tx_delay(belle_sip_stack_t *stack, int delay_ms){ stack->tx_delay=delay_ms; } void belle_sip_stack_set_send_error(belle_sip_stack_t *stack, int send_error){ stack->send_error=send_error; } void belle_sip_stack_set_resolver_tx_delay(belle_sip_stack_t *stack, int delay_ms) { stack->resolver_tx_delay = delay_ms; } void belle_sip_stack_set_resolver_send_error(belle_sip_stack_t *stack, int send_error) { stack->resolver_send_error = send_error; } const char * belle_sip_stack_get_dns_user_hosts_file(const belle_sip_stack_t *stack) { return stack->dns_user_hosts_file; } void belle_sip_stack_set_dns_user_hosts_file(belle_sip_stack_t *stack, const char *hosts_file) { if (stack->dns_user_hosts_file) belle_sip_free(stack->dns_user_hosts_file); stack->dns_user_hosts_file = hosts_file?belle_sip_strdup(hosts_file):NULL; } const char * belle_sip_stack_get_dns_resolv_conf_file(const belle_sip_stack_t *stack){ return stack->dns_resolv_conf; } void belle_sip_stack_set_dns_resolv_conf_file(belle_sip_stack_t *stack, const char *resolv_conf_file){ if (stack->dns_resolv_conf) belle_sip_free(stack->dns_resolv_conf); stack->dns_resolv_conf = resolv_conf_file?belle_sip_strdup(resolv_conf_file):NULL; } const char* belle_sip_version_to_string() { #ifdef BELLESIP_VERSION return BELLESIP_VERSION; #else return PACKAGE_VERSION; #endif } int belle_sip_stack_get_inactive_transport_timeout(const belle_sip_stack_t *stack){ return stack->inactive_transport_timeout; } void belle_sip_stack_set_inactive_transport_timeout(belle_sip_stack_t *stack, int seconds){ stack->inactive_transport_timeout=seconds; } void belle_sip_stack_set_default_dscp(belle_sip_stack_t *stack, int dscp){ stack->dscp=dscp; } int belle_sip_stack_get_default_dscp(belle_sip_stack_t *stack){ return stack->dscp; } int belle_sip_stack_tls_available(belle_sip_stack_t *stack){ return belle_sip_tls_listening_point_available(); } belle-sip-1.4.1/src/transaction.c000066400000000000000000000557741252242224000166660ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" const char *belle_sip_transaction_state_to_string(belle_sip_transaction_state_t state){ switch(state){ case BELLE_SIP_TRANSACTION_INIT: return "INIT"; case BELLE_SIP_TRANSACTION_TRYING: return "TRYING"; case BELLE_SIP_TRANSACTION_CALLING: return "CALLING"; case BELLE_SIP_TRANSACTION_COMPLETED: return "COMPLETED"; case BELLE_SIP_TRANSACTION_CONFIRMED: return "CONFIRMED"; case BELLE_SIP_TRANSACTION_ACCEPTED: return "ACCEPTED"; case BELLE_SIP_TRANSACTION_PROCEEDING: return "PROCEEDING"; case BELLE_SIP_TRANSACTION_TERMINATED: return "TERMINATED"; } belle_sip_fatal("Invalid transaction state."); return "INVALID"; } void belle_sip_transaction_set_state(belle_sip_transaction_t *t, belle_sip_transaction_state_t state) { belle_sip_message("Changing [%s] [%s] transaction [%p], from state [%s] to [%s]", BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t) ? "client" : "server", belle_sip_request_get_method(t->request), t, belle_sip_transaction_state_to_string(t->state), belle_sip_transaction_state_to_string(state)); t->state=state; } BELLESIP_EXPORT const char *belle_sip_transaction_get_method(const belle_sip_transaction_t *t){ return belle_sip_request_get_method(t->request); } static void belle_sip_transaction_init(belle_sip_transaction_t *t, belle_sip_provider_t *prov, belle_sip_request_t *req){ t->request=(belle_sip_request_t*)belle_sip_object_ref(req); t->provider=prov; } static void transaction_destroy(belle_sip_transaction_t *t){ if (t->request) belle_sip_object_unref(t->request); if (t->last_response) belle_sip_object_unref(t->last_response); if (t->channel) belle_sip_object_unref(t->channel); if (t->branch_id) belle_sip_free(t->branch_id); belle_sip_transaction_set_dialog(t,NULL); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_transaction_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_transaction_t) { BELLE_SIP_VPTR_INIT(belle_sip_transaction_t,belle_sip_object_t,FALSE), (belle_sip_object_destroy_t) transaction_destroy, NULL,/*no clone*/ NULL,/*no marshal*/ }, NULL /*on_terminate*/ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END void *belle_sip_transaction_get_application_data(const belle_sip_transaction_t *t){ return t->appdata; } void belle_sip_transaction_set_application_data(belle_sip_transaction_t *t, void *data){ t->appdata=data; } const char *belle_sip_transaction_get_branch_id(const belle_sip_transaction_t *t){ return t->branch_id; } belle_sip_transaction_state_t belle_sip_transaction_get_state(const belle_sip_transaction_t *t){ return t->state; } int belle_sip_transaction_state_is_transient(const belle_sip_transaction_state_t state) { switch(state){ case BELLE_SIP_TRANSACTION_INIT: case BELLE_SIP_TRANSACTION_TRYING: case BELLE_SIP_TRANSACTION_CALLING: case BELLE_SIP_TRANSACTION_PROCEEDING: return 1; default: return 0; } } void belle_sip_transaction_terminate(belle_sip_transaction_t *t){ if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))!=BELLE_SIP_TRANSACTION_TERMINATED) { int is_client=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t); belle_sip_transaction_set_state(t,BELLE_SIP_TRANSACTION_TERMINATED); if (t->dialog && (!t->last_response || belle_sip_response_get_status_code(t->last_response)<200)){ /*inform the dialog if a transaction terminates without final response.*/ belle_sip_dialog_update(t->dialog,t,!is_client); } belle_sip_message("%s%s %s transaction [%p] terminated" ,is_client ? "Client":"Server" ,t->is_internal ? " internal":"" ,belle_sip_request_get_method(belle_sip_transaction_get_request(t)) ,t); BELLE_SIP_OBJECT_VPTR(t,belle_sip_transaction_t)->on_terminate(t); belle_sip_provider_set_transaction_terminated(t->provider,t); } } belle_sip_request_t *belle_sip_transaction_get_request(const belle_sip_transaction_t *t){ return t->request; } belle_sip_response_t *belle_sip_transaction_get_response(const belle_sip_transaction_t *t) { return t->last_response; } static void notify_timeout(belle_sip_transaction_t *t){ belle_sip_timeout_event_t ev; ev.source=(belle_sip_object_t*)t->provider; ev.transaction=t; ev.is_server_transaction=BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t); BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(t,process_timeout,&ev); } void belle_sip_transaction_notify_timeout(belle_sip_transaction_t *t){ /*report the channel as possibly dead. If an alternate IP can be tryied, the channel will notify us with the RETRY state. * Otherwise it will report the error. * We limit this dead channel reporting to REGISTER transactions, who are unlikely to be unresponded. **/ if (strcmp(belle_sip_request_get_method(t->request),"REGISTER")==0){ if ( belle_sip_channel_notify_timeout(t->channel)==TRUE){ belle_sip_warning("Transaction [%p] reporting timeout, reporting to channel.",t); t->timed_out=TRUE; } }else { notify_timeout(t); belle_sip_transaction_terminate(t); } } belle_sip_dialog_t* belle_sip_transaction_get_dialog(const belle_sip_transaction_t *t) { return t->dialog; } static void belle_sip_transaction_reset_dialog(belle_sip_transaction_t *tr, belle_sip_dialog_t *dialog_disapeearing){ if (tr->dialog!=dialog_disapeearing) belle_sip_error("belle_sip_transaction_reset_dialog(): inconsistency."); tr->dialog=NULL; } void belle_sip_transaction_set_dialog(belle_sip_transaction_t *t, belle_sip_dialog_t *dialog){ if (t->dialog==dialog) return; if (dialog) belle_sip_object_weak_ref(dialog,(belle_sip_object_destroy_notify_t)belle_sip_transaction_reset_dialog,t); if (t->dialog) belle_sip_object_weak_unref(t->dialog,(belle_sip_object_destroy_notify_t)belle_sip_transaction_reset_dialog,t); t->dialog=dialog; } /* * Server transaction */ static void server_transaction_destroy(belle_sip_server_transaction_t *t){ } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_server_transaction_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_server_transaction_t) { { BELLE_SIP_VPTR_INIT(belle_sip_server_transaction_t,belle_sip_transaction_t,FALSE), (belle_sip_object_destroy_t) server_transaction_destroy, NULL, NULL }, NULL } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req){ const char *branch; belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via")); branch=belle_sip_header_via_get_branch(via); if (branch==NULL || strncmp(branch,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))!=0){ branch=req->rfc2543_branch; if (branch==NULL) belle_sip_fatal("No computed branch for RFC2543 style of message, this should never happen."); } t->base.branch_id=belle_sip_strdup(branch); belle_sip_transaction_init((belle_sip_transaction_t*)t,prov,req); belle_sip_random_token(t->to_tag,sizeof(t->to_tag)); } void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)t; belle_sip_header_to_t *to=(belle_sip_header_to_t*)belle_sip_message_get_header((belle_sip_message_t*)resp,"to"); belle_sip_dialog_t *dialog=base->dialog; int status_code; belle_sip_object_ref(resp); if (!base->last_response){ belle_sip_hop_t* hop=belle_sip_response_get_return_hop(resp); base->channel=belle_sip_provider_get_channel(base->provider,hop); belle_sip_object_unref(hop); if (!base->channel){ belle_sip_error("Transaction [%p]: No channel available for sending response.",t); return; } belle_sip_object_ref(base->channel); } status_code=belle_sip_response_get_status_code(resp); if (status_code!=100){ if (belle_sip_header_to_get_tag(to)==NULL){ //add a random to tag belle_sip_header_to_set_tag(to,t->to_tag); } /*12.1 Creation of a Dialog Dialogs are created through the generation of non-failure responses to requests with specific methods. Within this specification, only 2xx and 101-199 responses with a To tag, where the request was INVITE, will establish a dialog.*/ if (dialog && status_code>100 && status_code<300){ belle_sip_response_fill_for_dialog(resp,base->request); } } if (BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->send_new_response(t,resp)==0){ if (base->last_response) belle_sip_object_unref(base->last_response); base->last_response=resp; } if (dialog) belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),TRUE); } static void server_transaction_notify(belle_sip_server_transaction_t *t, belle_sip_request_t *req, belle_sip_dialog_t *dialog){ belle_sip_request_event_t event; event.source=(belle_sip_object_t*)t->base.provider; event.server_transaction=t; event.dialog=dialog; event.request=req; BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*) t),process_request_event,&event); } void belle_sip_server_transaction_on_request(belle_sip_server_transaction_t *t, belle_sip_request_t *req){ const char *method=belle_sip_request_get_method(req); if (strcmp(method,"ACK")==0){ /*this must be for an INVITE server transaction */ if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_ist_t)){ belle_sip_ist_t *ist=(belle_sip_ist_t*)t; if (belle_sip_ist_process_ack(ist,(belle_sip_message_t*)req)==0){ belle_sip_dialog_t *dialog=t->base.dialog; if (dialog && belle_sip_dialog_handle_ack(dialog,req)==0) server_transaction_notify(t,req,dialog); /*else nothing to do because retransmission of ACK*/ } }else{ belle_sip_warning("ACK received for non-invite server transaction ?"); } }else if (strcmp(method,"CANCEL")==0){ server_transaction_notify(t,req,t->base.dialog); }else BELLE_SIP_OBJECT_VPTR(t,belle_sip_server_transaction_t)->on_request_retransmission(t); } /* * client transaction */ belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t){ belle_sip_message_t *orig=(belle_sip_message_t*)t->base.request; belle_sip_request_t *req; const char *orig_method=belle_sip_request_get_method((belle_sip_request_t*)orig); if (strcmp(orig_method,"ACK")==0 || strcmp(orig_method,"INVITE")!=0){ belle_sip_error("belle_sip_client_transaction_create_cancel() cannot be used for ACK or non-INVITE transactions."); return NULL; } if (t->base.state!=BELLE_SIP_TRANSACTION_PROCEEDING){ belle_sip_error("belle_sip_client_transaction_create_cancel() can only be used in state BELLE_SIP_TRANSACTION_PROCEEDING" " but current transaction state is %s",belle_sip_transaction_state_to_string(t->base.state)); return NULL; } req=belle_sip_request_new(); belle_sip_request_set_method(req,"CANCEL"); /* 9.1 Client Behavior Since requests other than INVITE are responded to immediately, sending a CANCEL for a non-INVITE request would always create a race condition. The following procedures are used to construct a CANCEL request. The Request-URI, Call-ID, To, the numeric part of CSeq, and From header fields in the CANCEL request MUST be identical to those in the request being cancelled, including tags. A CANCEL constructed by a client MUST have only a single Via header field value matching the top Via value in the request being cancelled.*/ belle_sip_request_set_uri(req,(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri((belle_sip_request_t*)orig))); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"via",FALSE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"call-id",FALSE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"from",FALSE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"to",FALSE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,"route",TRUE); belle_sip_util_copy_headers(orig,(belle_sip_message_t*)req,BELLE_SIP_MAX_FORWARDS,FALSE); belle_sip_message_add_header((belle_sip_message_t*)req, (belle_sip_header_t*)belle_sip_header_cseq_create( belle_sip_header_cseq_get_seq_number((belle_sip_header_cseq_t*)belle_sip_message_get_header(orig,"cseq")), "CANCEL")); return req; } int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t){ return belle_sip_client_transaction_send_request_to(t,NULL); } int belle_sip_client_transaction_send_request_to(belle_sip_client_transaction_t *t,belle_sip_uri_t* outbound_proxy) { belle_sip_channel_t *chan; belle_sip_provider_t *prov=t->base.provider; belle_sip_dialog_t *dialog=t->base.dialog; belle_sip_request_t *req=t->base.request; int result=-1; if (t->base.state!=BELLE_SIP_TRANSACTION_INIT){ belle_sip_error("belle_sip_client_transaction_send_request: bad state."); return -1; } /*check uris components compliance*/ if (!belle_sip_request_check_uris_components(t->base.request)) { belle_sip_error("belle_sip_client_transaction_send_request: bad request for transaction [%p]",t); return -1; } /*store preset route for future use by refresher*/ if (outbound_proxy){ t->preset_route=outbound_proxy; belle_sip_object_ref(t->preset_route); } if (t->base.sent_by_dialog_queue){ /*it can be sent immediately, so update the request with latest cseq and route_set */ /*update route and contact just in case they changed*/ belle_sip_dialog_update_request(dialog,req); } else if (t->base.request->dialog_queued){ /*this request was created by belle_sip_dialog_create_queued_request().*/ if (belle_sip_dialog_request_pending(dialog) || dialog->queued_ct!=NULL){ /*it cannot be sent immediately, queue the transaction into dialog*/ belle_sip_message("belle_sip_client_transaction_send_request(): transaction [%p], cannot send request now because dialog is busy" " or other transactions are queued, so queuing into dialog.",t); belle_sip_dialog_queue_client_transaction(dialog,t); return 0; } belle_sip_dialog_update_request(dialog,req); } if (dialog){ belle_sip_dialog_update(dialog,(belle_sip_transaction_t*)t,BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t)); } if (!t->next_hop) { if (t->preset_route) { t->next_hop=belle_sip_hop_new_from_uri(t->preset_route); } else { t->next_hop = belle_sip_stack_get_next_hop(prov->stack,t->base.request); } belle_sip_object_ref(t->next_hop); } else { /*next hop already preset, probably in case of CANCEL*/ } belle_sip_provider_add_client_transaction(t->base.provider,t); /*add it in any case*/ chan=belle_sip_provider_get_channel(prov,t->next_hop); if (chan){ belle_sip_object_ref(chan); belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(t)); t->base.channel=chan; if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_INIT){ belle_sip_message("belle_sip_client_transaction_send_request(): waiting channel to be ready"); belle_sip_channel_prepare(chan); /*the channel will notify us when it is ready*/ } else if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_READY){ /*otherwise we can send immediately*/ BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t); } result=0; }else { belle_sip_error("belle_sip_client_transaction_send_request(): no channel available"); belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(t)); result=-1; } return result; } static unsigned int should_dialog_be_created(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){ belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t)); const char* method = belle_sip_request_get_method(req); int status_code = belle_sip_response_get_status_code(resp); return status_code>=101 && status_code<300 && (strcmp(method,"INVITE")==0 || strcmp(method,"SUBSCRIBE")==0); } void belle_sip_client_transaction_notify_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){ belle_sip_transaction_t *base=(belle_sip_transaction_t*)t; belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t)); const char* method = belle_sip_request_get_method(req); belle_sip_response_event_t event; belle_sip_dialog_t *dialog=base->dialog; int status_code = belle_sip_response_get_status_code(resp); if (base->last_response) belle_sip_object_unref(base->last_response); base->last_response=(belle_sip_response_t*)belle_sip_object_ref(resp); if (dialog){ if (status_code>=101 && status_code<300 && strcmp(method,"INVITE")==0 && (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED)){ /*make sure this response matches the current dialog, or creates a new one*/ if (!belle_sip_dialog_match(dialog,(belle_sip_message_t*)resp,FALSE)){ dialog=belle_sip_provider_find_dialog_from_message(t->base.provider,(belle_sip_message_t*)resp,FALSE); if (!dialog){ dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE);/*belle_sip_dialog_new(base);*/ belle_sip_message("Handling response creating a new dialog !"); } } } } else if (should_dialog_be_created(t,resp)) { dialog=belle_sip_provider_create_dialog_internal(t->base.provider,BELLE_SIP_TRANSACTION(t),FALSE); } if (dialog && belle_sip_dialog_update(dialog,BELLE_SIP_TRANSACTION(t),FALSE)) { /* retransmition, just return*/ belle_sip_message("[%p] is a 200 ok retransmition on dialog [%p], skiping",resp,dialog); return; } event.source=(belle_sip_object_t*)base->provider; event.client_transaction=t; event.dialog=dialog; event.response=(belle_sip_response_t*)resp; BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_response_event,&event); /*check that 200Ok for INVITEs have been acknowledged by listener*/ if (dialog && strcmp(method,"INVITE")==0) belle_sip_dialog_check_ack_sent(dialog); } void belle_sip_client_transaction_add_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){ BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->on_response(t,resp); } belle_sip_uri_t *belle_sip_client_transaction_get_route(belle_sip_client_transaction_t *t){ return t->preset_route; } static void client_transaction_destroy(belle_sip_client_transaction_t *t ){ if (t->preset_route) belle_sip_object_unref(t->preset_route); if (t->next_hop) belle_sip_object_unref(t->next_hop); } static void on_channel_state_changed(belle_sip_channel_listener_t *l, belle_sip_channel_t *chan, belle_sip_channel_state_t state){ belle_sip_client_transaction_t *t=(belle_sip_client_transaction_t*)l; belle_sip_io_error_event_t ev; belle_sip_transaction_state_t tr_state=belle_sip_transaction_get_state((belle_sip_transaction_t*)t); belle_sip_message("transaction [%p] channel state changed to [%s]" ,t ,belle_sip_channel_state_to_string(state)); switch(state){ case BELLE_SIP_CHANNEL_READY: if (tr_state==BELLE_SIP_TRANSACTION_INIT){ BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t); } break; case BELLE_SIP_CHANNEL_DISCONNECTED: case BELLE_SIP_CHANNEL_ERROR: ev.transport=belle_sip_channel_get_transport_name(chan); ev.source=BELLE_SIP_OBJECT(t); ev.port=chan->peer_port; ev.host=chan->peer_name; if ( tr_state!=BELLE_SIP_TRANSACTION_COMPLETED && tr_state!=BELLE_SIP_TRANSACTION_CONFIRMED && tr_state!=BELLE_SIP_TRANSACTION_ACCEPTED && tr_state!=BELLE_SIP_TRANSACTION_TERMINATED) { BELLE_SIP_PROVIDER_INVOKE_LISTENERS_FOR_TRANSACTION(((belle_sip_transaction_t*)t),process_io_error,&ev); } if (t->base.timed_out) notify_timeout((belle_sip_transaction_t*)t); belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(t)); break; default: /*ignored*/ break; } } BELLE_SIP_IMPLEMENT_INTERFACE_BEGIN(belle_sip_client_transaction_t,belle_sip_channel_listener_t) on_channel_state_changed, NULL, NULL BELLE_SIP_IMPLEMENT_INTERFACE_END BELLE_SIP_DECLARE_IMPLEMENTED_INTERFACES_1(belle_sip_client_transaction_t, belle_sip_channel_listener_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_client_transaction_t) { { BELLE_SIP_VPTR_INIT(belle_sip_client_transaction_t,belle_sip_transaction_t,FALSE), (belle_sip_object_destroy_t)client_transaction_destroy, NULL, NULL }, NULL }, NULL, NULL BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END void belle_sip_client_transaction_init(belle_sip_client_transaction_t *obj, belle_sip_provider_t *prov, belle_sip_request_t *req){ belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via")); char token[BELLE_SIP_BRANCH_ID_LENGTH]; if (!via){ belle_sip_fatal("belle_sip_client_transaction_init(): No via in request."); } if (strcmp(belle_sip_request_get_method(req),"CANCEL")!=0){ obj->base.branch_id=belle_sip_strdup_printf(BELLE_SIP_BRANCH_MAGIC_COOKIE ".%s",belle_sip_random_token(token,sizeof(token))); belle_sip_header_via_set_branch(via,obj->base.branch_id); }else{ obj->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via)); } belle_sip_transaction_init((belle_sip_transaction_t*)obj, prov,req); } belle_sip_refresher_t* belle_sip_client_transaction_create_refresher(belle_sip_client_transaction_t *t) { return belle_sip_refresher_new(t); } belle_sip_request_t* belle_sip_client_transaction_create_authenticated_request(belle_sip_client_transaction_t *t,belle_sip_list_t** auth_infos,const char* realm) { belle_sip_request_t* initial_request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(t)); belle_sip_request_t* req=belle_sip_request_clone_with_body(initial_request); belle_sip_header_cseq_t* cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); if (belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)) != BELLE_SIP_TRANSACTION_COMPLETED && belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t)) != BELLE_SIP_TRANSACTION_TERMINATED) { belle_sip_error("Invalid state [%s] for transaction [%p], should be BELLE_SIP_TRANSACTION_COMPLETED | BELLE_SIP_TRANSACTION_TERMINATED" ,belle_sip_transaction_state_to_string(belle_sip_transaction_get_state(BELLE_SIP_TRANSACTION(t))) ,t); belle_sip_object_unref(req); return NULL; } /*remove auth headers*/ belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_PROXY_AUTHORIZATION); /*put auth header*/ belle_sip_provider_add_authorization(t->base.provider,req,t->base.last_response,NULL,auth_infos,realm); return req; } belle-sip-1.4.1/src/transports/000077500000000000000000000000001252242224000163725ustar00rootroot00000000000000belle-sip-1.4.1/src/transports/stream_channel.c000066400000000000000000000252401252242224000215240ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include "belle-sip/mainloop.h" #include "stream_channel.h" static void set_tcp_nodelay(belle_sip_socket_t sock){ int tmp=1; int err=setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,(char*)&tmp,sizeof(tmp)); if (err == -1){ belle_sip_warning ("Fail to set TCP_NODELAY: %s.", belle_sip_get_socket_error_string()); } } /*************TCP********/ static int stream_channel_process_data(belle_sip_stream_channel_t *obj,unsigned int revents); static void stream_channel_uninit(belle_sip_stream_channel_t *obj){ belle_sip_socket_t sock = belle_sip_source_get_socket((belle_sip_source_t*)obj); if (sock!=(belle_sip_socket_t)-1) stream_channel_close(obj); } int stream_channel_send(belle_sip_stream_channel_t *obj, const void *buf, size_t buflen){ belle_sip_socket_t sock = belle_sip_source_get_socket((belle_sip_source_t*)obj); int err; err=send(sock,buf,buflen,0); if (err==(belle_sip_socket_t)-1){ int errnum=get_socket_error(); if (!belle_sip_error_code_is_would_block(errnum)){ belle_sip_error("Could not send stream packet on channel [%p]: %s",obj,belle_sip_get_socket_error_string()); } return -errnum; } return err; } int stream_channel_recv(belle_sip_stream_channel_t *obj, void *buf, size_t buflen){ belle_sip_socket_t sock = belle_sip_source_get_socket((belle_sip_source_t*)obj); int err; err=recv(sock,buf,buflen,0); if (err==(belle_sip_socket_t)-1){ int errnum=get_socket_error(); if (!belle_sip_error_code_is_would_block(errnum)){ belle_sip_error("Could not receive stream packet: %s",belle_sip_get_socket_error_string()); } return -errnum; } return err; } void stream_channel_close(belle_sip_stream_channel_t *obj){ belle_sip_socket_t sock = belle_sip_source_get_socket((belle_sip_source_t*)obj); if (sock!=(belle_sip_socket_t)-1){ #if TARGET_OS_IPHONE if (obj->read_stream != NULL) { CFReadStreamClose (obj->read_stream); CFRelease (obj->read_stream); obj->read_stream=NULL; } if (obj->write_stream != NULL) { CFWriteStreamClose (obj->write_stream); CFRelease (obj->write_stream); obj->write_stream=NULL; } #endif close_socket(sock); } } #if TARGET_OS_IPHONE static void stream_channel_enable_ios_background_mode(belle_sip_stream_channel_t *obj){ int sock=belle_sip_source_get_socket((belle_sip_source_t*)obj); CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock, &obj->read_stream, &obj->write_stream); if (obj->read_stream){ if (!CFReadStreamSetProperty (obj->read_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP)){ belle_sip_warning("CFReadStreamSetProperty() could not set VoIP service type on read stream."); } }else belle_sip_warning("CFStreamCreatePairWithSocket() could not create the read stream."); if (obj->write_stream){ if (!CFWriteStreamSetProperty (obj->write_stream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP)){ belle_sip_warning("CFReadStreamSetProperty() could not set VoIP service type on write stream."); } }else belle_sip_warning("CFStreamCreatePairWithSocket() could not create the write stream."); if (!CFReadStreamOpen (obj->read_stream)) { belle_sip_warning("CFReadStreamOpen() failed."); } if (!CFWriteStreamOpen (obj->write_stream)) { belle_sip_warning("CFWriteStreamOpen() failed."); } } #endif int stream_channel_connect(belle_sip_stream_channel_t *obj, const struct addrinfo *ai){ int err; int tmp; belle_sip_socket_t sock; tmp=1; obj->base.ai_family=ai->ai_family; sock=socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP); if (sock==(belle_sip_socket_t)-1){ belle_sip_error("Could not create socket: %s",belle_sip_get_socket_error_string()); return -1; } err=setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,(char*)&tmp,sizeof(tmp)); if (err!=0){ belle_sip_error("setsockopt TCP_NODELAY failed: [%s]",belle_sip_get_socket_error_string()); } belle_sip_socket_set_nonblocking(sock); if (ai->ai_family==AF_INET6){ belle_sip_socket_enable_dual_stack(sock); } err = connect(sock,ai->ai_addr,ai->ai_addrlen); if (err != 0 && get_socket_error()!=BELLESIP_EINPROGRESS && get_socket_error()!=BELLESIP_EWOULDBLOCK) { belle_sip_error("stream connect failed %s",belle_sip_get_socket_error_string()); close_socket(sock); return -1; } belle_sip_channel_set_socket((belle_sip_channel_t*)obj,sock,(belle_sip_source_func_t)stream_channel_process_data); belle_sip_source_set_events((belle_sip_source_t*)obj,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_WRITE|BELLE_SIP_EVENT_ERROR); belle_sip_source_set_timeout((belle_sip_source_t*)obj,belle_sip_stack_get_transport_timeout(obj->base.stack)); belle_sip_main_loop_add_source(obj->base.stack->ml,(belle_sip_source_t*)obj); return 0; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_stream_channel_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_stream_channel_t) { { BELLE_SIP_VPTR_INIT(belle_sip_stream_channel_t,belle_sip_channel_t,FALSE), (belle_sip_object_destroy_t)stream_channel_uninit, NULL, NULL }, "TCP", 1, /*is_reliable*/ (int (*)(belle_sip_channel_t *, const struct addrinfo *))stream_channel_connect, (int (*)(belle_sip_channel_t *, const void *, size_t ))stream_channel_send, (int (*)(belle_sip_channel_t *, void *, size_t ))stream_channel_recv, (void (*)(belle_sip_channel_t *))stream_channel_close, } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END int finalize_stream_connection(belle_sip_stream_channel_t *obj, unsigned int revents, struct sockaddr *addr, socklen_t* slen) { int err, errnum; socklen_t optlen=sizeof(errnum); belle_sip_socket_t sock=belle_sip_source_get_socket((belle_sip_source_t*)obj); if (revents==BELLE_SIP_EVENT_TIMEOUT){ belle_sip_warning("channel [%p]: user-defined transport timeout.",obj); return -1; } if (!(revents & BELLE_SIP_EVENT_WRITE) && !(revents & BELLE_SIP_EVENT_READ)){ belle_sip_warning("channel [%p]: getting unexpected event while connecting",obj); return -1; } err=getsockopt(sock,SOL_SOCKET,SO_ERROR,(void*)&errnum,&optlen); if (err!=0){ belle_sip_error("Failed to retrieve connection status for fd [%i]: cause [%s]",sock,belle_sip_get_socket_error_string()); return -1; }else{ if (errnum==0){ /*obtain bind address for client*/ err=getsockname(sock,addr,slen); if (err<0){ belle_sip_error("Failed to retrieve sockname for fd [%i]: cause [%s]",sock,belle_sip_get_socket_error_string()); return -1; } #if TARGET_OS_IPHONE stream_channel_enable_ios_background_mode(obj); #endif if (obj->base.stack->dscp && obj->base.lp){ /*apply dscp only to channel belonging to a SIP listening point*/ belle_sip_socket_set_dscp(sock,obj->base.ai_family,obj->base.stack->dscp); } set_tcp_nodelay(sock); return 0; }else{ belle_sip_error("Connection failed for fd [%i]: cause [%s]",sock,belle_sip_get_socket_error_string_from_code(errnum)); return -1; } } } static int stream_channel_process_data(belle_sip_stream_channel_t *obj,unsigned int revents){ struct sockaddr_storage ss; socklen_t addrlen=sizeof(ss); belle_sip_channel_state_t state=belle_sip_channel_get_state((belle_sip_channel_t*)obj); belle_sip_channel_t *base=(belle_sip_channel_t*)obj; /*belle_sip_message("TCP channel process_data");*/ if (state == BELLE_SIP_CHANNEL_CONNECTING ) { if (finalize_stream_connection(obj,revents,(struct sockaddr*)&ss,&addrlen)) { belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(base),base->peer_name,base->peer_port); channel_set_state(base,BELLE_SIP_CHANNEL_ERROR); return BELLE_SIP_STOP; } belle_sip_source_set_events((belle_sip_source_t*)obj,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR); belle_sip_source_set_timeout((belle_sip_source_t*)obj,-1); belle_sip_channel_set_ready(base,(struct sockaddr*)&ss,addrlen); return BELLE_SIP_CONTINUE; } else if (state == BELLE_SIP_CHANNEL_READY) { return belle_sip_channel_process_data(base,revents); } else { belle_sip_warning("Unexpected event [%i], in state [%s] for channel [%p]",revents,belle_sip_channel_state_to_string(state),obj); return BELLE_SIP_STOP; } return BELLE_SIP_CONTINUE; } void belle_sip_stream_channel_init_client(belle_sip_stream_channel_t *obj, belle_sip_stack_t *stack, const char *bindip, int localport, const char *peer_cname, const char *dest, int port){ belle_sip_channel_init((belle_sip_channel_t*)obj, stack ,bindip,localport,peer_cname,dest,port); } belle_sip_channel_t * belle_sip_stream_channel_new_client(belle_sip_stack_t *stack,const char *bindip, int localport, const char *peer_cname, const char *dest, int port){ belle_sip_stream_channel_t *obj=belle_sip_object_new(belle_sip_stream_channel_t); belle_sip_stream_channel_init_client(obj,stack,bindip,localport,peer_cname,dest,port); return (belle_sip_channel_t*)obj; } /*child of server socket*/ belle_sip_channel_t * belle_sip_stream_channel_new_child(belle_sip_stack_t *stack, belle_sip_socket_t sock, struct sockaddr *remote_addr, socklen_t slen){ struct sockaddr_storage localaddr; socklen_t local_len=sizeof(localaddr); belle_sip_stream_channel_t *obj; int err; int optval=1; err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof (optval)); if (err == -1){ belle_sip_warning ("Fail to set SIP/TCP address reusable: %s.", belle_sip_get_socket_error_string()); } set_tcp_nodelay(sock); if (getsockname(sock,(struct sockaddr*)&localaddr,&local_len)==-1){ belle_sip_error("getsockname() failed: %s",belle_sip_get_socket_error_string()); return NULL; } obj=belle_sip_object_new(belle_sip_stream_channel_t); belle_sip_channel_init_with_addr((belle_sip_channel_t*)obj,stack,NULL,0,remote_addr,slen); belle_sip_socket_set_nonblocking(sock); belle_sip_channel_set_socket((belle_sip_channel_t*)obj,sock,(belle_sip_source_func_t)stream_channel_process_data); belle_sip_source_set_events((belle_sip_source_t*)obj,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR); belle_sip_channel_set_ready((belle_sip_channel_t*)obj,(struct sockaddr*)&localaddr,local_len); belle_sip_main_loop_add_source(stack->ml,(belle_sip_source_t*)obj); return (belle_sip_channel_t*)obj; } belle-sip-1.4.1/src/transports/stream_channel.h000066400000000000000000000046061252242224000215340ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef STREAM_CHANNEL_H_ #define STREAM_CHANNEL_H_ #ifdef __APPLE_ #include "TargetConditionals.h" #endif #if TARGET_OS_IPHONE #include #include #endif #include "channel.h" struct belle_sip_stream_channel{ belle_sip_channel_t base; #if TARGET_OS_IPHONE CFReadStreamRef read_stream; CFWriteStreamRef write_stream; #endif }; BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_stream_channel_t,belle_sip_channel_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END void belle_sip_stream_channel_init_client(belle_sip_stream_channel_t *obj, belle_sip_stack_t *stack, const char *bindip, int localport,const char *peer_cname, const char *dest, int port); BELLESIP_INTERNAL_EXPORT belle_sip_channel_t * belle_sip_stream_channel_new_client(belle_sip_stack_t *stack, const char *bindip, int localport, const char *peer_cname, const char *name, int port); belle_sip_channel_t * belle_sip_stream_channel_new_child(belle_sip_stack_t *stack, belle_sip_socket_t sock, struct sockaddr *remote_addr, socklen_t slen); void stream_channel_close(belle_sip_stream_channel_t *obj); int stream_channel_connect(belle_sip_stream_channel_t *obj, const struct addrinfo *ai); /*return 0 if succeed*/ int finalize_stream_connection(belle_sip_stream_channel_t *obj, unsigned int revents, struct sockaddr *addr, socklen_t* slen); int stream_channel_send(belle_sip_stream_channel_t *obj, const void *buf, size_t buflen); int stream_channel_recv(belle_sip_stream_channel_t *obj, void *buf, size_t buflen); /*for testing purpose*/ BELLESIP_INTERNAL_EXPORT void belle_sip_channel_parse_stream(belle_sip_channel_t *obj, int end_of_stream); #endif /* STREAM_CHANNEL_H_ */ belle-sip-1.4.1/src/transports/stream_listeningpoint.c000066400000000000000000000162411252242224000231630ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #ifdef ENABLE_SERVER_SOCKETS static int on_new_connection(void *userdata, unsigned int events); void belle_sip_stream_listening_point_destroy_server_socket(belle_sip_stream_listening_point_t *lp){ if (lp->server_sock!=(belle_sip_socket_t)-1){ close_socket(lp->server_sock); lp->server_sock=-1; } if (lp->source){ belle_sip_main_loop_remove_source(lp->base.stack->ml,lp->source); belle_sip_object_unref(lp->source); lp->source=NULL; } } #endif /* ENABLE_SERVER_SOCKETS */ static void belle_sip_stream_listening_point_uninit(belle_sip_stream_listening_point_t *lp){ #ifdef ENABLE_SERVER_SOCKETS belle_sip_stream_listening_point_destroy_server_socket(lp); #endif /* ENABLE_SERVER_SOCKETS */ } static belle_sip_channel_t *stream_create_channel(belle_sip_listening_point_t *lp, const belle_sip_hop_t *hop){ belle_sip_channel_t *chan=belle_sip_stream_channel_new_client(lp->stack ,belle_sip_uri_get_host(lp->listening_uri) ,belle_sip_uri_get_port(lp->listening_uri) ,hop->cname,hop->host,hop->port); return chan; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_stream_listening_point_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_stream_listening_point_t) { { BELLE_SIP_VPTR_INIT(belle_sip_stream_listening_point_t, belle_sip_listening_point_t,TRUE), (belle_sip_object_destroy_t)belle_sip_stream_listening_point_uninit, NULL, NULL }, "TCP", stream_create_channel } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END #ifdef ENABLE_SERVER_SOCKETS static belle_sip_socket_t create_server_socket(const char *addr, int * port, int *family){ struct addrinfo hints={0}; struct addrinfo *res=NULL; int err; belle_sip_socket_t sock; char portnum[10]; int optval=1; if (*port==-1) *port=0; /*random port for bind()*/ snprintf(portnum,sizeof(portnum),"%i",*port); hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=IPPROTO_TCP; hints.ai_flags=AI_NUMERICSERV; err=getaddrinfo(addr,portnum,&hints,&res); if (err!=0){ belle_sip_error("getaddrinfo() failed for %s port %i: %s",addr,*port,gai_strerror(err)); return -1; } *family=res->ai_family; sock=socket(res->ai_family,res->ai_socktype,res->ai_protocol); if (sock==(belle_sip_socket_t)-1){ belle_sip_error("Cannot create TCP socket: %s",belle_sip_get_socket_error_string()); freeaddrinfo(res); return -1; } err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof (optval)); if (err == -1){ belle_sip_warning ("Fail to set SIP/TCP address reusable: %s.", belle_sip_get_socket_error_string()); } if (res->ai_family==AF_INET6){ belle_sip_socket_enable_dual_stack(sock); } err=bind(sock,res->ai_addr,res->ai_addrlen); if (err==-1){ belle_sip_error("TCP bind() failed for %s port %i: %s",addr,*port,belle_sip_get_socket_error_string()); close_socket(sock); freeaddrinfo(res); return -1; } freeaddrinfo(res); if (*port==0){ struct sockaddr_storage saddr; socklen_t saddr_len=sizeof(saddr); err=getsockname(sock,(struct sockaddr*)&saddr,&saddr_len); if (err==0){ err=getnameinfo((struct sockaddr*)&saddr,saddr_len,NULL,0,portnum,sizeof(portnum),NI_NUMERICSERV|NI_NUMERICHOST); if (err==0){ *port=atoi(portnum); belle_sip_message("Random TCP port is %i",*port); }else belle_sip_error("TCP bind failed, getnameinfo(): %s",gai_strerror(err)); }else belle_sip_error("TCP bind failed, getsockname(): %s",belle_sip_get_socket_error_string()); } err=listen(sock,64); if (err==-1){ belle_sip_error("TCP listen() failed for %s port %i: %s",addr,*port,belle_sip_get_socket_error_string()); close_socket(sock); return -1; } return sock; } void belle_sip_stream_listening_point_setup_server_socket(belle_sip_stream_listening_point_t *obj, belle_sip_source_func_t on_new_connection_cb ){ int port=belle_sip_uri_get_port(obj->base.listening_uri); obj->server_sock=create_server_socket(belle_sip_uri_get_host(obj->base.listening_uri), &port, &obj->base.ai_family); if (obj->server_sock==(belle_sip_socket_t)-1) return; belle_sip_uri_set_port(((belle_sip_listening_point_t*)obj)->listening_uri,port); if (obj->base.stack->dscp) belle_sip_socket_set_dscp(obj->server_sock,obj->base.ai_family,obj->base.stack->dscp); obj->source=belle_sip_socket_source_new(on_new_connection_cb,obj,obj->server_sock,BELLE_SIP_EVENT_READ,-1); belle_sip_main_loop_add_source(obj->base.stack->ml,obj->source); } static int on_new_connection(void *userdata, unsigned int events){ belle_sip_socket_t child; struct sockaddr_storage addr; socklen_t slen=sizeof(addr); belle_sip_stream_listening_point_t *lp=(belle_sip_stream_listening_point_t*)userdata; belle_sip_channel_t *chan; child=accept(lp->server_sock,(struct sockaddr*)&addr,&slen); if (child==(belle_sip_socket_t)-1){ belle_sip_error("Listening point [%p] accept() failed on TCP server socket: %s",lp,belle_sip_get_socket_error_string()); belle_sip_stream_listening_point_destroy_server_socket(lp); belle_sip_stream_listening_point_setup_server_socket(lp,on_new_connection); return BELLE_SIP_STOP; } belle_sip_message("New connection arriving !"); chan=belle_sip_stream_channel_new_child(lp->base.stack,child,(struct sockaddr*)&addr,slen); if (chan) belle_sip_listening_point_add_channel((belle_sip_listening_point_t*)lp,chan); return BELLE_SIP_CONTINUE; } void belle_sip_stream_listening_point_init(belle_sip_stream_listening_point_t *obj, belle_sip_stack_t *s, const char *ipaddress, int port, belle_sip_source_func_t on_new_connection_cb ){ belle_sip_listening_point_init((belle_sip_listening_point_t*)obj,s,ipaddress,port); belle_sip_stream_listening_point_setup_server_socket(obj, on_new_connection_cb); } #else void belle_sip_stream_listening_point_init(belle_sip_stream_listening_point_t *obj, belle_sip_stack_t *s, const char *ipaddress, int port ){ belle_sip_listening_point_init((belle_sip_listening_point_t*)obj,s,ipaddress,port); } #endif /* ENABLE_SERVER_SOCKETS */ belle_sip_listening_point_t * belle_sip_stream_listening_point_new(belle_sip_stack_t *s, const char *ipaddress, int port){ belle_sip_stream_listening_point_t *lp=belle_sip_object_new(belle_sip_stream_listening_point_t); #ifdef ENABLE_SERVER_SOCKETS belle_sip_stream_listening_point_init(lp,s,ipaddress,port,on_new_connection); if (lp->server_sock==(belle_sip_socket_t)-1){ belle_sip_object_unref(lp); return NULL; } #else belle_sip_stream_listening_point_init(lp,s,ipaddress,port); #endif /* ENABLE_SERVER_SOCKETS */ return BELLE_SIP_LISTENING_POINT(lp); } belle-sip-1.4.1/src/transports/tls_channel_polarssl.c000066400000000000000000001022231252242224000227470ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include "stream_channel.h" #ifdef HAVE_POLARSSL /* Uncomment to get very verbose polarssl logs*/ //#define ENABLE_POLARSSL_LOGS #include #include #include #include #if POLARSSL_VERSION_NUMBER >= 0x01030000 #include #include #include #include #include #include #endif #endif struct belle_sip_certificates_chain { belle_sip_object_t objet; #ifdef HAVE_POLARSSL #if POLARSSL_VERSION_NUMBER < 0x01030000 x509_cert cert; #else x509_crt cert; #endif #endif }; struct belle_sip_signing_key { belle_sip_object_t objet; #ifdef HAVE_POLARSSL #if POLARSSL_VERSION_NUMBER < 0x01030000 rsa_context key; #else pk_context key; #endif #endif }; #if POLARSSL_VERSION_NUMBER < 0x01030000 /*stubs*/ char *belle_sip_certificates_chain_get_pem(belle_sip_certificates_chain_t *cert) { return NULL; } char *belle_sip_signing_key_get_pem(belle_sip_signing_key_t *key) { return NULL; } #endif #ifdef HAVE_POLARSSL /** * Retrieve key or certificate in a string(PEM format) */ #if POLARSSL_VERSION_NUMBER >= 0x01030000 char *belle_sip_certificates_chain_get_pem(belle_sip_certificates_chain_t *cert) { char *pem_certificate = NULL; size_t olen=0; if (cert == NULL) return NULL; pem_certificate = (char*)belle_sip_malloc(4096); pem_write_buffer("-----BEGIN CERTIFICATE-----\n", "-----END CERTIFICATE-----\n", cert->cert.raw.p, cert->cert.raw.len, (unsigned char*)pem_certificate, 4096, &olen ); return pem_certificate; } char *belle_sip_signing_key_get_pem(belle_sip_signing_key_t *key) { char *pem_key; if (key == NULL) return NULL; pem_key = (char *)belle_sip_malloc(4096); pk_write_key_pem( &(key->key), (unsigned char *)pem_key, 4096); return pem_key; } #endif /* POLARSSL_VERSION_NUMBER >= 0x01030000 */ /*************tls********/ // SSL verification callback prototype // der - raw certificate data, in DER format // length - length of certificate DER data // depth - position of certificate in cert chain, ending at 0 = root or top // flags - verification state for CURRENT certificate only typedef int (*verify_cb_error_cb_t)(unsigned char* der, int length, int depth, int* flags); static verify_cb_error_cb_t tls_verify_cb_error_cb = NULL; static int tls_process_data(belle_sip_channel_t *obj,unsigned int revents); struct belle_sip_tls_channel{ belle_sip_stream_channel_t base; ssl_context sslctx; #if POLARSSL_VERSION_NUMBER < 0x01030000 x509_cert root_ca; #else x509_crt root_ca; #endif struct sockaddr_storage ss; socklen_t socklen; int socket_connected; char *cur_debug_msg; belle_sip_certificates_chain_t* client_cert_chain; belle_sip_signing_key_t* client_cert_key; belle_tls_verify_policy_t *verify_ctx; }; static void tls_channel_close(belle_sip_tls_channel_t *obj){ belle_sip_socket_t sock = belle_sip_source_get_socket((belle_sip_source_t*)obj); if (sock!=-1 && belle_sip_channel_get_state((belle_sip_channel_t*)obj)!=BELLE_SIP_CHANNEL_ERROR) ssl_close_notify(&obj->sslctx); stream_channel_close((belle_sip_stream_channel_t*)obj); ssl_session_reset(&obj->sslctx); obj->socket_connected=0; } static void tls_channel_uninit(belle_sip_tls_channel_t *obj){ belle_sip_socket_t sock = belle_sip_source_get_socket((belle_sip_source_t*)obj); if (sock!=(belle_sip_socket_t)-1) tls_channel_close(obj); ssl_free(&obj->sslctx); #if POLARSSL_VERSION_NUMBER < 0x01030000 x509_free(&obj->root_ca); #else x509_crt_free(&obj->root_ca); #endif if (obj->cur_debug_msg) belle_sip_free(obj->cur_debug_msg); belle_sip_object_unref(obj->verify_ctx); if (obj->client_cert_chain) belle_sip_object_unref(obj->client_cert_chain); if (obj->client_cert_key) belle_sip_object_unref(obj->client_cert_key); } static int tls_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen){ belle_sip_tls_channel_t* channel = (belle_sip_tls_channel_t*)obj; int err = ssl_write(&channel->sslctx,buf,buflen); if (err<0){ char tmp[256]={0}; if (err==POLARSSL_ERR_NET_WANT_WRITE) return -BELLESIP_EWOULDBLOCK; error_strerror(err,tmp,sizeof(tmp)); belle_sip_error("Channel [%p]: ssl_write() error [%i]: %s",obj,err,tmp); } return err; } static int tls_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen){ belle_sip_tls_channel_t* channel = (belle_sip_tls_channel_t*)obj; int err = ssl_read(&channel->sslctx,buf,buflen); if (err==POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) return 0; if (err<0){ char tmp[256]={0}; if (err==POLARSSL_ERR_NET_WANT_READ) return -BELLESIP_EWOULDBLOCK; error_strerror(err,tmp,sizeof(tmp)); belle_sip_error("Channel [%p]: ssl_read() error [%i]: %s",obj, err, tmp); } return err; } static int tls_channel_connect(belle_sip_channel_t *obj, const struct addrinfo *ai){ int err= stream_channel_connect((belle_sip_stream_channel_t*)obj,ai); if (err==0){ belle_sip_source_set_notify((belle_sip_source_t *)obj, (belle_sip_source_func_t)tls_process_data); return 0; } return -1; } BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_tls_channel_t,belle_sip_stream_channel_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_tls_channel_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_tls_channel_t) { { { BELLE_SIP_VPTR_INIT(belle_sip_tls_channel_t,belle_sip_stream_channel_t,FALSE), (belle_sip_object_destroy_t)tls_channel_uninit, NULL, NULL }, "TLS", 1, /*is_reliable*/ tls_channel_connect, tls_channel_send, tls_channel_recv, (void (*)(belle_sip_channel_t*))tls_channel_close } } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END static int tls_channel_handshake(belle_sip_tls_channel_t *channel) { int ret; while( channel->sslctx.state != SSL_HANDSHAKE_OVER ) { if ((ret = ssl_handshake_step( &channel->sslctx ))) { break; } if (channel->sslctx.state == SSL_CLIENT_CERTIFICATE && channel->sslctx.client_auth >0) { BELLE_SIP_INVOKE_LISTENERS_ARG1_ARG2( channel->base.base.listeners ,belle_sip_channel_listener_t ,on_auth_requested ,&channel->base.base ,NULL/*not set yet*/); if (channel->client_cert_chain && channel->client_cert_key) { #if POLARSSL_VERSION_NUMBER >= 0x01030000 int err; #endif char tmp[512]={0}; #if POLARSSL_VERSION_NUMBER < 0x01030000 x509parse_cert_info(tmp,sizeof(tmp)-1,"",&channel->client_cert_chain->cert); #else x509_crt_info(tmp,sizeof(tmp)-1,"",&channel->client_cert_chain->cert); #endif belle_sip_message("Channel [%p] found client certificate:\n%s",channel,tmp); #if POLARSSL_VERSION_NUMBER < 0x01030000 ssl_set_own_cert(&channel->sslctx,&channel->client_cert_chain->cert,&channel->client_cert_key->key); #else /* allows public keys other than RSA */ if ((err=ssl_set_own_cert(&channel->sslctx,&channel->client_cert_chain->cert,&channel->client_cert_key->key))) { error_strerror(err,tmp,sizeof(tmp)-1); belle_sip_error("Channel [%p] cannot ssl_set_own_cert [%s]",channel,tmp); } /*update own cert see ssl_handshake frompolarssl*/ channel->sslctx.handshake->key_cert = channel->sslctx.key_cert; #endif } } } return ret; } static int tls_process_handshake(belle_sip_channel_t *obj){ belle_sip_tls_channel_t* channel=(belle_sip_tls_channel_t*)obj; int err=tls_channel_handshake(channel); if (err==0){ belle_sip_message("Channel [%p]: SSL handshake finished.",obj); belle_sip_source_set_timeout((belle_sip_source_t*)obj,-1); belle_sip_channel_set_ready(obj,(struct sockaddr*)&channel->ss,channel->socklen); }else if (err==POLARSSL_ERR_NET_WANT_READ || err==POLARSSL_ERR_NET_WANT_WRITE){ belle_sip_message("Channel [%p]: SSL handshake in progress...",obj); }else{ char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); belle_sip_error("Channel [%p]: SSL handshake failed : %s",obj,tmp); return -1; } return 0; } static int tls_process_data(belle_sip_channel_t *obj,unsigned int revents){ belle_sip_tls_channel_t* channel=(belle_sip_tls_channel_t*)obj; if (obj->state == BELLE_SIP_CHANNEL_CONNECTING ) { if (!channel->socket_connected) { channel->socklen=sizeof(channel->ss); if (finalize_stream_connection((belle_sip_stream_channel_t*)obj,revents,(struct sockaddr*)&channel->ss,&channel->socklen)) { goto process_error; } belle_sip_message("Channel [%p]: Connected at TCP level, now doing TLS handshake",obj); channel->socket_connected=1; belle_sip_source_set_events((belle_sip_source_t*)channel,BELLE_SIP_EVENT_READ|BELLE_SIP_EVENT_ERROR); belle_sip_source_set_timeout((belle_sip_source_t*)obj,belle_sip_stack_get_transport_timeout(obj->stack)); if (tls_process_handshake(obj)==-1) goto process_error; }else{ if (revents & BELLE_SIP_EVENT_READ){ if (tls_process_handshake(obj)==-1) goto process_error; }else if (revents==BELLE_SIP_EVENT_TIMEOUT){ belle_sip_error("channel [%p]: SSL handshake took too much time.",obj); goto process_error; }else{ belle_sip_warning("channeEHHCXCCCl [%p]: unexpected event [%i] during TLS handshake.",obj,revents); } } } else if ( obj->state == BELLE_SIP_CHANNEL_READY) { return belle_sip_channel_process_data(obj,revents); } else { belle_sip_warning("Unexpected event [%i], for channel [%p]",revents,channel); return BELLE_SIP_STOP; } return BELLE_SIP_CONTINUE; process_error: belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),obj->peer_name,obj->peer_port); channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR); return BELLE_SIP_STOP; } static int polarssl_read(void * ctx, unsigned char *buf, size_t len ){ belle_sip_stream_channel_t *super=(belle_sip_stream_channel_t *)ctx; int ret = stream_channel_recv(super,buf,len); if (ret<0){ ret=-ret; if (ret==BELLESIP_EWOULDBLOCK || ret==BELLESIP_EINPROGRESS || ret == EINTR ) return POLARSSL_ERR_NET_WANT_READ; return POLARSSL_ERR_NET_CONN_RESET; } return ret; } static int polarssl_write(void * ctx, const unsigned char *buf, size_t len ){ belle_sip_stream_channel_t *super=(belle_sip_stream_channel_t *)ctx; int ret = stream_channel_send(super, buf, len); if (ret<0){ ret=-ret; if (ret==BELLESIP_EWOULDBLOCK || ret==BELLESIP_EINPROGRESS || ret == EINTR ) return POLARSSL_ERR_NET_WANT_WRITE; return POLARSSL_ERR_NET_CONN_RESET; } return ret; } static int random_generator(void *ctx, unsigned char *ptr, size_t size){ belle_sip_random_bytes(ptr, size); return 0; } static const char *polarssl_certflags_to_string(char *buf, size_t size, int flags){ int i=0; memset(buf,0,size); size--; if (i0 // 4) return final verification result in *flags when depth == 0 // 5) callback must disable calls to linphone_core_iterate while running // #if POLARSSL_VERSION_NUMBER < 0x01030000 int belle_sip_verify_cb_error_wrapper(x509_cert *cert, int depth, int *flags){ #else int belle_sip_verify_cb_error_wrapper(x509_crt *cert, int depth, int *flags){ #endif int rc = 0; unsigned char *der = NULL; // do nothing if the callback is not set if (!tls_verify_cb_error_cb) { return 0; } belle_sip_message("belle_sip_verify_cb_error_wrapper: depth=[%d], flags=[%d]:\n", depth, *flags); der = belle_sip_malloc(cert->raw.len + 1); if (der == NULL) { // leave the flags alone and just return to the library belle_sip_error("belle_sip_verify_cb_error_wrapper: memory error\n"); return 0; } // copy in and NULL terminate again for safety memcpy(der, cert->raw.p, cert->raw.len); der[cert->raw.len] = '\0'; rc = tls_verify_cb_error_cb(der, cert->raw.len, depth, flags); belle_sip_message("belle_sip_verify_cb_error_wrapper: callback return rc: %d, flags: %d", rc, *flags); belle_sip_free(der); return rc; } #if POLARSSL_VERSION_NUMBER < 0x01030000 static int belle_sip_ssl_verify(void *data , x509_cert *cert , int depth, int *flags){ #else static int belle_sip_ssl_verify(void *data , x509_crt *cert , int depth, int *flags){ #endif belle_tls_verify_policy_t *verify_ctx=(belle_tls_verify_policy_t*)data; char tmp[512]; char flags_str[128]; #if POLARSSL_VERSION_NUMBER < 0x01030000 x509parse_cert_info(tmp,sizeof(tmp),"",cert); #else x509_crt_info(tmp,sizeof(tmp),"",cert); #endif belle_sip_message("Found certificate depth=[%i], flags=[%s]:\n%s", depth,polarssl_certflags_to_string(flags_str,sizeof(flags_str),*flags),tmp); if (verify_ctx->exception_flags==BELLE_TLS_VERIFY_ANY_REASON){ *flags=0; }else if (verify_ctx->exception_flags & BELLE_TLS_VERIFY_CN_MISMATCH){ *flags&=~BADCERT_CN_MISMATCH; } return belle_sip_verify_cb_error_wrapper(cert, depth, flags); } static int belle_sip_tls_channel_load_root_ca(belle_sip_tls_channel_t *obj, const char *path){ struct stat statbuf; if (stat(path,&statbuf)==0){ if (statbuf.st_mode & S_IFDIR){ #if POLARSSL_VERSION_NUMBER < 0x01030000 if (x509parse_crtpath(&obj->root_ca,path)<0){ #else if (x509_crt_parse_path(&obj->root_ca,path)<0){ #endif belle_sip_error("Failed to load root ca from directory %s",path); return -1; } }else{ #if POLARSSL_VERSION_NUMBER < 0x01030000 if (x509parse_crtfile(&obj->root_ca,path)<0){ #else if (x509_crt_parse_file(&obj->root_ca,path)<0){ #endif belle_sip_error("Failed to load root ca from file %s",path); return -1; } } return 0; } belle_sip_error("Could not load root ca from %s: %s",path,strerror(errno)); return -1; } #ifdef ENABLE_POLARSSL_LOGS /* * polarssl does a lot of logs, some with newline, some without. * We need to concatenate logs without new line until a new line is found. */ static void ssl_debug_to_belle_sip(void *context, int level, const char *str){ belle_sip_tls_channel_t *chan=(belle_sip_tls_channel_t*)context; int len=strlen(str); if (len>0 && (str[len-1]=='\n' || str[len-1]=='\r')){ /*eliminate the newline*/ char *tmp=belle_sip_strdup(str); tmp[len-1]=0; if (chan->cur_debug_msg){ belle_sip_message("ssl: %s%s",chan->cur_debug_msg,tmp); belle_sip_free(chan->cur_debug_msg); chan->cur_debug_msg=NULL; }else belle_sip_message("ssl: %s",tmp); belle_sip_free(tmp); }else{ if (chan->cur_debug_msg){ char *tmp=belle_sip_strdup_printf("%s%s",chan->cur_debug_msg,str); belle_sip_free(chan->cur_debug_msg); chan->cur_debug_msg=tmp; }else chan->cur_debug_msg=belle_sip_strdup(str); } } #endif belle_sip_channel_t * belle_sip_channel_new_tls(belle_sip_stack_t *stack, belle_tls_verify_policy_t *verify_ctx,const char *bindip, int localport, const char *peer_cname, const char *dest, int port){ belle_sip_tls_channel_t *obj=belle_sip_object_new(belle_sip_tls_channel_t); belle_sip_stream_channel_t* super=(belle_sip_stream_channel_t*)obj; belle_sip_stream_channel_init_client(super ,stack ,bindip,localport,peer_cname,dest,port); ssl_init(&obj->sslctx); #ifdef ENABLE_POLARSSL_LOGS ssl_set_dbg(&obj->sslctx,ssl_debug_to_belle_sip,obj); #endif ssl_set_endpoint(&obj->sslctx,SSL_IS_CLIENT); ssl_set_authmode(&obj->sslctx,SSL_VERIFY_REQUIRED); ssl_set_bio(&obj->sslctx,polarssl_read,obj,polarssl_write,obj); if (verify_ctx->root_ca && belle_sip_tls_channel_load_root_ca(obj,verify_ctx->root_ca)==0){ ssl_set_ca_chain(&obj->sslctx,&obj->root_ca,NULL,super->base.peer_cname ? super->base.peer_cname : super->base.peer_name ); } ssl_set_rng(&obj->sslctx,random_generator,NULL); ssl_set_verify(&obj->sslctx,belle_sip_ssl_verify,verify_ctx); obj->verify_ctx=(belle_tls_verify_policy_t*)belle_sip_object_ref(verify_ctx); return (belle_sip_channel_t*)obj; } void belle_sip_tls_channel_set_client_certificates_chain(belle_sip_tls_channel_t *channel, belle_sip_certificates_chain_t* cert_chain) { SET_OBJECT_PROPERTY(channel,client_cert_chain,cert_chain); } void belle_sip_tls_channel_set_client_certificate_key(belle_sip_tls_channel_t *channel, belle_sip_signing_key_t* key){ SET_OBJECT_PROPERTY(channel,client_cert_key,key); } #else /*HAVE_POLARSSL*/ void belle_sip_tls_channel_set_client_certificates_chain(belle_sip_tls_channel_t *obj, belle_sip_certificates_chain_t* cert_chain) { belle_sip_error("belle_sip_channel_set_client_certificate_chain requires TLS"); } void belle_sip_tls_channel_set_client_certificate_key(belle_sip_tls_channel_t *obj, belle_sip_signing_key_t* key) { belle_sip_error("belle_sip_channel_set_client_certificate_key requires TLS"); } unsigned char *belle_sip_get_certificates_pem(belle_sip_certificates_chain_t *cert) { return NULL; } unsigned char *belle_sip_get_key_pem(belle_sip_signing_key_t *key) { return NULL; } #endif /**************************** belle_sip_certificates_chain_t **/ static int belle_sip_certificate_fill(belle_sip_certificates_chain_t* certificate,const char* buff, size_t size,belle_sip_certificate_raw_format_t format) { #ifdef HAVE_POLARSSL int err; #if POLARSSL_VERSION_NUMBER < 0x01030000 if ((err=x509parse_crt(&certificate->cert,(const unsigned char *)buff,size)) <0) { #else if ((err=x509_crt_parse(&certificate->cert,(const unsigned char *)buff,size)) <0) { #endif char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); belle_sip_error("cannot parse x509 cert because [%s]",tmp); return -1; } return 0; #else /*HAVE_POLARSSL*/ return -1; #endif } static int belle_sip_certificate_fill_from_file(belle_sip_certificates_chain_t* certificate,const char* path,belle_sip_certificate_raw_format_t format) { #ifdef HAVE_POLARSSL int err; #if POLARSSL_VERSION_NUMBER < 0x01030000 if ((err=x509parse_crtfile(&certificate->cert, path)) <0) { #else if ((err=x509_crt_parse_file(&certificate->cert, path)) <0) { #endif char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); belle_sip_error("cannot parse x509 cert because [%s]",tmp); return -1; } return 0; #else /*HAVE_POLARSSL*/ return -1; #endif } /*belle_sip_certificate */ belle_sip_certificates_chain_t* belle_sip_certificates_chain_parse(const char* buff, size_t size,belle_sip_certificate_raw_format_t format) { belle_sip_certificates_chain_t* certificate = belle_sip_object_new(belle_sip_certificates_chain_t); if (belle_sip_certificate_fill(certificate,buff, size,format)) { belle_sip_object_unref(certificate); certificate=NULL; } return certificate; } belle_sip_certificates_chain_t* belle_sip_certificates_chain_parse_file(const char* path, belle_sip_certificate_raw_format_t format) { belle_sip_certificates_chain_t* certificate = belle_sip_object_new(belle_sip_certificates_chain_t); if (belle_sip_certificate_fill_from_file(certificate, path, format)) { belle_sip_object_unref(certificate); certificate=NULL; } return certificate; } /* * Parse all *.pem files in a given dir(non recursively) and return the one matching the given subject */ int belle_sip_get_certificate_and_pkey_in_dir(const char *path, const char *subject, belle_sip_certificates_chain_t **certificate, belle_sip_signing_key_t **pkey, belle_sip_certificate_raw_format_t format) { #ifdef HAVE_POLARSSL #if POLARSSL_VERSION_NUMBER < 0x01030000 return -1; #else /* POLARSSL_VERSION_NUMBER > 0x01030000 */ /* get all *.pem file from given path */ belle_sip_list_t *file_list = belle_sip_parse_directory(path, ".pem"); char *filename = NULL; file_list = belle_sip_list_pop_front(file_list, (void **)&filename); while (filename != NULL) { belle_sip_certificates_chain_t *found_certificate = belle_sip_certificates_chain_parse_file(filename, format); if (found_certificate != NULL) { /* there is a certificate in this file */ char *subject_CNAME_begin, *subject_CNAME_end; belle_sip_signing_key_t *found_key; char name[500]; memset( name, 0, sizeof(name) ); x509_dn_gets( name, sizeof(name), &(found_certificate->cert.subject)); /* this function is available only in polarssl version >=1.3 */ /* parse subject to find the CN=xxx, field. There may be no , at the and but a \0 */ subject_CNAME_begin = strstr(name, "CN="); if (subject_CNAME_begin!=NULL) { subject_CNAME_begin+=3; subject_CNAME_end = strstr(subject_CNAME_begin, ","); if (subject_CNAME_end != NULL) { *subject_CNAME_end = '\0'; } if (strcmp(subject_CNAME_begin, subject)==0) { /* subject CNAME match the one we are looking for*/ /* do we have a key too ? */ found_key = belle_sip_signing_key_parse_file(filename, NULL); if (found_key!=NULL) { *certificate = found_certificate; *pkey = found_key; belle_sip_free(filename); belle_sip_list_free_with_data(file_list, belle_sip_free); /* free possible rest of list */ return 0; } } } } belle_sip_free(filename); file_list = belle_sip_list_pop_front(file_list, (void **)&filename); } return -1; #endif /* POLARSSL_VERSION_NUMBER >= 0x01030000 */ #else /* ! HAVE_POLARSSL */ return -1; #endif } int belle_sip_generate_self_signed_certificate(const char* path, const char *subject, belle_sip_certificates_chain_t **certificate, belle_sip_signing_key_t **pkey) { #ifdef HAVE_POLARSSL #if POLARSSL_VERSION_NUMBER < 0x01030000 return -1; #else /* POLARSSL_VERSION_NUMBER < 0x01030000 */ entropy_context entropy; ctr_drbg_context ctr_drbg; int ret; mpi serial; x509write_cert crt; FILE *fd; char file_buffer[8192]; size_t file_buffer_len = 0; char *name_with_path; int path_length; char formatted_subject[512]; /* subject may be a sip URL or linphone-dtls-default-identity, add CN= before it to make a valid name */ memcpy(formatted_subject, "CN=", 3); memcpy(formatted_subject+3, subject, strlen(subject)+1); /* +1 to get the \0 termination */ /* allocate certificate and key */ *pkey = belle_sip_object_new(belle_sip_signing_key_t); *certificate = belle_sip_object_new(belle_sip_certificates_chain_t); entropy_init( &entropy ); if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, NULL, 0 ) ) != 0 ) { belle_sip_error("Certificate generation can't init ctr_drbg: -%x", -ret); return -1; } /* generate 3072 bits RSA public/private key */ pk_init( &((*pkey)->key) ); if ( (ret = pk_init_ctx( &((*pkey)->key), pk_info_from_type( POLARSSL_PK_RSA ) )) != 0) { belle_sip_error("Certificate generation can't init pk_ctx: -%x", -ret); return -1; } if ( ( ret = rsa_gen_key( pk_rsa( (*pkey)->key ), ctr_drbg_random, &ctr_drbg, 3072, 65537 ) ) != 0) { belle_sip_error("Certificate generation can't generate rsa key: -%x", -ret); return -1; } /* if there is no path, don't write a file */ if (path!=NULL) { pk_write_key_pem( &((*pkey)->key), (unsigned char *)file_buffer, 4096); file_buffer_len = strlen(file_buffer); } /* generate the certificate */ x509write_crt_init( &crt ); x509write_crt_set_md_alg( &crt, POLARSSL_MD_SHA256 ); mpi_init( &serial ); if ( (ret = mpi_read_string( &serial, 10, "1" ) ) != 0 ) { belle_sip_error("Certificate generation can't read serial mpi: -%x", -ret); return -1; } x509write_crt_set_subject_key( &crt, &((*pkey)->key) ); x509write_crt_set_issuer_key( &crt, &((*pkey)->key) ); if ( (ret = x509write_crt_set_subject_name( &crt, formatted_subject) ) != 0) { belle_sip_error("Certificate generation can't set subject name: -%x", -ret); return -1; } if ( (ret = x509write_crt_set_issuer_name( &crt, formatted_subject) ) != 0) { belle_sip_error("Certificate generation can't set issuer name: -%x", -ret); return -1; } if ( (ret = x509write_crt_set_serial( &crt, &serial ) ) != 0) { belle_sip_error("Certificate generation can't set serial: -%x", -ret); return -1; } mpi_free(&serial); if ( (ret = x509write_crt_set_validity( &crt, "20010101000000", "20300101000000" ) ) != 0) { belle_sip_error("Certificate generation can't set validity: -%x", -ret); return -1; } /* store anyway certificate in pem format in a string even if we do not have file to write as we need it to get it in a x509_crt structure */ if ( (ret = x509write_crt_pem( &crt, (unsigned char *)file_buffer+file_buffer_len, 4096, ctr_drbg_random, &ctr_drbg ) ) != 0) { belle_sip_error("Certificate generation can't write crt pem: -%x", -ret); return -1; } x509write_crt_free(&crt); if ( (ret = x509_crt_parse(&((*certificate)->cert), (unsigned char *)file_buffer, strlen(file_buffer)) ) != 0) { belle_sip_error("Certificate generation can't parse crt pem: -%x", -ret); return -1; } /* write the file if needed */ if (path!=NULL) { name_with_path = (char *)belle_sip_malloc(strlen(path)+257); /* max filename is 256 bytes in dirent structure, +1 for / */ path_length = strlen(path); memcpy(name_with_path, path, path_length); name_with_path[path_length] = '/'; path_length++; memcpy(name_with_path+path_length, subject, strlen(subject)); memcpy(name_with_path+path_length+strlen(subject), ".pem", 5); /* check if directory exists and if not, create it */ belle_sip_mkdir(path); if ( (fd = fopen(name_with_path, "w") ) == NULL) { belle_sip_error("Certificate generation can't open/create file %s", name_with_path); free(name_with_path); belle_sip_object_unref(*pkey); belle_sip_object_unref(*certificate); *pkey = NULL; *certificate = NULL; return -1; } if ( fwrite(file_buffer, 1, strlen(file_buffer), fd) != strlen(file_buffer) ) { belle_sip_error("Certificate generation can't write into file %s", name_with_path); fclose(fd); belle_sip_object_unref(*pkey); belle_sip_object_unref(*certificate); *pkey = NULL; *certificate = NULL; free(name_with_path); return -1; } fclose(fd); free(name_with_path); } return 0; #endif /* else POLARSSL_VERSION_NUMBER < 0x01030000 */ #else /* ! HAVE_POLARSSL */ return -1; #endif } /* Note : this code is duplicated in mediastreamer2/src/voip/dtls_srtp.c but get directly a x509_crt as input parameter */ char *belle_sip_certificates_chain_get_fingerprint(belle_sip_certificates_chain_t *certificate) { #ifdef HAVE_POLARSSL #if POLARSSL_VERSION_NUMBER < 0x01030000 return NULL; #else /* POLARSSL_VERSION_NUMBER < 0x01030000 */ unsigned char buffer[64]={0}; /* buffer is max length of returned hash, which is 64 in case we use sha-512 */ size_t hash_length = 0; const char *hash_alg_string=NULL; char *fingerprint = NULL; x509_crt *crt; if (certificate == NULL) return NULL; crt = &certificate->cert; /* fingerprint is a hash of the DER formated certificate (found in crt->raw.p) using the same hash function used by certificate signature */ switch (crt->sig_md) { case POLARSSL_MD_SHA1: sha1(crt->raw.p, crt->raw.len, buffer); hash_length = 20; hash_alg_string="SHA-1"; break; case POLARSSL_MD_SHA224: sha256(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-224 and not sha-256 */ hash_length = 28; hash_alg_string="SHA-224"; break; case POLARSSL_MD_SHA256: sha256(crt->raw.p, crt->raw.len, buffer, 0); hash_length = 32; hash_alg_string="SHA-256"; break; case POLARSSL_MD_SHA384: sha512(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-384 and not sha-512 */ hash_length = 48; hash_alg_string="SHA-384"; break; case POLARSSL_MD_SHA512: sha512(crt->raw.p, crt->raw.len, buffer, 1); /* last argument is a boolean, indicate to output sha-384 and not sha-512 */ hash_length = 64; hash_alg_string="SHA-512"; break; default: return NULL; break; } if (hash_length>0) { int i; int fingerprint_index = strlen(hash_alg_string); size_t size=fingerprint_index+3*hash_length+1; char prefix=' '; /* fingerprint will be : hash_alg_string+' '+HEX : separated values: length is strlen(hash_alg_string)+3*hash_lenght + 1 for null termination */ fingerprint = belle_sip_malloc0(size); snprintf(fingerprint, size, "%s", hash_alg_string); for (i=0; icert); #else x509_crt_free(&certificate->cert); #endif #endif } static void belle_sip_certificates_chain_clone(belle_sip_certificates_chain_t *certificate, const belle_sip_certificates_chain_t *orig){ belle_sip_error("belle_sip_certificate_clone not supported"); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_certificates_chain_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_certificates_chain_t,belle_sip_object_t,belle_sip_certificates_chain_destroy,belle_sip_certificates_chain_clone,NULL,TRUE); belle_sip_signing_key_t* belle_sip_signing_key_parse(const char* buff, size_t size,const char* passwd) { #ifdef HAVE_POLARSSL belle_sip_signing_key_t* signing_key = belle_sip_object_new(belle_sip_signing_key_t); int err; #if POLARSSL_VERSION_NUMBER < 0x01030000 if ((err=x509parse_key(&signing_key->key,(const unsigned char *)buff,size,(const unsigned char*)passwd,passwd?strlen(passwd):0)) <0) { #else pk_init(&signing_key->key); /* for API v1.3 or greater also parses public keys other than RSA */ err=pk_parse_key(&signing_key->key,(const unsigned char *)buff,size,(const unsigned char*)passwd,passwd?strlen(passwd):0); /* make sure cipher is RSA to be consistent with API v1.2 */ if(err==0 && !pk_can_do(&signing_key->key,POLARSSL_PK_RSA)) err=POLARSSL_ERR_PK_TYPE_MISMATCH; if (err<0) { #endif char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); belle_sip_error("cannot parse public key because [%s]",tmp); #if POLARSSL_VERSION_NUMBER >= 0x01030000 pk_free(&signing_key->key); #endif belle_sip_object_unref(signing_key); return NULL; } return signing_key; #else /*HAVE_POLARSSL*/ return NULL; #endif } belle_sip_signing_key_t* belle_sip_signing_key_parse_file(const char* path,const char* passwd) { #ifdef HAVE_POLARSSL belle_sip_signing_key_t* signing_key = belle_sip_object_new(belle_sip_signing_key_t); int err; #if POLARSSL_VERSION_NUMBER < 0x01030000 if ((err=x509parse_keyfile(&signing_key->key,path, passwd)) <0) { #else pk_init(&signing_key->key); /* for API v1.3 or greater also parses public keys other than RSA */ err=pk_parse_keyfile(&signing_key->key,path, passwd); /* make sure cipher is RSA to be consistent with API v1.2 */ if(err==0 && !pk_can_do(&signing_key->key,POLARSSL_PK_RSA)) err=POLARSSL_ERR_PK_TYPE_MISMATCH; if (err<0) { #endif char tmp[128]; error_strerror(err,tmp,sizeof(tmp)); belle_sip_error("cannot parse public key because [%s]",tmp); #if POLARSSL_VERSION_NUMBER >= 0x01030000 pk_free(&signing_key->key); #endif belle_sip_object_unref(signing_key); return NULL; } return signing_key; #else /*HAVE_POLARSSL*/ return NULL; #endif } static void belle_sip_signing_key_destroy(belle_sip_signing_key_t *signing_key){ #ifdef HAVE_POLARSSL #if POLARSSL_VERSION_NUMBER < 0x01030000 rsa_free(&signing_key->key); #else pk_free(&signing_key->key); #endif #endif } static void belle_sip_signing_key_clone(belle_sip_signing_key_t *signing_key, const belle_sip_signing_key_t *orig){ belle_sip_error("belle_sip_signing_key_clone not supported"); } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_signing_key_t); BELLE_SIP_INSTANCIATE_VPTR(belle_sip_signing_key_t,belle_sip_object_t,belle_sip_signing_key_destroy,belle_sip_signing_key_clone,NULL,TRUE); belle-sip-1.4.1/src/transports/tls_listeningpoint_polarssl.c000066400000000000000000000103261252242224000244070ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #ifdef HAVE_POLARSSL #include static void belle_sip_tls_listening_point_uninit(belle_sip_tls_listening_point_t *lp){ belle_sip_object_unref(lp->verify_ctx); } static belle_sip_channel_t *tls_create_channel(belle_sip_listening_point_t *lp, const belle_sip_hop_t *hop){ belle_sip_channel_t *chan=belle_sip_channel_new_tls(lp->stack, ((belle_sip_tls_listening_point_t*) lp)->verify_ctx ,belle_sip_uri_get_host(lp->listening_uri) ,belle_sip_uri_get_port(lp->listening_uri) ,hop->cname ,hop->host,hop->port); return chan; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_tls_listening_point_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_tls_listening_point_t) { { BELLE_SIP_VPTR_INIT(belle_sip_tls_listening_point_t, belle_sip_stream_listening_point_t,TRUE), (belle_sip_object_destroy_t)belle_sip_tls_listening_point_uninit, NULL, NULL }, "TLS", tls_create_channel } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END #ifdef ENABLE_SERVER_SOCKETS static int on_new_connection(void *userdata, unsigned int revents){ belle_sip_socket_t child; struct sockaddr_storage addr; socklen_t slen=sizeof(addr); belle_sip_tls_listening_point_t *lp=(belle_sip_tls_listening_point_t*)userdata; belle_sip_stream_listening_point_t *super=(belle_sip_stream_listening_point_t*)lp; child=accept(super->server_sock,(struct sockaddr*)&addr,&slen); if (child==(belle_sip_socket_t)-1){ belle_sip_error("Listening point [%p] accept() failed on TLS server socket: %s",lp,belle_sip_get_socket_error_string()); belle_sip_stream_listening_point_destroy_server_socket(super); belle_sip_stream_listening_point_setup_server_socket(super,on_new_connection); return BELLE_SIP_STOP; } belle_sip_message("New connection arriving on TLS, not handled !"); close_socket(child); return BELLE_SIP_CONTINUE; } #endif /* ENABLE_SERVER_SOCKETS */ belle_sip_listening_point_t * belle_sip_tls_listening_point_new(belle_sip_stack_t *s, const char *ipaddress, int port){ belle_sip_tls_listening_point_t *lp=belle_sip_object_new(belle_sip_tls_listening_point_t); #ifdef ENABLE_SERVER_SOCKETS belle_sip_stream_listening_point_init((belle_sip_stream_listening_point_t*)lp,s,ipaddress,port,on_new_connection); #else belle_sip_stream_listening_point_init((belle_sip_stream_listening_point_t*)lp,s,ipaddress,port); #endif /* ENABLE_SERVER_SOCKETS */ lp->verify_ctx=belle_tls_verify_policy_new(); return BELLE_SIP_LISTENING_POINT(lp); } int belle_sip_tls_listening_point_set_root_ca(belle_sip_tls_listening_point_t *lp, const char *path){ return belle_tls_verify_policy_set_root_ca(lp->verify_ctx,path); } int belle_sip_tls_listening_point_set_verify_exceptions(belle_sip_tls_listening_point_t *lp, int flags){ belle_tls_verify_policy_set_exceptions(lp->verify_ctx,flags); return 0; } int belle_sip_tls_listening_point_set_verify_policy(belle_sip_tls_listening_point_t *s, belle_tls_verify_policy_t *pol){ SET_OBJECT_PROPERTY(s,verify_ctx,pol); return 0; } int belle_sip_tls_listening_point_available(void){ return TRUE; } #else belle_sip_listening_point_t * belle_sip_tls_listening_point_new(belle_sip_stack_t *s, const char *ipaddress, int port){ return NULL; } int belle_sip_tls_listening_point_set_root_ca(belle_sip_tls_listening_point_t *s, const char *path){ return -1; } int belle_sip_tls_listening_point_set_verify_exceptions(belle_sip_tls_listening_point_t *s, int value){ return -1; } int belle_sip_tls_listening_point_available(void){ return FALSE; } #endif belle-sip-1.4.1/src/transports/tunnel_channel.c000066400000000000000000000113251252242224000215350ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010-2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include "channel.h" #define TUNNEL_POLLING_DURATION 20 /* in ms */ void * tunnel_client_create_socket(void *tunnelclient, int minLocalPort, int maxLocalPort); void tunnel_client_close_socket(void *tunnelclient, void *tunnelsocket); int tunnel_socket_has_data(void *tunnelsocket); int tunnel_socket_sendto(void *tunnelsocket, const void *buffer, size_t bufsize, const struct sockaddr *dest, socklen_t socklen); int tunnel_socket_recvfrom(void *tunnelsocket, void *buffer, size_t bufsize, struct sockaddr *src, socklen_t socklen); BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_tunnel_channel_t, belle_sip_channel_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END struct belle_sip_tunnel_channel { belle_sip_channel_t base; belle_sip_source_t *pollingtimer; void *tunnelclient; void *tunnelsocket; }; typedef struct belle_sip_tunnel_channel belle_sip_tunnel_channel_t; static int tunnel_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen) { belle_sip_tunnel_channel_t *chan = (belle_sip_tunnel_channel_t *)obj; return tunnel_socket_sendto(chan->tunnelsocket, buf, buflen, obj->current_peer->ai_addr, obj->current_peer->ai_addrlen); } static int tunnel_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen) { belle_sip_tunnel_channel_t *chan = (belle_sip_tunnel_channel_t *)obj; struct sockaddr_storage addr; socklen_t addrlen = sizeof(addr); return tunnel_socket_recvfrom(chan->tunnelsocket, buf, buflen, (struct sockaddr *)&addr, addrlen); } static int tunnel_channel_connect(belle_sip_channel_t *obj, const struct addrinfo *ai) { struct sockaddr_storage laddr; socklen_t lslen = sizeof(laddr); if (obj->local_ip == NULL) { belle_sip_get_src_addr_for(ai->ai_addr, ai->ai_addrlen, (struct sockaddr *)&laddr, &lslen, obj->local_port); } belle_sip_channel_set_ready(obj, (struct sockaddr *)&laddr, lslen); return 0; } static void tunnel_channel_close(belle_sip_channel_t *obj) { belle_sip_tunnel_channel_t *chan = (belle_sip_tunnel_channel_t *)obj; if( chan->tunnelsocket != NULL ){ tunnel_client_close_socket(chan->tunnelclient, chan->tunnelsocket); chan->tunnelsocket = NULL; } } static void tunnel_channel_uninit(belle_sip_channel_t *obj) { belle_sip_tunnel_channel_t *chan = (belle_sip_tunnel_channel_t *)obj; if (chan->tunnelsocket != NULL) { tunnel_channel_close(obj); } if (chan->pollingtimer != NULL) { belle_sip_main_loop_remove_source(obj->stack->ml, chan->pollingtimer); belle_sip_object_unref(chan->pollingtimer); chan->pollingtimer = NULL; } } static int tunnel_polling_timer(belle_sip_tunnel_channel_t *chan) { if ((chan->tunnelsocket != NULL) && tunnel_socket_has_data(chan->tunnelsocket)) { belle_sip_channel_process_data((belle_sip_channel_t *)chan, BELLE_SIP_EVENT_READ); } return BELLE_SIP_CONTINUE; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_tunnel_channel_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_tunnel_channel_t) { { BELLE_SIP_VPTR_INIT(belle_sip_tunnel_channel_t,belle_sip_channel_t,FALSE), (belle_sip_object_destroy_t)tunnel_channel_uninit, NULL, NULL }, "UDP", 0, /*is_reliable*/ tunnel_channel_connect, tunnel_channel_send, tunnel_channel_recv, tunnel_channel_close } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_channel_t * belle_sip_channel_new_tunnel(belle_sip_stack_t *stack, void *tunnelclient, const char *bindip, int localport, const char *dest, int port){ belle_sip_tunnel_channel_t *obj = belle_sip_object_new(belle_sip_tunnel_channel_t); belle_sip_channel_init((belle_sip_channel_t*)obj, stack, bindip, localport, NULL, dest, port); obj->tunnelclient = tunnelclient; obj->tunnelsocket = tunnel_client_create_socket(tunnelclient, 5060, 6060); obj->pollingtimer = belle_sip_timeout_source_new((belle_sip_source_func_t)tunnel_polling_timer, obj, TUNNEL_POLLING_DURATION); belle_sip_object_set_name((belle_sip_object_t*)obj->pollingtimer, "tunnel_polling_timer"); belle_sip_main_loop_add_source(stack->ml, obj->pollingtimer); return (belle_sip_channel_t*)obj; } belle-sip-1.4.1/src/transports/tunnel_listeningpoint.c000066400000000000000000000042311252242224000231710ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010-2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" struct belle_sip_tunnel_listening_point{ belle_sip_listening_point_t base; void *tunnelclient; }; static belle_sip_channel_t *tunnel_create_channel(belle_sip_listening_point_t *lp, const belle_sip_hop_t *hop){ belle_sip_channel_t *chan=belle_sip_channel_new_tunnel(lp->stack, ((belle_sip_tunnel_listening_point_t*)lp)->tunnelclient, belle_sip_uri_get_host(lp->listening_uri), belle_sip_uri_get_port(lp->listening_uri), hop->host, hop->port); return chan; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_tunnel_listening_point_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_tunnel_listening_point_t) { { BELLE_SIP_VPTR_INIT(belle_sip_tunnel_listening_point_t, belle_sip_listening_point_t,TRUE), NULL, NULL, NULL }, "UDP", tunnel_create_channel } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END static void belle_sip_tunnel_listening_point_init(belle_sip_tunnel_listening_point_t *lp, belle_sip_stack_t *s, void *tunnelclient) { belle_sip_listening_point_init((belle_sip_listening_point_t*)lp,s,"0.0.0.0",5060); lp->tunnelclient = tunnelclient; } belle_sip_listening_point_t * belle_sip_tunnel_listening_point_new(belle_sip_stack_t *s, void *tunnelclient){ belle_sip_tunnel_listening_point_t *lp=belle_sip_object_new(belle_sip_tunnel_listening_point_t); belle_sip_tunnel_listening_point_init(lp,s,tunnelclient); return (belle_sip_listening_point_t*)lp; } belle-sip-1.4.1/src/transports/tunnel_wrapper.cc000066400000000000000000000037011252242224000217470ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010-2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include using namespace belledonnecomm; extern "C" void * tunnel_client_create_socket(void *tunnelclient, int minLocalPort, int maxLocalPort) { TunnelClient *tc = static_cast(tunnelclient); return tc->createSocket(minLocalPort, maxLocalPort); } extern "C" void tunnel_client_close_socket(void *tunnelclient, void *tunnelsocket) { TunnelClient *tc = static_cast(tunnelclient); TunnelSocket *ts = static_cast(tunnelsocket); tc->closeSocket(ts); } extern "C" int tunnel_socket_has_data(void *tunnelsocket) { TunnelSocket *ts = static_cast(tunnelsocket); return ts->hasData(); } extern "C" int tunnel_socket_sendto(void *tunnelsocket, const void *buffer, size_t bufsize, const struct sockaddr *dest, socklen_t socklen) { TunnelSocket *ts = static_cast(tunnelsocket); return ts->sendto(buffer, bufsize, dest, socklen); } extern "C" int tunnel_socket_recvfrom(void *tunnelsocket, void *buffer, size_t bufsize, struct sockaddr *src, socklen_t socklen) { TunnelSocket *ts = static_cast(tunnelsocket); return ts->recvfrom(buffer, bufsize, src, socklen); } belle-sip-1.4.1/src/transports/udp_channel.c000066400000000000000000000077661252242224000210360ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" #include "channel.h" BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_udp_channel_t,belle_sip_channel_t) BELLE_SIP_DECLARE_CUSTOM_VPTR_END struct belle_sip_udp_channel{ belle_sip_channel_t base; }; typedef struct belle_sip_udp_channel belle_sip_udp_channel_t; static void udp_channel_uninit(belle_sip_udp_channel_t *obj){ /*no close of the socket, because it is owned by the listerning point and shared between all channels*/ } static int udp_channel_send(belle_sip_channel_t *obj, const void *buf, size_t buflen){ belle_sip_udp_channel_t *chan=(belle_sip_udp_channel_t *)obj; int err; belle_sip_socket_t sock=belle_sip_source_get_socket((belle_sip_source_t*)chan); err=sendto(sock,buf,buflen,0,obj->current_peer->ai_addr,obj->current_peer->ai_addrlen); if (err==-1){ belle_sip_error("channel [%p]: could not send UDP packet because [%s]",obj,belle_sip_get_socket_error_string()); return -errno; } return err; } static int udp_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen){ belle_sip_udp_channel_t *chan=(belle_sip_udp_channel_t *)obj; int err; struct sockaddr_storage addr; socklen_t addrlen=sizeof(addr); belle_sip_socket_t sock=belle_sip_source_get_socket((belle_sip_source_t*)chan); err=recvfrom(sock,buf,buflen,0,(struct sockaddr*)&addr,&addrlen); if (err==-1 && get_socket_error()!=BELLESIP_EWOULDBLOCK){ belle_sip_error("Could not receive UDP packet: %s",belle_sip_get_socket_error_string()); return -errno; } return err; } int udp_channel_connect(belle_sip_channel_t *obj, const struct addrinfo *ai){ struct sockaddr_storage laddr={0}; socklen_t lslen=sizeof(laddr); if (obj->local_ip==NULL){ belle_sip_get_src_addr_for(ai->ai_addr,ai->ai_addrlen,(struct sockaddr*)&laddr,&lslen,obj->local_port); } belle_sip_channel_set_ready(obj,(struct sockaddr*)&laddr,lslen); return 0; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_udp_channel_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_udp_channel_t) { { BELLE_SIP_VPTR_INIT(belle_sip_udp_channel_t,belle_sip_channel_t,FALSE), (belle_sip_object_destroy_t)udp_channel_uninit, NULL, NULL }, "UDP", 0, /*is_reliable*/ udp_channel_connect, udp_channel_send, udp_channel_recv /*no close method*/ } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END belle_sip_channel_t * belle_sip_channel_new_udp(belle_sip_stack_t *stack, int sock, const char *bindip, int localport, const char *dest, int port){ belle_sip_udp_channel_t *obj=belle_sip_object_new(belle_sip_udp_channel_t); belle_sip_channel_init((belle_sip_channel_t*)obj,stack,bindip,localport,NULL,dest,port); belle_sip_channel_set_socket((belle_sip_channel_t*)obj,sock,NULL); return (belle_sip_channel_t*)obj; } belle_sip_channel_t * belle_sip_channel_new_udp_with_addr(belle_sip_stack_t *stack, int sock, const char *bindip, int localport, const struct addrinfo *peer){ belle_sip_udp_channel_t *obj=belle_sip_object_new(belle_sip_udp_channel_t); belle_sip_channel_init_with_addr((belle_sip_channel_t*)obj, stack, bindip, localport, peer->ai_addr, peer->ai_addrlen); obj->base.local_port=localport; belle_sip_channel_set_socket((belle_sip_channel_t*)obj,sock,NULL); /*this lookups the local address*/ udp_channel_connect((belle_sip_channel_t*)obj,peer); return (belle_sip_channel_t*)obj; } belle-sip-1.4.1/src/transports/udp_listeningpoint.c000066400000000000000000000171061252242224000224610ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle_sip_internal.h" struct belle_sip_udp_listening_point{ belle_sip_listening_point_t base; belle_sip_socket_t sock; belle_sip_source_t *source; }; static void belle_sip_udp_listening_point_uninit(belle_sip_udp_listening_point_t *lp){ if (lp->sock!=-1) close_socket(lp->sock); if (lp->source) { belle_sip_main_loop_remove_source(lp->base.stack->ml,lp->source); belle_sip_object_unref(lp->source); } } static belle_sip_channel_t *udp_create_channel(belle_sip_listening_point_t *lp, const belle_sip_hop_t *hop){ belle_sip_channel_t *chan=belle_sip_channel_new_udp(lp->stack ,((belle_sip_udp_listening_point_t*)lp)->sock ,belle_sip_uri_get_host(lp->listening_uri) ,belle_sip_uri_get_port(lp->listening_uri) ,hop->host ,hop->port); return chan; } BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_udp_listening_point_t); BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_BEGIN(belle_sip_udp_listening_point_t) { { BELLE_SIP_VPTR_INIT(belle_sip_udp_listening_point_t, belle_sip_listening_point_t,TRUE), (belle_sip_object_destroy_t)belle_sip_udp_listening_point_uninit, NULL, NULL }, "UDP", udp_create_channel } BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END static belle_sip_socket_t create_udp_socket(const char *addr, int *port, int *family){ struct addrinfo hints={0}; struct addrinfo *res=NULL; int err; belle_sip_socket_t sock; char portnum[10]; int optval=1; if (*port==-1) *port=0; /*random port for bind()*/ snprintf(portnum,sizeof(portnum),"%i",*port); hints.ai_family=AF_UNSPEC; hints.ai_socktype=SOCK_DGRAM; hints.ai_protocol=IPPROTO_UDP; hints.ai_flags=AI_NUMERICSERV; err=getaddrinfo(addr,portnum,&hints,&res); if (err!=0){ belle_sip_error("getaddrinfo() failed for %s port %i: %s",addr,*port,gai_strerror(err)); return -1; } *family=res->ai_family; sock=socket(res->ai_family,res->ai_socktype,res->ai_protocol); if (sock==-1){ belle_sip_error("Cannot create UDP socket: %s",belle_sip_get_socket_error_string()); freeaddrinfo(res); return -1; } err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof (optval)); if (err == -1){ belle_sip_warning ("Fail to set SIP/UDP address reusable: %s.", belle_sip_get_socket_error_string()); } if (res->ai_family==AF_INET6){ belle_sip_socket_enable_dual_stack(sock); } err=bind(sock,res->ai_addr,res->ai_addrlen); if (err==-1){ belle_sip_error("udp bind() failed for %s port %i: %s",addr,*port,belle_sip_get_socket_error_string()); close_socket(sock); freeaddrinfo(res); return -1; } freeaddrinfo(res); if (*port==0){ struct sockaddr_storage saddr; socklen_t saddr_len=sizeof(saddr); err=getsockname(sock,(struct sockaddr*)&saddr,&saddr_len); if (err==0){ err=getnameinfo((struct sockaddr*)&saddr,saddr_len,NULL,0,portnum,sizeof(portnum),NI_NUMERICSERV|NI_NUMERICHOST); if (err==0){ *port=atoi(portnum); belle_sip_message("Random UDP port is %i",*port); }else belle_sip_error("udp bind failed, getnameinfo(): %s",gai_strerror(err)); }else belle_sip_error("udp bind failed, getsockname(): %s",belle_sip_get_socket_error_string()); } return sock; } static int on_udp_data(belle_sip_udp_listening_point_t *lp, unsigned int events); static int belle_sip_udp_listening_point_init_socket(belle_sip_udp_listening_point_t *lp){ int port=belle_sip_uri_get_listening_port(((belle_sip_listening_point_t*)lp)->listening_uri); lp->sock=create_udp_socket(belle_sip_uri_get_host(((belle_sip_listening_point_t*)lp)->listening_uri) ,&port,&lp->base.ai_family); if (lp->sock==(belle_sip_socket_t)-1){ return -1; } belle_sip_uri_set_port(((belle_sip_listening_point_t*)lp)->listening_uri,port); if (lp->base.stack->dscp) belle_sip_socket_set_dscp(lp->sock,lp->base.ai_family,lp->base.stack->dscp); lp->source=belle_sip_socket_source_new((belle_sip_source_func_t)on_udp_data,lp,lp->sock,BELLE_SIP_EVENT_READ,-1); belle_sip_main_loop_add_source(((belle_sip_listening_point_t*)lp)->stack->ml,lp->source); return 0; } static void belle_sip_udp_listening_point_init(belle_sip_udp_listening_point_t *lp, belle_sip_stack_t *s, const char *ipaddress, int port) { belle_sip_listening_point_init((belle_sip_listening_point_t*)lp,s,ipaddress,port); belle_sip_udp_listening_point_init_socket(lp); } /*peek data from the master socket to see where it comes from, and dispatch to matching channel. * If the channel does not exist, create it */ static int on_udp_data(belle_sip_udp_listening_point_t *lp, unsigned int events){ int err; unsigned char buf[4096]; struct sockaddr_storage addr; socklen_t addrlen=sizeof(addr); if (events & BELLE_SIP_EVENT_READ){ belle_sip_debug("udp_listening_point: data to read."); err=recvfrom(lp->sock,(char*)buf,sizeof(buf),MSG_PEEK,(struct sockaddr*)&addr,&addrlen); if (err==-1){ char *tmp=belle_sip_object_to_string((belle_sip_object_t*) ((belle_sip_listening_point_t*)lp)->listening_uri); belle_sip_error("udp_listening_point: recvfrom() failed on [%s], : [%s] reopening server socket" ,tmp ,belle_sip_get_socket_error_string()); belle_sip_free(tmp); belle_sip_udp_listening_point_uninit(lp); /*clean all udp channels that are actually sharing the server socket with the listening points*/ belle_sip_listening_point_clean_channels((belle_sip_listening_point_t*)lp); belle_sip_udp_listening_point_init_socket(lp); }else{ belle_sip_channel_t *chan; struct addrinfo ai={0}; /*preserve the V4 mapping*/ ai.ai_family=addr.ss_family; ai.ai_addr=(struct sockaddr*)&addr; ai.ai_addrlen=addrlen; chan=_belle_sip_listening_point_get_channel((belle_sip_listening_point_t*)lp,NULL,&ai); if (chan==NULL){ /*TODO: should rather create the channel with real local ip and port and not just 0.0.0.0"*/ chan=belle_sip_channel_new_udp_with_addr(lp->base.stack ,lp->sock ,belle_sip_uri_get_host(lp->base.listening_uri) ,belle_sip_uri_get_port(lp->base.listening_uri) ,&ai); if (chan!=NULL){ belle_sip_message("udp_listening_point: new channel created to %s:%i",chan->peer_name,chan->peer_port); belle_sip_listening_point_add_channel((belle_sip_listening_point_t*)lp,chan); } } if (chan){ /*notify the channel*/ belle_sip_debug("Notifying udp channel, local [%s:%i] remote [%s:%i]" ,chan->local_ip ,chan->local_port ,chan->peer_name ,chan->peer_port); belle_sip_channel_process_data(chan,events); } } } return BELLE_SIP_CONTINUE; } belle_sip_listening_point_t * belle_sip_udp_listening_point_new(belle_sip_stack_t *s, const char *ipaddress, int port){ belle_sip_udp_listening_point_t *lp=belle_sip_object_new(belle_sip_udp_listening_point_t); belle_sip_udp_listening_point_init(lp,s,ipaddress, port); if (lp->sock==(belle_sip_socket_t)-1){ belle_sip_object_unref(lp); return NULL; } return (belle_sip_listening_point_t*)lp; } belle-sip-1.4.1/src/wakelock.c000066400000000000000000000105731252242224000161250ustar00rootroot00000000000000#include "wakelock_internal.h" #include "belle-sip/utils.h" #include struct _WakeLock { JavaVM *jvm; jobject powerManager; pthread_key_t jniEnvKey; jint PARTIAL_WAKE_LOCK; jmethodID newWakeLockID; jmethodID acquireID; jmethodID releaseID; }; typedef struct _WakeLock WakeLock; static WakeLock ctx = { .jvm = NULL, .powerManager = NULL }; static JNIEnv *get_jni_env(void); static void jni_key_cleanup(void *data); void bellesip_wake_lock_init(JNIEnv *env, jobject pm) { if(ctx.jvm == NULL) { (*env)->GetJavaVM(env, &ctx.jvm); ctx.powerManager = (*env)->NewGlobalRef(env, pm); pthread_key_create(&ctx.jniEnvKey, jni_key_cleanup); jclass powerManagerClass = (*env)->FindClass(env, "android/os/PowerManager"); jclass wakeLockClass = (*env)->FindClass(env, "android/os/PowerManager$WakeLock"); jfieldID fieldID = (*env)->GetStaticFieldID(env, powerManagerClass, "PARTIAL_WAKE_LOCK", "I"); ctx.PARTIAL_WAKE_LOCK = (*env)->GetStaticIntField(env, powerManagerClass, fieldID); ctx.newWakeLockID = (*env)->GetMethodID(env, powerManagerClass, "newWakeLock", "(ILjava/lang/String;)Landroid/os/PowerManager$WakeLock;"); ctx.acquireID = (*env)->GetMethodID(env, wakeLockClass, "acquire", "()V"); ctx.releaseID = (*env)->GetMethodID(env, wakeLockClass, "release", "()V"); belle_sip_message("bellesip_wake_lock_init(): initialization succeed"); } else { belle_sip_warning("bellesip_wake_lock_init(): the wakelock system has already been initialized"); } } void bellesip_wake_lock_uninit(JNIEnv *env) { ctx.jvm = NULL; if(ctx.powerManager != NULL) { (*env)->DeleteGlobalRef(env, ctx.powerManager); ctx.powerManager = NULL; } } /** * @brief Callback called when a thread terminates it-self. * It detaches the thread from the JVM. * @param data Unused. */ static void jni_key_cleanup(void *data) { belle_sip_message("Thread end. Cleanup wake lock jni environment"); JNIEnv *env = pthread_getspecific(ctx.jniEnvKey); if(env != NULL) { if(ctx.jvm != NULL) { (*ctx.jvm)->DetachCurrentThread(ctx.jvm); pthread_setspecific(ctx.jniEnvKey, NULL); } else { belle_sip_fatal("Wake lock cleanup. No JVM found"); } } } /** * @brief Get a JNI environment. * Get a JNI by attaching the current thread * to the internaly stored JVM. That function can be safely * called several times. * @return JNI environement pointer. NULL if the function fails. */ static JNIEnv *get_jni_env(void) { JNIEnv *jenv = NULL; if(ctx.jvm != NULL) { jenv = pthread_getspecific(ctx.jniEnvKey); if(jenv == NULL) { if((*ctx.jvm)->AttachCurrentThread(ctx.jvm, &jenv, NULL) == JNI_OK) { pthread_setspecific(ctx.jniEnvKey, jenv); belle_sip_message("get_jni_env(): thread successfuly attached"); } else { belle_sip_fatal("get_jni_env(): thread could not be attached to the JVM"); jenv = NULL; } } } else { belle_sip_error("get_jni_env(): no JVM found"); } return jenv; } unsigned long wake_lock_acquire(const char *tag) { if(ctx.jvm != NULL && ctx.powerManager != NULL) { JNIEnv *env; if((env = get_jni_env())) { jstring tagString = (*env)->NewStringUTF(env, tag); jobject lock = (*env)->CallObjectMethod(env, ctx.powerManager, ctx.newWakeLockID, ctx.PARTIAL_WAKE_LOCK, tagString); (*env)->DeleteLocalRef(env, tagString); if(lock != NULL) { (*env)->CallVoidMethod(env, lock, ctx.acquireID); lock = (*env)->NewGlobalRef(env, lock); belle_sip_message("bellesip_wake_lock_acquire(): Android wake lock acquired [ref=%p]", (void *)lock); return (unsigned long)lock; } else { belle_sip_message("wake_lock_acquire(): wake lock creation failed"); } } else { belle_sip_error("bellesip_wake_lock_acquire(): cannot attach current thread to the JVM"); } } else { belle_sip_error("bellesip_wake_lock_acquire(): cannot acquire wake lock. No JVM found"); } return 0; } void wake_lock_release(unsigned long id) { if(ctx.jvm != NULL && ctx.powerManager != NULL) { if(id != 0) { jobject lock = (jobject)id; JNIEnv *env; if((env = get_jni_env())) { (*env)->CallVoidMethod(env, lock, ctx.releaseID); belle_sip_message("wake_lock_release(): Android wake lock released [ref=%p]", (void *)lock); (*env)->DeleteGlobalRef(env, lock); } else { belle_sip_error("bellesip_wake_lock_release(): cannot attach current thread to the JVM"); } } } else { belle_sip_error("wake_lock_release(): cannot release wake lock. No JVM found"); } } belle-sip-1.4.1/src/wakelock_internal.h000066400000000000000000000011701252242224000200170ustar00rootroot00000000000000#include "belle-sip/wakelock.h" /** * @brief Acquire a wake lock. * Ask to Android to prevent the system sleeping. That function * do nothing if the wake lock system has not been initialized * by the function bellesip_wake_lock_init(). * @param tag * @return An ID that anthentificates the taken wake lock. */ extern unsigned long wake_lock_acquire(const char *tag); /** * @brief Release a wake lock. * Ask to Android to release a prevously aquired * wake lock. After calling this function, the system * can sleep again. * @param id ID of the wake lock to release. */ extern void wake_lock_release(unsigned long id); belle-sip-1.4.1/tester/000077500000000000000000000000001252242224000146725ustar00rootroot00000000000000belle-sip-1.4.1/tester/CMakeLists.txt000066400000000000000000000047711252242224000174430ustar00rootroot00000000000000############################################################################ # CMakeLists.txt # Copyright (C) 2014 Belledonne Communications, Grenoble France # ############################################################################ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################ set(TESTER_SOURCES common/bc_tester_utils.c common/bc_tester_utils.h auth_helper_tester.c belle_generic_uri_tester.c belle_http_tester.c belle_sdp_tester.c belle_sip_core_tester.c belle_sip_dialog_tester.c belle_sip_headers_tester.c belle_sip_message_tester.c belle_sip_refresher_tester.c belle_sip_register_tester.c belle_sip_resolver_tester.c belle_sip_tester.c belle_sip_tester.h belle_sip_uri_tester.c cast_test.c register_tester.h ) add_definitions(-DBC_CONFIG_FILE="config.h") string(REPLACE ";" " " LINK_FLAGS_STR "${LINK_FLAGS}") add_executable(belle_sip_tester ${TESTER_SOURCES}) if(NOT "${LINK_FLAGS_STR}" STREQUAL "") set_target_properties(belle_sip_tester PROPERTIES LINK_FLAGS "${LINK_FLAGS_STR}") endif() target_include_directories(belle_sip_tester PUBLIC ${CUNIT_INCLUDE_DIR} PRIVATE common) target_link_libraries(belle_sip_tester ${CUNIT_LIBRARIES} bellesip) add_test(NAME belle_sip_tester COMMAND belle_sip_tester --verbose) set(OBJECT_DESCRIBE_SOURCES describe.c) add_executable(belle_sip_object_describe ${OBJECT_DESCRIBE_SOURCES}) if(NOT "${LINK_FLAGS_STR}" STREQUAL "") set_target_properties(belle_sip_object_describe PROPERTIES LINK_FLAGS "${LINK_FLAGS_STR}") endif() target_link_libraries(belle_sip_object_describe bellesip) set(PARSE_SOURCES parse.c) add_executable(belle_sip_parse ${PARSE_SOURCES}) if(NOT "${LINK_FLAGS_STR}" STREQUAL "") set_target_properties(belle_sip_parse PROPERTIES LINK_FLAGS "${LINK_FLAGS_STR}") endif() target_link_libraries(belle_sip_parse bellesip) belle-sip-1.4.1/tester/Makefile.am000066400000000000000000000025321252242224000167300ustar00rootroot00000000000000 if ENABLE_TESTS noinst_PROGRAMS=belle_sip_tester belle_sip_object_describe belle_sip_parse belle_http_get belle_sip_resolve belle_sip_tester_SOURCES= \ auth_helper_tester.c \ belle_generic_uri_tester.c \ belle_http_tester.c \ belle_sdp_tester.c \ belle_sip_core_tester.c \ belle_sip_dialog_tester.c \ belle_sip_headers_tester.c \ belle_sip_message_tester.c \ belle_sip_refresher_tester.c \ belle_sip_register_tester.c \ belle_sip_resolver_tester.c \ belle_sip_tester.c belle_sip_tester.h\ belle_sip_uri_tester.c \ cast_test.c \ register_tester.h \ common/bc_tester_utils.c common/bc_tester_utils.h belle_sip_tester_CFLAGS=\ -DBC_CONFIG_FILE=\"config.h\" \ $(CUNIT_CFLAGS) \ $(STRICT_OPTIONS) \ $(STRICT_OPTIONS_CC) \ $(TLS_CFLAGS) belle_sip_tester_LDFLAGS=$(CUNIT_LIBS) $(AM_LDFLAGS) belle_sip_object_describe_SOURCES=describe.c belle_sip_parse_SOURCES=parse.c belle_http_get_SOURCES=get.c belle_sip_resolve_SOURCES=resolve.c AM_CPPFLAGS=-I$(top_srcdir)/include -I$(top_srcdir)/src -I$(top_srcdir)/tester/common LDADD=$(top_builddir)/src/libbellesip.la AM_LDFLAGS=-no-undefined -export-dynamic AM_CFLAGS=$(STRICT_OPTIONS) $(STRICT_OPTIONS_CC) test: belle_sip_tester ./belle_sip_tester $(TEST_OPTIONS) else test: @echo "CUnit must be installed to be able to run the tests!" endif belle-sip-1.4.1/tester/auth_helper_tester.c000066400000000000000000000243441252242224000207330ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "belle-sip/auth-helper.h" #include "belle_sip_tester.h" #include #include "CUnit/Basic.h" #ifdef HAVE_POLARSSL #include #endif static void test_authentication(void) { const char* l_raw_header = "WWW-Authenticate: Digest " "algorithm=MD5, realm=\"sip.linphone.org\", opaque=\"1bc7f9097684320\"," " nonce=\"cz3h0gAAAAC06TKKAABmTz1V9OcAAAAA\""; char ha1[33]; belle_sip_header_www_authenticate_t* www_authenticate=belle_sip_header_www_authenticate_parse(l_raw_header); belle_sip_header_authorization_t* authorization = belle_sip_auth_helper_create_authorization(www_authenticate); belle_sip_header_authorization_set_uri(authorization,belle_sip_uri_parse("sip:sip.linphone.org")); CU_ASSERT_EQUAL_FATAL(0,belle_sip_auth_helper_compute_ha1("jehan-mac","sip.linphone.org","toto",ha1)); CU_ASSERT_EQUAL_FATAL(0,belle_sip_auth_helper_fill_authorization(authorization,"REGISTER",ha1)); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_response(authorization),"77ebf3de72e41934d806175586086508"); belle_sip_object_unref(www_authenticate); belle_sip_object_unref(authorization); } static void test_authentication_qop_auth(void) { const char* l_raw_header = "WWW-Authenticate: Digest " "algorithm=MD5, realm=\"sip.linphone.org\", opaque=\"1bc7f9097684320\"," " qop=\"auth,auth-int\", nonce=\"cz3h0gAAAAC06TKKAABmTz1V9OcAAAAA\""; char ha1[33]; belle_sip_header_www_authenticate_t* www_authenticate=belle_sip_header_www_authenticate_parse(l_raw_header); belle_sip_header_authorization_t* authorization = belle_sip_auth_helper_create_authorization(www_authenticate); belle_sip_header_authorization_set_uri(authorization,belle_sip_uri_parse("sip:sip.linphone.org")); belle_sip_header_authorization_set_nonce_count(authorization,1); belle_sip_header_authorization_set_qop(authorization,"auth"); belle_sip_header_authorization_set_cnonce(authorization,"8302210f"); /*for testing purpose*/ CU_ASSERT_EQUAL_FATAL(0,belle_sip_auth_helper_compute_ha1("jehan-mac","sip.linphone.org","toto",ha1)); CU_ASSERT_EQUAL_FATAL(0,belle_sip_auth_helper_fill_authorization(authorization,"REGISTER",ha1)); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_qop(authorization),"auth"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_response(authorization),"694dab8dfe7d50d28ba61e8c43e30666"); CU_ASSERT_EQUAL(belle_sip_header_authorization_get_nonce_count(authorization),1); belle_sip_object_unref(www_authenticate); belle_sip_object_unref(authorization); } static void test_proxy_authentication(void) { const char* l_raw_header = "Proxy-Authenticate: Digest " "algorithm=MD5, realm=\"sip.linphone.org\", opaque=\"1bc7f9097684320\"," " qop=\"auth,auth-int\", nonce=\"cz3h0gAAAAC06TKKAABmTz1V9OcAAAAA\""; char ha1[33]; belle_sip_header_proxy_authenticate_t* proxy_authenticate=belle_sip_header_proxy_authenticate_parse(l_raw_header); belle_sip_header_proxy_authorization_t* proxy_authorization = belle_sip_auth_helper_create_proxy_authorization(proxy_authenticate); belle_sip_header_authorization_set_uri(BELLE_SIP_HEADER_AUTHORIZATION(proxy_authorization),belle_sip_uri_parse("sip:sip.linphone.org")); CU_ASSERT_EQUAL_FATAL(0,belle_sip_auth_helper_compute_ha1("jehan-mac","sip.linphone.org","toto",ha1)); CU_ASSERT_EQUAL_FATAL(0,belle_sip_auth_helper_fill_proxy_authorization(proxy_authorization,"REGISTER",ha1)); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_response(BELLE_SIP_HEADER_AUTHORIZATION(proxy_authorization)) ,"77ebf3de72e41934d806175586086508"); belle_sip_object_unref(proxy_authenticate); belle_sip_object_unref(proxy_authorization); } #define TEMPORARY_CERTIFICATE_DIR "/belle_sip_tester_crt" static void test_generate_and_parse_certificates(void) { #ifdef HAVE_POLARSSL #if POLARSSL_VERSION_NUMBER >= 0x01030000 belle_sip_certificates_chain_t *certificate, *parsed_certificate; belle_sip_signing_key_t *key, *parsed_key; char *pem_certificate, *pem_parsed_certificate, *pem_key, *pem_parsed_key; int ret = 0; char *belle_sip_certificate_temporary_dir = belle_sip_strdup_printf("%s%s", bc_tester_writable_dir_prefix, TEMPORARY_CERTIFICATE_DIR); /* create 2 certificates in the temporary certificate directory (TODO : set the directory in a absolute path?? where?)*/ ret = belle_sip_generate_self_signed_certificate(belle_sip_certificate_temporary_dir, "test_certificate1", &certificate, &key); CU_ASSERT_EQUAL_FATAL(0, ret); ret = belle_sip_generate_self_signed_certificate(belle_sip_certificate_temporary_dir, "test_certificate2", &certificate, &key); CU_ASSERT_EQUAL_FATAL(0, ret); /* parse directory to get the certificate2 */ ret = belle_sip_get_certificate_and_pkey_in_dir(belle_sip_certificate_temporary_dir, "test_certificate2", &parsed_certificate, &parsed_key, BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM); belle_sip_free(belle_sip_certificate_temporary_dir); CU_ASSERT_EQUAL_FATAL(0, ret); /* get pem version of generated and parsed certificate and compare them */ pem_certificate = belle_sip_certificates_chain_get_pem(certificate); CU_ASSERT_TRUE_FATAL(pem_certificate!=NULL); pem_parsed_certificate = belle_sip_certificates_chain_get_pem(parsed_certificate); CU_ASSERT_TRUE_FATAL(pem_parsed_certificate!=NULL); CU_ASSERT_STRING_EQUAL(pem_certificate, pem_parsed_certificate); /* get pem version of generated and parsed key and compare them */ pem_key = belle_sip_signing_key_get_pem(key); CU_ASSERT_TRUE_FATAL(pem_key!=NULL); pem_parsed_key = belle_sip_signing_key_get_pem(parsed_key); CU_ASSERT_TRUE_FATAL(pem_parsed_key!=NULL); CU_ASSERT_STRING_EQUAL(pem_key, pem_parsed_key); belle_sip_free(pem_certificate); belle_sip_free(pem_parsed_certificate); belle_sip_free(pem_key); belle_sip_free(pem_parsed_key); belle_sip_object_unref(certificate); belle_sip_object_unref(parsed_certificate); belle_sip_object_unref(key); belle_sip_object_unref(parsed_key); #endif /* POLARSSL_VERSION_NUMBER >= 0x01030000 */ #endif /* HAVE_POLARSSL */ } const char* belle_sip_tester_fingerprint256_cert = /*for URI:sip:tester@client.example.org*/ "-----BEGIN CERTIFICATE-----\n" "MIIDtTCCAh2gAwIBAgIBATANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDExF0ZXN0\n" "X2NlcnRpZmljYXRlMTAeFw0wMTAxMDEwMDAwMDBaFw0zMDAxMDEwMDAwMDBaMBwx\n" "GjAYBgNVBAMTEXRlc3RfY2VydGlmaWNhdGUxMIIBojANBgkqhkiG9w0BAQEFAAOC\n" "AY8AMIIBigKCAYEAoI6Dpdyc8ARM9KTIkuagImUgpybuWrKayPfrAeUE/gnyd8bO\n" "Bf7CkGdpHv82c1BdUxE5Z1j19TMR0MHCtFD5z0PWtW3erWQqUdxdFYIUknIi5ObU\n" "AlXgqAIYLCSMaGWzmavdsC95HfHiuPC+YTLwr1vhNC6IWCSKt9N7xek/InY73cBh\n" "pNw/kJOB/AzB9r40uxcye6+6Hp3dAd2YOGOiuKlAFBlAeq/T70VKBvdw/D8QFi5Z\n" "BJ2+xX9jQBshzHi9JdMS6ZhLdtjBHwi37k1l1KyRh+qVTbze5pN7YCRmj8Q4dS0S\n" "3ozV27AXM60kXbX4+PWQG9nuL/PO2NxTx0olIaTkzjM+roxWE6srhAEQ+aXn3tCq\n" "bHND6AN2Yjm/mzQI2ig143gHraLRaHx+uTtRonMeWMvTeUlX/BwUoffjppmWqICd\n" "OiBFNXOpp3hlzZDdoEhwKgIVMu3WbEsOTG7uphkUGZo/VaTVW0zvYAS2JXC/0s/S\n" "85dB5M3Y9l/8v0T7AgMBAAGjAjAAMA0GCSqGSIb3DQEBCwUAA4IBgQBm5N00W7+G\n" "ygF6OUM3143N5B/41vTk5FDZ/iU/UJaPSLBM/aZhA2FjoTswjpFfY8V6IkALrtUH\n" "20FVip3lguMc7md9L9qMRVYj/2H94A2Bg/zx+PlhJNI0bshITzS6pHgM2qKk+KRB\n" "yZaHQTa8DjRCYuAp1roh4NKNDa16WdY4Dk5ncRORqzcxczBJ2LSbq4b78pdEl/iL\n" "nHOoFOSmiQQ2ui7H89bSUxRmVJFiNfPlTeYUKjc753LJCuri30rQVnHE+HMBmE5y\n" "sM6FiGawJxUKAcS0zuKeroHNXLzL0qIGgeLkoPb267se0tCAcJZImiqyK0y1cuHw\n" "o9BZ5t/I6UvTJLE9+p+wG7nR8TdszaZ+bLzSdHWDRPS2Ux4J+Ux3dnIAH/ZcD5CD\n" "/mj4F12yW0ZNukFVkptneS6ab1lQb3PT7tzkuzKud00QNHswZLbORQrXnvuk5LrR\n" "V7PbeVUz1FxaOjFwHXkkvFqrbwRdBc7GVqQZDVV40WVvciGGcBhemqc=\n" "-----END CERTIFICATE-----"; /* fingerprint of certificate generated using openssl x509 -fingerprint -sha256 */ const char* belle_sip_tester_fingerprint256_cert_fingerprint = "SHA-256 A0:98:2D:3E:68:F3:14:8D:ED:50:40:DB:ED:A4:28:BC:1E:1A:6A:05:59:9E:69:3F:02:E2:F8:22:BF:4C:92:14"; static void test_certificate_fingerprint(void) { #ifdef HAVE_POLARSSL #if POLARSSL_VERSION_NUMBER >= 0x01030000 char *fingerprint; /* parse certificate defined in belle_sip_register_tester.c */ belle_sip_certificates_chain_t* cert = belle_sip_certificates_chain_parse(belle_sip_tester_client_cert,strlen(belle_sip_tester_client_cert),BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM); /* generate fingerprint */ fingerprint = belle_sip_certificates_chain_get_fingerprint(cert); CU_ASSERT_TRUE_FATAL(fingerprint!=NULL); CU_ASSERT_STRING_EQUAL(fingerprint, belle_sip_tester_client_cert_fingerprint); belle_sip_free(fingerprint); belle_sip_object_unref(cert); /* parse certificate defined above, signing algo is sha256 */ cert = belle_sip_certificates_chain_parse(belle_sip_tester_fingerprint256_cert,strlen(belle_sip_tester_fingerprint256_cert),BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM); /* generate fingerprint */ fingerprint = belle_sip_certificates_chain_get_fingerprint(cert); CU_ASSERT_TRUE_FATAL(fingerprint!=NULL); CU_ASSERT_STRING_EQUAL(fingerprint, belle_sip_tester_fingerprint256_cert_fingerprint); belle_sip_free(fingerprint); belle_sip_object_unref(cert); #endif /* POLARSSL_VERSION_NUMBER >= 0x01030000 */ #endif /* HAVE_POLARSSL */ } test_t authentication_helper_tests[] = { { "Proxy-Authenticate", test_proxy_authentication }, { "WWW-Authenticate", test_authentication }, { "WWW-Authenticate (with qop)", test_authentication_qop_auth }, { "generate and parse self signed certificates", test_generate_and_parse_certificates}, { "generate certificate fingerprint", test_certificate_fingerprint} }; test_suite_t authentication_helper_test_suite = { "Authentication helper", NULL, NULL, sizeof(authentication_helper_tests) / sizeof(authentication_helper_tests[0]), authentication_helper_tests }; belle-sip-1.4.1/tester/belle_generic_uri_tester.c000066400000000000000000000137731252242224000220750ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL, Grenoble, France This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/belle-sip.h" #include "belle_sip_tester.h" #include #include "CUnit/Basic.h" static void test_basic_uri() { belle_generic_uri_t* source_uri = belle_generic_uri_parse("http://www.linphone.org/index.html"); char* source_uri_raw = belle_sip_object_to_string(source_uri); belle_generic_uri_t* first_uri = belle_generic_uri_parse(source_uri_raw); belle_generic_uri_t* uri=BELLE_GENERIC_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(first_uri))); belle_sip_free(source_uri_raw); belle_sip_object_unref(source_uri); belle_sip_object_unref(first_uri); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(uri),"http"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_host(uri),"www.linphone.org"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_path(uri),"/index.html"); belle_sip_object_unref(uri); source_uri = belle_generic_uri_parse("http://www.linphone.org/"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_path(source_uri),"/"); belle_sip_object_unref(source_uri); source_uri = belle_generic_uri_parse("http://www.linphone.org/a/b/c"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_path(source_uri),"/a/b/c"); CU_ASSERT_STRING_EQUAL("http://www.linphone.org/a/b/c",source_uri_raw = belle_sip_object_to_string(source_uri)); belle_sip_free(source_uri_raw); belle_sip_object_unref(source_uri); } static void test_complex_uri() { belle_generic_uri_t* source_uri = belle_generic_uri_parse("ftp://toto:secret@ftp.linphone.fr:1234/url?sa=t&rct=j&url=http%3A%2F%2Ftranslate.google.fr"); char* source_uri_raw = belle_generic_uri_to_string(source_uri); belle_generic_uri_t* first_uri = belle_generic_uri_parse(source_uri_raw); belle_generic_uri_t* uri=BELLE_GENERIC_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(first_uri))); belle_sip_free(source_uri_raw); belle_sip_object_unref(source_uri); belle_sip_object_unref(first_uri); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(uri),"ftp"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_host(uri),"ftp.linphone.fr"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_user(uri),"toto"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_user_password(uri),"secret"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_host(uri),"ftp.linphone.fr"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_path(uri),"/url"); CU_ASSERT_EQUAL(belle_generic_uri_get_port(uri),1234); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_query(uri),"sa=t&rct=j&url=http://translate.google.fr"); belle_sip_object_unref(uri); } static void test_file_path() { belle_generic_uri_t* source_uri = belle_generic_uri_parse("/index.html"); char* source_uri_raw = belle_sip_object_to_string(source_uri); belle_generic_uri_t* first_uri = belle_generic_uri_parse(source_uri_raw); belle_generic_uri_t* uri=BELLE_GENERIC_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(first_uri))); belle_sip_free(source_uri_raw); belle_sip_object_unref(source_uri); belle_sip_object_unref(first_uri); CU_ASSERT_PTR_NULL(belle_generic_uri_get_scheme(uri)); CU_ASSERT_PTR_NULL(belle_generic_uri_get_host(uri)); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_path(uri),"/index.html"); belle_sip_object_unref(uri); source_uri = belle_generic_uri_parse("file:///tmp/absolute-file"); CU_ASSERT_PTR_NOT_NULL(source_uri); if (source_uri!=NULL){ CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(source_uri),"file"); CU_ASSERT_PTR_NULL(belle_generic_uri_get_host(source_uri)); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_path(source_uri),"/tmp/absolute-file"); belle_sip_object_unref(source_uri); } /*this is INVALID*/ source_uri = belle_generic_uri_parse("file://./relative-file"); CU_ASSERT_PTR_NOT_NULL(source_uri); /* PATH segment always start by / */ source_uri = belle_generic_uri_parse("./relative-file"); CU_ASSERT_PTR_NULL(source_uri); if (source_uri!=NULL){ belle_sip_object_unref(source_uri); } } static void test_absolute_uri() { belle_generic_uri_t* source_uri = belle_generic_uri_parse("tel:+33123457"); char* source_uri_raw = belle_generic_uri_to_string(source_uri); belle_generic_uri_t* first_uri = belle_generic_uri_parse(source_uri_raw); belle_generic_uri_t* uri=BELLE_GENERIC_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(first_uri))); belle_sip_free(source_uri_raw); belle_sip_object_unref(source_uri); belle_sip_object_unref(first_uri); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(uri),"tel"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_opaque_part(uri),"+33123457"); belle_sip_object_unref(uri); source_uri = belle_generic_uri_parse("tel:11234567888;phone-context=vzims.com"); source_uri_raw = belle_generic_uri_to_string(source_uri); first_uri = belle_generic_uri_parse(source_uri_raw); uri=BELLE_GENERIC_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(first_uri))); belle_sip_free(source_uri_raw); belle_sip_object_unref(source_uri); belle_sip_object_unref(first_uri); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(uri),"tel"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_opaque_part(uri),"11234567888;phone-context=vzims.com"); belle_sip_object_unref(uri); } static test_t tests[] = { { "Simple uri", test_basic_uri }, { "Complex uri", test_complex_uri }, { "File path", test_file_path }, { "Absolute uri", test_absolute_uri } }; test_suite_t generic_uri_test_suite = { "Generic uri", NULL, NULL, sizeof(tests) / sizeof(tests[0]), tests }; belle-sip-1.4.1/tester/belle_http_tester.c000066400000000000000000000273771252242224000205660ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "CUnit/Basic.h" #include "belle-sip/belle-sip.h" #include "belle_sip_tester.h" #include typedef struct http_counters{ int response_headers_count; int response_count; int io_error_count; int two_hundred; int three_hundred; int four_hundred; }http_counters_t; static int wait_for(belle_sip_stack_t*s1,int* counter,int value,int timeout) { int retry=0; #define SLEEP_TIME 100 while (*counter!=value && retry++ <(timeout/SLEEP_TIME)) { if (s1) belle_sip_stack_sleep(s1,SLEEP_TIME); } if (*counter!=value) return FALSE; else return TRUE; } static void process_response(void *data, const belle_http_response_event_t *event){ http_counters_t *counters=(http_counters_t*)data; counters->response_count++; CU_ASSERT_PTR_NOT_NULL(event->response); if (event->response){ int code=belle_http_response_get_status_code(event->response); belle_sip_body_handler_t *body=belle_sip_message_get_body_handler(BELLE_SIP_MESSAGE(event->response)); if (code>=200 && code <300) counters->two_hundred++; else if (code>=300 && code <400) counters->three_hundred++; else if (code>=300 && code <400) counters->four_hundred++; CU_ASSERT_PTR_NOT_NULL(body); } } static void process_io_error(void *data, const belle_sip_io_error_event_t *event){ http_counters_t *counters=(http_counters_t*)data; counters->io_error_count++; } static void process_auth_requested(void *data, belle_sip_auth_event_t *event){ if (belle_sip_auth_event_get_mode(event)==BELLE_SIP_AUTH_MODE_TLS){ belle_sip_certificates_chain_t* cert = belle_sip_certificates_chain_parse(belle_sip_tester_client_cert,strlen(belle_sip_tester_client_cert),BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM); belle_sip_signing_key_t* key = belle_sip_signing_key_parse(belle_sip_tester_private_key,strlen(belle_sip_tester_private_key),belle_sip_tester_private_key_passwd); belle_sip_auth_event_set_client_certificates_chain(event,cert); belle_sip_auth_event_set_signing_key(event,key); belle_sip_message("process_auth_requested requested for DN [%s]" ,belle_sip_auth_event_get_distinguished_name(event)); } } static belle_sip_stack_t *stack=NULL; static belle_http_provider_t *prov=NULL; static int http_init(void){ stack=belle_sip_stack_new(NULL); prov=belle_sip_stack_create_http_provider(stack,"0.0.0.0"); if (belle_sip_tester_get_root_ca_path() != NULL) { belle_tls_verify_policy_t *policy=belle_tls_verify_policy_new(); belle_tls_verify_policy_set_root_ca(policy,belle_sip_tester_get_root_ca_path()); belle_http_provider_set_tls_verify_policy(prov,policy); } return 0; } static int http_cleanup(void){ belle_sip_object_unref(prov); belle_sip_object_unref(stack); return 0; } static void one_get(const char *url,http_counters_t* counters, int *counter){ belle_http_request_listener_callbacks_t cbs={0}; belle_http_request_listener_t *l; belle_generic_uri_t *uri; belle_http_request_t *req; uri=belle_generic_uri_parse(url); req=belle_http_request_create("GET", uri, belle_sip_header_create("User-Agent","belle-sip/"PACKAGE_VERSION), NULL); cbs.process_response=process_response; cbs.process_io_error=process_io_error; cbs.process_auth_requested=process_auth_requested; l=belle_http_request_listener_create_from_callbacks(&cbs,counters); belle_http_provider_send_request(prov,req,l); wait_for(stack,counter,1,10000); belle_sip_object_unref(l); } static void one_http_get(void){ http_counters_t counters={0}; one_get("http://smtp.linphone.org",&counters,&counters.response_count); CU_ASSERT_TRUE(counters.response_count==1); CU_ASSERT_TRUE(counters.io_error_count==0); CU_ASSERT_EQUAL(counters.two_hundred,1); } static void http_get_empty_body(void){ http_counters_t counters={0}; one_get("http://smtp.linphone.org/marie_invalid",&counters,&counters.response_count); CU_ASSERT_TRUE(counters.response_count==1); CU_ASSERT_TRUE(counters.io_error_count==0); CU_ASSERT_EQUAL(counters.two_hundred,1); } static void http_get_io_error(void){ http_counters_t counters={0}; one_get("http://blablabla.cul",&counters,&counters.io_error_count); CU_ASSERT_TRUE(counters.response_count==0); CU_ASSERT_EQUAL(counters.io_error_count,1); } static void one_https_get(void){ http_counters_t counters={0}; one_get("https://smtp.linphone.org",&counters,&counters.response_count); CU_ASSERT_TRUE(counters.response_count==1); CU_ASSERT_TRUE(counters.io_error_count==0); CU_ASSERT_EQUAL(counters.two_hundred,1); } static void https_get_long_body(void){ http_counters_t counters={0}; one_get("https://smtp.linphone.org/linphone.html",&counters, &counters.response_count); CU_ASSERT_TRUE(counters.response_count==1); CU_ASSERT_TRUE(counters.io_error_count==0); CU_ASSERT_EQUAL(counters.two_hundred,1); } static void https_digest_get(void){ http_counters_t counters={0}; one_get("https://pauline:pouet@smtp.linphone.org/restricted",&counters,&counters.response_count); CU_ASSERT_TRUE(counters.response_count==1); CU_ASSERT_TRUE(counters.io_error_count==0); CU_ASSERT_EQUAL(counters.three_hundred,1); } #if 0 static void https_client_cert_connection(void){ belle_tls_verify_policy_t *policy=belle_tls_verify_policy_new(); http_counters_t counters={0}; belle_tls_verify_policy_set_exceptions(policy,BELLE_TLS_VERIFY_ANY_REASON);/*ignore the server verification because we don't have a true certificate*/ belle_http_provider_set_tls_verify_policy(prov,policy); one_get("https://sip2.linphone.org:5063",&counters); CU_ASSERT_EQUAL(counters.two_hundred,1); belle_tls_verify_policy_set_exceptions(policy,0); belle_sip_object_unref(policy); } #endif static void on_progress(belle_sip_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, size_t total){ if (total!=0){ double frac=100.0*(double)offset/(double)total; belle_sip_message("transfer %g %% done",frac); }else belle_sip_message("%i bytes transfered",(int)offset); } #define MULTIPART_BOUNDARY "---------------------------14737809831466499882746641449" #define MULTIPART_BEGIN "somehash.jpg\r\n" \ "--" MULTIPART_BOUNDARY "\r\n" \ "Content-Disposition: form-data; name=\"userfile\"; filename=\"belle_http_sip_tester.jpg\"\r\n" \ "Content-Type: application/octet-stream\r\n\r\n" #define MULTIPART_END "\r\n--" MULTIPART_BOUNDARY "--\r\n" const char *multipart_boudary=MULTIPART_BOUNDARY; const int image_size=250000; static int on_send_body(belle_sip_user_body_handler_t *bh, belle_sip_message_t *msg, void *data, size_t offset, uint8_t *buffer, size_t *size){ size_t end_of_img=sizeof(MULTIPART_BEGIN)+image_size; if (offset==0){ int partlen=sizeof(MULTIPART_BEGIN); CU_ASSERT_TRUE_FATAL(partlen<*size); memcpy(buffer,MULTIPART_BEGIN,partlen); *size=partlen; }else if (offsetresponse_headers_count++; CU_ASSERT_PTR_NOT_NULL(event->response); if (event->response){ /*we are receiving a response, set a specific body handler to acquire the response. * if not done, belle-sip will create a memory body handler, the default*/ FILE *file=belle_sip_object_data_get(BELLE_SIP_OBJECT(event->request),"file"); belle_sip_message_set_body_handler( (belle_sip_message_t*)event->response, (belle_sip_body_handler_t*)belle_sip_user_body_handler_new(0,on_progress,on_recv_body,NULL,file) ); } } static void http_get_long_user_body(void){ belle_http_request_listener_callbacks_t cbs={0}; belle_http_request_listener_t *l; belle_generic_uri_t *uri; belle_http_request_t *req; http_counters_t counters={0}; const char *url="http://download-mirror.savannah.gnu.org/releases/linphone/belle-sip/belle-sip-1.3.0.tar.gz"; belle_sip_body_handler_t *bh; belle_http_response_t *resp; FILE *outfile=fopen("download.tar.gz","w"); uri=belle_generic_uri_parse(url); req=belle_http_request_create("GET", uri, belle_sip_header_create("User-Agent","belle-sip/" PACKAGE_VERSION), NULL); cbs.process_response_headers=process_response_headers; cbs.process_response=process_response; cbs.process_io_error=process_io_error; cbs.process_auth_requested=process_auth_requested; l=belle_http_request_listener_create_from_callbacks(&cbs,&counters); belle_sip_object_ref(req); belle_sip_object_data_set(BELLE_SIP_OBJECT(req),"file",outfile,NULL); belle_http_provider_send_request(prov,req,l); CU_ASSERT_TRUE(wait_for(stack,&counters.two_hundred,1,20000)); CU_ASSERT_TRUE(counters.response_headers_count==1); resp=belle_http_request_get_response(req); CU_ASSERT_PTR_NOT_NULL(resp); if (resp){ bh=belle_sip_message_get_body_handler((belle_sip_message_t*)resp); CU_ASSERT_TRUE(belle_sip_body_handler_get_size(bh)>0); } belle_sip_object_unref(req); belle_sip_object_unref(l); if (outfile) fclose(outfile); } test_t http_tests[] = { { "One http GET", one_http_get }, { "http GET of empty body", http_get_empty_body }, { "One https GET", one_https_get }, { "http request with io error", http_get_io_error }, { "https GET with long body", https_get_long_body }, { "https digest GET", https_digest_get },/*, FIXME, need a server for testing { "https with client certificate", https_client_cert_connection }*/ { "https POST with long body", https_post_long_body }, { "http GET with long user body", http_get_long_user_body} }; test_suite_t http_test_suite = { "http", http_init, http_cleanup, sizeof(http_tests) / sizeof(http_tests[0]), http_tests }; belle-sip-1.4.1/tester/belle_sdp_tester.c000066400000000000000000001047621252242224000203670ustar00rootroot00000000000000/* belle-sdp - SDP (RFC) library. Copyright (C) 2011 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/belle-sip.h" #include "belle_sip_tester.h" #include "port.h" #include #include "CUnit/Basic.h" //v=0 //o=jehan-mac 1239 1239 IN IP4 192.168.0.18 //s=Talk //c=IN IP4 192.168.0.18 //t=0 0 //m=audio 7078 RTP/AVP 111 110 3 0 8 101 //a=rtpmap:111 speex/16000 //a=fmtp:111 vbr=on //a=rtpmap:110 speex/8000 //a=fmtp:110 vbr=on //a=rtpmap:101 telephone-event/8000 //a=fmtp:101 0-11 //m=video 8078 RTP/AVP 99 97 98 //a=rtpmap:99 MP4V-ES/90000 //a=fmtp:99 profile-level-id=3 //a=rtpmap:97 theora/90000 //a=rtpmap:98 H263-1998/90000 //a=fmtp:98 CIF=1;QCIF=1 static belle_sdp_attribute_t* attribute_parse_marshall_parse_clone(const char* raw_attribute) { belle_sdp_attribute_t* lTmp; belle_sdp_attribute_t* lAttribute = belle_sdp_attribute_parse(raw_attribute); char* l_raw_attribute = belle_sip_object_to_string(BELLE_SIP_OBJECT(lAttribute)); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lTmp = belle_sdp_attribute_parse(l_raw_attribute); belle_sip_free(l_raw_attribute); lAttribute = BELLE_SDP_ATTRIBUTE(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); return lAttribute; } static void test_attribute(void) { belle_sdp_attribute_t* lAttribute = attribute_parse_marshall_parse_clone("a=rtpmap:101 telephone-event/8000"); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(lAttribute), "rtpmap"); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_value(lAttribute), "101 telephone-event/8000"); CU_ASSERT_TRUE(belle_sdp_attribute_has_value(lAttribute)); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); } static void test_attribute_2(void) { belle_sdp_attribute_t* lAttribute = attribute_parse_marshall_parse_clone("a=ice-pwd:31ec21eb38b2ec6d36e8dc7b"); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(lAttribute), "ice-pwd"); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_value(lAttribute), "31ec21eb38b2ec6d36e8dc7b"); CU_ASSERT_TRUE(belle_sdp_attribute_has_value(lAttribute)); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); } static void test_rtcp_fb_attribute(void) { belle_sdp_rtcp_fb_attribute_t* lAttribute; lAttribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-fb:* ack")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-fb"); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_id(lAttribute), -1); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_type(lAttribute), BELLE_SDP_RTCP_FB_ACK); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_param(lAttribute), BELLE_SDP_RTCP_FB_NONE); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lAttribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-fb:98 nack rpsi")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-fb"); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_id(lAttribute), 98); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_type(lAttribute), BELLE_SDP_RTCP_FB_NACK); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_param(lAttribute), BELLE_SDP_RTCP_FB_RPSI); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lAttribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-fb:* trr-int 3")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-fb"); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_id(lAttribute), -1); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_type(lAttribute), BELLE_SDP_RTCP_FB_TRR_INT); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_trr_int(lAttribute), 3); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lAttribute = BELLE_SDP_RTCP_FB_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-fb:103 ccm fir")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-fb"); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_id(lAttribute), 103); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_type(lAttribute), BELLE_SDP_RTCP_FB_CCM); CU_ASSERT_EQUAL(belle_sdp_rtcp_fb_attribute_get_param(lAttribute), BELLE_SDP_RTCP_FB_FIR); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); } static void test_rtcp_xr_attribute(void) { belle_sdp_rtcp_xr_attribute_t* lAttribute; lAttribute = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-xr")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-xr"); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_stat_summary(lAttribute) == FALSE); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_voip_metrics(lAttribute) == FALSE); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lAttribute = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-xr:rcvr-rtt=all:10")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-xr"); CU_ASSERT_STRING_EQUAL(belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(lAttribute), "all"); CU_ASSERT_EQUAL(belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(lAttribute), 10); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lAttribute = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-xr:stat-summary")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-xr"); CU_ASSERT_PTR_NULL(belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(lAttribute)); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_stat_summary(lAttribute) == TRUE); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_voip_metrics(lAttribute) == FALSE); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lAttribute = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-xr:stat-summary=loss,jitt")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-xr"); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_stat_summary(lAttribute) == TRUE); CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(lAttribute), (belle_sip_compare_func)strcasecmp, "loss")); CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(lAttribute), (belle_sip_compare_func)strcasecmp, "jitt")); CU_ASSERT_PTR_NULL(belle_sip_list_find_custom(belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(lAttribute), (belle_sip_compare_func)strcasecmp, "HL")); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lAttribute = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-xr:voip-metrics")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-xr"); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_stat_summary(lAttribute) == FALSE); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_voip_metrics(lAttribute) == TRUE); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); lAttribute = BELLE_SDP_RTCP_XR_ATTRIBUTE(attribute_parse_marshall_parse_clone("a=rtcp-xr:rcvr-rtt=sender stat-summary=loss,dup,jitt,TTL voip-metrics")); CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_name(BELLE_SDP_ATTRIBUTE(lAttribute)), "rtcp-xr"); CU_ASSERT_STRING_EQUAL(belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(lAttribute), "sender"); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_stat_summary(lAttribute) == TRUE); CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(lAttribute), (belle_sip_compare_func)strcasecmp, "loss")); CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(lAttribute), (belle_sip_compare_func)strcasecmp, "dup")); CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(lAttribute), (belle_sip_compare_func)strcasecmp, "jitt")); CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(lAttribute), (belle_sip_compare_func)strcasecmp, "TTL")); CU_ASSERT_TRUE(belle_sdp_rtcp_xr_attribute_has_voip_metrics(lAttribute) == TRUE); belle_sip_object_unref(BELLE_SIP_OBJECT(lAttribute)); } static void test_bandwidth(void) { belle_sdp_bandwidth_t* lTmp; belle_sdp_bandwidth_t* l_bandwidth = belle_sdp_bandwidth_parse("b=AS:380"); char* l_raw_bandwidth = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_bandwidth)); belle_sip_object_unref(BELLE_SIP_OBJECT(l_bandwidth)); lTmp = belle_sdp_bandwidth_parse(l_raw_bandwidth); l_bandwidth = BELLE_SDP_BANDWIDTH(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_bandwidth_get_type(l_bandwidth), "AS"); CU_ASSERT_EQUAL(belle_sdp_bandwidth_get_value(l_bandwidth),380); belle_sip_object_unref(BELLE_SIP_OBJECT(l_bandwidth)); belle_sip_free(l_raw_bandwidth); } static void test_origin(void) { belle_sdp_origin_t* lTmp; belle_sdp_origin_t* lOrigin = belle_sdp_origin_parse("o=jehan-mac 3800 2558 IN IP4 192.168.0.165"); char* l_raw_origin = belle_sip_object_to_string(BELLE_SIP_OBJECT(lOrigin)); belle_sip_object_unref(BELLE_SIP_OBJECT(lOrigin)); lTmp = belle_sdp_origin_parse(l_raw_origin); lOrigin = BELLE_SDP_ORIGIN(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_address(lOrigin), "192.168.0.165"); CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_address_type(lOrigin), "IP4"); CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_network_type(lOrigin), "IN"); belle_sip_object_unref(BELLE_SIP_OBJECT(lOrigin)); belle_sip_free(l_raw_origin); } static void test_malformed_origin(void) { belle_sdp_origin_t* lOrigin = belle_sdp_origin_parse("o=Jehan Monnier 3800 2558 IN IP4 192.168.0.165"); CU_ASSERT_PTR_NULL(lOrigin); } static void test_connection(void) { belle_sdp_connection_t* lTmp; belle_sdp_connection_t* lConnection = belle_sdp_connection_parse("c=IN IP4 192.168.0.18"); char* l_raw_connection = belle_sip_object_to_string(BELLE_SIP_OBJECT(lConnection)); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); lTmp = belle_sdp_connection_parse(l_raw_connection); lConnection = BELLE_SDP_CONNECTION(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address(lConnection), "192.168.0.18"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address_type(lConnection), "IP4"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_network_type(lConnection), "IN"); CU_ASSERT_EQUAL(belle_sdp_connection_get_ttl(lConnection), 0); CU_ASSERT_EQUAL(belle_sdp_connection_get_ttl(lConnection), 0); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); belle_sip_free(l_raw_connection); } static void test_connection_6(void) { belle_sdp_connection_t* lTmp; belle_sdp_connection_t* lConnection = belle_sdp_connection_parse("c=IN IP6 2a01:e35:1387:1020:6233:4bff:fe0b:5663"); char* l_raw_connection = belle_sip_object_to_string(BELLE_SIP_OBJECT(lConnection)); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); lTmp = belle_sdp_connection_parse(l_raw_connection); lConnection = BELLE_SDP_CONNECTION(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address(lConnection), "2a01:e35:1387:1020:6233:4bff:fe0b:5663"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address_type(lConnection), "IP6"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_network_type(lConnection), "IN"); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); belle_sip_free(l_raw_connection); } static void test_connection_multicast(void) { belle_sdp_connection_t* lTmp; belle_sdp_connection_t* lConnection = belle_sdp_connection_parse("c=IN IP4 224.2.1.1/127/3"); char* l_raw_connection = belle_sip_object_to_string(BELLE_SIP_OBJECT(lConnection)); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); lTmp = belle_sdp_connection_parse(l_raw_connection); lConnection = BELLE_SDP_CONNECTION(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address(lConnection), "224.2.1.1"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address_type(lConnection), "IP4"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_network_type(lConnection), "IN"); CU_ASSERT_EQUAL(belle_sdp_connection_get_ttl(lConnection), 127); CU_ASSERT_EQUAL(belle_sdp_connection_get_range(lConnection), 3); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); belle_sip_free(l_raw_connection); lConnection = belle_sdp_connection_parse("c=IN IP4 224.2.1.1/127"); l_raw_connection = belle_sip_object_to_string(BELLE_SIP_OBJECT(lConnection)); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); lTmp = belle_sdp_connection_parse(l_raw_connection); lConnection = BELLE_SDP_CONNECTION(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address(lConnection), "224.2.1.1"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address_type(lConnection), "IP4"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_network_type(lConnection), "IN"); CU_ASSERT_EQUAL(belle_sdp_connection_get_ttl(lConnection), 127); CU_ASSERT_EQUAL(belle_sdp_connection_get_range(lConnection), 0); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); belle_sip_free(l_raw_connection); lConnection = belle_sdp_connection_parse("c=IN IP6 ::1/3"); l_raw_connection = belle_sip_object_to_string(BELLE_SIP_OBJECT(lConnection)); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); lTmp = belle_sdp_connection_parse(l_raw_connection); lConnection = BELLE_SDP_CONNECTION(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address(lConnection), "::1"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address_type(lConnection), "IP6"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_network_type(lConnection), "IN"); CU_ASSERT_EQUAL(belle_sdp_connection_get_ttl(lConnection), 0); CU_ASSERT_EQUAL(belle_sdp_connection_get_range(lConnection), 3); belle_sip_object_unref(BELLE_SIP_OBJECT(lConnection)); belle_sip_free(l_raw_connection); } static void test_email(void) { belle_sdp_email_t* lTmp; belle_sdp_email_t* l_email = belle_sdp_email_parse("e= jehan "); char* l_raw_email = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_email)); belle_sip_object_unref(BELLE_SIP_OBJECT(l_email)); lTmp = belle_sdp_email_parse(l_raw_email); l_email = BELLE_SDP_EMAIL(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_email_get_value(l_email), " jehan "); belle_sip_object_unref(BELLE_SIP_OBJECT(l_email)); belle_sip_free(l_raw_email); } static void test_info(void) { belle_sdp_info_t* lTmp; belle_sdp_info_t* l_info = belle_sdp_info_parse("i=A Seminar on the session description protocol"); char* l_raw_info = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_info)); belle_sip_object_unref(BELLE_SIP_OBJECT(l_info)); lTmp = belle_sdp_info_parse(l_raw_info); l_info = BELLE_SDP_INFO(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_info_get_value(l_info), "A Seminar on the session description protocol"); belle_sip_object_unref(BELLE_SIP_OBJECT(l_info)); belle_sip_free(l_raw_info); } static void test_media(void) { belle_sdp_media_t* lTmp; belle_sip_list_t* list; belle_sdp_media_t* l_media = belle_sdp_media_parse("m=audio 7078 RTP/AVP 111 110 3 0 8 101"); char* l_raw_media = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_media)); int fmt[] ={111,110,3,0,8,101}; int i=0; belle_sip_object_unref(BELLE_SIP_OBJECT(l_media)); lTmp = belle_sdp_media_parse(l_raw_media); l_media = BELLE_SDP_MEDIA(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_STRING_EQUAL(belle_sdp_media_get_media_type(l_media), "audio"); CU_ASSERT_EQUAL(belle_sdp_media_get_media_port(l_media), 7078); CU_ASSERT_STRING_EQUAL(belle_sdp_media_get_protocol(l_media), "RTP/AVP"); list = belle_sdp_media_get_media_formats(l_media); CU_ASSERT_PTR_NOT_NULL(list); for(;list!=NULL;list=list->next){ CU_ASSERT_EQUAL(BELLE_SIP_POINTER_TO_INT(list->data),fmt[i++]); } belle_sip_object_unref(BELLE_SIP_OBJECT(l_media)); belle_sip_free(l_raw_media); } static void test_media_description_base(belle_sdp_media_description_t* media_description) { const char* attr[] ={"99 MP4V-ES/90000" ,"99 profile-level-id=3" ,"97 theora/90000" ,"98 H263-1998/90000" ,"98 CIF=1;QCIF=1"}; belle_sdp_connection_t* lConnection; belle_sdp_media_description_t* l_media_description=media_description; belle_sdp_media_t* l_media = belle_sdp_media_description_get_media(l_media_description); belle_sip_list_t* list; int fmt[] ={99,97,98}; int i=0; CU_ASSERT_PTR_NOT_NULL(l_media); CU_ASSERT_STRING_EQUAL(belle_sdp_media_get_media_type(l_media), "video"); CU_ASSERT_EQUAL(belle_sdp_media_get_media_port(l_media), 8078); CU_ASSERT_STRING_EQUAL(belle_sdp_media_get_protocol(l_media), "RTP/AVP"); list = belle_sdp_media_get_media_formats(l_media); CU_ASSERT_PTR_NOT_NULL(list); for(;list!=NULL;list=list->next){ CU_ASSERT_EQUAL(BELLE_SIP_POINTER_TO_INT(list->data),fmt[i++]); } /*connection*/ lConnection = belle_sdp_media_description_get_connection(l_media_description); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address(lConnection), "192.168.0.18"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_address_type(lConnection), "IP4"); CU_ASSERT_STRING_EQUAL(belle_sdp_connection_get_network_type(lConnection), "IN"); /*bandwidth*/ CU_ASSERT_EQUAL(belle_sdp_media_description_get_bandwidth(l_media_description,"AS"),380); /*attributes*/ list = belle_sdp_media_description_get_attributes(l_media_description); CU_ASSERT_PTR_NOT_NULL(list); i=0; for(;list!=NULL;list=list->next){ CU_ASSERT_STRING_EQUAL(belle_sdp_attribute_get_value((belle_sdp_attribute_t*)(list->data)),attr[i++]); } } static void test_media_description(void) { const char* l_src = "m=video 8078 RTP/AVP 99 97 98\r\n"\ "c=IN IP4 192.168.0.18\r\n"\ "b=AS:380\r\n"\ "a=rtpmap:99 MP4V-ES/90000\r\n"\ "a=fmtp:99 profile-level-id=3\r\n"\ "a=rtpmap:97 theora/90000\r\n"\ "a=rtpmap:98 H263-1998/90000\r\n"\ "a=fmtp:98 CIF=1;QCIF=1\r\n"; belle_sdp_media_description_t* lTmp; belle_sdp_media_description_t* l_media_description = belle_sdp_media_description_parse(l_src); char* l_raw_media_description = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_media_description)); belle_sip_object_unref(BELLE_SIP_OBJECT(l_media_description)); lTmp = belle_sdp_media_description_parse(l_raw_media_description); l_media_description = BELLE_SDP_MEDIA_DESCRIPTION(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); test_media_description_base(l_media_description); belle_sip_object_unref(BELLE_SIP_OBJECT(l_media_description)); belle_sip_free(l_raw_media_description); return; } static void test_simple_session_description(void) { const char* l_src = "v=0\r\n"\ "o=jehan-mac 1239 1239 IN IP4 192.168.0.18\r\n"\ "s=Talk\r\n"\ "c=IN IP4 192.168.0.18\r\n"\ "t=0 0\r\n"\ "m=audio 7078 RTP/AVP 111 110 3 0 8 101\r\n"\ "a=rtpmap:111 speex/16000\r\n"\ "a=fmtp:111 vbr=on\r\n"\ "a=rtpmap:110 speex/8000\r\n"\ "a=fmtp:110 vbr=on\r\n"\ "a=rtpmap:101 telephone-event/8000\r\n"\ "a=fmtp:101 0-11\r\n"\ "m=video 8078 RTP/AVP 99 97 98\r\n"\ "c=IN IP4 192.168.0.18\r\n"\ "b=AS:380\r\n"\ "a=rtpmap:99 MP4V-ES/90000\r\n"\ "a=fmtp:99 profile-level-id=3\r\n"\ "a=rtpmap:97 theora/90000\r\n"\ "a=rtpmap:98 H263-1998/90000\r\n"\ "a=fmtp:98 CIF=1;QCIF=1\r\n"; belle_sdp_origin_t* l_origin; belle_sip_list_t* media_descriptions; belle_sdp_session_description_t* lTmp; belle_sdp_session_description_t* l_session_description = belle_sdp_session_description_parse(l_src); char* l_raw_session_description = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_session_description)); belle_sip_object_unref(BELLE_SIP_OBJECT(l_session_description)); lTmp = belle_sdp_session_description_parse(l_raw_session_description); belle_sip_free(l_raw_session_description); l_session_description = BELLE_SDP_SESSION_DESCRIPTION(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_PTR_NOT_NULL(belle_sdp_session_description_get_version(l_session_description)); CU_ASSERT_EQUAL(belle_sdp_version_get_version(belle_sdp_session_description_get_version(l_session_description)),0); l_origin = belle_sdp_session_description_get_origin(l_session_description); CU_ASSERT_PTR_NOT_NULL(l_origin); CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_address(l_origin),"192.168.0.18") CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_address_type(l_origin),"IP4") CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_network_type(l_origin),"IN") CU_ASSERT_EQUAL(belle_sdp_origin_get_session_id(l_origin),1239) CU_ASSERT_EQUAL(belle_sdp_origin_get_session_version(l_origin),1239) CU_ASSERT_PTR_NOT_NULL(belle_sdp_session_description_get_session_name(l_session_description)); CU_ASSERT_STRING_EQUAL(belle_sdp_session_name_get_value(belle_sdp_session_description_get_session_name(l_session_description)),"Talk"); CU_ASSERT_PTR_NOT_NULL(belle_sdp_session_description_get_connection(l_session_description)); CU_ASSERT_PTR_NOT_NULL(belle_sdp_session_description_get_time_descriptions(l_session_description)); CU_ASSERT_EQUAL(belle_sdp_time_get_start(belle_sdp_time_description_get_time((belle_sdp_time_description_t*)(belle_sdp_session_description_get_time_descriptions(l_session_description)->data))),0); CU_ASSERT_EQUAL(belle_sdp_time_get_stop(belle_sdp_time_description_get_time((belle_sdp_time_description_t*)(belle_sdp_session_description_get_time_descriptions(l_session_description)->data))),0); media_descriptions = belle_sdp_session_description_get_media_descriptions(l_session_description); CU_ASSERT_PTR_NOT_NULL(media_descriptions); CU_ASSERT_STRING_EQUAL (belle_sdp_media_get_media_type(belle_sdp_media_description_get_media((belle_sdp_media_description_t*)(media_descriptions->data))),"audio"); media_descriptions=media_descriptions->next; CU_ASSERT_PTR_NOT_NULL(media_descriptions); test_media_description_base((belle_sdp_media_description_t*)(media_descriptions->data)); belle_sip_object_unref(l_session_description); return; } static void test_image_mline() { const char * sdp = "v=0\r\n" "o=cp10 138884701697 138884701699 IN IP4 10.7.1.133\r\n" "s=SIP Call\r\n" "c=IN IP4 91.121.128.144\r\n" "t=0 0\r\n" "m=image 33802 udptl t38\r\n" "a=sendrecv\r\n" "a=T38FaxVersion:0\r\n" "a=T38MaxBitRate:9600\r\n" "a=T38FaxRateManagement:transferredTCF\r\n" "a=T38FaxMaxBuffer:1000\r\n" "a=T38FaxMaxDatagram:200\r\n" "a=T38FaxUdpEC:t38UDPRedundancy\r\n"; belle_sdp_session_description_t* l_session_description = belle_sdp_session_description_parse(sdp); belle_sip_object_unref(l_session_description); } static const char* big_sdp = "v=0\r\n"\ "o=jehan-mac 1239 1239 IN IP6 2a01:e35:1387:1020:6233:4bff:fe0b:5663\r\n"\ "s=SIP Talk\r\n"\ "c=IN IP4 192.168.0.18\r\n"\ "b=AS:380\r\n"\ "t=0 0\r\n"\ "a=ice-pwd:31ec21eb38b2ec6d36e8dc7b\r\n"\ "m=audio 7078 RTP/AVP 111 110 3 0 8 101\r\n"\ "a=rtpmap:111 speex/16000\r\n"\ "a=fmtp:111 vbr=on\r\n"\ "a=rtpmap:110 speex/8000\r\n"\ "a=fmtp:110 vbr=on\r\n"\ "a=rtpmap:101 telephone-event/8000\r\n"\ "a=fmtp:101 0-11\r\n"\ "m=video 8078 RTP/AVP 99 97 98\r\n"\ "c=IN IP4 192.168.0.18\r\n"\ "b=AS:380\r\n"\ "a=rtpmap:99 MP4V-ES/90000\r\n"\ "a=fmtp:99 profile-level-id=3\r\n"\ "a=rtpmap:97 theora/90000\r\n"\ "a=rtpmap:98 H263-1998/90000\r\n"\ "a=fmtp:98 CIF=1;QCIF=1\r\n"; static void test_session_description(void) { const char* l_src = big_sdp; belle_sdp_origin_t* l_origin; belle_sdp_session_description_t* lTmp; belle_sip_list_t* media_descriptions; belle_sdp_session_description_t* l_session_description = belle_sdp_session_description_parse(l_src); char* l_raw_session_description = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_session_description)); belle_sip_object_unref(BELLE_SIP_OBJECT(l_session_description)); lTmp = belle_sdp_session_description_parse(l_raw_session_description); belle_sip_free(l_raw_session_description); l_session_description = BELLE_SDP_SESSION_DESCRIPTION(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(lTmp)); CU_ASSERT_PTR_NOT_NULL(belle_sdp_session_description_get_version(l_session_description)); CU_ASSERT_EQUAL(belle_sdp_version_get_version(belle_sdp_session_description_get_version(l_session_description)),0); l_origin = belle_sdp_session_description_get_origin(l_session_description); CU_ASSERT_PTR_NOT_NULL(l_origin); CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_address(l_origin),"2a01:e35:1387:1020:6233:4bff:fe0b:5663") CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_address_type(l_origin),"IP6") CU_ASSERT_STRING_EQUAL(belle_sdp_origin_get_network_type(l_origin),"IN") CU_ASSERT_EQUAL(belle_sdp_origin_get_session_id(l_origin),1239) CU_ASSERT_EQUAL(belle_sdp_origin_get_session_version(l_origin),1239) CU_ASSERT_PTR_NOT_NULL(belle_sdp_session_description_get_session_name(l_session_description)); CU_ASSERT_STRING_EQUAL(belle_sdp_session_name_get_value(belle_sdp_session_description_get_session_name(l_session_description)),"SIP Talk"); CU_ASSERT_PTR_NOT_NULL(belle_sdp_session_description_get_connection(l_session_description)); CU_ASSERT_PTR_NOT_NULL(belle_sdp_session_description_get_time_descriptions(l_session_description)); CU_ASSERT_EQUAL(belle_sdp_time_get_start(belle_sdp_time_description_get_time((belle_sdp_time_description_t*)(belle_sdp_session_description_get_time_descriptions(l_session_description)->data))),0); CU_ASSERT_EQUAL(belle_sdp_time_get_stop(belle_sdp_time_description_get_time((belle_sdp_time_description_t*)(belle_sdp_session_description_get_time_descriptions(l_session_description)->data))),0); media_descriptions = belle_sdp_session_description_get_media_descriptions(l_session_description); CU_ASSERT_PTR_NOT_NULL(media_descriptions); CU_ASSERT_STRING_EQUAL (belle_sdp_media_get_media_type(belle_sdp_media_description_get_media((belle_sdp_media_description_t*)(media_descriptions->data))),"audio"); media_descriptions=media_descriptions->next; CU_ASSERT_PTR_NOT_NULL(media_descriptions); test_media_description_base((belle_sdp_media_description_t*)(media_descriptions->data)); belle_sip_object_unref(l_session_description); return; } static void test_overflow(void){ belle_sdp_session_description_t* sdp; belle_sip_list_t *mds; belle_sdp_media_description_t *vmd; int i; const size_t orig_buffsize=1024; size_t buffsize=orig_buffsize; char *buffer=belle_sip_malloc0(buffsize); size_t offset=0; sdp=belle_sdp_session_description_parse(big_sdp); CU_ASSERT_PTR_NOT_NULL(sdp); mds=belle_sdp_session_description_get_media_descriptions(sdp); CU_ASSERT_PTR_NOT_NULL(mds); CU_ASSERT_PTR_NOT_NULL(mds->next); vmd=(belle_sdp_media_description_t*)mds->next->data; for(i=0;i<16;i++){ belle_sdp_media_description_add_attribute(vmd,belle_sdp_attribute_create("candidate","2 1 UDP 1694498815 82.65.223.97 9078 typ srflx raddr 192.168.0.2 rport 9078")); } CU_ASSERT_EQUAL(belle_sip_object_marshal(BELLE_SIP_OBJECT(sdp),buffer,buffsize,&offset),BELLE_SIP_BUFFER_OVERFLOW); belle_sip_message("marshal size is %i",(int)offset); CU_ASSERT_TRUE(offset==buffsize); belle_sip_object_unref(sdp); belle_sip_free(buffer); } static belle_sdp_mime_parameter_t* find_mime_parameter(belle_sip_list_t* list,const int format) { for(;list!=NULL;list=list->next){ if (belle_sdp_mime_parameter_get_media_format((belle_sdp_mime_parameter_t*)list->data) == format) { return (belle_sdp_mime_parameter_t*)list->data; } } return NULL; } static void check_mime_param (belle_sdp_mime_parameter_t* mime_param ,int rate ,int channel_count ,int ptime ,int max_ptime ,int media_format ,const char* type ,const char* parameters) { CU_ASSERT_PTR_NOT_NULL(mime_param); CU_ASSERT_EQUAL(belle_sdp_mime_parameter_get_rate(mime_param),rate); CU_ASSERT_EQUAL(belle_sdp_mime_parameter_get_channel_count(mime_param),channel_count); CU_ASSERT_EQUAL(belle_sdp_mime_parameter_get_ptime(mime_param),ptime); CU_ASSERT_EQUAL(belle_sdp_mime_parameter_get_max_ptime(mime_param),max_ptime); CU_ASSERT_EQUAL(belle_sdp_mime_parameter_get_media_format(mime_param),media_format); if (type) CU_ASSERT_STRING_EQUAL(belle_sdp_mime_parameter_get_type(mime_param),type); if (parameters) CU_ASSERT_STRING_EQUAL(belle_sdp_mime_parameter_get_parameters(mime_param),parameters); } int static compare_attribute(belle_sdp_attribute_t* attr, const char* value) { return strcasecmp(belle_sdp_attribute_get_name(attr),"rtpmap")==0 || strcasecmp(belle_sdp_attribute_get_value(attr),value)==0; } static void test_mime_parameter(void) { const char* l_src = "m=audio 7078 RTP/AVP 111 110 0 8 9 3 18 101\r\n"\ "a=rtpmap:111 speex/16000\r\n"\ "a=fmtp:111 vbr=on\r\n"\ "a=rtpmap:110 speex/8000\r\n"\ "a=fmtp:110 vbr=on\r\n"\ "a=rtpmap:8 PCMA/8000\r\n"\ "a=rtpmap:101 telephone-event/8000\r\n"\ "a=fmtp:101 0-11\r\n"\ "a=ptime:40\r\n"; belle_sdp_mime_parameter_t* l_param; belle_sdp_mime_parameter_t* lTmp; belle_sdp_media_t* l_media; belle_sip_list_t* mime_parameter_list; belle_sip_list_t* mime_parameter_list_iterator; belle_sdp_media_description_t* l_media_description_tmp = belle_sdp_media_description_parse(l_src); belle_sdp_media_description_t* l_media_description = belle_sdp_media_description_parse(belle_sip_object_to_string(l_media_description_tmp)); belle_sip_object_unref(l_media_description_tmp); mime_parameter_list = belle_sdp_media_description_build_mime_parameters(l_media_description); mime_parameter_list_iterator = mime_parameter_list; CU_ASSERT_PTR_NOT_NULL(mime_parameter_list); belle_sip_object_unref(BELLE_SIP_OBJECT(l_media_description)); l_media_description = belle_sdp_media_description_new(); belle_sdp_media_description_set_media(l_media_description,l_media=belle_sdp_media_parse("m=audio 7078 RTP/AVP 0")); belle_sdp_media_set_media_formats(l_media,belle_sip_list_free(belle_sdp_media_get_media_formats(l_media))); /*to remove 0*/ for (;mime_parameter_list_iterator!=NULL;mime_parameter_list_iterator=mime_parameter_list_iterator->next) { belle_sdp_media_description_append_values_from_mime_parameter(l_media_description,(belle_sdp_mime_parameter_t*)mime_parameter_list_iterator->data); } belle_sip_list_free_with_data(mime_parameter_list, (void (*)(void*))belle_sip_object_unref); /*marshal/unmarshal again*/ l_media_description_tmp = l_media_description; l_media_description= belle_sdp_media_description_parse(belle_sip_object_to_string(l_media_description)); belle_sip_object_unref(l_media_description_tmp); /*belle_sip_message("%s",belle_sip_object_to_string(l_media_description));*/ { belle_sip_list_t* attributes=belle_sdp_media_description_get_attributes(l_media_description); #ifdef BELLE_SDP_FORCE_RTP_MAP CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(attributes,(belle_sip_compare_func)compare_attribute,"8 PCMA/8000")); CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(attributes,(belle_sip_compare_func)compare_attribute,"18 G729/8000")); #else CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(attributes,(belle_sip_compare_func)compare_attribute,"8 PCMA/8000")); CU_ASSERT_PTR_NOT_NULL(belle_sip_list_find_custom(attributes,(belle_sip_compare_func)compare_attribute,"18 G729/8000")); #endif } mime_parameter_list = belle_sdp_media_description_build_mime_parameters(l_media_description); belle_sip_object_unref(l_media_description); lTmp = find_mime_parameter(mime_parameter_list,111); l_param = BELLE_SDP_MIME_PARAMETER(belle_sip_object_clone(BELLE_SIP_OBJECT(lTmp))); CU_ASSERT_PTR_NOT_NULL(l_param); check_mime_param(l_param,16000,1,40,-1,111,"speex","vbr=on"); belle_sip_object_unref(l_param); l_param = find_mime_parameter(mime_parameter_list,110); CU_ASSERT_PTR_NOT_NULL(l_param); check_mime_param(l_param,8000,1,40,-1,110,"speex","vbr=on"); l_param = find_mime_parameter(mime_parameter_list,3); CU_ASSERT_PTR_NOT_NULL(l_param); check_mime_param(l_param,8000,1,40,-1,3,"GSM",NULL); l_param = find_mime_parameter(mime_parameter_list,0); CU_ASSERT_PTR_NOT_NULL(l_param); check_mime_param(l_param,8000,1,40,-1,0,"PCMU",NULL); l_param = find_mime_parameter(mime_parameter_list,8); CU_ASSERT_PTR_NOT_NULL(l_param); check_mime_param(l_param,8000,1,40,-1,8,"PCMA",NULL); l_param = find_mime_parameter(mime_parameter_list,9); CU_ASSERT_PTR_NOT_NULL(l_param); check_mime_param(l_param,8000,1,40,-1,9,"G722",NULL); l_param = find_mime_parameter(mime_parameter_list,101); CU_ASSERT_PTR_NOT_NULL(l_param); check_mime_param(l_param,8000,1,40,-1,101,"telephone-event","0-11"); belle_sip_list_free_with_data(mime_parameter_list, (void (*)(void*))belle_sip_object_unref); } test_t sdp_tests[] = { { "a= (attribute)", test_attribute }, { "a= (attribute) 2", test_attribute_2 }, { "a=rtcp-fb", test_rtcp_fb_attribute }, { "a=rtcp-xr", test_rtcp_xr_attribute }, { "b= (bandwidth)", test_bandwidth }, { "o= (IPv4 origin)", test_origin }, { "o= (malformed origin)", test_malformed_origin }, { "c= (IPv4 connection)", test_connection }, { "c= (IPv6 connection)", test_connection_6 }, { "c= (multicast)", test_connection_multicast}, { "e= (email)", test_email }, { "i= (info)", test_info }, { "m= (media)", test_media }, { "mime parameter", test_mime_parameter }, { "Media description", test_media_description }, { "Simple session description", test_simple_session_description }, { "Session description", test_session_description }, { "Session description for fax", test_image_mline }, { "Marshal buffer overflow", test_overflow } }; test_suite_t sdp_test_suite = { "SDP", NULL, NULL, sizeof(sdp_tests) / sizeof(sdp_tests[0]), sdp_tests }; belle-sip-1.4.1/tester/belle_sip_core_tester.c000066400000000000000000000134571252242224000214040ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "CUnit/Basic.h" #include "belle-sip/belle-sip.h" #include "belle-sip/object.h" #include "belle-sip/dict.h" #include "belle_sip_tester.h" #include "belle_sip_internal.h" #include "register_tester.h" #ifndef WIN32 #include #include #endif #define INT_TO_VOIDPTR(i) ((void*)(intptr_t)(i)) #define VOIDPTR_TO_INT(p) ((int)(intptr_t)(p)) static int foreach_called = 0; static int destroy_called = 0; static int clone_called = 0; static void test_object_data_string_destroy(void* data){ belle_sip_free(data); destroy_called++; } static void* test_object_data_string_clone(const char*name, void* data){ clone_called++; if( strcmp(name, "test_str") == 0) return belle_sip_strdup(data); else return data; } static void test_object_data_foreach_cb(const char*name, void*data, void*udata) { (void)name; (void)data; (void)udata; foreach_called++; } static void test_object_data(void) { belle_sip_object_t* obj = belle_sip_object_new(belle_sip_object_t); belle_sip_object_t* cloned = belle_sip_object_new(belle_sip_object_t); int i = 123; const char* str = "toto", *str2 = "titi"; /* normal insertion with no destroy callback */ // should return 0 CU_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_i", INT_TO_VOIDPTR(i), NULL), 0); // should return the value we put in it CU_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")), i); /* * Overwriting insertion */ // overwrite data: should return 1 when set() i = 124; CU_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_i", INT_TO_VOIDPTR(i), NULL), 1 ); // should return the new value we put in it CU_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")), i); /* * normal insertion with destroy callback */ CU_ASSERT_EQUAL(belle_sip_object_data_set(obj, "test_str", (void*)belle_sip_strdup(str), test_object_data_string_destroy), 0); // we should get back the same string CU_ASSERT_STRING_EQUAL( (const char*)belle_sip_object_data_get(obj, "test_str"), str ); CU_ASSERT_EQUAL(belle_sip_object_data_remove(obj, "test_str"),0); // we expect the destroy() function to be called on removal CU_ASSERT_EQUAL(destroy_called, 1); destroy_called = 0; /* * string insertion and replace */ belle_sip_object_data_set(obj, "test_str", (void*)belle_sip_strdup(str), test_object_data_string_destroy); belle_sip_object_data_set(obj, "test_str", (void*)belle_sip_strdup(str2), test_object_data_string_destroy); CU_ASSERT_EQUAL(destroy_called, 1); // we expect the dtor to have been called to free the first string /* * Get non-existent key */ CU_ASSERT_EQUAL(belle_sip_object_data_get(obj, "non-exist"),NULL); /* * test cloning the dictionary */ belle_sip_object_data_clone(obj, cloned, test_object_data_string_clone); CU_ASSERT_EQUAL(clone_called,2); // we expect the clone function to be called for "test_i" and "test_str" // the values should be equal CU_ASSERT_EQUAL( VOIDPTR_TO_INT(belle_sip_object_data_get(obj, "test_i")), VOIDPTR_TO_INT(belle_sip_object_data_get(cloned, "test_i")) ); CU_ASSERT_STRING_EQUAL( (const char*)belle_sip_object_data_get(obj, "test_str"), (const char*)belle_sip_object_data_get(cloned, "test_str")); // but the pointers should be different CU_ASSERT_NOT_EQUAL( (const char*)belle_sip_object_data_get(obj, "test_str"), (const char*)belle_sip_object_data_get(cloned, "test_str")); /* * Foreach test */ belle_sip_object_data_foreach(obj, test_object_data_foreach_cb, NULL); CU_ASSERT_EQUAL( foreach_called, 2 ); belle_sip_object_unref(obj); belle_sip_object_unref(cloned); } static void test_dictionary(void) { belle_sip_dict_t* obj = belle_sip_object_new(belle_sip_dict_t); const char* str = ""; int i = 5; int64_t i64 = 0xF2345678 << 1; // gcc doesn't like 0x1234567890 as a 64 bit literal.. belle_sip_dict_set_int(obj, "test_i", i); CU_ASSERT_EQUAL(belle_sip_dict_get_int(obj,"test_i",-1),i); // return default int value CU_ASSERT_EQUAL(belle_sip_dict_get_int(obj,"unexistent",-1),-1); // remove existing entry CU_ASSERT_EQUAL(belle_sip_dict_remove(obj, "test_i"),0); // test_i should't be present anymore CU_ASSERT_EQUAL(belle_sip_dict_get_int(obj,"test_i",-1),-1); // remove unknown entry CU_ASSERT_NOT_EQUAL(belle_sip_dict_remove(obj, "unexistent"),0); belle_sip_dict_set_string(obj, "test_str", str); CU_ASSERT_STRING_EQUAL( (const char*)belle_sip_dict_get_string(obj, "test_str", ""),str); // unknown string value CU_ASSERT_STRING_EQUAL( (const char*)belle_sip_dict_get_string(obj, "unexistent", "toto"),"toto"); belle_sip_dict_set_int64(obj, "test_i64", i64); CU_ASSERT_EQUAL(belle_sip_dict_get_int64(obj,"test_i64",-1),i64); belle_sip_dict_clear(obj); // test_str shouldn't exist anymore CU_ASSERT_STRING_EQUAL(belle_sip_dict_get_string(obj,"test_str","toto"),"toto"); belle_sip_object_unref(obj); } test_t core_tests[] = { { "Object Data", test_object_data }, { "Dictionary", test_dictionary } }; test_suite_t core_test_suite = { "Core", NULL, NULL, sizeof(core_tests) / sizeof(core_tests[0]), core_tests }; belle-sip-1.4.1/tester/belle_sip_dialog_tester.c000066400000000000000000000431211252242224000217020ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "CUnit/Basic.h" #include "belle-sip/belle-sip.h" #include "belle_sip_tester.h" #include "register_tester.h" static const char* sdp = "v=0\r\n"\ "o=jehan-mac 1239 1239 IN IP4 192.168.0.18\r\n"\ "s=Talk\r\n"\ "c=IN IP4 192.168.0.18\r\n"\ "t=0 0\r\n"\ "m=audio 7078 RTP/AVP 111 110 3 0 8 101\r\n"\ "a=rtpmap:111 speex/16000\r\n"\ "a=fmtp:111 vbr=on\r\n"\ "a=rtpmap:110 speex/8000\r\n"\ "a=fmtp:110 vbr=on\r\n"\ "a=rtpmap:101 telephone-event/8000\r\n"\ "a=fmtp:101 0-11\r\n"\ "m=video 8078 RTP/AVP 99 97 98\r\n"\ "c=IN IP4 192.168.0.18\r\n"\ "b=AS:380\r\n"\ "a=rtpmap:99 MP4V-ES/90000\r\n"\ "a=fmtp:99 profile-level-id=3\r\n"\ "a=rtpmap:97 theora/90000\r\n"\ "a=rtpmap:98 H263-1998/90000\r\n"\ "a=fmtp:98 CIF=1;QCIF=1\r\n"; static belle_sip_dialog_t* caller_dialog; static belle_sip_dialog_t* callee_dialog; static belle_sip_response_t* ok_response; static belle_sip_server_transaction_t* inserv_transaction; belle_sip_request_t* build_request(belle_sip_stack_t * stack , belle_sip_provider_t *prov ,belle_sip_header_address_t* from ,belle_sip_header_address_t* to ,belle_sip_header_address_t* route ,const char* method) { belle_sip_header_from_t* from_header; belle_sip_header_to_t* to_header; belle_sip_request_t *req; belle_sip_uri_t* req_uri; belle_sip_header_contact_t* contact_header; BELLESIP_UNUSED(stack); from_header = belle_sip_header_from_create(from,BELLE_SIP_RANDOM_TAG); to_header = belle_sip_header_to_create(to,NULL); req_uri = (belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_header_address_get_uri((belle_sip_header_address_t*)to_header)); contact_header= belle_sip_header_contact_new(); belle_sip_header_address_set_uri((belle_sip_header_address_t*)contact_header,belle_sip_uri_new()); belle_sip_uri_set_user(belle_sip_header_address_get_uri((belle_sip_header_address_t*)contact_header),belle_sip_uri_get_user(req_uri)); req=belle_sip_request_create( req_uri, method, belle_sip_provider_create_call_id(prov), belle_sip_header_cseq_create(20,method), from_header, to_header, belle_sip_header_via_new(), 70); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact_header)); if (route) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_route_create(route))); } return req; } static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_terminated_event_t *event){ BELLESIP_UNUSED(user_ctx); BELLESIP_UNUSED(event); belle_sip_message("process_dialog_terminated not implemented yet"); } static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ BELLESIP_UNUSED(user_ctx); BELLESIP_UNUSED(event); belle_sip_message("process_io_error not implemented yet"); } static void caller_process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { belle_sip_server_transaction_t* server_transaction; belle_sip_response_t* resp; belle_sip_dialog_t* dialog; belle_sip_header_to_t* to=belle_sip_message_get_header_by_type(belle_sip_request_event_get_request(event),belle_sip_header_to_t); if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to)))) { belle_sip_message("Message [%p] not for caller, skipping",belle_sip_request_event_get_request(event)); return; /*not for the caller*/ } belle_sip_message("caller_process_request_event received [%s] message",belle_sip_request_get_method(belle_sip_request_event_get_request(event))); server_transaction=belle_sip_provider_create_server_transaction(prov,belle_sip_request_event_get_request(event)); CU_ASSERT_STRING_EQUAL_FATAL("BYE",belle_sip_request_get_method(belle_sip_request_event_get_request(event))); dialog = belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(server_transaction)); CU_ASSERT_PTR_NOT_NULL_FATAL(dialog); CU_ASSERT_EQUAL(belle_sip_dialog_get_state(dialog) , BELLE_SIP_DIALOG_CONFIRMED); resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),200); belle_sip_server_transaction_send_response(server_transaction,resp); } static void callee_process_request_event(void *user_ctx, const belle_sip_request_event_t *event) { belle_sip_dialog_t* dialog; belle_sip_response_t* ringing_response; belle_sip_header_content_type_t* content_type ; belle_sip_header_content_length_t* content_length; belle_sip_server_transaction_t* server_transaction = belle_sip_request_event_get_server_transaction(event); belle_sip_header_to_t* to=belle_sip_message_get_header_by_type(belle_sip_request_event_get_request(event),belle_sip_header_to_t); const char* method; if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(to)))) { belle_sip_message("Message [%p] not for callee, skipping",belle_sip_request_event_get_request(event)); return; /*not for the callee*/ } method = belle_sip_request_get_method(belle_sip_request_event_get_request(event)); if (!server_transaction && strcmp(method,"ACK")!=0) { server_transaction= belle_sip_provider_create_server_transaction(prov,belle_sip_request_event_get_request(event)); } belle_sip_message("callee_process_request_event received [%s] message",method); dialog = belle_sip_request_event_get_dialog(event); if (!dialog ) { CU_ASSERT_STRING_EQUAL_FATAL("INVITE",method); dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(server_transaction)); callee_dialog=dialog; inserv_transaction=server_transaction; } if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_NULL) { ringing_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)),180); /*prepare 200ok*/ ok_response = belle_sip_response_create_from_request(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)),200); content_length= belle_sip_header_content_length_create(strlen(sdp)); content_type = belle_sip_header_content_type_create("application","sdp"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(ok_response),BELLE_SIP_HEADER(content_type)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(ok_response),BELLE_SIP_HEADER(content_length)); belle_sip_message_set_body(BELLE_SIP_MESSAGE(ok_response),sdp,strlen(sdp)); belle_sip_object_ref(ok_response); /*only send ringing*/ belle_sip_server_transaction_send_response(server_transaction,ringing_response); } else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_CONFIRMED) { /*time to send bye*/ belle_sip_client_transaction_t* client_transaction = belle_sip_provider_create_client_transaction(prov,belle_sip_dialog_create_request(dialog,"BYE")); belle_sip_client_transaction_send_request(client_transaction); } else { belle_sip_warning("Unexpected state [%s] for dialog [%p]",belle_sip_dialog_state_to_string(belle_sip_dialog_get_state(dialog)),dialog ); } } static void caller_process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); belle_sip_header_from_t* from=belle_sip_message_get_header_by_type(belle_sip_response_event_get_response(event),belle_sip_header_from_t); belle_sip_header_cseq_t* invite_cseq=belle_sip_message_get_header_by_type(belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction)),belle_sip_header_cseq_t); belle_sip_request_t* ack; belle_sip_dialog_t* dialog; int status; if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)))) { belle_sip_message("Message [%p] not for caller, skipping",belle_sip_response_event_get_response(event)); return; /*not for the caller*/ } status = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); belle_sip_message("caller_process_response_event [%i]",status); CU_ASSERT_PTR_NOT_NULL_FATAL(client_transaction); dialog = belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(client_transaction)); CU_ASSERT_PTR_NOT_NULL_FATAL(dialog); CU_ASSERT_PTR_EQUAL(caller_dialog,dialog); if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_NULL) { CU_ASSERT_EQUAL(status,100); } else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_EARLY){ CU_ASSERT_EQUAL(status,180); /*send 200ok from callee*/ belle_sip_server_transaction_send_response(inserv_transaction,ok_response); belle_sip_object_unref(ok_response); ok_response=NULL; } else if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_CONFIRMED) { ack=belle_sip_dialog_create_ack(dialog,belle_sip_header_cseq_get_seq_number(invite_cseq)); belle_sip_dialog_send_ack(dialog,ack); } } static void callee_process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ belle_sip_dialog_t* dialog; belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); belle_sip_header_from_t* from=belle_sip_message_get_header_by_type(belle_sip_response_event_get_response(event),belle_sip_header_from_t); int status = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); if (!belle_sip_uri_equals(BELLE_SIP_URI(user_ctx),belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(from)))) { belle_sip_message("Message [%p] not for callee, skipping",belle_sip_response_event_get_response(event)); return; /*not for the callee*/ } CU_ASSERT_PTR_NOT_NULL_FATAL(client_transaction); dialog = belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(client_transaction)); CU_ASSERT_PTR_NOT_NULL_FATAL(dialog); CU_ASSERT_PTR_EQUAL(callee_dialog,dialog); if (belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_TERMINATED) { call_endeed=1; belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } belle_sip_message("callee_process_response_event [%i] on dialog [%p] for state [%s]",status ,dialog ,belle_sip_dialog_state_to_string(belle_sip_dialog_get_state(dialog))); } static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event) { BELLESIP_UNUSED(user_ctx); /* belle_sip_client_transaction_t* client_transaction = belle_sip_timeout_event_get_client_transaction(event); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(client_transaction)); if (op->callbacks.process_timeout) { op->callbacks.process_timeout(op,event); } else*/ { belle_sip_message("Unhandled event timeout [%p]",event); } } static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event) { BELLESIP_UNUSED(user_ctx); /* belle_sip_client_transaction_t* client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event); SalOp* op = (SalOp*)belle_sip_transaction_get_application_data(client_transaction); if (op->calbacks.process_transaction_terminated) { op->calbacks.process_transaction_terminated(op,event); } else */{ belle_sip_message("Unhandled transaction terminated [%p]",event); } } static void listener_destroyed(void *user_ctx){ belle_sip_object_unref(user_ctx); } static void do_simple_call(void) { #define CALLER "marie" #define CALLEE "pauline" belle_sip_request_t *pauline_register_req; belle_sip_request_t *marie_register_req; belle_sip_listener_callbacks_t caller_listener_callbacks; belle_sip_listener_t* caller_listener; belle_sip_listener_callbacks_t callee_listener_callbacks; belle_sip_listener_t* callee_listener; belle_sip_request_t* req; belle_sip_header_address_t* from; belle_sip_header_address_t* to; belle_sip_header_address_t* route; belle_sip_header_allow_t* header_allow; belle_sip_header_content_type_t* content_type ; belle_sip_header_content_length_t* content_length; belle_sip_client_transaction_t* client_transaction; char cookie[4]; caller_listener_callbacks.process_dialog_terminated=process_dialog_terminated; caller_listener_callbacks.process_io_error=process_io_error; caller_listener_callbacks.process_request_event=caller_process_request_event; caller_listener_callbacks.process_response_event=caller_process_response_event; caller_listener_callbacks.process_timeout=process_timeout; caller_listener_callbacks.process_transaction_terminated=process_transaction_terminated; caller_listener_callbacks.listener_destroyed=listener_destroyed; callee_listener_callbacks.process_dialog_terminated=process_dialog_terminated; callee_listener_callbacks.process_io_error=process_io_error; callee_listener_callbacks.process_request_event=callee_process_request_event; callee_listener_callbacks.process_response_event=callee_process_response_event; callee_listener_callbacks.process_timeout=process_timeout; callee_listener_callbacks.process_transaction_terminated=process_transaction_terminated; callee_listener_callbacks.listener_destroyed=listener_destroyed; pauline_register_req=register_user(stack, prov, "TCP" ,1 ,CALLER,NULL); if (belle_sip_provider_get_listening_point(prov, "tls")) { marie_register_req=register_user(stack, prov, "TLS" ,1 ,CALLEE,NULL); } else { marie_register_req=register_user(stack, prov, "TCP" ,1 ,CALLEE,NULL); } from=belle_sip_header_address_create(NULL,belle_sip_uri_create(CALLER,test_domain)); /*to make sure unexpected messages are ignored*/ belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(from),"cookie",belle_sip_random_token(cookie,sizeof(cookie))); /*to make sure unexpected messages are ignored*/ to=belle_sip_header_address_create(NULL,belle_sip_uri_create(CALLEE,test_domain)); belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(to),"cookie",belle_sip_random_token(cookie,sizeof(cookie))); belle_sip_provider_add_sip_listener(prov,caller_listener=belle_sip_listener_create_from_callbacks(&caller_listener_callbacks,belle_sip_object_ref(belle_sip_header_address_get_uri((belle_sip_header_address_t*)from)))); belle_sip_provider_add_sip_listener(prov,callee_listener=belle_sip_listener_create_from_callbacks(&callee_listener_callbacks,belle_sip_object_ref(belle_sip_header_address_get_uri((belle_sip_header_address_t*)to)))); route = belle_sip_header_address_create(NULL,belle_sip_uri_create(NULL,test_domain)); belle_sip_uri_set_transport_param(belle_sip_header_address_get_uri(route),"tcp"); req=build_request(stack,prov,from,to,route,"INVITE"); header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(header_allow)); content_length= belle_sip_header_content_length_create(strlen(sdp)); content_type = belle_sip_header_content_type_create("application","sdp"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(content_type)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(content_length)); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),sdp,strlen(sdp)); client_transaction = belle_sip_provider_create_client_transaction(prov,req); caller_dialog=belle_sip_provider_create_dialog(prov,BELLE_SIP_TRANSACTION(client_transaction)); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(client_transaction))); //belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),op); call_endeed=0; belle_sip_client_transaction_send_request(client_transaction); //int i=0; //for(i=0;i<10 &&!call_endeed;i++) belle_sip_stack_sleep(stack,30000); CU_ASSERT_EQUAL(call_endeed,1); belle_sip_provider_remove_sip_listener(prov,caller_listener); belle_sip_provider_remove_sip_listener(prov,callee_listener); belle_sip_object_unref(caller_listener); belle_sip_object_unref(callee_listener); unregister_user(stack, prov, pauline_register_req ,1); belle_sip_object_unref(pauline_register_req); unregister_user(stack, prov, marie_register_req ,1); belle_sip_object_unref(marie_register_req); } static void simple_call(void){ belle_sip_stack_set_tx_delay(stack,0); do_simple_call(); } static void simple_call_with_delay(void){ belle_sip_stack_set_tx_delay(stack,2000); do_simple_call(); belle_sip_stack_set_tx_delay(stack,0); } /*static void simple_call_udp_tcp_with_delay(void){ belle_sip_listening_point_t* lp=belle_sip_provider_get_listening_point(prov,"tls"); belle_sip_object_ref(lp); belle_sip_stack_set_tx_delay(stack,2000); belle_sip_provider_remove_listening_point(prov,lp); do_simple_call(); belle_sip_stack_set_tx_delay(stack,0); belle_sip_provider_add_listening_point(prov,lp); belle_sip_object_unref(lp); }*/ test_t dialog_tests[] = { { "Simple call", simple_call }, { "Simple call with delay", simple_call_with_delay } }; test_suite_t dialog_test_suite = { "Dialog", register_init, register_uninit, sizeof(dialog_tests) / sizeof(dialog_tests[0]), dialog_tests }; belle-sip-1.4.1/tester/belle_sip_headers_tester.c000066400000000000000000001437211252242224000220650ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/belle-sip.h" #include "belle_sip_internal.h" #include "belle_sip_tester.h" #include #include "CUnit/Basic.h" static void test_simple_contact_header(void) { belle_sip_header_contact_t* L_tmp; belle_sip_uri_t* L_uri; belle_sip_header_contact_t* L_contact = belle_sip_header_contact_parse("m:sip:titi.com"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_contact)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_contact)); L_tmp = belle_sip_header_contact_parse(l_raw_header); L_contact = BELLE_SIP_HEADER_CONTACT(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri((belle_sip_header_address_t*)L_contact); CU_ASSERT_PTR_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "titi.com"); CU_ASSERT_PTR_NULL(belle_sip_uri_get_transport_param(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_contact)); CU_ASSERT_PTR_NULL(belle_sip_header_contact_parse("nimportequoi")); } static void test_complex_contact_header(void) { belle_sip_header_contact_t* L_contact; belle_sip_uri_t* L_uri; belle_sip_header_contact_t* L_tmp = belle_sip_header_contact_parse("Contact: \"j\x8eremis\" ;expires=3600;q=0.7, sip:titi.com"); belle_sip_header_t* l_next; belle_sip_header_contact_t* L_next_contact; char* l_raw_header; float l_qvalue; L_contact = BELLE_SIP_HEADER_CONTACT(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); L_uri = belle_sip_header_address_get_uri((belle_sip_header_address_t*)L_contact); CU_ASSERT_PTR_NOT_NULL(L_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "sip.linphone.org"); CU_ASSERT_STRING_EQUAL(belle_sip_header_address_get_displayname((belle_sip_header_address_t*)L_contact), "j\x8eremis"); CU_ASSERT_EQUAL(belle_sip_header_contact_get_expires(L_contact),3600); l_qvalue = belle_sip_header_contact_get_qvalue(L_contact); CU_ASSERT_EQUAL(l_qvalue,0.7f); l_next = belle_sip_header_get_next(BELLE_SIP_HEADER(L_contact)); L_next_contact = BELLE_SIP_HEADER_CONTACT(l_next); CU_ASSERT_PTR_NOT_NULL(L_next_contact); CU_ASSERT_PTR_NOT_NULL( belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_contact))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_contact)); L_contact = belle_sip_header_contact_parse("Contact: super toto ;expires=3600; q=0.7"); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_contact)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_contact)); L_contact = belle_sip_header_contact_parse(l_raw_header); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_address_get_displayname((belle_sip_header_address_t*)L_contact), "super toto"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_contact)); CU_ASSERT_PTR_NULL(belle_sip_header_contact_parse("m:sip:titi.com, nimportequoi")); } static void test_from_header(void) { belle_sip_header_from_t* L_tmp; belle_sip_uri_t* L_uri; belle_generic_uri_t* L_absoluteUri; belle_sip_header_from_t* L_from = belle_sip_header_from_parse("f:;tag=dlfjklcn6545614XX"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_from)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_from)); L_tmp = belle_sip_header_from_parse(l_raw_header); L_from = BELLE_SIP_HEADER_FROM(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_from)); CU_ASSERT_PTR_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "titi.com"); CU_ASSERT_STRING_EQUAL(belle_sip_header_from_get_tag(L_from),"dlfjklcn6545614XX"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_from)); L_from = belle_sip_header_from_parse("From: ;tag=dlfjklcn6545614XX"); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_from)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_from)); L_tmp = belle_sip_header_from_parse(l_raw_header); L_from = BELLE_SIP_HEADER_FROM(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); L_absoluteUri = belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(L_from)); CU_ASSERT_PTR_NULL(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_from))); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_opaque_part(L_absoluteUri), "+33124585454;toto=titi"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(L_absoluteUri), "tel"); CU_ASSERT_STRING_EQUAL(belle_sip_header_from_get_tag(L_from),"dlfjklcn6545614XX"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_from)); /*test factory*/ L_from = belle_sip_header_from_create2("super ","12345-abc"); CU_ASSERT_PTR_NOT_NULL_FATAL(L_from); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_from)); CU_ASSERT_PTR_NOT_NULL_FATAL(L_uri); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"lr")); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"ttl")); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"method")); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"maddr")); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"transport")); CU_ASSERT_FALSE(belle_sip_uri_get_port(L_uri)>0); CU_ASSERT_EQUAL(belle_sip_list_size(belle_sip_uri_get_header_names(L_uri)),0); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "titi.com"); CU_ASSERT_STRING_EQUAL(belle_sip_header_from_get_tag(L_from),"12345-abc"); belle_sip_object_unref(L_from); CU_ASSERT_PTR_NULL(belle_sip_header_from_parse("nimportequoi")); } static void test_from_header_with_paramless_address_spec(void) { belle_generic_uri_t *L_absoluteUri; belle_sip_header_from_t* L_from = belle_sip_header_from_parse("From: sip:bob@titi.com;tag=dlfjklcn6545614XX"); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_header_from_get_tag(L_from)); CU_ASSERT_STRING_EQUAL(belle_sip_header_from_get_tag(L_from),"dlfjklcn6545614XX"); belle_sip_object_unref(L_from); L_from = belle_sip_header_from_parse("From: tel:1234567;tag=dlfjklcn6545614XX"); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_header_from_get_tag(L_from)); L_absoluteUri = belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(L_from)); CU_ASSERT_PTR_NULL(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_from))); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_opaque_part(L_absoluteUri), "1234567"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(L_absoluteUri), "tel"); CU_ASSERT_STRING_EQUAL(belle_sip_header_from_get_tag(L_from),"dlfjklcn6545614XX"); belle_sip_object_unref(L_from); } static void test_to_header_with_paramless_address_spec(void) { belle_generic_uri_t *L_absoluteUri; belle_sip_header_to_t* L_to = belle_sip_header_to_parse("To: sip:bob@titi.com;tag=dlfjklcn6545614XX"); belle_sip_uri_t *L_uri; CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_header_to_get_tag(L_to)); CU_ASSERT_STRING_EQUAL(belle_sip_header_to_get_tag(L_to),"dlfjklcn6545614XX"); belle_sip_object_unref(L_to); L_to = belle_sip_header_to_parse("To:sip:1002@192.168.1.199;tag=as1f0a0817"); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_header_to_get_tag(L_to)); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_to)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri),"1002"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "192.168.1.199"); CU_ASSERT_STRING_EQUAL(belle_sip_header_to_get_tag(L_to),"as1f0a0817"); belle_sip_object_unref(L_to); L_to = belle_sip_header_to_parse("To: tel:1234567;tag=dlfjklcn6545614XX"); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_header_to_get_tag(L_to)); L_absoluteUri = belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(L_to)); CU_ASSERT_PTR_NULL(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_to))); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_opaque_part(L_absoluteUri), "1234567"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(L_absoluteUri), "tel"); CU_ASSERT_STRING_EQUAL(belle_sip_header_to_get_tag(L_to),"dlfjklcn6545614XX"); belle_sip_object_unref(L_to); CU_ASSERT_PTR_NULL(belle_sip_header_to_parse("nimportequoi")); } static void test_contact_header_with_paramless_address_spec(void) { belle_sip_header_contact_t* L_contact = belle_sip_header_contact_parse("Contact: sip:bob@titi.com;expires=60"); CU_ASSERT_EQUAL(belle_sip_header_contact_get_expires(L_contact),60); belle_sip_object_unref(L_contact); } static void test_to_header(void) { belle_sip_uri_t* L_uri; belle_generic_uri_t* L_absoluteUri; belle_sip_header_to_t *L_tmp, *L_to = belle_sip_header_to_parse("t : < sip:titi.com;transport=tcp> ; tag = dlfjklcn6545614XX"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_to)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_to)); L_to = belle_sip_header_to_parse(l_raw_header); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_to)); CU_ASSERT_PTR_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "titi.com"); CU_ASSERT_STRING_EQUAL(belle_sip_header_to_get_tag(L_to),"dlfjklcn6545614XX"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_to)); /*test factory*/ L_to = belle_sip_header_to_create2("\"super man\" ","12345-abc"); CU_ASSERT_PTR_NOT_NULL_FATAL(L_to); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_to)); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"lr")); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"ttl")); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"method")); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"maddr")); CU_ASSERT_FALSE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri),"transport")); CU_ASSERT_FALSE(belle_sip_uri_get_port(L_uri)>0); CU_ASSERT_EQUAL(belle_sip_list_size(belle_sip_uri_get_header_names(L_uri)),0); CU_ASSERT_PTR_NOT_NULL_FATAL(L_uri); CU_ASSERT_STRING_EQUAL(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(L_to)), "super man"); CU_ASSERT_STRING_EQUAL(belle_sip_header_to_get_tag(L_to),"12345-abc"); belle_sip_object_unref(L_to); L_to = belle_sip_header_to_parse("To: ;tag=dlfjklcn6545614XX"); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_to)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_to)); L_tmp = belle_sip_header_to_parse(l_raw_header); L_to = BELLE_SIP_HEADER_TO(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); L_absoluteUri = belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(L_to)); CU_ASSERT_PTR_NULL(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_to))); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_opaque_part(L_absoluteUri), "+33124585454;toto=titi"); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_scheme(L_absoluteUri), "tel"); CU_ASSERT_STRING_EQUAL(belle_sip_header_to_get_tag(L_to),"dlfjklcn6545614XX"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_to)); } static void test_via_header(void) { belle_sip_header_via_t* L_tmp; belle_sip_header_t* l_next; belle_sip_header_via_t* L_next_via; belle_sip_header_via_t* L_via = belle_sip_header_via_parse("v: SIP/2.0/UDP [::1]:5062;rport;received=::1;branch=z9hG4bK368560724"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_via)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_via)); L_tmp = belle_sip_header_via_parse(l_raw_header); L_via = BELLE_SIP_HEADER_VIA(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_via_get_protocol(L_via), "SIP/2.0"); CU_ASSERT_STRING_EQUAL(belle_sip_header_via_get_transport(L_via), "UDP"); CU_ASSERT_STRING_EQUAL(belle_sip_header_via_get_host(L_via), "::1"); CU_ASSERT_EQUAL(belle_sip_header_via_get_port(L_via),5062); CU_ASSERT_TRUE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_via),"rport")); CU_ASSERT_STRING_EQUAL(belle_sip_header_via_get_received(L_via),"::1"); CU_ASSERT_STRING_EQUAL(belle_sip_header_via_get_branch(L_via),"z9hG4bK368560724"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_via)); L_via = belle_sip_header_via_parse("Via: SIP/2.0/UDP 192.168.0.19:5062;received=192.169.0.4;rport=1234;branch=z9hG4bK368560724, SIP/2.0/UDP 192.168.0.19:5062"); l_next = belle_sip_header_get_next(BELLE_SIP_HEADER(L_via)); L_next_via = BELLE_SIP_HEADER_VIA(l_next); CU_ASSERT_PTR_NOT_NULL(L_next_via); CU_ASSERT_STRING_EQUAL(belle_sip_header_via_get_host(L_next_via),"192.168.0.19"); CU_ASSERT_STRING_EQUAL(belle_sip_header_via_get_received(L_via),"192.169.0.4"); CU_ASSERT_EQUAL(belle_sip_header_via_get_rport(L_via),1234); belle_sip_object_unref(BELLE_SIP_OBJECT(L_via)); CU_ASSERT_PTR_NULL(belle_sip_header_via_parse("nimportequoi")); CU_ASSERT_PTR_NULL(belle_sip_header_contact_parse("Via: SIP/2.0/UDP 192.168.0.19:5062;branch=z9hG4bK368560724, nimportequoi")); } static void test_call_id_header(void) { belle_sip_header_call_id_t* L_tmp; belle_sip_header_call_id_t* L_call_id = belle_sip_header_call_id_parse("i: 1665237789@titi.com"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_call_id)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_call_id)); L_tmp= belle_sip_header_call_id_parse(l_raw_header); L_call_id = BELLE_SIP_HEADER_CALL_ID(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_call_id_get_call_id(L_call_id), "1665237789@titi.com"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_call_id)); CU_ASSERT_PTR_NULL(belle_sip_header_call_id_parse("nimportequoi")); } static void test_cseq_header(void) { belle_sip_header_cseq_t* L_tmp; belle_sip_header_cseq_t* L_cseq = belle_sip_header_cseq_parse("CSeq: 21 INVITE"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_cseq)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_cseq)); L_tmp = belle_sip_header_cseq_parse(l_raw_header); L_cseq = BELLE_SIP_HEADER_CSEQ(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_EQUAL(belle_sip_header_cseq_get_seq_number(L_cseq),21); CU_ASSERT_STRING_EQUAL(belle_sip_header_cseq_get_method(L_cseq),"INVITE"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_cseq)); /*test factory*/ L_cseq = belle_sip_header_cseq_create(1,"INFO"); CU_ASSERT_EQUAL(belle_sip_header_cseq_get_seq_number(L_cseq),1); CU_ASSERT_STRING_EQUAL(belle_sip_header_cseq_get_method(L_cseq),"INFO"); belle_sip_object_unref(L_cseq); CU_ASSERT_PTR_NULL(belle_sip_header_cseq_parse("nimportequoi")); } static void test_content_type_header(void) { belle_sip_header_content_type_t* L_tmp; belle_sip_header_content_type_t* L_content_type = belle_sip_header_content_type_parse("c: text/html; charset=ISO-8859-4"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_content_type)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_content_type)); L_tmp = belle_sip_header_content_type_parse(l_raw_header); L_content_type = BELLE_SIP_HEADER_CONTENT_TYPE(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_content_type_get_type(L_content_type),"text"); CU_ASSERT_STRING_EQUAL(belle_sip_header_content_type_get_subtype(L_content_type),"html"); CU_ASSERT_STRING_EQUAL(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(L_content_type),"charset"),"ISO-8859-4"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_content_type)); L_content_type = belle_sip_header_content_type_parse("Content-Type: application/sdp"); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_content_type)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_content_type)); L_content_type = belle_sip_header_content_type_parse(l_raw_header); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_content_type_get_type(L_content_type),"application"); CU_ASSERT_STRING_EQUAL(belle_sip_header_content_type_get_subtype(L_content_type),"sdp"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_content_type)); L_content_type = belle_sip_header_content_type_parse("Content-Type: application/pkcs7-mime; smime-type=enveloped-data; \r\n name=smime.p7m"); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_content_type)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_content_type)); L_content_type = belle_sip_header_content_type_parse(l_raw_header); belle_sip_free(l_raw_header); belle_sip_object_unref(BELLE_SIP_OBJECT(L_content_type)); CU_ASSERT_PTR_NULL(belle_sip_header_content_type_parse("nimportequoi")); } static void test_record_route_header(void) { belle_sip_uri_t* L_uri; belle_sip_header_t* l_next; belle_sip_header_record_route_t* L_next_route; belle_sip_header_record_route_t* L_record_route = belle_sip_header_record_route_parse("Record-Route: ;charset=ISO-8859-4"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_record_route)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_record_route)); L_record_route = belle_sip_header_record_route_parse(l_raw_header); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_record_route)); CU_ASSERT_PTR_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "212.27.52.5"); CU_ASSERT_STRING_EQUAL(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(L_record_route),"charset"),"ISO-8859-4"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_record_route)); L_record_route = belle_sip_header_record_route_parse("Record-Route: ;charset=ISO-8859-4, "); l_next = belle_sip_header_get_next(BELLE_SIP_HEADER(L_record_route)); L_next_route = BELLE_SIP_HEADER_RECORD_ROUTE(l_next); CU_ASSERT_PTR_NOT_NULL(L_next_route); CU_ASSERT_PTR_NOT_NULL( belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_next_route))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_record_route)); CU_ASSERT_PTR_NULL(belle_sip_header_record_route_parse("nimportequoi")); CU_ASSERT_PTR_NULL(belle_sip_header_record_route_parse("Record-Route: , nimportequoi")); L_record_route=belle_sip_header_record_route_parse("Record-route: "); l_raw_header=belle_sip_object_to_string(L_record_route); belle_sip_object_unref(L_record_route); L_record_route=belle_sip_header_record_route_parse(l_raw_header); CU_ASSERT_PTR_NOT_NULL(L_record_route); if (L_record_route) belle_sip_object_unref(L_record_route); belle_sip_free(l_raw_header); } static void test_route_header(void) { belle_sip_header_route_t* L_route; belle_sip_uri_t* L_uri; belle_sip_header_t* l_next; belle_sip_header_route_t* L_next_route; belle_sip_header_address_t* address = belle_sip_header_address_parse(""); char* l_raw_header; CU_ASSERT_PTR_NOT_NULL_FATAL(address); L_route = belle_sip_header_route_create(address); CU_ASSERT_PTR_NOT_NULL_FATAL(L_route); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_route)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_route)); L_route = belle_sip_header_route_parse(l_raw_header); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_route)); CU_ASSERT_PTR_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_EQUAL(belle_sip_uri_get_port(L_uri), 5060); belle_sip_object_unref(BELLE_SIP_OBJECT(L_route)); L_route = belle_sip_header_route_parse("Route: ;charset=ISO-8859-4, "); l_next = belle_sip_header_get_next(BELLE_SIP_HEADER(L_route)); L_next_route = BELLE_SIP_HEADER_ROUTE(l_next); CU_ASSERT_PTR_NOT_NULL(L_next_route); CU_ASSERT_PTR_NOT_NULL( belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_next_route))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_route)); CU_ASSERT_PTR_NULL(belle_sip_header_route_parse("nimportequoi")); CU_ASSERT_PTR_NULL(belle_sip_header_contact_parse("Route: , nimportequoi")); L_route=belle_sip_header_route_parse("Route: "); l_raw_header=belle_sip_object_to_string(L_route); belle_sip_object_unref(L_route); L_route=belle_sip_header_route_parse(l_raw_header); CU_ASSERT_PTR_NOT_NULL(L_route); if (L_route) belle_sip_object_unref(L_route); belle_sip_free(l_raw_header); } static void test_service_route_header(void) { belle_sip_header_service_route_t* L_service_route = belle_sip_header_service_route_parse("Service-Route: "); belle_sip_uri_t* L_uri; char* l_raw_header; CU_ASSERT_PTR_NOT_NULL_FATAL(L_service_route); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_service_route)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_service_route)); L_service_route = belle_sip_header_service_route_parse(l_raw_header); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_service_route)); CU_ASSERT_PTR_NOT_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_EQUAL(belle_sip_uri_get_port(L_uri), 6060); belle_sip_object_unref(BELLE_SIP_OBJECT(L_service_route)); CU_ASSERT_PTR_NULL(belle_sip_header_service_route_parse("nimportequoi")); } static void test_content_length_header(void) { belle_sip_header_content_length_t* L_tmp; belle_sip_header_content_length_t* L_content_length = belle_sip_header_content_length_parse("Content-Length: 3495"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_content_length)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_content_length)); L_tmp = belle_sip_header_content_length_parse(l_raw_header); L_content_length = BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_EQUAL(belle_sip_header_content_length_get_content_length(L_content_length), 3495); belle_sip_object_unref(BELLE_SIP_OBJECT(L_content_length)); CU_ASSERT_PTR_NULL(belle_sip_header_content_length_parse("nimportequoi")); } static belle_sip_header_t* test_header_extension(const char* name,const char* value) { belle_sip_header_t* L_tmp; belle_sip_header_t* L_extension; char header[256]; char* l_raw_header=NULL; snprintf(header,sizeof(header),"%s:%s",name,value); L_extension = belle_sip_header_parse(header); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_extension)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_extension)); L_tmp = belle_sip_header_parse(l_raw_header); L_extension = BELLE_SIP_HEADER(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_get_unparsed_value(L_extension), value); /*FIXME jehan check why missing colon does not lead an exception CU_ASSERT_PTR_NULL(belle_sip_header_extension_parse("nimportequoi"));*/ return L_extension; } static void test_header_extension_1() { belle_sip_object_unref(test_header_extension("toto","titi")); } static void test_header_extension_2() { belle_sip_header_t* header = test_header_extension("From","sip:localhost"); CU_ASSERT_TRUE(BELLE_SIP_OBJECT_IS_INSTANCE_OF(header,belle_sip_header_from_t)); belle_sip_object_unref(header); } static void test_authorization_header(void) { const char* l_header = "Authorization: Digest username=\"0033482532176\", "\ "realm=\"sip.ovh.net\", nonce=\"1bcdcb194b30df5f43973d4c69bdf54f\", uri=\"sip:sip.ovh.net\", response=\"eb36c8d5c8642c1c5f44ec3404613c81\","\ "algorithm=MD5, opaque=\"1bc7f9097684320\"," "\r\n qop=auth, nc=00000001,cnonce=\"0a4f113b\", blabla=\"toto\""; belle_sip_header_authorization_t* L_tmp; belle_sip_header_authorization_t* L_authorization = belle_sip_header_authorization_parse(l_header); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_authorization)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_authorization)); L_tmp = belle_sip_header_authorization_parse(l_raw_header); L_authorization = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_PTR_NOT_NULL_FATAL(L_authorization); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_scheme(L_authorization), "Digest"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_username(L_authorization), "0033482532176"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_realm(L_authorization), "sip.ovh.net"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_nonce(L_authorization), "1bcdcb194b30df5f43973d4c69bdf54f"); CU_ASSERT_PTR_NOT_NULL(belle_sip_header_authorization_get_uri(L_authorization)); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_response(L_authorization), "eb36c8d5c8642c1c5f44ec3404613c81"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_algorithm(L_authorization), "MD5"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_opaque(L_authorization), "1bc7f9097684320"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_qop(L_authorization), "auth"); CU_ASSERT_EQUAL(belle_sip_header_authorization_get_nonce_count(L_authorization), 1); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_cnonce(L_authorization), "0a4f113b"); CU_ASSERT_STRING_EQUAL(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(L_authorization), "blabla"),"\"toto\""); belle_sip_object_unref(BELLE_SIP_OBJECT(L_authorization)); CU_ASSERT_PTR_NULL(belle_sip_header_authorization_parse("nimportequoi")); } static void test_proxy_authorization_header(void) { const char* l_header = "Proxy-Authorization: Digest username=\"Alice\"" ", realm=\"atlanta.com\", nonce=\"c60f3082ee1212b402a21831ae\"" ", response=\"245f23415f11432b3434341c022\""; belle_sip_header_proxy_authorization_t* L_authorization = belle_sip_header_proxy_authorization_parse(l_header); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_authorization)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_authorization)); L_authorization = belle_sip_header_proxy_authorization_parse(l_raw_header); belle_sip_free(l_raw_header); CU_ASSERT_PTR_NOT_NULL(L_authorization); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_username(BELLE_SIP_HEADER_AUTHORIZATION(L_authorization)), "Alice"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_realm(BELLE_SIP_HEADER_AUTHORIZATION(L_authorization)), "atlanta.com"); CU_ASSERT_STRING_EQUAL(belle_sip_header_authorization_get_nonce(BELLE_SIP_HEADER_AUTHORIZATION(L_authorization)), "c60f3082ee1212b402a21831ae"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_authorization)); CU_ASSERT_PTR_NULL(belle_sip_header_proxy_authorization_parse("nimportequoi")); } static void check_header_authenticate(belle_sip_header_www_authenticate_t* authenticate) { belle_sip_list_t* qop; CU_ASSERT_PTR_NOT_NULL(authenticate); CU_ASSERT_STRING_EQUAL(belle_sip_header_www_authenticate_get_realm(authenticate), "atlanta.com"); CU_ASSERT_STRING_EQUAL(belle_sip_header_www_authenticate_get_domain(authenticate), "sip:boxesbybob.com"); CU_ASSERT_STRING_EQUAL(belle_sip_header_www_authenticate_get_nonce(authenticate), "c60f3082ee1212b402a21831ae"); CU_ASSERT_STRING_EQUAL(belle_sip_header_www_authenticate_get_algorithm(authenticate), "MD5"); CU_ASSERT_STRING_EQUAL(belle_sip_header_www_authenticate_get_opaque(authenticate), "1bc7f9097684320"); CU_ASSERT_PTR_NOT_NULL_FATAL(qop=belle_sip_header_www_authenticate_get_qop(authenticate)); CU_ASSERT_STRING_EQUAL((const char*)qop->data, "auth"); CU_ASSERT_PTR_NOT_NULL_FATAL(qop=qop->next); CU_ASSERT_STRING_EQUAL((const char*)qop->data, "auth-int"); CU_ASSERT_STRING_EQUAL(belle_sip_header_www_authenticate_get_qop(authenticate)->data, "auth"); CU_ASSERT_STRING_EQUAL(belle_sip_header_www_authenticate_get_scheme(authenticate), "Digest"); CU_ASSERT_EQUAL(belle_sip_header_www_authenticate_is_stale(authenticate),1); belle_sip_object_unref(BELLE_SIP_OBJECT(authenticate)); } static void test_www_authenticate_header(void) { const char* l_header = "WWW-Authenticate: Digest " "algorithm=MD5,\r\n realm=\"atlanta.com\",\r\n opaque=\"1bc7f9097684320\"," " qop=\"auth,auth-int\", nonce=\"c60f3082ee1212b402a21831ae\", stale=true, domain=\"sip:boxesbybob.com\""; const char* l_header_1 = "WWW-Authenticate: Digest realm=\"toto.com\",\r\n nonce=\"b543409177c9036dbf3054aea940e9703dc8f84c0108\"" ",\r\n opaque=\"ALU:QbkRBthOEgEQAkgVEwwHRAIBHgkdHwQCQ1lFRkRWEAkic203MSEzJCgoZS8iI3VlYWRj\",\r\n algorithm=MD5" ",\r\n qop=\"auth\""; belle_sip_header_www_authenticate_t* L_tmp; belle_sip_header_www_authenticate_t *l_authenticate = belle_sip_header_www_authenticate_parse(l_header); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_authenticate)); belle_sip_object_unref(BELLE_SIP_OBJECT(l_authenticate)); L_tmp = belle_sip_header_www_authenticate_parse(l_raw_header); l_authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); check_header_authenticate(l_authenticate); l_authenticate = belle_sip_header_www_authenticate_parse(l_header_1); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(l_authenticate)); belle_sip_object_unref(BELLE_SIP_OBJECT(l_authenticate)); L_tmp = belle_sip_header_www_authenticate_parse(l_raw_header); l_authenticate = BELLE_SIP_HEADER_WWW_AUTHENTICATE(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(l_authenticate)); CU_ASSERT_PTR_NULL(belle_sip_header_www_authenticate_parse("nimportequoi")); } static void test_proxy_authenticate_header(void) { const char* l_header = "Proxy-Authenticate: Digest " "algorithm=MD5, realm=\"atlanta.com\", opaque=\"1bc7f9097684320\"," " qop=\"auth,auth-int\", nonce=\"c60f3082ee1212b402a21831ae\", stale=true, domain=\"sip:boxesbybob.com\""; belle_sip_header_proxy_authenticate_t* L_tmp; belle_sip_header_proxy_authenticate_t* L_proxy_authorization = belle_sip_header_proxy_authenticate_parse(l_header); //belle_sip_list_t* qop; char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_proxy_authorization)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_proxy_authorization)); L_tmp = belle_sip_header_proxy_authenticate_parse(l_raw_header); L_proxy_authorization = BELLE_SIP_HEADER_PROXY_AUTHENTICATE(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); check_header_authenticate(BELLE_SIP_HEADER_WWW_AUTHENTICATE(L_proxy_authorization)); CU_ASSERT_PTR_NULL(belle_sip_header_proxy_authenticate_parse("nimportequoi")); } static void test_max_forwards_header(void) { const char* l_header = "Max-Forwards: 6"; belle_sip_header_max_forwards_t* L_tmp; belle_sip_header_max_forwards_t* L_max_forwards = belle_sip_header_max_forwards_parse(l_header); char* l_raw_header; belle_sip_header_max_forwards_decrement_max_forwards(L_max_forwards); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_max_forwards)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_max_forwards)); L_tmp = belle_sip_header_max_forwards_parse(l_raw_header); L_max_forwards = BELLE_SIP_HEADER_MAX_FORWARDS(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_PTR_NOT_NULL(L_max_forwards); CU_ASSERT_EQUAL(belle_sip_header_max_forwards_get_max_forwards(L_max_forwards), 5); belle_sip_object_unref(BELLE_SIP_OBJECT(L_max_forwards)); CU_ASSERT_PTR_NULL(belle_sip_header_max_forwards_parse("nimportequoi")); } static void test_user_agent_header(void) { const char* l_header = "User-Agent: Linphone/3.4.99.1 (eXosip2/3.3.0)"; const char* values[] ={"Linphone/3.4.99.1" ,"(eXosip2/3.3.0)"}; belle_sip_list_t* products; belle_sip_header_user_agent_t* L_tmp; belle_sip_header_user_agent_t* L_user_agent = belle_sip_header_user_agent_parse(l_header); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_user_agent)); int i=0; belle_sip_object_unref(BELLE_SIP_OBJECT(L_user_agent)); L_tmp = belle_sip_header_user_agent_parse(l_raw_header); L_user_agent = BELLE_SIP_HEADER_USER_AGENT(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); products = belle_sip_header_user_agent_get_products(L_user_agent); for(i=0;i<2;i++){ CU_ASSERT_PTR_NOT_NULL(products); CU_ASSERT_STRING_EQUAL((const char *)(products->data),values[i]); products=products->next; } belle_sip_object_unref(BELLE_SIP_OBJECT(L_user_agent)); CU_ASSERT_PTR_NULL(belle_sip_header_user_agent_parse("nimportequoi")); } static void test_expires_header(void) { belle_sip_header_expires_t* L_tmp; belle_sip_header_expires_t* L_expires = belle_sip_header_expires_parse("Expires: 3600"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_expires)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_expires)); L_tmp= belle_sip_header_expires_parse(l_raw_header); L_expires = BELLE_SIP_HEADER_EXPIRES(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_EQUAL(belle_sip_header_expires_get_expires(L_expires), 3600); belle_sip_object_unref(BELLE_SIP_OBJECT(L_expires)); /*test factory*/ L_expires = belle_sip_header_expires_create(600); CU_ASSERT_EQUAL(belle_sip_header_expires_get_expires(L_expires), 600); belle_sip_object_unref(L_expires); CU_ASSERT_PTR_NULL(belle_sip_header_expires_parse("nimportequoi")); } static void test_allow_header(void) { belle_sip_header_allow_t* L_tmp; belle_sip_header_allow_t* L_allow = belle_sip_header_allow_parse("Allow:INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_allow)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_allow)); L_tmp = belle_sip_header_allow_parse(l_raw_header); L_allow = BELLE_SIP_HEADER_ALLOW(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_allow_get_method(L_allow), "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_allow)); CU_ASSERT_PTR_NULL(belle_sip_header_allow_parse("nimportequoi")); } static void test_address_with_error_header(void) { belle_sip_header_address_t* laddress = belle_sip_header_address_parse("sip:liblinphone_tester@=auth1.example.org"); CU_ASSERT_PTR_NULL(laddress); laddress = belle_sip_header_address_parse("liblinphone_tester"); CU_ASSERT_PTR_NULL(laddress); } static void test_address_header(void) { belle_sip_uri_t* L_uri; char* L_raw; belle_sip_header_address_t* laddress = belle_sip_header_address_parse("\"toto\" "); CU_ASSERT_PTR_NOT_NULL(laddress); L_raw = belle_sip_object_to_string(BELLE_SIP_OBJECT(laddress)); CU_ASSERT_PTR_NOT_NULL(L_raw); belle_sip_object_unref(BELLE_SIP_OBJECT(laddress)); laddress = belle_sip_header_address_parse(L_raw); belle_sip_free(L_raw); CU_ASSERT_STRING_EQUAL("toto",belle_sip_header_address_get_displayname(laddress)) L_uri = belle_sip_header_address_get_uri(laddress); CU_ASSERT_PTR_NOT_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "81.56.11.2"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri), "liblinphone_tester"); CU_ASSERT_EQUAL(belle_sip_uri_get_port(L_uri), 5060); belle_sip_object_unref(BELLE_SIP_OBJECT(laddress)); laddress = belle_sip_header_address_parse("\"\\\"to\\\\to\\\"\" "); CU_ASSERT_PTR_NOT_NULL(laddress); L_raw = belle_sip_object_to_string(BELLE_SIP_OBJECT(laddress)); CU_ASSERT_PTR_NOT_NULL(L_raw); belle_sip_object_unref(BELLE_SIP_OBJECT(laddress)); laddress = belle_sip_header_address_parse(L_raw); belle_sip_free(L_raw); CU_ASSERT_STRING_EQUAL("\"to\\to\"",belle_sip_header_address_get_displayname(laddress)) belle_sip_object_unref(BELLE_SIP_OBJECT(laddress)); } static void test_address_header_with_tel_uri(void) { belle_generic_uri_t* L_uri; char* L_raw; belle_sip_header_address_t* laddress = belle_sip_header_address_parse("\"toto\" "); CU_ASSERT_PTR_NOT_NULL(laddress); L_raw = belle_sip_object_to_string(BELLE_SIP_OBJECT(laddress)); CU_ASSERT_PTR_NOT_NULL(L_raw); belle_sip_object_unref(BELLE_SIP_OBJECT(laddress)); laddress = belle_sip_header_address_parse(L_raw); belle_sip_free(L_raw); CU_ASSERT_STRING_EQUAL("toto",belle_sip_header_address_get_displayname(laddress)); L_uri = belle_sip_header_address_get_absolute_uri(laddress); CU_ASSERT_PTR_NOT_NULL(belle_generic_uri_get_opaque_part(L_uri)); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_opaque_part(L_uri), "123456"); belle_sip_object_unref(BELLE_SIP_OBJECT(laddress)); } static void test_very_long_address_header(void) { belle_sip_uri_t* L_uri; const char* raw = ""; /*not compliant but*/ belle_sip_header_address_t* laddress = belle_sip_header_address_parse(raw); CU_ASSERT_PTR_NOT_NULL_FATAL(laddress); L_uri = belle_sip_header_address_get_uri(laddress); CU_ASSERT_PTR_NOT_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "sip.linphone.org"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri), "jehan"); CU_ASSERT_STRING_EQUAL(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(L_uri),"pn-tok") ,"APA91bHPVa4PuKOMnr6ppWb3XYUL06QO-ND4eeiw7dG49q4o_Ywzal7BxVRgH-wvqH9iB9V7h6kfb-DCiVdSpnl6CeWO25FAkM4eh6DJyWcbP7SzhKdku_-r9936kJW7-4drI6-Om4qp"); belle_sip_object_unref(BELLE_SIP_OBJECT(laddress)); } static void test_subscription_state_header(void) { belle_sip_header_subscription_state_t* L_tmp; belle_sip_header_subscription_state_t* L_subscription_state = belle_sip_header_subscription_state_parse("Subscription-State: terminated;expires=600"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_subscription_state)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_subscription_state)); L_tmp = belle_sip_header_subscription_state_parse(l_raw_header); L_subscription_state = BELLE_SIP_HEADER_SUBSCRIPTION_STATE(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_subscription_state_get_state(L_subscription_state), "terminated"); CU_ASSERT_EQUAL(belle_sip_header_subscription_state_get_expires(L_subscription_state), 600); belle_sip_object_unref(BELLE_SIP_OBJECT(L_subscription_state)); CU_ASSERT_PTR_NULL(belle_sip_header_subscription_state_parse("nimportequoi")); } static void test_refer_to_header(void) { belle_sip_uri_t* L_uri; belle_sip_header_refer_to_t* L_refer_to = belle_sip_header_refer_to_parse("Refer-To: "); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_refer_to)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_refer_to)); L_refer_to = belle_sip_header_refer_to_parse(l_raw_header); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_refer_to)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri),"dave"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "denver.example.org"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_refer_to)); /*test factory*/ L_refer_to = belle_sip_header_refer_to_create(belle_sip_header_address_parse("\"super man\" ")); CU_ASSERT_PTR_NOT_NULL_FATAL(L_refer_to); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_refer_to)); CU_ASSERT_PTR_NOT_NULL_FATAL(L_uri); CU_ASSERT_STRING_EQUAL(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(L_refer_to)), "super man"); belle_sip_object_unref(L_refer_to); CU_ASSERT_PTR_NULL(belle_sip_header_refer_to_parse("nimportequoi")); } static void test_referred_by_header(void) { belle_sip_uri_t* L_uri; belle_sip_header_referred_by_t* L_referred_by = belle_sip_header_referred_by_parse("Referred-By: sip:r@ref.example;cid=\"2UWQFN309shb3@ref.example\""); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_referred_by)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_referred_by)); L_referred_by = belle_sip_header_referred_by_parse(l_raw_header); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_referred_by)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri),"r"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "ref.example"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_referred_by)); CU_ASSERT_PTR_NULL(belle_sip_header_referred_by_parse("nimportequoi")); } static void test_replaces_header(void) { belle_sip_header_replaces_t* L_tmp; belle_sip_header_replaces_t* L_replaces = belle_sip_header_replaces_parse("Replaces: 12345@149.112.118.3;to-tag=12345;from-tag=54321"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_replaces)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_replaces)); L_tmp= belle_sip_header_replaces_parse(l_raw_header); L_replaces = BELLE_SIP_HEADER_REPLACES(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_replaces_get_call_id(L_replaces), "12345@149.112.118.3"); CU_ASSERT_STRING_EQUAL(belle_sip_header_replaces_get_from_tag(L_replaces), "54321"); CU_ASSERT_STRING_EQUAL(belle_sip_header_replaces_get_to_tag(L_replaces), "12345"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_replaces)); CU_ASSERT_PTR_NULL(belle_sip_header_replaces_parse("nimportequoi")); } static void test_replaces_escaped_header(void) { belle_sip_header_replaces_t* L_replaces; char* escaped_to_string; char* l_raw_header; belle_sip_header_replaces_t* L_tmp = belle_sip_header_replaces_create("12345@192.168.118.3","5FFE-3994","12345"); escaped_to_string=belle_sip_header_replaces_value_to_escaped_string(L_tmp); L_replaces=belle_sip_header_replaces_create2(escaped_to_string); l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_replaces)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_replaces)); L_tmp= belle_sip_header_replaces_parse(l_raw_header); L_replaces = BELLE_SIP_HEADER_REPLACES(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); belle_sip_free(escaped_to_string); CU_ASSERT_STRING_EQUAL(belle_sip_header_replaces_get_call_id(L_replaces), "12345@192.168.118.3"); CU_ASSERT_STRING_EQUAL(belle_sip_header_replaces_get_from_tag(L_replaces), "5FFE-3994"); CU_ASSERT_STRING_EQUAL(belle_sip_header_replaces_get_to_tag(L_replaces), "12345"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_replaces)); } #ifndef WIN32 static void _test_date_header(void){ belle_sip_header_date_t *date,*date2; time_t utc; #define DATE_EXAMPLE "Thu, 21 Feb 2002 13:02:03 GMT" #define DATE_UTC_EXAMPLE 1014296523L /* the above date in UTC */ date=belle_sip_header_date_parse("Date: " DATE_EXAMPLE); CU_ASSERT_PTR_NOT_NULL(date); utc=belle_sip_header_date_get_time(date); CU_ASSERT_EQUAL(utc,DATE_UTC_EXAMPLE); date2=belle_sip_header_date_create_from_time(&utc); CU_ASSERT_PTR_NOT_NULL(date2); CU_ASSERT_TRUE(strcmp(belle_sip_header_date_get_date(date2),DATE_EXAMPLE)==0); CU_ASSERT_PTR_NULL(belle_sip_header_date_parse("nimportequoi")); } #endif static void test_date_header(void){ #ifdef WIN32 // TODO: setenv and unsetenv are not available for Windows #else char *tz; /* test in our timezone */ _test_date_header(); /* test within another timezone */ tz = getenv("TZ"); setenv("TZ","Etc/GMT+4",1); tzset(); _test_date_header(); /* reset to original timezone */ if(tz) setenv("TZ", tz, 1); else unsetenv("TZ"); tzset(); #endif } static void test_p_preferred_identity_header(void) { belle_sip_uri_t* L_uri; belle_sip_header_p_preferred_identity_t* L_p_preferred_identity = belle_sip_header_p_preferred_identity_parse("P-Preferred-Identity: \"Cullen Jennings\" "); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_p_preferred_identity)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_p_preferred_identity)); L_p_preferred_identity = belle_sip_header_p_preferred_identity_parse(l_raw_header); belle_sip_free(l_raw_header); L_uri = belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(L_p_preferred_identity)); CU_ASSERT_STRING_EQUAL(belle_sip_header_address_get_displayname(BELLE_SIP_HEADER_ADDRESS(L_p_preferred_identity)),"Cullen Jennings"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri),"fluffy"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "cisco.com"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_p_preferred_identity)); CU_ASSERT_PTR_NULL(belle_sip_header_p_preferred_identity_parse("nimportequoi")); } static void test_privacy(const char* raw_header,const char* values[],size_t number_values) { belle_sip_list_t* list; belle_sip_header_privacy_t* L_tmp; belle_sip_header_privacy_t* L_privacy = belle_sip_header_privacy_parse(raw_header); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_privacy)); int i=0; belle_sip_object_unref(BELLE_SIP_OBJECT(L_privacy)); L_tmp = belle_sip_header_privacy_parse(l_raw_header); L_privacy = BELLE_SIP_HEADER_PRIVACY(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); list = belle_sip_header_privacy_get_privacy(L_privacy); for(i=0;idata),values[i]); list=list->next; } belle_sip_object_unref(BELLE_SIP_OBJECT(L_privacy)); CU_ASSERT_PTR_NULL(belle_sip_header_privacy_parse("nimportequoi")); } static void test_privacy_header() { const char* value1[] ={"user","critical"}; const char* value2[] ={"id"}; test_privacy("Privacy: user; critical",value1,2); test_privacy("Privacy: id",value2,1); } static void test_event_header(void) { belle_sip_header_event_t* L_tmp; belle_sip_header_event_t* L_event = belle_sip_header_event_parse("Event: presence;id=blabla1"); char* l_raw_header = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_event)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_event)); L_tmp = belle_sip_header_event_parse(l_raw_header); L_event = BELLE_SIP_HEADER_EVENT(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_header); CU_ASSERT_STRING_EQUAL(belle_sip_header_event_get_package_name(L_event), "presence"); CU_ASSERT_STRING_EQUAL(belle_sip_header_event_get_id(L_event), "blabla1"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_event)); CU_ASSERT_PTR_NULL(belle_sip_header_event_parse("nimportequoi")); } test_t headers_tests[] = { { "Address", test_address_header }, { "Address tel uri", test_address_header_with_tel_uri }, { "Header address (very long)", test_very_long_address_header }, { "Address with error", test_address_with_error_header }, { "Allow", test_allow_header }, { "Authorization", test_authorization_header }, { "Call-ID", test_call_id_header }, { "Contact (Simple)", test_simple_contact_header }, { "Contact (Complex)", test_complex_contact_header }, { "Contact (Param-less address spec)", test_contact_header_with_paramless_address_spec }, { "Content-Length", test_content_length_header }, { "Content-Type", test_content_type_header }, { "CSeq", test_cseq_header }, { "Date", test_date_header }, { "Expires", test_expires_header }, { "From", test_from_header }, { "From (Param-less address spec)", test_from_header_with_paramless_address_spec }, { "Max-Forwards", test_max_forwards_header }, { "Privacy", test_privacy_header }, { "P-Preferred-Identity", test_p_preferred_identity_header }, { "Proxy-Authenticate", test_proxy_authenticate_header }, { "Proxy-Authorization", test_proxy_authorization_header }, { "Record-Route", test_record_route_header }, { "Refer-To", test_refer_to_header }, { "Referred-By", test_referred_by_header }, { "Replaces", test_replaces_header }, { "Replaces (Escaped)", test_replaces_escaped_header }, { "Route", test_route_header }, { "Service-Route", test_service_route_header }, { "Subscription-State", test_subscription_state_header }, { "To", test_to_header }, { "To (Param-less address spec)", test_to_header_with_paramless_address_spec }, { "User-Agent", test_user_agent_header }, { "Via", test_via_header }, { "WWW-Authenticate", test_www_authenticate_header }, { "Header extension", test_header_extension_1 }, { "Header extension 2", test_header_extension_2 }, { "Header event", test_event_header } }; test_suite_t headers_test_suite = { "Headers", NULL, NULL, sizeof(headers_tests) / sizeof(headers_tests[0]), headers_tests }; belle-sip-1.4.1/tester/belle_sip_message_tester.c000066400000000000000000001354151252242224000220770ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/belle-sip.h" #include "belle_sip_tester.h" #include #include "CUnit/Basic.h" static void check_uri_and_headers(belle_sip_message_t* message) { if (belle_sip_message_is_request(message)) { CU_ASSERT_TRUE(belle_sip_request_get_uri(BELLE_SIP_REQUEST(message))|| belle_sip_request_get_absolute_uri(BELLE_SIP_REQUEST(message)) ); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Max-Forwards")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_MAX_FORWARDS(belle_sip_message_get_header(message,"Max-Forwards"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"User-Agent")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_USER_AGENT(belle_sip_message_get_header(message,"User-Agent"))); } CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"From")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_FROM(belle_sip_message_get_header(message,"From"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"To")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_TO(belle_sip_message_get_header(message,"To"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"CSeq")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_CSEQ(belle_sip_message_get_header(message,"CSeq"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Via")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_VIA(belle_sip_message_get_header(message,"Via"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Call-ID")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header(message,"Call-ID"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Content-Length")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_CONTENT_LENGTH(belle_sip_message_get_header(message,"Content-Length"))); } static void testRegisterMessage(void) { const char* raw_message = "REGISTER sip:192.168.0.20 SIP/2.0\r\n"\ "v: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n"\ "f: ;tag=465687829\r\n"\ "t: \r\n"\ "i: 1053183492\r\n"\ "CSeq: 1 REGISTER\r\n"\ "m: \r\n"\ "Max-Forwards: 70\r\n"\ "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n"\ "Expires: 3600\r\n"\ "Proxy-Authorization: Digest username=\"8117396\", realm=\"Realm\", nonce=\"MTMwNDAwMjIxMjA4NzVkODY4ZmZhODMzMzU4ZDJkOTA1NzM2NTQ2NDZlNmIz"\ ", uri=\"sip:linphone.net\", response=\"eed376ff7c963441255ec66594e470e7\", algorithm=MD5, cnonce=\"0a4f113b\", qop=auth, nc=00000001\r\n"\ "l: 0\r\n\r\n"; belle_sip_request_t* request; belle_sip_message_t* message = belle_sip_message_parse(raw_message); char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); message = belle_sip_message_parse(encoded_message); request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"REGISTER"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Expires")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_EXPIRES(belle_sip_message_get_header(message,"Expires"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Proxy-Authorization")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Contact")); check_uri_and_headers(message); belle_sip_free(encoded_message); belle_sip_object_unref(message); } static void testInviteMessage(void) { const char* raw_message = "INVITE sip:becheong@sip.linphone.org SIP/2.0\r\n"\ "Via: SIP/2.0/UDP 10.23.17.117:22600;branch=z9hG4bK-d8754z-4d7620d2feccbfac-1---d8754z-;rport=4820;received=202.165.193.129\r\n"\ "Max-Forwards: 70\r\n"\ "Contact: \r\n"\ "To: \"becheong\" \r\n"\ "From: \"Benjamin Cheong\" ;tag=7326e5f6\r\n"\ "Call-ID: Y2NlNzg0ODc0ZGIxODU1MWI5MzhkNDVkNDZhOTQ4YWU.\r\n"\ "CSeq: 1 INVITE\r\n"\ "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO\r\n"\ "c: application/sdp\r\n"\ "Supported: replaces\r\n"\ "Authorization: Digest username=\"003332176\", realm=\"sip.ovh.net\", nonce=\"24212965507cde726e8bc37e04686459\", uri=\"sip:sip.ovh.net\", response=\"896e786e9c0525ca3085322c7f1bce7b\", algorithm=MD5, opaque=\"241b9fb347752f2\"\r\n"\ "User-Agent: X-Lite 4 release 4.0 stamp 58832\r\n"\ "Content-Length: 230\r\n\r\n"; belle_sip_request_t* request; belle_sip_message_t* message = belle_sip_message_parse(raw_message); char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); message = belle_sip_message_parse(encoded_message); request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"INVITE"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Contact")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Authorization")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Content-Type")); check_uri_and_headers(message); belle_sip_object_unref(message); belle_sip_free(encoded_message); } static void testInviteMessageWithTelUri(void) { const char* raw_message = "INVITE tel:11234567888;phone-context=vzims.fr SIP/2.0\r\n"\ "Via: SIP/2.0/UDP 10.23.17.117:22600;branch=z9hG4bK-d8754z-4d7620d2feccbfac-1---d8754z-;rport=4820;received=202.165.193.129\r\n"\ "Max-Forwards: 70\r\n"\ "Contact: \r\n"\ "To: \r\n"\ "From: tel:11234567888;tag=werwrw\r\n"\ "Call-ID: Y2NlNzg0ODc0ZGIxODU1MWI5MzhkNDVkNDZhOTQ4YWU.\r\n"\ "CSeq: 1 INVITE\r\n"\ "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO\r\n"\ "c: application/sdp\r\n"\ "Supported: replaces\r\n"\ "Authorization: Digest username=\"003332176\", realm=\"sip.ovh.net\", nonce=\"24212965507cde726e8bc37e04686459\", uri=\"sip:sip.ovh.net\", response=\"896e786e9c0525ca3085322c7f1bce7b\", algorithm=MD5, opaque=\"241b9fb347752f2\"\r\n"\ "User-Agent: X-Lite 4 release 4.0 stamp 58832\r\n"\ "Content-Length: 230\r\n\r\n"; belle_sip_request_t* request; belle_sip_message_t* message = belle_sip_message_parse(raw_message); char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); message = belle_sip_message_parse(encoded_message); request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"INVITE"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Contact")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Authorization")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Content-Type")); check_uri_and_headers(message); CU_ASSERT_PTR_NOT_NULL(belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header_by_type(message,belle_sip_header_from_t)))); CU_ASSERT_PTR_NOT_NULL(belle_sip_header_address_get_absolute_uri(BELLE_SIP_HEADER_ADDRESS(belle_sip_message_get_header_by_type(message,belle_sip_header_to_t)))); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_opaque_part(belle_sip_request_get_absolute_uri(request)),"11234567888;phone-context=vzims.fr"); belle_sip_object_unref(message); belle_sip_free(encoded_message); } static void test401Response(void) { const char* raw_message = "SIP/2.0 401 Unauthorized\r\n" "Call-ID: 577586163\r\n" "CSeq: 21 REGISTER\r\n" "From: ;tag=1790643209\r\n" "Server: Cirpack/v4.42x (gw_sip)\r\n" "To: ;tag=00-08075-24212984-22e348d97\r\n" "Via: SIP/2.0/UDP 192.168.0.18:5062;received=81.56.113.2;rport=5062;branch=z9hG4bK1939354046\r\n" "WWW-Authenticate: Digest realm=\"sip.ovh.net\",nonce=\"24212965507cde726e8bc37e04686459\",opaque=\"241b9fb347752f2\",stale=false,algorithm=MD5\r\n" "Content-Length: 0\r\n\r\n"; belle_sip_response_t* response; belle_sip_message_t* message = belle_sip_message_parse(raw_message); char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); message = belle_sip_message_parse(encoded_message); response = BELLE_SIP_RESPONSE(message); CU_ASSERT_EQUAL(belle_sip_response_get_status_code(response),401); CU_ASSERT_STRING_EQUAL(belle_sip_response_get_reason_phrase(response),"Unauthorized"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"WWW-Authenticate")); check_uri_and_headers(message); belle_sip_object_unref(message); belle_sip_free(encoded_message); } static void test401ResponseWithoutResponsePhrase(void) { const char* raw_message = "SIP/2.0 401 \r\n" "Call-ID: 577586163\r\n" "CSeq: 21 REGISTER\r\n" "From: ;tag=1790643209\r\n" "Server: Cirpack/v4.42x (gw_sip)\r\n" "To: ;tag=00-08075-24212984-22e348d97\r\n" "Via: SIP/2.0/UDP 192.168.0.18:5062;received=81.56.113.2;rport=5062;branch=z9hG4bK1939354046\r\n" "WWW-Authenticate: Digest realm=\"sip.ovh.net\",\r\n nonce=\"24212965507cde726e8bc37e04686459\",opaque=\"241b9fb347752f2\",stale=false,algorithm=MD5\r\n" "Content-Length: 0\r\n\r\n"; belle_sip_response_t* response; belle_sip_message_t* message = belle_sip_message_parse(raw_message); char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); message = belle_sip_message_parse(encoded_message); response = BELLE_SIP_RESPONSE(message); CU_ASSERT_EQUAL(belle_sip_response_get_status_code(response),401); CU_ASSERT_PTR_NULL(belle_sip_response_get_reason_phrase(response)); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"WWW-Authenticate")); check_uri_and_headers(message); belle_sip_object_unref(message); belle_sip_free(encoded_message); } static void testRegisterRaw(void) { const char* raw_message = "REGISTER sip:192.168.0.20 SIP/2.0\r\n"\ "Via: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n"\ "From: ;tag=465687829\r\n"\ "To: \r\n"\ "Call-ID: 1053183492\r\n"\ "CSeq: 1 REGISTER\r\n"\ "Contact: \r\n"\ "Max-Forwards: 70\r\n"\ "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n"\ "Expires: 3600\r\n"\ "Content-Length: 0\r\n\r\n123456789"; belle_sip_request_t* request; size_t size=0; size_t raw_message_size= strlen(raw_message); belle_sip_message_t* message = belle_sip_message_parse_raw(raw_message,raw_message_size,&size); CU_ASSERT_EQUAL(raw_message_size,size+9); request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"REGISTER"); CU_ASSERT_PTR_NOT_NULL(belle_sip_request_get_uri(request)); CU_ASSERT_STRING_EQUAL(&raw_message[size],"123456789"); belle_sip_object_unref(message); } static void testOptionMessage(void) { const char* raw_message = "REGISTER sip:192.168.0.20 SIP/2.0\r\n"\ "Via: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n"\ "From: ;tag=465687829\r\n"\ "To: \r\n"\ "Call-ID: 1053183492\r\n"\ "CSeq: 1 REGISTER\r\n"\ "Contact: \r\n"\ "Max-Forwards: 70\r\n"\ "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n"\ "Expires: 3600\r\n"\ "Content-Length: 0\r\n\r\n"; belle_sip_message_t* message = belle_sip_message_parse(raw_message); belle_sip_request_t* request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"REGISTER"); CU_ASSERT_PTR_NOT_NULL(belle_sip_request_get_uri(request)); belle_sip_object_unref(message); } static void test_extract_source(void) { const char * invite_1="INVITE sip:jehan@81.56.113.2:50343;transport=tcp;line=f18e0009dd6cc43 SIP/2.0\r\n" "Via: SIP/2.0/TCP 37.59.129.73;branch=z9hG4bK.SKvK9U327e8mU68XUv5rt144pg\r\n" "Via: SIP/2.0/UDP 192.168.1.12:15060;rport=15060;branch=z9hG4bK1596944937;received=81.56.113.2\r\n" "Record-Route: \r\n" "Record-Route: \r\n" "Max-Forwards: 70\r\n" "From: ;tag=711138653\r\n" "To: \r\n" "Call-ID: 977107319\r\n" "CSeq: 21 INVITE\r\n" "Contact: \r\n" "Subject: Phone call\r\n" "User-Agent: Linphone/3.5.2 (eXosip2/3.6.0)\r\n" "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO\r\n" "Content-Type: application/sdp\r\n"\ "Content-Length: 230\r\n\r\n"; const char * invite_2="INVITE sip:jehan@81.56.113.2:50343;transport=tcp;line=f18e0009dd6cc43 SIP/2.0\r\n" "Via: SIP/2.0/UDP 192.168.1.12:15060;rport=15060;branch=z9hG4bK1596944937;received=81.56.113.2\r\n" "Via: SIP/2.0/TCP 37.59.129.73;branch=z9hG4bK.SKvK9U327e8mU68XUv5rt144pg\r\n" "Record-Route: \r\n" "Record-Route: \r\n" "Max-Forwards: 70\r\n" "From: ;tag=711138653\r\n" "To: \r\n" "Call-ID: 977107319\r\n" "CSeq: 21 INVITE\r\n" "Contact: \r\n" "Subject: Phone call\r\n" "User-Agent: Linphone/3.5.2 (eXosip2/3.6.0)\r\n" "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO\r\n" "Content-Length: 0\r\n\r\n"; belle_sip_message_t* message = belle_sip_message_parse(invite_1); belle_sip_request_t* request = BELLE_SIP_REQUEST(message); belle_sip_uri_t* source =belle_sip_request_extract_origin(request); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Content-type")); CU_ASSERT_PTR_NOT_NULL(source); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(source),"37.59.129.73"); CU_ASSERT_EQUAL(belle_sip_uri_get_port(source),0); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_transport_param(source),"tcp"); belle_sip_object_unref(message); message = belle_sip_message_parse(invite_2); request = BELLE_SIP_REQUEST(message); source =belle_sip_request_extract_origin(request); CU_ASSERT_PTR_NOT_NULL(source); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(source),"81.56.113.2"); CU_ASSERT_EQUAL(belle_sip_uri_get_port(source),15060); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_transport_param(source),"udp"); belle_sip_object_unref(message); } static void test_sipfrag(void) { const char* raw_message = "SIP/2.0 100 Trying\r\n"; belle_sip_response_t* response; belle_sip_message_t* message = belle_sip_message_parse(raw_message); response = BELLE_SIP_RESPONSE(message); CU_ASSERT_EQUAL(belle_sip_response_get_status_code(response),100); CU_ASSERT_STRING_EQUAL(belle_sip_response_get_reason_phrase(response),"Trying"); belle_sip_object_unref(message); } /*static void test_fix_contact_with_received_rport() { }*/ static void testMalformedMessage(void) { const char * raw_message= "INVITE sip:jehan@81.56.113.2:50343;transport=tcp;line=f18e0009dd6cc43 SIP/2.0\r\n" "Via: SIP/2.0/UDP 192.168.1.12:15060;rport=15060;branch=z9hG4bK1596944937;received=81.56.113.2\r\n" "Via: SIP/2.0/TCP 37.59.129.73;branch=z9hG4bK.SKvK9U327e8mU68XUv5rt144pg\r\n" "Record-Route: \r\n" "Record-Route: \r\n" "Max-Forwards: 70\r\n" "From: ;tag=711138653\r\n" "To: \r\n" "Call-ID: 977107319\r\n" "CSeq: 21 INVITE\r\n" "Contact: ;pn-tok=/throttledthirdparty\r\n" /*Slash is not allowed for contact params*/\ "Subject: Phone call\r\n" "User-Agent: Linphone/3.5.2 (eXosip2/3.6.0)\r\n" "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO\r\n" "Content-Length: 0\r\n\r\n"; belle_sip_message_t* message = belle_sip_message_parse(raw_message); CU_ASSERT_FALSE(belle_sip_message_check_headers(message)); } static void testMalformedOptionnalHeaderInMessage(void) { const char* raw_message = "REGISTER sip:192.168.0.20 SIP/2.0\r\n"\ "Via: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n"\ "From: ;tag=465687829\r\n"\ "To: \r\n"\ "Call-ID: 1053183492\r\n"\ "CSeq: 1 REGISTER\r\n"\ "Contact: ;pn-tok=/throttledthirdparty\r\n" /*Slash is not allowed for contact params*/\ "Max-Forwards: 70\r\n"\ "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n"\ "Expires: 3600\r\n"\ "Proxy-Authorization: Digest username=\"8117396\", realm=\"Realm\", nonce=\"MTMwNDAwMjIxMjA4NzVkODY4ZmZhODMzMzU4ZDJkOTA1NzM2NTQ2NDZlNmIz"\ ", uri=\"sip:linphone.net\", response=\"eed376ff7c963441255ec66594e470e7\", algorithm=MD5, cnonce=\"0a4f113b\", qop=auth, nc=00000001\r\n"\ "Content-Length: 0\r\n\r\n"; belle_sip_request_t* request; belle_sip_message_t* message = belle_sip_message_parse(raw_message); char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); message = belle_sip_message_parse(encoded_message); request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"REGISTER"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Expires")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_EXPIRES(belle_sip_message_get_header(message,"Expires"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Proxy-Authorization")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(message,"Contact")); /*contact is optionnal in register*/ check_uri_and_headers(message); belle_sip_free(encoded_message); belle_sip_object_unref(message); } static void testMalformedMessageWithWrongStart(void) { const char * raw_message= "\r\n" "INVITE sip:jehan@81.56.113.2:50343;transport=tcp;line=f18e0009dd6cc43 SIP/2.0\r\n" "Via: SIP/2.0/UDP 192.168.1.12:15060;rport=15060;branch=z9hG4bK1596944937;received=81.56.113.2\r\n" "Via: SIP/2.0/TCP 37.59.129.73;branch=z9hG4bK.SKvK9U327e8mU68XUv5rt144pg\r\n" "Record-Route: \r\n" "Record-Route: \r\n" "Max-Forwards: 70\r\n" "From: ;tag=711138653\r\n" "To: \r\n" "Call-ID: 977107319\r\n" "CSeq: 21 INVITE\r\n" "Contact: \r\n" "Subject: Phone call\r\n" "User-Agent: Linphone/3.5.2 (eXosip2/3.6.0)\r\n" "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO\r\n" "Content-Length: 0\r\n\r\n"; belle_sip_message_t* message = belle_sip_message_parse(raw_message); CU_ASSERT_PTR_NULL(message); } #include "belle_sip_internal.h" void channel_parser_tester_recovery_from_error_base (const char* prelude,const char* raw_message) { belle_sip_stack_t* stack = belle_sip_stack_new(NULL); belle_sip_channel_t* channel = belle_sip_stream_channel_new_client(stack , NULL , 45421 , NULL , "127.0.0.1" , 45421); belle_sip_request_t* request; belle_sip_message_t* message; if (prelude) { channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,prelude); channel->input_stream.write_ptr+=strlen(prelude); belle_sip_channel_parse_stream(channel,FALSE); } channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,raw_message); channel->input_stream.write_ptr+=strlen(raw_message); belle_sip_channel_parse_stream(channel,FALSE); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages->data); message=BELLE_SIP_MESSAGE(channel->incoming_messages->data); CU_ASSERT_TRUE(BELLE_SIP_OBJECT_IS_INSTANCE_OF(message,belle_sip_request_t)); request = BELLE_SIP_REQUEST(message); CU_ASSERT_STRING_EQUAL(belle_sip_request_get_method(request),"REGISTER"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Expires")); CU_ASSERT_PTR_NOT_NULL(BELLE_SIP_HEADER_EXPIRES(belle_sip_message_get_header(message,"Expires"))); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Proxy-Authorization")); check_uri_and_headers(message); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(stack); } void channel_parser_tester_recovery_from_error () { const char * raw_message= "debut de stream tout pourri\r\n" "INVITE je_suis_une_fausse _request_uri_hihihi SIP/2.0\r\n" "Via: SIP/2.0/UDP 192.168.1.12:15060;rport=15060;branch=z9hG4bK1596944937;received=81.56.113.2\r\n" "Via: SIP/2.0/TCP 37.59.129.73;branch=z9hG4bK.SKvK9U327e8mU68XUv5rt144pg\r\n" "Record-Route: \r\n" "Record-Route: \r\n" "Max-Forwards: 70\r\n" "From: ;tag=711138653\r\n" "To: \r\n" "Call-ID: 977107319\r\n" "CSeq: 21 INVITE\r\n" "Contact: \r\n" "Subject: Phone call\r\n" "User-Agent: Linphone/3.5.2 (eXosip2/3.6.0)\r\n" "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO\r\n" "Content-Length: 0\r\n" "\r\n" "REGISTER sip:192.168.0.20 SIP/2.0\r\n"\ "Via: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n"\ "From: ;tag=465687829\r\n"\ "To: \r\n"\ "Call-ID: 1053183492\r\n"\ "CSeq: 1 REGISTER\r\n"\ "Contact: \r\n" \ "Max-Forwards: 70\r\n"\ "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n"\ "Expires: 3600\r\n"\ "Proxy-Authorization: Digest username=\"8117396\", realm=\"Realm\", nonce=\"MTMwNDAwMjIxMjA4NzVkODY4ZmZhODMzMzU4ZDJkOTA1NzM2NTQ2NDZlNmIz"\ ", uri=\"sip:linphone.net\", response=\"eed376ff7c963441255ec66594e470e7\", algorithm=MD5, cnonce=\"0a4f113b\", qop=auth, nc=00000001\r\n"\ "Content-Length: 0\r\n" "\r\n"; channel_parser_tester_recovery_from_error_base (NULL, raw_message); } void channel_parser_malformed_start () { const char * raw_message= "debut de stream tout pourri\r\n" "REGISTER sip:192.168.0.20 SIP/2.0\r\n" "Via: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n" "From: ;tag=465687829\r\n" "To: \r\n" "Call-ID: 1053183492\r\n" "CSeq: 1 REGISTER\r\n" "Contact: \r\n" "Max-Forwards: 70\r\n" "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n" "Expires: 3600\r\n" "Proxy-Authorization: Digest username=\"8117396\", realm=\"Realm\", nonce=\"MTMwNDAwMjIxMjA4NzVkODY4ZmZhODMzMzU4ZDJkOTA1NzM2NTQ2NDZlNmIz" ", uri=\"sip:linphone.net\", response=\"eed376ff7c963441255ec66594e470e7\", algorithm=MD5, cnonce=\"0a4f113b\", qop=auth, nc=00000001\r\n" "Content-Length: 0\r\n" "\r\n"; channel_parser_tester_recovery_from_error_base (NULL, raw_message); } void channel_parser_truncated_start () { const char * prelude= "R"; const char * raw_message= "EGISTER sip:192.168.0.20 SIP/2.0\r\n" "Via: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n" "From: ;tag=465687829\r\n" "To: \r\n" "Call-ID: 1053183492\r\n" "CSeq: 1 REGISTER\r\n" "Contact: \r\n" "Max-Forwards: 70\r\n" "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n" "Expires: 3600\r\n" "Proxy-Authorization: Digest username=\"8117396\", realm=\"Realm\", nonce=\"MTMwNDAwMjIxMjA4NzVkODY4ZmZhODMzMzU4ZDJkOTA1NzM2NTQ2NDZlNmIz" ", uri=\"sip:linphone.net\", response=\"eed376ff7c963441255ec66594e470e7\", algorithm=MD5, cnonce=\"0a4f113b\", qop=auth, nc=00000001\r\n" "Content-Length: 0\r\n" "\r\n"; channel_parser_tester_recovery_from_error_base (prelude, raw_message); } void channel_parser_truncated_start_with_garbage() { const char * prelude= "truc tout pourit R"; const char * raw_message= "EGISTER sip:192.168.0.20 SIP/2.0\r\n" "Via: SIP/2.0/UDP 192.168.1.8:5062;rport;branch=z9hG4bK1439638806\r\n" "From: ;tag=465687829\r\n" "To: \r\n" "Call-ID: 1053183492\r\n" "CSeq: 1 REGISTER\r\n" "Contact: \r\n" "Max-Forwards: 70\r\n" "User-Agent: Linphone/3.3.99.10 (eXosip2/3.3.0)\r\n" "Expires: 3600\r\n" "Proxy-Authorization: Digest username=\"8117396\", realm=\"Realm\", nonce=\"MTMwNDAwMjIxMjA4NzVkODY4ZmZhODMzMzU4ZDJkOTA1NzM2NTQ2NDZlNmIz" ", uri=\"sip:linphone.net\", response=\"eed376ff7c963441255ec66594e470e7\", algorithm=MD5, cnonce=\"0a4f113b\", qop=auth, nc=00000001\r\n" "Content-Length: 0\r\n" "\r\n"; channel_parser_tester_recovery_from_error_base (prelude, raw_message); } static void testMalformedFrom_process_response_cb(void *user_ctx, const belle_sip_response_event_t *event){ int status = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); belle_sip_message("testMalformedFrom_process_response_cb [%i]",status); (*(int*)user_ctx) += 1; // increment the call counter CU_ASSERT( status == 400 ); } #define LISTENING_POINT_PORT 45421 #define LISTENING_POINT_HOSTPORT "127.0.0.1:45421" /* need the same port as above */ static void testMalformedFrom(void){ belle_sip_stack_t* stack = belle_sip_stack_new(NULL); belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(stack, "127.0.0.1", LISTENING_POINT_PORT, "tcp"); belle_sip_provider_t* provider = belle_sip_provider_new(stack,lp); belle_sip_listener_callbacks_t listener_cbs = {0}; const char* raw_message = "INVITE sip:us2@172.1.1.1 SIP/2.0\r\n" "Via: SIP/2.0/TCP " LISTENING_POINT_HOSTPORT ";branch=z9hG4bK-edx-U_1zoIkaq72GJPqpSmDpJQ-ouBelFuLODzf9oS5J9MeFUA;rport\r\n" "From: c\x8e test ;tag=klsk+kwDc\r\n" /** 'cŽ test' should be enclosed in double quotes */ "To: \r\n" "Contact: \r\n" "Call-ID: 2b6fb0320-1384-179494-426025-23b6b0-2e3303331@172.16.42.1\r\n" "Content-Type: application/sdp\r\n" "Content-Length: 389\r\n" "CSeq: 1 INVITE\r\n" "Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, INFO, UPDATE, REGISTER, MESSAGE, REFER, SUBSCRIBE, PRACK\r\n" "Accept: application/sdp, application/dtmf-relay\r\n" "Max-Forwards: 69\r\n" "\r\n" "v=0\r\n" "o=- 1826 1826 IN IP4 172.16.42.1\r\n" "s=VeriCall Edge\r\n" "c=IN IP4 172.16.42.1\r\n" "t=0 0\r\n" "m=audio 20506 RTP/AVP 0 8 13 101\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:13 CN/8000\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n" "m=video 24194 RTP/AVP 105 104\r\n" "a=sendonly\r\n" "a=rtpmap:105 H264/90000\r\n" "a=fmtp:105 packetization-mode=0\r\n" "a=rtpmap:104 H263-1998/90000\r\n" "a=fmtp:104 CIF=1;J=1\r\n"; belle_sip_message_t* message = belle_sip_message_parse(raw_message); belle_sip_listener_t* listener = NULL; int called_times = 0; listener_cbs.process_response_event = testMalformedFrom_process_response_cb; listener = belle_sip_listener_create_from_callbacks(&listener_cbs, &called_times); belle_sip_provider_add_sip_listener(provider, listener); belle_sip_object_ref(message); belle_sip_object_ref(message); /* double ref: originally the message is created with 0 refcount, and dispatch_message will unref() it.*/ belle_sip_provider_dispatch_message(provider, message); // we expect the stack to send a 400 error belle_sip_stack_sleep(stack,1000); CU_ASSERT_EQUAL(called_times,1); belle_sip_provider_remove_sip_listener(provider,listener); belle_sip_object_unref(listener); belle_sip_object_unref(provider); belle_sip_object_unref(stack); belle_sip_object_unref(message); } static void testMalformedMandatoryField(void){ belle_sip_stack_t* stack = belle_sip_stack_new(NULL); belle_sip_listening_point_t* lp = belle_sip_stack_create_listening_point(stack, "127.0.0.1", LISTENING_POINT_PORT, "tcp"); belle_sip_provider_t* provider = belle_sip_provider_new(stack,lp); belle_sip_listener_callbacks_t listener_cbs = {0}; /* the MESSAGE message has no definition on which fields are required, which means we'll go into * * * */ const char* raw_message = "MESSAGE sip:lollol.iphone@22.22.222.222:5861;transport=tcp SIP/2.0\r\n" "Via: SIP/2.0/TCP " LISTENING_POINT_HOSTPORT ";branch=z9hG4bK5eca096a;rport\r\n" "Max-Forwards: 70\r\n" "From: \"MS TFT\" ;tag=as2413a381\r\n" "To: ;tag=\r\n" "Call-ID: 4070383971a9674201f463af2de1f012@11.11.111.111:5060\r\n" "CSeq: 103 MESSAGE\r\n" "User-Agent: Sip Server On Host (20130523_12h10)\r\n" "Content-Type: text/plain;charset=UTF-8\r\n" "Content-Length: 276\r\n" "\r\n" "\r\n" "\r\n" "\r\n"; belle_sip_message_t* message = belle_sip_message_parse(raw_message); belle_sip_listener_t* listener = NULL; int called_times = 0; listener_cbs.process_response_event = testMalformedFrom_process_response_cb; listener = belle_sip_listener_create_from_callbacks(&listener_cbs, &called_times); belle_sip_provider_add_sip_listener(provider, listener); belle_sip_object_ref(message); belle_sip_object_ref(message); /* double ref: originally the message is created with 0 refcount, and dispatch_message will unref() it.*/ belle_sip_provider_dispatch_message(provider, message); // we expect the stack to send a 400 error belle_sip_stack_sleep(stack,1000); CU_ASSERT_EQUAL(called_times,1); belle_sip_provider_remove_sip_listener(provider,listener); belle_sip_object_unref(listener); belle_sip_object_unref(provider); belle_sip_object_unref(stack); belle_sip_object_unref(message); } static void testRFC2543_base(char* branch) { belle_sip_server_transaction_t *tr; const char* raw_message_base = "INVITE sip:me@127.0.0.1 SIP/2.0\r\n" "Via: SIP/2.0/UDP 192.168.1.12:15060;%srport=15060;received=81.56.113.2\r\n" "Record-Route: \r\n" "Record-Route: \r\n" "Max-Forwards: 70\r\n" "From: ;tag=711138653\r\n" "To: \r\n" "Call-ID: 977107319\r\n" "CSeq: 21 INVITE\r\n" "Contact: \r\n" "Subject: Phone call\r\n" "User-Agent: Linphone/3.5.2 (eXosip2/3.6.0)\r\n" "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO\r\n" "Content-Length: 0\r\n" "Extended: \r\n" /*fixme lexer*/ "\r\n"; char raw_message[2048]; belle_sip_request_t* request; belle_sip_stack_t *stack=belle_sip_stack_new(NULL); belle_sip_provider_t *prov=belle_sip_provider_new(stack,NULL); belle_sip_message_t* message; snprintf(raw_message,sizeof(raw_message),raw_message_base,branch); message = belle_sip_message_parse(raw_message); belle_sip_object_ref(message); belle_sip_object_ref(message); /*yes double ref: originally the message is created with 0 refcount, and dispatch_message will unref() it.*/ belle_sip_provider_dispatch_message(prov,message); request = BELLE_SIP_REQUEST(message); CU_ASSERT_PTR_NOT_NULL(request); tr=belle_sip_provider_create_server_transaction(prov,request); CU_ASSERT_PTR_NOT_NULL(belle_sip_provider_find_matching_server_transaction(prov,request)); /*make sure branch id is properly set*/ CU_ASSERT_PTR_NOT_NULL(tr); belle_sip_object_unref(prov); belle_sip_object_unref(stack); belle_sip_object_unref(message); } static void testRFC2543Compat(void) { testRFC2543_base(""); } static void testRFC2543CompatWithBranch() { testRFC2543_base("branch=blablabla;"); } static void testUriHeadersInInvite(void) { belle_sip_request_t* request; belle_sip_stack_t *stack=belle_sip_stack_new(NULL); belle_sip_provider_t *prov=belle_sip_provider_new(stack,NULL); const char* raw_uri="sip:toto@titi.com" "?header1=blabla" "&header2=blue%3Bweftutu%3Dbla" "&From=toto" "&To=sip%3Atoto%40titi.com" "&Call-ID=asdads" "&CSeq=asdasd" "&Via=asdasd" "&Accept=adsad" "&Accept-Encoding=adsad" "&Accept-Language=adsad" "&Allow=adsad" "&Record-Route=adsad" "&Contact=adsad" "&Organization=adsad" "&Supported=adsad" "&User-Agent=adsad"; belle_sip_header_t* raw_header; request=belle_sip_request_create( belle_sip_uri_parse(raw_uri) ,"INVITE" ,belle_sip_provider_create_call_id(prov) ,belle_sip_header_cseq_create(20,"INVITE") ,belle_sip_header_from_create2("sip:toto@titi.com","4654") ,NULL ,belle_sip_header_via_new() ,70); CU_ASSERT_PTR_NOT_NULL(request); CU_ASSERT_PTR_NOT_NULL(raw_header=belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"header1")); if (raw_header) { CU_ASSERT_STRING_EQUAL(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(raw_header)),"blabla"); } CU_ASSERT_PTR_NOT_NULL(raw_header=belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"header2")); if (raw_header) { CU_ASSERT_STRING_EQUAL(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(raw_header)),"blue;weftutu=bla"); } CU_ASSERT_PTR_NOT_NULL(raw_header=belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"To")); if (raw_header) { CU_ASSERT_STRING_EQUAL(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(raw_header)),"sip:toto@titi.com"); } CU_ASSERT_STRING_NOT_EQUAL(belle_sip_header_get_unparsed_value(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"From")),"toto"); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"Record-Route")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"Accept")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"Accept-Encoding")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"Accept-Language")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"Allow")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"Contact")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"Organization")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"Supported")); CU_ASSERT_PTR_NULL(belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),"User-Agent")); belle_sip_object_unref(request); } static void testUrisComponentsForRequest(void) { belle_sip_request_t* request; belle_sip_stack_t *stack=belle_sip_stack_new(NULL); belle_sip_provider_t *prov=belle_sip_provider_new(stack,NULL); belle_sip_client_transaction_t* t; const char* raw_uri="sip:toto@titi.com?header1=blabla"; request=belle_sip_request_create( belle_sip_uri_parse(raw_uri) ,"INVITE" ,belle_sip_provider_create_call_id(prov) ,belle_sip_header_cseq_create(20,"INVITE") ,belle_sip_header_from_create2("sip:toto@titi.com","4654") ,belle_sip_header_to_parse("To: sip:titi@titi.com:5061") ,belle_sip_header_via_new() ,70); CU_ASSERT_PTR_NOT_NULL(request); t=belle_sip_provider_create_client_transaction(prov,request); CU_ASSERT_NOT_EQUAL(belle_sip_client_transaction_send_request(t),0); } static void testGenericMessage(void) { const char* raw_message = "SIP/2.0 180 Ringing\r\n" "Via: SIP/2.0/UDP 192.168.1.73:5060;branch=z9hG4bK.hhdJx4~kD;rport\r\n" "Record-Route: \r\n" "Record-Route: \r\n" "From: ;tag=5DuaoDRru\r\n" "To: ;tag=PelIhu0\r\n" "Call-ID: e-2Q~fxwNs\r\n" "CSeq: 21 INVITE\r\n" "user-agent: Linphone/3.6.99 (belle-sip/1.2.4)\r\n" "supported: replaces\r\n" "supported: outbound\r\n" "Content-Length: 0\r\n" "\r\n"; belle_sip_response_t* response; belle_sip_message_t* message = belle_sip_message_parse(raw_message); char* encoded_message = belle_sip_object_to_string(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); message = belle_sip_message_parse(encoded_message); response = BELLE_SIP_RESPONSE(message); CU_ASSERT_EQUAL(belle_sip_response_get_status_code(response),180); /* CU_ASSERT_STRING_EQUAL(belle_sip_response_get_reason_phrase(response),"Unauthorized"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"WWW-Authenticate")); check_uri_and_headers(message);*/ belle_sip_object_unref(message); belle_sip_free(encoded_message); } static void testHttpGet(void) { const char* raw_message = "GET /index.php HTTP/1.1\r\n" "User-Agent: Wget/1.14 (darwin11.4.2)\r\n" "Accept: */*\r\n" "Host: www.linphone.org\r\n" "Connection: Keep-Alive\r\n" "\r\n"; char* marshaled_msg; belle_sip_message_t* msg = belle_sip_message_parse(raw_message); belle_http_request_t* http_request; belle_generic_uri_t* uri; belle_sip_header_extension_t* host_header; belle_sip_object_t* tmp; CU_ASSERT_PTR_NOT_NULL_FATAL(msg); marshaled_msg=belle_sip_object_to_string(BELLE_SIP_OBJECT(msg)); belle_sip_object_unref(msg); msg = belle_sip_message_parse(marshaled_msg); belle_sip_free(marshaled_msg); tmp=belle_sip_object_clone(BELLE_SIP_OBJECT(msg)); belle_sip_object_unref(msg); msg=BELLE_SIP_MESSAGE(tmp); CU_ASSERT_TRUE(BELLE_SIP_IS_INSTANCE_OF(msg,belle_http_request_t)); http_request=BELLE_HTTP_REQUEST(msg); CU_ASSERT_PTR_NOT_NULL_FATAL(uri=belle_http_request_get_uri(http_request)); CU_ASSERT_STRING_EQUAL(belle_generic_uri_get_path(uri),"/index.php"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(msg,"User-Agent")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(msg,"Accept")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(msg,"Connection")); CU_ASSERT_PTR_NOT_NULL(host_header=BELLE_SIP_HEADER_EXTENSION(belle_sip_message_get_header(msg,"Host"))); CU_ASSERT_STRING_EQUAL(belle_sip_header_extension_get_value(host_header),"www.linphone.org"); belle_sip_object_unref(msg); } static void testHttp200Ok(void) { const char* raw_message = "HTTP/1.1 200 OK\r\n" "Date: Tue, 07 Jan 2014 09:28:43 GMT\r\n" "Server: Apache\r\n" "Last-Modified: Tue, 18 Aug 1998 20:19:11 GMT\r\n" "ETag: \"8982a60-14a17-335b3dcdcadc0\"\r\n" "Accept-Ranges: bytes\r\n" "Vary: Accept-Encoding\r\n" "Content-Encoding: gzip\r\n" "Content-Length: 6\r\n" "Keep-Alive: timeout=15, max=100\r\n" "Connection: Keep-Alive\r\n" "Content-Type: text/plain\r\n" "\r\n" "blabla"; char* marshaled_msg; belle_sip_message_t* msg = belle_sip_message_parse(raw_message); belle_http_response_t* http_response; belle_sip_header_extension_t* host_header; belle_sip_object_t* tmp; CU_ASSERT_PTR_NOT_NULL_FATAL(msg); marshaled_msg=belle_sip_object_to_string(BELLE_SIP_OBJECT(msg)); belle_sip_object_unref(msg); msg = belle_sip_message_parse(marshaled_msg); belle_sip_free(marshaled_msg); tmp=belle_sip_object_clone(BELLE_SIP_OBJECT(msg)); belle_sip_object_unref(msg); msg=BELLE_SIP_MESSAGE(tmp); CU_ASSERT_TRUE(BELLE_SIP_IS_INSTANCE_OF(msg,belle_http_response_t)); http_response=BELLE_HTTP_RESPONSE(msg); CU_ASSERT_EQUAL(belle_http_response_get_status_code(http_response),200); CU_ASSERT_STRING_EQUAL(belle_http_response_get_reason_phrase(http_response),"OK"); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(msg,"Date")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(msg,"ETag")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(msg,"Connection")); CU_ASSERT_PTR_NOT_NULL(host_header=BELLE_SIP_HEADER_EXTENSION(belle_sip_message_get_header(msg,"Server"))); CU_ASSERT_STRING_EQUAL(belle_sip_header_extension_get_value(host_header),"Apache"); belle_sip_object_unref(msg); } void channel_parser_http_response () { belle_sip_stack_t* stack = belle_sip_stack_new(NULL); belle_sip_channel_t* channel = belle_sip_stream_channel_new_client(stack , NULL , 45421 , NULL , "127.0.0.1" , 45421); const char * raw_message= "HTTP/1.1 200 OK\r\n" "Cache-Control: private\r\n" "Date: Tue, 07 Jan 2014 13:51:57 GMT\r\n" "Content-Type: text/html; charset=utf-8\r\n" "Server: Microsoft-IIS/6.0\r\n" "X-Powered-By: ASP.NET\r\n" "Content-Encoding: gzip\r\n" "Vary: Accept-Encoding\r\n" "Transfer-Encoding: chunked\r\n" "\r\n" "\r\n\r\n"; belle_http_response_t* response; belle_sip_message_t* message; channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,raw_message); channel->input_stream.write_ptr+=strlen(raw_message); belle_sip_channel_parse_stream(channel,TRUE); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages->data); message=BELLE_SIP_MESSAGE(channel->incoming_messages->data); CU_ASSERT_TRUE(BELLE_SIP_OBJECT_IS_INSTANCE_OF(message,belle_http_response_t)); response = BELLE_HTTP_RESPONSE(message); CU_ASSERT_STRING_EQUAL(belle_http_response_get_reason_phrase(response),"OK"); CU_ASSERT_EQUAL(belle_http_response_get_status_code(response),200); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Cache-Control")); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header(message,"Vary")); belle_sip_object_unref(BELLE_SIP_OBJECT(message)); belle_sip_object_unref(stack); } void testGetBody(void) { const char* raw_message = "INVITE sip:us2@172.1.1.1 SIP/2.0\r\n" "Via: SIP/2.0/TCP " LISTENING_POINT_HOSTPORT ";branch=z9hG4bK-edx-U_1zoIkaq72GJPqpSmDpJQ-ouBelFuLODzf9oS5J9MeFUA;rport\r\n" "From: test ;tag=klsk+kwDc\r\n" "To: \r\n" "Contact: \r\n" "Call-ID: 2b6fb0320-1384-179494-426025-23b6b0-2e3303331@172.16.42.1\r\n" "Content-Type: application/sdp\r\n" "Content-Length: 389\r\n" "CSeq: 1 INVITE\r\n" "Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, INFO, UPDATE, REGISTER, MESSAGE, REFER, SUBSCRIBE, PRACK\r\n" "Accept: application/sdp, application/dtmf-relay\r\n" "Max-Forwards: 69\r\n" "\r\n" "v=0\r\n" "o=- 1826 1826 IN IP4 172.16.42.1\r\n" "s=VeriCall Edge\r\n" "c=IN IP4 172.16.42.1\r\n" "t=0 0\r\n" "m=audio 20506 RTP/AVP 0 8 13 101\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:13 CN/8000\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n" "m=video 24194 RTP/AVP 105 104\r\n" "a=sendonly\r\n" "a=rtpmap:105 H264/90000\r\n" "a=fmtp:105 packetization-mode=0\r\n" "a=rtpmap:104 H263-1998/90000\r\n" "a=fmtp:104 CIF=1;J=1\r\n" "nimportequoi a la fin"; belle_sip_stack_t* stack = belle_sip_stack_new(NULL); belle_sip_channel_t* channel = belle_sip_stream_channel_new_client(stack , NULL , LISTENING_POINT_PORT , NULL , "127.0.0.1" , LISTENING_POINT_PORT); belle_sip_message_t* message; belle_sip_header_content_length_t *ctlt; channel->input_stream.write_ptr = strcpy(channel->input_stream.write_ptr,raw_message); channel->input_stream.write_ptr+=strlen(raw_message); belle_sip_channel_parse_stream(channel,FALSE); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages); CU_ASSERT_PTR_NOT_NULL(channel->incoming_messages->data); message=BELLE_SIP_MESSAGE(channel->incoming_messages->data); ctlt = belle_sip_message_get_header_by_type(message,belle_sip_header_content_length_t); CU_ASSERT_PTR_NOT_NULL(ctlt); CU_ASSERT_EQUAL(belle_sip_header_content_length_get_content_length(ctlt),strlen(belle_sip_message_get_body(message))); CU_ASSERT_EQUAL(belle_sip_header_content_length_get_content_length(ctlt),belle_sip_message_get_body_size(message)); belle_sip_object_unref(message); } /* NOTE - ORDER IS IMPORTANT - MUST TEST fread() AFTER fprintf() */ test_t message_tests[] = { { "REGISTER", testRegisterMessage }, { "INVITE", testInviteMessage }, { "INVITE with tel uri", testInviteMessageWithTelUri}, { "Option message", testOptionMessage }, { "REGISTER (Raw)", testRegisterRaw }, { "401 Response", test401Response }, { "Response without response phrase",test401ResponseWithoutResponsePhrase}, { "Origin extraction", test_extract_source }, { "SIP frag", test_sipfrag }, { "Malformed invite", testMalformedMessage }, { "Malformed from", testMalformedFrom }, { "Malformed mandatory field", testMalformedMandatoryField }, { "Malformed invite with bad begin", testMalformedMessageWithWrongStart }, { "Malformed register", testMalformedOptionnalHeaderInMessage }, { "Channel parser error recovery", channel_parser_tester_recovery_from_error}, { "Channel parser malformed start", channel_parser_malformed_start}, { "Channel parser truncated start", channel_parser_truncated_start}, { "Channel parser truncated start with garbage",channel_parser_truncated_start_with_garbage}, { "RFC2543 compatibility", testRFC2543Compat}, { "RFC2543 compatibility with branch id",testRFC2543CompatWithBranch}, { "Uri headers in sip INVITE",testUriHeadersInInvite}, { "Uris components in request",testUrisComponentsForRequest}, { "Generic message test",testGenericMessage}, { "HTTP get",testHttpGet}, { "HTTP 200 Ok",testHttp200Ok}, { "Channel parser for HTTP reponse",channel_parser_http_response}, { "Get body size",testGetBody} }; test_suite_t message_test_suite = { "Message", NULL, NULL, sizeof(message_tests) / sizeof(message_tests[0]), message_tests }; belle-sip-1.4.1/tester/belle_sip_refresher_tester.c000066400000000000000000001003151252242224000224270ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "CUnit/Basic.h" #include "belle-sip/belle-sip.h" #include "belle_sip_internal.h" #include "belle_sip_tester.h" #ifndef _MSC_VER #include #endif #define USERNAME "toto" #define SIPDOMAIN "sip.linphone.org" #define PASSWD "secret" static char publish_body[]= "\n" "\n" " \n" " \n" " open\n" " \n" " tel:+09012345678\n" " \n" "\n"; typedef enum auth_mode { none ,digest ,digest_auth }auth_mode_t; typedef struct _status { int twoHundredOk; int fourHundredOne; int refreshOk; int refreshKo; }status_t; typedef struct endpoint { belle_sip_stack_t* stack; belle_sip_listener_callbacks_t* listener_callbacks; belle_sip_provider_t* provider; belle_sip_listening_point_t *lp; belle_sip_listener_t *listener; auth_mode_t auth; status_t stat; unsigned char expire_in_contact; char nonce[32]; unsigned int nonce_count; const char* received; int rport; unsigned char unreconizable_contact; int connection_family; int register_count; int transiant_network_failure; belle_sip_refresher_t* refresher; int early_refresher; } endpoint_t; static unsigned int wait_for(belle_sip_stack_t*s1, belle_sip_stack_t*s2,int* counter,int value,int timeout) { int retry=0; #define ITER 100 while (*counterprovider,belle_sip_request_event_get_request(event)); belle_sip_request_t* req = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(server_transaction)); belle_sip_response_t* resp; belle_sip_header_contact_t* contact; belle_sip_header_expires_t* expires; belle_sip_header_authorization_t* authorization; belle_sip_header_via_t* via; const char* raw_authenticate_digest = "WWW-Authenticate: Digest " "algorithm=MD5, realm=\"" SIPDOMAIN "\", opaque=\"1bc7f9097684320\""; belle_sip_header_www_authenticate_t* www_authenticate=NULL; const char* auth_uri; const char* qop; unsigned char auth_ok=0; char local_resp[33]; belle_sip_message("caller_process_request_event received [%s] message",belle_sip_request_get_method(belle_sip_request_event_get_request(event))); switch (endpoint->auth) { case none: { auth_ok=1; break; } case digest_auth: case digest: { if ((authorization=belle_sip_message_get_header_by_type(req,belle_sip_header_authorization_t)) != NULL){ qop=belle_sip_header_authorization_get_qop(authorization); if (qop && strcmp(qop,"auth")==0) { compute_response_auth_qop( belle_sip_header_authorization_get_username(authorization) ,belle_sip_header_authorization_get_realm(authorization) ,PASSWD ,endpoint->nonce ,endpoint->nonce_count ,belle_sip_header_authorization_get_cnonce(authorization) ,belle_sip_header_authorization_get_qop(authorization) ,belle_sip_request_get_method(req) ,auth_uri=belle_sip_uri_to_string(belle_sip_header_authorization_get_uri(authorization)) ,local_resp); } else { /*digest*/ compute_response(belle_sip_header_authorization_get_username(authorization) ,belle_sip_header_authorization_get_realm(authorization) ,PASSWD ,endpoint->nonce ,belle_sip_request_get_method(req) ,auth_uri=belle_sip_uri_to_string(belle_sip_header_authorization_get_uri(authorization)) ,local_resp); } belle_sip_free((void*)auth_uri); auth_ok=strcmp(belle_sip_header_authorization_get_response(authorization),local_resp)==0; } if (auth_ok && endpoint->nonce_countauth == digest ) { sprintf(endpoint->nonce,"%p",authorization); //*change the nonce for next auth*/ } else { endpoint->nonce_count++; } } else { auth_ok=0; www_authenticate=belle_sip_header_www_authenticate_parse(raw_authenticate_digest); sprintf(endpoint->nonce,"%p",authorization); //*change the nonce for next auth*/ belle_sip_header_www_authenticate_set_nonce(www_authenticate,endpoint->nonce); if (endpoint->auth == digest_auth) { belle_sip_header_www_authenticate_add_qop(www_authenticate,"auth"); if (endpoint->nonce_count>=MAX_NC_COUNT) { belle_sip_header_www_authenticate_set_stale(www_authenticate,1); endpoint->nonce_count=1; } } } } break; default: break; } if (auth_ok) { resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),200); if (!endpoint->expire_in_contact) { belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(expires=belle_sip_message_get_header_by_type(req,belle_sip_header_expires_t))); } if (strcmp(belle_sip_request_get_method(req),"REGISTER")==0) { contact=belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); } else { contact=belle_sip_header_contact_new(); } if(endpoint->unreconizable_contact) { /*put an unexpected address*/ belle_sip_uri_set_host(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact)),"nimportequoi.com"); } belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(contact)); if (strcmp(belle_sip_request_get_method(req),"PUBLISH")==0) { belle_sip_header_t* sip_if_match=belle_sip_message_get_header(BELLE_SIP_MESSAGE(resp),"SIP-If-Match"); if (sip_if_match) { CU_ASSERT_STRING_EQUAL(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(sip_if_match)),"blablietag"); } /*check for body*/ CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))); if (belle_sip_message_get_body(BELLE_SIP_MESSAGE(req))) { CU_ASSERT_STRING_EQUAL(belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)),publish_body); } CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t)); CU_ASSERT_PTR_NOT_NULL(belle_sip_message_get_header_by_type(req,belle_sip_header_content_length_t)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),belle_sip_header_create("SIP-ETag","blablietag")); } } else { resp=belle_sip_response_create_from_request(belle_sip_request_event_get_request(event),401); if (www_authenticate) belle_sip_message_add_header(BELLE_SIP_MESSAGE(resp),BELLE_SIP_HEADER(www_authenticate)); } if (endpoint->received) { via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t); belle_sip_header_via_set_received(via,endpoint->received); } belle_sip_server_transaction_send_response(server_transaction,resp); } static void client_process_response_event(void *obj, const belle_sip_response_event_t *event){ //belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event); endpoint_t* endpoint = (endpoint_t*)obj; int status = belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)); belle_sip_message("caller_process_response_event [%i]",status); switch (status) { case 200: endpoint->stat.twoHundredOk++; if (endpoint->connection_family!=AF_UNSPEC){ const char *host; int family_found; belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type( (belle_sip_message_t*)belle_sip_response_event_get_response(event),belle_sip_header_contact_t); CU_ASSERT_PTR_NOT_NULL_FATAL(ct); host=belle_sip_uri_get_host(belle_sip_header_address_get_uri((belle_sip_header_address_t*)ct)); if (strchr(host,':')) family_found=AF_INET6; else family_found=AF_INET; CU_ASSERT_TRUE(family_found==endpoint->connection_family); } break; case 401:endpoint->stat.fourHundredOne++; break; default: break; } } //static void process_timeout(void *obj, const belle_sip_timeout_event_t *event){ // belle_sip_message("process_timeout"); //} //static void process_transaction_terminated(void *obj, const belle_sip_transaction_terminated_event_t *event){ // belle_sip_message("process_transaction_terminated"); //} static void client_process_auth_requested(void *obj, belle_sip_auth_event_t *event){ BELLESIP_UNUSED(obj); belle_sip_message("process_auth_requested requested for [%s@%s]" ,belle_sip_auth_event_get_username(event) ,belle_sip_auth_event_get_realm(event)); belle_sip_auth_event_set_passwd(event,PASSWD); } static void belle_sip_refresher_listener (belle_sip_refresher_t* refresher ,void* user_pointer ,unsigned int status_code ,const char* reason_phrase) { endpoint_t* endpoint = (endpoint_t*)user_pointer; BELLESIP_UNUSED(refresher); belle_sip_message("belle_sip_refresher_listener [%i] reason [%s]",status_code,reason_phrase); switch (status_code) { case 200:endpoint->stat.refreshOk++; break; default: endpoint->stat.refreshKo++; break; } if (endpoint->stat.refreshKo==1 && endpoint->transiant_network_failure) { belle_sip_stack_set_send_error(endpoint->stack,0); } else if (endpoint->stat.refreshOk==1 && endpoint->transiant_network_failure) { /*generate a network failure*/ belle_sip_refresher_set_retry_after(endpoint->refresher,100); belle_sip_stack_set_send_error(endpoint->stack,-1); } } static endpoint_t* create_endpoint(const char *ip, int port,const char* transport,belle_sip_listener_callbacks_t* listener_callbacks) { endpoint_t* endpoint = belle_sip_new0(endpoint_t); endpoint->stack=belle_sip_stack_new(NULL); endpoint->listener_callbacks=listener_callbacks; endpoint->lp=belle_sip_stack_create_listening_point(endpoint->stack,ip,port,transport); endpoint->connection_family=AF_INET; if (endpoint->lp) belle_sip_object_ref(endpoint->lp); endpoint->provider=belle_sip_stack_create_provider(endpoint->stack,endpoint->lp); belle_sip_provider_add_sip_listener(endpoint->provider,(endpoint->listener=belle_sip_listener_create_from_callbacks(endpoint->listener_callbacks,endpoint))); sprintf(endpoint->nonce,"%p",endpoint); /*initial nonce*/ endpoint->nonce_count=1; endpoint->register_count=3; return endpoint; } static void destroy_endpoint(endpoint_t* endpoint) { belle_sip_object_unref(endpoint->lp); belle_sip_object_unref(endpoint->provider); belle_sip_object_unref(endpoint->stack); belle_sip_object_unref(endpoint->listener); belle_sip_free(endpoint); } static endpoint_t* create_udp_endpoint(int port,belle_sip_listener_callbacks_t* listener_callbacks) { endpoint_t *endpoint=create_endpoint("0.0.0.0",port,"udp",listener_callbacks); CU_ASSERT_PTR_NOT_NULL_FATAL(endpoint->lp); return endpoint; } static void refresher_base_with_body(endpoint_t* client ,endpoint_t *server , const char* method , belle_sip_header_content_type_t* content_type ,const char* body) { belle_sip_request_t* req; belle_sip_client_transaction_t* trans; belle_sip_header_route_t* destination_route; belle_sip_refresher_t* refresher; const char* identity = "sip:" USERNAME "@" SIPDOMAIN ; const char* domain="sip:" SIPDOMAIN ; belle_sip_header_contact_t* contact=belle_sip_header_contact_new(); belle_sip_uri_t *dest_uri; uint64_t begin; uint64_t end; if (client->expire_in_contact) belle_sip_header_contact_set_expires(contact,1); dest_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_listening_point_get_uri(server->lp)); if (client->connection_family==AF_INET6) belle_sip_uri_set_host(dest_uri,"::1"); else belle_sip_uri_set_host(dest_uri,"127.0.0.1"); destination_route=belle_sip_header_route_create(belle_sip_header_address_create(NULL,dest_uri)); req=belle_sip_request_create( belle_sip_uri_parse(domain), method, belle_sip_provider_create_call_id(client->provider), belle_sip_header_cseq_create(20,method), belle_sip_header_from_create2(identity,BELLE_SIP_RANDOM_TAG), belle_sip_header_to_create2(identity,NULL), belle_sip_header_via_new(), 70); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact)); if (!client->expire_in_contact) belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(1))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(destination_route)); if (content_type && body) { size_t body_lenth=strlen(body); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(content_type)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(body_lenth))); belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),body,body_lenth); } trans=belle_sip_provider_create_client_transaction(client->provider,req); belle_sip_object_ref(trans);/*to avoid trans from being deleted before refresher can use it*/ belle_sip_client_transaction_send_request(trans); if (client->early_refresher) { client->refresher= refresher = belle_sip_client_transaction_create_refresher(trans); } else { if (server->auth == none) { CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000)); } else { CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredOne,1,1000)); /*update cseq*/ req=belle_sip_client_transaction_create_authenticated_request(trans,NULL,NULL); belle_sip_object_unref(trans); trans=belle_sip_provider_create_client_transaction(client->provider,req); belle_sip_object_ref(trans); belle_sip_client_transaction_send_request(trans); CU_ASSERT_TRUE_FATAL(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000)); } client->refresher= refresher = belle_sip_client_transaction_create_refresher(trans); } CU_ASSERT_TRUE_FATAL(refresher!=NULL); belle_sip_object_unref(trans); belle_sip_refresher_set_listener(refresher,belle_sip_refresher_listener,client); begin = belle_sip_time_ms(); CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,client->register_count+(client->early_refresher?1:0),client->register_count*1000 + 1000)); end = belle_sip_time_ms(); CU_ASSERT_TRUE(end-begin>=client->register_count*1000*.9); /*because refresh is at 90% of expire*/ CU_ASSERT_TRUE(end-begin<(client->register_count*1000 + 2000)); /*unregister twice to make sure refresh operation can be safely cascaded*/ belle_sip_refresher_refresh(refresher,0); belle_sip_refresher_refresh(refresher,0); CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,client->register_count+1,1000)); CU_ASSERT_EQUAL(client->stat.refreshOk,client->register_count+1); belle_sip_refresher_stop(refresher); belle_sip_object_unref(refresher); } static void refresher_base(endpoint_t* client,endpoint_t *server, const char* method) { refresher_base_with_body(client,server,method,NULL,NULL); } static void register_base(endpoint_t* client,endpoint_t *server) { refresher_base(client,server,"REGISTER"); } static void refresher_base_with_param_and_body(const char* method , unsigned char expire_in_contact , auth_mode_t auth_mode , int early_refresher , belle_sip_header_content_type_t* content_type ,const char* body){ belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; endpoint_t* client,*server; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_udp_endpoint(3452,&client_callbacks); server = create_udp_endpoint(6788,&server_callbacks); server->expire_in_contact=client->expire_in_contact=expire_in_contact; server->auth=auth_mode; client->early_refresher=early_refresher; refresher_base_with_body(client,server,method,content_type,body); destroy_endpoint(client); destroy_endpoint(server); } static void refresher_base_with_param(const char* method, unsigned char expire_in_contact,auth_mode_t auth_mode) { refresher_base_with_param_and_body(method,expire_in_contact,auth_mode,FALSE,NULL,NULL); } static void register_test_with_param(unsigned char expire_in_contact,auth_mode_t auth_mode) { refresher_base_with_param("REGISTER",expire_in_contact,auth_mode); } static void subscribe_test(void) { belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; belle_sip_request_t* req; belle_sip_client_transaction_t* trans; belle_sip_header_route_t* destination_route; const char* identity = "sip:" USERNAME "@" SIPDOMAIN ; const char* domain="sip:" SIPDOMAIN ; endpoint_t* client,*server; belle_sip_uri_t *dest_uri; belle_sip_refresher_t* refresher; belle_sip_header_contact_t* contact=belle_sip_header_contact_new(); uint64_t begin; uint64_t end; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_udp_endpoint(3452,&client_callbacks); server = create_udp_endpoint(6788,&server_callbacks); server->expire_in_contact=0; server->auth=digest_auth; dest_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_listening_point_get_uri(server->lp)); belle_sip_uri_set_host(dest_uri,"127.0.0.1"); destination_route=belle_sip_header_route_create(belle_sip_header_address_create(NULL,dest_uri)); req=belle_sip_request_create( belle_sip_uri_parse(domain), "SUBSCRIBE", belle_sip_provider_create_call_id(client->provider), belle_sip_header_cseq_create(20,"SUBSCRIBE"), belle_sip_header_from_create2(identity,BELLE_SIP_RANDOM_TAG), belle_sip_header_to_create2(identity,NULL), belle_sip_header_via_new(), 70); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(1))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_create("Event","Presence"))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(destination_route)); trans=belle_sip_provider_create_client_transaction(client->provider,req); belle_sip_object_ref(trans);/*to avoid trans from being deleted before refresher can use it*/ belle_sip_client_transaction_send_request(trans); CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredOne,1,1000)); req=belle_sip_client_transaction_create_authenticated_request(trans,NULL,NULL); belle_sip_object_unref(trans); trans=belle_sip_provider_create_client_transaction(client->provider,req); belle_sip_object_ref(trans); belle_sip_client_transaction_send_request(trans); CU_ASSERT_TRUE_FATAL(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000)); /*maybe dialog should be automatically created*/ CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(trans))) refresher = belle_sip_client_transaction_create_refresher(trans); belle_sip_object_unref(trans); belle_sip_refresher_set_listener(refresher,belle_sip_refresher_listener,client); begin = belle_sip_time_ms(); CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,3,4000)); end = belle_sip_time_ms(); CU_ASSERT_TRUE(end-begin>=3000); CU_ASSERT_TRUE(end-begin<5000); /*unsubscribe twice to make sure refresh operation can be safely cascaded*/ belle_sip_refresher_refresh(refresher,0); belle_sip_refresher_refresh(refresher,0); belle_sip_refresher_stop(refresher); belle_sip_object_unref(refresher); destroy_endpoint(client); destroy_endpoint(server); } static void register_expires_header(void) { register_test_with_param(0,none); } static void register_expires_in_contact(void) { register_test_with_param(1,none); } static void register_expires_header_digest(void) { register_test_with_param(0,digest); } static void register_expires_in_contact_header_digest_auth(void) { register_test_with_param(1,digest_auth); } static void register_with_failure(void) { belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; endpoint_t* client,*server; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_udp_endpoint(3452,&client_callbacks); server = create_udp_endpoint(6788,&server_callbacks); server->expire_in_contact=1; server->auth=digest; client->transiant_network_failure=1; register_base(client,server); CU_ASSERT_EQUAL(client->stat.refreshKo,1); destroy_endpoint(client); destroy_endpoint(server); } static void register_with_unrecognizable_contact(void) { belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; endpoint_t* client,*server; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_udp_endpoint(3452,&client_callbacks); server = create_udp_endpoint(6788,&server_callbacks); server->expire_in_contact=1; server->unreconizable_contact=1; server->auth=digest; register_base(client,server); destroy_endpoint(client); destroy_endpoint(server); } static void register_early_refresher(void) { belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; endpoint_t* client,*server; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_udp_endpoint(3452,&client_callbacks); server = create_udp_endpoint(6788,&server_callbacks); server->expire_in_contact=1; server->auth=digest; client->early_refresher=1; register_base(client,server); destroy_endpoint(client); destroy_endpoint(server); } static int register_test_with_interfaces(const char *transport, const char *client_ip, const char *server_ip, int connection_family) { int ret=0; belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; endpoint_t* client,*server; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_endpoint(client_ip,3452,transport,&client_callbacks); client->connection_family=connection_family; client->register_count=1; server = create_endpoint(server_ip,6788,transport,&server_callbacks); server->expire_in_contact=client->expire_in_contact=0; server->auth=none; if (client->lp==NULL || server->lp==NULL){ belle_sip_warning("Cannot check ipv6 because host has no ipv6 support."); ret=-1; }else register_base(client,server); destroy_endpoint(client); destroy_endpoint(server); return ret; } static int register_test_with_random_port(const char *transport, const char *client_ip, const char *server_ip, int connection_family) { int ret=0; belle_sip_listener_callbacks_t client_callbacks; belle_sip_listener_callbacks_t server_callbacks; endpoint_t* client,*server; memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t)); client_callbacks.process_response_event=client_process_response_event; client_callbacks.process_auth_requested=client_process_auth_requested; server_callbacks.process_request_event=server_process_request_event; client = create_endpoint(client_ip,-1,transport,&client_callbacks); client->connection_family=connection_family; client->register_count=1; server = create_endpoint(server_ip,6788,transport,&server_callbacks); server->expire_in_contact=client->expire_in_contact=0; server->auth=none; if (client->lp==NULL || server->lp==NULL){ belle_sip_warning("Cannot check ipv6 because host has no ipv6 support."); ret=-1; }else register_base(client,server); destroy_endpoint(client); destroy_endpoint(server); return ret; } static void register_test_ipv6_to_ipv4(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("udp","::0","0.0.0.0",AF_INET); } static void register_test_ipv4_to_ipv6(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("udp","0.0.0.0","::0",AF_INET); } static void register_test_ipv6_to_ipv6_with_ipv4(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("udp","::0","::0",AF_INET); } static void register_test_ipv6_to_ipv6_with_ipv6(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("udp","::0","::0",AF_INET6); } static void register_tcp_test_ipv6_to_ipv4(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("tcp","::0","0.0.0.0",AF_INET); } static void register_tcp_test_ipv4_to_ipv6(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("tcp","0.0.0.0","::0",AF_INET); } static void register_tcp_test_ipv6_to_ipv6_with_ipv4(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("tcp","::0","::0",AF_INET); } static void register_tcp_test_ipv6_to_ipv6_with_ipv6(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_interfaces("tcp","::0","::0",AF_INET6); } static void register_udp_test_ipv4_random_port(void){ register_test_with_random_port("udp","0.0.0.0","0.0.0.0",AF_INET); } static void register_udp_test_ipv6_random_port(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_random_port("udp","::0","0.0.0.0",AF_INET); } static void register_tcp_test_ipv4_random_port(void){ register_test_with_random_port("tcp","0.0.0.0","0.0.0.0",AF_INET); } static void register_tcp_test_ipv6_random_port(void){ if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } register_test_with_random_port("tcp","::0","0.0.0.0",AF_INET); } static void simple_publish() { belle_sip_header_content_type_t* content_type=belle_sip_header_content_type_create("application","pidf+xml"); refresher_base_with_param_and_body("PUBLISH",FALSE,TRUE,FALSE, content_type,publish_body); } static void simple_publish_with_early_refresher() { belle_sip_header_content_type_t* content_type=belle_sip_header_content_type_create("application","pidf+xml"); refresher_base_with_param_and_body("PUBLISH",FALSE,TRUE,TRUE, content_type,publish_body); } test_t refresher_tests[] = { { "REGISTER Expires header", register_expires_header }, { "REGISTER Expires in Contact", register_expires_in_contact }, { "REGISTER Expires header digest", register_expires_header_digest }, { "REGISTER Expires in Contact digest auth", register_expires_in_contact_header_digest_auth }, { "REGISTER with failure", register_with_failure }, { "REGISTER with early refresher",register_early_refresher}, { "SUBSCRIBE", subscribe_test }, { "PUBLISH", simple_publish }, { "PUBLISH with early refresher", simple_publish_with_early_refresher }, { "REGISTER with unrecognizable Contact", register_with_unrecognizable_contact }, { "REGISTER UDP from ipv6 to ipv4", register_test_ipv6_to_ipv4 }, { "REGISTER UDP from ipv4 to ipv6", register_test_ipv4_to_ipv6 }, { "REGISTER UDP from ipv6 to ipv6 with ipv4", register_test_ipv6_to_ipv6_with_ipv4 }, { "REGISTER UDP from ipv6 to ipv6 with ipv6", register_test_ipv6_to_ipv6_with_ipv6 }, { "REGISTER TCP from ipv6 to ipv4", register_tcp_test_ipv6_to_ipv4 }, { "REGISTER TCP from ipv4 to ipv6", register_tcp_test_ipv4_to_ipv6 }, { "REGISTER TCP from ipv6 to ipv6 with ipv4", register_tcp_test_ipv6_to_ipv6_with_ipv4 }, { "REGISTER TCP from ipv6 to ipv6 with ipv6", register_tcp_test_ipv6_to_ipv6_with_ipv6 }, { "REGISTER UDP from random port using AF_INET", register_udp_test_ipv4_random_port }, { "REGISTER UDP from random port using AF_INET6", register_udp_test_ipv6_random_port }, { "REGISTER TCP from random port using AF_INET", register_tcp_test_ipv4_random_port }, { "REGISTER TCP from random port using AF_INET6", register_tcp_test_ipv6_random_port }, }; test_suite_t refresher_test_suite = { "Refresher", NULL, NULL, sizeof(refresher_tests) / sizeof(refresher_tests[0]), refresher_tests }; belle-sip-1.4.1/tester/belle_sip_register_tester.c000066400000000000000000000741531252242224000223000ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "CUnit/Basic.h" #include "belle-sip/belle-sip.h" #include "belle_sip_internal.h" #include "belle_sip_tester.h" #include "register_tester.h" const char *test_domain="sip2.linphone.org"; const char *auth_domain="sip.linphone.org"; const char *client_auth_domain="client.example.org"; const char *client_auth_outbound_proxy="sips:sip2.linphone.org:5063"; const char *no_server_running_here="sip:test.linphone.org:3;transport=tcp"; const char *no_response_here="sip:78.220.48.77:3;transport=%s"; const char *test_domain_tls_to_tcp="sip:sip2.linphone.org:5060;transport=tls"; static int is_register_ok; static int number_of_challenge; static int using_transaction; static int io_error_count=0; belle_sip_stack_t * stack; belle_sip_provider_t *prov; static belle_sip_listener_t* l; belle_sip_request_t* authorized_request; belle_sip_listener_callbacks_t listener_callbacks; belle_sip_listener_t *listener; static void process_dialog_terminated(void *user_ctx, const belle_sip_dialog_terminated_event_t *event){ BELLESIP_UNUSED(user_ctx); BELLESIP_UNUSED(event); belle_sip_message("process_dialog_terminated called"); } static void process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ BELLESIP_UNUSED(user_ctx); BELLESIP_UNUSED(event); belle_sip_message("process_io_error, exiting main loop"); belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); io_error_count++; /*CU_ASSERT(CU_FALSE);*/ } static void process_request_event(void *user_ctx, const belle_sip_request_event_t *event){ BELLESIP_UNUSED(user_ctx); BELLESIP_UNUSED(event); belle_sip_message("process_request_event"); } static void process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ int status; belle_sip_request_t* request; BELLESIP_UNUSED(user_ctx); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_response(event)); belle_sip_message("process_response_event [%i] [%s]" ,status=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)) ,belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event))); if (status==401){ belle_sip_header_cseq_t* cseq; belle_sip_client_transaction_t *t; belle_sip_uri_t *dest; // CU_ASSERT_NOT_EQUAL_FATAL(number_of_challenge,2); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_client_transaction(event)); /*require transaction mode*/ dest=belle_sip_client_transaction_get_route(belle_sip_response_event_get_client_transaction(event)); request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(belle_sip_response_event_get_client_transaction(event))); cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_CSEQ); belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION); belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION); CU_ASSERT_TRUE_FATAL(belle_sip_provider_add_authorization(prov,request,belle_sip_response_event_get_response(event),NULL,NULL,auth_domain)); t=belle_sip_provider_create_client_transaction(prov,request); belle_sip_client_transaction_send_request_to(t,dest); number_of_challenge++; authorized_request=request; belle_sip_object_ref(authorized_request); } else { CU_ASSERT_EQUAL(status,200); is_register_ok=1; using_transaction=belle_sip_response_event_get_client_transaction(event)!=NULL; belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } } static void process_timeout(void *user_ctx, const belle_sip_timeout_event_t *event){ BELLESIP_UNUSED(user_ctx); BELLESIP_UNUSED(event); belle_sip_message("process_timeout"); } static void process_transaction_terminated(void *user_ctx, const belle_sip_transaction_terminated_event_t *event){ BELLESIP_UNUSED(user_ctx); BELLESIP_UNUSED(event); belle_sip_message("process_transaction_terminated"); } const char* belle_sip_tester_client_cert = /*for URI:sip:tester@client.example.org*/ "-----BEGIN CERTIFICATE-----\n" "MIIDYzCCAsygAwIBAgIBCDANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx\n" "EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK\n" "DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV\n" "BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA\n" "YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTMxMDAzMTQ0MTEwWhcN\n" "MjMxMDAxMTQ0MTEwWjCBtTELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTER\n" "MA8GA1UEBwwIR3Jlbm9ibGUxIjAgBgNVBAoMGUJlbGxlZG9ubmUgQ29tbXVuaWNh\n" "dGlvbnMxDDAKBgNVBAsMA0xBQjEUMBIGA1UEAwwLY2xpZW50IGNlcnQxOjA4Bgkq\n" "hkiG9w0BCQEWK2plaGFuLm1vbm5pZXJAYmVsbGVkb25uZS1jb21tdW5pY2F0aW9u\n" "cy5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALZxC/qBi/zB/4lgI7V7\n" "I5TsmMmOp0+R/TCyVnYvKQuaJXh9i+CobVM7wj/pQg8RgsY1x+4mVwH1QbhOdIN0\n" "ExYHKgLTPlo9FaN6oHPOcHxU/wt552aZhCHC+ushwUUyjy8+T09UOP+xK9V7y5uD\n" "ZY+vIOvi6QNwc5cqyy8TREwNAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4\n" "QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTL\n" "eWEg7jewRbQbKXSdBvsyygGIFzAfBgNVHSMEGDAWgBQGX13HFq9i+C1ucQOIoNYd\n" "KwR/ujANBgkqhkiG9w0BAQUFAAOBgQBTbEoi94pVfevbK22Oj8PJFsuy+el1pJG+\n" "h0XGM9SQGfbcS7PsV/MhFXtmpnmj3vQB3u5QtMGtWcLA2uxXi79i82gw+oEpBKHR\n" "sLqsNCzWNCL9n1pjpNSdqqBFGUdB9pSpnYalujAbuzkqq1ZLyzsElvK7pCaLQcSs\n" "oEncRDdPOA==\n" "-----END CERTIFICATE-----"; /* fingerprint of certificate generated using openssl x509 -fingerprint */ const char* belle_sip_tester_client_cert_fingerprint = "SHA-1 79:2F:9E:8B:28:CC:38:53:90:1D:71:DC:8F:70:66:75:E5:34:CE:C4"; const char* belle_sip_tester_private_key = "-----BEGIN ENCRYPTED PRIVATE KEY-----\n" "MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIbEHnQwhgRwoCAggA\n" "MBQGCCqGSIb3DQMHBAgmrtCEBCP9kASCAoCq9EKInROalaBSLWY44U4RVAC+CKdx\n" "Q8ooT7Bz/grgZuCiaGf0UKINJeV4LYHoP+AWjCH8EeebIA8dldNy5rGcBTt7sXd1\n" "QOGmnkBplXTW/NTsb9maYRK56kNJhLE4DR5X5keziV1Tdy2KBmTlpllsCXWsSOBq\n" "iI63PTaakIvZxA0TEmie5QQWpH777e/LmW3vVHdH8hhp2zeDDjfSW2E290+ce4Yj\n" "SDW9oFXvauzhzhSYRkUdfoJSbpu5MYwyzhjAXQpmBJDauu7+jAU/rQw6TLmYjDNZ\n" "3PYHzyD4N7tCG9u4mPBo33dhUirP+8E1BftHB+i/VIn6pI3ypMyiFZ1ZCHqi4vhW\n" "z7aChRrUY/8XWCpln3azcfj4SW+Mz62sAChY8rn+yyxFgIno8d9rrx67jyAnYJ6Q\n" "sfIMwKp3Sz5oI7IDk8If5SuBVkpqlRV+eZFT6zRRFk65beYpq70BN2mYaKzSV8A7\n" "rnciho/dfa9wvyWmkqXciBgWh18UTACOM9HPLmQef3FGaUDLiTAGS1osyypGUEPt\n" "Ox3u51qpYkibwyQZo1+ujQkh9PiKfevIAXmty0nTFWMEED15G2SJKjunw5N1rEAh\n" "M9jlYpLnATcfigPfGo19QrIPQ1c0LB4BqdwAWN3ZLe0QqYdgwzdcwIoLQRp9iDcw\n" "Omc31+38cTc2yGQ2Y2XHZkL8GY/rkqkbhVt9Rnh+VJxFeB6FlsL66EycApe07ngx\n" "QimGP57yp4aBzpJyW+6GPf8A/Ogsv3ay1QBLUiGEJtUglRHnl9F6nm5Nxm7wubVx\n" "WEuSefVM4xgB+mfQauAJu2N9yKhzXOytslZflpa06qJedlLYFk9njvcv\n" "-----END ENCRYPTED PRIVATE KEY-----\n"; const char* belle_sip_tester_private_key_passwd="secret"; static void process_auth_requested(void *user_ctx, belle_sip_auth_event_t *event){ BELLESIP_UNUSED(user_ctx); if (belle_sip_auth_event_get_mode(event) == BELLE_SIP_AUTH_MODE_HTTP_DIGEST) { const char *username = belle_sip_auth_event_get_username(event); const char *realm = belle_sip_auth_event_get_realm(event); belle_sip_message("process_auth_requested requested for [%s@%s]" ,username?username:"" ,realm?realm:""); belle_sip_auth_event_set_passwd(event,"secret"); } else if (belle_sip_auth_event_get_mode(event) == BELLE_SIP_AUTH_MODE_TLS) { const char *distinguished_name = NULL; belle_sip_certificates_chain_t* cert = belle_sip_certificates_chain_parse(belle_sip_tester_client_cert,strlen(belle_sip_tester_client_cert),BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM); belle_sip_signing_key_t* key = belle_sip_signing_key_parse(belle_sip_tester_private_key,strlen(belle_sip_tester_private_key),belle_sip_tester_private_key_passwd); belle_sip_auth_event_set_client_certificates_chain(event,cert); belle_sip_auth_event_set_signing_key(event,key); distinguished_name = belle_sip_auth_event_get_distinguished_name(event); belle_sip_message("process_auth_requested requested for DN[%s]",distinguished_name?distinguished_name:""); } else { belle_sip_error("Unexpected auth mode"); } } int register_init(void) { belle_sip_listening_point_t *lp; stack=belle_sip_stack_new(NULL); lp=belle_sip_stack_create_listening_point(stack,"0.0.0.0",7060,"UDP"); prov=belle_sip_stack_create_provider(stack,lp); lp=belle_sip_stack_create_listening_point(stack,"0.0.0.0",7060,"TCP"); belle_sip_provider_add_listening_point(prov,lp); lp=belle_sip_stack_create_listening_point(stack,"0.0.0.0",7061,"TLS"); if (lp) { /* since test.linphone.org does not have proper certificates, don't verify anything*/ belle_sip_tls_listening_point_set_verify_exceptions(BELLE_SIP_TLS_LISTENING_POINT(lp),BELLE_SIP_TLS_LISTENING_POINT_BADCERT_ANY_REASON); if (belle_sip_tester_get_root_ca_path() != NULL) { belle_sip_tls_listening_point_set_root_ca(BELLE_SIP_TLS_LISTENING_POINT(lp), belle_sip_tester_get_root_ca_path()); } belle_sip_provider_add_listening_point(prov,lp); } listener_callbacks.process_dialog_terminated=process_dialog_terminated; listener_callbacks.process_io_error=process_io_error; listener_callbacks.process_request_event=process_request_event; listener_callbacks.process_response_event=process_response_event; listener_callbacks.process_timeout=process_timeout; listener_callbacks.process_transaction_terminated=process_transaction_terminated; listener_callbacks.process_auth_requested=process_auth_requested; listener_callbacks.listener_destroyed=NULL; listener=belle_sip_listener_create_from_callbacks(&listener_callbacks,NULL); return 0; } int register_uninit(void) { belle_sip_object_unref(prov); belle_sip_object_unref(stack); belle_sip_object_unref(listener); return 0; } void unregister_user(belle_sip_stack_t * stack ,belle_sip_provider_t *prov ,belle_sip_request_t* initial_request ,int use_transaction) { belle_sip_request_t *req; belle_sip_header_cseq_t* cseq; belle_sip_header_expires_t* expires_header; int i; belle_sip_provider_add_sip_listener(prov,l); is_register_ok=0; using_transaction=0; req=(belle_sip_request_t*)belle_sip_object_clone((belle_sip_object_t*)initial_request); belle_sip_object_ref(req); cseq=(belle_sip_header_cseq_t*)belle_sip_message_get_header((belle_sip_message_t*)req,BELLE_SIP_CSEQ); belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+2); /*+2 if initial reg was challenged*/ expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_EXPIRES); belle_sip_header_expires_set_expires(expires_header,0); if (use_transaction){ belle_sip_client_transaction_t *t; belle_sip_provider_add_authorization(prov,req,NULL,NULL,NULL,NULL); /*just in case*/ t=belle_sip_provider_create_client_transaction(prov,req); belle_sip_client_transaction_send_request(t); }else belle_sip_provider_send_request(prov,req); for(i=0;!is_register_ok && i<20 ;i++) { belle_sip_stack_sleep(stack,500); if (!use_transaction && !is_register_ok) { belle_sip_object_ref(req); belle_sip_provider_send_request(prov,req); /*manage retransmitions*/ } } CU_ASSERT_EQUAL(is_register_ok,1); CU_ASSERT_EQUAL(using_transaction,use_transaction); belle_sip_object_unref(req); belle_sip_provider_remove_sip_listener(prov,l); } belle_sip_request_t* try_register_user_at_domain(belle_sip_stack_t * stack ,belle_sip_provider_t *prov ,const char *transport ,int use_transaction ,const char* username ,const char* domain ,const char* outbound_proxy ,int success_expected) { belle_sip_request_t *req,*copy; char identity[256]; char uri[256]; int i; char *outbound=NULL; number_of_challenge=0; if (transport) snprintf(uri,sizeof(uri),"sip:%s;transport=%s",domain,transport); else snprintf(uri,sizeof(uri),"sip:%s",domain); if (transport && strcasecmp("tls",transport)==0 && belle_sip_provider_get_listening_point(prov,"tls")==NULL){ belle_sip_error("No TLS support, test skipped."); return NULL; } if (outbound_proxy){ if (strstr(outbound_proxy,"sip:")==NULL && strstr(outbound_proxy,"sips:")==NULL){ outbound=belle_sip_strdup_printf("sip:%s",outbound_proxy); }else outbound=belle_sip_strdup(outbound_proxy); } snprintf(identity,sizeof(identity),"Tester ",username,domain); req=belle_sip_request_create( belle_sip_uri_parse(uri), "REGISTER", belle_sip_provider_create_call_id(prov), belle_sip_header_cseq_create(20,"REGISTER"), belle_sip_header_from_create2(identity,BELLE_SIP_RANDOM_TAG), belle_sip_header_to_create2(identity,NULL), belle_sip_header_via_new(), 70); belle_sip_object_ref(req); is_register_ok=0; io_error_count=0; using_transaction=0; belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_contact_new())); copy=(belle_sip_request_t*)belle_sip_object_ref(belle_sip_object_clone((belle_sip_object_t*)req)); belle_sip_provider_add_sip_listener(prov,l=BELLE_SIP_LISTENER(listener)); if (use_transaction){ belle_sip_client_transaction_t *t=belle_sip_provider_create_client_transaction(prov,req); belle_sip_client_transaction_send_request_to(t,outbound?belle_sip_uri_parse(outbound):NULL); }else belle_sip_provider_send_request(prov,req); for(i=0;!is_register_ok && i<20 && io_error_count==0;i++) { belle_sip_stack_sleep(stack,500); if (!use_transaction && !is_register_ok) { belle_sip_object_ref(req); belle_sip_provider_send_request(prov,req); /*manage retransmitions*/ } } CU_ASSERT_EQUAL(is_register_ok,success_expected); if (success_expected) CU_ASSERT_EQUAL(using_transaction,use_transaction); belle_sip_object_unref(req); belle_sip_provider_remove_sip_listener(prov,l); if (outbound) belle_sip_free(outbound); return copy; } belle_sip_request_t* register_user_at_domain(belle_sip_stack_t * stack ,belle_sip_provider_t *prov ,const char *transport ,int use_transaction ,const char* username ,const char* domain ,const char* outbound) { return try_register_user_at_domain(stack,prov,transport,use_transaction,username,domain,outbound,1); } belle_sip_request_t* register_user(belle_sip_stack_t * stack ,belle_sip_provider_t *prov ,const char *transport ,int use_transaction ,const char* username ,const char* outbound) { return register_user_at_domain(stack,prov,transport,use_transaction,username,test_domain,outbound); } static void register_with_outbound(const char *transport, int use_transaction,const char* outbound ) { belle_sip_request_t *req; req=register_user(stack, prov, transport,use_transaction,"tester",outbound); if (req) { unregister_user(stack,prov,req,use_transaction); belle_sip_object_unref(req); } } static void register_test(const char *transport, int use_transaction) { register_with_outbound(transport,use_transaction,NULL); } static void stateless_register_udp(void){ register_test(NULL,0); } static void stateless_register_tls(void){ register_test("tls",0); } static void stateless_register_tcp(void){ register_test("tcp",0); } static void stateful_register_udp(void){ register_test(NULL,1); } static void stateful_register_udp_with_keep_alive(void) { belle_sip_listening_point_set_keep_alive(belle_sip_provider_get_listening_point(prov,"udp"),200); register_test(NULL,1); belle_sip_main_loop_sleep(belle_sip_stack_get_main_loop(stack),500); belle_sip_listening_point_set_keep_alive(belle_sip_provider_get_listening_point(prov,"udp"),-1); } static void stateful_register_udp_with_outbound_proxy(void){ register_with_outbound("udp",1,test_domain); } static void stateful_register_udp_delayed(void){ belle_sip_stack_set_tx_delay(stack,3000); register_test(NULL,1); belle_sip_stack_set_tx_delay(stack,0); } static void stateful_register_udp_with_send_error(void){ belle_sip_request_t *req; belle_sip_stack_set_send_error(stack,-1); req=try_register_user_at_domain(stack, prov, NULL,1,"tester",test_domain,NULL,0); belle_sip_stack_set_send_error(stack,0); if (req) belle_sip_object_unref(req); } static void stateful_register_tcp(void){ register_test("tcp",1); } static void stateful_register_tls(void){ register_test("tls",1); } static void bad_req_process_io_error(void *user_ctx, const belle_sip_io_error_event_t *event){ BELLESIP_UNUSED(user_ctx); BELLESIP_UNUSED(event); belle_sip_message("bad_req_process_io_error not implemented yet"); } static void bad_req_process_response_event(void *user_ctx, const belle_sip_response_event_t *event){ int *bad_request_response_received=(int*)user_ctx; belle_sip_response_t *resp=belle_sip_response_event_get_response(event); CU_ASSERT_TRUE(resp && belle_sip_response_get_status_code(resp)==400); *bad_request_response_received=1; belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } static void test_bad_request(void) { belle_sip_request_t *req; belle_sip_listener_t *bad_req_listener; belle_sip_client_transaction_t *t; belle_sip_header_address_t* route_address=belle_sip_header_address_create(NULL,belle_sip_uri_create(NULL,test_domain)); belle_sip_header_route_t* route; belle_sip_header_to_t* to = belle_sip_header_to_create2("sip:toto@titi.com",NULL); belle_sip_listener_callbacks_t cbs; belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(prov,"TCP"); int bad_request_response_received=0; memset(&cbs,0,sizeof(cbs)); cbs.process_io_error=bad_req_process_io_error; cbs.process_response_event=bad_req_process_response_event; bad_req_listener = belle_sip_listener_create_from_callbacks(&cbs,&bad_request_response_received); req=belle_sip_request_create( BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(belle_sip_header_address_get_uri(route_address)))), "REGISTER", belle_sip_provider_create_call_id(prov), belle_sip_header_cseq_create(20,"REGISTER"), belle_sip_header_from_create2("sip:toto@titi.com",BELLE_SIP_RANDOM_TAG), to, belle_sip_header_via_new(), 70); belle_sip_uri_set_transport_param(belle_sip_header_address_get_uri(route_address),"tcp"); route = belle_sip_header_route_create(route_address); belle_sip_header_set_name(BELLE_SIP_HEADER(to),"BrokenHeader"); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(600))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route)); belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_contact_new())); belle_sip_provider_add_sip_listener(prov,bad_req_listener); t=belle_sip_provider_create_client_transaction(prov,req); belle_sip_client_transaction_send_request(t); belle_sip_stack_sleep(stack,3000); CU_ASSERT_TRUE(bad_request_response_received==1); belle_sip_provider_remove_sip_listener(prov,bad_req_listener); belle_sip_object_unref(bad_req_listener); belle_sip_listening_point_clean_channels(lp); } static void test_register_authenticate(void) { belle_sip_request_t *reg; number_of_challenge=0; authorized_request=NULL; reg=register_user_at_domain(stack, prov, "udp",1,"bellesip",auth_domain,NULL); if (authorized_request) { unregister_user(stack,prov,authorized_request,1); belle_sip_object_unref(authorized_request); } belle_sip_object_unref(reg); } static void test_register_channel_inactive(void){ belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(prov,"TCP"); CU_ASSERT_PTR_NOT_NULL_FATAL(lp); belle_sip_stack_set_inactive_transport_timeout(stack,5); belle_sip_listening_point_clean_channels(lp); CU_ASSERT_EQUAL(belle_sip_listening_point_get_channel_count(lp),0); register_test("tcp",1); CU_ASSERT_EQUAL(belle_sip_listening_point_get_channel_count(lp),1); belle_sip_stack_sleep(stack,5000); CU_ASSERT_EQUAL(belle_sip_listening_point_get_channel_count(lp),0); belle_sip_stack_set_inactive_transport_timeout(stack,3600); } static void test_register_client_authenticated(void) { belle_sip_request_t *reg; authorized_request=NULL; /*we don't care to check sercer cert*/ belle_sip_tls_listening_point_set_verify_exceptions( (belle_sip_tls_listening_point_t*)belle_sip_provider_get_listening_point(prov,"tls") ,BELLE_SIP_TLS_LISTENING_POINT_BADCERT_ANY_REASON); reg=register_user_at_domain(stack, prov, "tls",1,"tester",client_auth_domain,client_auth_outbound_proxy); if (authorized_request) { unregister_user(stack,prov,authorized_request,1); belle_sip_object_unref(authorized_request); } if (reg) belle_sip_object_unref(reg); } static void test_connection_failure(void){ belle_sip_request_t *req; io_error_count=0; req=try_register_user_at_domain(stack, prov, "TCP",1,"tester","sip.linphone.org",no_server_running_here,0); CU_ASSERT_TRUE(io_error_count>=1); if (req) belle_sip_object_unref(req); } static void test_connection_too_long(const char *transport){ belle_sip_request_t *req; int orig=belle_sip_stack_get_transport_timeout(stack); char *no_response_here_with_transport = belle_sip_strdup_printf(no_response_here, transport); io_error_count=0; belle_sip_stack_set_transport_timeout(stack,2000); req=try_register_user_at_domain(stack, prov, transport,1,"tester","sip.linphone.org",no_response_here_with_transport,0); CU_ASSERT_TRUE(io_error_count>=1); belle_sip_stack_set_transport_timeout(stack,orig); belle_sip_free(no_response_here_with_transport); if (req) belle_sip_object_unref(req); } static void test_connection_too_long_tcp(void){ test_connection_too_long("tcp"); } static void test_connection_too_long_tls(void){ test_connection_too_long("tls"); } static void test_tls_to_tcp(void){ belle_sip_request_t *req; int orig=belle_sip_stack_get_transport_timeout(stack); io_error_count=0; belle_sip_stack_set_transport_timeout(stack,2000); req=try_register_user_at_domain(stack, prov, "TLS",1,"tester",test_domain,test_domain_tls_to_tcp,0); if (req){ CU_ASSERT_TRUE(io_error_count>=1); belle_sip_object_unref(req); } belle_sip_stack_set_transport_timeout(stack,orig); } static void register_dns_srv_tcp(void){ belle_sip_request_t *req; io_error_count=0; req=try_register_user_at_domain(stack, prov, "TCP",1,"tester",client_auth_domain,"sip:linphone.net;transport=tcp",1); CU_ASSERT_TRUE(io_error_count==0); if (req) belle_sip_object_unref(req); } static void register_dns_srv_tls(void){ belle_sip_request_t *req; io_error_count=0; req=try_register_user_at_domain(stack, prov, "TLS",1,"tester",client_auth_domain,"sip:linphone.net;transport=tls",1); CU_ASSERT_TRUE(io_error_count==0); if (req) belle_sip_object_unref(req); } static void register_dns_load_balancing(void) { belle_sip_request_t *req; io_error_count = 0; req = try_register_user_at_domain(stack, prov, "TCP", 1, "tester", client_auth_domain, "sip:belle-sip.net;transport=tcp", 1); CU_ASSERT_TRUE(io_error_count == 0); if (req) belle_sip_object_unref(req); } static void process_message_response_event(void *user_ctx, const belle_sip_response_event_t *event){ int status; BELLESIP_UNUSED(user_ctx); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_response_event_get_response(event)); belle_sip_message("process_response_event [%i] [%s]" ,status=belle_sip_response_get_status_code(belle_sip_response_event_get_response(event)) ,belle_sip_response_get_reason_phrase(belle_sip_response_event_get_response(event))); if (status >= 200){ is_register_ok=status; belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } } static belle_sip_request_t* send_message(belle_sip_request_t *initial_request, const char* realm){ int i; int io_error_count=0; belle_sip_request_t *message_request=NULL; belle_sip_request_t *clone_request=NULL; // belle_sip_header_authorization_t * h=NULL; is_register_ok = 0; message_request=belle_sip_request_create( belle_sip_uri_parse("sip:sip.linphone.org;transport=tcp") ,"MESSAGE" ,belle_sip_provider_create_call_id(prov) ,belle_sip_header_cseq_create(22,"MESSAGE") ,belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(initial_request), belle_sip_header_from_t) ,belle_sip_header_to_parse("To: sip:marie@sip.linphone.org") ,belle_sip_header_via_new() ,70); belle_sip_message_add_header(BELLE_SIP_MESSAGE(message_request),BELLE_SIP_HEADER(belle_sip_header_expires_create(600))); belle_sip_message_add_header(BELLE_SIP_MESSAGE(message_request),BELLE_SIP_HEADER(belle_sip_header_contact_new())); belle_sip_provider_add_authorization(prov,message_request,NULL,NULL,NULL,realm); // h = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(message_request), belle_sip_header_authorization_t); /*if a matching authorization was found, use it as a proxy authorization*/ // if (h != NULL){ // belle_sip_header_set_name(BELLE_SIP_HEADER(h), BELLE_SIP_PROXY_AUTHORIZATION); // } clone_request = (belle_sip_request_t*)belle_sip_object_ref(belle_sip_object_clone((belle_sip_object_t*)message_request)); belle_sip_client_transaction_send_request_to(belle_sip_provider_create_client_transaction(prov,message_request),NULL); for(i=0; i<2 && io_error_count==0 &&is_register_ok==0;i++) belle_sip_stack_sleep(stack,5000); return clone_request; } static void reuse_nonce(void) { belle_sip_request_t *register_request; int initial_auth_context_count=belle_sip_list_size(prov->auth_contexts); register_request=register_user_at_domain(stack, prov, "tcp",1,"marie","sip.linphone.org",NULL); if (register_request) { char * first_nonce_used; belle_sip_header_authorization_t * h = NULL; belle_sip_request_t *message_request; listener_callbacks.process_dialog_terminated=process_dialog_terminated; listener_callbacks.process_io_error=process_io_error; listener_callbacks.process_request_event=process_request_event; listener_callbacks.process_response_event=process_message_response_event; listener_callbacks.process_timeout=process_timeout; listener_callbacks.process_transaction_terminated=process_transaction_terminated; listener_callbacks.process_auth_requested=process_auth_requested; listener_callbacks.listener_destroyed=NULL; listener=belle_sip_listener_create_from_callbacks(&listener_callbacks,NULL); belle_sip_provider_add_sip_listener(prov,BELLE_SIP_LISTENER(listener)); /*currently only one nonce should have been used (the one for the REGISTER)*/ CU_ASSERT_EQUAL(belle_sip_list_size(prov->auth_contexts), initial_auth_context_count+1); /*this should reuse previous nonce*/ message_request=send_message(register_request, auth_domain); CU_ASSERT_EQUAL(is_register_ok, 404); h = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type( BELLE_SIP_MESSAGE(message_request), belle_sip_header_proxy_authorization_t )); CU_ASSERT_PTR_NOT_NULL_FATAL(h); CU_ASSERT_EQUAL(2, belle_sip_header_authorization_get_nonce_count(h)); first_nonce_used = belle_sip_strdup(belle_sip_header_authorization_get_nonce(h)); belle_sip_object_unref(message_request); /*new nonce should be created when not using outbound proxy realm*/ message_request=send_message(register_request, NULL); CU_ASSERT_EQUAL(is_register_ok, 407); h = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type( BELLE_SIP_MESSAGE(message_request), belle_sip_header_proxy_authorization_t )); CU_ASSERT_PTR_NULL_FATAL(h); belle_sip_object_unref(message_request); /*new nonce should be created here too*/ message_request=send_message(register_request, "wrongrealm"); CU_ASSERT_EQUAL(is_register_ok, 407); h = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type( BELLE_SIP_MESSAGE(message_request), belle_sip_header_proxy_authorization_t )); CU_ASSERT_PTR_NULL_FATAL(h); belle_sip_object_unref(message_request); /*first nonce created should be reused*/ message_request=send_message(register_request, auth_domain); CU_ASSERT_EQUAL(is_register_ok, 404); h = BELLE_SIP_HEADER_AUTHORIZATION(belle_sip_message_get_header_by_type( BELLE_SIP_MESSAGE(message_request), belle_sip_header_proxy_authorization_t )); CU_ASSERT_PTR_NOT_NULL_FATAL(h); CU_ASSERT_EQUAL(3, belle_sip_header_authorization_get_nonce_count(h)); belle_sip_object_unref(message_request); belle_sip_provider_remove_sip_listener(prov,BELLE_SIP_LISTENER(listener)); unregister_user(stack,prov,register_request,1); belle_sip_object_unref(register_request); belle_sip_free(first_nonce_used); } } test_t register_tests[] = { { "Stateful UDP", stateful_register_udp }, { "Stateful UDP with keep-alive", stateful_register_udp_with_keep_alive }, { "Stateful UDP with network delay", stateful_register_udp_delayed }, { "Stateful UDP with send error", stateful_register_udp_with_send_error }, { "Stateful UDP with outbound proxy", stateful_register_udp_with_outbound_proxy }, { "Stateful TCP", stateful_register_tcp }, { "Stateful TLS", stateful_register_tls }, { "Stateless UDP", stateless_register_udp }, { "Stateless TCP", stateless_register_tcp }, { "Stateless TLS", stateless_register_tls }, { "Bad TCP request", test_bad_request }, { "Authenticate", test_register_authenticate }, { "TLS client cert authentication", test_register_client_authenticated }, { "Channel inactive", test_register_channel_inactive }, { "TCP connection failure", test_connection_failure }, { "TCP connection too long", test_connection_too_long_tcp }, { "TLS connection too long", test_connection_too_long_tls }, { "TLS connection to TCP server", test_tls_to_tcp }, { "Register with DNS SRV failover TCP", register_dns_srv_tcp }, { "Register with DNS SRV failover TLS", register_dns_srv_tls }, { "Register with DNS load-balancing", register_dns_load_balancing }, { "Nonce reutilization", reuse_nonce } }; test_suite_t register_test_suite = { "REGISTER", register_init, register_uninit, sizeof(register_tests) / sizeof(register_tests[0]), register_tests }; belle-sip-1.4.1/tester/belle_sip_resolver_tester.c000066400000000000000000000473131252242224000223130ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010-2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "CUnit/Basic.h" #include "belle-sip/belle-sip.h" #include "belle_sip_internal.h" #include "belle_sip_tester.h" #define IPV4_SIP_DOMAIN "sip.linphone.org" #define IPV4_SIP_IP "91.121.209.194" #define IPV4_CNAME "stun.linphone.org" #define IPV4_CNAME_IP "37.59.51.72" #define IPV4_SIP_BAD_DOMAIN "dummy.linphone.org" #define IPV4_MULTIRES_DOMAIN "yahoo.fr" /* sip2.linphone.org has an IPv6 and an IPv4 IP*/ #define IPV6_SIP_DOMAIN "sip2.linphone.org" #define IPV6_SIP_IP "2001:41d0:2:14b0::1" #define IPV6_SIP_IPV4 "88.191.250.2" #define SRV_DOMAIN "linphone.org" #define SIP_PORT 5060 #if __QNX__ #define WRITE_FILE_PATH "./tmp/" #else #define WRITE_FILE_PATH #endif typedef struct endpoint { belle_sip_stack_t* stack; belle_sip_resolver_context_t *resolver_ctx; int resolve_done; int resolve_ko; struct addrinfo *ai_list; belle_sip_list_t *srv_list; /**< List of struct dns_srv pointers */ } endpoint_t; static unsigned int wait_for(belle_sip_stack_t *stack, int *current_value, int expected_value, int timeout) { #define ITER 100 uint64_t begin, end; begin = belle_sip_time_ms(); end = begin + timeout; while ((*current_value != expected_value) && (belle_sip_time_ms() < end)) { if (stack) belle_sip_stack_sleep(stack, ITER); } if (*current_value != expected_value) return FALSE; else return TRUE; } static endpoint_t* create_endpoint() { endpoint_t* endpoint; endpoint = belle_sip_new0(endpoint_t); endpoint->stack = belle_sip_stack_new(NULL); return endpoint; } static void reset_endpoint(endpoint_t *endpoint) { endpoint->resolver_ctx = 0; endpoint->resolve_done = 0; endpoint->resolve_ko = 0; if (endpoint->ai_list != NULL) { belle_sip_freeaddrinfo(endpoint->ai_list); endpoint->ai_list = NULL; } if (endpoint->srv_list != NULL) { belle_sip_list_free_with_data(endpoint->srv_list, belle_sip_object_unref); endpoint->srv_list = NULL; } } static void destroy_endpoint(endpoint_t *endpoint) { reset_endpoint(endpoint); belle_sip_object_unref(endpoint->stack); belle_sip_free(endpoint); belle_sip_uninit_sockets(); } static void a_resolve_done(void *data, const char *name, struct addrinfo *ai_list) { endpoint_t *client = (endpoint_t *)data; BELLESIP_UNUSED(name); client->resolve_done = 1; if (ai_list) { client->ai_list = ai_list; client->resolve_done = 1; } else client->resolve_ko = 1; } static void srv_resolve_done(void *data, const char *name, belle_sip_list_t *srv_list) { endpoint_t *client = (endpoint_t *)data; BELLESIP_UNUSED(name); client->resolve_done = 1; if (srv_list) { client->srv_list = srv_list; client->resolve_done = 1; } else client->resolve_ko = 1; } /* Successful IPv4 A query */ static void ipv4_a_query(void) { struct addrinfo *ai; int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET, IPV4_SIP_IP, SIP_PORT); if (ai) { CU_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); belle_sip_freeaddrinfo(ai); } } destroy_endpoint(client); } /* Successful IPv4 A query to a CNAME*/ /*This tests the recursion of dns.c*/ static void ipv4_cname_a_query(void) { struct addrinfo *ai; int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_CNAME, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET, IPV4_CNAME_IP, SIP_PORT); if (ai) { CU_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); belle_sip_freeaddrinfo(ai); } } destroy_endpoint(client); } static void local_query(void) { int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, "localhost", SIP_PORT, AF_INET, a_resolve_done, client); // A DNS query is needed on Windows platform #ifdef WIN32 CU_ASSERT_PTR_NOT_EQUAL(client->resolver_ctx, NULL); #else CU_ASSERT_PTR_EQUAL(client->resolver_ctx, NULL); #endif CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); } destroy_endpoint(client); } /* Successful IPv4 A query with no result */ static void ipv4_a_query_no_result(void) { int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_BAD_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_EQUAL(client->ai_list, NULL); destroy_endpoint(client); } /* IPv4 A query send failure */ static void ipv4_a_query_send_failure(void) { endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); belle_sip_stack_set_resolver_send_error(client->stack, -1); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_EQUAL(client->resolver_ctx, NULL); belle_sip_stack_set_resolver_send_error(client->stack, 0); destroy_endpoint(client); } /* IPv4 A query timeout */ static void ipv4_a_query_timeout(void) { endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); belle_sip_stack_set_dns_timeout(client->stack, 0); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, "toto.com", SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 2000)); CU_ASSERT_PTR_EQUAL(client->ai_list, NULL); CU_ASSERT_EQUAL(client->resolve_ko,1); destroy_endpoint(client); } /* Successful IPv4 A query with multiple results */ static void ipv4_a_query_multiple_results(void) { int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_MULTIRES_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { CU_ASSERT_PTR_NOT_NULL(client->ai_list->ai_next); } destroy_endpoint(client); } static void ipv4_a_query_with_v4mapped_results(void) { int timeout; endpoint_t *client; if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET6, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_NULL(client->ai_list); destroy_endpoint(client); } /* Successful IPv6 AAAA query */ static void ipv6_aaaa_query(void) { struct addrinfo *ai; int timeout; endpoint_t *client; if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV6_SIP_DOMAIN, SIP_PORT, AF_INET6, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct addrinfo *next; struct sockaddr_in6 *sock_in6 = (struct sockaddr_in6 *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in6->sin6_port), SIP_PORT); /*the IPv6 address shall return first, and must be a real ipv6 address*/ CU_ASSERT_TRUE(client->ai_list->ai_family==AF_INET6); CU_ASSERT_FALSE(IN6_IS_ADDR_V4MAPPED(&sock_in6->sin6_addr)); ai = belle_sip_ip_address_to_addrinfo(AF_INET6, IPV6_SIP_IP, SIP_PORT); CU_ASSERT_PTR_NOT_NULL(ai); if (ai) { struct in6_addr *ipv6_address = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; int i; for (i = 0; i < 8; i++) { CU_ASSERT_EQUAL(sock_in6->sin6_addr.s6_addr[i], ipv6_address->s6_addr[i]); } belle_sip_freeaddrinfo(ai); } next=client->ai_list->ai_next; CU_ASSERT_PTR_NOT_NULL(next); if (next){ sock_in6 = (struct sockaddr_in6 *)next->ai_addr; CU_ASSERT_TRUE(next->ai_family==AF_INET6); CU_ASSERT_TRUE(IN6_IS_ADDR_V4MAPPED(&sock_in6->sin6_addr)); CU_ASSERT_EQUAL(ntohs(sock_in6->sin6_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET6, IPV6_SIP_IPV4, SIP_PORT); CU_ASSERT_PTR_NOT_NULL(ai); if (ai) { struct in6_addr *ipv6_address = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; int i; for (i = 0; i < 8; i++) { CU_ASSERT_EQUAL(sock_in6->sin6_addr.s6_addr[i], ipv6_address->s6_addr[i]); } belle_sip_freeaddrinfo(ai); } } } destroy_endpoint(client); } /* Successful SRV query */ static void srv_query(void) { int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve_srv(client->stack, "udp", SRV_DOMAIN, srv_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->srv_list, NULL); CU_ASSERT_NOT_EQUAL(belle_sip_list_size(client->srv_list), 0); if (client->srv_list && (belle_sip_list_size(client->srv_list) > 0)) { belle_sip_dns_srv_t *result_srv = belle_sip_list_nth_data(client->srv_list, 0); CU_ASSERT_EQUAL(belle_sip_dns_srv_get_port(result_srv), SIP_PORT); } destroy_endpoint(client); } /* Successful SRV + A or AAAA queries */ static void srv_a_query(void) { int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve(client->stack, "udp", SRV_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); destroy_endpoint(client); } /* Successful SRV query with no result + A query */ static void srv_a_query_no_srv_result(void) { struct addrinfo *ai; int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve(client->stack, "udp", IPV4_CNAME, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET, IPV4_CNAME_IP, SIP_PORT); if (ai) { CU_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); belle_sip_freeaddrinfo(ai); } } destroy_endpoint(client); } static void local_full_query(void) { int timeout; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); client->resolver_ctx = belle_sip_stack_resolve(client->stack, "tcp", "localhost", SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_PTR_NOT_NULL(client->resolver_ctx); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); } destroy_endpoint(client); } /* No query needed because already resolved */ static void no_query_needed(void) { struct addrinfo *ai; endpoint_t *client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); client->resolver_ctx = belle_sip_stack_resolve(client->stack, "udp", IPV4_SIP_IP, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(client->resolve_done); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET, IPV4_SIP_IP, SIP_PORT); if (ai) { CU_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); belle_sip_freeaddrinfo(ai); } } destroy_endpoint(client); } static void set_custom_resolv_conf(belle_sip_stack_t *stack, const char *ns[3]){ FILE *f=fopen(WRITE_FILE_PATH "tmp_resolv.conf","w"); CU_ASSERT_PTR_NOT_NULL(f); if (f){ int i; for (i=0; i<3; ++i){ if (ns[i]!=NULL){ fprintf(f,"nameserver %s\n",ns[i]); }else break; } fclose(f); } belle_sip_stack_set_dns_resolv_conf_file(stack,WRITE_FILE_PATH "tmp_resolv.conf"); } static void dns_fallback(void) { struct addrinfo *ai; int timeout; endpoint_t *client = create_endpoint(); const char *nameservers[]={ "94.23.19.176", /*linphone.org ; this is not a name server, it will not respond*/ "8.8.8.8", /* public nameserver, should work*/ NULL }; CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); set_custom_resolv_conf(client->stack,nameservers); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET, IPV4_SIP_IP, SIP_PORT); if (ai) { CU_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); belle_sip_freeaddrinfo(ai); } } destroy_endpoint(client); } static void ipv6_dns_server(void) { struct addrinfo *ai; int timeout; endpoint_t *client; const char *nameservers[]={ "2001:4860:4860::8888", NULL }; if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); set_custom_resolv_conf(client->stack,nameservers); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET, IPV4_SIP_IP, SIP_PORT); if (ai) { CU_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); belle_sip_freeaddrinfo(ai); } } destroy_endpoint(client); } static void ipv4_and_ipv6_dns_server(void) { struct addrinfo *ai; int timeout; endpoint_t *client; const char *nameservers[]={ "8.8.8.8", "2a01:e00::2", NULL }; if (!belle_sip_tester_ipv6_available()){ belle_sip_warning("Test skipped, IPv6 connectivity not available."); return; } client = create_endpoint(); CU_ASSERT_PTR_NOT_NULL_FATAL(client); timeout = belle_sip_stack_get_dns_timeout(client->stack); set_custom_resolv_conf(client->stack,nameservers); client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client); CU_ASSERT_NOT_EQUAL(client->resolver_ctx, NULL); CU_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout)); CU_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL); if (client->ai_list) { struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr; CU_ASSERT_EQUAL(ntohs(sock_in->sin_port), SIP_PORT); ai = belle_sip_ip_address_to_addrinfo(AF_INET, IPV4_SIP_IP, SIP_PORT); if (ai) { CU_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); belle_sip_freeaddrinfo(ai); } } destroy_endpoint(client); } test_t resolver_tests[] = { { "A query (IPv4)", ipv4_a_query }, { "A query (IPv4) with CNAME", ipv4_cname_a_query }, { "A query (IPv4) with no result", ipv4_a_query_no_result }, { "A query (IPv4) with send failure", ipv4_a_query_send_failure }, { "A query (IPv4) with timeout", ipv4_a_query_timeout }, { "A query (IPv4) with multiple results", ipv4_a_query_multiple_results }, { "A query (IPv4) with AI_V4MAPPED results", ipv4_a_query_with_v4mapped_results }, { "Local query", local_query }, { "AAAA query (IPv6)", ipv6_aaaa_query }, { "SRV query", srv_query }, { "SRV + A query", srv_a_query }, { "SRV + A query with no SRV result", srv_a_query_no_srv_result }, { "Local SRV+A query", local_full_query }, { "No query needed", no_query_needed }, { "DNS fallback", dns_fallback }, { "IPv6 DNS server", ipv6_dns_server }, { "IPv4 and v6 DNS servers", ipv4_and_ipv6_dns_server } }; test_suite_t resolver_test_suite = { "Resolver", NULL, NULL, sizeof(resolver_tests) / sizeof(resolver_tests[0]), resolver_tests }; belle-sip-1.4.1/tester/belle_sip_tester.c000066400000000000000000000123631252242224000203670ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "belle_sip_tester.h" #include #include #include "CUnit/Basic.h" #include "CUnit/MyMem.h" #include "CUnit/Automated.h" #ifdef HAVE_CU_CURSES #include "CUnit/CUCurses.h" #endif #include #include "port.h" extern const char *test_domain; extern const char *auth_domain; static const char *belle_sip_tester_root_ca_path = NULL; static FILE * log_file = NULL; static belle_sip_object_pool_t *pool; static int _belle_sip_tester_ipv6_available(void){ struct addrinfo *ai=belle_sip_ip_address_to_addrinfo(AF_INET6,"2a01:e00::2",53); if (ai){ struct sockaddr_storage ss; struct addrinfo src; socklen_t slen=sizeof(ss); char localip[128]; int port=0; belle_sip_get_src_addr_for(ai->ai_addr,ai->ai_addrlen,(struct sockaddr*) &ss,&slen,4444); src.ai_addr=(struct sockaddr*) &ss; src.ai_addrlen=slen; belle_sip_addrinfo_to_ip(&src,localip, sizeof(localip),&port); belle_sip_freeaddrinfo(ai); return strcmp(localip,"::1")!=0; } return FALSE; } static int ipv6_available=0; int belle_sip_tester_ipv6_available(void){ return ipv6_available; } const char * belle_sip_tester_get_root_ca_path(void) { return belle_sip_tester_root_ca_path; } void belle_sip_tester_set_root_ca_path(const char *root_ca_path) { belle_sip_tester_root_ca_path = root_ca_path; } static void log_handler(int lev, const char *fmt, va_list args) { #ifdef WIN32 /* We must use stdio to avoid log formatting (for autocompletion etc.) */ vfprintf(lev == BELLE_SIP_LOG_ERROR ? stderr : stdout, fmt, args); fprintf(lev == BELLE_SIP_LOG_ERROR ? stderr : stdout, "\n"); #else va_list cap; va_copy(cap,args); vfprintf(lev == BELLE_SIP_LOG_ERROR ? stderr : stdout, fmt, cap); fprintf(lev == BELLE_SIP_LOG_ERROR ? stderr : stdout, "\n"); va_end(cap); #endif if (log_file){ belle_sip_logv(lev, fmt, args); } } void belle_sip_tester_init() { bc_tester_init(log_handler, BELLE_SIP_LOG_MESSAGE, BELLE_SIP_LOG_ERROR); belle_sip_init_sockets(); belle_sip_object_enable_marshal_check(TRUE); ipv6_available=_belle_sip_tester_ipv6_available(); bc_tester_add_suite(&cast_test_suite); bc_tester_add_suite(&sip_uri_test_suite); bc_tester_add_suite(&generic_uri_test_suite); bc_tester_add_suite(&headers_test_suite); bc_tester_add_suite(&core_test_suite); bc_tester_add_suite(&sdp_test_suite); bc_tester_add_suite(&resolver_test_suite); bc_tester_add_suite(&message_test_suite); bc_tester_add_suite(&authentication_helper_test_suite); bc_tester_add_suite(®ister_test_suite); bc_tester_add_suite(&dialog_test_suite); bc_tester_add_suite(&refresher_test_suite); bc_tester_add_suite(&http_test_suite); } void belle_sip_tester_uninit(void) { belle_sip_object_unref(pool); belle_sip_uninit_sockets(); bc_tester_uninit(); } static const char* belle_sip_helper = "\t\t\t--verbose\n" "\t\t\t--silent\n" "\t\t\t--log-file \n" "\t\t\t--domain \n" "\t\t\t--auth-domain \n" "\t\t\t--root-ca \n"; #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) int main (int argc, char *argv[]) { int i; int ret; const char *root_ca_path = NULL; const char *env_domain=getenv("TEST_DOMAIN"); belle_sip_tester_init(); if (env_domain) { test_domain=env_domain; } for(i=1;i0) { i += ret - 1; continue; } else if (ret<0) { bc_tester_helper(argv[0], belle_sip_helper); } return ret; } } belle_sip_tester_set_root_ca_path(root_ca_path); pool=belle_sip_object_pool_push(); ret = bc_tester_start(); belle_sip_tester_uninit(); return ret; } #endif belle-sip-1.4.1/tester/belle_sip_tester.h000066400000000000000000000034661252242224000204000ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010-2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef _BELLE_SIP_TESTER_H #define _BELLE_SIP_TESTER_H #include "bc_tester_utils.h" #ifdef __cplusplus extern "C" { #endif extern test_suite_t cast_test_suite; extern test_suite_t generic_uri_test_suite; extern test_suite_t sip_uri_test_suite; extern test_suite_t headers_test_suite; extern test_suite_t core_test_suite; extern test_suite_t sdp_test_suite; extern test_suite_t resolver_test_suite; extern test_suite_t message_test_suite; extern test_suite_t authentication_helper_test_suite; extern test_suite_t register_test_suite; extern test_suite_t dialog_test_suite; extern test_suite_t refresher_test_suite; extern test_suite_t http_test_suite; extern int belle_sip_tester_ipv6_available(void); extern const char * belle_sip_tester_get_root_ca_path(void); extern void belle_sip_tester_set_root_ca_path(const char *root_ca_path); extern const char* belle_sip_tester_client_cert; extern const char* belle_sip_tester_client_cert_fingerprint; extern const char* belle_sip_tester_private_key; extern const char* belle_sip_tester_private_key_passwd; #ifdef __cplusplus }; #endif #endif /* _BELLE_SIP_TESTER_H */ belle-sip-1.4.1/tester/belle_sip_uri_tester.c000066400000000000000000000457751252242224000212630ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "belle-sip/belle-sip.h" #include "belle_sip_tester.h" #include "belle_sip_internal.h" #include #include "CUnit/Basic.h" static void testSIMPLEURI(void) { belle_sip_uri_t* L_tmp; belle_sip_uri_t* L_uri = belle_sip_uri_parse("sip:sip.titi.com"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_tmp = belle_sip_uri_parse(l_raw_uri); L_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_uri); CU_ASSERT_PTR_NULL(belle_sip_uri_get_user(L_uri)); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "sip.titi.com"); CU_ASSERT_PTR_NULL(belle_sip_uri_get_transport_param(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void testCOMPLEXURI(void) { belle_sip_uri_t* L_tmp; belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:toto@titi.com:5060;transport=tcp"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_tmp = belle_sip_uri_parse(l_raw_uri); L_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri), "toto"); CU_ASSERT_EQUAL(belle_sip_uri_get_port(L_uri), 5060); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "titi.com"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_transport_param(L_uri), "tcp"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void testIPV6URI_base(const char* ip6) { belle_sip_uri_t* L_tmp; belle_sip_uri_t * L_uri; char* l_raw_uri; char uri[256]; snprintf(uri,sizeof(uri),"sip:toto@[%s]:5060;transport=tcp",ip6); L_uri = belle_sip_uri_parse(uri); l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_tmp = belle_sip_uri_parse(l_raw_uri); L_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri), "toto"); CU_ASSERT_EQUAL(belle_sip_uri_get_port(L_uri), 5060); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri),ip6); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_transport_param(L_uri), "tcp"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void testIPV6URI(void) { testIPV6URI_base("fe80::1"); testIPV6URI_base("2a01:e35:1387:1020:6233:4bff:fe0b:5663"); testIPV6URI_base("2a01:e35:1387:1020:6233::5663"); testIPV6URI_base("::1"); } static void testSIPSURI(void) { belle_sip_uri_t * L_uri = belle_sip_uri_parse("sips:linphone.org"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse(l_raw_uri); belle_sip_free(l_raw_uri); CU_ASSERT_EQUAL(belle_sip_uri_is_secure(L_uri), 1); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse("sip:linphone.org"); CU_ASSERT_EQUAL(belle_sip_uri_is_secure(L_uri), 0); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_ip_host(void) { belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:192.168.0.1"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse(l_raw_uri); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "192.168.0.1"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_lr(void) { belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:192.168.0.1;lr"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse(l_raw_uri); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "192.168.0.1"); CU_ASSERT_EQUAL(belle_sip_uri_has_lr_param(L_uri), 1); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_maddr(void) { belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:192.168.0.1;lr;maddr=linphone.org"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse(l_raw_uri); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_maddr_param(L_uri), "linphone.org"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_user_passwd(void) { belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:toto:tata@bla;"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse(l_raw_uri); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user_password(L_uri), "tata"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_uri_parameters (void) { char* l_raw_uri; belle_sip_uri_t* L_tmp; belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:192.168.0.1;ttl=12"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse("sip:maddr=@192.168.0.1;lr;maddr=192.168.0.1;user=ip;ttl=140;transport=sctp;method=INVITE;rport=5060"); l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_tmp = belle_sip_uri_parse(l_raw_uri); L_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_maddr_param(L_uri), "192.168.0.1"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user_param(L_uri), "ip"); CU_ASSERT_EQUAL(belle_sip_uri_get_ttl_param(L_uri),140); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_transport_param(L_uri), "sctp"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_method_param(L_uri), "INVITE"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_headers(void) { belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:192.168.0.1?toto=titi"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse(l_raw_uri); belle_sip_free(l_raw_uri); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_uri_get_header(L_uri,"toto")); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_header(L_uri,"toto"), "titi"); CU_ASSERT_PTR_NULL(belle_sip_uri_get_header(L_uri,"bla")); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse("sip:192.168.0.1?toto=titi&header2=popo&header3="); l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse(l_raw_uri); belle_sip_free(l_raw_uri); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_uri_get_header(L_uri,"toto")); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_header(L_uri,"header2"), "popo"); belle_sip_object_unref(L_uri); } static void test_escaped_headers(void) { const char* raw_uri_2= "sip:eNgwBpkNcH6EdTHlX0cq8@toto.com?" "P-Group-Id=Fu0hHIQ23H4hveVT:New%20Group" "&P-Expert-Profile-Id=zKQOBOB2jTmUOjkB:New%20Group" "&P-Reverse-Charging=0&P-Campaign-Id=none" "&P-Embed-Url=https://toto.com/caller/?1.4.0-dev-42-91bdf0c%26id%3DFu0hHIQ23H4hveVT%26CAMPAIGN_ID%3Dnone"; belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:toto@sip.linhone.org?User-to-User=323a313030363a3230385a48363039313941364b4342463845495936%3Bencoding%3Dhex"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_uri = belle_sip_uri_parse(l_raw_uri); belle_sip_free(l_raw_uri); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_uri_get_header(L_uri,"User-to-User")); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_header(L_uri,"User-to-User"), "323a313030363a3230385a48363039313941364b4342463845495936;encoding=hex"); belle_sip_object_unref(L_uri); L_uri = belle_sip_uri_parse(raw_uri_2); l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_free(l_raw_uri); CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_uri_get_header(L_uri,"P-Embed-Url")); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_header(L_uri,"P-Embed-Url"), "https://toto.com/caller/?1.4.0-dev-42-91bdf0c&id=Fu0hHIQ23H4hveVT&CAMPAIGN_ID=none"); belle_sip_object_unref(L_uri); } static void testSIMPLEURI_error(void) { belle_sip_uri_t* L_uri = belle_sip_uri_parse("siptcom"); CU_ASSERT_PTR_NULL(L_uri); } static void test_escaped_username(void) { belle_sip_uri_t* L_tmp; belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:toto%40linphone.org@titi.com"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_tmp = belle_sip_uri_parse(l_raw_uri); L_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri), "toto@linphone.org"); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "titi.com"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_escaped_passwd(void) { belle_sip_uri_t* L_tmp; belle_sip_uri_t * L_uri = belle_sip_uri_parse("sips:%22jehan%22%20%3cjehan%40sip2.linphone.org:544%3e@sip.linphone.org"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_tmp = belle_sip_uri_parse(l_raw_uri); L_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_user(L_uri), "\"jehan\" "); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_escaped_parameter(void) { belle_sip_uri_t* L_tmp; belle_sip_uri_t * L_uri = belle_sip_uri_parse("sip:toto@titi.com;pa%3Dram=aa%40bb:5060[];o%40"); char* l_raw_uri = belle_sip_object_to_string(BELLE_SIP_OBJECT(L_uri)); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); L_tmp = belle_sip_uri_parse(l_raw_uri); L_uri = BELLE_SIP_URI(belle_sip_object_clone(BELLE_SIP_OBJECT(L_tmp))); belle_sip_object_unref(BELLE_SIP_OBJECT(L_tmp)); belle_sip_free(l_raw_uri); CU_ASSERT_STRING_EQUAL(belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(L_uri), "pa=ram"), "aa@bb:5060[]"); CU_ASSERT_TRUE(belle_sip_parameters_has_parameter(BELLE_SIP_PARAMETERS(L_uri), "o@")); CU_ASSERT_STRING_EQUAL(belle_sip_uri_get_host(L_uri), "titi.com"); belle_sip_object_unref(BELLE_SIP_OBJECT(L_uri)); } static void test_uri_equals(void) { belle_sip_uri_t* a; belle_sip_uri_t* b; /* * The URIs within each of the following sets are equivalent: sip:%61lice@atlanta.com;transport=TCP sip:alice@AtLanTa.CoM;Transport=tcp */ a = belle_sip_uri_parse("sip:%61lice@atlanta.com;transport=TCP"); CU_ASSERT_PTR_NOT_NULL_FATAL(a); b = belle_sip_uri_parse("sip:alice@AtLanTa.CoM;Transport=tcp"); CU_ASSERT_PTR_NOT_NULL_FATAL(b); CU_ASSERT_TRUE(belle_sip_uri_equals(a,b)); belle_sip_object_unref(a); belle_sip_object_unref(b); /* sip:carol@chicago.com sip:carol@chicago.com;newparam=5 sip:carol@chicago.com;security=on */ a = belle_sip_uri_parse("sip:carol@chicago.com"); CU_ASSERT_PTR_NOT_NULL_FATAL(a); b = belle_sip_uri_parse("sip:carol@chicago.com;newparam=5"); CU_ASSERT_PTR_NOT_NULL_FATAL(b); CU_ASSERT_TRUE(belle_sip_uri_equals(a,b)); belle_sip_object_unref(a); belle_sip_object_unref(b); /* sip:biloxi.com;transport=tcp;method=REGISTER?to=sip:bob%40biloxi.com sip:biloxi.com;method=REGISTER;transport=tcp?to=sip:bob%40biloxi.com */ a = belle_sip_uri_parse("sip:biloxi.com;transport=tcp;method=REGISTER?to=sip:bob%40biloxi.com"); CU_ASSERT_PTR_NOT_NULL_FATAL(a); b = belle_sip_uri_parse("sip:biloxi.com;method=REGISTER;transport=tcp?to=sip:bob%40biloxi.com"); CU_ASSERT_PTR_NOT_NULL_FATAL(b); CU_ASSERT_TRUE(belle_sip_uri_equals(a,b)); belle_sip_object_unref(a); belle_sip_object_unref(b); /* sip:alice@atlanta.com?subject=project%20x&priority=urgent sip:alice@atlanta.com?priority=urgent&subject=project%20x The URIs within each of the following sets are not equivalent: SIP:ALICE@AtLanTa.CoM;Transport=udp (different usernames) sip:alice@AtLanTa.CoM;Transport=UDP */ a = belle_sip_uri_parse("sip:ALICE@AtLanTa.CoM;Transport=udp"); CU_ASSERT_PTR_NOT_NULL_FATAL(a); b = belle_sip_uri_parse("sip:alice@AtLanTa.CoM;Transport=UDP"); CU_ASSERT_PTR_NOT_NULL_FATAL(b); CU_ASSERT_FALSE(belle_sip_uri_equals(a,b)); belle_sip_object_unref(a); belle_sip_object_unref(b); /* sip:bob@biloxi.com (can resolve to different ports) sip:bob@biloxi.com:5060 */ a = belle_sip_uri_parse("sip:ALICE@AtLanTa.CoM;Transport=udp"); CU_ASSERT_PTR_NOT_NULL_FATAL(a); b = belle_sip_uri_parse("sip:alice@AtLanTa.CoM;Transport=UDP"); CU_ASSERT_PTR_NOT_NULL_FATAL(b); CU_ASSERT_FALSE(belle_sip_uri_equals(a,b)); belle_sip_object_unref(a); belle_sip_object_unref(b); /* sip:bob@biloxi.com (can resolve to different transports) sip:bob@biloxi.com;transport=udp */ a = belle_sip_uri_parse("sip:bob@biloxi.com"); CU_ASSERT_PTR_NOT_NULL_FATAL(a); b = belle_sip_uri_parse("sip:bob@biloxi.com;transport=udp"); CU_ASSERT_PTR_NOT_NULL_FATAL(b); CU_ASSERT_FALSE(belle_sip_uri_equals(a,b)); belle_sip_object_unref(a); belle_sip_object_unref(b); /* sip:bob@biloxi.com (can resolve to different port and transports) sip:bob@biloxi.com:6000;transport=tcp */ a = belle_sip_uri_parse("sip:bob@biloxi.com"); CU_ASSERT_PTR_NOT_NULL_FATAL(a); b = belle_sip_uri_parse("sip:bob@biloxi.com:6000;transport=tcp"); CU_ASSERT_PTR_NOT_NULL_FATAL(b); CU_ASSERT_FALSE(belle_sip_uri_equals(a,b)); belle_sip_object_unref(a); belle_sip_object_unref(b); /* sip:carol@chicago.com (different header component) sip:carol@chicago.com?Subject=next%20meeting sip:bob@phone21.boxesbybob.com (even though that's what sip:bob@192.0.2.4 phone21.boxesbybob.com resolves to) Note that equality is not transitive: o sip:carol@chicago.com and sip:carol@chicago.com;security=on are equivalent o sip:carol@chicago.com and sip:carol@chicago.com;security=off are equivalent o sip:carol@chicago.com;security=on and sip:carol@chicago.com;security=off are not equivalent Rosenberg, et. al. Standards Track [Page 155] RFC 3261 SIP: Session Initiation Protocol June 2002 */ } /* * From 19.1.1 SIP and SIPS URI Components * dialog reg./redir. Contact/ default Req.-URI To From Contact R-R/Route external user -- o o o o o o password -- o o o o o o host -- m m m m m m port (1) o - - o o o user-param ip o o o o o o method INVITE - - - - - o maddr-param -- o - - o o o ttl-param 1 o - - o - o transp.-param (2) o - - o o o lr-param -- o - - - o o other-param -- o o o o o o headers -- - - - o - o*/ void testUriComponentsChecker() { belle_sip_uri_t* uri = belle_sip_uri_parse("sip:hostonly"); CU_ASSERT_TRUE(belle_sip_uri_check_components_from_request_uri(uri)); belle_sip_object_unref(uri); { belle_sip_header_from_t* header = belle_sip_header_from_parse("From: sip:linphone.org:5061"); CU_ASSERT_FALSE(belle_sip_uri_check_components_from_context(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)),NULL,"From")); belle_sip_object_unref(header); } { belle_sip_header_to_t* header = belle_sip_header_to_parse("To: sip:linphone.org?header=interdit"); CU_ASSERT_FALSE(belle_sip_uri_check_components_from_context(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)),NULL,"To")); belle_sip_object_unref(header); } { belle_sip_header_contact_t* header = belle_sip_header_contact_parse("Contact: "); CU_ASSERT_FALSE(belle_sip_uri_check_components_from_context(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)),"REGISTER","Contact")); CU_ASSERT_TRUE(belle_sip_uri_check_components_from_context(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)),NULL,"Contact")); belle_sip_object_unref(header); } { belle_sip_header_record_route_t* header = belle_sip_header_record_route_parse("Record-Route: "); CU_ASSERT_FALSE(belle_sip_uri_check_components_from_context(belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(header)),NULL,"Record-Route")); belle_sip_object_unref(header); } { belle_sip_uri_t* uri = belle_sip_uri_parse("sip:linphone.org:5061?header=toto"); CU_ASSERT_TRUE(belle_sip_uri_check_components_from_context(uri,NULL,"Any")); belle_sip_object_unref(uri); } } void test_escaping_bad_chars(void){ char bad_uri[13] = { 'h', 'e', 'l', 'l', 'o', (char)0xa0, (char)0xc8, 'w', 'o', 'r', 'l', 'd', 0x0 }; char *escaped = belle_sip_uri_to_escaped_username(bad_uri); CU_ASSERT_STRING_EQUAL(escaped, "hello%a0%c8world"); belle_sip_free(escaped); } static test_t uri_tests[] = { { "Simple URI", testSIMPLEURI }, { "Complex URI", testCOMPLEXURI }, { "Escaped username", test_escaped_username }, { "Escaped username with bad chars", test_escaping_bad_chars }, { "Escaped parameter", test_escaped_parameter }, { "Escaped passwd", test_escaped_passwd}, { "User passwd", test_user_passwd}, { "IP host", test_ip_host }, { "lr", test_lr }, { "maddr", test_maddr }, { "headers", test_headers }, { "Escaped headers", test_escaped_headers}, { "URI parameters", test_uri_parameters }, { "SIPS URI", testSIPSURI }, { "URI equals", test_uri_equals }, { "Simple URI error", testSIMPLEURI_error }, { "IPv6 URI", testIPV6URI }, { "URI components", testUriComponentsChecker } }; test_suite_t sip_uri_test_suite = { "SIP URI", NULL, NULL, sizeof(uri_tests) / sizeof(uri_tests[0]), uri_tests }; belle-sip-1.4.1/tester/cast_test.c000066400000000000000000000043561252242224000170370ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "CUnit/Basic.h" #include "belle-sip/belle-sip.h" #include "belle_sip_tester.h" static void cast_test(void){ belle_sip_stack_t *stack=belle_sip_stack_new(NULL); belle_sip_listening_point_t *lp=belle_sip_stack_create_listening_point(stack,"0.0.0.0",7060,"UDP"); belle_sip_provider_t *provider; belle_sip_request_t *req=belle_sip_request_new(); belle_sip_response_t *resp=belle_sip_response_new(); belle_sip_message_t *msg; int tmp; CU_ASSERT_PTR_NOT_NULL_FATAL(stack); CU_ASSERT_PTR_NOT_NULL_FATAL(lp); provider=belle_sip_stack_create_provider(stack,lp); CU_ASSERT_PTR_NOT_NULL_FATAL(provider); CU_ASSERT_PTR_NOT_NULL_FATAL(req); CU_ASSERT_PTR_NOT_NULL_FATAL(resp); belle_sip_message("Casting belle_sip_request_t to belle_sip_message_t"); msg=BELLE_SIP_MESSAGE(req); CU_ASSERT_PTR_NOT_NULL(msg); belle_sip_message("Ok."); belle_sip_message("Casting belle_sip_response_t to belle_sip_message_t"); msg=BELLE_SIP_MESSAGE(resp); CU_ASSERT_PTR_NOT_NULL(msg); belle_sip_message("Ok."); tmp=BELLE_SIP_IS_INSTANCE_OF(req,belle_sip_response_t); belle_sip_message("Casting belle_sip_request_t to belle_sip_response_t: %s",tmp ? "yes" : "no"); CU_ASSERT_EQUAL(tmp,0); belle_sip_object_unref(req); belle_sip_object_unref(resp); belle_sip_object_unref(provider); belle_sip_object_unref(stack); } test_t cast_tests[] = { { "Casting requests and responses", cast_test } }; test_suite_t cast_test_suite = { "Object inheritence", NULL, NULL, sizeof(cast_tests) / sizeof(cast_tests[0]), cast_tests }; belle-sip-1.4.1/tester/certificates/000077500000000000000000000000001252242224000173375ustar00rootroot00000000000000belle-sip-1.4.1/tester/certificates/openssl-client-cert.cnf000066400000000000000000000255271252242224000237340ustar00rootroot00000000000000# # OpenSSL example configuration file. # This is mostly being used for generation of certificate requests. # # This definition stops the following lines choking if HOME isn't # defined. HOME = . RANDFILE = $ENV::HOME/.rnd # Extra OBJECT IDENTIFIER info: #oid_file = $ENV::HOME/.oid oid_section = new_oids # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: # extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) [ new_oids ] # We can add new OIDs in here for use by 'ca', 'req' and 'ts'. # Add a simple OID like this: # testoid1=1.2.3.4 # Or use config file substitution like this: # testoid2=${testoid1}.5.6 # Policies used by the TSA examples. tsa_policy1 = 1.2.3.4.1 tsa_policy2 = 1.2.3.4.5.6 tsa_policy3 = 1.2.3.4.5.7 #################################################################### [ ca ] default_ca = CA_default # The default ca section #################################################################### [ CA_default ] dir = ./root-ca # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. #unique_subject = no # Set to 'no' to allow creation of # several ctificates with same subject. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL crl = $dir/crl.pem # The current CRL private_key = $dir/private/cakey.pem# The private key RANDFILE = $dir/private/.rand # private random number file x509_extensions = usr_cert # The extentions to add to the cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default # Subject Name options cert_opt = ca_default # Certificate field options # Extension copying option: use with caution. # copy_extensions = copy # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs # so this is commented out by default to leave a V1 CRL. # crlnumber must also be commented out to leave a V1 CRL. # crl_extensions = crl_ext default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = default # use public key default MD preserve = no # keep passed DN ordering # A few difference way of specifying how similar the request should look # For type CA, the listed attributes must be the same, and the optional # and supplied fields are just that :-) policy = policy_match # For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional # For the 'anything' policy # At this point in time, you must list all acceptable 'object' # types. [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional #################################################################### [ req ] default_bits = 1024 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert # Passwords for private keys if not present they will be prompted for # input_password = secret # output_password = secret # This sets a mask for permitted string types. There are several options. # default: PrintableString, T61String, BMPString. # pkix : PrintableString, BMPString (PKIX recommendation before 2004) # utf8only: only UTF8Strings (PKIX recommendation after 2004). # nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). # MASK:XXXX a literal mask value. # WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. string_mask = utf8only req_extensions = v3_req # The extensions to add to a certificate request [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = FR countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = France localityName = Locality Name (eg, city) localityName_default = Grenoble 0.organizationName = Organization Name (eg, company) 0.organizationName_default = Belledonne Communications # we can do this but it is not needed normally :-) #1.organizationName = Second Organization Name (eg, company) #1.organizationName_default = World Wide Web Pty Ltd organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = LAB #organizationalUnitName_default = commonName = Common Name (e.g. server FQDN or YOUR name) commonName_max = 64 commonName_default = See altname for DNS name emailAddress = Email Address emailAddress_max = 64 emailAddress_default = jehan.monnier@belledonne-communications.com # SET-ex3 = SET extension number 3 [ req_attributes ] challengePassword = A challenge password challengePassword_min = 4 challengePassword_max = 20 unstructuredName = An optional company name [ usr_cert ] # These extensions are added when 'ca' signs a request. # This goes against PKIX guidelines but some CAs do it and some software # requires this to avoid interpreting an end user certificate as a CA. basicConstraints=CA:FALSE # Here are some examples of the usage of nsCertType. If it is omitted # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. # nsCertType = server # For an object signing certificate this would be used. # nsCertType = objsign # For normal client use this is typical # nsCertType = client, email # and for everything including object signing: # nsCertType = client, email, objsign # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment # This will be displayed in Netscape's comment listbox. nsComment = "OpenSSL Generated Certificate" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer # This stuff is for subjectAltName and issuerAltname. # Import the email address. # subjectAltName=email:copy # An alternative to produce certificates that aren't # deprecated according to PKIX. # subjectAltName=email:move # Copy subject details # issuerAltName=issuer:copy #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem #nsBaseUrl #nsRevocationUrl #nsRenewalUrl #nsCaPolicyUrl #nsSslServerName # This is required for TSA certificates. # extendedKeyUsage = critical,timeStamping [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [alt_names] URI = sip:tester@client.example.org [ v3_ca ] # Extensions for a typical CA # PKIX recommendation. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer # This is what PKIX recommends but some broken software chokes on critical # extensions. #basicConstraints = critical,CA:true # So we do this instead. basicConstraints = CA:true # Key usage: this is typical for a CA certificate. However since it will # prevent it being used as an test self-signed certificate it is best # left out by default. # keyUsage = cRLSign, keyCertSign # Some might want this also # nsCertType = sslCA, emailCA # Include email address in subject alt name: another PKIX recommendation # subjectAltName=email:copy # Copy issuer details # issuerAltName=issuer:copy # DER hex encoding of an extension: beware experts only! # obj=DER:02:03 # Where 'obj' is a standard or added object # You can even override a supported extension: # basicConstraints= critical, DER:30:03:01:01:FF [ crl_ext ] # CRL extensions. # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always [ proxy_cert_ext ] # These extensions should be added when creating a proxy certificate # This goes against PKIX guidelines but some CAs do it and some software # requires this to avoid interpreting an end user certificate as a CA. basicConstraints=CA:FALSE # Here are some examples of the usage of nsCertType. If it is omitted # the certificate can be used for anything *except* object signing. # This is OK for an SSL server. # nsCertType = server # For an object signing certificate this would be used. # nsCertType = objsign # For normal client use this is typical # nsCertType = client, email # and for everything including object signing: # nsCertType = client, email, objsign # This is typical in keyUsage for a client certificate. # keyUsage = nonRepudiation, digitalSignature, keyEncipherment # This will be displayed in Netscape's comment listbox. nsComment = "OpenSSL Generated Certificate" # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer # This stuff is for subjectAltName and issuerAltname. # Import the email address. # subjectAltName=email:copy # An alternative to produce certificates that aren't # deprecated according to PKIX. # subjectAltName=email:move # Copy subject details # issuerAltName=issuer:copy #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem #nsBaseUrl #nsRevocationUrl #nsRenewalUrl #nsCaPolicyUrl #nsSslServerName # This really needs to be in place for it to be a proxy certificate. proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo #################################################################### [ tsa ] default_tsa = tsa_config1 # the default TSA section [ tsa_config1 ] # These are used by the TSA reply generation only. dir = ./root-ca # TSA root directory serial = $dir/tsaserial # The current serial number (mandatory) crypto_device = builtin # OpenSSL engine to use for signing signer_cert = $dir/tsacert.pem # The TSA signing certificate # (optional) certs = $dir/cacert.pem # Certificate chain to include in reply # (optional) signer_key = $dir/private/tsakey.pem # The TSA private key (optional) default_policy = tsa_policy1 # Policy if request did not specify it # (optional) other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) digests = md5, sha1 # Acceptable message digests (mandatory) accuracy = secs:1, millisecs:500, microsecs:100 # (optional) clock_precision_digits = 0 # number of digits after dot. (optional) ordering = yes # Is ordering defined for timestamps? # (optional, default: no) tsa_name = yes # Must the TSA name be included in the reply? # (optional, default: no) ess_cert_id_chain = no # Must the ESS cert id chain be included? # (optional, default: no) belle-sip-1.4.1/tester/common/000077500000000000000000000000001252242224000161625ustar00rootroot00000000000000belle-sip-1.4.1/tester/common/bc_completion000066400000000000000000000106671252242224000207340ustar00rootroot00000000000000# Copyright (C) 2012 Belledonne Comunications, Grenoble, France # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Created by Gautier Pelloux-Prayer on 2014/10/24. # This script adds auto-completion for liblinphone_tester binary for Bash and # Zsh. To use it, just type: `source liblinphone_completion`, then for each # supported exectuable (see end of file), you will get auto-completions. # To use it permanently, source this file in your .rc file (.bashrc or .zshrc). _liblinphone_complete() { local completions command_requiring_argument prev_arg latest_arg available_tasks has_not_set_suite suite_name if [ -n "$BASH_VERSION" ]; then set -- "${COMP_WORDS[@]}" #convert them to arguments (eg $1,$#,$@,etc.) elif [ -n "$ZSH_VERSION" ]; then local args read -cA args #read list of arguments user entered set -- "${args[@]}" #convert them to arguments (eg $1,$#,$@,etc.) fi #skip program name program=$1 shift # if user required help, do not complete anything if ! grep -q -- "--help" <<< "$@"; then # retrieve the last argument latest_arg="" prev_arg="" latest_is_empty=0 for arg in "$@"; do if [ ! -z "$arg" ]; then prev_arg="$latest_arg" latest_arg="$arg" else latest_is_empty=1 fi done # get the tasks available, from --help available_tasks="$($program 2>&1 --help | sed -nE "s/.*--([^ ]*).*/--\\1/p")" # these commands expect an argument command_requiring_argument="$($program 2>&1 --help | sed -nE "s/.*--(.*) <.*/--\\1/p")" # remove all already provided tasks (it's useless to provide them twice) if [[ ! -z "$@" ]]; then current_tasks=$(echo $@ | grep -Eo -- "--([^ ])*" | tr '\n' '|' | sed 's/|/$|/g')--$ if [ ! -z "$current_tasks" ]; then available_tasks=$(echo "$available_tasks" | grep -vE -- "(${current_tasks})") fi fi # remove --test option if --suite is not provided yet! has_not_set_suite=$(grep -q -- "--suite" <<< "$@"; echo $?) if [ $has_not_set_suite = 1 ]; then available_tasks=$(echo "$available_tasks" | grep -v -- --test) fi # if latest arg does not start with '--', it is a custom value if [ $latest_is_empty = 0 ] && ! grep -q -- '^--' <<< "$latest_arg"; then # echo "yes!$prev_arg $has_not_set_suite" if [ "$prev_arg" = "--test" ] && [ $has_not_set_suite = 0 ]; then suite_name=$(echo $@ | sed -nE 's/.*--suite (.*) (--.*)$/\1/p' |sed "s@\\\\@@g") completions="$($program --list-tests $suite_name)" elif [ "$prev_arg" = "--suite" ] || [ "$prev_arg" = "--list-tests" ]; then completions="$($program --list-suites)" fi elif [ "$latest_arg" = "--test" ]; then if [ $has_not_set_suite = 0 ]; then suite_name=$(echo $@ | sed -nE 's/.*--suite (.*) (--.*)$/\1/p' |sed "s@\\\\@@g") completions="$($program --list-tests $suite_name)" fi elif [ "$latest_arg" = "--suite" ] || [ "$latest_arg" = "--list-tests" ]; then completions="$($program --list-suites)" # we are waiting for a custom value, so do not hint anything elif [[ ! -z "$latest_arg" ]] && grep -q -- "^$latest_arg$" <<< "$command_requiring_argument"; then completions="" else completions="$available_tasks" fi fi if [ ! -z "$completions" ]; then if [ -n "$BASH_VERSION" ]; then IFS=$'\n' #if that even necessary? COMPREPLY=($(compgen -W "${completions}" -- ${COMP_WORDS[COMP_CWORD]})) elif [ -n "$ZSH_VERSION" ]; then reply=( "${(ps:\n:)completions}" ) fi fi } for tester in liblinphone_tester mediastreamer2_tester belle_sip_tester pcap_playback \ bench mediastream msaudiocmp mtudiscover videodisplay linphone lpc2xml_test \ lp-gen-wrappers xml2lpc_test; do if [ -n "$BASH_VERSION" ]; then complete -F _liblinphone_complete $tester elif [ -n "$ZSH_VERSION" ]; then compctl -K _liblinphone_complete $tester else echo "Your shell might be not supported! Only bash and zsh tested." fi done belle-sip-1.4.1/tester/common/bc_tester_utils.c000066400000000000000000000256161252242224000215320ustar00rootroot00000000000000/* tester - liblinphone test suite Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* this must be provided at compile time*/ #include BC_CONFIG_FILE #include "bc_tester_utils.h" #include #include "CUnit/Automated.h" #if WINAPI_FAMILY_PHONE_APP const char *bc_tester_read_dir_prefix="Assets"; #elif defined(__QNX__) const char *bc_tester_read_dir_prefix="./app/native/assets/"; #else const char *bc_tester_read_dir_prefix="."; #endif /* TODO: have the same "static" for QNX and windows as above? */ #ifdef ANDROID const char *bc_tester_writable_dir_prefix = "/data/data/org.linphone.tester/cache"; #else const char *bc_tester_writable_dir_prefix = "."; #endif int bc_printf_verbosity_info; int bc_printf_verbosity_error; static test_suite_t **test_suite = NULL; static int nb_test_suites = 0; #ifdef HAVE_CU_CURSES #include "CUnit/CUCurses.h" static unsigned char curses = 0; #endif char* xml_file = "CUnitAutomated-Results.xml"; int xml_enabled = 0; char * suite_name; char * test_name; void (*tester_printf_va)(int level, const char *fmt, va_list args); void bc_tester_printf(int level, const char *fmt, ...) { va_list args; va_start (args, fmt); tester_printf_va(level, fmt, args); va_end (args); } int bc_tester_run_suite(test_suite_t *suite) { int i; CU_pSuite pSuite = CU_add_suite(suite->name, suite->init_func, suite->cleanup_func); for (i = 0; i < suite->nb_tests; i++) { if (NULL == CU_add_test(pSuite, suite->tests[i].name, suite->tests[i].func)) { return CU_get_error(); } } return 0; } const char * bc_tester_suite_name(int suite_index) { if (suite_index >= nb_test_suites) return NULL; return test_suite[suite_index]->name; } int bc_tester_suite_index(const char *suite_name) { int i; for (i = 0; i < nb_test_suites; i++) { if ((strcmp(suite_name, test_suite[i]->name) == 0) && (strlen(suite_name) == strlen(test_suite[i]->name))) { return i; } } return -1; } int bc_tester_nb_suites() { return nb_test_suites; } const char * bc_tester_test_name(const char *suite_name, int test_index) { int suite_index = bc_tester_suite_index(suite_name); if ((suite_index < 0) || (suite_index >= nb_test_suites)) return NULL; if (test_index >= test_suite[suite_index]->nb_tests) return NULL; return test_suite[suite_index]->tests[test_index].name; } int bc_tester_nb_tests(const char *suite_name) { int i = bc_tester_suite_index(suite_name); if (i < 0) return 0; return test_suite[i]->nb_tests; } void bc_tester_list_suites() { int j; for(j=0;jpName); } static void suite_cleanup_failure_message_handler(const CU_pSuite pSuite) { bc_tester_printf(bc_printf_verbosity_error,"Suite cleanup failed for [%s]", pSuite->pName); } #ifdef HAVE_CU_GET_SUITE static void suite_start_message_handler(const CU_pSuite pSuite) { bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] started\n", pSuite->pName); } static void suite_complete_message_handler(const CU_pSuite pSuite, const CU_pFailureRecord pFailure) { bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] ended\n", pSuite->pName); } static void test_start_message_handler(const CU_pTest pTest, const CU_pSuite pSuite) { bc_tester_printf(bc_printf_verbosity_info,"Suite [%s] Test [%s] started", pSuite->pName,pTest->pName); } /*derivated from cunit*/ static void test_complete_message_handler(const CU_pTest pTest, const CU_pSuite pSuite, const CU_pFailureRecord pFailureList) { int i; char result[2048]; char buffer[2048]; CU_pFailureRecord pFailure = pFailureList; snprintf(result, sizeof(result), "Suite [%s] Test [%s]", pSuite->pName, pTest->pName); if (pFailure) { strncat(result, " failed:", strlen(" failed:")); for (i = 1 ; (NULL != pFailure) ; pFailure = pFailure->pNext, i++) { snprintf(buffer, sizeof(buffer), "\n %d. %s:%u - %s", i, (NULL != pFailure->strFileName) ? pFailure->strFileName : "", pFailure->uiLineNumber, (NULL != pFailure->strCondition) ? pFailure->strCondition : ""); strncat(result, buffer, strlen(buffer)); } } else { strncat(result, " passed", strlen(" passed")); } bc_tester_printf(bc_printf_verbosity_info,"%s\n", result); } #endif int bc_tester_run_tests(const char *suite_name, const char *test_name) { int i; /* initialize the CUnit test registry */ if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error(); for (i = 0; i < nb_test_suites; i++) { bc_tester_run_suite(test_suite[i]); } #ifdef HAVE_CU_GET_SUITE CU_set_suite_start_handler(suite_start_message_handler); CU_set_suite_complete_handler(suite_complete_message_handler); CU_set_test_start_handler(test_start_message_handler); CU_set_test_complete_handler(test_complete_message_handler); #endif CU_set_all_test_complete_handler(all_complete_message_handler); CU_set_suite_init_failure_handler(suite_init_failure_message_handler); CU_set_suite_cleanup_failure_handler(suite_cleanup_failure_message_handler); if( xml_enabled != 0 ){ CU_automated_run_tests(); } else { #ifndef HAVE_CU_GET_SUITE if( suite_name ){ bc_tester_printf(bc_printf_verbosity_info, "Tester compiled without CU_get_suite() function, running all tests instead of suite '%s'", suite_name); } #else if (suite_name){ CU_pSuite suite; suite=CU_get_suite(suite_name); if (!suite) { bc_tester_printf(bc_printf_verbosity_error, "Could not find suite '%s'. Available suites are:", suite_name); bc_tester_list_suites(); return -1; } else if (test_name) { CU_pTest test=CU_get_test_by_name(test_name, suite); if (!test) { bc_tester_printf(bc_printf_verbosity_error, "Could not find test '%s' in suite '%s'. Available tests are:", test_name, suite_name); // do not use suite_name here, since this method is case sensitive bc_tester_list_tests(suite->pName); return -2; } else { CU_ErrorCode err= CU_run_test(suite, test); if (err != CUE_SUCCESS) bc_tester_printf(bc_printf_verbosity_error, "CU_basic_run_test error %d", err); } } else { CU_run_suite(suite); } } else #endif { #ifdef HAVE_CU_CURSES if (curses) { /* Run tests using the CUnit curses interface */ CU_curses_run_tests(); } else #endif { /* Run all tests using the CUnit Basic interface */ CU_run_all_tests(); } } } return CU_get_number_of_tests_failed()!=0; } void bc_tester_helper(const char *name, const char* additionnal_helper) { bc_tester_printf(bc_printf_verbosity_info,"%s --help\n" "\t\t\t--list-suites\n" "\t\t\t--list-tests \n" "\t\t\t--suite \n" "\t\t\t--test \n" #ifdef HAVE_CU_CURSES "\t\t\t--curses\n" #endif "\t\t\t--xml\n" "\t\t\t--xml-file \n" "And additionally:\n" "%s" , name , additionnal_helper); } void bc_tester_init(void (*ftester_printf)(int level, const char *fmt, va_list args), int iverbosity_info, int iverbosity_error) { tester_printf_va = ftester_printf; bc_printf_verbosity_error = iverbosity_error; bc_printf_verbosity_info = iverbosity_info; } int bc_tester_parse_args(int argc, char **argv, int argid) { int i = argid; if (strcmp(argv[i],"--help")==0){ return -1; } else if (strcmp(argv[i],"--test")==0){ CHECK_ARG("--test", ++i, argc); test_name=argv[i]; }else if (strcmp(argv[i],"--suite")==0){ CHECK_ARG("--suite", ++i, argc); suite_name=argv[i]; } else if (strcmp(argv[i],"--list-suites")==0){ bc_tester_list_suites(); return 0; } else if (strcmp(argv[i],"--list-tests")==0){ CHECK_ARG("--list-tests", ++i, argc); suite_name = argv[i]; bc_tester_list_tests(suite_name); return 0; } else if (strcmp(argv[i], "--xml-file") == 0){ CHECK_ARG("--xml-file", ++i, argc); xml_file = argv[i]; xml_enabled = 1; } else if (strcmp(argv[i], "--xml") == 0){ xml_enabled = 1; }else { bc_tester_printf(bc_printf_verbosity_error, "Unknown option \"%s\"\n", argv[i]); return -1; } if( xml_enabled && (suite_name || test_name) ){ bc_tester_printf(bc_printf_verbosity_error, "Cannot use both XML and specific test suite\n"); return -1; } /* returns number of arguments read + 1 */ return i - argid + 1; } int bc_tester_start() { int ret; if( xml_enabled ){ size_t size = strlen(xml_file) + strlen(".tmp") + 1; char * xml_tmp_file = malloc(sizeof(char) * size); snprintf(xml_tmp_file, size, "%s.tmp", xml_file); CU_set_output_filename(xml_tmp_file); free(xml_tmp_file); } ret = bc_tester_run_tests(suite_name, test_name); return ret; } void bc_tester_add_suite(test_suite_t *suite) { if (test_suite == NULL) { test_suite = (test_suite_t **)malloc(10 * sizeof(test_suite_t *)); } test_suite[nb_test_suites] = suite; nb_test_suites++; if ((nb_test_suites % 10) == 0) { test_suite = (test_suite_t **)realloc(test_suite, (nb_test_suites + 10) * sizeof(test_suite_t *)); } } void bc_tester_uninit() { /* Redisplay list of failed tests on end */ if (CU_get_number_of_failure_records()){ CU_basic_show_failures(CU_get_failure_list()); } CU_cleanup_registry(); /*add missing final newline*/ bc_tester_printf(bc_printf_verbosity_info,""); if( xml_enabled ){ /*create real xml file only if tester did not crash*/ size_t size = strlen(xml_file) + strlen(".tmp-Results.xml") + 1; char * xml_tmp_file = malloc(sizeof(char) * size); snprintf(xml_tmp_file, size, "%s.tmp-Results.xml", xml_file); rename(xml_tmp_file, xml_file); free(xml_tmp_file); } if (test_suite != NULL) { free(test_suite); test_suite = NULL; nb_test_suites = 0; } } char * bc_tester_res(const char *name) { char* file = NULL; if (name) { size_t len = strlen(bc_tester_read_dir_prefix) + 1 + strlen(name) + 1; file = malloc(len); snprintf(file, len, "%s/%s", bc_tester_read_dir_prefix, name); } return file; } belle-sip-1.4.1/tester/common/bc_tester_utils.h000066400000000000000000000264461252242224000215410ustar00rootroot00000000000000/* tester - liblinphone test suite Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef TESTER_UTILS_H #define TESTER_UTILS_H #include "CUnit/Basic.h" #include #include extern const char *bc_tester_read_dir_prefix; extern const char *bc_tester_writable_dir_prefix; extern int bc_printf_verbosity_info; extern int bc_printf_verbosity_error; typedef void (*test_function_t)(void); typedef int (*test_suite_function_t)(const char *name); typedef struct { const char *name; test_function_t func; } test_t; typedef struct { const char *name; CU_InitializeFunc init_func; CU_CleanupFunc cleanup_func; int nb_tests; test_t *tests; } test_suite_t; #ifdef __cplusplus extern "C" { #endif #define CHECK_ARG(argument, index, argc) \ if(index >= argc) { \ fprintf(stderr, "Missing argument for \"%s\"\n", argument); \ return -1; \ } \ void bc_tester_init(void (*ftester_printf)(int level, const char *fmt, va_list args) , int verbosity_info, int verbosity_error); void bc_tester_helper(const char *name, const char* additionnal_helper); int bc_tester_parse_args(int argc, char** argv, int argid); int bc_tester_start(); void bc_tester_add_suite(test_suite_t *suite); void bc_tester_uninit(); void bc_tester_printf(int level, const char *fmt, ...); int bc_tester_nb_suites(); int bc_tester_nb_tests(const char* name); void bc_tester_list_suites(); void bc_tester_list_tests(const char *suite_name); const char * bc_tester_suite_name(int suite_index); const char * bc_tester_test_name(const char *suite_name, int test_index); int bc_tester_run_suite(test_suite_t *suite); int bc_tester_run_tests(const char *suite_name, const char *test_name); int bc_tester_suite_index(const char *suite_name); /** * Get full path to the given resource * * @param name relative resource path (relative to bc_tester_writable_dir_prefix) * @return path to the resource. Must be freed by caller. */ char * bc_tester_res(const char *name); /*Redefine the CU_... macros WITHOUT final ';' semicolon, to allow IF conditions */ #define BC_ASSERT_EQUAL(actual, expected) CU_assertImplementation(((actual) == (expected)), __LINE__, ("CU_ASSERT_EQUAL(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) #define BC_PASS(msg) CU_assertImplementation(CU_TRUE, __LINE__, ("CU_PASS(" #msg ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT(value) CU_assertImplementation((value), __LINE__, #value, __FILE__, "", CU_FALSE) #define BC_ASSERT_FATAL(value) CU_assertImplementation((value), __LINE__, #value, __FILE__, "", CU_TRUE) #define BC_TEST(value) CU_assertImplementation((value), __LINE__, #value, __FILE__, "", CU_FALSE) #define BC_TEST_FATAL(value) CU_assertImplementation((value), __LINE__, #value, __FILE__, "", CU_TRUE) #define BC_ASSERT_TRUE(value) CU_assertImplementation((value), __LINE__, ("CU_ASSERT_TRUE(" #value ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_TRUE_FATAL(value) CU_assertImplementation((value), __LINE__, ("CU_ASSERT_TRUE_FATAL(" #value ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_FALSE(value) CU_assertImplementation(!(value), __LINE__, ("CU_ASSERT_FALSE(" #value ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_FALSE_FATAL(value) CU_assertImplementation(!(value), __LINE__, ("CU_ASSERT_FALSE_FATAL(" #value ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_EQUAL(actual, expected) CU_assertImplementation(((actual) == (expected)), __LINE__, ("CU_ASSERT_EQUAL(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_EQUAL_FATAL(actual, expected) CU_assertImplementation(((actual) == (expected)), __LINE__, ("CU_ASSERT_EQUAL_FATAL(" #actual "," #expected ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_NOT_EQUAL(actual, expected) CU_assertImplementation(((actual) != (expected)), __LINE__, ("CU_ASSERT_NOT_EQUAL(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_NOT_EQUAL_FATAL(actual, expected) CU_assertImplementation(((actual) != (expected)), __LINE__, ("CU_ASSERT_NOT_EQUAL_FATAL(" #actual "," #expected ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_PTR_EQUAL(actual, expected) CU_assertImplementation(((const void*)(actual) == (const void*)(expected)), __LINE__, ("CU_ASSERT_PTR_EQUAL(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_PTR_EQUAL_FATAL(actual, expected) CU_assertImplementation(((const void*)(actual) == (const void*)(expected)), __LINE__, ("CU_ASSERT_PTR_EQUAL_FATAL(" #actual "," #expected ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_PTR_NOT_EQUAL(actual, expected) CU_assertImplementation(((const void*)(actual) != (const void*)(expected)), __LINE__, ("CU_ASSERT_PTR_NOT_EQUAL(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_PTR_NOT_EQUAL_FATAL(actual, expected) CU_assertImplementation(((const void*)(actual) != (const void*)(expected)), __LINE__, ("CU_ASSERT_PTR_NOT_EQUAL_FATAL(" #actual "," #expected ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_PTR_NULL(value) CU_assertImplementation((NULL == (const void*)(value)), __LINE__, ("CU_ASSERT_PTR_NULL(" #value")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_PTR_NULL_FATAL(value) CU_assertImplementation((NULL == (const void*)(value)), __LINE__, ("CU_ASSERT_PTR_NULL_FATAL(" #value")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_PTR_NOT_NULL(value) CU_assertImplementation((NULL != (const void*)(value)), __LINE__, ("CU_ASSERT_PTR_NOT_NULL(" #value")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_PTR_NOT_NULL_FATAL(value) CU_assertImplementation((NULL != (const void*)(value)), __LINE__, ("CU_ASSERT_PTR_NOT_NULL_FATAL(" #value")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_STRING_EQUAL(actual, expected) CU_assertImplementation(!(strcmp((const char*)(actual), (const char*)(expected))), __LINE__, ("CU_ASSERT_STRING_EQUAL(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_STRING_EQUAL_FATAL(actual, expected) CU_assertImplementation(!(strcmp((const char*)(actual), (const char*)(expected))), __LINE__, ("CU_ASSERT_STRING_EQUAL_FATAL(" #actual "," #expected ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_STRING_NOT_EQUAL(actual, expected) CU_assertImplementation((strcmp((const char*)(actual), (const char*)(expected))), __LINE__, ("CU_ASSERT_STRING_NOT_EQUAL(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_STRING_NOT_EQUAL_FATAL(actual, expected) CU_assertImplementation((strcmp((const char*)(actual), (const char*)(expected))), __LINE__, ("CU_ASSERT_STRING_NOT_EQUAL_FATAL(" #actual "," #expected ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_NSTRING_EQUAL(actual, expected, count) CU_assertImplementation(!(strncmp((const char*)(actual), (const char*)(expected), (size_t)(count))), __LINE__, ("CU_ASSERT_NSTRING_EQUAL(" #actual "," #expected "," #count ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_NSTRING_EQUAL_FATAL(actual, expected, count) CU_assertImplementation(!(strncmp((const char*)(actual), (const char*)(expected), (size_t)(count))), __LINE__, ("CU_ASSERT_NSTRING_EQUAL_FATAL(" #actual "," #expected "," #count ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_NSTRING_NOT_EQUAL(actual, expected, count) CU_assertImplementation((strncmp((const char*)(actual), (const char*)(expected), (size_t)(count))), __LINE__, ("CU_ASSERT_NSTRING_NOT_EQUAL(" #actual "," #expected "," #count ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_NSTRING_NOT_EQUAL_FATAL(actual, expected, count) CU_assertImplementation((strncmp((const char*)(actual), (const char*)(expected), (size_t)(count))), __LINE__, ("CU_ASSERT_NSTRING_NOT_EQUAL_FATAL(" #actual "," #expected "," #count ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_DOUBLE_EQUAL(actual, expected, granularity) CU_assertImplementation(((fabs((double)(actual) - (expected)) <= fabs((double)(granularity)))), __LINE__, ("CU_ASSERT_DOUBLE_EQUAL(" #actual "," #expected "," #granularity ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_DOUBLE_EQUAL_FATAL(actual, expected, granularity) CU_assertImplementation(((fabs((double)(actual) - (expected)) <= fabs((double)(granularity)))), __LINE__, ("CU_ASSERT_DOUBLE_EQUAL_FATAL(" #actual "," #expected "," #granularity ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_DOUBLE_NOT_EQUAL(actual, expected, granularity) CU_assertImplementation(((fabs((double)(actual) - (expected)) > fabs((double)(granularity)))), __LINE__, ("CU_ASSERT_DOUBLE_NOT_EQUAL(" #actual "," #expected "," #granularity ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_DOUBLE_NOT_EQUAL_FATAL(actual, expected, granularity) CU_assertImplementation(((fabs((double)(actual) - (expected)) > fabs((double)(granularity)))), __LINE__, ("CU_ASSERT_DOUBLE_NOT_EQUAL_FATAL(" #actual "," #expected "," #granularity ")"), __FILE__, "", CU_TRUE) #define BC_ASSERT_GREATER(actual, expected) CU_assertImplementation(((actual) >= (expected)), __LINE__, ("CU_ASSERT_GREATER(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) #define BC_ASSERT_LOWER(actual, expected) CU_assertImplementation(((actual) <= (expected)), __LINE__, ("CU_ASSERT_LOWER(" #actual "," #expected ")"), __FILE__, "", CU_FALSE) /*Add some custom defines with logs in case of fail*/ #define BC_ASSERT_EQUAL_INT(actual, expected) { \ int cactual = (actual), cexpected = (expected); \ if (! BC_ASSERT_EQUAL(cactual, cexpected)) { \ bc_tester_printf(bc_printf_verbosity_error, "%s:%d - Expected " #actual " = " #expected " but was %d != %d\n", __FILE__, __LINE__, cactual, cexpected); \ } \ } #define BC_ASSERT_GREATER_INT(actual, expected) { \ int cactual = (actual), cexpected = (expected); \ if (! BC_ASSERT_GREATER(cactual, cexpected)) { \ bc_tester_printf(bc_printf_verbosity_error, "%s:%d - Expected " #actual " >= " #expected " but was %d < %d\n", __FILE__, __LINE__, cactual, cexpected); \ } \ } #define BC_ASSERT_LOWER_INT(actual, expected) { \ int cactual = (actual), cexpected = (expected); \ if (! BC_ASSERT_LOWER(cactual, cexpected)) { \ bc_tester_printf(bc_printf_verbosity_error, "%s:%d - Expected " #actual " <= " #expected " but was %d > %d\n", __FILE__, __LINE__, cactual, cexpected); \ } \ } #define BC_ASSERT_GREATER_UINT64_T(actual, expected) { \ uint64_t cactual = (actual), cexpected = (expected); \ if (! BC_ASSERT_GREATER(cactual, cexpected)) { \ bc_tester_printf(bc_printf_verbosity_error, "%s:%d - Expected " #actual " >= " #expected " but was %lu < %lu\n", __FILE__, __LINE__, (long unsigned)cactual, (long unsigned)cexpected); \ } \ } #define BC_ASSERT_LOWER_UINT64_T(actual, expected) { \ uint64_t cactual = (actual), cexpected = (expected); \ if (! BC_ASSERT_LOWER(cactual, cexpected)) { \ bc_tester_printf(bc_printf_verbosity_error, "%s:%d - Expected " #actual " <= " #expected " but was %lu > %lu\n", __FILE__, __LINE__, (long unsigned)cactual, (long unsigned)cexpected); \ } \ } #ifdef __cplusplus } #endif #endif belle-sip-1.4.1/tester/describe.c000066400000000000000000000021541252242224000166200ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "belle-sip/belle-sip.h" int main(int argc, char *argv[]){ char *str; if (argc!=2){ fprintf(stderr,"Usage:\n%s \n",argv[0]); return -1; } str=belle_sip_object_describe_type_from_name(argv[1]); if (str){ printf("%s\n",str); belle_sip_free(str); }else{ fprintf(stderr,"Unknown type %s\n",argv[1]); return -1; } return 0; } belle-sip-1.4.1/tester/get.c000066400000000000000000000050221252242224000156140ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "belle-sip/belle-sip.h" static belle_sip_stack_t *stack=NULL; static void process_response(void *data, const belle_http_response_event_t *event){ belle_http_response_t *resp=event->response; const char *body=belle_sip_message_get_body(BELLE_SIP_MESSAGE(resp)); if (body){ fprintf(stdout,"%s",body); } belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } static void process_io_error(void *data, const belle_sip_io_error_event_t *event){ fprintf(stderr,"IO error\n"); belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } static void process_timeout(void *data, const belle_sip_timeout_event_t *event){ fprintf(stderr,"Timeout\n"); belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } int main(int argc, char *argv[]){ belle_http_provider_t *prov; belle_http_request_t *req; belle_generic_uri_t *uri; belle_http_request_listener_callbacks_t cbs={0}; if (argc<2){ fprintf(stderr,"Usage:\n%s [--debug]\n",argv[0]); return -1; } if (argc==3){ if (strcmp(argv[2],"--debug")==0){ belle_sip_set_log_level(BELLE_SIP_LOG_DEBUG); } } stack=belle_sip_stack_new(NULL); prov=belle_sip_stack_create_http_provider(stack,"0.0.0.0"); uri=belle_generic_uri_parse(argv[1]); if (!uri){ fprintf(stderr,"Bad uri %s\n",argv[1]); return -1; } cbs.process_response=process_response; cbs.process_io_error=process_io_error; cbs.process_timeout=process_timeout; req=belle_http_request_create("GET",uri,NULL); belle_http_provider_send_request(prov,req,belle_http_request_listener_create_from_callbacks(&cbs,NULL)); belle_sip_stack_main(stack); belle_sip_object_unref(prov); belle_sip_object_unref(stack); return 0; } belle-sip-1.4.1/tester/parse.c000066400000000000000000000055351252242224000161600ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2010 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #if WIN32 #define strcasecmp _stricmp #else #include #endif #include #include "belle-sip/belle-sip.h" #include "belle-sip/belle-sdp.h" int main(int argc, char *argv[]){ char *str; struct stat st; int fd; int i; const char *filename=NULL; const char *protocol="sip"; if (argc<2){ fprintf(stderr,"Usage:\n%s [--protocol sip|http|sdp] \n",argv[0]); return -1; } for(i=1;i. */ extern belle_sip_stack_t * stack; extern belle_sip_provider_t *prov; extern const char *test_domain; int call_endeed; extern int register_init(void); extern int register_uninit(void); extern belle_sip_request_t* register_user(belle_sip_stack_t * stack ,belle_sip_provider_t *prov ,const char *transport ,int use_transaction ,const char* username,const char* outbound) ; extern void unregister_user(belle_sip_stack_t * stack ,belle_sip_provider_t *prov ,belle_sip_request_t* initial_request ,int use_transaction); belle-sip-1.4.1/tester/resolve.c000066400000000000000000000041771252242224000165260ustar00rootroot00000000000000/* belle-sip - SIP (RFC3261) library. Copyright (C) 2013 Belledonne Communications SARL This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include "belle-sip/belle-sip.h" static belle_sip_stack_t *stack; static void resolver_callback(void *data, const char *queried_name, struct addrinfo *ai_list){ int err; struct addrinfo *ai_it; char name[NI_MAXHOST]; char port[NI_MAXSERV]; for(ai_it=ai_list;ai_it!=NULL;ai_it=ai_it->ai_next){ err=getnameinfo(ai_it->ai_addr,ai_list->ai_addrlen,name,sizeof(name),port,sizeof(port),NI_NUMERICSERV|NI_NUMERICHOST); if (err!=0){ fprintf(stderr,"getnameinfo error: %s",gai_strerror(err)); }else{ printf("\t%s %s\n",name,port); } } belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack)); } int main(int argc, char *argv[]){ int i; const char *domain=NULL; const char *transport="udp"; if (argc<2){ fprintf(stderr,"Usage:\n%s [transport] [--debug]\n",argv[0]); return -1; } domain=argv[1]; for (i=2;i