pax_global_header00006660000000000000000000000064123613317670014523gustar00rootroot0000000000000052 comment=cc6d622150db36cf90cd89e42ce4e3de5f48f1ec xmlrpc-c-1.33.14/000077500000000000000000000000001236133176700134215ustar00rootroot00000000000000xmlrpc-c-1.33.14/GNUmakefile000066400000000000000000000150111236133176700154710ustar00rootroot00000000000000include srcdir.mk BLDDIR = $(CURDIR) SUBDIR = export SRCDIR export BLDDIR include $(BLDDIR)/config.mk SUBDIRS = include lib src test examples ifeq ($(BUILD_TOOLS),yes) SUBDIRS += tools endif # The reason we don't build tools and examples by default is that they # contain executables, which require significantly more from the # environment to build than libraries. Ergo, they are signficantly # more likely to fail to build. Indeed, when 'tools' was built by # default, the majority of the reported build problems were with that. # Since they are ancillary to the package, building them by default is # not worth causing the whole build to fail. # As with any subdirectory, to build 'tools' or 'examples', cd to the # subdirectory and make there. DEFAULT_SUBDIRS = include lib src PROGRAMS_TO_INSTALL = xmlrpc-c-config default: xmlrpc-c-config xmlrpc-c-config.test $(DEFAULT_SUBDIRS:%=%/all) # We don't want common.mk's rule for version.h OMIT_VERSION_H = Y # We don't want common.mk's rule for transport_config.h OMIT_TRANSPORT_CONFIG_H = Y # We don't want common.mk's rule for xmlrpc-c-config.test: OMIT_XMLRPC_C_CONFIG_TEST = Y include $(SRCDIR)/common.mk .PHONY: all all: xmlrpc-c-config xmlrpc-c-config.test $(SUBDIRS:%=%/all) # The examples subdirectory is special, because even the make file in there # is designed to be an example. So it has to be simple and as close as # possible to something a person could use outside of the Xmlrpc-c source # tree. One ramification of that is that it does not specify dependencies # on other parts of the Xmlrpc-c build. That means we must separately # ensure that the Xmlrpc-c libraries are built before making the example # programs. # # It also means that you have to manually clean the examples directory # in order to get the examples rebuilt after you modify the Xmlrpc-c # libraries. examples/all: xmlrpc-c-config.test lib/all src/all include/all # Parallel make (make --jobs) is not smart enough to coordinate builds # between submakes, so a naive parallel make would cause certain # targets to get built multiple times simultaneously. That is usually # unacceptable. So we introduce extra dependencies here just to make # sure such targets are already up to date before the submake starts, # for the benefit of parallel make. Note that we ensure that parallel # make works for 'make all' in the top directory, but it may still fail # for the aforementioned reason for other invocations. tools/all test/all: include/all lib/all src/all src/all lib/all: include/all src/all: lib/all MAJOR := $(XMLRPC_MAJOR_RELEASE) MINOR := $(XMLRPC_MINOR_RELEASE) POINT := $(XMLRPC_POINT_RELEASE) version.h: $(SRCDIR)/version.mk rm -f $@ echo "/* Generated by make file rule */" >>$@ echo "#define XMLRPC_C_VERSION" \"$(MAJOR).$(MINOR).$(POINT)"\"" >>$@ echo "#define XMLRPC_VERSION_MAJOR $(MAJOR)" >>$@ echo "#define XMLRPC_VERSION_MINOR $(MINOR)" >>$@ echo "#define XMLRPC_VERSION_POINT $(POINT)" >>$@ include transport_config.mk # shell_config is a fragment to place inside a Bourne shell program that # sets variables that tell how the build is configured. shell_config: $(BLDDIR)/config.mk rm -f $@ @echo "Lots of echoes to '$@' suppressed here ..." @echo '#' >>$@ @echo '#######################################################' >>$@ @echo "# From '$@'" >>$@ @echo '#######################################################' >>$@ @echo 'ENABLE_ABYSS_THREADS="$(ENABLE_ABYSS_THREADS)"' >>$@ @echo 'THREAD_LIBS="$(THREAD_LIBS)"' >>$@ @echo 'ENABLE_LIBXML2_BACKEND="$(ENABLE_LIBXML2_BACKEND)"' >>$@ @echo 'MUST_BUILD_WININET_CLIENT="$(MUST_BUILD_WININET_CLIENT)"'>>$@ @echo 'MUST_BUILD_CURL_CLIENT="$(MUST_BUILD_CURL_CLIENT)"' >>$@ @echo 'MUST_BUILD_LIBWWW_CLIENT="$(MUST_BUILD_LIBWWW_CLIENT)"' >>$@ @echo 'NEED_RPATH="$(NEED_RPATH)"' >>$@ @echo 'NEED_WL_RPATH="$(NEED_WL_RPATH)"' >>$@ @echo 'LIBXMLRPCPP_NAME="$(LIBXMLRPCPP_NAME)"' >>$@ @echo 'LSOCKET="$(LSOCKET)"' >>$@ @echo 'WININET_LDADD="$(WININET_LDADD)"' >>$@ @echo 'WININET_LIBDIR="$(WININET_LIBDIR)"' >>$@ @echo 'CURL_LDADD="$(CURL_LDADD)"' >>$@ @echo 'CURL_LIBDIR="$(CURL_LIBDIR)"' >>$@ @echo 'LIBWWW_LDADD="$(LIBWWW_LDADD)"' >>$@ @echo 'LIBWWW_LIBDIR="$(LIBWWW_LIBDIR)"' >>$@ @echo 'XMLRPC_MAJOR_RELEASE="$(XMLRPC_MAJOR_RELEASE)"' >>$@ @echo 'XMLRPC_MINOR_RELEASE="$(XMLRPC_MINOR_RELEASE)"' >>$@ @echo 'XMLRPC_POINT_RELEASE="$(XMLRPC_POINT_RELEASE)"' >>$@ @echo 'FEATURE_LIST="$(FEATURE_LIST)"' >>$@ @echo 'PREFIX="$(PREFIX)"' >>$@ @echo 'HEADERINST_DIR="$(HEADERINST_DIR)"' >>$@ @echo 'LIBINST_DIR="$(LIBINST_DIR)"' >>$@ @echo 'BLDDIR="$(BLDDIR)"' >>$@ @echo 'ABS_SRCDIR="$(ABS_SRCDIR)"' >>$@ @echo '#######################################################' >>$@ xmlrpc-c-config xmlrpc-c-config.test:%: %.main shell_config rm -f $@ @echo "Echoes to '$@' suppressed here ..." @echo '#! /bin/sh' >>$@ @echo '#' >>$@ @echo '# This file was generated by a make rule' >>$@ @echo '#' >>$@ cat shell_config >>$@ cat $< >>$@ chmod a+rx $@ .PHONY: clean clean-local clean: $(SUBDIRS:%=%/clean) clean-common clean-local clean-local: rm -f transport_config.h version.h .PHONY: distclean distclean-local distclean: $(SUBDIRS:%=%/distclean) distclean-common distclean-local distclean-local: clean-local rm -f config.log config.status config.mk srcdir.mk rm -f xmlrpc_config.h xmlrpc_amconfig.h stamp-h rm -f shell_config xmlrpc-c-config xmlrpc-c-config.test rm -f TAGS check: $(SUBDIRS:%=%/check) $(MAKE) -C test runtests DISTFILES = .PHONY: distdir distdir: distdir-common .PHONY: install install: $(DEFAULT_SUBDIRS:%=%/install) install-common .PHONY: dep dep: version.h $(BLDDIR)/include/xmlrpc-c/config.h $(SUBDIRS:%=%/dep) xmlrpc_config.h xmlrpc_amconfig.h \ :%:%.in $(SRCDIR)/configure $(SRCDIR)/configure # A trick to catch a common user error. When you don't run 'configure', # you don't have a srcdir.mk, which means $(SRCDIR) is null. /common.mk: @echo ======================================= @echo = You must run Configure before Make. = @echo ======================================= false # 'tags' generates/updates an Emacs tags file, anmed TAGS, in the current # directory. Use with Emacs command 'find-tag'. .PHONY: tags tags: find . -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" | \ etags - xmlrpc-c-1.33.14/Makefile000066400000000000000000000013341236133176700150620ustar00rootroot00000000000000# The make files for this package exploit features of GNU Make that # other Makes do not have. Because it is a common mistake for users # to try to build with a different Make, we have this make file that # does nothing but tell the user to use GNU Make. # If the user were using GNU Make now, this file would not get used because # GNU Make uses a make file named "GNUmakefile" in preference to "Makefile" # if it exists. This package contains a "GNUmakefile". default: all all install clean dep depend: @echo "You must use GNU Make to build this. You are running some " @echo "other Make. GNU Make may be installed on your system with " @echo "the name 'gmake'. If not, see http://www.gnu.org/software ." @echo false xmlrpc-c-1.33.14/README000066400000000000000000000031661236133176700143070ustar00rootroot00000000000000This is the source code for XML-RPC for C/C++, called Xmlrpc-c for short. XML-RPC for C/C++ is programming libraries and related tools to help you write an XML-RPC server or client in C or C++. Documentation for the package is at http://xmlrpc-c.sourceforge.net/doc See the Xmlrpc-c website at: http://xmlrpc-c.sourceforge.net/ PREREQUISITES ------------- To build a useful Xmlrpc-c client library, you'll need to have at least one HTTP library. Xmlrpc-c knows how to use W3C Libwww (Version 5.3.2 or newer), Curl, and Wininet. The configurator gives you the option of building libraries that use any or all of these, and defaults to every one you appear to have installed. If you don't appear to have any installed, the configurator causes the build to omit client facilities altogether. Information about W3C Libwww, including how to get it are at . For Curl, see . Wininet comes with Windows, and isn't available for any other platform. You also need an XML parser/builder library. An old version of Expat is included in the package and used by default, so there's no actual prerequisite here. But if you separately obtain Libxml2, you can configure the build to use that instead. There's no really pressing reason to do that, though. BUILDING, INSTALLING -------------------- See the file doc/INSTALL. In the simplest case, it's just a conventional $ ./configure $ make $ make install ADDITIONAL INFORMATION ---------------------- See the doc/ directory of the source tree for information about the source code. User documentation is on the web, as described above. xmlrpc-c-1.33.14/Windows/000077500000000000000000000000001236133176700150535ustar00rootroot00000000000000xmlrpc-c-1.33.14/Windows/CleanAll.bat000066400000000000000000000046751236133176700172320ustar00rootroot00000000000000@echo This batch file requires a powerful XDELETE program. One @echo that will REMOVE whole directories recursively ... @echo If you do NOT have such a program, then abort now, and @echo adjust the line below ... @set TEMPX=xdelete -dfrm @echo set TEMPX=%TEMPX% @pause @echo ##################################################### @echo ARE YOU SURE YOU WANT TO DO THIS? Ctrl+C to abort ... @echo ##################################################### @pause @echo CleanAll: Last chance ... ctrl+c to abort ... @pause @echo CleanAll: Cleaning the headers ... call CleanWin32 @echo CleanAll: and removing the SOLUTION files ... call delsln @echo CleanAll: Cleaning the gennmtab generated header ... @if EXIST ..\lib\expat\xmltok\nametab.h del ..\lib\expat\xmltok\nametab.h > nul @echo CleanAll: Cleaning all built binaries ... @if EXIST ..\bin\*.exe del ..\bin\*.exe > nul @if EXIST ..\bin\*.exp del ..\bin\*.exp > nul @if EXIST ..\bin\*.ilk del ..\bin\*.ilk > nul @if EXIST ..\bin\*.lib del ..\bin\*.lib > nul @if EXIST ..\lib\*.lib del ..\lib\*.lib > nul @if EXIST ..\lib\*.dll del ..\lib\*.dll > nul @echo CleanAll: Cleaning test data files ... @if EXIST ..\bin\data\*.xml del ..\bin\data\*.xml > nul @if EXIST ..\bin\data\. rd ..\bin\data > nul @if EXIST ..\bin\. rd ..\bin > nul @echo CleanAll: Cleaning old residual built binaries ... but none should exist ... @if EXIST ..\lib\expat\gennmtab\Debug\. %TEMPX% ..\lib\expat\gennmtab\Debug @if EXIST ..\lib\expat\gennmtab\Release\. %TEMPX% ..\lib\expat\gennmtab\Release @if EXIST ..\lib\expat\xmlparse\Debug\. %TEMPX% ..\lib\expat\xmlparse\Debug @if EXIST ..\lib\expat\xmlparse\DebugDLL\. %TEMPX% ..\lib\expat\xmlparse\DebugDLL @if EXIST ..\lib\expat\xmlparse\Release\. %TEMPX% ..\lib\expat\xmlparse\Release @if EXIST ..\lib\expat\xmlparse\ReleaseDLL\. %TEMPX% ..\lib\expat\xmlparse\ReleaseDLL @if EXIST ..\lib\expat\xmlparse\ReleaseMinSizeDLL\. %TEMPX% ..\lib\expat\xmlparse\ReleaseMinSizeDLL @if EXIST ..\lib\expat\xmltok\Debug\. %TEMPX% ..\lib\expat\xmltok\Debug @if EXIST ..\lib\expat\xmltok\DebugDLL\. %TEMPX% ..\lib\expat\xmltok\DebugDLL @if EXIST ..\lib\expat\xmltok\Release\. %TEMPX% ..\lib\expat\xmltok\Release @if EXIST ..\lib\expat\xmltok\ReleaseDLL\. %TEMPX% ..\lib\expat\xmltok\ReleaseDLL @echo CleanAll: Finally, cleaning the main intermediate directories ... @if EXIST Debug\. %TEMPX% Debug @if EXIST Release\. %TEMPX% Release @echo . @echo CleanAll: Phew ... all done ... @echo . xmlrpc-c-1.33.14/Windows/CleanWin32.bat000066400000000000000000000025531236133176700174150ustar00rootroot00000000000000@echo Windows build @echo This batch file deletes the copied header files, @echo Deleting Win32 header files... @echo ##################################################### @echo IF YOU HAVE MADE CHANGES IN ..\xmlrpc_config.h, ..\include\xmlrpc-c\config.h etc ... @echo THESE CHANGES WILL BE LOST! @echo You should run diffcfg.bat first to check for changes, @echo and updcfg.bat if you have made changes ... @echo ##################################################### @echo ARE YOU SURE YOU WANT TO DO THIS? Ctrl+C to abort ... @echo ##################################################### @pause @set TEMP1= @if NOT EXIST ..\include\xmlrpc-c\config.h goto DN1 del ..\include\xmlrpc-c\config.h > nul @set TEMP1=%TEMP1% ..\include\xmlrpc-c\config.h :DN1 @if NOT EXIST ..\xmlrpc_config.h goto DN2 del ..\xmlrpc_config.h > nul @set TEMP1=%TEMP1% ..\xmlrpc_config.h :DN2 @if NOT EXIST ..\transport_config.h goto DN3 del ..\transport_config.h > nul @set TEMP1=%TEMP1% ..\transport_config.h :DN3 @if NOT EXIST ..\version.h goto DN4 del ..\version.h > nul @set TEMP1=%TEMP1% ..\version.h :DN4 @if NOT EXIST ..\examples\config.h goto DN5 del ..\examples\config.h > nul @set TEMP1=%TEMP1% ..\examples\config.h :DN5 @if "%TEMP1%." == "." goto ALLDN @echo DELETED win32 header files. @echo %TEMP1% @goto END :ALLDN @echo NOne to DELETE ... @goto END :END xmlrpc-c-1.33.14/Windows/ConfigureWin32.bat000066400000000000000000000021061236133176700203060ustar00rootroot00000000000000@REM Windows build @REM This must be RUN once to establish some header files, @REM that are generated by the automake process @echo creating Win32 header files...once only @set TEMPV= @if EXIST ..\include\xmlrpc-c\config.h goto DN1 copy .\win32_config.h ..\include\xmlrpc-c\config.h > nul @set TEMPV=%TEMPV% ..\include\xmlrpc-c\config.h :DN1 @if EXIST ..\xmlrpc_config.h goto DN2 copy .\xmlrpc_win32_config.h ..\xmlrpc_config.h > nul @set TEMPV=%TEMPV% ..\xmlrpc_config.h :DN2 @if EXIST ..\transport_config.h goto DN3 copy .\transport_config_win32.h ..\transport_config.h > nul @set TEMPV=%TEMPV% ..\transport_config.h :DN3 @if EXIST ..\version.h goto DN4 call mkvers @set TEMPV=%TEMPV% ..\version.h :DN4 @if EXIST ..\examples\config.h goto DN5 copy .\xmlrpc_win32_config.h ..\examples\config.h > nul @set TEMPV=%TEMPV% ..\examples\config.h :DN5 @if "%TEMPV%." == "." goto ALLDN @echo Generated the following win32 header files ... @echo %TEMPV% @goto END :ALLDN @echo Using previous copies ... Use CleanWin32.bat to remove, and do again ... @goto END :END xmlrpc-c-1.33.14/Windows/ReadMeWin32.txt000066400000000000000000000055361236133176700176050ustar00rootroot00000000000000Build Instructions For XML-RPC For C/C++ On Windows --------------------------------------------------- ------------------------------------------------------------------------- These instructions are for static link libraries, using Microsoft Visual Studio 7 and later. There are project files to create DLLs, using Visual Studio 2008 or later, in the 'dll' subdirectory. People maintain those project files separately from the rest of the build system, so it's not uncommon for something to work with one but not the other. ------------------------------------------------------------------------- 1. Run the batch file ConfigureWin32.bat, found in the Windows directory. This will copy four(4) headers to the appropriate folders. 2. Load xmlrpc.dsw in MSVC[7,8] or later, and build the Release or Debug configurations. DLL configurations are not included, and may not compile. This build requires that you have a Microsoft SDK, or Plaform SDK installed, since among other things, it uses , and HTTPAPI.LIB, from the SDK. Once built, the rpctest.exe, in the bin folder, should run with no errors, and the xmlrpc_sample_add_server.exe, using port 8080, and xmlrpc_sample_add_sync_client.exe should communicate ... proving 7+5 = 12 ;=)) Have fun. PS: Several other batch files are included in the Windows folder ... delsln.bat - to delete all the MSVC7 and 8 solution file. diffcfg.bat - compare the headers in windows with the version used in the compile. Requires diff.exe to be in the path. updcfg.bat - copy the 3 manually maintained configuration files back to the Windows folder (for distribution). cleawin32.bat - deletes the headers used in the compile. That is does the opposite of ConfigureWin32.bat. cleanall.bat - to remove ALL the binary files created. Requires an xdelete program which will recursively delete an entire folder. There is some historical information in ReadMeOld.txt, which used to be the contents of this file. Some of it is still valid. Developing XML-RPC For C/C++ for Windows ---------------------------------------- If you fix or enhance something in the Windows build system, please send your updates to the Xmlrpc-c maintainer to be included in future releases so others don't have to repeat your work. Output of a Subversion 'diff' is usually the best way to send updates, but you can also send complete files or just a description of the change if that is easier. For the project files, we distribute only MSVC6-compatible DSP and DSW files (which are, of course, usable as input to later versions of MSVC as well). That means if you need to modify something in the project files and you are not using MSVC6, you must edit the project files manually as text files. Modifying them via the IDE would simply generate new files in a format that cannot be used with older MSVC. xmlrpc-c-1.33.14/Windows/UsingCURLinWin32.txt000066400000000000000000000063501236133176700205450ustar00rootroot00000000000000Motivation: Lets say you need to have a Xmlrpc-c client running as a service. In this situation you cannot use WinInet. You can find details of the restriction on the Curl website or various Microsoft KB articles. Your alternative is to use the Curl HTTP client library. This document tells how to use use the Curl library instead of the default Wininet as your client XML transport mechanism. Overview: The default projects in Xmlrpc-c create standalone executables that do not require other DLLs. Therefore, we need to create static link libraries for libcurl. Once we create the link libraries, we add them (plus the requisite curl headers) into the Xmlrpc-c project. Finally, we configure the build to build the curl transport and build client libraries that use it. Finally, we build and test the project. BUILD THE CURL LIBRARY ---------------------- Download the Curl source code. Run the buildconf.bat to generate some additional files. This builds a 'dummy' hugehelp.c, but it can also be built using the src\mkhelp.pl Perl script. You may have to build your own VCPROJ file for CURL, if you want to use MSVC. To build all the CURL library variations, use > nmake /nologo vc-all but note this will use the /MD[d] DLL runtime. Only by adding RTCFGLIB=static to each of the makefile commands will /MT[d] be used. Essentially, for building the static Debug or Release CURL libraries, it is all the sources in the curl\lib folder. Make sure you choose /MT and /MTd for the runtime, and build both using the name 'libcurl.lib'. BUILD XMLRPC-C, LINK WITH CURL ------------------------------ From the step above, you have Debug\libcurl.lib and Release\libcurl.lib. After running xmlrpc-c\Windows\configurewin32.bat, start Visual Studio. In the File View, in the 'xmlrpc' project, in the properties of xmlrpc_curl_transport.c, change "Exclude file from build" from "yes" to "no", for Debug and Release. ==>BUT NOTE: as late as Xmlrpc-c 1.30, this is broken - there is no xmlrpc_curl_transport.c in the projects. You need to add it. If you do, please send your changes to the Xmlrpc-c maintainer to help the next person. In the 'Header Files' section, open the "transport_config.h" file, and change MUST_BUILD_CURL_CLIENT to 1, and the XMLRPC_DEFAULT_TRANSPORT to "curl", if you want. As usual, for each of the "client" projects, and 'rpctest', in the properties, Linker section, you can add the library libcurl.lib on the Input tab, and the relative path to the library in the General tab to something like - ..\..\curl\Debug and ..\..\curl\Release (or wherever you placed the static Curl libraries you built if you didn't follow recommendations above). Or you can adjust the Windows/curlink.h, to directly point to your respective Debug and Release static Curl libraries. Now, Xmlrpc-c should build using the Curl transport. Note, for the final linking, all libraries must be linked the same. A mixture of /MD and /MT will give big linkage problems. Any one project built with the alterate library will show many items defined more than once. And of course, you also cannot mix Debug with Release. That is /MDd with /MD, nor /MTd with /MT. Otherwise, there will be unresolved debug items. xmlrpc-c-1.33.14/Windows/UsingProxyDSP.txt000066400000000000000000000033511236133176700203140ustar00rootroot00000000000000 Using xmlrpc_cpp_proxy.dsp While not included in the main xmlrpc.dsw file, this xmlrpc_cpp_proxy.dsp, if added as a project to the xmlrpc solution, will build bin\xmlrpc_cpp_proxy.exe and xmlrpc_cpp_proxyD.exe, for testing using the default WinINET transport. After you have loaded the xmlrpc_cpp_proxy.dsp, which adds an xmlrpc_cpp_proxy project, it is necessary to ADD a dependance on the xmlrpc library, to complete the link. To do this in say MSVC8, select the xmlrpc_cpp_proxy project, and right mouse click, and in the context menu, select 'Project Dependancies...'. And in the Project Dependancies dialog, check the xmlrpc proejct, then [Ok] ... To test your xmlrpc_cpp_proxy[D].exe - 1. In a console start the server, like - bin/xmlrpc_sample_add_serverD 8080 Note, since this server opens a socket, you may have to enable it on some anti-virus software that detects the socket being established, and 'Unblock' it in the Windows Security Alert system dialog that appears. You can later remove this program from the Firewall exceptions, through Control Panel -> Windows Firewall, selecting the 'Exceptions' tab, where you can also disable this 'blocking' notification, but not recommended. The server should start, and report - Running XML-RPC server... 2. In another console run the cpp proxy client, with say - bin>xmlrpc_cpp_proxyD http://localhost:8080/RPC2 null null The client should connect to the server, and output a 'null' header, and implementation file. If this functions, for a bigger example, try - bin>xmlrpc_cpp_proxyD http://localhost:8080/RPC2 system systemProxy and you should see a better example of a class header, and the implementation code ... 20 December, 2007 EOF xmlrpc-c-1.33.14/Windows/delsln.bat000066400000000000000000000033241236133176700170260ustar00rootroot00000000000000@echo Delete the MSVC7 or MSVC8 soultion files ... @echo ***************************************************** @echo ARE YOU SURE YOU WANT TO DO THIS? Ctrl+C to ABORT ... @echo ***************************************************** @pause @echo Deleting SOLUTION files ... @if EXIST *.sln del *.sln > nul @if EXIST *.vcproj del *.vcproj > nul @if EXIST *.old echo Deleting *.old ... @if EXIST *.old Del *.old > nul @if EXIST *.bak echo Deleting *.bak ... @if EXIST *.bak Del *.bak > nul @if NOT EXIST temp*.* goto dntmp @echo Delete temp*.* ... @del temp*.* > nul :dntmp @if NOT EXIST *.obj goto dnobj @echo Delete *.obj ... @del *.obj > nul :dnobj @if NOT EXIST *.err goto dnerr @echo Delete *.err ... @del *.err > nul :dnerr @if NOT EXIST *.pdb goto dnpdb @echo Delete *.pdb ... @del *.pdb > nul :dnpdb @if NOT EXIST *.lst goto dnlst @echo Delete *.lst ... @del *.lst > nul :dnlst @if EXIST *.pch echo Deleting *.pch ... @if EXIST *.pch Del *.pch > nul @if EXIST *.ilk echo Deleting *.ilk ... @if EXIST *.ilk Del *.ilk > nul @if EXIST *.NCB echo Deleting *.NCB ... @if EXIST *.NCB Del *.NCB > nul @if EXIST *.plg echo Deleting *.plg ... @if EXIST *.plg Del *.plg > nul @if EXIST *.OPT echo Deleting *.OPT ... @if EXIST *.OPT Del *.OPT > nul @if EXIST *.idb echo Deleting *.idb ... @if EXIST *.idb Del *.idb > nul @if EXIST *.aps echo Deleting *.aps ... @if EXIST *.aps Del *.aps > nul @if EXIST *.sbr echo Deleting *.sbr ... @if EXIST *.sbr Del *.sbr > nul @if NOT EXIST *.suo goto DNSUO @attrib -S -R -H *.suo > nul @if EXIST *.suo echo Deleting *.suo ... @if EXIST *.suo Del *.suo > nul :DNSUO @if EXIST *.user echo Deleting *.user ... @if EXIST *.user Del *.user > nul @echo All done ... xmlrpc-c-1.33.14/Windows/diffcfg.bat000066400000000000000000000004511236133176700171330ustar00rootroot00000000000000diff -us win32_config.h ..\include\xmlrpc-c\config.h > tempcfg.diff diff -us xmlrpc_win32_config.h ..\xmlrpc_config.h >> tempcfg.diff diff -us transport_config_win32.h ..\transport_config.h >> tempcfg.diff diff -us xmlrpc_win32_config.h ..\examples\config.h >> tempcfg.diff np tempcfg.diff xmlrpc-c-1.33.14/Windows/mkvers.bat000066400000000000000000000026011236133176700170510ustar00rootroot00000000000000@if EXIST ..\version.h goto SHOW @if NOT EXIST ..\version.mk goto ERR1 @if NOT EXIST mkvers1.bat goto ERR2 @echo updating/creating ..\version.h ... @set TEMP1=1 @for /F "skip=8 tokens=3" %%i in (..\version.mk) do @call mkvers1 %%i @if "%TEMPX1%." == "." goto NOX1 @if "%TEMPX2%." == "." goto NOX1 @if "%TEMPX3%." == "." goto NOX1 @set TEMP1=..\version.h @echo #ifndef XMLRPC_C_VERSION_INCLUDED > %TEMP1% @echo #define XMLRPC_C_VERSION_INCLUDED >> %TEMP1% @echo /* generated by Windows/mkvers.bat on %DATE% ... */ >> %TEMP1% @echo #define XMLRPC_C_VERSION "%TEMPX1%.%TEMPX2%.%TEMPX3%" >> %TEMP1% @echo #define XMLRPC_VERSION_MAJOR %TEMPX1% >> %TEMP1% @echo #define XMLRPC_VERSION_MINOR %TEMPX2% >> %TEMP1% @echo #define XMLRPC_VERSION_POINT %TEMPX3% >> %TEMP1% @echo #endif >> %TEMP1% type %TEMP1% @echo ..\version.h set to the above ... @set TEMP1= @set TEMPX1= @set TEMPX2= @set TEMPX3= @goto END :NOX1 @echo Some error occurred in the batch process ... @goto NOVER :NOVER @echo Failed to create ..\version.h . @pause @goto END :ERR1 @echo Can not locate ..\version.mk ... check name, location ... @pause @goto END :ERR2 @echo Can not locate mkvers1.bat ... check name, location ... @pause @goto END :SHOW @echo ..\version.h already exist, with version ... @type ..\version.h @echo Delete this file if you wish to redo it ... @pause @goto END :END xmlrpc-c-1.33.14/Windows/mkvers1.bat000066400000000000000000000010401236133176700171260ustar00rootroot00000000000000@if "%1." == "." goto ERR2 @if "%TEMP1%." == "." goto ERR1 @if "%TEMP1%" == "1" goto SET1 @if "%TEMP1%" == "2" goto SET2 @if "%TEMP1%" == "3" goto SET3 @echo environment variable has an invalid value %TEMP1% ... @goto ERR2 :SET1 @set TEMPX1=%1 @set TEMP1=2 @goto END :SET2 @set TEMPX2=%1 @set TEMP1=3 @goto END :SET3 @set TEMPX3=%1 @set TEMP1=4 @goto END :ERR1 @echo Environment variable TEMP1 not set ... :ERR2 @echo This batch is only intended to be run from within UPDVERS.BAT ... @pause @goto END :END xmlrpc-c-1.33.14/Windows/project/000077500000000000000000000000001236133176700165215ustar00rootroot00000000000000xmlrpc-c-1.33.14/Windows/project/vs2008/000077500000000000000000000000001236133176700174635ustar00rootroot00000000000000xmlrpc-c-1.33.14/Windows/project/vs2008/cpptest.vcproj000066400000000000000000000517521236133176700224040ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/gennmtab.vcproj000066400000000000000000000517211236133176700225110ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/rpctest.vcproj000066400000000000000000000600011236133176700223710ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/sample_add_asynch_client.vcproj000066400000000000000000000510261236133176700257100ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/sample_add_server.vcproj000066400000000000000000000477521236133176700244060ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/sample_add_server_w32httpsys.vcproj000066400000000000000000000477431236133176700265400ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/sample_add_sync_client.vcproj000066400000000000000000000500201236133176700253700ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/sample_auth_client.vcproj000066400000000000000000000477731236133176700245720ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/tool_xmlrpc-transport.vcproj000066400000000000000000000470571236133176700253210ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/tool_xmlrpc.vcproj000066400000000000000000000470171236133176700232630ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc.sln000066400000000000000000001161531236133176700215150ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_xmlparse", "xmlrpc_xmlparse.vcproj", "{40B0756D-AFEE-4A38-9F38-A372CE431404}" ProjectSection(ProjectDependencies) = postProject {BD9F6041-A272-462D-8C41-87CEF1F11408} = {BD9F6041-A272-462D-8C41-87CEF1F11408} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_xmltok", "xmlrpc_xmltok.vcproj", "{BD9F6041-A272-462D-8C41-87CEF1F11408}" ProjectSection(ProjectDependencies) = postProject {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412} = {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gennmtab", "gennmtab.vcproj", "{99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_util", "xmlrpc_util.vcproj", "{29FBABB6-E36A-4559-9514-B3DAF6AE1416}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc", "xmlrpc.vcproj", "{226AB06F-60CA-4B21-9040-C6ECC0581522}" ProjectSection(ProjectDependencies) = postProject {40B0756D-AFEE-4A38-9F38-A372CE431404} = {40B0756D-AFEE-4A38-9F38-A372CE431404} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_abyss", "xmlrpc_abyss.vcproj", "{20A8F64B-F738-4D32-A798-A65AD8291541}" ProjectSection(ProjectDependencies) = postProject {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_server", "xmlrpc_server.vcproj", "{74B67128-BC84-4BCB-A256-9286B6371552}" ProjectSection(ProjectDependencies) = postProject {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_server_abyss", "xmlrpc_server_abyss.vcproj", "{E98186CB-F1B0-40A6-87A5-77B13A3F1600}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {20A8F64B-F738-4D32-A798-A65AD8291541} = {20A8F64B-F738-4D32-A798-A65AD8291541} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_server_cgi", "xmlrpc_server_cgi.vcproj", "{A2AAAF37-F382-4A11-8D86-53B589921616}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_server_w32httpsys", "xmlrpc_server_w32httpsys.vcproj", "{0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc_client", "xmlrpc_client.vcproj", "{28BB53D9-D487-41DF-BBB3-FDB5846D1630}" ProjectSection(ProjectDependencies) = postProject {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_add_asynch_client", "sample_add_asynch_client.vcproj", "{2D4A179E-E2BA-4ED9-934E-7E54C08F1652}" ProjectSection(ProjectDependencies) = postProject {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {28BB53D9-D487-41DF-BBB3-FDB5846D1630} = {28BB53D9-D487-41DF-BBB3-FDB5846D1630} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_add_server", "sample_add_server.vcproj", "{BEEB1B9C-BAF4-4B54-AB51-891156301702}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {E98186CB-F1B0-40A6-87A5-77B13A3F1600} = {E98186CB-F1B0-40A6-87A5-77B13A3F1600} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_add_server_w32httpsys", "sample_add_server_w32httpsys.vcproj", "{B6887828-9480-4D4D-9CFC-AE4980D41707}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622} = {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_add_sync_client", "sample_add_sync_client.vcproj", "{A7A81BBD-C84D-479A-A9BD-194ADA3B1710}" ProjectSection(ProjectDependencies) = postProject {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {28BB53D9-D487-41DF-BBB3-FDB5846D1630} = {28BB53D9-D487-41DF-BBB3-FDB5846D1630} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_auth_client", "sample_auth_client.vcproj", "{29A2BBC4-9ED9-4162-817C-FEEB36FB1714}" ProjectSection(ProjectDependencies) = postProject {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {28BB53D9-D487-41DF-BBB3-FDB5846D1630} = {28BB53D9-D487-41DF-BBB3-FDB5846D1630} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpctest", "rpctest.vcproj", "{4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {20A8F64B-F738-4D32-A798-A65AD8291541} = {20A8F64B-F738-4D32-A798-A65AD8291541} {40B0756D-AFEE-4A38-9F38-A372CE431404} = {40B0756D-AFEE-4A38-9F38-A372CE431404} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {E98186CB-F1B0-40A6-87A5-77B13A3F1600} = {E98186CB-F1B0-40A6-87A5-77B13A3F1600} {28BB53D9-D487-41DF-BBB3-FDB5846D1630} = {28BB53D9-D487-41DF-BBB3-FDB5846D1630} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libxmlrpc++", "xmlrpc__.vcproj", "{3E7064F3-6200-4C39-85BE-775931D21828}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {20A8F64B-F738-4D32-A798-A65AD8291541} = {20A8F64B-F738-4D32-A798-A65AD8291541} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {E98186CB-F1B0-40A6-87A5-77B13A3F1600} = {E98186CB-F1B0-40A6-87A5-77B13A3F1600} {28BB53D9-D487-41DF-BBB3-FDB5846D1630} = {28BB53D9-D487-41DF-BBB3-FDB5846D1630} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cpptest", "cpptest.vcproj", "{26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {20A8F64B-F738-4D32-A798-A65AD8291541} = {20A8F64B-F738-4D32-A798-A65AD8291541} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {28BB53D9-D487-41DF-BBB3-FDB5846D1630} = {28BB53D9-D487-41DF-BBB3-FDB5846D1630} {3E7064F3-6200-4C39-85BE-775931D21828} = {3E7064F3-6200-4C39-85BE-775931D21828} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc", "tool_xmlrpc.vcproj", "{4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}" ProjectSection(ProjectDependencies) = postProject {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {28BB53D9-D487-41DF-BBB3-FDB5846D1630} = {28BB53D9-D487-41DF-BBB3-FDB5846D1630} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlrpc_transport", "tool_xmlrpc-transport.vcproj", "{4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}" ProjectSection(ProjectDependencies) = postProject {74B67128-BC84-4BCB-A256-9286B6371552} = {74B67128-BC84-4BCB-A256-9286B6371552} {226AB06F-60CA-4B21-9040-C6ECC0581522} = {226AB06F-60CA-4B21-9040-C6ECC0581522} {29FBABB6-E36A-4559-9514-B3DAF6AE1416} = {29FBABB6-E36A-4559-9514-B3DAF6AE1416} {28BB53D9-D487-41DF-BBB3-FDB5846D1630} = {28BB53D9-D487-41DF-BBB3-FDB5846D1630} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug-DLL|Win32 = Debug-DLL|Win32 Debug-DLL|x64 = Debug-DLL|x64 Debug-Static|Win32 = Debug-Static|Win32 Debug-Static|x64 = Debug-Static|x64 Release-DLL|Win32 = Release-DLL|Win32 Release-DLL|x64 = Release-DLL|x64 Release-Static|Win32 = Release-Static|Win32 Release-Static|x64 = Release-Static|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {40B0756D-AFEE-4A38-9F38-A372CE431404}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Debug-Static|x64.Build.0 = Debug-Static|x64 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Release-DLL|x64.Build.0 = Release-DLL|x64 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Release-Static|Win32.Build.0 = Release-Static|Win32 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Release-Static|x64.ActiveCfg = Release-Static|x64 {40B0756D-AFEE-4A38-9F38-A372CE431404}.Release-Static|x64.Build.0 = Release-Static|x64 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Debug-Static|x64.Build.0 = Debug-Static|x64 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Release-DLL|x64.Build.0 = Release-DLL|x64 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Release-Static|Win32.Build.0 = Release-Static|Win32 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Release-Static|x64.ActiveCfg = Release-Static|x64 {BD9F6041-A272-462D-8C41-87CEF1F11408}.Release-Static|x64.Build.0 = Release-Static|x64 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Debug-Static|x64.Build.0 = Debug-Static|x64 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Release-DLL|x64.Build.0 = Release-DLL|x64 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Release-Static|Win32.Build.0 = Release-Static|Win32 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Release-Static|x64.ActiveCfg = Release-Static|x64 {99BD200E-A4D5-4ED4-9D00-A6A19EFE1412}.Release-Static|x64.Build.0 = Release-Static|x64 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Debug-Static|x64.Build.0 = Debug-Static|x64 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Release-DLL|x64.Build.0 = Release-DLL|x64 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Release-Static|Win32.Build.0 = Release-Static|Win32 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Release-Static|x64.ActiveCfg = Release-Static|x64 {29FBABB6-E36A-4559-9514-B3DAF6AE1416}.Release-Static|x64.Build.0 = Release-Static|x64 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Debug-Static|x64.Build.0 = Debug-Static|x64 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Release-DLL|x64.Build.0 = Release-DLL|x64 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Release-Static|Win32.Build.0 = Release-Static|Win32 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Release-Static|x64.ActiveCfg = Release-Static|x64 {226AB06F-60CA-4B21-9040-C6ECC0581522}.Release-Static|x64.Build.0 = Release-Static|x64 {20A8F64B-F738-4D32-A798-A65AD8291541}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {20A8F64B-F738-4D32-A798-A65AD8291541}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {20A8F64B-F738-4D32-A798-A65AD8291541}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {20A8F64B-F738-4D32-A798-A65AD8291541}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {20A8F64B-F738-4D32-A798-A65AD8291541}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {20A8F64B-F738-4D32-A798-A65AD8291541}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {20A8F64B-F738-4D32-A798-A65AD8291541}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {20A8F64B-F738-4D32-A798-A65AD8291541}.Debug-Static|x64.Build.0 = Debug-Static|x64 {20A8F64B-F738-4D32-A798-A65AD8291541}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {20A8F64B-F738-4D32-A798-A65AD8291541}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {20A8F64B-F738-4D32-A798-A65AD8291541}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {20A8F64B-F738-4D32-A798-A65AD8291541}.Release-DLL|x64.Build.0 = Release-DLL|x64 {20A8F64B-F738-4D32-A798-A65AD8291541}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {20A8F64B-F738-4D32-A798-A65AD8291541}.Release-Static|Win32.Build.0 = Release-Static|Win32 {20A8F64B-F738-4D32-A798-A65AD8291541}.Release-Static|x64.ActiveCfg = Release-Static|x64 {20A8F64B-F738-4D32-A798-A65AD8291541}.Release-Static|x64.Build.0 = Release-Static|x64 {74B67128-BC84-4BCB-A256-9286B6371552}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {74B67128-BC84-4BCB-A256-9286B6371552}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {74B67128-BC84-4BCB-A256-9286B6371552}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {74B67128-BC84-4BCB-A256-9286B6371552}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {74B67128-BC84-4BCB-A256-9286B6371552}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {74B67128-BC84-4BCB-A256-9286B6371552}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {74B67128-BC84-4BCB-A256-9286B6371552}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {74B67128-BC84-4BCB-A256-9286B6371552}.Debug-Static|x64.Build.0 = Debug-Static|x64 {74B67128-BC84-4BCB-A256-9286B6371552}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {74B67128-BC84-4BCB-A256-9286B6371552}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {74B67128-BC84-4BCB-A256-9286B6371552}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {74B67128-BC84-4BCB-A256-9286B6371552}.Release-DLL|x64.Build.0 = Release-DLL|x64 {74B67128-BC84-4BCB-A256-9286B6371552}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {74B67128-BC84-4BCB-A256-9286B6371552}.Release-Static|Win32.Build.0 = Release-Static|Win32 {74B67128-BC84-4BCB-A256-9286B6371552}.Release-Static|x64.ActiveCfg = Release-Static|x64 {74B67128-BC84-4BCB-A256-9286B6371552}.Release-Static|x64.Build.0 = Release-Static|x64 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Debug-Static|x64.Build.0 = Debug-Static|x64 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Release-DLL|x64.Build.0 = Release-DLL|x64 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Release-Static|Win32.Build.0 = Release-Static|Win32 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Release-Static|x64.ActiveCfg = Release-Static|x64 {E98186CB-F1B0-40A6-87A5-77B13A3F1600}.Release-Static|x64.Build.0 = Release-Static|x64 {A2AAAF37-F382-4A11-8D86-53B589921616}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {A2AAAF37-F382-4A11-8D86-53B589921616}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {A2AAAF37-F382-4A11-8D86-53B589921616}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {A2AAAF37-F382-4A11-8D86-53B589921616}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {A2AAAF37-F382-4A11-8D86-53B589921616}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {A2AAAF37-F382-4A11-8D86-53B589921616}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {A2AAAF37-F382-4A11-8D86-53B589921616}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {A2AAAF37-F382-4A11-8D86-53B589921616}.Debug-Static|x64.Build.0 = Debug-Static|x64 {A2AAAF37-F382-4A11-8D86-53B589921616}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {A2AAAF37-F382-4A11-8D86-53B589921616}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {A2AAAF37-F382-4A11-8D86-53B589921616}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {A2AAAF37-F382-4A11-8D86-53B589921616}.Release-DLL|x64.Build.0 = Release-DLL|x64 {A2AAAF37-F382-4A11-8D86-53B589921616}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {A2AAAF37-F382-4A11-8D86-53B589921616}.Release-Static|Win32.Build.0 = Release-Static|Win32 {A2AAAF37-F382-4A11-8D86-53B589921616}.Release-Static|x64.ActiveCfg = Release-Static|x64 {A2AAAF37-F382-4A11-8D86-53B589921616}.Release-Static|x64.Build.0 = Release-Static|x64 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Debug-Static|x64.Build.0 = Debug-Static|x64 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Release-DLL|x64.Build.0 = Release-DLL|x64 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Release-Static|Win32.Build.0 = Release-Static|Win32 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Release-Static|x64.ActiveCfg = Release-Static|x64 {0EECB080-FC8F-4C46-9FB7-5DB22F9D1622}.Release-Static|x64.Build.0 = Release-Static|x64 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Debug-Static|x64.Build.0 = Debug-Static|x64 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Release-DLL|x64.Build.0 = Release-DLL|x64 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Release-Static|Win32.Build.0 = Release-Static|Win32 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Release-Static|x64.ActiveCfg = Release-Static|x64 {28BB53D9-D487-41DF-BBB3-FDB5846D1630}.Release-Static|x64.Build.0 = Release-Static|x64 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Debug-Static|x64.Build.0 = Debug-Static|x64 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Release-DLL|x64.Build.0 = Release-DLL|x64 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Release-Static|Win32.Build.0 = Release-Static|Win32 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Release-Static|x64.ActiveCfg = Release-Static|x64 {2D4A179E-E2BA-4ED9-934E-7E54C08F1652}.Release-Static|x64.Build.0 = Release-Static|x64 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Debug-Static|x64.Build.0 = Debug-Static|x64 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Release-DLL|x64.Build.0 = Release-DLL|x64 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Release-Static|Win32.Build.0 = Release-Static|Win32 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Release-Static|x64.ActiveCfg = Release-Static|x64 {BEEB1B9C-BAF4-4B54-AB51-891156301702}.Release-Static|x64.Build.0 = Release-Static|x64 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Debug-Static|x64.Build.0 = Debug-Static|x64 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Release-DLL|x64.Build.0 = Release-DLL|x64 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Release-Static|Win32.Build.0 = Release-Static|Win32 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Release-Static|x64.ActiveCfg = Release-Static|x64 {B6887828-9480-4D4D-9CFC-AE4980D41707}.Release-Static|x64.Build.0 = Release-Static|x64 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Debug-Static|x64.Build.0 = Debug-Static|x64 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Release-DLL|x64.Build.0 = Release-DLL|x64 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Release-Static|Win32.Build.0 = Release-Static|Win32 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Release-Static|x64.ActiveCfg = Release-Static|x64 {A7A81BBD-C84D-479A-A9BD-194ADA3B1710}.Release-Static|x64.Build.0 = Release-Static|x64 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Debug-Static|x64.Build.0 = Debug-Static|x64 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Release-DLL|x64.Build.0 = Release-DLL|x64 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Release-Static|Win32.Build.0 = Release-Static|Win32 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Release-Static|x64.ActiveCfg = Release-Static|x64 {29A2BBC4-9ED9-4162-817C-FEEB36FB1714}.Release-Static|x64.Build.0 = Release-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Debug-Static|x64.Build.0 = Debug-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Release-DLL|x64.Build.0 = Release-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Release-Static|Win32.Build.0 = Release-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Release-Static|x64.ActiveCfg = Release-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1722}.Release-Static|x64.Build.0 = Release-Static|x64 {3E7064F3-6200-4C39-85BE-775931D21828}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {3E7064F3-6200-4C39-85BE-775931D21828}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {3E7064F3-6200-4C39-85BE-775931D21828}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {3E7064F3-6200-4C39-85BE-775931D21828}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {3E7064F3-6200-4C39-85BE-775931D21828}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {3E7064F3-6200-4C39-85BE-775931D21828}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {3E7064F3-6200-4C39-85BE-775931D21828}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {3E7064F3-6200-4C39-85BE-775931D21828}.Debug-Static|x64.Build.0 = Debug-Static|x64 {3E7064F3-6200-4C39-85BE-775931D21828}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {3E7064F3-6200-4C39-85BE-775931D21828}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {3E7064F3-6200-4C39-85BE-775931D21828}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {3E7064F3-6200-4C39-85BE-775931D21828}.Release-DLL|x64.Build.0 = Release-DLL|x64 {3E7064F3-6200-4C39-85BE-775931D21828}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {3E7064F3-6200-4C39-85BE-775931D21828}.Release-Static|Win32.Build.0 = Release-Static|Win32 {3E7064F3-6200-4C39-85BE-775931D21828}.Release-Static|x64.ActiveCfg = Release-Static|x64 {3E7064F3-6200-4C39-85BE-775931D21828}.Release-Static|x64.Build.0 = Release-Static|x64 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Debug-Static|x64.Build.0 = Debug-Static|x64 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Release-DLL|x64.Build.0 = Release-DLL|x64 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Release-Static|Win32.Build.0 = Release-Static|Win32 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Release-Static|x64.ActiveCfg = Release-Static|x64 {26FB3E14-7E0C-4B0C-AB1E-CFE4B48A1856}.Release-Static|x64.Build.0 = Release-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Debug-Static|x64.Build.0 = Debug-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Release-DLL|x64.Build.0 = Release-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Release-Static|Win32.Build.0 = Release-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Release-Static|x64.ActiveCfg = Release-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1940}.Release-Static|x64.Build.0 = Release-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Debug-DLL|Win32.ActiveCfg = Debug-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Debug-DLL|Win32.Build.0 = Debug-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Debug-DLL|x64.ActiveCfg = Debug-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Debug-DLL|x64.Build.0 = Debug-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Debug-Static|x64.Build.0 = Debug-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Release-DLL|Win32.ActiveCfg = Release-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Release-DLL|Win32.Build.0 = Release-DLL|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Release-DLL|x64.ActiveCfg = Release-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Release-DLL|x64.Build.0 = Release-DLL|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Release-Static|Win32.Build.0 = Release-Static|Win32 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Release-Static|x64.ActiveCfg = Release-Static|x64 {4CFB235E-56AE-4BF2-BE67-8FD4AF5F1942}.Release-Static|x64.Build.0 = Release-Static|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc.vcproj000066400000000000000000000455311236133176700222250ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc__.vcproj000066400000000000000000001611401236133176700225160ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_abyss.vcproj000066400000000000000000001620471236133176700234300ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_client.vcproj000066400000000000000000000443171236133176700235640ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_server.vcproj000066400000000000000000000433161236133176700236120ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_server_abyss.vcproj000066400000000000000000000433111236133176700250060ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_server_cgi.vcproj000066400000000000000000000430351236133176700244320ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_server_w32httpsys.vcproj000066400000000000000000000443411236133176700257430ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_util.vcproj000066400000000000000000000455111236133176700232600ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_xmlparse.vcproj000066400000000000000000000443561236133176700241440ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/project/vs2008/xmlrpc_xmltok.vcproj000066400000000000000000000502621236133176700236200ustar00rootroot00000000000000 xmlrpc-c-1.33.14/Windows/socketpair.cpp000066400000000000000000000040731236133176700177270ustar00rootroot00000000000000#include int xmlrpc_win32_socketpair(int const domain, int const type, int const protocol, SOCKET socks[2]) { bool error; error = false; // initial value SOCKET listener; listener = socket(AF_INET, SOCK_STREAM, 0); if (listener == INVALID_SOCKET) error = true; else { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(0x7f000001); addr.sin_port = 0; int rc; rc = bind(listener, (const struct sockaddr*) &addr, sizeof(addr)); if (rc == SOCKET_ERROR) error = true; else { int addrlen; int rc; addrlen = sizeof(addr); // initial value rc = getsockname(listener, (struct sockaddr*) &addr, &addrlen); if (rc == SOCKET_ERROR) error = true; else { int rc; rc = listen(listener, 1); if (rc == SOCKET_ERROR) error = true; else { socks[0] = socket(AF_INET, SOCK_STREAM, 0); if (socks[0] == INVALID_SOCKET) error = true; else { int rc; rc = connect(socks[0], (const struct sockaddr*) &addr, sizeof(addr)); if (rc == SOCKET_ERROR) error = true; else { socks[1] = accept(listener, NULL, NULL); if (socks[1] == INVALID_SOCKET) error = true; } if (error) closesocket(socks[0]); } } } } closesocket(listener); } return error ? -1 : 0; } xmlrpc-c-1.33.14/Windows/transport_config_win32.h000066400000000000000000000011001236133176700216170ustar00rootroot00000000000000/* Win32 version of transport_config.h. For other platforms, this is generated automatically, but for Windows, someone generates it manually. Nonetheless, we keep it looking as much as possible like the automatically generated one to make it easier to maintain (e.g. you can compare the two and see why something builds differently for Windows that for some other platform). */ #define MUST_BUILD_WININET_CLIENT 1 #define MUST_BUILD_CURL_CLIENT 0 #define MUST_BUILD_LIBWWW_CLIENT 0 static const char * const XMLRPC_DEFAULT_TRANSPORT = "wininet"; xmlrpc-c-1.33.14/Windows/updcfg.bat000066400000000000000000000006011236133176700170100ustar00rootroot00000000000000@echo This will COPY the current config.h, xmlrpc_config.h, transprt_config.h, @echo version.h, overwriting files in this 'Windows' folder! @echo ARE YOU SURE YOU WANT TO DO THIS??? Ctrl+C to abort ... @pause copy ..\include\xmlrpc-c\config.h win32_config.h copy ..\xmlrpc_config.h xmlrpc_win32_config.h copy ..\transport_config.h transport_config_win32.h @echo all done ... xmlrpc-c-1.33.14/Windows/win32_config.h000066400000000000000000000022161236133176700175140ustar00rootroot00000000000000#ifndef XMLRPC_C_CONFIG_H_INCLUDED #define XMLRPC_C_CONFIG_H_INCLUDED /* This file, part of XML-RPC For C/C++, is meant to define characteristics of this particular installation that the other header files need in order to compile correctly when #included in Xmlrpc-c user code. Those header files #include this one. This file was created by a make rule. */ #define XMLRPC_HAVE_WCHAR 1 #ifdef WIN32 /* SOCKET is a type defined by . Anyone who uses XMLRPC_SOCKET on a WIN32 system must #include */ #define XMLRPC_SOCKET SOCKET #define XMLRPC_HAVE_TIMEVAL 0 #define XMLRPC_HAVE_TIMESPEC 0 #define XMLRPC_HAVE_PTHREAD 0 #else #define XMLRPC_SOCKET int #define XMLRPC_HAVE_TIMEVAL 1 #define XMLRPC_HAVE_TIMESPEC 1 #define XMLRPC_HAVE_PTHREAD 1 #endif #if defined(_MSC_VER) /* Newer MSVC has long long, but MSVC 6 does not */ #define XMLRPC_INT64 __int64 #define XMLRPC_INT32 __int32 #define XMLRPC_PRId64 PRId64 #else #define XMLRPC_INT64 long long #define XMLRPC_INT32 int #define XMLRPC_PRId64 "I64d" #endif #endif xmlrpc-c-1.33.14/Windows/xmlrpc_win32_config.h000066400000000000000000000157351236133176700211130ustar00rootroot00000000000000/* Win32 version of xmlrpc_config.h. For other platforms, this is generated automatically, but for Windows, someone generates it manually. Nonetheless, we keep it looking as much as possible like the automatically generated one to make it easier to maintain (e.g. you can compare the two and see why something builds differently for Windows than for some other platform). The purpose of this file is to define stuff particular to the build environment being used to build Xmlrpc-c. Xmlrpc-c source files can #include this file and have build-environment-independent source code. A major goal of this file is to reduce conditional compilation in the other source files as much as possible. Even more, we want to avoid having to generate source code particular to a build environment except in this file. This file is NOT meant to be used by any code outside of the Xmlrpc-c source tree. There is a similar file that gets installed as that performs the same function for Xmlrpc-c interface header files that get compiled as part of a user's program. Logical macros are 0 or 1 instead of the more traditional defined and undefined. That's so we can distinguish when compiling code between "false" and some problem with the code. */ #ifndef XMLRPC_CONFIG_H_INCLUDED #define XMLRPC_CONFIG_H_INCLUDED /* From xmlrpc_amconfig.h */ #define HAVE__STRICMP 1 #define HAVE__STRTOUI64 1 /* Name of package */ #define PACKAGE "xmlrpc-c" /*----------------------------------*/ #ifndef HAVE_SETGROUPS #define HAVE_SETGROUPS 0 #endif #ifndef HAVE_ASPRINTF #define HAVE_ASPRINTF 0 #endif #ifndef HAVE_SETENV #define HAVE_SETENV 0 #endif #ifndef HAVE_PSELECT #define HAVE_PSELECT 0 #endif #ifndef HAVE_WCSNCMP #define HAVE_WCSNCMP 1 #endif #ifndef HAVE_GETTIMEOFDAY #define HAVE_GETTIMEOFDAY 0 #endif #ifndef HAVE_LOCALTIME_R #define HAVE_LOCALTIME_R 0 #endif #ifndef HAVE_GMTIME_R #define HAVE_GMTIME_R 0 #endif #ifndef HAVE_STRCASECMP #define HAVE_STRCASECMP 0 #endif #ifndef HAVE_STRICMP #define HAVE_STRICMP 0 #endif #ifndef HAVE__STRICMP #define HAVE__STRICMP 0 #endif #define HAVE_WCHAR_H 1 #define HAVE_SYS_FILIO_H 0 #define HAVE_SYS_IOCTL_H 0 #define HAVE_SYS_SELECT_H 0 #define VA_LIST_IS_ARRAY 0 #define HAVE_LIBWWW_SSL 0 /* Used to mark an unused function parameter */ #define ATTR_UNUSED #define DIRECTORY_SEPARATOR "\\" #define HAVE_UNICODE_WCHAR 1 /* Xmlrpc-c code uses __inline__ to declare functions that should be compiled as inline code. GNU C recognizes the __inline__ keyword. Others recognize 'inline' or '__inline' or nothing at all to say a function should be inlined. We could make 'configure' simply do a trial compile to figure out which one, but for now, this approximation is easier: */ #if (!defined(__GNUC__)) #if (!defined(__inline__)) #if (defined(__sgi) || defined(_AIX) || defined(_MSC_VER)) #define __inline__ __inline #else #define __inline__ #endif #endif #endif /* MSVCRT means we're using the Microsoft Visual C++ runtime library */ #ifdef _MSC_VER /* The compiler is Microsoft Visual C++. */ #define MSVCRT _MSC_VER #else #define MSVCRT 0 #endif #if MSVCRT /* The MSVC runtime library _does_ have a 'struct timeval', but it is part of the Winsock interface (along with select(), which is probably its intended use), so isn't intended for use for general timekeeping. */ #define HAVE_TIMEVAL 0 #define HAVE_TIMESPEC 0 #else #define HAVE_TIMEVAL 1 /* timespec is Posix.1b. If we need to work on a non-Posix.1b non-Windows system, we'll have to figure out how to make Configure determine this. */ #define HAVE_TIMESPEC 1 #endif #if MSVCRT #define HAVE_WINDOWS_THREAD 1 #else #define HAVE_WINDOWS_THREAD 0 #endif /* Some people have and use pthreads on Windows. See http://sourceware.org/pthreads-win32 . For that case, we can set HAVE_PTHREAD to 1. The builder prefers to use pthreads if it has a choice. */ #define HAVE_PTHREAD 0 /* Note that the return value of XMLRPC_VSNPRINTF is int on Windows, ssize_t on POSIX. */ #if MSVCRT #define XMLRPC_VSNPRINTF _vsnprintf #else #define XMLRPC_VSNPRINTF vsnprintf #endif #if MSVCRT #define HAVE_REGEX 0 #else #define HAVE_REGEX 1 #endif #if MSVCRT #define XMLRPC_SOCKETPAIR xmlrpc_win32_socketpair #define XMLRPC_CLOSESOCKET closesocket #else #define XMLRPC_SOCKETPAIR socketpair #define XMLRPC_CLOSESOCKET close #endif #if defined(_MSC_VER) && (_MSC_VER >= 1400) /* Starting with MSVC 8, the runtime library defines various POSIX functions such as strdup() whose names violate the ISO C standard (the standard says the strXXX names are reserved for the standard), but warns you of the standards violation. That warning is 4996, along with other warnings that tell you you're using a function that Microsoft thinks you shouldn't. Well, POSIX is more important than that element of ISO C, so we disable that warning. FYI, msvcrt also defines _strdup(), etc, which doesn't violate the naming standard. But since other environments don't define _strdup(), we can't use it in portable code. */ #pragma warning(disable:4996) #endif /* Warning C4090 is "different 'const' qualifiers". We disable this warning because MSVC erroneously issues it when there is in fact no difference in const qualifiers: const char ** p; void * q; q = p; Note that both p and q are pointers to non-const. We have seen this in MSVC 7.1, 8, and 9 (but not 6). */ #pragma warning(disable:4090) #if HAVE_STRTOLL # define XMLRPC_STRTOLL strtoll #elif HAVE_STRTOQ # define XMLRPC_STRTOLL strtoq /* Interix */ #elif HAVE___STRTOLL # define XMLRPC_STRTOLL __strtoll /* HP-UX <= 11.11 */ #elif HAVE__STRTOUI64 #define XMLRPC_STRTOLL _strtoui64 /* Windows MSVC */ #endif #if HAVE_STRTOULL # define XMLRPC_STRTOULL strtoull #elif HAVE_STRTOUQ # define XMLRPC_STRTOULL strtouq /* Interix */ #elif HAVE___STRTOULL # define XMLRPC_STRTOULL __strtoull /* HP-UX <= 11.11 */ #elif HAVE__STRTOUI64 #define XMLRPC_STRTOULL _strtoui64 /* Windows MSVC */ #endif #if MSVCRT #define snprintf _snprintf #define popen _popen #endif /* S_IRUSR is POSIX, defined in Some old BSD systems and Windows systems have S_IREAD instead. Most Unix today (2011) has both. In 2011, Android has S_IRUSR and not S_IREAD. Some Windows (2011) has _S_IREAD. We're ignoring S_IREAD now to see if anyone misses it. If there are still users that need it, we can handle it here. */ #if MSVCRT #define XMLRPC_S_IWUSR _S_IWRITE #define XMLRPC_S_IRUSR _S_IREAD #else #define XMLRPC_S_IWUSR S_IWUSR #define XMLRPC_S_IRUSR S_IRUSR #endif #if MSVCRT #define XMLRPC_CHDIR _chdir #else #define XMLRPC_CHDIR chdir #endif #endif xmlrpc-c-1.33.14/aclocal.m4000066400000000000000000000440651236133176700152720ustar00rootroot00000000000000dnl aclocal.m4 generated automatically by aclocal 1.4 dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A dnl PARTICULAR PURPOSE. # Like AC_CONFIG_HEADER, but automatically create stamp file. AC_DEFUN(AM_CONFIG_HEADER, [AC_PREREQ([2.12]) AC_CONFIG_HEADER([$1]) dnl When config.status generates a header, we must update the stamp-h file. dnl This file resides in the same directory as the config header dnl that is generated. We must strip everything past the first ":", dnl and everything past the last "/". AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, <>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, <>; do case " <<$>>CONFIG_HEADERS " in *" <<$>>am_file "*<<)>> echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx ;; esac am_indx=`expr "<<$>>am_indx" + 1` done<<>>dnl>>) changequote([,]))]) # Do all the work for Automake. This macro actually does too much -- # some checks are only needed if your package does certain things. # But this isn't really a big deal. # serial 1 dnl Usage: dnl AM_INIT_AUTOMAKE(package,version, [no-define]) AC_DEFUN(AM_INIT_AUTOMAKE, [AC_REQUIRE([AC_PROG_INSTALL]) PACKAGE=[$1] AC_SUBST(PACKAGE) VERSION=[$2] AC_SUBST(VERSION) dnl test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi ifelse([$3],, AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) AC_REQUIRE([AM_SANITY_CHECK]) AC_REQUIRE([AC_ARG_PROGRAM]) dnl FIXME This is truly gross. missing_dir=`cd $ac_aux_dir && pwd` AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) AC_REQUIRE([AC_PROG_MAKE_SET])]) # # Check to make sure that the build environment is sane. # AC_DEFUN(AM_SANITY_CHECK, [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftestfile # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` if test "[$]*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftestfile` fi if test "[$]*" != "X $srcdir/configure conftestfile" \ && test "[$]*" != "X conftestfile $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "[$]2" = conftestfile ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi rm -f conftest* AC_MSG_RESULT(yes)]) dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) dnl The program must properly implement --version. AC_DEFUN(AM_MISSING_PROG, [AC_MSG_CHECKING(for working $2) # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if ($2 --version) < /dev/null > /dev/null 2>&1; then $1=$2 AC_MSG_RESULT(found) else $1="$3/missing $2" AC_MSG_RESULT(missing) fi AC_SUBST($1)]) # serial 40 AC_PROG_LIBTOOL AC_DEFUN(AC_PROG_LIBTOOL, [AC_REQUIRE([AC_LIBTOOL_SETUP])dnl # Save cache, so that ltconfig can load it AC_CACHE_SAVE # Actually configure libtool. ac_aux_dir is where install-sh is found. CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \ DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \ ${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ $libtool_flags --no-verify $ac_aux_dir/ltmain.sh $lt_target \ || AC_MSG_ERROR([libtool configure failed]) # Reload cache, that may have been modified by ltconfig AC_CACHE_LOAD # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl # Redirect the config.log output again, so that the ltconfig log is not # clobbered by the next message. exec 5>>./config.log ]) AC_DEFUN(AC_LIBTOOL_SETUP, [AC_PREREQ(2.13)dnl AC_REQUIRE([AC_ENABLE_SHARED])dnl AC_REQUIRE([AC_ENABLE_STATIC])dnl AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([AC_PROG_RANLIB])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_LD])dnl AC_REQUIRE([AC_PROG_NM])dnl AC_REQUIRE([AC_PROG_LN_S])dnl dnl case "$target" in NONE) lt_target="$host" ;; *) lt_target="$target" ;; esac # Check for any special flags to pass to ltconfig. # # the following will cause an existing older ltconfig to fail, so # we ignore this at the expense of the cache file... Checking this # will just take longer ... bummer! #libtool_flags="--cache-file=$cache_file" # test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], [libtool_flags="$libtool_flags --enable-dlopen"]) ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], [libtool_flags="$libtool_flags --enable-win32-dll"]) AC_ARG_ENABLE(libtool-lock, [ --disable-libtool-lock avoid locking (might break parallel builds)]) test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" # Some flags need to be propagated to the compiler or linker for good # libtool support. case "$lt_target" in *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case "`/usr/bin/file conftest.o`" in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], [*-*-cygwin* | *-*-mingw*) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; ]) esac ]) # AC_LIBTOOL_DLOPEN - enable checks for dlopen support AC_DEFUN(AC_LIBTOOL_DLOPEN, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) # AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's AC_DEFUN(AC_LIBTOOL_WIN32_DLL, [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) # AC_ENABLE_SHARED - implement the --enable-shared flag # Usage: AC_ENABLE_SHARED[(DEFAULT)] # Where DEFAULT is either `yes' or `no'. If omitted, it defaults to # `yes'. AC_DEFUN(AC_ENABLE_SHARED, [dnl define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE(shared, changequote(<<, >>)dnl << --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], changequote([, ])dnl [p=${PACKAGE-default} case "$enableval" in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," for pkg in $enableval; do if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$ac_save_ifs" ;; esac], enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl ]) # AC_DISABLE_SHARED - set the default shared flag to --disable-shared AC_DEFUN(AC_DISABLE_SHARED, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_SHARED(no)]) # AC_ENABLE_STATIC - implement the --enable-static flag # Usage: AC_ENABLE_STATIC[(DEFAULT)] # Where DEFAULT is either `yes' or `no'. If omitted, it defaults to # `yes'. AC_DEFUN(AC_ENABLE_STATIC, [dnl define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE(static, changequote(<<, >>)dnl << --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], changequote([, ])dnl [p=${PACKAGE-default} case "$enableval" in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," for pkg in $enableval; do if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$ac_save_ifs" ;; esac], enable_static=AC_ENABLE_STATIC_DEFAULT)dnl ]) # AC_DISABLE_STATIC - set the default static flag to --disable-static AC_DEFUN(AC_DISABLE_STATIC, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_STATIC(no)]) # AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag # Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] # Where DEFAULT is either `yes' or `no'. If omitted, it defaults to # `yes'. AC_DEFUN(AC_ENABLE_FAST_INSTALL, [dnl define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE(fast-install, changequote(<<, >>)dnl << --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], changequote([, ])dnl [p=${PACKAGE-default} case "$enableval" in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," for pkg in $enableval; do if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$ac_save_ifs" ;; esac], enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl ]) # AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install AC_DEFUN(AC_DISABLE_FAST_INSTALL, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_FAST_INSTALL(no)]) # AC_PROG_LD - find the path to the GNU or non-GNU linker AC_DEFUN(AC_PROG_LD, [AC_ARG_WITH(gnu-ld, [ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl ac_prog=ld if test "$ac_cv_prog_gcc" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by GCC]) ac_prog=`($CC -print-prog-name=ld) 2>&5` case "$ac_prog" in # Accept absolute paths. changequote(,)dnl [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' changequote([,])dnl # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(ac_cv_path_LD, [if test -z "$LD"; then IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ac_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then test "$with_gnu_ld" != no && break else test "$with_gnu_ld" != yes && break fi fi done IFS="$ac_save_ifs" else ac_cv_path_LD="$LD" # Let the user override the test with a path. fi]) LD="$ac_cv_path_LD" if test -n "$LD"; then AC_MSG_RESULT($LD) else AC_MSG_RESULT(no) fi test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) AC_PROG_LD_GNU ]) AC_DEFUN(AC_PROG_LD_GNU, [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, [# I'd rather use --version here, but apparently some GNU ld's only accept -v. if $LD -v 2>&1 &5; then ac_cv_prog_gnu_ld=yes else ac_cv_prog_gnu_ld=no fi]) ]) # AC_PROG_NM - find the path to a BSD-compatible name lister AC_DEFUN(AC_PROG_NM, [AC_MSG_CHECKING([for BSD-compatible nm]) AC_CACHE_VAL(ac_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. ac_cv_path_NM="$NM" else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then ac_cv_path_NM="$ac_dir/nm -B" break elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then ac_cv_path_NM="$ac_dir/nm -p" break else ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags fi fi done IFS="$ac_save_ifs" test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm fi]) NM="$ac_cv_path_NM" AC_MSG_RESULT([$NM]) ]) # AC_CHECK_LIBM - check for math library AC_DEFUN(AC_CHECK_LIBM, [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case "$lt_target" in *-*-beos* | *-*-cygwin*) # These system don't have libm ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, main, LIBM="-lm") ;; esac ]) # AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for # the libltdl convenience library and INCLTDL to the include flags for # the libltdl header and adds --enable-ltdl-convenience to the # configure arguments. Note that LIBLTDL and INCLTDL are not # AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not # provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed # with '${top_builddir}/' and INCLTDL will be prefixed with # '${top_srcdir}/' (note the single quotes!). If your package is not # flat and you're not using automake, define top_builddir and # top_srcdir appropriately in the Makefiles. AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl case "$enable_ltdl_convenience" in no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; "") enable_ltdl_convenience=yes ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) ]) # AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for # the libltdl installable library and INCLTDL to the include flags for # the libltdl header and adds --enable-ltdl-install to the configure # arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is # AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed # libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will # be prefixed with '${top_builddir}/' and INCLTDL will be prefixed # with '${top_srcdir}/' (note the single quotes!). If your package is # not flat and you're not using automake, define top_builddir and # top_srcdir appropriately in the Makefiles. # In the future, this macro may have to be called after AC_PROG_LIBTOOL. AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_CHECK_LIB(ltdl, main, [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], [if test x"$enable_ltdl_install" = xno; then AC_MSG_WARN([libltdl not installed, but installation disabled]) else enable_ltdl_install=yes fi ]) if test x"$enable_ltdl_install" = x"yes"; then ac_configure_args="$ac_configure_args --enable-ltdl-install" LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) else ac_configure_args="$ac_configure_args --enable-ltdl-install=no" LIBLTDL="-lltdl" INCLTDL= fi ]) dnl old names AC_DEFUN(AM_PROG_LIBTOOL, [indir([AC_PROG_LIBTOOL])])dnl AC_DEFUN(AM_ENABLE_SHARED, [indir([AC_ENABLE_SHARED], $@)])dnl AC_DEFUN(AM_ENABLE_STATIC, [indir([AC_ENABLE_STATIC], $@)])dnl AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl dnl This is just to silence aclocal about the macro not being used ifelse([AC_DISABLE_FAST_INSTALL])dnl xmlrpc-c-1.33.14/common.mk000066400000000000000000000572201236133176700152500ustar00rootroot00000000000000# This file contains rules and variable settings for the convenience # of every other make file in the package. # No make file is required to use this file, but it usually saves a lot # of duplication. # The following make variables are meaningful as input to this file: # # SRCDIR: Name of directory which is the top of the Xmlrpc-c source tree. # BLDDIR: Name of directory which is the top of the Xmlrpc-c build tree. include $(SRCDIR)/version.mk # .DELETE_ON_ERROR is a special predefined Make target that says to delete # the target if a command in the rule for it fails. That's important, # because we don't want a half-made target sitting around looking like it's # fully made. .DELETE_ON_ERROR: GCC_WARNINGS = -Wall -W -Wno-uninitialized -Wundef -Wimplicit \ -Wno-unknown-pragmas # We need -Wwrite-strings after we fix all the missing consts # # -Wuninitialized catches some great bugs, but it also flags a whole lot # of perfectly good code that can't be written any better. Too bad there's # no way to annotate particular variables as being OK, so we could turn # on -Wuninitialized for all the others. GCC_C_WARNINGS = $(GCC_WARNINGS) \ -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes GCC_CXX_WARNINGS = $(GCC_WARNINGS) -Wsynth # Before 09.05.20, we had -Woverloaded-virtual, but it doesn't seem to do # anything useful. It causes a warning that a method was hidden, but # experiments show nothing is actually hidden. The GCC manual's description # of what it does does not match empirical evidence. The option causes # warnings when a derived class of xmlrpc_c::method2 overrides one of the # execute() methods and not the other (as cpp/test/registry.cpp does), but the # code works fine. # The NDEBUG macro says not to build code that assumes there are no bugs. # This makes the code go faster. The main thing it does is tell the C library # to make assert() a no-op as opposed to generating code to check the # assertion and crash the program if it isn't really true. You can add # -UNDEBUG (in any of various ways) to override this. # CFLAGS_COMMON = -DNDEBUG CXXFLAGS_COMMON = -DNDEBUG ifeq ($(C_COMPILER_GNU),yes) CFLAGS_COMMON += $(GCC_C_WARNINGS) -fno-common -g -O3 endif ifeq ($(CXX_COMPILER_GNU),yes) CXXFLAGS_COMMON += $(GCC_CXX_WARNINGS) -g endif DISTDIR = $(BLDDIR)/$(PACKAGE)-$(VERSION)/$(SUBDIR) # MIN is the minor version number for shared libraries. # MAJ is the major version number, but is set separately by # individual make files so that the major number of one library can change # from one release to another while the major number of another does not. MIN = $(XMLRPC_MINOR_RELEASE) # CURDIR was introduced in GNU Make 3.77. ifeq ($(CURDIR)x,x) CURDIR := $(shell /bin/pwd) endif # The package XmlRpc++ on Sourceforge includes a library named # libxmlrpc++ just as Xmlrpc-c does. To use them both, you may need # to rename one. To rename the Xmlrpc-c one, set the make variable # LIBXMLRPCPP_NAME, e.g. on the 'make' command line. ifeq ($(LIBXMLRPCPP_NAME),) LIBXMLRPCPP_NAME := xmlrpc++ endif ifneq ($(LADD),) # We used to use make variable LADD, but now use the conventional LDFLAGS, # for user-supplied additional link flags LDFLAGS := $(LADD) endif LDFLAGS_ALL = $(LDFLAGS_PERSONAL) $(LDFLAGS) ############################################################################## # STATIC LINK LIBRARY RULES # ############################################################################## # To use this rule, the including make file must set a target-specific # variable LIBOBJECTS (and declare dependencies that include LIBOBJECTS). # Example: # FOO_OBJECTS = foo1.o foo2.o # libfoo.a: LIBOBJECTS = $(FOO_OBJECTS) # libfoo.a: $(FOO_OBJECTS) # TARGET_LIBRARY_NAMES = libfoo TARGET_STATIC_LIBRARIES = \ $(TARGET_LIBRARY_NAMES:%=%.a) $(TARGET_LIB_NAMES_PP:%=%.a) $(TARGET_STATIC_LIBRARIES): -rm -f $@ $(AR) cru $@ $(LIBOBJECTS) $(RANLIB) $@ ############################################################################## # SHARED LIBRARY RULES, VARIABLES # ############################################################################## ifeq ($(SHARED_LIB_TYPE),unix) include $(SRCDIR)/unix-common.mk endif ifeq ($(SHARED_LIB_TYPE),irix) include $(SRCDIR)/irix-common.mk endif ifeq ($(SHARED_LIB_TYPE),dll) include $(SRCDIR)/dll-common.mk endif ifeq ($(SHARED_LIB_TYPE),dylib) include $(SRCDIR)/dylib-common.mk endif ifeq ($(SHARED_LIB_TYPE),NONE) install-shared-libraries: endif # To use this rule, the including make file must set a target-specific # variable LIBOBJECTS (and declare dependencies that include LIBOBJECTS). # Analogous to static library rule above. # Optionally, including make file can set LIBDEP (probably # target-specific) to the -L and -l options necessary to declare the # libraries the target uses at run time. (This information gets built # into the shared library so that the runtime library loader will load # the specified libraries when asked to load the target library). ifeq ($(MUST_BUILD_SHLIB),Y) TARGET_SHARED_LIBRARIES = $(call shlibfn, $(TARGET_LIBRARY_NAMES)) TARGET_SHARED_LIBS_PP = $(call shlibfn, $(TARGET_LIB_NAMES_PP)) ifeq ($(MUST_BUILD_SHLIBLE),Y) TARGET_SHARED_LE_LIBS = \ $(call shliblefn, $(TARGET_LIBRARY_NAMES) $(TARGET_LIB_NAMES_PP)) else TARGET_SHARED_LE_LIBS = endif else TARGET_SHARED_LIBRARIES = TARGET_SHARED_LIBS_PP = TARGET_SHARED_LE_LIBS = endif LDFLAGS_SHLIB_ALL=$(LDFLAGS_ALL) $(LDFLAGS_SHLIB) #------ the actual rules ---------------------------------------------------- $(TARGET_SHARED_LIBRARIES) dummyshlib: $(CCLD) $(LDFLAGS_SHLIB_ALL) $(LIBOBJECTS) $(LIBDEP) -o $@ $(TARGET_SHARED_LIBS_PP) dummyshlibpp: $(CXXLD) $(LDFLAGS_SHLIB_ALL) $(LIBOBJECTS) $(LIBDEP) -o $@ #---------------------------------------------------------------------------- LIBXMLRPC_UTIL_DIR = $(BLDDIR)/lib/libutil ifneq ($(OMIT_LIBXMLRPC_UTIL_RULE),Y) LIBXMLRPC_UTIL = \ $(call shliblefn, $(LIBXMLRPC_UTIL_DIR)/libxmlrpc_util) LIBXMLRPC_UTIL_A = $(LIBXMLRPC_UTIL_DIR)/libxmlrpc_util.a endif ifneq ($(OMIT_XMLRPC_LIB_RULE),Y) LIBXMLRPC = \ $(call shliblefn, $(BLDDIR)/src/libxmlrpc) LIBXMLRPC_CLIENT = \ $(call shliblefn, $(BLDDIR)/src/libxmlrpc_client) LIBXMLRPC_SERVER = \ $(call shliblefn, $(BLDDIR)/src/libxmlrpc_server) LIBXMLRPC_SERVER_ABYSS = \ $(call shliblefn, $(BLDDIR)/src/libxmlrpc_server_abyss) LIBXMLRPC_SERVER_CGI = \ $(call shliblefn, $(BLDDIR)/src/libxmlrpc_server_cgi) LIBXMLRPC_A = $(BLDDIR)/src/libxmlrpc.a LIBXMLRPC_CLIENT_A = $(BLDDIR)/src/libxmlrpc_client.a LIBXMLRPC_SERVER_A = $(BLDDIR)/src/libxmlrpc_server.a LIBXMLRPC_SERVER_ABYSS_A = $(BLDDIR)/src/libxmlrpc_server_abyss.a LIBXMLRPC_SERVER_CGI_A = $(BLDDIR)/src/libxmlrpc_server_cgi.a endif LIBXMLRPC_XMLTOK_DIR = $(BLDDIR)/lib/expat/xmltok ifneq ($(OMIT_XMLTOK_LIB_RULE),Y) LIBXMLRPC_XMLTOK = \ $(call shliblefn, $(LIBXMLRPC_XMLTOK_DIR)/libxmlrpc_xmltok) LIBXMLRPC_XMLTOK_A = $(LIBXMLRPC_XMLTOK_DIR)/libxmlrpc_xmltok.a endif LIBXMLRPC_XMLPARSE_DIR = $(BLDDIR)/lib/expat/xmlparse ifneq ($(OMIT_XMLPARSE_LIB_RULE),Y) LIBXMLRPC_XMLPARSE = \ $(call shliblefn, $(LIBXMLRPC_XMLPARSE_DIR)/libxmlrpc_xmlparse) LIBXMLRPC_XMLPARSE_A = $(LIBXMLRPC_XMLPARSE_DIR)/libxmlrpc_xmlparse.a endif LIBXMLRPC_ABYSS_DIR = $(BLDDIR)/lib/abyss/src ifneq ($(OMIT_ABYSS_LIB_RULE),Y) LIBXMLRPC_ABYSS = \ $(call shliblefn, $(LIBXMLRPC_ABYSS_DIR)/libxmlrpc_abyss) LIBXMLRPC_ABYSS_A = $(LIBXMLRPC_ABYSS_DIR)/libxmlrpc_abyss.a endif LIBXMLRPC_CPP = \ $(call shliblefn, $(BLDDIR)/src/cpp/libxmlrpc_cpp) LIBXMLRPC_CPP_A = $(BLDDIR)/src/cpp/libxmlrpc_cpp.a LIBXMLRPCPP = \ $(call shliblefn, $(BLDDIR)/src/cpp/libxmlrpc++) LIBXMLRPCPP_A = $(BLDDIR)/src/cpp/libxmlrpc++.a LIBXMLRPC_PACKETSOCKET = \ $(call shliblefn, $(BLDDIR)/src/cpp/libxmlrpc_packetsocket) LIBXMLRPC_PACKETSOCKET_A = $(BLDDIR)/src/cpp/libxmlrpc_packetsocket.a LIBXMLRPC_CLIENTPP = \ $(call shliblefn, $(BLDDIR)/src/cpp/libxmlrpc_client++) LIBXMLRPC_CLIENTPP_A = $(BLDDIR)/src/cpp/libxmlrpc_client++.a LIBXMLRPC_SERVERPP = \ $(call shliblefn, $(BLDDIR)/src/cpp/libxmlrpc_server++) LIBXMLRPC_SERVERPP_A = $(BLDDIR)/src/cpp/libxmlrpc_server++.a LIBXMLRPC_SERVER_ABYSSPP = \ $(call shliblefn, $(BLDDIR)/src/cpp/libxmlrpc_server_abyss++) LIBXMLRPC_SERVER_ABYSSPP_A = $(BLDDIR)/src/cpp/libxmlrpc_server_abyss++.a LIBXMLRPC_SERVER_PSTREAMPP = \ $(call shliblefn, $(BLDDIR)/src/cpp/libxmlrpc_server_pstream++) LIBXMLRPC_SERVER_PSTREAMPP_A = $(BLDDIR)/src/cpp/libxmlrpc_server_pstream++.a # LIBXMLRPC_XML is the list of Xmlrpc-c libraries we need to parse # XML. If we're using an external library to parse XML, this is null. # LDLIBS_XML is the corresponding -L/-l options ifneq ($(ENABLE_LIBXML2_BACKEND),yes) # We're using the internal Expat XML parser LIBXMLRPC_XML = $(LIBXMLRPC_XMLPARSE) $(LIBXMLRPC_XMLTOK) LDLIBS_XML = \ -L$(BLDDIR)/lib/expat/xmlparse -lxmlrpc_xmlparse \ -L$(BLDDIR)/lib/expat/xmltok -lxmlrpc_xmltok else LDLIBS_XML = $(shell xml2-config --libs) endif # LIBXMLRPC_UTIL_LIBDEP is the string of linker options you need on the link # of a shared library that refers to symbols in libxmlrpc_util. It tells # the linker to record a dependency upon libxmlrpc_util in the shared library # being built, and also dependencies on things on which libxmlrpc_util # depends. You might think that the linker could get the latter out of # libxmlrpc_util itself, but we have found (2012.12) that in a Mingw build # it does not. LIBXMLRPC_UTIL_LIBDEP = -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util -lpthread ############################################################################## # RULES TO BUILD OBJECT FILES TO LINK INTO LIBRARIES # ############################################################################## # The including make file sets TARGET_MODS to a list of all modules that # might go into a library. Its a list of the bare module names. The # including make file also sets INCLUDES, in a target-dependent manner, # to the string of -I options needed for each target. Example: # TARGET_MODS = foo bar # # foo.o foo.osh: INCLUDES = -Iinclude -I/usr/include/foostuff # bar.o bar.osh: INCLUDES = -Iinclude -I/usr/include/barstuff # # include common.mk # # The above generates rules to build foo.o, bar.o, foo.osh, and bar.osh # # For C++ source files, use TARGET_MODS_PP instead. # CFLAGS and CXXFLAGS are designed to be picked up as environment # variables. The user may use them to add inclusion search directories # (-I) or control 32/64 bitness or the like. Using these is always # iffy, because the options one might include can interact in unpredictable # ways with what the make file is trying to do. But at least some users # get useful results. ifneq ($(CADD),) # We used to use make variable CADD, but now use the conventional CFLAGS, # for user-supplied additional link flags CFLAGS := $(CADD) CXXFLAGS := $(CADD) endif CFLAGS_ALL = $(CFLAGS_COMMON) $(CFLAGS_LOCAL) \ $(INCLUDES) $(CFLAGS_PERSONAL) $(CFLAGS) CXXFLAGS_ALL = $(CXXFLAGS_COMMON) $(CFLAGS_LOCAL) \ $(INCLUDES) $(CFLAGS_PERSONAL) $(CXXFLAGS) $(TARGET_MODS:%=%.o):%.o:%.c $(CC) -c -o $@ $(CFLAGS_ALL) $< $(TARGET_MODS:%=%.osh): CFLAGS_COMMON += $(CFLAGS_SHLIB) $(TARGET_MODS:%=%.osh):%.osh:%.c $(CC) -c -o $@ $(INCLUDES) $(CFLAGS_ALL) $(CFLAGS_SHLIB) $< $(TARGET_MODS_PP:%=%.o):%.o:%.cpp $(CXX) -c -o $@ $(INCLUDES) $(CXXFLAGS_ALL) $< $(TARGET_MODS_PP:%=%.osh): CXXFLAGS_COMMON += $(CFLAGS_SHLIB) $(TARGET_MODS_PP:%=%.osh):%.osh:%.cpp $(CXX) -c -o $@ $(INCLUDES) $(CXXFLAGS_ALL) $< ############################################################################## # MISC BUILD RULES # ############################################################################## # We use the srcdir symbolic link simply to make the make # rules easier to read in the make output. We could use the $(SRCDIR) # variable, but that makes the compile and link commands # a mile long. Note that Make sometime figures that a directory which # is a dependency is newer than the symbolic link pointing to it and wants # to rebuild the symbolic link. So we don't make $(SRCDIR) a # dependency of 'srcdir'. srcdir: $(LN_S) $(SRCDIR) $@ blddir: $(LN_S) $(BLDDIR) $@ ############################################################################## # RECURSIVE SUBDIRECTORY BUILD RULES # ############################################################################## .PHONY: $(SUBDIRS:%=%/all) $(SUBDIRS:%=%/all): %/all: $(CURDIR)/% $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ $(notdir $@) .PHONY: $(SUBDIRS:%=%/install) $(SUBDIRS:%=%/install): %/install: $(CURDIR)/% $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ $(notdir $@) .PHONY: $(SUBDIRS:%=%/clean) $(SUBDIRS:%=%/clean): %/clean: $(CURDIR)/% $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ $(notdir $@) .PHONY: $(SUBDIRS:%=%/distclean) $(SUBDIRS:%=%/distclean): %/distclean: $(CURDIR)/% $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ $(notdir $@) .PHONY: $(SUBDIRS:%=%/check) $(SUBDIRS:%=%/check): %/check: $(CURDIR)/% $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ $(notdir $@) .PHONY: $(SUBDIRS:%=%/distdir) $(SUBDIRS:%=%/distdir): %/distdir: $(CURDIR)/% $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ $(notdir $@) .PHONY: $(SUBDIRS:%=%/dep) $(SUBDIRS:%=%/dep): %/dep: $(CURDIR)/% $(MAKE) -C $(dir $@) -f $(SRCDIR)/$(SUBDIR)/$(dir $@)Makefile \ $(notdir $@) ############################################################################## # CROSS-COMPONENT BUILD RULES # ############################################################################## ifneq ($(OMIT_WININET_TRANSPORT_RULE),Y) $(BLDDIR)/lib/wininet_transport/xmlrpc_wininet_transport.o \ $(BLDDIR)/lib/wininet_transport/xmlrpc_wininet_transport.osh \ : FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/wininet_transport/Makefile \ $(notdir $@) endif ifneq ($(OMIT_CURL_TRANSPORT_RULE),Y) $(BLDDIR)/lib/curl_transport/xmlrpc_curl_transport.o \ $(BLDDIR)/lib/curl_transport/xmlrpc_curl_transport.osh \ $(BLDDIR)/lib/curl_transport/curltransaction.o \ $(BLDDIR)/lib/curl_transport/curltransaction.osh \ $(BLDDIR)/lib/curl_transport/curlmulti.o \ $(BLDDIR)/lib/curl_transport/curlmulti.osh \ $(BLDDIR)/lib/curl_transport/lock_pthread.o \ $(BLDDIR)/lib/curl_transport/lock_pthread.osh \ : FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/curl_transport/Makefile \ $(notdir $@) endif ifneq ($(OMIT_LIBWWW_TRANSPORT_RULE),Y) $(BLDDIR)/lib/libwww_transport/xmlrpc_libwww_transport.o \ $(BLDDIR)/lib/libwww_transport/xmlrpc_libwww_transport.osh \ : FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/libwww_transport/Makefile \ $(notdir $@) endif $(LIBXMLRPC) \ $(LIBXMLRPC_CLIENT) \ $(LIBXMLRPC_SERVER) \ $(LIBXMLRPC_SERVER_ABYSS) \ $(LIBXMLRPC_SERVER_CGI) \ $(LIBXMLRPC_A) \ $(LIBXMLRPC_CLIENT_A) \ $(LIBXMLRPC_SERVER_A) \ $(LIBXMLRPC_SERVER_ABYSS_A) \ $(LIBXMLRPC_SERVER_CGI_A): FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/src/Makefile \ $(notdir $@) $(LIBXMLRPC_UTIL) $(LIBXMLRPC_UTIL_A) : FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/libutil/Makefile \ $(notdir $@) $(LIBXMLRPC_XMLPARSE) $(LIBXMLRPC_XMLPARSE_A) : FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/expat/xmlparse/Makefile \ $(notdir $@) $(LIBXMLRPC_XMLTOK) $(LIBXMLRPC_XMLTOK_A) : FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/expat/xmltok/Makefile \ $(notdir $@) $(LIBXMLRPC_ABYSS) $(LIBXMLRPC_ABYSS_A): FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/abyss/src/Makefile \ $(notdir $@) ifneq ($(OMIT_CPP_LIB_RULES),Y) $(LIBXMLRPCPP) $(LIBXMLRPCPP_A) \ $(LIBXMLRPC_PACKETSOCKET) $(LIBXMLRPC_PACKETSOCKET_A) \ $(LIBXMLRPC_CLIENTPP) $(LIBXMLRPC_CLIENTPP_A) \ $(LIBXMLRPC_SERVERPP) $(LIBXMLRPC_SERVERPP_A) \ $(LIBXMLRPC_SERVER_ABYSSPP) $(LIBXMLRPC_SERVER_ABYSSPP_A) \ $(LIBXMLRPC_SERVER_PSTREAMPP) $(LIBXMLRPC_SERVER_PSTREAMPP_A) \ $(LIBXMLRPC_CPP) $(LIBXMLRPC_CPP_A) : FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/src/cpp/Makefile \ $(notdir $@) endif # For the following utilities, we don't bother with a library -- we # just explicitly link the object file we need. This is to save # complexity. If the list gets too big, we may need a library just to # keep link commands short. UTIL_DIR = $(BLDDIR)/lib/util UTILS = \ casprintf.o \ cmdline_parser.o \ cmdline_parser_cpp.o \ getoptx.o \ stripcaseeq.o \ string_parser.o \ ifneq ($(OMIT_UTILS_RULE),Y) $(UTILS:%=$(UTIL_DIR)/%): FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/lib/util/Makefile \ $(notdir $@) endif CASPRINTF = $(UTIL_DIR)/casprintf.o # About version.h: This is a built header file, which means it is a supreme # pain in the ass. The biggest problem is that when we automatically make # dependencies (depend.mk), it doesn't exist yet. This means Gcc # generates a dependency on it being in the local directory. Therefore, # we generate it in the local directory, as a symbolic link, wherever it # is needed. But the original is always in the top level directory, # generated by a rule in that directory's make file. Problem 2 is that # the top directory's make file includes common.mk, so the rules # below conflict with it. That's what OMIT_VERSION_H is for. ifneq ($(OMIT_VERSION_H),Y) $(BLDDIR)/version.h: $(MAKE) -C $(dir $@) -f $(SRCDIR)/GNUmakefile $(notdir $@) version.h: $(BLDDIR)/version.h $(LN_S) $< $@ endif ifneq ($(OMIT_CONFIG_H_RULE),Y) $(BLDDIR)/include/xmlrpc-c/config.h: $(MAKE) -C $(BLDDIR)/include -f $(SRCDIR)/include/Makefile \ xmlrpc-c/config.h endif ifneq ($(OMIT_TRANSPORT_CONFIG_H),Y) $(BLDDIR)/transport_config.h: $(MAKE) -C $(dir $@) -f $(SRCDIR)/GNUmakefile $(notdir $@) endif ifneq ($(OMIT_XMLRPC_C_CONFIG_TEST),Y) $(BLDDIR)/xmlrpc-c-config.test: $(MAKE) -C $(dir $@) -f $(SRCDIR)/GNUmakefile $(notdir $@) endif $(TARGET_MODS:%=%.o) $(TARGET_MODS:%=%.osh): \ $(BLDDIR)/include/xmlrpc-c/config.h ifneq ($(OMIT_XMLRPC_LIB_RULE),Y) $(BLDDIR)/src/libxmlrpc_client.cflags: $(MAKE) -C $(dir $@) -f $(SRCDIR)/src/Makefile $(notdir $@) $(BLDDIR)/src/libxmlrpc_client.ldflags: $(MAKE) -C $(dir $@) -f $(SRCDIR)/src/Makefile $(notdir $@) endif # With a separate build directory, you have to make the directory itself # before you can make anything in it. Here's the rule to do that. $(SUBDIRS:%=$(CURDIR)/%): mkdir $@ ############################################################################## # INSTALL RULES # # (except shared libraries) # ############################################################################## MKINSTALLDIRS = $(SHELL) $(SRCDIR)/mkinstalldirs .PHONY: install-common install-headers install-bin install-man install-common: \ install-static-libraries install-shared-libraries \ install-headers install-bin install-man INSTALL_LIB_CMD = $(INSTALL_DATA) $$p $(DESTDIR)$(LIBINST_DIR)/$$p RANLIB_CMD = $(RANLIB) $(DESTDIR)$(LIBINST_DIR)/$$p install-static-libraries: $(STATIC_LIBRARIES_TO_INSTALL) $(MKINSTALLDIRS) $(DESTDIR)$(LIBINST_DIR) @list='$(STATIC_LIBRARIES_TO_INSTALL)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_LIB_CMD)"; \ $(INSTALL_LIB_CMD); \ else :; fi; \ done @$(POST_INSTALL) @list='$(STATIC_LIBRARIES_TO_INSTALL)'; for p in $$list; do \ if test -f $$p; then \ echo " $(RANLIB_CMD)"; \ $(RANLIB_CMD); \ else :; fi; \ done HEADERDESTDIR = $(DESTDIR)$(HEADERINST_DIR) INSTALL_HDR_CMD = $(INSTALL_DATA) $$d$$p $(HEADERDESTDIR)/$$p install-headers: $(HEADERS_TO_INSTALL) $(MKINSTALLDIRS) $(HEADERDESTDIR) $(MKINSTALLDIRS) $(HEADERDESTDIR)/xmlrpc-c @list='$(HEADERS_TO_INSTALL)'; for p in $$list; do \ if test -f "$$p"; then d= ; else d="$(SRCDIR)/$(SUBDIR)/"; fi; \ echo " $(INSTALL_HDR_CMD)"; \ $(INSTALL_HDR_CMD); \ done INSTALL_PROGRAM_CMD = $(INSTALL_PROGRAM) $$p $(DESTDIR)$(PROGRAMINST_DIR)/$$p install-bin: $(PROGRAMS_TO_INSTALL) $(DESTDIR)$(PROGRAMINST_DIR) @list='$(PROGRAMS_TO_INSTALL)'; \ for p in $$list; do \ echo "$(INSTALL_PROGRAM_CMD)"; \ $(INSTALL_PROGRAM_CMD); \ done $(DESTDIR)$(PROGRAMINST_DIR): $(MKINSTALLDIRS) $@ MANDESTDIR = $(DESTDIR)$(MANINST_DIR) INSTALL_MAN_CMD = $(INSTALL_DATA) $$p $(MANDESTDIR)/$$p install-man: $(MAN_FILES_TO_INSTALL) $(MKINSTALLDIRS) $(MANDESTDIR) @list='$(MAN_FILES_TO_INSTALL)'; \ for p in $$list; do \ echo "$(MAN_FILES_TO_INSTALL)"; \ $(INSTALL_MAN_CMD); \ done ############################################################################## # MISCELLANEOUS RULES # ############################################################################## .PHONY: clean-common clean-common: rm -f *.o *.osh *.a *.s *.i *.la *.lo rm -f *.$(SHLIB_SUFFIX) *.$(SHLIB_SUFFIX).* rm -rf .libs ifneq ($(OMIT_VERSION_H),Y) rm -f version.h endif .PHONY: distclean-common distclean-common: # depend.mk is generated by 'make dep' and contains only dependencies # that make parts get _rebuilt_ when parts upon which they depend change. # It does not contain dependencies that are necessary to cause a part to # get built in the first place. E.g. if foo.c uses bar.h and bar.h gets built # by a make rule, you must put the dependency of foo.c on bar.h somewhere # besides depend.mk. # # Because of this, a user doesn't need depend.mk, because he # doesn't modify source files. A developer, on the other hand, must make his # own depend.mk, because 'make dep' creates depend.mk with # absolute pathnames, specific to the developer's system. # # So we obliterate depend.mk here. The build will automatically # create an empty depend.mk when it is needed for the user. The # developer must do 'make dep' if he wants to edit and rebuild. # # Other projects have the build automatically build a true # depend.mk, suitable for a developer. We have found that to be # an utter disaster -- it's way too complicated and prone to failure, # especially with built .h files. Better not to burden the user, who # gains nothing from it, with that. # rm -f depend.mk rm -f Makefile.depend # We used to create a file by this name rm -f srcdir blddir .PHONY: distdir-common distdir-common: @for file in $(DISTFILES); do \ d=$(SRCDIR); \ if test -d $$d/$$file; then \ cp -pr $$d/$$file $(DISTDIR)/$$file; \ else \ test -f $(DISTDIR)/$$file \ || ln $$d/$$file $(DISTDIR)/$$file 2> /dev/null \ || cp -p $$d/$$file $(DISTDIR)/$$file || :; \ fi; \ done DEP_SOURCES = $(wildcard *.c *.cpp) # This is a filter to turn "foo.o:" rules into "foo.o foo.lo foo.osh:" # to make dependencies for all the various forms of object file out of # a file made by a depedency generator that knows only about .o. DEPEND_MASSAGER = perl -walnpe's{^(.*)\.o:}{$$1.o $$1.lo $$1.osh:}' .PHONY: dep-common dep-common: FORCE ifneq ($(DEP_SOURCES)x,x) -$(CC) -MM -MG -I. $(INCLUDES) $(DEP_SOURCES) | \ $(DEPEND_MASSAGER) \ >depend.mk endif depend.mk: cat /dev/null >$@ # The automatic dependency generation is a pain in the butt and # totally unnecessary for people just installing the distributed code, # so to avoid needless failures in the field and a complex build, the # 'distclean' target simply makes depend.mk an empty file. A # developer may do 'make dep' to create a depend.mk full of real # dependencies. # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: # Use the FORCE target as a dependency to force a target to get remade FORCE: xmlrpc-c-1.33.14/config.guess000077500000000000000000001276371236133176700157610ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 # Free Software Foundation, Inc. timestamp='2009-12-30' # This file 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: xmlrpc-c-1.33.14/config.mk.in000066400000000000000000000326741236133176700156400ustar00rootroot00000000000000# config.mk is generated by 'configure' using config.mk.in # as a template and information that 'configure' gathers from the build # system and from user options. # config.mk should someday replace most of the other files that # 'configure' generates, thus simplifying development and customization. # config.mk is intended to contain information specific to the # particular build environment or user build choices. # Furthermore, most of the logic in 'configure', and thus 'configure.in', # should go into the make files to simplify the build. config.mk # should just pass raw configure variables through to the make file. # Tokens of the form @TOKEN@ in the template file get replaced by # 'configure' with the values of variables of the same name within # 'configure', because of a AC_SUBST(TOKEN) statement in the # 'configure.in' from which 'configure' was built. # Here are the options the user chose on 'configure': ENABLE_ABYSS_SERVER = @ENABLE_ABYSS_SERVER@ ENABLE_ABYSS_THREADS = @ENABLE_ABYSS_THREADS@ ENABLE_CPLUSPLUS = @ENABLE_CPLUSPLUS@ ENABLE_CGI_SERVER = @ENABLE_CGI_SERVER@ ENABLE_LIBXML2_BACKEND = @ENABLE_LIBXML2_BACKEND@ MUST_BUILD_WININET_CLIENT = @MUST_BUILD_WININET_CLIENT@ MUST_BUILD_CURL_CLIENT = @MUST_BUILD_CURL_CLIENT@ MUST_BUILD_LIBWWW_CLIENT = @MUST_BUILD_LIBWWW_CLIENT@ BUILD_TOOLS = @BUILD_TOOLS@ BUILD_XMLRPC_PSTREAM = @BUILD_XMLRPC_PSTREAM@ LSOCKET = @LSOCKET@ WININET_LDADD = @WININET_LDADD@ WININET_LIBDIR = @WININET_LIBDIR@ CURL_LDADD = @CURL_LDADD@ CURL_LIBDIR = @CURL_LIBDIR@ LIBWWW_LDADD = @LIBWWW_LDADD@ LIBWWW_LIBDIR = @LIBWWW_LIBDIR@ FEATURE_LIST = @FEATURE_LIST@ ABS_SRCDIR = @abs_srcdir@ PREFIX = @prefix@ HAVE_WCHAR_H_DEFINE = @HAVE_WCHAR_H_DEFINE@ # Stuff 'configure' figured out about our build platform: SHELL = @SHELL@ CC = @CC@ CXX = @CXX@ CCLD = $(CC) CXXLD = $(CXX) AR = @AR@ RANLIB = @RANLIB@ LN_S = ln -s INSTALL = $(SRCDIR)/install-sh C_COMPILER_GNU = @C_COMPILER_GNU@ CXX_COMPILER_GNU = @CXX_COMPILER_GNU@ # Stuff 'configure' figured out via AC_CANONICAL_HOST macro in configure.in # and config.guess program and 'configure' command options: # HOST_OS names the operating system on which Xmlrpc-c is to run. # E.g. "linux-gnu". HOST_OS = @host_os@ ############################################################################### MUST_BUILD_CLIENT = no ifeq ($(MUST_BUILD_WININET_CLIENT),yes) MUST_BUILD_CLIENT = yes endif ifeq ($(MUST_BUILD_CURL_CLIENT),yes) MUST_BUILD_CLIENT = yes endif ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) MUST_BUILD_CLIENT = yes endif ############################################################################## # SHARED LIBRARY STUFF ############################################################################## # Shared libraries are very difficult, because how you build and use # them varies greatly from one platform to the next. # First, we break down shared library schemes into a few major types, # and indicate the type by SHARED_LIB_TYPE. # We also have a bunch of other make variables that reflect the different # ways we have to build on and for different platforms: # CFLAGS_SHLIB is a set of flags needed to compile a module which will # become part of a shared library. # On older systems, you have to make shared libraries out of position # independent code, so you need -fpic or -fPIC here. (The rule is: if # -fpic works, use it. If it bombs, go to -fPIC). On newer systems, # it isn't necessary, but can save real memory at the expense of # execution speed. Without position independent code, the library # loader may have to patch addresses into the executable text. On an # older system, this would cause a program crash because the loader # would be writing into read-only shared memory. But on newer # systems, the system silently creates a private mapping of the page # or segment being modified (the "copy on write" phenomenon). So it # needs its own private real page frame. # We have seen -fPIC required on IA64 and AMD64 machines (GNU # compiler/linker). Build-time linking fails without it. I don't # know why -- history seems to be repeating itself. 2005.02.23. # SHLIB_CLIB is the link option to include the C library in a shared library, # normally "-lc". On typical systems, this serves no purpose. On some, # though, it causes information about which C library to use to be recorded # in the shared library and thus choose the correct library among several or # avoid using an incompatible one. But on some systems, the link fails. # On 2002.09.30, "John H. DuBois III" reports that on # SCO OpenServer, he gets the following error message with -lc: # # -lc; relocations referenced ; from file(s) /usr/ccs/lib/libc.so(random.o); # fatal error: relocations remain against allocatable but non-writable # section: ; .text # # On Bryan's system, with gcc 2.95.3 and glibc 2.2.2, -lc causes # throws (from anywhere in a program that links the shared library) # not to work. I have no idea how. # LDFLAGS_SHLIB is the linker (Ld) flags needed to generate a shared # library from object files. It may use $(SONAME) as the soname for # the shared library being created (assuming sonames exist). # # This make file defines these functions that the including make file # can use: # # $(call shlibfn, LIBNAMELIST): file names of shared libraries # whose base names are LIBNAMELIST. E.g. if LIBNAMELIST is # "libfoo libbar", function returns "libfoo.so.3.1 libbar.so.3.1" # # $(call shliblefn, LIBNAMELIST): same as shlibfn, but for the file you # use at link-edit time. E.g. libfoo.so . # NEED_RPATH says on this platform, when you link-edit an executable you # need to have -R linker options to tell where to look, at run time, # for the shared libraries that the program uses. The linker puts that # information into the executable. # NEED_WL_RPATH is like NEED_RPATH, but it's a compiler option for when # you have the compiler call the linker. So E.g. "-Wl,-rpath,/my/runtime", # which tells the compiler to pass the option "-rpath /my/runtime" to # the linker. # Defaults: NEED_WL_RPATH=no NEED_RPATH=no # We build shared libraries only for platforms for which we've figured # out how. For the rest, we have this default: SHARED_LIB_TYPE = NONE MUST_BUILD_SHLIB = N MUST_BUILD_SHLIBLE = N shlibfn = $(1:%=%.shlibdummy) shliblefn = $(1:%=%.shlibledummy) # HOST_OS is usually has a version number suffix, e.g. "aix5.3.0.0", so # we compare based on prefix. ifeq ($(patsubst linux-gnu%,linux-gnu,$(HOST_OS)),linux-gnu) # Assume linker is GNU Compiler (gcc) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = so shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) # SHLIB_CLIB = -lc LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) CFLAGS_SHLIB=-fPIC endif ifeq ($(patsubst solaris%,solaris,$(HOST_OS)),solaris) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = so shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) # We assume Sun compiler and linker here. It isn't clear what to do # about a user who uses GNU compiler and Ld instead. For that, the # options should be the same as "linux-gnu" platform, above, except # with NEED_WL_RPATH. If the user uses the GNU compiler but the Sun # linker, it's even more complicated: we need an rpath option of the # form -Wl,-R . # Solaris compiler (Sun C 5.5) can't take multiple ld options as # -Wl,-a,-b . Ld sees -a,-b in that case. LDFLAGS_SHLIB = -Wl,-Bdynamic -Wl,-G -Wl,-h -Wl,$(SONAME) CFLAGS_SHLIB = -Kpic NEED_RPATH=yes endif ifeq ($(patsubst aix%,aix,$(HOST_OS)),aix) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = a shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) LDFLAGS_SHLIB = -qmkshrobj endif ifeq ($(patsubst hpux%,hpux,$(HOST_OS)),hpux) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = sl shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) LDFLAGS_SHLIB: -shared -fPIC endif ifeq ($(patsubst osf%,osf,$(HOST_OS)),osf) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = so shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) LDFLAGS_SHLIB = -shared -expect_unresolved endif ifeq ($(patsubst netbsd%,netbsd,$(HOST_OS)),netbsd) SHARED_LIB_TYPE = unix SHLIB_SUFFIX = so MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) CFLAGS_SHLIB = -fpic LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) NEED_WL_RPATH=yes endif ifeq ($(patsubst freebsd%,freebsd,$(HOST_OS)),freebsd) SHARED_LIB_TYPE = unix SHLIB_SUFFIX = so MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) CFLAGS_SHLIB = -fpic LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) NEED_WL_RPATH=yes endif ifeq ($(findstring interix,$(HOST_OS)),interix) SHARED_LIB_TYPE = unix SHLIB_SUFFIX = so MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) CFLAGS_SHLIB = LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) NEED_WL_RPATH=yes endif ifeq ($(patsubst dragonfly%,dragonfly,$(HOST_OS)),dragonfly) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = so shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) CFLAGS_SHLIB = -fpic LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) endif ifeq ($(patsubst beos%,beos,$(HOST_OS)),beos) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = so shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) LDFLAGS_SHLIB = -nostart endif ifeq ($(patsubst darwin%,darwin,$(HOST_OS)),darwin) SHARED_LIB_TYPE = dylib MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = dylib shlibfn = $(1:%=%.$(MAJ).$(MIN).$(SHLIB_SUFFIX)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) LDFLAGS_SHLIB = -dynamiclib -undefined suppress -single_module \ -flat_namespace -install_name $(LIBINST_DIR)/$(SONAME) $(SHLIB_CLIB) endif ifeq ($(patsubst irix%,irix,$(HOST_OS)),irix) SHARED_LIB_TYPE = irix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y SHLIB_SUFFIX = so shlibfn = $(1:%=%.$(SHLIB_SUFFIX).$(MAJ)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) VERSIONPERLPROG = \ print "sgi$(MAJ)." . join(":sgi$(MAJ) . ", (0..$(MIN))) . "\n" LDFLAGS_SHLIB = -shared -n32 -soname $(SONAME) \ -set_version $(shell perl -e '$(VERSIONPERLPROG)') -lc endif ifeq ($(patsubst cygwin%,cygwin,$(HOST_OS)),cygwin) SHARED_LIB_TYPE = dll MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = N SHLIB_SUFFIX = dll shlibfn = $(1:%=%.$(SHLIB_SUFFIX)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) endif ifeq ($(patsubst mingw32%,mingw32,$(HOST_OS)),mingw32) SHARED_LIB_TYPE = dll MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = N SHLIB_SUFFIX = dll shlibfn = $(1:%=%.$(SHLIB_SUFFIX)) shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) MSVCRT = yes endif ############################################################################## # MISCELLANEOUS ############################################################################## # BUILDTOOL_CC is the compiler to use to generate build tools, which we # will then run to build the product. The typical reason this would be # different from CC is that you're cross-compiling: the product will run # in Environment A, but you're building in Environment B, so you must # build the build tools for Environment B. # The cross compiling user can update config.mk or override # BUILDTOOL_CC on a make command. BUILDTOOL_CC = $(CC) BUILDTOOL_CCLD = $(CCLD) THREAD_LIBS = -lpthread # Here are the commands 'make install' uses to install various kinds of files: INSTALL_PROGRAM = $(INSTALL) -c -m 755 INSTALL_SHLIB = $(INSTALL) -c -m 755 INSTALL_DATA = $(INSTALL) -c -m 644 INSTALL_SCRIPT = $(INSTALL) -c -m 755 # Here are the locations at which 'make install' puts files: # PREFIX is designed to be overridden at make time if the user decides # he doesn't like the default specified at 'configure' time. prefix = $(PREFIX) datarootdir = $(DATAROOT_DIR) #datarootdir is the new Autoconf(2.60) name for datadir, which is still #accepted, but a warning is issued if datarootdir is not also used. exec_prefix = @exec_prefix@ DATAROOT_DIR = @datarootdir@ DATAINST_DIR = @datadir@ LIBINST_DIR = @libdir@ HEADERINST_DIR = @includedir@ PROGRAMINST_DIR = @bindir@ MANINST_DIR = @mandir@/man1 # DESTDIR is designed to be overridden at make time in order to relocate # the entire install into a subdirectory. DESTDIR = # VPATH probably doesn't belong in this file, but it's a convenient # place to set it once. VPATH is a special Make variable that tells # Make where to look for dependencies. E.g. if a make file says bar.c # is a dependency of bar.o and VPATH is ".:/usr/src/mypkg", Make will # look for bar.c first in the current directory (.) (as it would with # no VPATH), then in /usr/src/mypkg. The purpose of this is to allow # you to build in a fresh build directory, while your source stays in # the read-only directory /usr/src/mypkg . VPATH := .:$(SRCDIR)/$(SUBDIR) xmlrpc-c-1.33.14/config.sub000077500000000000000000001034451236133176700154130ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 # Free Software Foundation, Inc. timestamp='2010-01-22' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | ubicom32 \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile-* | tilegx-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; # This must be matched before tile*. tilegx*) basic_machine=tilegx-unknown os=-linux-gnu ;; tile*) basic_machine=tile-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: xmlrpc-c-1.33.14/configure000077500000000000000000006226601236133176700153440ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="include/xmlrpc-c/base.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS RANLIB AR BUILDDIR CPP_WARN_FLAGS CC_WARN_FLAGS CXX_COMPILER_GNU C_COMPILER_GNU ENABLE_LIBXML2_BACKEND have_xml2_config HAVE_LIBWWW_SSL_DEFINE CURL_LIBDIR CURL_LDADD CURL_CONFIG LIBWWW_LIBDIR LIBWWW_LDADD LIBWWW_CONFIG WININET_LIBDIR WININET_LDADD WININET_CFLAGS WININET_CONFIG ENABLE_ABYSS_THREADS DIRECTORY_SEPARATOR ATTR_UNUSED VA_LIST_IS_ARRAY_DEFINE HAVE_SYS_SELECT_H_DEFINE HAVE_SYS_IOCTL_H_DEFINE HAVE_SYS_FILIO_H_DEFINE HAVE_WCHAR_H_DEFINE EGREP GREP CPP LSOCKET ac_ct_CXX CXXFLAGS CXX FEATURE_LIST XML_RPC_API2CPP_SUBDIR XMLRPCCPP_H CPPTEST LIBXMLRPC_CPP_A ENABLE_CPLUSPLUS ENABLE_CGI_SERVER SERVER XMLRPC_ABYSS_H VALIDATEE SERVERTEST ABYSS_SUBDIR ENABLE_ABYSS_SERVER QUERY_MEERKAT AUTH_CLIENT ASYNCH_CLIENT SYNCH_CLIENT XMLRPC_TRANSPORT_H XMLRPC_CLIENT_H CLIENTTEST BUILD_XMLRPC_PSTREAM BUILD_TOOLS OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC MUST_BUILD_LIBWWW_CLIENT have_libwww_config MUST_BUILD_CURL_CLIENT have_curl_config MUST_BUILD_WININET_CLIENT have_wininet_config host_os host_vendor host_cpu host build_os build_vendor build_cpu build SET_MAKE MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_wininet_client enable_curl_client enable_libwww_client enable_abyss_server enable_cgi_server enable_cplusplus enable_abyss_threads with_libwww_ssl enable_libxml2_backend ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-wininet-client Don't build the Wininet client transport --disable-curl-client Don't build the Curl client transport --disable-libwww-client Don't build the Libwww client transport --disable-abyss-server Don't build the Abyss server module --disable-cgi-server Don't build the CGI server module --disable-cplusplus Don't build the C++ wrapper classes or tools --disable-abyss-threads Use fork in Abyss instead of pthreads --enable-libxml2-backend Use libxml2 instead of built-in expat Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-libwww-ssl Include libwww SSL capability. Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.67 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5 ; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers xmlrpc_amconfig.h" ac_config_commands="$ac_config_commands default-1" ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftestfile # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftestfile` fi if test "$*" != "X $srcdir/configure conftestfile" \ && test "$*" != "X conftestfile $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftestfile ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi rm -f conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi PACKAGE=xmlrpc-c VERSION=x.xx if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF missing_dir=`cd $ac_aux_dir && pwd` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working aclocal" >&5 $as_echo_n "checking for working aclocal... " >&6; } # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (aclocal --version) < /dev/null > /dev/null 2>&1; then ACLOCAL=aclocal { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } else ACLOCAL="$missing_dir/missing aclocal" { $as_echo "$as_me:${as_lineno-$LINENO}: result: missing" >&5 $as_echo "missing" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working autoconf" >&5 $as_echo_n "checking for working autoconf... " >&6; } # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (autoconf --version) < /dev/null > /dev/null 2>&1; then AUTOCONF=autoconf { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } else AUTOCONF="$missing_dir/missing autoconf" { $as_echo "$as_me:${as_lineno-$LINENO}: result: missing" >&5 $as_echo "missing" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working automake" >&5 $as_echo_n "checking for working automake... " >&6; } # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (automake --version) < /dev/null > /dev/null 2>&1; then AUTOMAKE=automake { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } else AUTOMAKE="$missing_dir/missing automake" { $as_echo "$as_me:${as_lineno-$LINENO}: result: missing" >&5 $as_echo "missing" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working autoheader" >&5 $as_echo_n "checking for working autoheader... " >&6; } # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (autoheader --version) < /dev/null > /dev/null 2>&1; then AUTOHEADER=autoheader { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } else AUTOHEADER="$missing_dir/missing autoheader" { $as_echo "$as_me:${as_lineno-$LINENO}: result: missing" >&5 $as_echo "missing" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working makeinfo" >&5 $as_echo_n "checking for working makeinfo... " >&6; } # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. if (makeinfo --version) < /dev/null > /dev/null 2>&1; then MAKEINFO=makeinfo { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } else MAKEINFO="$missing_dir/missing makeinfo" { $as_echo "$as_me:${as_lineno-$LINENO}: result: missing" >&5 $as_echo "missing" >&6; } fi # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if test "${ac_cv_build+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5 ;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if test "${ac_cv_host+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5 ;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac FEATURE_LIST= # Check whether --enable-wininet-client was given. if test "${enable_wininet_client+set}" = set; then : enableval=$enable_wininet_client; else enable_wininet_client=maybe fi if test $enable_wininet_client = maybe; then # Extract the first word of "wininet-config", so it can be a program name with args. set dummy wininet-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_have_wininet_config+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$have_wininet_config"; then ac_cv_prog_have_wininet_config="$have_wininet_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_have_wininet_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_have_wininet_config" && ac_cv_prog_have_wininet_config="no" fi fi have_wininet_config=$ac_cv_prog_have_wininet_config if test -n "$have_wininet_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_wininet_config" >&5 $as_echo "$have_wininet_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test $have_wininet_config = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: You don't appear to have Wininet installed (no working wininet-config in your command search path), so we will not build the Wininet client XML transport" >&5 $as_echo "$as_me: You don't appear to have Wininet installed (no working wininet-config in your command search path), so we will not build the Wininet client XML transport" >&6;} MUST_BUILD_WININET_CLIENT=no else MUST_BUILD_WININET_CLIENT=yes fi else MUST_BUILD_WININET_CLIENT=$enable_wininet_client fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Wininet client XML transport module" >&5 $as_echo_n "checking whether to build Wininet client XML transport module... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MUST_BUILD_WININET_CLIENT" >&5 $as_echo "$MUST_BUILD_WININET_CLIENT" >&6; } # Check whether --enable-curl-client was given. if test "${enable_curl_client+set}" = set; then : enableval=$enable_curl_client; else enable_curl_client=maybe fi if test $enable_curl_client = maybe; then # Extract the first word of "curl-config", so it can be a program name with args. set dummy curl-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_have_curl_config+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$have_curl_config"; then ac_cv_prog_have_curl_config="$have_curl_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_have_curl_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_have_curl_config" && ac_cv_prog_have_curl_config="no" fi fi have_curl_config=$ac_cv_prog_have_curl_config if test -n "$have_curl_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_curl_config" >&5 $as_echo "$have_curl_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test $have_curl_config = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: You don't appear to have Curl installed (no working curl-config in your command search path), so we will not build the Curl client XML transport" >&5 $as_echo "$as_me: You don't appear to have Curl installed (no working curl-config in your command search path), so we will not build the Curl client XML transport" >&6;} MUST_BUILD_CURL_CLIENT=no else MUST_BUILD_CURL_CLIENT=yes fi else MUST_BUILD_CURL_CLIENT=$enable_curl_client fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Curl client XML transport module" >&5 $as_echo_n "checking whether to build Curl client XML transport module... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MUST_BUILD_CURL_CLIENT" >&5 $as_echo "$MUST_BUILD_CURL_CLIENT" >&6; } # Check whether --enable-libwww-client was given. if test "${enable_libwww_client+set}" = set; then : enableval=$enable_libwww_client; else enable_libwww_client=maybe fi if test $enable_libwww_client = maybe; then # Extract the first word of "libwww-config", so it can be a program name with args. set dummy libwww-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_have_libwww_config+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$have_libwww_config"; then ac_cv_prog_have_libwww_config="$have_libwww_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_have_libwww_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_have_libwww_config" && ac_cv_prog_have_libwww_config="no" fi fi have_libwww_config=$ac_cv_prog_have_libwww_config if test -n "$have_libwww_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_libwww_config" >&5 $as_echo "$have_libwww_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test $have_libwww_config = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: You don't appear to have Libwww installed (no working libwww-config in your command search path), so we will not build the Libwww client XML transport" >&5 $as_echo "$as_me: You don't appear to have Libwww installed (no working libwww-config in your command search path), so we will not build the Libwww client XML transport" >&6;} MUST_BUILD_LIBWWW_CLIENT=no else MUST_BUILD_LIBWWW_CLIENT=yes fi else MUST_BUILD_LIBWWW_CLIENT=$enable_libwww_client fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Libwww client XML transport module" >&5 $as_echo_n "checking whether to build Libwww client XML transport module... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MUST_BUILD_LIBWWW_CLIENT" >&5 $as_echo "$MUST_BUILD_LIBWWW_CLIENT" >&6; } # The first AC_CHECK_LIB has to be in unconditional code because as a # side effect, it determines what the object file suffix is on this system, # and if it is statically present even though not actually executed, Autoconf # later thinks it has already computed the object file suffix and uses it # without computing it. This was with Autoconf 2.59 ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5 ; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5 ; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lncurses" >&5 $as_echo_n "checking for main in -lncurses... " >&6; } if test "${ac_cv_lib_ncurses_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lncurses $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ncurses_main=yes else ac_cv_lib_ncurses_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_main" >&5 $as_echo "$ac_cv_lib_ncurses_main" >&6; } if test "x$ac_cv_lib_ncurses_main" = x""yes; then : have_libncurses=yes else have_libncurses=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lreadline" >&5 $as_echo_n "checking for main in -lreadline... " >&6; } if test "${ac_cv_lib_readline_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_readline_main=yes else ac_cv_lib_readline_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_main" >&5 $as_echo "$ac_cv_lib_readline_main" >&6; } if test "x$ac_cv_lib_readline_main" = x""yes; then : have_libreadline=yes else have_libreadline=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build tools" >&5 $as_echo_n "checking whether to build tools... " >&6; } BUILD_XMLRPC_PSTREAM=no if ! test "$MUST_BUILD_WININET_CLIENT $MUST_BUILD_CURL_CLIENT $MUST_BUILD_LIBWWW_CLIENT" = "no no no"; then if test $have_libreadline = yes && test $have_libncurses = yes; then BUILD_XMLRPC_PSTREAM=yes fi BUILD_TOOLS=yes else BUILD_TOOLS=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_TOOLS" >&5 $as_echo "$BUILD_TOOLS" >&6; } if test $BUILD_TOOLS = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build the xmlrpc_pstream tool" >&5 $as_echo_n "checking whether to build the xmlrpc_pstream tool... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_XMLRPC_PSTREAM" >&5 $as_echo "$BUILD_XMLRPC_PSTREAM" >&6; } fi CLIENTTEST=clienttest XMLRPC_CLIENT_H=xmlrpc_client.h XMLRPC_TRANSPORT_H=xmlrpc_transport.h SYNCH_CLIENT=synch_client ASYNCH_CLIENT=asynch_client AUTH_CLIENT=auth_client QUERY_MEERKAT=query-meerkat if test $MUST_BUILD_WININET_CLIENT = yes; then FEATURE_LIST="wininet-client $FEATURE_LIST" fi if test $MUST_BUILD_CURL_CLIENT = yes; then FEATURE_LIST="curl-client $FEATURE_LIST" fi if test $MUST_BUILD_LIBWWW_CLIENT = yes; then FEATURE_LIST="libwww-client $FEATURE_LIST" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Abyss server module" >&5 $as_echo_n "checking whether to build Abyss server module... " >&6; } # Check whether --enable-abyss-server was given. if test "${enable_abyss_server+set}" = set; then : enableval=$enable_abyss_server; else enable_abyss_server=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_abyss_server" >&5 $as_echo "$enable_abyss_server" >&6; } ENABLE_ABYSS_SERVER=$enable_abyss_server ABYSS_SUBDIR= SERVERTEST= VALIDATEE= XMLRPC_ABYSS_H= SERVER= if test x"$enable_abyss_server" != xno; then FEATURE_LIST="abyss-server $FEATURE_LIST" ABYSS_SUBDIR=abyss SERVERTEST=servertest VALIDATEE=validatee XMLRPC_ABYSS_H=xmlrpc_abyss.h SERVER=server fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build CGI server module" >&5 $as_echo_n "checking whether to build CGI server module... " >&6; } # Check whether --enable-cgi-server was given. if test "${enable_cgi_server+set}" = set; then : enableval=$enable_cgi_server; else enable_cgi_server=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_cgi_server" >&5 $as_echo "$enable_cgi_server" >&6; } ENABLE_CGI_SERVER=$enable_cgi_server { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build C++ wrappers and tools" >&5 $as_echo_n "checking whether to build C++ wrappers and tools... " >&6; } # Check whether --enable-cplusplus was given. if test "${enable_cplusplus+set}" = set; then : enableval=$enable_cplusplus; else enable_cplusplus=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_cplusplus" >&5 $as_echo "$enable_cplusplus" >&6; } ENABLE_CPLUSPLUS=$enable_cplusplus LIBXMLRPC_CPP_A= CPPTEST= XMLRPCCPP_H= XML_RPC_API2CPP_SUBDIR= MEERKAT_APP_LIST= INTEROP_CLIENT_SUBDIR= if test x"$enable_cplusplus" != xno; then FEATURE_LIST="c++ $FEATURE_LIST" LIBXMLRPC_CPP_A=libxmlrpc_cpp.a CPPTEST=cpptest XMLRPCCPP_H=XmlRpcCpp.h if test $MUST_BUILD_LIBWWW_CLIENT = yes; then XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp elif test $MUST_BUILD_CURL_CLIENT = yes; then XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test x"$enable_cplusplus" != xno; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi # Code by albert chin to check for various # oddball networking libraries. Solaris and some other operating systems # hide their networking code in various places. (Yes, this links too many # of our libraries against -lsocket, but a finer-grained mechanism would # require too much testing.) ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" if test "x$ac_cv_func_socket" = x""yes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } if test "${ac_cv_lib_socket_socket+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_socket=yes else ac_cv_lib_socket_socket=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } if test "x$ac_cv_lib_socket_socket" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi fi # Above sets LIBS, which is not all that useful because we don't want # to include every library in every link. It also sets # ac_cv_lib_socket_socket, which we use to pass more specific information # to the configuration files. if test x"$ac_cv_lib_socket_socket" = xyes; then LSOCKET=-lsocket else LSOCKET= fi # For some reason, we don't seem to need this on Solaris. If you do # need it, go ahead and try it. # AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent)) ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in wchar.h do : ac_fn_c_check_header_mongrel "$LINENO" "wchar.h" "ac_cv_header_wchar_h" "$ac_includes_default" if test "x$ac_cv_header_wchar_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_WCHAR_H 1 _ACEOF fi done if test x"$ac_cv_header_wchar_h" = xyes; then HAVE_WCHAR_H_DEFINE=1 else HAVE_WCHAR_H_DEFINE=0 fi # Needed by Abyss on Solaris: for ac_header in sys/filio.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/filio.h" "ac_cv_header_sys_filio_h" "$ac_includes_default" if test "x$ac_cv_header_sys_filio_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_FILIO_H 1 _ACEOF fi done if test x"$ac_cv_header_sys_filio_h" = xyes; then HAVE_SYS_FILIO_H_DEFINE=1 else HAVE_SYS_FILIO_H_DEFINE=0 fi # Needed by Abyss on Solaris: for ac_header in sys/ioctl.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ioctl_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_IOCTL_H 1 _ACEOF fi done if test x"$ac_cv_header_sys_ioctl_h" = xyes; then HAVE_SYS_IOCTL_H_DEFINE=1 else HAVE_SYS_IOCTL_H_DEFINE=0 fi for ac_header in sys/select.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" if test "x$ac_cv_header_sys_select_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_SELECT_H 1 _ACEOF fi done if test x"$ac_cv_header_sys_select_h" = xyes; then HAVE_SYS_SELECT_H_DEFINE=1 else HAVE_SYS_SELECT_H_DEFINE=0 fi for ac_header in stdarg.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdarg.h" "ac_cv_header_stdarg_h" "$ac_includes_default" if test "x$ac_cv_header_stdarg_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDARG_H 1 _ACEOF else as_fn_error $? "stdarg.h is required to build this library" "$LINENO" 5 fi done ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi va_list_is_array=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether va_list is an array" >&5 $as_echo_n "checking whether va_list is an array... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { va_list list1, list2; list1 = list2; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else va_list_is_array=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $va_list_is_array" >&5 $as_echo "$va_list_is_array" >&6; } if test x"$va_list_is_array" = xyes; then VA_LIST_IS_ARRAY_DEFINE=1 else VA_LIST_IS_ARRAY_DEFINE=0 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler has __attribute__" >&5 $as_echo_n "checking whether compiler has __attribute__... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { int x __attribute__((__unused__)); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : compiler_has_attribute=yes else compiler_has_attribute=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $compiler_has_attribute" >&5 $as_echo "$compiler_has_attribute" >&6; } if test x"$compiler_has_attribute" = xyes; then ATTR_UNUSED="__attribute__((__unused__))" else ATTR_UNUSED= fi ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" if test "x$ac_cv_func_vsnprintf" = x""yes; then : else as_fn_error $? "your C library does not provide vsnprintf" "$LINENO" 5 fi for ac_func in wcsncmp do : ac_fn_c_check_func "$LINENO" "wcsncmp" "ac_cv_func_wcsncmp" if test "x$ac_cv_func_wcsncmp" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_WCSNCMP 1 _ACEOF fi done for ac_func in setgroups do : ac_fn_c_check_func "$LINENO" "setgroups" "ac_cv_func_setgroups" if test "x$ac_cv_func_setgroups" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETGROUPS 1 _ACEOF fi done for ac_func in asprintf do : ac_fn_c_check_func "$LINENO" "asprintf" "ac_cv_func_asprintf" if test "x$ac_cv_func_asprintf" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ASPRINTF 1 _ACEOF fi done for ac_func in setenv strtoll strtoull strtoq strtouq __strtoll __strtoull do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in pselect do : ac_fn_c_check_func "$LINENO" "pselect" "ac_cv_func_pselect" if test "x$ac_cv_func_pselect" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PSELECT 1 _ACEOF fi done for ac_func in gettimeofday do : ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" if test "x$ac_cv_func_gettimeofday" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETTIMEOFDAY 1 _ACEOF fi done for ac_func in localtime_r do : ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r" if test "x$ac_cv_func_localtime_r" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LOCALTIME_R 1 _ACEOF fi done for ac_func in gmtime_r do : ac_fn_c_check_func "$LINENO" "gmtime_r" "ac_cv_func_gmtime_r" if test "x$ac_cv_func_gmtime_r" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GMTIME_R 1 _ACEOF fi done for ac_func in strcasecmp do : ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp" if test "x$ac_cv_func_strcasecmp" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRCASECMP 1 _ACEOF fi done for ac_func in stricmp do : ac_fn_c_check_func "$LINENO" "stricmp" "ac_cv_func_stricmp" if test "x$ac_cv_func_stricmp" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRICMP 1 _ACEOF fi done for ac_func in _stricmp do : ac_fn_c_check_func "$LINENO" "_stricmp" "ac_cv_func__stricmp" if test "x$ac_cv_func__stricmp" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE__STRICMP 1 _ACEOF fi done case "$host_os" in *mingw*) DIRECTORY_SEPARATOR="\\\\" ;; *) DIRECTORY_SEPARATOR="/" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use Abyss pthread function" >&5 $as_echo_n "checking whether to use Abyss pthread function... " >&6; } # Check whether --enable-abyss-threads was given. if test "${enable_abyss_threads+set}" = set; then : enableval=$enable_abyss_threads; else enable_abyss_threads=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_abyss_threads" >&5 $as_echo "$enable_abyss_threads" >&6; } ENABLE_ABYSS_THREADS=$enable_abyss_threads if test x"$enable_abyss_threads" != xno; then CFLAGS="$CFLAGS -D_THREAD" fi if test $MUST_BUILD_WININET_CLIENT = yes; then for ac_prog in wininet-xmlrpc-config wininet-config do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_WININET_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $WININET_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_WININET_CONFIG="$WININET_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_WININET_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi WININET_CONFIG=$ac_cv_path_WININET_CONFIG if test -n "$WININET_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WININET_CONFIG" >&5 $as_echo "$WININET_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$WININET_CONFIG" && break done test -n "$WININET_CONFIG" || WININET_CONFIG="no" if test "x$WININET_CONFIG" = "xno"; then as_fn_error then not found "Configure INTERNAL ERROR - first wininet-config found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wininet version >= 1.0.0" >&5 $as_echo_n "checking for wininet version >= 1.0.0... " >&6; } W3VER=$($WININET_CONFIG --version) WININET_MAJOR=\ $(echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/') WININET_MINOR=\ $(echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/') WININET_MICRO=\ $(echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/') { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WININET_MAJOR.$WININET_MINOR.$WININET_MICRO" >&5 $as_echo "$WININET_MAJOR.$WININET_MINOR.$WININET_MICRO" >&6; } WININET_VERSION_OK=yes if test $WININET_MAJOR -lt 1; then WININET_VERSION_OK=no else if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -lt 0; then WININET_VERSION_OK=no else if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -eq 0 \ -a $WININET_MICRO -lt 0; then WININET_VERSION_OK=no fi fi fi if test "x$WININET_VERSION_OK" = "xno"; then as_fn_error $? "wininet version >= 1.0.0 required" "$LINENO" 5 fi WININET_CFLAGS=$($WININET_CONFIG --cflags) CFLAGS="$CFLAGS $WININET_CFLAGS" WININET_LDADD=$($WININET_CONFIG --libs) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wininet library directory" >&5 $as_echo_n "checking for wininet library directory... " >&6; } WININET_LIBDIR="$($WININET_CONFIG --prefix)/lib" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WININET_LIBDIR" >&5 $as_echo "$WININET_LIBDIR" >&6; } fi # MUST_BUILD_WININET_CLIENT if test $MUST_BUILD_LIBWWW_CLIENT = yes; then for ac_prog in libwww-xmlrpc-config libwww-config do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_LIBWWW_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $LIBWWW_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_LIBWWW_CONFIG="$LIBWWW_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LIBWWW_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi LIBWWW_CONFIG=$ac_cv_path_LIBWWW_CONFIG if test -n "$LIBWWW_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBWWW_CONFIG" >&5 $as_echo "$LIBWWW_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$LIBWWW_CONFIG" && break done test -n "$LIBWWW_CONFIG" || LIBWWW_CONFIG="no" if test "x$LIBWWW_CONFIG" = "xno"; then as_fn_error then not found "Configure INTERNAL ERROR - first libwww-config found" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for w3c-libwww version >= 5.2.8" >&5 $as_echo_n "checking for w3c-libwww version >= 5.2.8... " >&6; } W3VER=$($LIBWWW_CONFIG --version) LIBWWW_MAJOR=\ $(echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/') LIBWWW_MINOR=\ $(echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/') LIBWWW_MICRO=\ $(echo $W3VER|sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/') { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBWWW_MAJOR.$LIBWWW_MINOR.$LIBWWW_MICRO" >&5 $as_echo "$LIBWWW_MAJOR.$LIBWWW_MINOR.$LIBWWW_MICRO" >&6; } LIBWWW_VERSION_OK=yes if test $LIBWWW_MAJOR -lt 5; then LIBWWW_VERSION_OK=no else if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -lt 2; then LIBWWW_VERSION_OK=no else if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -eq 2 \ -a $LIBWWW_MICRO -lt 8; then LIBWWW_VERSION_OK=no fi fi fi if test "x$LIBWWW_VERSION_OK" = "xno"; then as_fn_error $? "w3c-libwww version >= 5.2.8 required" "$LINENO" 5 fi LIBWWW_LDADD=$($LIBWWW_CONFIG --libs) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libwww library directory" >&5 $as_echo_n "checking for libwww library directory... " >&6; } LIBWWW_LIBDIR="$($LIBWWW_CONFIG --prefix)/lib" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBWWW_LIBDIR" >&5 $as_echo "$LIBWWW_LIBDIR" >&6; } fi # MUST_BUILD_LIBWWW_CLIENT if test $MUST_BUILD_CURL_CLIENT = yes; then for ac_prog in curl-xmlrpc-config curl-config do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_CURL_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $CURL_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_CURL_CONFIG="$CURL_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_CURL_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CURL_CONFIG=$ac_cv_path_CURL_CONFIG if test -n "$CURL_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CURL_CONFIG" >&5 $as_echo "$CURL_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CURL_CONFIG" && break done test -n "$CURL_CONFIG" || CURL_CONFIG="no" if test "x$CURL_CONFIG" = "xno"; then as_fn_error then not found "Configure INTERNAL ERROR - first curl-config found" "$LINENO" 5 fi CURL_LDADD=$($CURL_CONFIG --libs) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Curl library directory" >&5 $as_echo_n "checking for Curl library directory... " >&6; } CURL_LIBDIR="$($CURL_CONFIG --prefix)/lib" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CURL_LIBDIR" >&5 $as_echo "$CURL_LIBDIR" >&6; } fi # MUST_BUILD_CURL_CLIENT # Check whether --with-libwww-ssl was given. if test "${with_libwww_ssl+set}" = set; then : withval=$with_libwww_ssl; fi if test x"$enable_libwww_client" != xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use SSL with libwww" >&5 $as_echo_n "checking whether to use SSL with libwww... " >&6; } if test x"$with_libwww_ssl" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } HAVE_LIBWWW_SSL_DEFINE=1 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } HAVE_LIBWWW_SSL_DEFINE=0 fi else HAVE_LIBWWW_SSL_DEFINE=0 fi # Check whether --enable-libxml2-backend was given. if test "${enable_libxml2_backend+set}" = set; then : enableval=$enable_libxml2_backend; else enable_libxml2_backend=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build the libxml2 backend" >&5 $as_echo_n "checking whether to build the libxml2 backend... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libxml2_backend" >&5 $as_echo "$enable_libxml2_backend" >&6; } if test $enable_libxml2_backend = yes; then # Extract the first word of "xml2-config", so it can be a program name with args. set dummy xml2-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_have_xml2_config+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$have_xml2_config"; then ac_cv_prog_have_xml2_config="$have_xml2_config" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_have_xml2_config="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_have_xml2_config" && ac_cv_prog_have_xml2_config="no" fi fi have_xml2_config=$ac_cv_prog_have_xml2_config if test -n "$have_xml2_config"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_xml2_config" >&5 $as_echo "$have_xml2_config" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test $have_xml2_config = no; then as_fn_error $? "You specified --enable-libxml2_backend, but don't appear to have libxml2 installed (no working xml2-config in your command search path), so we cannot not build for libxml2" "$LINENO" 5 fi fi ENABLE_LIBXML2_BACKEND=$enable_libxml2_backend C_COMPILER_GNU=$ac_cv_c_compiler_gnu CXX_COMPILER_GNU=$ac_cv_cxx_compiler_gnu CC_WARN_FLAGS= CPP_WARN_FLAGS= BUILDDIR=$(pwd) AR=${ac_tool_prefix}ar RANLIB=${ac_tool_prefix}ranlib ac_config_files="$ac_config_files srcdir.mk config.mk xmlrpc_config.h" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "xmlrpc_amconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS xmlrpc_amconfig.h" ;; "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; "srcdir.mk") CONFIG_FILES="$CONFIG_FILES srcdir.mk" ;; "config.mk") CONFIG_FILES="$CONFIG_FILES config.mk" ;; "xmlrpc_config.h") CONFIG_FILES="$CONFIG_FILES xmlrpc_config.h" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_t=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_t"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "default-1":C) test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi if test ! -f GNUmakefile; then ln -s "${srcdir}/GNUmakefile" . fi if test ! -f Makefile; then ln -s "${srcdir}/Makefile" . fi if test ! -f transport_config.mk; then ln -s "${srcdir}/transport_config.mk" . fi if test "$MUST_BUILD_WININET_CLIENT $MUST_BUILD_CURL_CLIENT $MUST_BUILD_LIBWWW_CLIENT" = "no no no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: ==>" >&5 $as_echo "$as_me: ==>" >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: ==>We are not building any client XML transport (see earlier messages explaining why), therefore WE WILL NOT BUILD THE CLIENT LIBRARY." >&5 $as_echo "$as_me: ==>We are not building any client XML transport (see earlier messages explaining why), therefore WE WILL NOT BUILD THE CLIENT LIBRARY." >&6;} { $as_echo "$as_me:${as_lineno-$LINENO}: ==>" >&5 $as_echo "$as_me: ==>" >&6;} fi xmlrpc-c-1.33.14/configure.in000066400000000000000000000506401236133176700157370ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. AC_INIT(include/xmlrpc-c/base.h) AM_CONFIG_HEADER(xmlrpc_amconfig.h) dnl ======================================================================= dnl Define PACKAGE, VERSION, @PACKAGE@, @VERSION@ dnl ======================================================================= dnl "x.xx" is supposed to be a version number, but is meaningless here. dnl The real version number is in Makefile.version. AM_INIT_AUTOMAKE(xmlrpc-c, x.xx) dnl Define @build@, @build_cpu@, @build_vendor@, @build_os, dnl @host, @host_cpu@, @host_vender, and @host_os@ substitutions. dnl "host" means the target system -- the one for which we are building. dnl "build" means the system that will do the building. AC_CANONICAL_HOST dnl ======================================================================= dnl Decide What To Build dnl ======================================================================= FEATURE_LIST= AC_ARG_ENABLE(wininet-client, [ --disable-wininet-client Don't build the Wininet client transport], , enable_wininet_client=maybe) if test $enable_wininet_client = maybe; then AC_CHECK_PROG(have_wininet_config, wininet-config, yes, no) if test $have_wininet_config = no; then AC_MSG_NOTICE([You don't appear to have Wininet installed (no working wininet-config in your command search path), so we will not build the Wininet client XML transport]) MUST_BUILD_WININET_CLIENT=no else MUST_BUILD_WININET_CLIENT=yes fi else MUST_BUILD_WININET_CLIENT=$enable_wininet_client fi AC_MSG_CHECKING(whether to build Wininet client XML transport module) AC_MSG_RESULT($MUST_BUILD_WININET_CLIENT) AC_SUBST(MUST_BUILD_WININET_CLIENT) AC_ARG_ENABLE(curl-client, [ --disable-curl-client Don't build the Curl client transport], , enable_curl_client=maybe) if test $enable_curl_client = maybe; then AC_CHECK_PROG(have_curl_config, curl-config, yes, no) if test $have_curl_config = no; then AC_MSG_NOTICE([You don't appear to have Curl installed (no working curl-config in your command search path), so we will not build the Curl client XML transport]) MUST_BUILD_CURL_CLIENT=no else MUST_BUILD_CURL_CLIENT=yes fi else MUST_BUILD_CURL_CLIENT=$enable_curl_client fi AC_MSG_CHECKING(whether to build Curl client XML transport module) AC_MSG_RESULT($MUST_BUILD_CURL_CLIENT) AC_SUBST(MUST_BUILD_CURL_CLIENT) AC_ARG_ENABLE(libwww-client, [ --disable-libwww-client Don't build the Libwww client transport], , enable_libwww_client=maybe) if test $enable_libwww_client = maybe; then AC_CHECK_PROG(have_libwww_config, libwww-config, yes, no) if test $have_libwww_config = no; then AC_MSG_NOTICE([You don't appear to have Libwww installed (no working libwww-config in your command search path), so we will not build the Libwww client XML transport]) MUST_BUILD_LIBWWW_CLIENT=no else MUST_BUILD_LIBWWW_CLIENT=yes fi else MUST_BUILD_LIBWWW_CLIENT=$enable_libwww_client fi AC_MSG_CHECKING(whether to build Libwww client XML transport module) AC_MSG_RESULT($MUST_BUILD_LIBWWW_CLIENT) AC_SUBST(MUST_BUILD_LIBWWW_CLIENT) # The first AC_CHECK_LIB has to be in unconditional code because as a # side effect, it determines what the object file suffix is on this system, # and if it is statically present even though not actually executed, Autoconf # later thinks it has already computed the object file suffix and uses it # without computing it. This was with Autoconf 2.59 AC_CHECK_LIB(ncurses, main, [have_libncurses=yes], [have_libncurses=no]) AC_CHECK_LIB(readline, main, [have_libreadline=yes], [have_libreadline=no]) AC_MSG_CHECKING(whether to build tools) BUILD_XMLRPC_PSTREAM=no if ! test "$MUST_BUILD_WININET_CLIENT $MUST_BUILD_CURL_CLIENT $MUST_BUILD_LIBWWW_CLIENT" = "no no no"; then if test $have_libreadline = yes && test $have_libncurses = yes; then BUILD_XMLRPC_PSTREAM=yes fi BUILD_TOOLS=yes else BUILD_TOOLS=no fi AC_MSG_RESULT($BUILD_TOOLS) AC_SUBST(BUILD_TOOLS) if test $BUILD_TOOLS = yes; then AC_MSG_CHECKING(whether to build the xmlrpc_pstream tool) AC_MSG_RESULT($BUILD_XMLRPC_PSTREAM) AC_SUBST(BUILD_XMLRPC_PSTREAM) fi dnl Set up the appropriate Makefile substitutions. CLIENTTEST=clienttest AC_SUBST(CLIENTTEST) XMLRPC_CLIENT_H=xmlrpc_client.h AC_SUBST(XMLRPC_CLIENT_H) XMLRPC_TRANSPORT_H=xmlrpc_transport.h AC_SUBST(XMLRPC_TRANSPORT_H) SYNCH_CLIENT=synch_client AC_SUBST(SYNCH_CLIENT) ASYNCH_CLIENT=asynch_client AC_SUBST(ASYNCH_CLIENT) AUTH_CLIENT=auth_client AC_SUBST(AUTH_CLIENT) QUERY_MEERKAT=query-meerkat AC_SUBST(QUERY_MEERKAT) if test $MUST_BUILD_WININET_CLIENT = yes; then FEATURE_LIST="wininet-client $FEATURE_LIST" fi if test $MUST_BUILD_CURL_CLIENT = yes; then FEATURE_LIST="curl-client $FEATURE_LIST" fi if test $MUST_BUILD_LIBWWW_CLIENT = yes; then FEATURE_LIST="libwww-client $FEATURE_LIST" fi dnl Check to see if we should build our Abyss server module. AC_MSG_CHECKING(whether to build Abyss server module) AC_ARG_ENABLE(abyss-server, [ --disable-abyss-server Don't build the Abyss server module], , enable_abyss_server=yes) AC_MSG_RESULT($enable_abyss_server) ENABLE_ABYSS_SERVER=$enable_abyss_server AC_SUBST(ENABLE_ABYSS_SERVER) dnl Set up the appropriate Makefile substitutions. ABYSS_SUBDIR= SERVERTEST= VALIDATEE= XMLRPC_ABYSS_H= SERVER= if test x"$enable_abyss_server" != xno; then FEATURE_LIST="abyss-server $FEATURE_LIST" ABYSS_SUBDIR=abyss SERVERTEST=servertest VALIDATEE=validatee XMLRPC_ABYSS_H=xmlrpc_abyss.h SERVER=server fi AC_SUBST(ABYSS_SUBDIR) AC_SUBST(SERVERTEST) AC_SUBST(VALIDATEE) AC_SUBST(XMLRPC_ABYSS_H) AC_SUBST(SERVER) dnl Check to see if we should build our CGI server module. AC_MSG_CHECKING(whether to build CGI server module) AC_ARG_ENABLE(cgi-server, [ --disable-cgi-server Don't build the CGI server module], , enable_cgi_server=yes) AC_MSG_RESULT($enable_cgi_server) ENABLE_CGI_SERVER=$enable_cgi_server AC_SUBST(ENABLE_CGI_SERVER) dnl Check to see if we should build our C++ stuff. AC_MSG_CHECKING(whether to build C++ wrappers and tools) AC_ARG_ENABLE(cplusplus, [ --disable-cplusplus Don't build the C++ wrapper classes or tools], , enable_cplusplus=yes) AC_MSG_RESULT($enable_cplusplus) ENABLE_CPLUSPLUS=$enable_cplusplus AC_SUBST(ENABLE_CPLUSPLUS) dnl Set up the appropriate Makefile substitutions. LIBXMLRPC_CPP_A= CPPTEST= XMLRPCCPP_H= XML_RPC_API2CPP_SUBDIR= MEERKAT_APP_LIST= INTEROP_CLIENT_SUBDIR= if test x"$enable_cplusplus" != xno; then FEATURE_LIST="c++ $FEATURE_LIST" LIBXMLRPC_CPP_A=libxmlrpc_cpp.a CPPTEST=cpptest XMLRPCCPP_H=XmlRpcCpp.h if test $MUST_BUILD_LIBWWW_CLIENT = yes; then XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp elif test $MUST_BUILD_CURL_CLIENT = yes; then XML_RPC_API2CPP_SUBDIR=xml-rpc-api2cpp fi fi AC_SUBST(LIBXMLRPC_CPP_A) AC_SUBST(CPPTEST) AC_SUBST(XMLRPCCPP_H) AC_SUBST(XML_RPC_API2CPP_SUBDIR) AC_SUBST(FEATURE_LIST) dnl ======================================================================= dnl Checks for programs. dnl ======================================================================= AC_PROG_CC if test x"$enable_cplusplus" != xno; then AC_PROG_CXX fi dnl ======================================================================= dnl Checks for libraries. dnl ======================================================================= # Code by albert chin to check for various # oddball networking libraries. Solaris and some other operating systems # hide their networking code in various places. (Yes, this links too many # of our libraries against -lsocket, but a finer-grained mechanism would # require too much testing.) AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket)) # Above sets LIBS, which is not all that useful because we don't want # to include every library in every link. It also sets # ac_cv_lib_socket_socket, which we use to pass more specific information # to the configuration files. if test x"$ac_cv_lib_socket_socket" = xyes; then LSOCKET=-lsocket else LSOCKET= fi AC_SUBST(LSOCKET) # For some reason, we don't seem to need this on Solaris. If you do # need it, go ahead and try it. # AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent)) dnl ======================================================================= dnl Checks for header files. dnl ======================================================================= AC_STDC_HEADERS dnl We don't use AM_CONFIG_HEADER to define HAVE_WCHAR_H, etc. because dnl the following is more straightforward and easier to understand, dnl especially for a newcomer. Furthermore, AM_CONFIG_HEADER represents dnl false as undefined, whereas our scheme represents it as 0. undefined dnl is a poor choice because it often means just that you neglected to dnl choose a value for some reason. dnl defines ac_cv_header_wchar_h, etc: AC_CHECK_HEADERS(wchar.h) if test x"$ac_cv_header_wchar_h" = xyes; then HAVE_WCHAR_H_DEFINE=1 else HAVE_WCHAR_H_DEFINE=0 fi AC_SUBST(HAVE_WCHAR_H_DEFINE) # Needed by Abyss on Solaris: AC_CHECK_HEADERS(sys/filio.h) if test x"$ac_cv_header_sys_filio_h" = xyes; then HAVE_SYS_FILIO_H_DEFINE=1 else HAVE_SYS_FILIO_H_DEFINE=0 fi AC_SUBST(HAVE_SYS_FILIO_H_DEFINE) # Needed by Abyss on Solaris: AC_CHECK_HEADERS(sys/ioctl.h) if test x"$ac_cv_header_sys_ioctl_h" = xyes; then HAVE_SYS_IOCTL_H_DEFINE=1 else HAVE_SYS_IOCTL_H_DEFINE=0 fi AC_SUBST(HAVE_SYS_IOCTL_H_DEFINE) AC_CHECK_HEADERS(sys/select.h) if test x"$ac_cv_header_sys_select_h" = xyes; then HAVE_SYS_SELECT_H_DEFINE=1 else HAVE_SYS_SELECT_H_DEFINE=0 fi AC_SUBST(HAVE_SYS_SELECT_H_DEFINE) AC_CHECK_HEADERS(stdarg.h, , [ AC_MSG_ERROR(stdarg.h is required to build this library) ]) dnl ======================================================================= dnl Checks for typedefs, structures, and compiler characteristics. dnl ======================================================================= dnl AC_C_BIGENDIAN AC_TYPE_SIZE_T dnl This check is borrowed from Python 1.5.2. va_list_is_array=no AC_MSG_CHECKING(whether va_list is an array) AC_TRY_COMPILE([ #include ], [va_list list1, list2; list1 = list2;], , va_list_is_array=yes) AC_MSG_RESULT($va_list_is_array) if test x"$va_list_is_array" = xyes; then VA_LIST_IS_ARRAY_DEFINE=1 else VA_LIST_IS_ARRAY_DEFINE=0 fi AC_SUBST(VA_LIST_IS_ARRAY_DEFINE) AC_MSG_CHECKING(whether compiler has __attribute__) AC_TRY_COMPILE(, [int x __attribute__((__unused__));], compiler_has_attribute=yes, compiler_has_attribute=no) AC_MSG_RESULT($compiler_has_attribute) if test x"$compiler_has_attribute" = xyes; then ATTR_UNUSED="__attribute__((__unused__))" else ATTR_UNUSED= fi AC_SUBST(ATTR_UNUSED) dnl ======================================================================= dnl Checks for library functions. dnl ======================================================================= AC_CHECK_FUNC(vsnprintf, , [ AC_MSG_ERROR(your C library does not provide vsnprintf) ]) dnl Unicode function needed by test suites. AC_CHECK_FUNCS(wcsncmp) dnl CygWin doesn't provide setgroups. AC_CHECK_FUNCS(setgroups) AC_CHECK_FUNCS(asprintf) AC_CHECK_FUNCS(setenv strtoll strtoull strtoq strtouq __strtoll __strtoull) dnl uclib doesn't have pselect AC_CHECK_FUNCS(pselect) dnl Windows doesn't have gettimeofday, localtime_r, or gmtime_r AC_CHECK_FUNCS(gettimeofday) AC_CHECK_FUNCS(localtime_r) AC_CHECK_FUNCS(gmtime_r) dnl Windows doesn't have strcasecmp; AC_CHECK_FUNCS(strcasecmp) AC_CHECK_FUNCS(stricmp) AC_CHECK_FUNCS(_stricmp) dnl ======================================================================= dnl Checks for operating system features. dnl ======================================================================= dnl Non-Unix systems will need to set up their platform configuration file dnl by hand. case "$host_os" in *mingw*) DIRECTORY_SEPARATOR="\\\\" ;; *) DIRECTORY_SEPARATOR="/" ;; esac AC_SUBST(DIRECTORY_SEPARATOR) dnl ======================================================================= dnl ABYSS Configuration dnl ======================================================================= AC_MSG_CHECKING(whether to use Abyss pthread function) AC_ARG_ENABLE(abyss-threads, [ --disable-abyss-threads Use fork in Abyss instead of pthreads], , enable_abyss_threads=yes) AC_MSG_RESULT($enable_abyss_threads) ENABLE_ABYSS_THREADS=$enable_abyss_threads AC_SUBST(ENABLE_ABYSS_THREADS) if test x"$enable_abyss_threads" != xno; then CFLAGS="$CFLAGS -D_THREAD" fi dnl ======================================================================= dnl Finding wininet stubs dnl ======================================================================= dnl If you implement the parts of wininet.h the wininet_transport uses, dnl you will need to configure this way.. if test $MUST_BUILD_WININET_CLIENT = yes; then dnl You can control which of these gets chosen by controlling PATH. AC_PATH_PROGS(WININET_CONFIG, wininet-xmlrpc-config wininet-config, no) if test "x$WININET_CONFIG" = "xno"; then AC_MSG_ERROR(Configure INTERNAL ERROR - first wininet-config found, then not found) fi dnl Get our wininet version. dnl Adapted from a macro which called gtk-config. AC_MSG_CHECKING(for wininet version >= 1.0.0) W3VER=$($WININET_CONFIG --version) WININET_MAJOR=\ $(echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/') WININET_MINOR=\ $(echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/') WININET_MICRO=\ $(echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/') AC_MSG_RESULT($WININET_MAJOR.$WININET_MINOR.$WININET_MICRO) dnl Check to make sure our version is OK. WININET_VERSION_OK=yes if test $WININET_MAJOR -lt 1; then WININET_VERSION_OK=no else if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -lt 0; then WININET_VERSION_OK=no else if test $WININET_MAJOR -eq 1 -a $WININET_MINOR -eq 0 \ -a $WININET_MICRO -lt 0; then WININET_VERSION_OK=no fi fi fi if test "x$WININET_VERSION_OK" = "xno"; then AC_MSG_ERROR(wininet version >= 1.0.0 required) fi dnl Get the necessary CFLAGS, and merge them into our master list. WININET_CFLAGS=$($WININET_CONFIG --cflags) AC_SUBST(WININET_CFLAGS) CFLAGS="$CFLAGS $WININET_CFLAGS" dnl Get the huge list of libraries we need to link against. WININET_LDADD=$($WININET_CONFIG --libs) AC_SUBST(WININET_LDADD) AC_MSG_CHECKING(for wininet library directory) WININET_LIBDIR="$($WININET_CONFIG --prefix)/lib" AC_MSG_RESULT($WININET_LIBDIR) AC_SUBST(WININET_LIBDIR) fi # MUST_BUILD_WININET_CLIENT dnl ======================================================================= dnl Finding w3c-libwww dnl ======================================================================= if test $MUST_BUILD_LIBWWW_CLIENT = yes; then dnl First of all, locate the libwww config program. dnl You can control which of these gets chosen by controlling PATH. AC_PATH_PROGS(LIBWWW_CONFIG, libwww-xmlrpc-config libwww-config, no) if test "x$LIBWWW_CONFIG" = "xno"; then AC_MSG_ERROR(Configure INTERNAL ERROR - first libwww-config found, then not found) fi dnl Get our libwww version. dnl Adapted from a macro which called gtk-config. AC_MSG_CHECKING(for w3c-libwww version >= 5.2.8) W3VER=$($LIBWWW_CONFIG --version) LIBWWW_MAJOR=\ $(echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/') LIBWWW_MINOR=\ $(echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/') LIBWWW_MICRO=\ $(echo $W3VER|sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/') AC_MSG_RESULT($LIBWWW_MAJOR.$LIBWWW_MINOR.$LIBWWW_MICRO) dnl Check to make sure our version is OK. LIBWWW_VERSION_OK=yes if test $LIBWWW_MAJOR -lt 5; then LIBWWW_VERSION_OK=no else if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -lt 2; then LIBWWW_VERSION_OK=no else if test $LIBWWW_MAJOR -eq 5 -a $LIBWWW_MINOR -eq 2 \ -a $LIBWWW_MICRO -lt 8; then LIBWWW_VERSION_OK=no fi fi fi if test "x$LIBWWW_VERSION_OK" = "xno"; then AC_MSG_ERROR(w3c-libwww version >= 5.2.8 required) fi dnl Get the huge list of libraries we need to link against. LIBWWW_LDADD=$($LIBWWW_CONFIG --libs) AC_SUBST(LIBWWW_LDADD) AC_MSG_CHECKING(for libwww library directory) LIBWWW_LIBDIR="$($LIBWWW_CONFIG --prefix)/lib" AC_MSG_RESULT($LIBWWW_LIBDIR) AC_SUBST(LIBWWW_LIBDIR) fi # MUST_BUILD_LIBWWW_CLIENT dnl ======================================================================= dnl Finding Curl dnl ======================================================================= if test $MUST_BUILD_CURL_CLIENT = yes; then dnl First of all, locate the Curl config program. dnl You can control which of these gets chosen by controlling PATH. AC_PATH_PROGS(CURL_CONFIG, curl-xmlrpc-config curl-config, no) if test "x$CURL_CONFIG" = "xno"; then AC_MSG_ERROR(Configure INTERNAL ERROR - first curl-config found, then not found) fi dnl There used to be code here to check the Curl version and make sure dnl it is at least 7.8. But there were bugs both in the code and in dnl curl (curl-config --vernum, at least in older versions of Curl, dnl omits the leading zero). So it didn't work. Plus, checking version dnl numbers isn't a good idea. Better to check for feature presence. dnl So we don't do any check now. If we find out there's a problem with dnl older Curls, we will revisit that. CURL_LDADD=$($CURL_CONFIG --libs) AC_SUBST(CURL_LDADD) AC_MSG_CHECKING(for Curl library directory) CURL_LIBDIR="$($CURL_CONFIG --prefix)/lib" AC_MSG_RESULT($CURL_LIBDIR) AC_SUBST(CURL_LIBDIR) fi # MUST_BUILD_CURL_CLIENT dnl ======================================================================= dnl Checks for build options. dnl ======================================================================= AC_ARG_WITH(libwww-ssl, [ --with-libwww-ssl Include libwww SSL capability.] ) if test x"$enable_libwww_client" != xno; then AC_MSG_CHECKING(whether to use SSL with libwww) if test x"$with_libwww_ssl" = xyes; then AC_MSG_RESULT(yes) HAVE_LIBWWW_SSL_DEFINE=1 else AC_MSG_RESULT(no) HAVE_LIBWWW_SSL_DEFINE=0 fi else HAVE_LIBWWW_SSL_DEFINE=0 fi AC_SUBST(HAVE_LIBWWW_SSL_DEFINE) dnl Check to see if we should build the libxml2 backend. AC_ARG_ENABLE(libxml2-backend, [ --enable-libxml2-backend Use libxml2 instead of built-in expat], , enable_libxml2_backend=no) AC_MSG_CHECKING(whether to build the libxml2 backend) AC_MSG_RESULT($enable_libxml2_backend) if test $enable_libxml2_backend = yes; then AC_CHECK_PROG(have_xml2_config, xml2-config, yes, no) if test $have_xml2_config = no; then AC_MSG_ERROR([You specified --enable-libxml2_backend, but don't appear to have libxml2 installed (no working xml2-config in your command search path), so we cannot not build for libxml2]) fi fi ENABLE_LIBXML2_BACKEND=$enable_libxml2_backend AC_SUBST(ENABLE_LIBXML2_BACKEND) dnl ======================================================================= dnl Compiler information dnl ======================================================================= C_COMPILER_GNU=$ac_cv_c_compiler_gnu AC_SUBST(C_COMPILER_GNU) CXX_COMPILER_GNU=$ac_cv_cxx_compiler_gnu AC_SUBST(CXX_COMPILER_GNU) dnl obsolete variables, need to be removed from Makefile.in: CC_WARN_FLAGS= AC_SUBST(CC_WARN_FLAGS) CPP_WARN_FLAGS= AC_SUBST(CPP_WARN_FLAGS) BUILDDIR=$(pwd) AC_SUBST(BUILDDIR) AR=${ac_tool_prefix}ar AC_SUBST([AR]) RANLIB=${ac_tool_prefix}ranlib AC_SUBST([RANLIB]) dnl ======================================================================= dnl Output our results. dnl ======================================================================= dnl Note that AM_CONFIG_HEADER at the top of this file outputs another dnl result: xmlrpc_amconfig.h . AC_OUTPUT( \ srcdir.mk \ config.mk \ xmlrpc_config.h \ ) if test ! -f GNUmakefile; then ln -s "${srcdir}/GNUmakefile" . fi if test ! -f Makefile; then ln -s "${srcdir}/Makefile" . fi if test ! -f transport_config.mk; then ln -s "${srcdir}/transport_config.mk" . fi if test "$MUST_BUILD_WININET_CLIENT $MUST_BUILD_CURL_CLIENT $MUST_BUILD_LIBWWW_CLIENT" = "no no no"; then AC_MSG_NOTICE([==>]) AC_MSG_NOTICE([==>We are not building any client XML transport (see earlier messages explaining why), therefore WE WILL NOT BUILD THE CLIENT LIBRARY.]) AC_MSG_NOTICE([==>]) fi xmlrpc-c-1.33.14/dll-common.mk000066400000000000000000000012211236133176700160070ustar00rootroot00000000000000# -*-makefile-*- <-- an Emacs control # See unix-common.mk for an explanation of this file. This file is # analogous to unix-common.mk, but is for a Windows system SONAME = $@ IMPLIB = $(@:%:%.dll.a) SHLIB_CMD = $(CCLD) $(LDFLAGS_SHLIB) -o $@ $^ $(LADD) .PHONY: $(SHLIB_INSTALL_TARGETS) .PHONY: install-shared-libraries SHLIB_INSTALL_TARGETS = $(SHARED_LIBS_TO_INSTALL:%=%/install) #SHLIB_INSTALL_TARGETS is like "libfoo/install libbar/install" install-shared-libraries: $(SHLIB_INSTALL_TARGETS) $(SHLIB_INSTALL_TARGETS):%/install:%.$(SHLIB_SUFFIX) # $< is a library file name, e.g. libfoo.dll . $(INSTALL_SHLIB) $< $(DESTDIR)$(LIBINST_DIR)/$< xmlrpc-c-1.33.14/doc/000077500000000000000000000000001236133176700141665ustar00rootroot00000000000000xmlrpc-c-1.33.14/doc/COPYING000066400000000000000000000151751236133176700152320ustar00rootroot00000000000000The copyright owners of this package license the public to copy it (and do other things with it which are controlled by copyright law) under a few simple conditions. Each source file describes the copyright license for that particular file. This file summarizes the licenses for your convenience. All the code written specifically for Xmlrpc-c, which is most of the code, and the aggregation, is licensed under the XML-RPC FOR C/C++ license shown below. Some of the code was written for another purpose and copied into Xmlrpc-c. Its copyright owners license the code under a different license: The Expat Licence applies to the contents of the directory lib/expat, the ABYSS Web Server License applies to the contents of the directory lib/abyss and parts of the file src/xmlrpc_abyss.c. The Python 1.5.2 license applies to parts of the file src/xmlrpc_base64.c. And as for the tools/ directory, you'll have to examine the licenses on your own. These same licenses have been offered throughout Xmlrpc-c's history. XML-RPC For C/C++ License ------------------------- Copyright (C) 2001 by First Peer, Inc. All rights reserved. Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. Expat License ------------- Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd 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. ABYSS Web Server License ------------------------ Copyright (C) 2000 by Moez Mahfoudh . 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. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. Python 1.5.2 License -------------------- Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI or Corporation for National Research Initiatives or CNRI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. While CWI is the initial source for this software, a modified version is made available by the Corporation for National Research Initiatives (CNRI) at the Internet address ftp://ftp.python.org. STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. xmlrpc-c-1.33.14/doc/CREDITS000066400000000000000000000012421236133176700152050ustar00rootroot00000000000000Funding for the project that created the original Xmlrpc-c was provided in part by the good folks at First Peer, Inc., producers of P2P applications. Eric Kidd developed the original Xmlrpc-c in 2000 and maintained it up through June 2001. Bryan Henderson took over as maintainer in October 2004. Xmlrpc-c contains (and relies on for some server functions) a derivation of the Abyss web server by Moez Mahfoudh. Xmlrpc-c contains (and relies on) a derivation of the Expat XML parser, written by James Clark. The base64 code was derived from what Jack Jansen developed for Python. For more history, including credits for more minor contributions, see the HISTORY file. xmlrpc-c-1.33.14/doc/DEVELOPING000066400000000000000000000056341236133176700155550ustar00rootroot00000000000000Here are some notes to help you develop code for Xmlrpc-c. I include as "developing" debugging to figure out why Xmlrpc-c doesn't work for you. CODE LIBRARY ------------ The master Xmlrpc-c source code tree is the CVS repository on Sourceforge. Anybody can read it; only the maintainer can commit to it. If you're not the maintainer, simply use a 'cvs diff' command in your CVS working directory to create a patch file that embodies your changes and email that to the maintainer. He can easily apply that patch to his own CVS working directory and then commit the changes. MAKE VARIABLES -------------- You can pass make variable values to GNU Make to change the build. There are two common ways to do this: 1) Like this: $ make MYVAR=myvalue 2) Via an environment variable, like this: $ MYVAR=myvalue make or $ export MYVAR=myvalue $ make See GNU Make and shell documentation for details. In Xmlrpc-c make files, there are two make variables that add arbitrary options to every compile command: CADD and CFLAGS_PERSONAL. They both do the same thing. CADD is meant to be set on an individual make command, whereas CFLAGS_PERSONAL is meant to be a long-lived environment variable. CFLAGS_PERSONAL is for flags you like on all your compiles, but maybe others don't. One of my favorite CADD settings is CADD=--save-temps. To the GNU Compiler, --save-temps means to create, in addition to the object code, a file containing the intermediate preprocessed C code and a file containing the intermediate assembler source code. I can use that to debug certain things. The Xmlrpc-c build uses -g by default with Gcc, so you don't need to use CADD to get debugging symbols in your object code. There's also LADD for linker options. CODE STYLE ---------- The maintainer is pretty particular about coding style, but doesn't require anyone to submit code in any particular style. He changes what he thinks isn't maintainable enough as submitted. You could do him a big favor, though, and reduce the chance of him introducing bugs into your code, but trying to copy the style you see in existing code. The major theme is high level programming -- closer to English prose and further from machine instructions. Probably the most important thing is not to use tabs. Tabs are actually quite common in Unix C programming, but apart from tradition, they are a bad idea. They don't look the same to everyone. A person must suffer an additional configuration step -- setting up tab stops in order to see the code the right way. Spaces, on the other hand, look the same to everyone. Very old editors made it easier to compose with tabs than with spaces, but with modern ones, there is no difference. The maintainer tries to catch all tabs in code submitted to him and convert them to spaces, but this often leaves the code incorrectly indented. Better to give him code that already has the right number of spaces explicitly. xmlrpc-c-1.33.14/doc/HISTORY000066400000000000000000000063571236133176700152650ustar00rootroot00000000000000For a release-by-release change history, see . XML-RPC For C/C++ was created by Eric Kidd in 2000, when XML-RPC was new and vital. Its development was funded in significant part by First Peer, Inc. Eric released the package in January 2001 and set up an extensive project to maintain it. The project used virtually every feature on Sourceforge, had about 8 official developers, and distributed code in various formats. There were mailing lists, trackers, CVS branches, RPMs, and a full PHP-based web site, just to name a few features of the project. Then everything ground to a halt in June 2001, with the disappearance of Eric. We don't know what happened to him, but Google searches in late 2004 indicated he dropped off the face of the web at that time. While people continued to use Xmlrpc-c, and some developed fixes and enhancements and posted them to the Sourceforge trackers, the release remained frozen at 0.9.10. The web site also became frozen in time. In the years that followed the great freeze, XML-RPC became marginalized by more sophisticated alternatives such as SOAP. XML-RPC consequently became rather stable and interest in Xmlrpc-c levelled off. This dark age of Xmlrpc-c lasted until October 2004, when Bryan Henderson set out to find an RPC mechanism to use in one of his projects. Bryan found XML-RPC and then Xmlrpc-c. He decided that the two were almost right for his needs, but he needed some small extensions. On finding out that the project was orphaned, Bryan decided to take it over. Bryan became the Sourceforge project administrator through Sourceforge's abandonned project process, then gathered the patches that had been submitted over the years and made a come-back release called 1.0. Bryan then proceeded to add a lot of features in subsequent releases about every two months. Most of it was code Bryan wrote himself, but significant parts were contributed by others, as you can see in the detailed history below. Among the larger enhancements was a new C++ interface; the old one was a fairly weak wrapper around the C interface and required the user to manage memory and access the underlying C structures; the new one used pure C++ principles with automatic memory management. Bryan also wrote a complete user's manual. Surprisingly, in spite of the wide array of features the project had, documentation wasn't one of them. There was only a smattering of information available on how to use the package. One significant change Bryan made to the project was to strip it down considerably. In order to concentrate the small amount of time Bryan had available for Xmlrpc-c development on actual code and documentation, Bryan had to greatly reduce the amount of bureaucracy involved in administering the project and making releases, and reduce the set of skills required to do it. Bryan made static make files (for GNU Make) to replace the two extra build stages that originally generated make files. Bryan moved away from Libtool and toward simple compiling and linking. Bryan eliminated all pre-built distributions; each of his releases consisted of a single source code tarball, and that tarball was not signed. Bryan removed some redundant sources of information from the package and the web site. xmlrpc-c-1.33.14/doc/INSTALL000066400000000000000000000172011236133176700152200ustar00rootroot00000000000000These are instructions for building Xmlrpc-c from source and installing it on a system. See the README file for information on prerequisites (things you need to have installed before you can build). Essentially, it's just the conventional $ ./configure $ make $ make install To build handy tools such as the 'xmlrpc' command line XML-RPC client: $ cd tools $ make $ make install You can also do $ make check to run a battery of tests before you install. But note that it's as common for the tests to fail because the tests are broken as because the product is broken, so consider the results carefully. To see it work, build and run a simple server like this: $ cd examples $ make $ ./xmlrpc_sample_add_server 8080 That runs forever, serving clients as they arrive. Now, from another shell, run a client that does an RPC to this server: $ ./xmlrpc_sample_add_client Also try other example servers and clients, described in examples/README. You may want to pass a '--prefix' argument to 'configure'. See './configure --help' for details. You may also want to disable client XML transports that you won't be using. In particular, the Libwww transport can be inconvenient, because it typically uses about 20 shared libraries. Any XML-RPC client program that uses Xmlrpc-c, whether or not the program uses any of the libwww facilities, must attach all those libraries, and that can take a significant amount of time. See './configure --help' for the options that disable certain transports. SEPARATE BUILD TREE ------------------- While it's traditional to build a Unix package by adding object files to the same tree with the source files, it's actually much cleaner to keep your source tree exactly as you got it and put the built files in a separate directory, called the build tree. To do this, just create an empty directory and run 'configure' in it, then 'make': mkdir xmlrpcbuild cd xmlrpcbuild /usr/src/xmlrpc-c/configure ... make But if you plan to work on Xmlrpc-c source code, you'll probably find it more convenient to build the traditional way, with a single tree for source and build. In the source tree, you can type 'make' in any directory to do the default make for that directory, or make FILENAME to make the file of that name there. In the separate build tree, there are special facilities to allow you to do a simple make from the _top level directory_, but if you want to make a subcomponent or individual part, you have to have a -f option and set SRCDIR and BLDDIR on your 'make' command. CROSS-COMPILING --------------- Cross compiling is building code on one machine to be run on another, particularly when the two machines are different enough that it matters, e.g. one executes x86 instructions and the other executes PowerPC instructions. The machine that will run the code is called the target machine. The one that will build the code is the build machine. To cross-compile, you set up nearly all of the build environment for the target machine (that includes such things as the default include file search path for the compiler and library search path for the linker). On your 'configure' command, you use a --host option to identify the kind of target machine (rather than let it default to the kind of machine on which 'configure' is running). It's a nontrivial task, and beyond the scope of this document as it is not specific to Xmlrpc-c. There is one area that requires special attention and is specific to Xmlrpc-c: The Xmlrpc-c build does part of its job by compiling a program from C source code and running that program as part of the build. That compile, unlike all the regular ones, must be done for the build machine, not the target machine. To facilitate that, there are the BUILDTOOL_CC and BUILDTOOL_CCLD make variables. BUILDTOOL_CC is the command name for the appropriate compiler which which to build a build tool, i.e. a compiler that generates code to run on the build system. BUILDTOOL_CCLD is similarly for the linker, and should be the kind of linker command that invokes a combined compiler/linker, e.g. "gcc" instead of "ld". You can set these make variables on the Make command line, or if you prefer, by modifying the file 'config.mk' after 'configure' creates it. The default value of these variables (as set in 'config.mk') is the same compile and link commands as for building target code. (There is probably a way to do this with GNU Autoconf facilities and avoid the BUILDTOOL_CC complication. If you know how (without using Automake), tell the Xmlrpc-c maintainer and he will change the build system to use it). COMMON PROBLEMS --------------- Improper -config files ---------------------- The most common problem building Xmlrpc-c is one of improperly installed prerequisite libraries, namely Libwww and Curl. These libraries are designed to be installed along with a -config program (libwww-config and curl-config) that tells builders of dependent packages (such as Xmlrpc-c) how to use them. When the -config program is wrong, you get Xmlrpc-c build failures with messages about undefined references. The exact nature of the problems with -config programs can be quite involved, especially since there is no guarantee that a -config program can do what's required of it in every situation. But I'll explain the basic problem. For simplicity, I'll talk specifically about Curl, but the principles apply to any library that has a -config program. The point of curl-config is to describe how Curl is installed on your particular system. You have choices of where to install the various parts and what prerequisites to build into them, and curl-config is how you communicate those choices to the Xmlrpc-c make files. Curl's builder automatically creates a curl-config program for you, but you should not think of it as part of Curl. It's really a configuration file -- something that tells how your particular system is put together. The Curl builder is not smart enough to know exactly what to put in curl-config; it just builds one that works for most people. The local system administrator is actually responsible for the contents of curl-config. One rather complex way in which the curl-config that the Curl builder builds can be wrong is that it often indicates that to link to the Curl library, you need a "-L /usr/lib" option (or something like that -- an option that adds to the linker's search path a directory that is already in it). This is usually unnecessary because the directory is already in the search path, and often breaks things because it puts the directory too early in the search path. If your curl-config says to link with -L /usr/lib, you should normally edit it to remove that. As an example of how -L /usr/lib breaks things, here is a problem that is often reported: The user has Xmlrpc-c installed on his system, but wants to build a new one to replace it, or to use for a particular project instead of the system version. But the build of the new version fails with undefined references to symbol "xmlrpc_foo". xmlrpc_foo is a new symbol - it was added to Xmlrpc-c in a recent release. The version of Xmlrpc-c installed on the system is too old to have it. The make file obviously specifies the path to the current libraries that the user just built in the link library search order, but the link is picking up the old system version instead. Why? Because the link options say to search /usr/lib _before_ the local build directory. And they do that because curl-config erroneously says that you need a -L /usr/lib link option to find the Curl library. WINDOWS ------- All of the above is essentially for Unix-type operating systems. To build and use Xmlrpc-c on Windows, see the file Windows/ReadMeWin32.txt. xmlrpc-c-1.33.14/doc/SECURITY000066400000000000000000000042301236133176700153570ustar00rootroot00000000000000Security Advisories =================== The Xmlrpc-c maintainer will normally post security advisories related to xmlrpc-c to the xmlrpc-c-announce mailing list. You can subscribe to this using the web: http://xmlrpc-c.sourceforge.net/lists.php You will also find a list of all known bugs including those with security ramifications, in the release notes on Sourceforge. To see the release notes for a release, go to the file download page and click on the release name. The list is current only for the most current release -- i.e. we stop adding to the list for release N after we release N+1. XML-RPC Security ================ There are some security issues inherent in XML-RPC: 1) XML-RPC messages are not encrypted at the XML-RPC level. This means that unless you encrypt them at some lower level, someone with sufficient access to the network can see them with standard packet-sniffing and network administration tools. This is especially dangerous because XML-RPC is a stateless protocol. If you include reusable authentication tokens in an XML-RPC call, they can probably be sniffed and used by attackers. You can solve this problem by using SSL under HTTP. This is possible with Xmlrpc-c, but it's nontrivial to set up and the Xmlrpc-c documentation doesn't tell you how. 2) There are no permission restrictions and no authentication built into Xmlrpc-c by default -- any client can call any method on any visible server and neither can know for sure to whom it is talking. If you need permission and authentication, you either have to put it above the XML-RPC layer or below. For a server, above means in the method code you supply and register with the Xmlrpc-c server facilities; below means something like a firewall that lets clients only from a certain IP address connect to your server. 3) XML-RPC is a complex protocol based on complex data structures. Layers and layers of potentially buggy code gets run between the time network data is received, and the time it is understood; and conversely between the time data is conceived and the time it gets sent. xmlrpc-c-1.33.14/doc/TESTING000066400000000000000000000053561236133176700152370ustar00rootroot00000000000000In general, we want to run as many automated test tools on the Xmlrpc-c libraries as possible. Before releasing a new release, please run as many of these tests as possible. Included Test Suites -------------------- The 'test' program tests core functions. These are functions that don't involve HTTP communications. So obviously, it doesn't do any end-to-end client/server tests. The program is in src/test/test. You have to build that explicitly (with src/test/ as your current directory, do a 'make'); a top level 'make all' doesn't build it. (Reason: it's a tricky build, and we don't a user's build to fail just because of this program that a user doesn't need). src/cpp/cpptest is similar for the C++ libraries. Note: Before Release 1.03, 'test' was called 'rpctest' and both it and 'cpptest' were in the src/ directory and were built by 'make all'. Memory Leaks ------------ (Linux only?) Install Owen Taylor's 'memprof' utility. This program includes a malloc debugger and a conservative garbage collector. To run it, type: memprof test This should report any memory leaks which occur while the test suites are running. Electric Fence -------------- (Most Unix platforms.) Install Bruce Perens' Electric Fence library, and read the man pages carefully. Link 'test' against '-lefence', and run it with the following sets of environment variables: 1) (Default environment.) Test for heap block overruns. 2) EF_PROTECT_BELOW=1 Test for heap block underruns. 3) EF_PROTECT_FREE=1 Test for doubly-freed memory and illegal accesses to freed memory. 4) EF_ALIGNMENT=0 Test for very small block overruns. This is an important test, but it may not work on some platforms. Please see the efence manpage for more information. (After each run, unset the environment variables from the previous run.) Using a Bourne shell (such as bash) you can run all these tests as follows: test EF_PROTECT_BELOW=1 test EF_PROTECT_FREE=1 test EF_ALIGNMENT=0 test Alternatively, if you have a copy of Purify installed, please run that. End-to-End Tests ---------------- To test Abyss and the client XML transports, use the example programs examples/sample_add_server and examples/sample_add_client: $ export XMLRPC_TRACE_XML=1 $ examples/sample_add_server 8080& $ examples/sample_add_client Note that we use XMLRPC_TRACE_XML so we can see the XML flying by on both sides of the connection. Note that the Port 8080 is hardcoded in sample_add_client. Note that sample_add_client uses only the default XML transport. You can do more extensive client testing with the 'xmlrpc' program (tools/xmlrpc/xmlrpc). Tips ---- To debug Abyss without threads, don't pass -D_UNIX or -D_WIN32. The server will run in a single-threaded mode. xmlrpc-c-1.33.14/doc/TODO000066400000000000000000000043511236133176700146610ustar00rootroot00000000000000Here are some changes we'd like to see to Xmlrpc-c. While it's unlikely anyone will ever do them, the list is at least useful as an indication of what direction the maintainer wants the package to take, and that should be useful to anyone proposing changes of any kind. FUNCTIONAL CHANGES ------------------ Put details in the manual for the xmlrpc-c/server_abyss.hpp interface: libxmlrpc_server_abyss++.html. Implement pluggable XML transports on the server side like on the client side. Create a non-XML non-HTTP efficient transport, client and server. The tools/binmode-rpc-kit/ directory might be useful. Consider XDR. Change the argument order of asynchronous response callbacks to be more consistent with the xmlrpc_client_call_asynch function. Also take a look at the server method callback. Make an optional destructor function for XMLRPC_TYPE_C_PTR. Return XMLRPC_LIMIT_EXCEEDED_ERROR when nesting limits are exceeded. This will break binary and source API compatibility in a very minor way. Expand the Perl interface to Xmlrpc-c libraries to do server functions. Maybe match some other features of RPC::XML. Don't use xmlrpc_value for things that aren't part of an XML-RPC call or response. It's confusing. In particular, we use an xmlrpc_value array to pass the parameters of an RPC to xmlrpc_client_call(), and it should instead be a normal C array plus count, or variable argument list. Don't use XML-RPC fault codes internally. It's confusing. Plus, there's no need for fault codes at all. Just use the string descriptions. Add a function to deregister a method from a method registry. Add a "registry" type that works via a filesystem directory. There is a .so file for each method with its code, and probably a configuration file. Make it dynamically updatable. IMPLEMENTATION CHANGES ---------------------- Use function pointers to access cleanup code in xmlrpc_DECREF? Or even better: Should we create some kind of class-like system to declare XML-RPC types, with a per-type dispatch table? Fix abstract XML parser API to access children via functions named xml_element_child(env,elem,index) and xml_element_child_count(env,elem). Clean up corresponding client code. Make the C++ server implementation less based on the C functions. xmlrpc-c-1.33.14/doc/configure_doc000066400000000000000000000177161236133176700167330ustar00rootroot00000000000000Xmlrpc-c's 'configure' program is a GNU Autoconf configurator -- i.e. it is created by GNU Autoconf. This is the standard configurator you find throughout the open source software world. Here are the instructions for 'configure' from GNU Autoconf; in most packages, you find these in a file called INSTALL. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. xmlrpc-c-1.33.14/dylib-common.mk000066400000000000000000000023501236133176700163430ustar00rootroot00000000000000# -*-makefile-*- <-- an Emacs control # See unix-common.mk for an explanation of this file. This file is # analogous to unix-common.mk, but is for an Irix system. SONAME = $(@:%.$(MIN)=%) SHLIB_CMD = $(CCLD) $(LADD) $(LDFLAGS_SHLIB) -o $@ $^ SHLIBPP_CMD = $(CXXLD) $(LADD) $(LDFLAGS_SHLIB) -o $@ $^ SHLIB_LE_TARGETS = $(call shliblefn, $(SHARED_LIBS_TO_BUILD)) $(SHLIB_LE_TARGETS):%.$(SHLIB_SUFFIX):%.$(MAJ).$(MIN).$(SHLIB_SUFFIX) rm -f $@ $(LN_S) $< $@ .PHONY: $(SHLIB_INSTALL_TARGETS) .PHONY: install-shared-libraries SHLIB_INSTALL_TARGETS = $(SHARED_LIBS_TO_INSTALL:%=%/install) #SHLIB_INSTALL_TARGETS is like "libfoo/install libbar/install" install-shared-libraries: $(SHLIB_INSTALL_TARGETS) $(SHLIB_INSTALL_TARGETS):%/install:%.$(MAJ).$(MIN).$(SHLIB_SUFFIX) # $< is a library file name, e.g. libfoo.so.3.1 . $(INSTALL_SHLIB) $< $(DESTDIR)$(LIBINST_DIR)/$< cd $(DESTDIR)$(LIBINST_DIR); \ rm -f $(<:%.$(MIN).$(SHLIB_SUFFIX)=%.$(SHLIB_SUFFIX)); \ $(LN_S) $< $(<:%.$(MIN).$(SHLIB_SUFFIX)=%.$(SHLIB_SUFFIX)) cd $(DESTDIR)$(LIBINST_DIR); \ rm -f $(<:%.$(MAJ).$(MIN).$(SHLIB_SUFFIX)=%.$(SHLIB_SUFFIX)); \ $(LN_S) $(<:%.$(MIN).$(SHLIB_SUFFIX)=%.$(SHLIB_SUFFIX)) \ $(<:%.$(MAJ).$(MIN).$(SHLIB_SUFFIX)=%.$(SHLIB_SUFFIX)) xmlrpc-c-1.33.14/examples/000077500000000000000000000000001236133176700152375ustar00rootroot00000000000000xmlrpc-c-1.33.14/examples/Makefile000066400000000000000000000076551236133176700167140ustar00rootroot00000000000000# Since the programs in this directory are examples for the user, this make # file should be as ordinary as possible. It should not rely heavily on # included make files or configuration parameters. Also, we don't try to # build or rebuild the libraries on which these programs depend or even # recognize that they've changed on their own. ifeq ($(SRCDIR),) SRCDIR = $(CURDIR)/.. BLDDIR = $(SRCDIR) endif SUBDIR = examples include $(BLDDIR)/config.mk default: all CFLAGS += $(CFLAGS_PERSONAL) $(CADD) LDFLAGS += $(LDFLAGS_PERSONAL) $(LADD) # If this were a real application, working from an installed copy of # Xmlrpc-c, XMLRPC_C_CONFIG would just be 'xmlrpc-c-config'. It would be # found in the user's PATH. XMLRPC_C_CONFIG = $(BLDDIR)/xmlrpc-c-config.test CLIENTPROGS = \ auth_client \ compound_value_client \ synch_client \ xmlrpc_sample_add_client \ xmlrpc_asynch_client \ ifeq ($(MUST_BUILD_CURL_CLIENT),yes) ifneq ($(MSVCRT),yes) CLIENTPROGS += interrupted_client endif endif SERVERPROGS_CGI = \ xmlrpc_sample_add_server.cgi SERVERPROGS_ABYSS = \ compound_value_server \ xmlrpc_inetd_server \ xmlrpc_socket_server \ xmlrpc_loop_server \ xmlrpc_sample_add_server \ xmlrpc_server_validatee \ ifneq ($(MSVCRT),yes) SERVERPROGS_ABYSS += interrupted_server endif BASIC_PROGS = \ json \ gen_sample_add_xml \ parse_xml \ # Build up PROGS: PROGS = PROGS += $(BASIC_PROGS) ifeq ($(ENABLE_ABYSS_SERVER),yes) PROGS += $(SERVERPROGS_ABYSS) endif ifeq ($(MUST_BUILD_CLIENT),yes) PROGS += $(CLIENTPROGS) endif ifeq ($(ENABLE_CGI_SERVER),yes) PROGS += $(SERVERPROGS_CGI) endif INCLUDES = -I. $(shell $(XMLRPC_C_CONFIG) client abyss-server --cflags) LIBS_CLIENT = \ $(shell $(XMLRPC_C_CONFIG) client --libs) LIBS_SERVER_ABYSS = \ $(shell $(XMLRPC_C_CONFIG) abyss-server --libs) LIBS_SERVER_CGI = \ $(shell $(XMLRPC_C_CONFIG) cgi-server --libs) LIBS_BASE = \ $(shell $(XMLRPC_C_CONFIG) --libs) all: $(PROGS) ifeq ($(ENABLE_CPLUSPLUS),yes) all: cpp/all endif .PHONY: cpp/all cpp/all: $(BLDDIR)/examples/cpp $(MAKE) -C cpp -f $(SRCDIR)/examples/cpp/Makefile all # When building in separate tree, directory won't exist yet $(BLDDIR)/examples/cpp: mkdir $@ $(CLIENTPROGS):%:%.o $(CCLD) -o $@ $^ $(LIBS_CLIENT) $(LDFLAGS) $(SERVERPROGS_CGI):%.cgi:%_cgi.o $(CCLD) -o $@ $^ $(LIBS_SERVER_CGI) $(LDFLAGS) $(SERVERPROGS_ABYSS):%:%.o $(CCLD) -o $@ $^ $(LIBS_SERVER_ABYSS) $(LDFLAGS) $(BASIC_PROGS):%:%.o $(CCLD) -o $@ $^ $(LIBS_BASE) $(LDFLAGS) OBJECTS = $(patsubst %,%.o,$(patsubst %.cgi,%_cgi,$(PROGS))) $(OBJECTS):%.o:%.c $(CC) -c $(INCLUDES) $(CFLAGS) $< # config.h and xmlrpc_amconfig.h just describe the build environment. # We use them so that the example programs will build in users' # various environments. If you're copying these examples, you can # just remove these headers from the programs and hardcode whatever is # right for your build environment. $(OBJECTS): config.h xmlrpc_amconfig.h config.h: $(LN_S) $(BLDDIR)/xmlrpc_config.h $@ xmlrpc_amconfig.h: $(LN_S) $(BLDDIR)/$@ . .PHONY: clean clean: rm -f $(PROGS) *.o config.h xmlrpc_amconfig.h $(MAKE) -C cpp clean .PHONY: distclean distclean: clean BINDIR=$(DESTDIR)$(bindir) FILENAME_GENERATOR = "echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'" INSTCMD = "$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p \ $(BINDIR)/`$(FILENAME_GENERATOR)`" .PHONY: install install: $(PROGS) @$(NORMAL_INSTALL) $(MKINSTALLDIRS) $(BINDIR) @list='$(bin_PROGRAMS)'; for p in $$list; do \ if test -f $$p; then \ echo "$(INSTCMD)"; $(INSTCMD); \ else :; \ fi; \ done .PHONY: check check: .PHONY: dep depend dep depend: # We don't do dependencies in this directory, because it's supposed to be # an example of what a program outside this package would do, so we can't # go weaving it into the rest of the package. Ergo, a developer must # carefully clean and remake examples as he updates other parts of the tree. xmlrpc-c-1.33.14/examples/README000066400000000000000000000027021236133176700161200ustar00rootroot00000000000000This directory contains working examples of uses of XML-RPC-c. There are XML-RPC server programs and XML-RPC client programs that use the Xmlrpc-c libraries. The make file is a combination of an example of how to build programs that use Xmlrpc-c libraries and something that actually does build the programs in this directory. As such, it isn't perfect for either of those purposes. To build the examples, you must first build the libraries (make dependencies will not take care of that for you). Do that by running a default 'make' in the top level source directory. Then you can issue a simple 'make' in this directory. A default make in the root of the Xmlrpc-c source directory does not build this directory, but a 'make all' does. The simplest server program is 'xmlrpc_sample_add_server'. This implements a single XML-RPC method called 'sample.add'. All it does is add two numbers and return the sum. You can run such a server like this: $ ./xmlrpc_sample_add_server 8080 The server this runs is based on the Abyss HTTP server. file. The argument tell it to listen on TCP Port 8080 for RPCs. It puts log information in /tmp, so be sure to look there. A client program that goes along with this server is 'xmlrpc_sample_add_client'. All this client does is make an XML-RPC request to Port 8080 of 'localhost' to add the numbers 5 and 7 and print the result on Standard Output. You can run such a client like this: $ ./xmlrpc_sample_add_client xmlrpc-c-1.33.14/examples/auth_client.c000066400000000000000000000045041236133176700177050ustar00rootroot00000000000000/* A demonstration of using HTTP basic authentication with XML-RPC. ** ** In general, you shouldn't write XML-RPC servers which require basic ** authenticaion. (Few XML-RPC clients are capable of it, and it's not part of ** any standard.) Instead, you should pass any authentication information ** as a regular XML-RPC parameter (or look into using SSL). ** ** But certain XML-RPC servers, including Zope, rely heavily on HTTP ** basic authentication. Here's how to talk to them. */ #include #include #include #include #include "config.h" /* information about this build environment */ #define NAME "XML-RPC C Auth Client" #define VERSION "1.0" #define SERVER_URL "http://localhost:8080/RPC2" static void die_if_fault_occurred(xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "XML-RPC Fault: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } int main(int const argc, const char ** const argv) { xmlrpc_env env; xmlrpc_server_info * serverP; xmlrpc_value * resultP; xmlrpc_int sum; if (argc-1 > 0) { fprintf(stderr, "There are no arguments. You specified %d", argc-1); exit(1); } /* Start up our XML-RPC client library. */ xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION); xmlrpc_env_init(&env); /* Make a new object to represent our XML-RPC server. */ serverP = xmlrpc_server_info_new(&env, SERVER_URL); die_if_fault_occurred(&env); /* Set up our authentication information. */ xmlrpc_server_info_set_basic_auth(&env, serverP, "jrandom", "secret"); die_if_fault_occurred(&env); resultP = xmlrpc_client_call_server( &env, serverP, "sample.add", "(ii)", (xmlrpc_int32) 5, (xmlrpc_int32) 7); die_if_fault_occurred(&env); /* Dispose of our server object. */ xmlrpc_server_info_free(serverP); /* Get the result of the RPC and print it out. */ xmlrpc_read_int(&env, resultP, &sum); die_if_fault_occurred(&env); printf("The sum is %d\n", sum); /* Dispose of our result value. */ xmlrpc_DECREF(resultP); /* Shut down our XML-RPC client library. */ xmlrpc_env_clean(&env); xmlrpc_client_cleanup(); return 0; } xmlrpc-c-1.33.14/examples/compound_value_client.c000066400000000000000000000107661236133176700217730ustar00rootroot00000000000000/* An XML-RPC client program written in C, as an example of using compound XML-RPC values. For a simple client program that just deals with integer values, see xmlrpc_sample_add_client.c. This example focuses just on the compound XML-RPC values and not the client functions. This client invokes the example.divide XML-RPC method that the example server program compound_value_server.c provides. That method takes a list of pairs of numbers and returns the list of their quotients. Compound XML-RPC values are arrays and structures. We call them compound because they are made up of other XML-RPC values (e.g. an array of XML-RPC integers). The arguments to the example.divide method are specified as follows: There are two arguments: Argument 0: Integer. Version number of this argument protocol. Must be 1. Argument 1: Array. One element for each pair of numbers you want the server to divide. Each element is structure, with these members: KEY: "dividend" VALUE: floating point number. The dividend. KEY: "divisor" VALUE: floating point number. The divisor. The result of the method is an array. It has one member for each pair of numbers in the arguments (So it is the same size as Argument 1). That member is a floating point number. It is the quotient of the numbers in the corresponding element of Argument 1. The client sends the RPC to the server running on the local system ("localhost"), HTTP Port 8080. */ #include #include #include #include #include "config.h" /* information about this build environment */ #define NAME "Xmlrpc-c Test Client" #define VERSION "1.0" static void dieIfFaultOccurred (xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "ERROR: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } struct ratio { double dividend; double divisor; }; int main(int const argc, const char ** const argv) { const char * const serverUrl = "http://localhost:8080/RPC2"; const char * const methodName = "example.divide"; unsigned int const argVersion = 1; struct ratio const data[] = {{1,2},{12,3},{10,3},{89,3000}}; xmlrpc_env env; xmlrpc_value * resultP; unsigned int i; xmlrpc_value * ratioArrayP; unsigned int quotientCt; if (argc-1 > 0) { fprintf(stderr, "This program has no arguments\n"); exit(1); } xmlrpc_env_init(&env); xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0); dieIfFaultOccurred(&env); /* Build the 2nd method argument: the array of ratios */ ratioArrayP = xmlrpc_array_new(&env); dieIfFaultOccurred(&env); for (i = 0; i < 4; ++i) { xmlrpc_value * dividendP; xmlrpc_value * divisorP; xmlrpc_value * ratioP; dividendP = xmlrpc_double_new(&env, data[i].dividend); dieIfFaultOccurred(&env); divisorP = xmlrpc_double_new(&env, data[i].divisor); dieIfFaultOccurred(&env); ratioP = xmlrpc_struct_new(&env); dieIfFaultOccurred(&env); xmlrpc_struct_set_value(&env, ratioP, "DIVIDEND", dividendP); dieIfFaultOccurred(&env); xmlrpc_struct_set_value(&env, ratioP, "DIVISOR", divisorP); dieIfFaultOccurred(&env); xmlrpc_array_append_item(&env, ratioArrayP, ratioP); dieIfFaultOccurred(&env); xmlrpc_DECREF(ratioP); xmlrpc_DECREF(divisorP); xmlrpc_DECREF(dividendP); } /* Make the call */ resultP = xmlrpc_client_call(&env, serverUrl, methodName, "(iA)", (xmlrpc_int32) argVersion, ratioArrayP); dieIfFaultOccurred(&env); /* Print out the quotients returned */ quotientCt = xmlrpc_array_size(&env, resultP); dieIfFaultOccurred(&env); for (i = 0; i < quotientCt; ++i) { xmlrpc_value * quotientP; xmlrpc_double quotient; xmlrpc_array_read_item(&env, resultP, i, "ientP); dieIfFaultOccurred(&env); xmlrpc_read_double(&env, quotientP, "ient); dieIfFaultOccurred(&env); printf("Server says quotient %u is %f\n", i, quotient); xmlrpc_DECREF(quotientP); } xmlrpc_DECREF(resultP); xmlrpc_env_clean(&env); xmlrpc_client_cleanup(); return 0; } xmlrpc-c-1.33.14/examples/compound_value_server.c000066400000000000000000000130501236133176700220100ustar00rootroot00000000000000/* An XML-RPC server program written in C, as an example of using compound XML-RPC values. For a simple server program that just deals with integer values, see xmlrpc_sample_add_server.c. This example focuses just on the compound XML-RPC values and not the server functions. This server provides the example.divide XML-RPC method that the example client program compound_value_client.c invokes. See that program for details on what the method does. The program takes one argument: the HTTP port number on which the server is to accept connections, in decimal. Example: $ ./compound_value_server 8080& $ ./compound_value_client */ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.h */ #include #include #include #include #include #include "config.h" /* information about this build environment */ static void computeQuotient(xmlrpc_env * const envP, xmlrpc_value * const ratioP, xmlrpc_double * const quotientP) { xmlrpc_value * dividendP; xmlrpc_struct_find_value(envP, ratioP, "DIVIDEND", ÷ndP); if (!envP->fault_occurred) { if (!dividendP) xmlrpc_env_set_fault( envP, 0, "Structure is missing 'DIVIDEND' member"); else { xmlrpc_value * divisorP; xmlrpc_struct_find_value(envP, ratioP, "DIVISOR", &divisorP); if (!envP->fault_occurred) { if (!divisorP) xmlrpc_env_set_fault( envP, 0, "Structure is missing 'DIVISOR' member"); else { xmlrpc_double dividend; xmlrpc_read_double(envP, dividendP, ÷nd); if (!envP->fault_occurred) { xmlrpc_double divisor; xmlrpc_read_double(envP, divisorP, &divisor); if (!envP->fault_occurred) *quotientP = dividend / divisor; } xmlrpc_DECREF(divisorP); } } xmlrpc_DECREF(dividendP); } } } static void computeQuotients(xmlrpc_env * const envP, xmlrpc_value * const ratioArrayP, xmlrpc_value ** const quotientArrayPP) { xmlrpc_value * quotientArrayP; quotientArrayP = xmlrpc_array_new(envP); if (!envP->fault_occurred) { unsigned int const ratioCt = xmlrpc_array_size(envP, ratioArrayP); unsigned int i; for (i = 0; i < ratioCt && !envP->fault_occurred; ++i) { xmlrpc_value * ratioP; xmlrpc_array_read_item(envP, ratioArrayP, i, &ratioP); if (!envP->fault_occurred) { xmlrpc_double quotient; computeQuotient(envP, ratioP, "ient); if (!envP->fault_occurred) { xmlrpc_value * quotientP; quotientP = xmlrpc_double_new(envP, quotient); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, quotientArrayP, quotientP); xmlrpc_DECREF(quotientP); } } xmlrpc_DECREF(ratioP); } } if (envP->fault_occurred) xmlrpc_DECREF(quotientArrayP); else *quotientArrayPP = quotientArrayP; } } static xmlrpc_value * example_divide(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const channelInfo) { xmlrpc_value * retvalP; xmlrpc_int32 argVersion; xmlrpc_value * ratioArrayP; xmlrpc_decompose_value(envP, paramArrayP, "(iA)", &argVersion, &ratioArrayP); if (envP->fault_occurred) return NULL; if (argVersion != 1) { xmlrpc_env_set_fault(envP, 0, "Parameter list version must be 1"); return NULL; } computeQuotients(envP, ratioArrayP, &retvalP); xmlrpc_DECREF(ratioArrayP); if (envP->fault_occurred) return NULL; return retvalP; } int main(int const argc, const char ** const argv) { struct xmlrpc_method_info3 const methodInfo = { /* .methodName = */ "example.divide", /* .methodFunction = */ &example_divide, }; xmlrpc_server_abyss_parms serverparm; xmlrpc_registry * registryP; xmlrpc_env env; if (argc-1 != 1) { fprintf(stderr, "You must specify 1 argument: The TCP port " "number on which the server will accept connections " "for RPCs (8080 is a common choice). " "You specified %d arguments.\n", argc-1); exit(1); } xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); xmlrpc_registry_add_method3(&env, registryP, &methodInfo); /* In the modern form of the Abyss API, we supply parameters in memory like a normal API. We select the modern form by setting config_file_name to NULL: */ serverparm.config_file_name = NULL; serverparm.registryP = registryP; serverparm.port_number = atoi(argv[1]); serverparm.log_file_name = "/tmp/xmlrpc_log"; printf("Running XML-RPC server...\n"); xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name)); /* xmlrpc_server_abyss() never returns */ return 0; } xmlrpc-c-1.33.14/examples/cpp/000077500000000000000000000000001236133176700160215ustar00rootroot00000000000000xmlrpc-c-1.33.14/examples/cpp/Makefile000066400000000000000000000057551236133176700174750ustar00rootroot00000000000000# Since the programs in this directories are examples for the user, this # make file should be as ordinary as possible. It should not rely heavily # on included make files or configuration parameters. It should not use # libtool. Also, we don't try to build or rebuild the libraries on which # these programs depend. ifeq ($(SRCDIR),) SRCDIR = $(CURDIR)/../.. BLDDIR = $(SRCDIR) endif SUBDIR=examples/cpp include $(BLDDIR)/config.mk default: all CXXFLAGS = $(CFLAGS_PERSONAL) $(CADD) LDFLAGS += $(LADD) # If this were a real application, working from an installed copy of # Xmlrpc-c, XMLRPC_C_CONFIG would just be 'xmlrpc-c-config'. It would be # found in the user's PATH. XMLRPC_C_CONFIG = $(BLDDIR)/xmlrpc-c-config.test SERVERPROGS_CGI = \ xmlrpc_sample_add_server.cgi SERVERPROGS_ABYSS = \ xmlrpc_inetd_server \ xmlrpc_loop_server \ xmlrpc_sample_add_server \ callinfo_abyss_server \ CLIENTPROGS = \ xmlrpc_sample_add_client \ sample_add_client_complex \ asynch_client \ # Build up PROGS: PROGS = ifeq ($(ENABLE_ABYSS_SERVER),yes) PROGS += $(SERVERPROGS_ABYSS) endif ifeq ($(MUST_BUILD_CLIENT),yes) PROGS += $(CLIENTPROGS) endif ifeq ($(ENABLE_CGI_SERVER),yes) PROGS += $(SERVERPROGS_CGI) endif PROGS += pstream_inetd_server pstream_serial_server ifeq ($(MUST_BUILD_CLIENT),yes) PROGS += pstream_client endif INCLUDES = -I. $(shell $(XMLRPC_C_CONFIG) c++2 client abyss-server --cflags) LIBS_SERVER_ABYSS = \ $(shell $(XMLRPC_C_CONFIG) c++2 abyss-server --libs) LIBS_SERVER_CGI = \ $(shell $(XMLRPC_C_CONFIG) c++2 cgi-server --libs) LIBS_CLIENT = \ $(shell $(XMLRPC_C_CONFIG) c++2 client --libs) LIBS_BASE = \ $(shell $(XMLRPC_C_CONFIG) c++2 --libs) all: $(PROGS) $(SERVERPROGS_CGI):%.cgi:%_cgi.o $(CXXLD) -o $@ $^ $(LIBS_SERVER_CGI) $(LDFLAGS) $(SERVERPROGS_ABYSS):%:%.o $(CXXLD) -o $@ $^ $(LIBS_SERVER_ABYSS) $(LDFLAGS) $(CLIENTPROGS):%:%.o $(CXXLD) -o $@ $^ $(LIBS_CLIENT) $(LDFLAGS) LIBS_PSTREAM_CLIENT = \ $(shell $(XMLRPC_C_CONFIG) c++2 client --libs) pstream_client:%:%.o $(CXXLD) -o $@ $^ $(LIBS_PSTREAM_CLIENT) $(LDFLAGS) LIBS_PSTREAM_SERVER = \ $(shell $(XMLRPC_C_CONFIG) c++2 pstream-server --libs) pstream_inetd_server pstream_serial_server:%:%.o $(CXXLD) -o $@ $^ $(LIBS_PSTREAM_SERVER) $(LDFLAGS) OBJECTS = $(patsubst %,%.o,$(patsubst %.cgi,%_cgi,$(PROGS))) $(OBJECTS):%.o:%.cpp $(CXX) -c $(INCLUDES) $(CXXFLAGS) $< # See example/Makefile for an explanation of config.h and xmlrpc_amconfig.h $(OBJECTS): config.h xmlrpc_amconfig.h config.h: $(LN_S) $(BLDDIR)/xmlrpc_config.h $@ xmlrpc_amconfig.h: $(LN_S) $(BLDDIR)/$@ . .PHONY: clean clean: rm -f $(PROGS) *.o config.h xmlrpc_amconfig.h .PHONY: distclean distclean: clean .PHONY: dep depend dep depend: # We don't do dependencies in this directory, because it's supposed to be # an example of what a program outside this package would do, so we can't # go weaving it into the rest of the package. Ergo, a developer must # carefully clean and remake examples as he updates other parts of the tree. xmlrpc-c-1.33.14/examples/cpp/asynch_client.cpp000066400000000000000000000043611236133176700213540ustar00rootroot00000000000000/*============================================================================= asynch_client.cpp =============================================================================== This is an example of an XML-RPC client that uses XML-RPC for C/C++ (Xmlrpc-c). In particular, it does multiple RPCs asynchronously, running simultaneously. =============================================================================*/ #include #include #include #include #include #include #include using namespace std; int main(int argc, char **) { if (argc-1 > 0) { cerr << "This program has no arguments" << endl; exit(1); } try { xmlrpc_c::clientXmlTransport_curl myTransport; xmlrpc_c::client_xml myClient(&myTransport); string const methodName("sample.add"); xmlrpc_c::paramList sampleAddParms1; sampleAddParms1.add(xmlrpc_c::value_int(3)); sampleAddParms1.add(xmlrpc_c::value_int(1)); xmlrpc_c::rpcPtr rpc1P(methodName, sampleAddParms1); xmlrpc_c::paramList sampleAddParms2; sampleAddParms2.add(xmlrpc_c::value_int(5)); sampleAddParms2.add(xmlrpc_c::value_int(7)); xmlrpc_c::rpcPtr rpc2P(methodName, sampleAddParms2); string const serverUrl("http://localhost:8080/RPC2"); xmlrpc_c::carriageParm_curl0 myCarriageParm(serverUrl); rpc1P->start(&myClient, &myCarriageParm); rpc2P->start(&myClient, &myCarriageParm); cout << "Two RPCs started. Waiting for them to finish." << endl; myClient.finishAsync(xmlrpc_c::timeout()); // infinite timeout assert(rpc1P->isFinished()); assert(rpc2P->isFinished()); int const sum1(xmlrpc_c::value_int(rpc1P->getResult())); int const sum2(xmlrpc_c::value_int(rpc2P->getResult())); cout << "Result of RPC 1 (sum of 3 and 1): " << sum1 << endl; cout << "Result of RPC 2 (sum of 5 and 7): " << sum2 << endl; } catch (exception const& e) { cerr << "Client threw error: " << e.what() << endl; } catch (...) { cerr << "Client threw unexpected error." << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/callinfo_abyss_server.cpp000066400000000000000000000076441236133176700231160ustar00rootroot00000000000000// A simple standalone XML-RPC server written in C++. // // This server returns to the caller his IP address and port number, // as a demonstration of how to access such information. // // This works only on Unix (to wit, something that uses Abyss's // ChanSwitchUnix channel switch to accept TCP connections from clients). // // See xmlrpc_sample_add_server.cpp for a more basic example. // // To run this: // // $ ./callinfo_abyss_server & // $ xmlrpc localhost:8080 getCallInfo #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.hpp */ #include #include #include #include #include #ifndef _WIN32 #include #include #endif #include #include #include #include using namespace std; struct tcpPortAddr { unsigned char ipAddr[4]; unsigned short portNumber; }; static struct tcpPortAddr tcpAddrFromSockAddr(struct sockaddr const sockAddr) { const struct sockaddr_in * const sockAddrInP( static_cast((void *)&sockAddr)); const unsigned char * const ipAddr( static_cast( (const void *)&sockAddrInP->sin_addr.s_addr) ); // 4 byte array assert(sockAddrInP->sin_family == AF_INET); struct tcpPortAddr retval; retval.ipAddr[0] = ipAddr[0]; retval.ipAddr[1] = ipAddr[1]; retval.ipAddr[2] = ipAddr[2]; retval.ipAddr[3] = ipAddr[3]; retval.portNumber = ntohs(sockAddrInP->sin_port); return retval; } /* On Windows, we have struct abyss_win_chaninfo, while on Unix we have struct abyss_unix_chaninfo, but for what we're doing here, they're fungible -- we use only members that exist in both. So we refer to the generically with macro CHANINFO_TYPE. */ #ifdef _WIN32 #define CHANINFO_TYPE abyss_win_chaninfo #else #define CHANINFO_TYPE abyss_unix_chaninfo #endif static string rpcIpAddrMsg(xmlrpc_c::callInfo_serverAbyss const& callInfo) { void * chanInfoPtr; SessionGetChannelInfo(callInfo.abyssSessionP, &chanInfoPtr); struct CHANINFO_TYPE * const chanInfoP( static_cast(chanInfoPtr)); struct tcpPortAddr const tcpAddr(tcpAddrFromSockAddr(chanInfoP->peerAddr)); char msg[128]; sprintf(msg, "RPC is from IP address %u.%u.%u.%u, Port %hu", tcpAddr.ipAddr[0], tcpAddr.ipAddr[1], tcpAddr.ipAddr[2], tcpAddr.ipAddr[3], tcpAddr.portNumber); return string(msg); } class getCallInfoMethod : public xmlrpc_c::method2 { public: void execute(xmlrpc_c::paramList const& paramList, const xmlrpc_c::callInfo * const callInfoPtr, xmlrpc_c::value * const retvalP) { const xmlrpc_c::callInfo_serverAbyss * const callInfoP( dynamic_cast(callInfoPtr)); paramList.verifyEnd(0); // Because this gets called via a xmlrpc_c::serverAbyss: assert(callInfoP != NULL); *retvalP = xmlrpc_c::value_string(rpcIpAddrMsg(*callInfoP)); } }; int main(int const, const char ** const) { try { xmlrpc_c::registry myRegistry; xmlrpc_c::methodPtr const getCallInfoMethodP(new getCallInfoMethod); myRegistry.addMethod("getCallInfo", getCallInfoMethodP); xmlrpc_c::serverAbyss myAbyssServer(xmlrpc_c::serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(8080) ); myAbyssServer.run(); // xmlrpc_c::serverAbyss.run() never returns assert(false); } catch (exception const& e) { cerr << "Something failed. " << e.what() << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/pstream_client.cpp000066400000000000000000000050411236133176700215360ustar00rootroot00000000000000/*============================================================================= pstream_client.cpp =============================================================================== This is an example of a client that uses XML-RPC for C/C++ (Xmlrpc-c). In particular, it uses the simple "packet stream" XML transport mechanism instead of HTTP as specified by XML-RPC (so this is not an XML-RPC client). You have to supply as Standard Input a stream (TCP) socket whose other end is hooked up to the RPC server. The 'socket_exec' program is a good way to arrange that. The sample program pstream_server.cpp is compatible with this client. Example: $ socketexec -connect -remote_host=localhost -remote_port=8080 \ ./pstream_client =============================================================================*/ #include #include #include #include #include #include #include #include #include #include using namespace std; int main(int argc, char **) { if (argc-1 > 0) { cerr << "This program has no arguments" << endl; exit(1); } #ifndef _WIN32 // It's a good idea to disable SIGPIPE signals; if server closes his end // of the pipe/socket, we'd rather see a failure to send a call than // get killed by the OS. signal(SIGPIPE, SIG_IGN); #endif try { xmlrpc_c::clientXmlTransport_pstream myTransport( xmlrpc_c::clientXmlTransport_pstream::constrOpt() .fd(STDIN_FILENO)); xmlrpc_c::client_xml myClient(&myTransport); string const methodName("sample.add"); xmlrpc_c::paramList sampleAddParms; sampleAddParms.add(xmlrpc_c::value_int(5)); sampleAddParms.add(xmlrpc_c::value_int(7)); xmlrpc_c::rpcPtr myRpcP(methodName, sampleAddParms); xmlrpc_c::carriageParm_pstream myCarriageParm; // Empty; transport doesn't need any information myRpcP->call(&myClient, &myCarriageParm); assert(myRpcP->isFinished()); int const sum(xmlrpc_c::value_int(myRpcP->getResult())); // Assume the method returned an integer; throws error if not cout << "Result of RPC (sum of 5 and 7): " << sum << endl; } catch (exception const& e) { cerr << "Client threw error: " << e.what() << endl; } catch (...) { cerr << "Client threw unexpected error." << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/pstream_inetd_server.cpp000066400000000000000000000047651236133176700227650ustar00rootroot00000000000000/* A simple standalone RPC server based on an Xmlrpc-c packet socket. This program expects the invoker to provide an established connection to a client as Standard Input (E.g. Inetd can do this). It processes RPCs from that connection until the client closes the connection. This is not an XML-RPC server, because it uses a simple packet socket instead of HTTP. See xmlrpc_sample_add_server.cpp for an example of an XML-RPC server. The advantage of this example over XML-RPC is that it has a connection concept. The client can be connected indefinitely and the server gets notified when the client terminates, even if it gets aborted by its OS. Here's an example of running this: $ socketexec -accept -local_port=8080 ./pstream_inetd_server */ #ifndef _WIN32 #include #endif #include #include #include #include #include #include using namespace std; class sampleAddMethod : public xmlrpc_c::method { public: sampleAddMethod() { // signature and help strings are documentation -- the client // can query this information with a system.methodSignature and // system.methodHelp RPC. this->_signature = "i:ii"; // method's arguments are two integers this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = xmlrpc_c::value_int(addend + adder); } }; int main(int const, const char ** const) { #ifndef _WIN32 // It's a good idea to disable SIGPIPE signals; if client closes his end // of the pipe/socket, we'd rather see a failure to send a response than // get killed by the OS. signal(SIGPIPE, SIG_IGN); #endif try { xmlrpc_c::registry myRegistry; xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); myRegistry.addMethod("sample.add", sampleAddMethodP); xmlrpc_c::serverPstreamConn server( xmlrpc_c::serverPstreamConn::constrOpt() .socketFd(STDIN_FILENO) .registryP(&myRegistry)); server.run(); } catch (exception const& e) { cerr << "Something threw an error: " << e.what() << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/pstream_serial_server.cpp000066400000000000000000000045711236133176700231340ustar00rootroot00000000000000/* A simple standalone RPC server based on an Xmlrpc-c packet socket. This program expects the invoker to provide a socket in listen mode as Standard Input. This is not an XML-RPC server, because it uses a simple packet socket instead of HTTP. See xmlrpc_sample_add_server.cpp for an example of an XML-RPC server. The advantage of this example over XML-RPC is that it has a connection concept. The client can be connected indefinitely and the server gets notified when the client terminates, even if it gets aborted by its OS. Here's an example of running this: $ socketexec -listen -local_port=8080 ./pstream_serial_server */ #ifndef WIN32 #include #endif #include #include #include #include #include #include using namespace std; class sampleAddMethod : public xmlrpc_c::method { public: sampleAddMethod() { // signature and help strings are documentation -- the client // can query this information with a system.methodSignature and // system.methodHelp RPC. this->_signature = "i:ii"; // method's arguments are two integers this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = xmlrpc_c::value_int(addend + adder); } }; int main(int const, const char ** const) { #ifndef _WIN32 // It's a good idea to disable SIGPIPE signals; if client closes his end // of the pipe/socket, we'd rather see a failure to send a response than // get killed by the OS. signal(SIGPIPE, SIG_IGN); #endif try { xmlrpc_c::registry myRegistry; xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); myRegistry.addMethod("sample.add", sampleAddMethodP); xmlrpc_c::serverPstream server( xmlrpc_c::serverPstream::constrOpt() .socketFd(STDIN_FILENO) .registryP(&myRegistry)); server.runSerial(); } catch (exception const& e) { cerr << "Something threw an error: " << e.what() << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/sample_add_client_complex.cpp000066400000000000000000000043141236133176700237050ustar00rootroot00000000000000/*============================================================================= sample_add_client_complex.cpp =============================================================================== This is an example of an XML-RPC client that uses XML-RPC for C/C++ (Xmlrpc-c). In particular, it uses the complex lower-level interface that gives you lots of flexibility but requires lots of code. Also see xmlrpc_sample_add_server, which does the same thing as this program, but with much simpler code because it uses a simpler facility of Xmlrpc-c. This program actually gains nothing from using the more difficult facility. It is for demonstration purposes. =============================================================================*/ #include #include #include #include #include #include #include using namespace std; int main(int argc, char **) { if (argc-1 > 0) { cerr << "This program has no arguments" << endl; exit(1); } try { xmlrpc_c::clientXmlTransport_curl myTransport( xmlrpc_c::clientXmlTransport_curl::constrOpt() .timeout(10000) // milliseconds .user_agent("sample_add/1.0")); xmlrpc_c::client_xml myClient(&myTransport); string const methodName("sample.add"); xmlrpc_c::paramList sampleAddParms; sampleAddParms.add(xmlrpc_c::value_int(5)); sampleAddParms.add(xmlrpc_c::value_int(7)); xmlrpc_c::rpcPtr myRpcP(methodName, sampleAddParms); string const serverUrl("http://localhost:8080/RPC2"); xmlrpc_c::carriageParm_curl0 myCarriageParm(serverUrl); myRpcP->call(&myClient, &myCarriageParm); assert(myRpcP->isFinished()); int const sum(xmlrpc_c::value_int(myRpcP->getResult())); // Assume the method returned an integer; throws error if not cout << "Result of RPC (sum of 5 and 7): " << sum << endl; } catch (exception const& e) { cerr << "Client threw error: " << e.what() << endl; } catch (...) { cerr << "Client threw unexpected error." << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/xmlrpc_inetd_server.cpp000066400000000000000000000047771236133176700226220ustar00rootroot00000000000000/* A simple XML-RPC server that runs under Inetd. I.e. it lets the invoking program handle all the connection switching and simply processes one RPC on the provided connection (Standard Input) and exits. A typical example of where this would be useful is with an Inetd "super server." xmlrpc_sample_add_server.cpp is a server that does the same thing, but you give it a TCP port number and it listens for TCP connections and processes RPCs ad infinitum. xmlrpc_socket_server.c is halfway in between those -- you give it an already bound and listening socket, and it listens for TCP connections and processes RPCs ad infinitum. Here is an easy way to test this program: socketexec --accept --local_port=8080 --stdin -- ./xmlrpc_inetd_server Now run the client program 'xmlrpc_sample_add_client'. Socketexec will accept the connection that the client program requests and pass it to this program on Standard Input. This program will perform the RPC, respond to the client, then exit. */ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.hpp */ #ifndef _WIN32 # include #endif #include #include #include #include using namespace std; class sampleAddMethod : public xmlrpc_c::method { public: sampleAddMethod() { // signature and help strings are documentation -- the client // can query this information with a system.methodSignature and // system.methodHelp RPC. this->_signature = "i:ii"; // method's arguments are two integers this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = xmlrpc_c::value_int(addend + adder); } }; int main(int const, const char ** const) { xmlrpc_c::registry myRegistry; xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); myRegistry.addMethod("sample.add", sampleAddMethodP); xmlrpc_c::serverAbyss myAbyssServer( xmlrpc_c::serverAbyss::constrOpt() .registryP(&myRegistry)); myAbyssServer.runConn(STDIN_FILENO); /* This reads the HTTP POST request from Standard Input and executes the indicated RPC. */ return 0; } xmlrpc-c-1.33.14/examples/cpp/xmlrpc_loop_server.cpp000066400000000000000000000042001236133176700224450ustar00rootroot00000000000000/* A simple standalone XML-RPC server based on Abyss that contains a simple one-thread request processing loop. xmlrpc_sample_add_server.cpp is a server that does the same thing, but does it by running a full Abyss daemon in the background, so it has less control over how the requests are served. */ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.hpp */ #include #include #include #include #include using namespace std; class sampleAddMethod : public xmlrpc_c::method { public: sampleAddMethod() { // signature and help strings are documentation -- the client // can query this information with a system.methodSignature and // system.methodHelp RPC. this->_signature = "i:ii"; // method's arguments, result are integers this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = xmlrpc_c::value_int(addend + adder); } }; int main(int const, const char ** const) { try { xmlrpc_c::registry myRegistry; xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); myRegistry.addMethod("sample.add", sampleAddMethodP); xmlrpc_c::serverAbyss myAbyssServer( xmlrpc_c::serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(8080) .logFileName("/tmp/xmlrpc_log")); while (true) { cout << "Waiting for next RPC..." << endl; myAbyssServer.runOnce(); /* This waits for the next connection, accepts it, reads the HTTP POST request, executes the indicated RPC, and closes the connection. */ } } catch (exception const& e) { cerr << "Something failed. " << e.what() << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/xmlrpc_sample_add_client.cpp000066400000000000000000000017161236133176700235460ustar00rootroot00000000000000#include #include #include #include #include #include using namespace std; int main(int argc, char **) { if (argc-1 > 0) { cerr << "This program has no arguments" << endl; exit(1); } try { string const serverUrl("http://localhost:8080/RPC2"); string const methodName("sample.add"); xmlrpc_c::clientSimple myClient; xmlrpc_c::value result; myClient.call(serverUrl, methodName, "ii", &result, 5, 7); int const sum = xmlrpc_c::value_int(result); // Assume the method returned an integer; throws error if not cout << "Result of RPC (sum of 5 and 7): " << sum << endl; } catch (exception const& e) { cerr << "Client threw error: " << e.what() << endl; } catch (...) { cerr << "Client threw unexpected error." << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/xmlrpc_sample_add_server.cpp000066400000000000000000000037371236133176700236030ustar00rootroot00000000000000#define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.hpp */ #include #include #include #ifdef _WIN32 # include #else # include #endif #include #include #include using namespace std; #ifdef _WIN32 #define SLEEP(seconds) SleepEx(seconds * 1000); #else #define SLEEP(seconds) sleep(seconds); #endif class sampleAddMethod : public xmlrpc_c::method { public: sampleAddMethod() { // signature and help strings are documentation -- the client // can query this information with a system.methodSignature and // system.methodHelp RPC. this->_signature = "i:ii"; // method's result and two arguments are integers this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = xmlrpc_c::value_int(addend + adder); // Sometimes, make it look hard (so client can see what it's like // to do an RPC that takes a while). if (adder == 1) SLEEP(2); } }; int main(int const, const char ** const) { try { xmlrpc_c::registry myRegistry; xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); myRegistry.addMethod("sample.add", sampleAddMethodP); xmlrpc_c::serverAbyss myAbyssServer( xmlrpc_c::serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(8080)); myAbyssServer.run(); // xmlrpc_c::serverAbyss.run() never returns assert(false); } catch (exception const& e) { cerr << "Something failed. " << e.what() << endl; } return 0; } xmlrpc-c-1.33.14/examples/cpp/xmlrpc_sample_add_server_cgi.cpp000066400000000000000000000030541236133176700244150ustar00rootroot00000000000000/* A CGI script that effects a simple XML-RPC server, written in C++. See the identically named C program source code for hints on running this example. */ #include #include #include #include #include using namespace std; class sampleAddMethod : public xmlrpc_c::method { public: sampleAddMethod() { // signature and help strings are documentation -- the client // can query this information with a system.methodSignature and // system.methodHelp RPC. this->_signature = "i:ii"; // method's arguments, result are integers this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = xmlrpc_c::value_int(addend + adder); } }; int main(int const, const char ** const) { try { xmlrpc_c::registry myRegistry; xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod); myRegistry.addMethod("sample.add", sampleAddMethodP); xmlrpc_c::serverCgi myServer( xmlrpc_c::serverCgi::constrOpt() .registryP(&myRegistry)); myServer.processCall(); } catch (exception const& e) { cerr << "Something failed. " << e.what() << endl; } return 0; } xmlrpc-c-1.33.14/examples/gen_sample_add_xml.c000066400000000000000000000033341236133176700212100ustar00rootroot00000000000000/* This program generates on Standard Output the XML for an XML-RPC call suitable for the xmlrpc_sample_add_server program. This is the same XML that the xmlrpc_sample_add_client program sends. Use this either as an example of how to use the Xmlrpc-c XML-generating functions or to generate XML that you can use to test an XML-RPC server. */ #include #include #include #include "config.h" static void die_if_fault_occurred(xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "XML-RPC Fault: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } int main(int const argc, const char ** const argv) { char * const methodName = "sample.add"; xmlrpc_env env; xmlrpc_value * params; xmlrpc_mem_block * xmlmemblockP; if (argc-1 > 0) { fprintf(stderr, "This program has no arguments\n"); exit(1); } /* Initialize our error-handling environment. */ xmlrpc_env_init(&env); params = xmlrpc_build_value(&env, "(ii)", (xmlrpc_int32) 5, (xmlrpc_int32) 7); die_if_fault_occurred(&env); xmlmemblockP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); xmlrpc_serialize_call(&env, xmlmemblockP, methodName, params); die_if_fault_occurred(&env); fwrite(XMLRPC_MEMBLOCK_CONTENTS(char, xmlmemblockP), sizeof(char), XMLRPC_MEMBLOCK_SIZE(char, xmlmemblockP), stdout); XMLRPC_MEMBLOCK_FREE(char, xmlmemblockP); /* Dispose of our parameter array. */ xmlrpc_DECREF(params); /* Clean up our error-handling environment. */ xmlrpc_env_clean(&env); return 0; } xmlrpc-c-1.33.14/examples/interrupted_client.c000066400000000000000000000102721236133176700213100ustar00rootroot00000000000000/* Same as xmlrpc_sample_add_client.c, except the call is interruptible, both by timeout and by control-C. */ #define _XOPEN_SOURCE 600 #include #include #include #include #include #include #include "config.h" /* information about this build environment */ static int interrupt; /* This is a flag telling libxmlrpc_client to abort whatever it's doing. It's global because we set it with a signal handler. */ static void die_if_fault_occurred (xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "XML-RPC Fault: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } static void interruptRpc(int const signalClass) { switch (signalClass) { case SIGINT: printf("SIGINT signal received.\n"); break; case SIGALRM: printf("SIGALRM signal received.\n"); break; default: printf("Internal error: signal of class %u caught even though " "we didn't set up a handler for that class\n", signalClass); }; interrupt = 1; } static void setupSignalHandlers(void) { struct sigaction mysigaction; sigemptyset(&mysigaction.sa_mask); mysigaction.sa_flags = 0; /* Usually, this signal indicates the user pressed Ctl-C */ mysigaction.sa_handler = interruptRpc; sigaction(SIGINT, &mysigaction, NULL); /* This signal indicates a timed alarm you requested happened */ sigaction(SIGALRM, &mysigaction, NULL); } static void addInterruptibly(xmlrpc_client * const clientP, const char * const serverUrl, int const addend, int const adder) { const char * const methodName = "sample.add"; xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_int32 sum; xmlrpc_env_init(&env); printf("Making XMLRPC call to server url '%s' method '%s' " "to request the sum " "of %d and %d...\n", serverUrl, methodName, addend, adder); interrupt = 0; /* Global variable */ alarm(2); /* Interrupt the call if it hasn't finished 2 seconds from now */ /* Make the remote procedure call */ xmlrpc_client_call2f(&env, clientP, serverUrl, methodName, &resultP, "(ii)", (xmlrpc_int32) addend, (xmlrpc_int32) adder); die_if_fault_occurred(&env); alarm(0); /* Cancel alarm, if it hasn't happened yet */ /* Get our sum and print it out. */ xmlrpc_read_int(&env, resultP, &sum); die_if_fault_occurred(&env); printf("The sum is %d\n", sum); /* Dispose of our result value. */ xmlrpc_DECREF(resultP); xmlrpc_env_clean(&env); } int main(int const argc, const char ** const argv) { const char * const serverUrl = "http://localhost:8080/RPC2"; xmlrpc_env env; struct xmlrpc_clientparms clientParms; xmlrpc_client * clientP; if (argc-1 > 0) { fprintf(stderr, "This program has no arguments\n"); exit(1); } setupSignalHandlers(); /* Initialize our error-handling environment. */ xmlrpc_env_init(&env); /* Required before any use of Xmlrpc-c client library: */ xmlrpc_client_setup_global_const(&env); die_if_fault_occurred(&env); clientParms.transport = "curl"; /* Create a client object */ xmlrpc_client_create(&env, 0, NULL, NULL, &clientParms, XMLRPC_CPSIZE(transport), &clientP); die_if_fault_occurred(&env); xmlrpc_client_set_interrupt(clientP, &interrupt); /* If our server is running 'xmlrpc_sample_add_server' normally, the RPC will finish almost instantly. UNLESS the adder is 1, in which case said server is programmed to take 3 seconds to do the computation, thus allowing us to demonstrate a timeout or CTL-C. */ addInterruptibly(clientP, serverUrl, 5, 7); /* Should finish instantly */ addInterruptibly(clientP, serverUrl, 5, 1); /* Should time out after 2 seconds */ xmlrpc_env_clean(&env); xmlrpc_client_destroy(clientP); xmlrpc_client_teardown_global_const(); return 0; } xmlrpc-c-1.33.14/examples/interrupted_server.c000066400000000000000000000100711236133176700213350ustar00rootroot00000000000000/* A simple standalone XML-RPC server program based on Abyss. You can terminate this server in controlled fashion with a SIGTERM signal. xmlrpc_sample_add_server.c is a server that does the same thing with simpler code, but it is not interruptible with SIGTERM. */ #define _XOPEN_SOURCE 600 #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.h */ #include #include #include #include #include #include #include #include #include #include "config.h" /* information about this build environment */ static void dieIfFailed(const char * const description, xmlrpc_env const env) { if (env.fault_occurred) { fprintf(stderr, "%s failed. %s\n", description, env.fault_string); exit(1); } } static xmlrpc_server_abyss_t * serverToTerminateP; static void sigtermHandler(int const signalClass) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_server_abyss_terminate(&env, serverToTerminateP); dieIfFailed("xmlrpc_server_abyss_terminate", env); xmlrpc_env_clean(&env); } static void setupSigtermHandler(xmlrpc_server_abyss_t * const serverP) { struct sigaction mysigaction; serverToTerminateP = serverP; sigemptyset(&mysigaction.sa_mask); mysigaction.sa_flags = 0; mysigaction.sa_handler = sigtermHandler; sigaction(SIGTERM, &mysigaction, NULL); } static void restoreSigtermHandler(void){ struct sigaction mysigaction; sigemptyset(&mysigaction.sa_mask); mysigaction.sa_flags = 0; mysigaction.sa_handler = SIG_DFL; sigaction(SIGTERM, &mysigaction, NULL); } static xmlrpc_value * sample_add(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const channelInfo) { xmlrpc_int x, y, z; /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); if (envP->fault_occurred) return NULL; /* Add our two numbers. */ z = x + y; /* Return our result. */ return xmlrpc_build_value(envP, "i", z); } int main(int const argc, const char ** const argv) { struct xmlrpc_method_info3 const methodInfo = { .methodName = "sample.add", .methodFunction = &sample_add, .serverInfo = NULL }; xmlrpc_server_abyss_parms serverparm; xmlrpc_server_abyss_t * serverP; xmlrpc_registry * registryP; xmlrpc_env env; xmlrpc_server_abyss_sig * oldHandlersP; if (argc-1 != 1) { fprintf(stderr, "You must specify 1 argument: The TCP port number " "on which to listen for XML-RPC calls. " "You specified %d.\n", argc-1); exit(1); } xmlrpc_env_init(&env); xmlrpc_server_abyss_global_init(&env); dieIfFailed("xmlrpc_server_abyss_global_init", env); registryP = xmlrpc_registry_new(&env); dieIfFailed("xmlrpc_registry_new", env); xmlrpc_registry_add_method3(&env, registryP, &methodInfo); dieIfFailed("xmlrpc_registry_add_method2", env); serverparm.config_file_name = NULL; serverparm.registryP = registryP; serverparm.port_number = atoi(argv[1]); xmlrpc_server_abyss_create(&env, &serverparm, XMLRPC_APSIZE(port_number), &serverP); dieIfFailed("xmlrpc_server_abyss_create", env); xmlrpc_server_abyss_setup_sig(&env, serverP, &oldHandlersP); dieIfFailed("xmlrpc_server_abyss_setup_sig", env); setupSigtermHandler(serverP); printf("Running XML-RPC server...\n"); xmlrpc_server_abyss_run_server(&env, serverP); dieIfFailed("xmlrpc_server_abyss_run_server", env); printf("Server has terminated\n"); restoreSigtermHandler(); xmlrpc_server_abyss_restore_sig(oldHandlersP); xmlrpc_server_abyss_destroy(serverP); xmlrpc_registry_free(registryP); xmlrpc_server_abyss_global_term(); xmlrpc_env_clean(&env); return 0; } xmlrpc-c-1.33.14/examples/json.c000066400000000000000000000041731236133176700163610ustar00rootroot00000000000000/* This example program demonstrates the JSON parsing and generating capabilities of Xmlrpc-c. The program reads JSON text from Standard Input and displays its value as XML-RPC XML text. It then re-generates JSON from the intermediate parsed information and displays that. */ #include #include #include static void dieIfFaultOccurred(xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "ERROR: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } void printAsXml(xmlrpc_value * const valP) { xmlrpc_env env; xmlrpc_mem_block out; xmlrpc_env_init(&env); XMLRPC_MEMBLOCK_INIT(char, &env, &out, 0); dieIfFaultOccurred(&env); xmlrpc_serialize_value(&env, &out, valP); printf("XML-RPC XML:\n"); printf("%.*s\n", XMLRPC_MEMBLOCK_SIZE(char, &out), XMLRPC_MEMBLOCK_CONTENTS(char, &out)); XMLRPC_MEMBLOCK_CLEAN(char, &out); xmlrpc_env_clean(&env); } void printAsJson(xmlrpc_value * const valP) { xmlrpc_env env; xmlrpc_mem_block out; xmlrpc_value * val2P; xmlrpc_env_init(&env); XMLRPC_MEMBLOCK_INIT(char, &env, &out, 0); dieIfFaultOccurred(&env); xmlrpc_serialize_json(&env, valP, &out); dieIfFaultOccurred(&env); printf("JSON:\n"); printf("%.*s\n", XMLRPC_MEMBLOCK_SIZE(char, &out), XMLRPC_MEMBLOCK_CONTENTS(char, &out)); XMLRPC_MEMBLOCK_CLEAN(char, &out); xmlrpc_env_clean(&env); } int main(int argc, const char *argv[]) { xmlrpc_env env; char buf[1024]; xmlrpc_value * valP; size_t bytesRead; xmlrpc_env_init(&env); if (argc-1 > 0) { fprintf(stderr, "This program has no arguments. " "JSON input is from Standard Input\n"); exit(1); } bytesRead = fread(buf, 1, sizeof(buf), stdin); buf[bytesRead] = '\0'; valP = xmlrpc_parse_json(&env, buf); dieIfFaultOccurred(&env); printAsXml(valP); printAsJson(valP); xmlrpc_DECREF(valP); xmlrpc_env_clean(&env); return 0; } xmlrpc-c-1.33.14/examples/parse_xml.c000066400000000000000000000043731236133176700174040ustar00rootroot00000000000000/*============================================================================= parse_xml =============================================================================== This is an example of using the XML parsing facilities of XML-RPC For C/C++, in particular its libxmlrpc_xmlparse library. Feed XML (any XML - doesn't have to be XML-RPC) to this program as standard input. It parses it and tells you what it sees. Example: $ ./gen_sample_add_xml | ./parse_xml =============================================================================*/ #include #include #include #include "xmlrpc-c/base.h" #include "xmlrpc-c/xmlparser.h" static const char * getStdin(void) { size_t const maxInputSize = 64 * 1024; char * retval; retval = malloc(maxInputSize + 1); if (retval == NULL) { fprintf(stderr, "malloc failed."); exit(100); } else { size_t rc; rc = fread(retval, 1, maxInputSize, stdin); if (rc < 0) fprintf(stderr, "Failed to read Standard Input"); else { size_t const bytesRead = rc; retval[bytesRead] = '\0'; } } return retval; } static void describeXmlElement(const xml_element * const elemP, const char * const prefix) { unsigned int i; printf("%sXML element type: '%s'\n", prefix, xml_element_name(elemP)); printf("%sNumber of child elements: %u\n", prefix, xml_element_children_size(elemP)); for (i = 0; i < xml_element_children_size(elemP); ++i) { char * const newPrefix = malloc(strlen(prefix) + 2); sprintf(newPrefix, "%s ", prefix); describeXmlElement(xml_element_children(elemP)[i], newPrefix); free(newPrefix); } } int main(int argc, const char ** argv) { const char * xml; xmlrpc_env env; xml_element * elemP; xmlrpc_env_init(&env); xml = getStdin(); xml_parse(&env, xml, strlen(xml), &elemP); if (env.fault_occurred) printf("xml_parse failed. %s\n", env.fault_string); else { printf("Parsed successfully.\n"); describeXmlElement(elemP, ""); } xmlrpc_env_clean(&env); return 0; } xmlrpc-c-1.33.14/examples/synch_client.c000066400000000000000000000032111236133176700200620ustar00rootroot00000000000000/* A simple synchronous XML-RPC client program written in C. */ #include #include #include #include #include "config.h" /* information about this build environment */ #define NAME "XML-RPC C Test Client synch_client" #define VERSION "1.0" static void die_if_fault_occurred(xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "XML-RPC Fault: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } int main(int const argc, const char ** const argv) { xmlrpc_env env; xmlrpc_value * resultP; const char * stateName; if (argc-1 > 0) { fprintf(stderr, "No arguments"); exit(0); } /* Start up our XML-RPC client library. */ xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION); /* Initialize our error-handling environment. */ xmlrpc_env_init(&env); /* Call the famous server at UserLand. */ resultP = xmlrpc_client_call(&env, "http://betty.userland.com/RPC2", "examples.getStateName", "(i)", (xmlrpc_int32) 41); die_if_fault_occurred(&env); /* Get our state name and print it out. */ xmlrpc_read_string(&env, resultP, &stateName); die_if_fault_occurred(&env); printf("%s\n", stateName); free((char*)stateName); /* Dispose of our result value. */ xmlrpc_DECREF(resultP); /* Clean up our error-handling environment. */ xmlrpc_env_clean(&env); /* Shutdown our XML-RPC client library. */ xmlrpc_client_cleanup(); return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_asynch_client.c000066400000000000000000000072361236133176700216230ustar00rootroot00000000000000/* A simple asynchronous XML-RPC client program written in C, as an example of Xmlrpc-c asynchronous RPC facilities. This is the same as the simpler synchronous client xmlprc_sample_add_client.c, except that it adds 3 different pairs of numbers with the summation RPCs going on simultaneously. Use this with xmlrpc_sample_add_server. Note that that server intentionally takes extra time to add 1 to anything, so you can see our 5+1 RPC finish after our 5+0 and 5+2 RPCs. */ #include #include #include #include #include "config.h" /* information about this build environment */ #define NAME "Xmlrpc-c Asynchronous Test Client" #define VERSION "1.0" static void die_if_fault_occurred(xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "Something failed. %s (XML-RPC fault code %d)\n", envP->fault_string, envP->fault_code); exit(1); } } static void handle_sample_add_response(const char * const serverUrl, const char * const methodName, xmlrpc_value * const paramArrayP, void * const user_data, xmlrpc_env * const faultP, xmlrpc_value * const resultP) { xmlrpc_env env; xmlrpc_int addend, adder; /* Initialize our error environment variable */ xmlrpc_env_init(&env); /* Our first four arguments provide helpful context. Let's grab the addends from our parameter array. */ xmlrpc_decompose_value(&env, paramArrayP, "(ii)", &addend, &adder); die_if_fault_occurred(&env); printf("RPC with method '%s' at URL '%s' to add %d and %d " "has completed\n", methodName, serverUrl, addend, adder); if (faultP->fault_occurred) printf("The RPC failed. %s\n", faultP->fault_string); else { xmlrpc_int sum; xmlrpc_read_int(&env, resultP, &sum); die_if_fault_occurred(&env); printf("The sum is %d\n", sum); } } int main(int const argc, const char ** const argv) { const char * const serverUrl = "http://localhost:8080/RPC2"; const char * const methodName = "sample.add"; xmlrpc_env env; xmlrpc_client * clientP; xmlrpc_int adder; if (argc-1 > 0) { fprintf(stderr, "This program has no arguments\n"); exit(1); } /* Initialize our error environment variable */ xmlrpc_env_init(&env); /* Required before any use of Xmlrpc-c client library: */ xmlrpc_client_setup_global_const(&env); die_if_fault_occurred(&env); xmlrpc_client_create(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0, &clientP); die_if_fault_occurred(&env); for (adder = 0; adder < 3; ++adder) { printf("Making XMLRPC call to server url '%s' method '%s' " "to request the sum " "of 5 and %d...\n", serverUrl, methodName, adder); /* request the remote procedure call */ xmlrpc_client_start_rpcf(&env, clientP, serverUrl, methodName, handle_sample_add_response, NULL, "(ii)", (xmlrpc_int32) 5, adder); die_if_fault_occurred(&env); } printf("RPCs all requested. Waiting for & handling responses...\n"); /* Wait for all RPCs to be done. With some transports, this is also what causes them to go. */ xmlrpc_client_event_loop_finish(clientP); printf("All RPCs finished.\n"); xmlrpc_client_destroy(clientP); xmlrpc_client_teardown_global_const(); return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_inetd_server.c000066400000000000000000000073111236133176700214630ustar00rootroot00000000000000/* A simple standalone XML-RPC server program based on Abyss that processes a single RPC from an existing TCP connection on Standard Input. A typical example of where this would be useful is with an Inetd "super server." xmlrpc_sample_add_server.c is a server that does the same thing, but you give it a TCP port number and it listens for TCP connecitons and processes RPCs ad infinitum. xmlrpc_socket_server.c is halfway in between those -- you give it an already bound and listening socket, and it lists for TCP connections and processes RPCs ad infinitum. Here is an easy way to test this program: socketexec --accept --local_port=8080 --stdin -- ./xmlrpc_inetd_server Now run the client program 'xmlrpc_sample_add_client'. Socketexec will accept the connection that the client program requests and pass it to this program on Standard Input. This program will perform the RPC, respond to the client, then exit. */ #define _XOPEN_SOURCE 600 #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.h */ #include #include #include #ifndef _WIN32 # include #endif #include #include #include #include #include "config.h" /* information about this build environment */ static void setupSignalHandlers(void) { /* In UNIX, when you try to write to a socket that has been closed from the other end, your write fails, but you also get a SIGPIPE signal. That signal will kill you before you even have a chance to see the write fail unless you catch, block, or ignore it. If a client should connect to us and then disconnect before we've sent our response, we see this socket-closed behavior. We obviously don't want to die just because a client didn't complete an RPC, so we ignore SIGPIPE. */ #ifndef _WIN32 struct sigaction mysigaction; sigemptyset(&mysigaction.sa_mask); mysigaction.sa_flags = 0; mysigaction.sa_handler = SIG_IGN; sigaction(SIGPIPE, &mysigaction, NULL); #endif } static xmlrpc_value * sample_add(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const channelInfo) { xmlrpc_int x, y, z; /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); if (envP->fault_occurred) return NULL; /* Add our two numbers. */ z = x + y; /* Return our result. */ return xmlrpc_build_value(envP, "i", z); } int main(int const argc, const char ** const argv) { struct xmlrpc_method_info3 const methodInfo = { .methodName = "sample.add", .methodFunction = &sample_add, .serverInfo = NULL }; TServer abyssServer; xmlrpc_registry * registryP; xmlrpc_env env; if (argc-1 != 0) { fprintf(stderr, "There are no arguments. You must supply a " "bound socket on which to listen for client connections " "as Standard Input\n"); if (argv) {} /* silence unused parameter warning */ exit(1); } xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); xmlrpc_registry_add_method3(&env, registryP, &methodInfo); ServerCreateNoAccept(&abyssServer, "XmlRpcServer", NULL, NULL); xmlrpc_server_abyss_set_handlers(&abyssServer, registryP); setupSignalHandlers(); ServerRunConn(&abyssServer, STDIN_FILENO); /* This reads the HTTP POST request from Standard Input and executes the indicated RPC. */ ServerFree(&abyssServer); return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_loop_server.c000066400000000000000000000115201236133176700213260ustar00rootroot00000000000000/* A simple standalone XML-RPC server program based on Abyss that contains a simple one-thread request processing loop. This uses the "provide your own Abyss server" mode of operation. xmlrpc_sample_add_server.c is a server that does the same thing, but does it by running a full Abyss daemon in the background, so it has less control over how the requests are served. */ #define _XOPEN_SOURCE 600 #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.h */ #include #include #include #ifndef _WIN32 #include #include #endif #include #include #include #include #include "config.h" /* information about this build environment */ static void setupSignalHandlers(void) { /* In UNIX, when you try to write to a socket that has been closed from the other end, your write fails, but you also get a SIGPIPE signal. That signal will kill you before you even have a chance to see the write fail unless you catch, block, or ignore it. If a client should connect to us and then disconnect before we've sent our response, we see this socket-closed behavior. We obviously don't want to die just because a client didn't complete an RPC, so we ignore SIGPIPE. */ #ifndef _WIN32 struct sigaction mysigaction; sigemptyset(&mysigaction.sa_mask); mysigaction.sa_flags = 0; mysigaction.sa_handler = SIG_IGN; sigaction(SIGPIPE, &mysigaction, NULL); #endif } static void printPeerIpAddr(TSession * const abyssSessionP) { #ifdef _WIN32 struct abyss_win_chaninfo * channelInfoP; #else struct abyss_unix_chaninfo * channelInfoP; #endif struct sockaddr_in * sockAddrInP; unsigned char * ipAddr; /* 4 byte array */ SessionGetChannelInfo(abyssSessionP, (void*)&channelInfoP); sockAddrInP = (struct sockaddr_in *) &channelInfoP->peerAddr; ipAddr = (unsigned char *)&sockAddrInP->sin_addr.s_addr; printf("RPC is from IP address %u.%u.%u.%u\n", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]); } static xmlrpc_value * sample_add(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const channelInfo) { xmlrpc_int x, y, z; printPeerIpAddr(channelInfo); /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); if (envP->fault_occurred) return NULL; /* Add our two numbers. */ z = x + y; /* Return our result. */ return xmlrpc_build_value(envP, "i", z); } static xmlrpc_server_shutdown_fn requestShutdown; static void requestShutdown(xmlrpc_env * const faultP, void * const context, const char * const comment, void * const callInfo) { /* You make this run by executing the system method 'system.shutdown'. This function is registered in the method registry as the thing to call for that. */ int * const terminationRequestedP = context; TSession * const abyssSessionP = callInfo; xmlrpc_env_init(faultP); fprintf(stderr, "Termination requested: %s\n", comment); printPeerIpAddr(abyssSessionP); *terminationRequestedP = 1; } int main(int const argc, const char ** const argv) { struct xmlrpc_method_info3 const methodInfo = { .methodName = "sample.add", .methodFunction = &sample_add, .serverInfo = NULL }; TServer abyssServer; xmlrpc_registry * registryP; xmlrpc_env env; int terminationRequested; /* A boolean value */ const char * error; if (argc-1 != 1) { fprintf(stderr, "You must specify 1 argument: The TCP port number " "on which to listen for XML-RPC calls. " "You specified %d.\n", argc-1); exit(1); } AbyssInit(&error); xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); xmlrpc_registry_add_method3(&env, registryP, &methodInfo); xmlrpc_registry_set_shutdown(registryP, &requestShutdown, &terminationRequested); ServerCreate(&abyssServer, "XmlRpcServer", atoi(argv[1]), NULL, NULL); xmlrpc_server_abyss_set_handlers2(&abyssServer, "/RPC2", registryP); ServerInit(&abyssServer); setupSignalHandlers(); terminationRequested = 0; while (!terminationRequested) { printf("Waiting for next RPC...\n"); ServerRunOnce(&abyssServer); /* This waits for the next connection, accepts it, reads the HTTP POST request, executes the indicated RPC, and closes the connection. */ } ServerFree(&abyssServer); AbyssTerm(); return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_sample_add_client.c000066400000000000000000000042051236133176700224200ustar00rootroot00000000000000/* A simple synchronous XML-RPC client program written in C, as an example of an Xmlrpc-c client. This invokes the sample.add procedure that the Xmlrpc-c example xmlrpc_sample_add_server.c server provides. I.e. it adds two numbers together, the hard way. This sends the RPC to the server running on the local system ("localhost"), HTTP Port 8080. */ #include #include #include #include #include "config.h" /* information about this build environment */ #define NAME "Xmlrpc-c Test Client" #define VERSION "1.0" static void dieIfFaultOccurred (xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "ERROR: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } int main(int const argc, const char ** const argv) { xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_int32 sum; const char * const serverUrl = "http://localhost:8080/RPC2"; const char * const methodName = "sample.add"; if (argc-1 > 0) { fprintf(stderr, "This program has no arguments\n"); exit(1); } /* Initialize our error-handling environment. */ xmlrpc_env_init(&env); /* Start up our XML-RPC client library. */ xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0); dieIfFaultOccurred(&env); printf("Making XMLRPC call to server url '%s' method '%s' " "to request the sum " "of 5 and 7...\n", serverUrl, methodName); /* Make the remote procedure call */ resultP = xmlrpc_client_call(&env, serverUrl, methodName, "(ii)", (xmlrpc_int32) 5, (xmlrpc_int32) 7); dieIfFaultOccurred(&env); /* Get our sum and print it out. */ xmlrpc_read_int(&env, resultP, &sum); dieIfFaultOccurred(&env); printf("The sum is %d\n", sum); /* Dispose of our result value. */ xmlrpc_DECREF(resultP); /* Clean up our error-handling environment. */ xmlrpc_env_clean(&env); /* Shutdown our XML-RPC client library. */ xmlrpc_client_cleanup(); return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_sample_add_server.c000066400000000000000000000063541236133176700224570ustar00rootroot00000000000000/* A simple standalone XML-RPC server program written in C. */ /* This server knows one RPC class (besides the system classes): "sample.add". The program takes one argument: the HTTP port number on which the server is to accept connections, in decimal. You can use the example program 'xmlrpc_sample_add_client' to send an RPC to this server. Example: $ ./xmlrpc_sample_add_server 8080& $ ./xmlrpc_sample_add_client For more fun, run client and server in separate terminals and turn on tracing for each: $ export XMLRPC_TRACE_XML=1 */ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.h */ #include #include #ifdef _WIN32 # include # include #else # include #endif #include #include #include #include "config.h" /* information about this build environment */ #ifdef _WIN32 #define SLEEP(seconds) SleepEx(seconds * 1000, 1); #else #define SLEEP(seconds) sleep(seconds); #endif static xmlrpc_value * sample_add(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const channelInfo) { xmlrpc_int32 x, y, z; /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); if (envP->fault_occurred) return NULL; /* Add our two numbers. */ z = x + y; /* Sometimes, make it look hard (so client can see what it's like to do an RPC that takes a while). */ if (y == 1) SLEEP(3); /* Return our result. */ return xmlrpc_build_value(envP, "i", z); } int main(int const argc, const char ** const argv) { struct xmlrpc_method_info3 const methodInfo = { /* .methodName = */ "sample.add", /* .methodFunction = */ &sample_add, }; xmlrpc_server_abyss_parms serverparm; xmlrpc_registry * registryP; xmlrpc_env env; if (argc-1 != 1) { fprintf(stderr, "You must specify 1 argument: The TCP port " "number on which the server will accept connections " "for RPCs (8080 is a common choice). " "You specified %d arguments.\n", argc-1); exit(1); } xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); if (env.fault_occurred) { printf("xmlrpc_registry_new() failed. %s\n", env.fault_string); exit(1); } xmlrpc_registry_add_method3(&env, registryP, &methodInfo); if (env.fault_occurred) { printf("xmlrpc_registry_add_method3() failed. %s\n", env.fault_string); exit(1); } serverparm.config_file_name = NULL; /* Select the modern normal API */ serverparm.registryP = registryP; serverparm.port_number = atoi(argv[1]); serverparm.log_file_name = "/tmp/xmlrpc_log"; printf("Running XML-RPC server...\n"); xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name)); if (env.fault_occurred) { printf("xmlrpc_server_abyss() failed. %s\n", env.fault_string); exit(1); } /* xmlrpc_server_abyss() never returns unless it fails */ return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_sample_add_server_cgi.c000066400000000000000000000033651236133176700233000ustar00rootroot00000000000000/* A CGI script written in C to effect a simple XML-RPC server. Example of use: - Compile this as the executable 'xmlrpc_sample_add_server.cgi' - Place the .cgi file in web server www.example.com's /cgi-bin directory. - Configure the web server to permit CGI scripts in /cgi-bin (Apache ExecCgi directory option). - Configure the web server to recognize this .cgi file as a CGI script (Apache "AddHandler cgi-script ..." or ScriptAlias). - $ xmlrpc http://www.example.com/cgi-bin/xmlrpc_sample_add_server.cgi \ sample.add i/5 i/7 */ #include #include #include #include #include #include "config.h" /* information about this build environment */ static xmlrpc_value * sample_add(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const user_data) { xmlrpc_int32 x, y, z; /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); if (envP->fault_occurred) return NULL; /* Add our two numbers. */ z = x + y; /* Return our result. */ return xmlrpc_build_value(envP, "i", z); } int main(int const argc, const char ** const argv) { xmlrpc_registry * registryP; xmlrpc_env env; if (argc-1 > 0 && argv==argv) { fprintf(stderr, "There are no arguments to a CGI script\n"); exit(1); } xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); xmlrpc_registry_add_method( &env, registryP, NULL, "sample.add", &sample_add, NULL); xmlrpc_server_cgi_process_call(registryP); xmlrpc_registry_free(registryP); return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_sample_add_server_w32httpsys.c000066400000000000000000000174771236133176700246210ustar00rootroot00000000000000/* Copyright (C) 2005 by Steven A. Bone, sbone@pobox.com. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /* COMPILATION NOTE: Note that the Platform SDK headers and link libraries for Windows XP SP2 or newer are required to compile xmlrpc-c for this module. If you are not using this server, it is safe to exclude the xmlrpc_server_w32httpsys.c file from the xmlrpc project and these dependencies will not be required. You can get the latest platform SDK at http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ Be sure after installation to choose the program to "register the PSDK directories with Visual Studio" so the newer headers are found. */ #include #include #include #include #include /* SECURITY NOTE: Using HTTP Authorization The current implementation of HTTP Authorization in the win32httpsys server only uses basic Authorization. This means the userid and password is sent in clear-text over the network (Technically, it is Base64 encoded, but this is essentially clear text). This method is not secure, as it can be captured and decoded. The use of HTTP Basic Authorization with SSL is considered much more secure. See the note below for configuring SSL support. */ /* HOWTO: Configure SSL for the XMLRPC-C Server To use SSL you need an SSL certificate. For testing purposes, it is possible to create a self-signed SSL certificate. To do so, you must download the IIS 6.0 Resource Kit tools. The current URL to get the download link is http://support.microsoft.com/kb/840671 We will be using the SelfSSL version 1.0 from this toolkit for this example. The other tool you will need is httpcfg.exe, which can be compiled from the sources in the Windows XP SP2 (or newer) Platform SDK, or downloaded as part of the Windows XP SP2 Support Tools at the following URL: http://www.microsoft.com/downloads/details.aspx?FamilyID=49ae8576-9bb9-4126-9761-ba8011fabf38&displaylang=en The last assumption is that this procedure is being done on the machine that is hosting the XMLRPC-C server application. 1) Make sure that IIS is installed, and you are running at least Windows XP SP2 or Windows Server 2003. WARNING: This process will replace any existing IIS SSL certificates currently installed. 2) In a command prompt, navigate to the directory of the IIS Support Tools where the selfssl program exists (usually C:\Program Files\IIS Resources\SelfSSL). Assuming (as we are for this example) that we are going to run on port 8443, use the following command line (see the documentation for all the flags): selfssl /T /V:365 /P:8443 3) In the Control Panel, Administrative tools, run the Internet Information Services program. Drill down to the Default Web Site. Right-click it and choose Properties. On the "Web Site" tab, you will notice that the SSL port is now set to 8443. Change it back to 443. On the Directory Security tab, pick "View Certificate". In the "Details" tab, select the "Thumbprint" line. The edit box below the listbox will display a series of hex numbers. Copy these to the clipboard and paste into notepad. OK yourself out of the IIS program. 4) Remove all the spaces in the hex string so you are left with a string with no spaces. This is your SSL Thumbprint hash which you will need in the next step. 5) At your command prompt, navigate to the support tools directory (or the location where you built httpcfg.exe) - usually C:\Program Files\Support Tools. Run the following command line, replacing both the brackets and text with your thumbprint hash from step 4 above: httpcfg.exe set ssl -i 0.0.0.0:8443 -h -g "{2bb50d9c-7f6a-4d6f-873d-5aee7fb43290}" -c "MY" -t "" -n "" 6) You can check the setup by performing a "httpcfg.exe query ssl" if you wish. 7) Modify the example server code below to use SSL. Set the xmlrpc_server_httpsys_parms.useSSL to '1' and the xmlrpc_server_httpsys_parms.portNum to be '8443'. You can test the server by using IE to browse to the URL https://127.0.0.1:8443/rpc2. An error 405 (Resource not allowed) is the expected result if everything is working properly. NOTE: Testing clients with a 'test' or not real SSL certificate involves changing some of the default code in the client samples, as by default the transports will fail if there are any issues with the certificate. The WinInet transport as of 1.2 has a transport-specific setting to allow invalid SSL certificates. See the libxmlrpc_client.html documentation for more details. NOTE: Failure to follow all the steps listed above correctly will result in no application errors, event log messages, or HTTP.SYS log messages indicating failure or the cause. If anyone can provide information on debugging SSL certificate issues in HTTP.SYS, please submit to us! */ static xmlrpc_value * sample_add(xmlrpc_env * const env, xmlrpc_value * const param_array, void * const user_data ) { xmlrpc_int32 x, y, z; /* Parse our argument array. */ xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y); if (env->fault_occurred) return NULL; /* Add our two numbers. */ z = x + y; /* Return our result. */ return xmlrpc_build_value(env, "i", z); } static void handleAuthorization( xmlrpc_env * envP, char * userid, char * password) { if (strcmp(userid,"jrandom")==0 && strcmp(password,"secret")==0) return; xmlrpc_env_set_fault( envP, XMLRPC_REQUEST_REFUSED_ERROR, "Username and/or password do not match."); } int __cdecl wmain( int argc, wchar_t * argv[]) { xmlrpc_server_httpsys_parms serverparm; xmlrpc_registry * registryP; xmlrpc_env env; xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); xmlrpc_registry_add_method( &env, registryP, NULL, "sample.add", &sample_add, NULL); wprintf(L"Starting XML-RPC server...\n"); //Sets the port number we are listening on serverparm.portNum=8080; //if this is set, we will use the authorization function //serverparm.authfn=NULL; serverparm.authfn=&handleAuthorization; //set the logging level and log file serverparm.logLevel=2; serverparm.logFile="C:\\httpsysserverlog.txt"; //set the use of SSL serverparm.useSSL=0; serverparm.registryP = registryP; xmlrpc_server_httpsys(&env, &serverparm, XMLRPC_HSSIZE(authfn)); wprintf(L"Stopping XML-RPC server...\n"); xmlrpc_registry_free(registryP); xmlrpc_env_clean(&env); return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_server_validatee.c000066400000000000000000000327611236133176700223250ustar00rootroot00000000000000/* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /*============================================================================ xmlrpc_server_validatee ============================================================================== This program runs an XMLRPC server, using the Xmlrpc-c libraries. The server implements the methods that the Userland Validator1 test suite invokes, which are supposed to exercise a broad range of XMLRPC server function. Coments here used to say you could get information about Validator1 from , but as of 2004.09.25, there's nothing there (there's a web server, but it is not configured to serve that particular URL). ============================================================================*/ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.h */ #include #include #include #include #include #include #include "config.h" /* information about this build environment */ #define RETURN_IF_FAULT(envP) \ do { \ if ((envP)->fault_occurred) \ return NULL; \ } while (0) /*========================================================================= ** validator1.arrayOfStructsTest **========================================================================= */ static xmlrpc_value * array_of_structs(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const user_data) { xmlrpc_value * arrayP; xmlrpc_value * retval; xmlrpc_decompose_value(envP, paramArrayP, "(A)", &arrayP); if (envP->fault_occurred) retval = NULL; else { /* Add up all the struct elements named "curly". */ size_t size; size = xmlrpc_array_size(envP, arrayP); if (envP->fault_occurred) retval = NULL; else { unsigned int sum; unsigned int i; sum = 0; for (i = 0; i < size && !envP->fault_occurred; ++i) { xmlrpc_value * strctP; strctP = xmlrpc_array_get_item(envP, arrayP, i); if (!envP->fault_occurred) { xmlrpc_int32 curly; xmlrpc_decompose_value(envP, strctP, "{s:i,*}", "curly", &curly); if (!envP->fault_occurred) sum += curly; } } xmlrpc_DECREF(arrayP); if (envP->fault_occurred) retval = NULL; else retval = xmlrpc_build_value(envP, "i", sum); } } return retval; } /*========================================================================= ** validator1.countTheEntities **========================================================================= */ static xmlrpc_value * count_entities(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const user_data) { const char * str; size_t len, i; xmlrpc_int32 left, right, amp, apos, quote; xmlrpc_decompose_value(envP, paramArrayP, "(s#)", &str, &len); RETURN_IF_FAULT(envP); left = right = amp = apos = quote = 0; for (i = 0; i < len; ++i) { switch (str[i]) { case '<': ++left; break; case '>': ++right; break; case '&': ++amp; break; case '\'': ++apos; break; case '\"': ++quote; break; default: break; } } free((void*)str); return xmlrpc_build_value(envP, "{s:i,s:i,s:i,s:i,s:i}", "ctLeftAngleBrackets", left, "ctRightAngleBrackets", right, "ctAmpersands", amp, "ctApostrophes", apos, "ctQuotes", quote); } /*========================================================================= ** validator1.easyStructTest **========================================================================= */ static xmlrpc_value * easy_struct(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const user_data) { xmlrpc_int32 larry, moe, curly; /* Parse our argument array and get the stooges. */ xmlrpc_decompose_value(envP, paramArrayP, "({s:i,s:i,s:i,*})", "larry", &larry, "moe", &moe, "curly", &curly); RETURN_IF_FAULT(envP); /* Return our result. */ return xmlrpc_build_value(envP, "i", larry + moe + curly); } /*========================================================================= ** validator1.echoStructTest **========================================================================= */ static xmlrpc_value * echo_struct(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const user_data) { xmlrpc_value * sP; /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(S)", &sP); RETURN_IF_FAULT(envP); return sP; /* We transfer our reference on '*sP' to Caller */ } /*========================================================================= ** validator1.manyTypesTest **========================================================================= */ static xmlrpc_value * many_types(xmlrpc_env * const env, xmlrpc_value * const param_array, void * const user_data) { /* Create another reference to our argument array and return it as is. */ xmlrpc_INCREF(param_array); return param_array; } /*========================================================================= ** validator1.moderateSizeArrayCheck **========================================================================= */ static void concatenate(xmlrpc_env * const envP, const char * const str1, size_t const str1_len, const char * const str2, size_t const str2_len, xmlrpc_value ** const resultPP) { /* Concatenate the two strings. */ char * buffer; buffer = (char*) malloc(str1_len + str2_len); if (!buffer) { xmlrpc_env_set_fault(envP, 1, "Couldn't allocate concatenated string"); } else { memcpy(buffer, str1, str1_len); memcpy(&buffer[str1_len], str2, str2_len); *resultPP = xmlrpc_build_value(envP, "s#", buffer, str1_len + str2_len); free(buffer); } } static xmlrpc_value * moderate_array(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const user_data) { xmlrpc_value * retval; xmlrpc_value * arrayP; /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(A)", &arrayP); if (!envP->fault_occurred) { int const size = xmlrpc_array_size(envP, arrayP); if (!envP->fault_occurred) { /* Get our first string. */ xmlrpc_value * const firstItemP = xmlrpc_array_get_item(envP, arrayP, 0); if (!envP->fault_occurred) { const char * str1; size_t str1_len; xmlrpc_read_string_lp(envP, firstItemP, &str1_len, &str1); if (!envP->fault_occurred) { /* Get our last string. */ xmlrpc_value * const lastItemP = xmlrpc_array_get_item(envP, arrayP, size - 1); if (!envP->fault_occurred) { const char * str2; size_t str2_len; xmlrpc_read_string_lp(envP, lastItemP, &str2_len, &str2); if (!envP->fault_occurred) { concatenate(envP, str1, str1_len, str2, str2_len, &retval); free((char*)str2); } } free((char*)str1); } } } xmlrpc_DECREF(arrayP); } return retval; } /*========================================================================= ** validator1.nestedStructTest **========================================================================= */ static xmlrpc_value * nested_struct(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const user_data) { xmlrpc_value * yearsP; xmlrpc_value * retval; /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(S)", &yearsP); if (envP->fault_occurred) retval = NULL; else { /* Get values of larry, moe and curly for 2000-04-01. */ xmlrpc_int32 larry, moe, curly; xmlrpc_decompose_value(envP, yearsP, "{s:{s:{s:{s:i,s:i,s:i,*},*},*},*}", "2000", "04", "01", "larry", &larry, "moe", &moe, "curly", &curly); if (envP->fault_occurred) retval = NULL; else retval = xmlrpc_build_value(envP, "i", larry + moe + curly); xmlrpc_DECREF(yearsP); } return retval; } /*========================================================================= ** validator1.simpleStructReturnTest **========================================================================= */ static xmlrpc_value * struct_return(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const user_data) { xmlrpc_int32 i; xmlrpc_decompose_value(envP, paramArrayP, "(i)", &i); RETURN_IF_FAULT(envP); return xmlrpc_build_value(envP, "{s:i,s:i,s:i}", "times10", (xmlrpc_int32) i * 10, "times100", (xmlrpc_int32) i * 100, "times1000", (xmlrpc_int32) i * 1000); } /*========================================================================= ** main **========================================================================= */ int main(int const argc, const char ** const argv) { xmlrpc_server_abyss_parms serverparm; xmlrpc_registry * registryP; xmlrpc_env env; if (argc-1 != 1) { fprintf(stderr, "You must specify 1 argument: The TCP port " "number on which the server will accept connections " "for RPCs. You specified %d arguments.\n", argc-1); exit(1); } xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); xmlrpc_registry_add_method( &env, registryP, NULL, "validator1.arrayOfStructsTest", &array_of_structs, NULL); xmlrpc_registry_add_method( &env, registryP, NULL, "validator1.countTheEntities", &count_entities, NULL); xmlrpc_registry_add_method( &env, registryP, NULL, "validator1.easyStructTest", &easy_struct, NULL); xmlrpc_registry_add_method( &env, registryP, NULL, "validator1.echoStructTest", &echo_struct, NULL); xmlrpc_registry_add_method( &env, registryP, NULL, "validator1.manyTypesTest", &many_types, NULL); xmlrpc_registry_add_method( &env, registryP, NULL, "validator1.moderateSizeArrayCheck", &moderate_array, NULL); xmlrpc_registry_add_method( &env, registryP, NULL, "validator1.nestedStructTest", &nested_struct, NULL); xmlrpc_registry_add_method( &env, registryP, NULL, "validator1.simpleStructReturnTest", &struct_return, NULL); serverparm.config_file_name = NULL; serverparm.registryP = registryP; serverparm.port_number = atoi(argv[1]); serverparm.log_file_name = NULL; printf("Running XML-RPC server...\n"); xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(log_file_name)); /* This never gets executed. */ return 0; } xmlrpc-c-1.33.14/examples/xmlrpc_socket_server.c000066400000000000000000000061411236133176700216500ustar00rootroot00000000000000/* A simple standalone XML-RPC server program written in C as an example of use of the Xmlrpc-c libraries. This example expects an already bound socket on Standard Input, ready to be listened on for client connections. Also see xmlrpc_sample_add_server, which is the same thing, except you tell it a TCP port number and it creates the socket itself. Also see xmlrpc_inetd_server.c, which is the same thing except you give it a socket which is already connected to a client. Example: $ socketexec -local_port=8080 ./xmlrpc_socket_server */ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/server_abyss.h */ #include #include #ifdef _WIN32 # include #else # include #endif #include #include #include #include "config.h" /* information about this build environment */ #ifdef _WIN32 #define SLEEP(seconds) SleepEx(seconds * 1000, 1); #else #define SLEEP(seconds) sleep(seconds); #endif static xmlrpc_value * sample_add(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const channelInfo) { xmlrpc_int32 x, y, z; /* Parse our argument array. */ xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); if (envP->fault_occurred) return NULL; /* Add our two numbers. */ z = x + y; /* Sometimes, make it look hard (so client can see what it's like to do an RPC that takes a while). */ if (y == 1) SLEEP(2); /* Return our result. */ return xmlrpc_build_value(envP, "i", z); } int main(int const argc, const char ** const argv) { struct xmlrpc_method_info3 const methodInfo = { .methodName = "sample.add", .methodFunction = &sample_add, .serverInfo = NULL }; xmlrpc_server_abyss_parms serverparm; xmlrpc_registry * registryP; xmlrpc_env env; if (argc-1 != 0) { fprintf(stderr, "There are no arguments. You must supply a " "bound socket on which to listen for client connections " "as Standard Input\n"); if (argv) {} /* silence unused parameter warning */ exit(1); } xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); xmlrpc_registry_add_method3(&env, registryP, &methodInfo); /* In the modern form of the Abyss API, we supply parameters in memory like a normal API. We select the modern form by setting config_file_name to NULL: */ serverparm.config_file_name = NULL; serverparm.registryP = registryP; serverparm.log_file_name = "/tmp/xmlrpc_log"; serverparm.keepalive_timeout = 0; serverparm.keepalive_max_conn = 0; serverparm.timeout = 0; serverparm.dont_advertise = FALSE; serverparm.socket_bound = TRUE; serverparm.socket_handle = STDIN_FILENO; printf("Running XML-RPC server...\n"); xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(socket_handle)); return 0; } xmlrpc-c-1.33.14/include/000077500000000000000000000000001236133176700150445ustar00rootroot00000000000000xmlrpc-c-1.33.14/include/Makefile000066400000000000000000000126521236133176700165120ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') SRCDIR := $(call updir,$(CURDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := include include $(BLDDIR)/config.mk default: all all: xmlrpc-c/config.h xmlrpc-c/config.h: $(BLDDIR)/$(SUBDIR)/xmlrpc-c >$@ @echo "Lots of echoes to '$@' suppressed here ..." @echo '#ifndef XMLRPC_C_CONFIG_H_INCLUDED' >>$@ @echo '#define XMLRPC_C_CONFIG_H_INCLUDED' >>$@ @echo '' >>$@ @echo '/* This file, part of XML-RPC For C/C++, is meant to ' >>$@ @echo ' define characteristics of this particular installation '>>$@ @echo ' that the other header files need in ' >>$@ @echo ' order to compile correctly when #included in Xmlrpc-c' >>$@ @echo ' user code.' >>$@ @echo '' >>$@ @echo ' Those header files #include this one.' >>$@ @echo '' >>$@ @echo ' This file was created by a make rule.' >>$@ @echo '*/' >>$@ @echo '#define XMLRPC_HAVE_WCHAR $(HAVE_WCHAR_H_DEFINE)' >>$@ @echo '#ifdef _WIN32' >>$@ @echo ' /* SOCKET is a type defined by . Anyone who' >>$@ @echo ' uses XMLRPC_SOCKET on a WIN32 system must #include' >>$@ @echo ' ' >>$@ @echo ' */' >>$@ @echo ' #define XMLRPC_SOCKET SOCKET' >>$@ @echo ' #define XMLRPC_HAVE_TIMEVAL 0' >>$@ @echo ' #define XMLRPC_HAVE_TIMESPEC 0' >>$@ @echo ' #define XMLRPC_HAVE_PTHREAD 0' >>$@ @echo ' #define XMLRPC_HAVE_WINTHREAD 1' >>$@ @echo '#else' >>$@ @echo ' #define XMLRPC_SOCKET int' >>$@ @echo ' #define XMLRPC_HAVE_TIMEVAL 1' >>$@ @echo ' #define XMLRPC_HAVE_TIMESPEC 1' >>$@ @echo ' #define XMLRPC_HAVE_PTHREAD 1' >>$@ @echo ' #define XMLRPC_HAVE_WINTHREAD 0' >>$@ @echo '#endif' >>$@ @echo '' >>$@ @echo '#if defined(_MSC_VER)' >>$@ @echo ' /* Newer MSVC has long long, but MSVC 6 does not */' >>$@ @echo ' #define XMLRPC_INT64 __int64' >>$@ @echo ' #define XMLRPC_PRId64 "I64"' >>$@ @echo ' #define XMLRPC_INT32 __int32' >>$@ @echo '#else' >>$@ @echo ' #define XMLRPC_INT64 long long' >>$@ @echo ' #define XMLRPC_PRId64 "lld"' >>$@ @echo ' #define XMLRPC_INT32 int' >>$@ @echo '#endif' >>$@ @echo '#endif' >>$@ $(BLDDIR)/$(SUBDIR)/xmlrpc-c: mkdir $@ COMPAT_LINK_CMDS = \ $(LN_S) xmlrpc-c/oldxmlrpc.h xmlrpc.h; \ $(LN_S) xmlrpc-c/server.h xmlrpc_server.h; \ $(LN_S) xmlrpc-c/server_abyss.h xmlrpc_abyss.h; \ $(LN_S) xmlrpc-c/server_w32httpsys.h xmlrpc_server_w32httpsys.h; \ HEADERS_TO_INSTALL = \ xmlrpc-c/config.h \ xmlrpc-c/inttypes.h \ xmlrpc-c/c_util.h \ xmlrpc-c/util.h \ xmlrpc-c/base.h \ xmlrpc-c/json.h \ xmlrpc-c/abyss.h \ xmlrpc-c/abyss_unixsock.h \ xmlrpc-c/abyss_winsock.h \ xmlrpc-c/server.h \ xmlrpc-c/server_abyss.h \ xmlrpc-c/server_w32httpsys.h \ xmlrpc-c/oldxmlrpc.h \ ifeq ($(ENABLE_CPLUSPLUS),yes) HEADERS_TO_INSTALL += \ xmlrpc-c/oldcppwrapper.hpp \ xmlrpc-c/girerr.hpp \ xmlrpc-c/girmem.hpp \ xmlrpc-c/base.hpp \ xmlrpc-c/base64.hpp \ xmlrpc-c/timeout.hpp \ xmlrpc-c/xml.hpp \ xmlrpc-c/registry.hpp \ xmlrpc-c/server_abyss.hpp \ xmlrpc-c/packetsocket.hpp \ xmlrpc-c/server_pstream.hpp \ COMPAT_LINK_CMDS += $(LN_S) xmlrpc-c/oldcppwrapper.hpp XmlRpcCpp.h; endif HEADERINST_PREFIX = /xmlrpc-c ifeq ($(MUST_BUILD_CLIENT),yes) HEADERS_TO_INSTALL += \ xmlrpc-c/client.h \ xmlrpc-c/transport.h \ xmlrpc-c/client_global.h \ COMPAT_LINK_CMDS += $(LN_S) xmlrpc-c/client.h xmlrpc_client.h; ifeq ($(ENABLE_CPLUSPLUS),yes) HEADERS_TO_INSTALL += \ xmlrpc-c/client.hpp \ xmlrpc-c/client_transport.hpp \ xmlrpc-c/client_simple.hpp \ endif endif ifeq ($(ENABLE_CGI_SERVER),yes) HEADERS_TO_INSTALL += xmlrpc-c/server_cgi.h COMPAT_LINK_CMDS += $(LN_S) xmlrpc-c/server_cgi.h xmlrpc_cgi.h; endif default: all all: .PHONY: install-compat-hdr install-compat-hdr: install-headers # Install old names of header files for backward compatibility cd $(DESTDIR)$(HEADERINST_DIR); \ rm -f xmlrpc.h xmlrpc_client.h xmlrpc_server.h xmlrpc_cgi.h \ xmlrpc_server_abyss.h xmlrpc_abyss.h \ xmlrpc_server_w32httpsys.h \ XmlRpcCpp.h; \ $(COMPAT_LINK_CMDS) .PHONY: install install: install-common install-compat-hdr .PHONY: clean clean: rm -f xmlrpc-c/config.h .PHONY: distclean distclean: clean .PHONY: check check: .PHONY: dep dep: OMIT_CONFIG_H_RULE = Y include $(SRCDIR)/common.mk xmlrpc-c-1.33.14/include/xmlrpc-c/000077500000000000000000000000001236133176700165715ustar00rootroot00000000000000xmlrpc-c-1.33.14/include/xmlrpc-c/abyss.h000066400000000000000000000474001236133176700200700ustar00rootroot00000000000000/***************************************************************************** abyss.h ****************************************************************************** This file is the interface header for the Abyss HTTP server component of XML-RPC For C/C++ (Xmlrpc-c). The Abyss component of Xmlrpc-c is based on the independently developed and distributed Abyss web server package from 2001. Nothing may include this header file that also includes , because it conflicts with this file's use of . Furthermore, nothing including this file may include without previously defining WIN32_LEAN_AND_MEAN, because without that macro includes automatically. (see abyss_winsock.h). Copyright information is at the end of the file. ****************************************************************************/ #ifndef XMLRPC_ABYSS_H_INCLUDED #define XMLRPC_ABYSS_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #include #include #include /* XMLRPC_ABYSS_EXPORTED marks a symbol in this file that is exported from libxmlrpc_abyss. XMLRPC_BUILDING_ABYSS says this compilation is part of libxmlrpc_abyss, as opposed to something that _uses_ libxmlrpc_abyss. */ #ifdef XMLRPC_BUILDING_ABYSS #define XMLRPC_ABYSS_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_ABYSS_EXPORTED #endif /**************************************************************************** STUFF FOR THE OUTER CONTROL PROGRAM TO USE ****************************************************************************/ typedef int abyss_bool; /**************************************************************************** GLOBAL (STATIC) PROGRAM STUFF ****************************************************************************/ XMLRPC_ABYSS_EXPORTED void AbyssInit(const char ** const errorP); XMLRPC_ABYSS_EXPORTED void AbyssTerm(void); /********************************************************************* ** MIMEType *********************************************************************/ typedef struct MIMEType MIMEType; XMLRPC_ABYSS_EXPORTED MIMEType * MIMETypeCreate(void); XMLRPC_ABYSS_EXPORTED void MIMETypeDestroy(MIMEType * const MIMETypeP); XMLRPC_ABYSS_EXPORTED void MIMETypeInit(void); XMLRPC_ABYSS_EXPORTED void MIMETypeTerm(void); XMLRPC_ABYSS_EXPORTED abyss_bool MIMETypeAdd2(MIMEType * const MIMETypeP, const char * const type, const char * const ext); XMLRPC_ABYSS_EXPORTED abyss_bool MIMETypeAdd(const char * const type, const char * const ext); enum abyss_foreback {ABYSS_FOREGROUND, ABYSS_BACKGROUND}; #define HAVE_CHANSWITCH typedef struct _TChanSwitch TChanSwitch; typedef struct _TChannel TChannel; typedef struct _TSocket TSocket; #ifdef _WIN32 #include #else #include #endif XMLRPC_ABYSS_EXPORTED void ChanSwitchInit(const char ** const errorP); XMLRPC_ABYSS_EXPORTED void ChanSwitchTerm(void); /* If you're wondering where the constructors for TChanSwitch, TChannel, and TSocket are: They're implementation-specific, so look in abyss_unixsock.h, etc. */ XMLRPC_ABYSS_EXPORTED void ChanSwitchDestroy(TChanSwitch * const chanSwitchP); XMLRPC_ABYSS_EXPORTED void ChannelInit(const char ** const errorP); XMLRPC_ABYSS_EXPORTED void ChannelTerm(void); XMLRPC_ABYSS_EXPORTED void ChannelDestroy(TChannel * const channelP); XMLRPC_ABYSS_EXPORTED void SocketDestroy(TSocket * const socketP); typedef struct { /* Before Xmlrpc-c 1.04, the internal server representation, struct _TServer, was exposed to users and was the only way to set certain parameters of the server. Now, use the (new) ServerSet...() functions. Use the HAVE_ macros to determine which method you have to use. */ struct _TServer * srvP; } TServer; typedef struct _TSession TSession; XMLRPC_ABYSS_EXPORTED abyss_bool ServerCreate(TServer * const serverP, const char * const name, xmlrpc_uint16_t const port, const char * const filespath, const char * const logfilename); XMLRPC_ABYSS_EXPORTED void ServerCreateSwitch(TServer * const serverP, TChanSwitch * const chanSwitchP, const char ** const errorP); XMLRPC_ABYSS_EXPORTED abyss_bool ServerCreateSocket(TServer * const serverP, const char * const name, TOsSocket const socketFd, const char * const filespath, const char * const logfilename); #define HAVE_SERVER_CREATE_SOCKET_2 XMLRPC_ABYSS_EXPORTED void ServerCreateSocket2(TServer * const serverP, TSocket * const socketP, const char ** const errorP); XMLRPC_ABYSS_EXPORTED abyss_bool ServerCreateNoAccept(TServer * const serverP, const char * const name, const char * const filespath, const char * const logfilename); XMLRPC_ABYSS_EXPORTED void ServerFree(TServer * const serverP); XMLRPC_ABYSS_EXPORTED void ServerSetName(TServer * const serverP, const char * const name); XMLRPC_ABYSS_EXPORTED void ServerSetFilesPath(TServer * const serverP, const char * const filesPath); XMLRPC_ABYSS_EXPORTED void ServerSetLogFileName(TServer * const serverP, const char * const logFileName); #define HAVE_SERVER_SET_KEEPALIVE_TIMEOUT 1 XMLRPC_ABYSS_EXPORTED void ServerSetKeepaliveTimeout(TServer * const serverP, xmlrpc_uint32_t const keepaliveTimeout); #define HAVE_SERVER_SET_KEEPALIVE_MAX_CONN 1 XMLRPC_ABYSS_EXPORTED void ServerSetKeepaliveMaxConn(TServer * const serverP, xmlrpc_uint32_t const keepaliveMaxConn); #define HAVE_SERVER_SET_TIMEOUT 1 XMLRPC_ABYSS_EXPORTED void ServerSetTimeout(TServer * const serverP, xmlrpc_uint32_t const timeout); #define HAVE_SERVER_SET_ADVERTISE 1 XMLRPC_ABYSS_EXPORTED void ServerSetAdvertise(TServer * const serverP, abyss_bool const advertise); #define HAVE_SERVER_SET_MIME_TYPE 1 XMLRPC_ABYSS_EXPORTED void ServerSetMimeType(TServer * const serverP, MIMEType * const MIMETypeP); #define HAVE_SERVER_SET_MAX_CONN 1 XMLRPC_ABYSS_EXPORTED void ServerSetMaxConn(TServer * const serverP, unsigned int const maxConn); #define HAVE_SERVER_SET_MAX_CONN_BACKLOG 1 XMLRPC_ABYSS_EXPORTED void ServerSetMaxConnBacklog(TServer * const serverP, unsigned int const maxConnBacklog); XMLRPC_ABYSS_EXPORTED void ServerInit2(TServer * const serverP, const char ** const errorP); XMLRPC_ABYSS_EXPORTED void ServerInit(TServer * const serverP); XMLRPC_ABYSS_EXPORTED void ServerRun(TServer * const serverP); XMLRPC_ABYSS_EXPORTED void ServerRunOnce(TServer * const serverP); /* ServerRunOnce2() is obsolete. See user's guide. */ XMLRPC_ABYSS_EXPORTED void ServerRunOnce2(TServer * const serverP, enum abyss_foreback const foregroundBackground); XMLRPC_ABYSS_EXPORTED void ServerRunChannel(TServer * const serverP, TChannel * const channelP, void * const channelInfoP, const char ** const errorP); #define HAVE_SERVER_RUN_CONN_2 XMLRPC_ABYSS_EXPORTED void ServerRunConn2(TServer * const serverP, TSocket * const connectedSocketP, const char ** const errorP); XMLRPC_ABYSS_EXPORTED void ServerRunConn(TServer * const serverP, TOsSocket const connectedSocket); XMLRPC_ABYSS_EXPORTED void ServerDaemonize(TServer * const serverP); XMLRPC_ABYSS_EXPORTED void ServerTerminate(TServer * const serverP); XMLRPC_ABYSS_EXPORTED void ServerResetTerminate(TServer * const serverP); XMLRPC_ABYSS_EXPORTED void ServerUseSigchld(TServer * const serverP); #ifndef _WIN32 void ServerHandleSigchld(pid_t const pid); #endif typedef abyss_bool (*URIHandler) (TSession *); /* deprecated */ struct URIHandler2; typedef void (*initHandlerFn)(struct URIHandler2 *, abyss_bool *); typedef void (*termHandlerFn)(void *); typedef void (*handleReq3Fn)(void *, TSession *, abyss_bool *); typedef void (*handleReq2Fn)(struct URIHandler2 *, TSession *, abyss_bool *); struct ServerReqHandler3 { termHandlerFn term; handleReq3Fn handleReq; void * userdata; size_t handleReqStackSize; /* zero = default */ }; XMLRPC_ABYSS_EXPORTED void ServerAddHandler3(TServer * const serverP, const struct ServerReqHandler3 * const handlerP, abyss_bool * const successP); typedef struct URIHandler2 { initHandlerFn init; termHandlerFn term; handleReq2Fn handleReq2; URIHandler handleReq1; /* deprecated */ void * userdata; } URIHandler2; XMLRPC_ABYSS_EXPORTED void ServerAddHandler2(TServer * const srvP, URIHandler2 * const handlerP, abyss_bool * const successP); XMLRPC_ABYSS_EXPORTED abyss_bool ServerAddHandler(TServer * const srvP, URIHandler const handler); typedef abyss_bool (*THandlerDflt) (TSession *); /* Note: 'handler' used to be URIHandler; THandlerDflt is a newer name for the same type */ XMLRPC_ABYSS_EXPORTED void ServerDefaultHandler(TServer * const srvP, THandlerDflt const handler); /* ConfReadServerFile() is inappropriately named; it was a mistake. But then, so is having this function at all. The config file is inappropriate for an API. */ XMLRPC_ABYSS_EXPORTED abyss_bool ConfReadServerFile(const char * const filename, TServer * const srvP); XMLRPC_ABYSS_EXPORTED void LogWrite(TServer * const srvP, const char * const c); /**************************************************************************** STUFF FOR HTTP REQUEST HANDLERS TO USE ****************************************************************************/ typedef enum { m_unknown, m_get, m_put, m_head, m_post, m_delete, m_trace, m_options } TMethod; typedef struct { TMethod method; const char * uri; /* This is NOT the URI. It is the pathname part of the URI. We really should fix that and put the pathname in another member. If the URI does not contain a pathname, this is "*". */ const char * query; /* The query part of the URI (stuff after '?'). NULL if none. */ const char * host; /* NOT the value of the host: header field. Rather, the name of the target host (could be part of the host: value; could be from the URI). No port number. NULL if request does not specify a host name. */ const char * from; const char * useragent; const char * referer; const char * requestline; const char * user; /* Requesting user (from authorization: header field). NULL if request doesn't specify or handler has not authenticated it. */ xmlrpc_uint16_t port; /* The port number from the URI, or default 80 if the URI doesn't specify a port. */ abyss_bool keepalive; } TRequestInfo; XMLRPC_ABYSS_EXPORTED abyss_bool SessionRefillBuffer(TSession * const sessionP); XMLRPC_ABYSS_EXPORTED size_t SessionReadDataAvail(TSession * const sessionP); XMLRPC_ABYSS_EXPORTED void SessionGetReadData(TSession * const sessionP, size_t const max, const char ** const outStartP, size_t * const outLenP); XMLRPC_ABYSS_EXPORTED void SessionGetRequestInfo(TSession * const sessionP, const TRequestInfo ** const requestInfoPP); XMLRPC_ABYSS_EXPORTED void SessionGetChannelInfo(TSession * const sessionP, void ** const channelInfoPP); XMLRPC_ABYSS_EXPORTED void * SessionGetDefaultHandlerCtx(TSession * const sessionP); XMLRPC_ABYSS_EXPORTED char * RequestHeaderValue(TSession * const sessionP, const char * const name); XMLRPC_ABYSS_EXPORTED abyss_bool RequestAuth(TSession * const sessionP, const char * const credential, const char * const user, const char * const pass); XMLRPC_ABYSS_EXPORTED abyss_bool ResponseAddField(TSession * const sessionP, const char * const name, const char * const value); XMLRPC_ABYSS_EXPORTED void ResponseWriteStart(TSession * const sessionP); /* For backward compatibility: */ #define ResponseWrite ResponseWriteStart XMLRPC_ABYSS_EXPORTED abyss_bool ResponseWriteBody(TSession * const sessionP, const char * const data, xmlrpc_uint32_t const len); XMLRPC_ABYSS_EXPORTED abyss_bool ResponseWriteEnd(TSession * const sessionP); XMLRPC_ABYSS_EXPORTED abyss_bool ResponseChunked(TSession * const sessionP); XMLRPC_ABYSS_EXPORTED xmlrpc_uint16_t ResponseStatusFromErrno(int const errnoArg); XMLRPC_ABYSS_EXPORTED void ResponseStatus(TSession * const sessionP, xmlrpc_uint16_t const code); XMLRPC_ABYSS_EXPORTED void ResponseStatusErrno(TSession * const sessionP); XMLRPC_ABYSS_EXPORTED abyss_bool ResponseContentType(TSession * const serverP, const char * const type); XMLRPC_ABYSS_EXPORTED abyss_bool ResponseContentLength(TSession * const sessionP, xmlrpc_uint64_t const len); typedef struct { /*---------------------------------------------------------------------------- These are parameters to control the HTTP "Access Control" functions. That's where the client asks whether it is OK to send a request that some other server asked the client to send (e.g. a person web browses a page at a.example.com, and it sends a script that executes on the user's computer and tries to perform an XML-RPC RPC on b.example.com. The user's browser first asks b.example.com if it is OK to do an RPC that is really initiated by a.example.com. These parameters tell the server how to respond to such a request. -----------------------------------------------------------------------------*/ const char * allowOrigin; /* This tells what original servers (a.example.com in the example above) are allowed to submit RPCs indirectly to us. The value is a verbatim value for an HTTP Access-Control-Allow-Origin header field (just the value part of the field, not the whole field). "*" therefore means everyone is allowed. "" means no one. NULL means not to say anything about access control to the client. */ abyss_bool expires; /* The permissions herein expire after a certain period from now. 'maxAge' is that period. */ unsigned int maxAge; /* Meaningful only when 'expires' is true. The expiration period in seconds. Zero is valid. */ } ResponseAccessCtl; XMLRPC_ABYSS_EXPORTED void ResponseAccessControl(TSession * const abyssSessionP, ResponseAccessCtl const accessControl); XMLRPC_ABYSS_EXPORTED void ResponseError2(TSession * const sessionP, const char * const explanation); XMLRPC_ABYSS_EXPORTED void ResponseError(TSession * const sessionP); XMLRPC_ABYSS_EXPORTED const char * MIMETypeFromExt(const char * const ext); XMLRPC_ABYSS_EXPORTED const char * MIMETypeFromExt2(MIMEType * const MIMETypeP, const char * const ext); XMLRPC_ABYSS_EXPORTED const char * MIMETypeFromFileName2(MIMEType * const MIMETypeP, const char * const fileName); XMLRPC_ABYSS_EXPORTED const char * MIMETypeFromFileName(const char * const fileName); XMLRPC_ABYSS_EXPORTED const char * MIMETypeGuessFromFile2(MIMEType * const MIMETypeP, const char * const fileName); XMLRPC_ABYSS_EXPORTED const char * MIMETypeGuessFromFile(const char * const filename); /**************************************************************************** STUFF THAT PROBABLY DOESN'T BELONG IN THIS FILE BECAUSE IT IS INTERNAL Some day, we sort this out. ****************************************************************************/ #define CR '\r' #define LF '\n' #define CRLF "\r\n" /********************************************************************* ** Paths and so on... *********************************************************************/ #ifdef _WIN32 #define DEFAULT_ROOT "c:\\abyss" #define DEFAULT_DOCS DEFAULT_ROOT"\\htdocs" #define DEFAULT_CONF_FILE DEFAULT_ROOT"\\conf\\abyss.conf" #define DEFAULT_LOG_FILE DEFAULT_ROOT"\\log\\abyss.log" #else #ifdef __rtems__ #define DEFAULT_ROOT "/abyss" #else #define DEFAULT_ROOT "/usr/local/abyss" #endif #define DEFAULT_DOCS DEFAULT_ROOT"/htdocs" #define DEFAULT_CONF_FILE DEFAULT_ROOT"/conf/abyss.conf" #define DEFAULT_LOG_FILE DEFAULT_ROOT"/log/abyss.log" #endif /********************************************************************* ** General purpose definitions *********************************************************************/ #ifndef NULL #define NULL ((void *)0) #endif /* NULL */ #ifndef TRUE #define TRUE 1 #endif /* TRUE */ #ifndef FALSE #define FALSE 0 #endif /* FALSE */ /********************************************************************* ** Range *********************************************************************/ XMLRPC_ABYSS_EXPORTED abyss_bool RangeDecode(char * const str, xmlrpc_uint64_t const filesize, xmlrpc_uint64_t * const start, xmlrpc_uint64_t * const end); XMLRPC_ABYSS_EXPORTED abyss_bool DateInit(void); /********************************************************************* ** Session *********************************************************************/ XMLRPC_ABYSS_EXPORTED abyss_bool SessionLog(TSession * const s); #ifdef __cplusplus } #endif /***************************************************************************** ** Here is the copyright notice from the Abyss web server project file from ** which this file is derived. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ #endif /* _ABYSS_H_ */ xmlrpc-c-1.33.14/include/xmlrpc-c/abyss_opensslsock.h000066400000000000000000000017111236133176700225060ustar00rootroot00000000000000/* This is just a sub-file for abyss.h */ #include struct abyss_openssl_chaninfo { /* TODO: figure out useful information to put in here. Maybe client IP address and port. Maybe authenticated host name. Maybe authentication level. Maybe a certificate. */ int dummy; }; void ChanSwitchOpensslCreate(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP); void ChanSwitchOpensslCreateFd(int const fd, TChanSwitch ** const chanSwitchPP, const char ** const errorP); void ChannelOpensslCreateSsl(SSL * const sslP, TChannel ** const channelPP, struct abyss_openssl_chaninfo ** const channelInfoPP, const char ** const errorP); xmlrpc-c-1.33.14/include/xmlrpc-c/abyss_unixsock.h000066400000000000000000000034731236133176700220150ustar00rootroot00000000000000/* This is just a sub-file for abyss.h */ #include #include struct abyss_unix_chaninfo { size_t peerAddrLen; struct sockaddr peerAddr; }; void ChanSwitchUnixCreate(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP); void ChanSwitchUnixCreate2(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP); void ChanSwitchUnixCreateIpV6Port(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP); void ChanSwitchUnixCreateFd(int const fd, TChanSwitch ** const chanSwitchPP, const char ** const errorP); void ChannelUnixCreateFd(int const fd, TChannel ** const channelPP, struct abyss_unix_chaninfo ** const channelInfoPP, const char ** const errorP); void ChannelUnixGetPeerName(TChannel * const channelP, struct sockaddr ** const sockaddrPP, size_t * const sockaddrLenP, const char ** const errorP); void SocketUnixCreateFd(int const fd, TSocket ** const socketPP); typedef int TOsSocket; /* TOsSocket is the type of a conventional socket offered by our OS. This is for backward compatibility; everyone should use TChanSwitch and TChannel instead today. */ xmlrpc-c-1.33.14/include/xmlrpc-c/abyss_winsock.h000066400000000000000000000024651236133176700216270ustar00rootroot00000000000000/* This is just a sub-file for abyss.h */ /* See restrictions on including and at the top of abyss.h. */ #include #include struct abyss_win_chaninfo { size_t peerAddrLen; struct sockaddr peerAddr; }; XMLRPC_ABYSS_EXPORTED void ChanSwitchWinCreate2(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP); XMLRPC_ABYSS_EXPORTED void ChanSwitchWinCreate(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP); XMLRPC_ABYSS_EXPORTED void ChanSwitchWinCreateWinsock(SOCKET const winsock, TChanSwitch ** const chanSwitchPP, const char ** const errorP); XMLRPC_ABYSS_EXPORTED void ChannelWinCreateWinsock(SOCKET const fd, TChannel ** const channelPP, struct abyss_win_chaninfo ** const channelInfoPP, const char ** const errorP); typedef SOCKET TOsSocket; xmlrpc-c-1.33.14/include/xmlrpc-c/base.h000066400000000000000000000732711236133176700176660ustar00rootroot00000000000000/* Copyright and license information is at the end of the file */ #ifndef XMLRPC_H_INCLUDED #define XMLRPC_H_INCLUDED #include #include #include #include #include #include /* Defines XMLRPC_HAVE_WCHAR, XMLRPC_INT64, XMLRPC_HAVE_TIMEVAL */ #if XMLRPC_HAVE_WCHAR #include #endif #if XMLRPC_HAVE_TIMEVAL #include #endif #ifdef __cplusplus extern "C" { #endif /* XMLRPC_LIB_EXPORTED marks a symbol in this file that is exported from libxmlrpc. XMLRPC_BUILDING_LIB says this compilation is part of libxmlrpc, as opposed to something that _uses_ libxmlrpc. */ #ifdef XMLRPC_BUILDING_LIB #define XMLRPC_LIB_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_LIB_EXPORTED #endif /*========================================================================= ** Global static library initialization **=======================================================================*/ void xmlrpc_init(xmlrpc_env * const envP); void xmlrpc_term(void); /*========================================================================= ** Version of libxmlrpc **=======================================================================*/ /* These are for backward compatibility -- they can't be exported from a Windows DLL. xmlrpc_server_version() is preferred. */ extern unsigned int const xmlrpc_version_major; extern unsigned int const xmlrpc_version_minor; extern unsigned int const xmlrpc_version_point; XMLRPC_LIB_EXPORTED void xmlrpc_version(unsigned int * const majorP, unsigned int * const minorP, unsigned int * const pointP); /*========================================================================= ** C types equivalent to XML-RPC types **=======================================================================*/ /* We define names for these types, because they may change from platform to platform. */ typedef signed int xmlrpc_int; /* An integer of the type defined by XML-RPC ; i.e. 32 bit */ typedef XMLRPC_INT32 xmlrpc_int32; /* An integer of the type defined by XML-RPC ; i.e. 32 bit */ typedef XMLRPC_INT64 xmlrpc_int64; /* An integer of the type defined by "XML-RPC" ; i.e. 64 bit */ typedef int xmlrpc_bool; /* A boolean (of the type defined by XML-RPC , but there's really only one kind) */ typedef double xmlrpc_double; /* A double precision floating point number as defined by XML-RPC . But the C "double" type is universally the same, so it's probably clearer just to use that. This typedef is here for mathematical completeness. */ typedef struct { /* A datetime of the type defined by XML-RPC with a few extensions. I.e. in the range 1-9999 AD with microsecond resolution. */ unsigned int Y; /* 1-? */ unsigned int M; /* 1-12 */ unsigned int D; /* 1-31 */ unsigned int h; /* 0-23 */ unsigned int m; /* 0-59 */ unsigned int s; /* 0-59 */ unsigned int u; /* 0-999999 */ } xmlrpc_datetime; /* xmlrpc_socket is just for backward compatibility, in case someone decided to use this in user code. New code should use the native type for a socket (e.g. int or SOCKET). (We stopped using this because for winsock users, we would have to #include in every file that #includes and we don't want that). */ typedef int xmlrpc_socket; #define XMLRPC_INT32_MAX 0x7fffffff #define XMLRPC_INT32_MIN (-XMLRPC_INT32_MAX - 1) #define XMLRPC_INT64_MAX 0x7fffffffffffffffll #define XMLRPC_INT64_MIN (-XMLRPC_INT64_MAX - 1) /*========================================================================= ** xmlrpc_value **========================================================================= ** An XML-RPC value (of any type). */ typedef enum { XMLRPC_TYPE_INT = 0, XMLRPC_TYPE_BOOL = 1, XMLRPC_TYPE_DOUBLE = 2, XMLRPC_TYPE_DATETIME = 3, XMLRPC_TYPE_STRING = 4, XMLRPC_TYPE_BASE64 = 5, XMLRPC_TYPE_ARRAY = 6, XMLRPC_TYPE_STRUCT = 7, XMLRPC_TYPE_C_PTR = 8, XMLRPC_TYPE_NIL = 9, XMLRPC_TYPE_I8 = 10, XMLRPC_TYPE_DEAD = 0xDEAD } xmlrpc_type; #define XMLRPC_HAVE_I8 1 typedef struct _xmlrpc_value xmlrpc_value; XMLRPC_LIB_EXPORTED const char * xmlrpc_type_name(xmlrpc_type const type); XMLRPC_LIB_EXPORTED void xmlrpc_abort_if_array_bad(xmlrpc_value * const arrayP); #define XMLRPC_ASSERT_ARRAY_OK(val) \ xmlrpc_abort_if_array_bad(val) /* Increment the reference count of an xmlrpc_value. */ XMLRPC_LIB_EXPORTED extern void xmlrpc_INCREF(xmlrpc_value* const value); /* Decrement the reference count of an xmlrpc_value. If there ** are no more references, free it. */ XMLRPC_LIB_EXPORTED extern void xmlrpc_DECREF(xmlrpc_value* const value); /* Get the type of an XML-RPC value. */ XMLRPC_LIB_EXPORTED extern xmlrpc_type xmlrpc_value_type (xmlrpc_value* const value); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_int_new(xmlrpc_env * const envP, int const intValue); XMLRPC_LIB_EXPORTED void xmlrpc_read_int(xmlrpc_env * const envP, const xmlrpc_value * const valueP, int * const intValueP); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_i8_new(xmlrpc_env * const envP, xmlrpc_int64 const value); XMLRPC_LIB_EXPORTED void xmlrpc_read_i8(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_int64 * const intValueP); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_bool_new(xmlrpc_env * const envP, xmlrpc_bool const boolValue); XMLRPC_LIB_EXPORTED void xmlrpc_read_bool(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_bool * const boolValueP); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_double_new(xmlrpc_env * const envP, double const doubleValue); XMLRPC_LIB_EXPORTED void xmlrpc_read_double(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_double * const doubleValueP); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_datetime_new(xmlrpc_env * const envP, xmlrpc_datetime const dt); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_datetime_new_str(xmlrpc_env * const envP, const char * const value); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_datetime_new_sec(xmlrpc_env * const envP, time_t const value); XMLRPC_LIB_EXPORTED xmlrpc_value* xmlrpc_datetime_new_usec(xmlrpc_env * const envP, time_t const secs, unsigned int const usecs); #if XMLRPC_HAVE_TIMEVAL XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_datetime_new_timeval(xmlrpc_env * const envP, struct timeval const value); #endif #if XMLRPC_HAVE_TIMESPEC XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_datetime_new_timespec(xmlrpc_env * const envP, struct timespec const value); #endif void XMLRPC_LIB_EXPORTED xmlrpc_read_datetime(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_datetime * const dtP); XMLRPC_LIB_EXPORTED void xmlrpc_read_datetime_sec(xmlrpc_env * const envP, const xmlrpc_value * const valueP, time_t * const timeValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_datetime_usec(xmlrpc_env * const envP, const xmlrpc_value * const valueP, time_t * const secsP, unsigned int * const usecsP); #if XMLRPC_HAVE_TIMEVAL XMLRPC_LIB_EXPORTED void xmlrpc_read_datetime_timeval(xmlrpc_env * const envP, const xmlrpc_value * const valueP, struct timeval * const timeValueP); #endif #if XMLRPC_HAVE_TIMESPEC XMLRPC_LIB_EXPORTED void xmlrpc_read_datetime_timespec(xmlrpc_env * const envP, const xmlrpc_value * const valueP, struct timespec * const timeValueP); #endif void XMLRPC_LIB_EXPORTED xmlrpc_read_datetime_8601(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const iso8601ValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_datetime_str(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_new(xmlrpc_env * const envP, const char * const stringValue); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_new_lp(xmlrpc_env * const envP, size_t const length, const char * const stringValue); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_new_va(xmlrpc_env * const envP, const char * const format, va_list args); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_new_f(xmlrpc_env * const envP, const char * const format, ...); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_new_lp_cr(xmlrpc_env * const envP, size_t const length, const char * const value); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_new_cr(xmlrpc_env * const envP, const char * const value); XMLRPC_LIB_EXPORTED void xmlrpc_read_string(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_string_crlf(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_string_lp_crlf(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const char ** const stringValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_string_lp(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const char ** const stringValueP); #if XMLRPC_HAVE_WCHAR XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_w_new(xmlrpc_env * const envP, const wchar_t * const stringValue); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_w_new_lp(xmlrpc_env * const envP, size_t const length, const wchar_t * const stringValue); XMLRPC_LIB_EXPORTED void xmlrpc_read_string_w(xmlrpc_env * const envP, xmlrpc_value * const valueP, const wchar_t ** const stringValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_string_w_crlf(xmlrpc_env * const envP, xmlrpc_value * const valueP, const wchar_t ** const stringValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_string_w_lp(xmlrpc_env * const envP, xmlrpc_value * const valueP, size_t * const lengthP, const wchar_t ** const stringValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_string_w_lp_crlf(xmlrpc_env * const envP, xmlrpc_value * const valueP, size_t * const lengthP, const wchar_t ** const stringValueP); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_w_new_lp_cr(xmlrpc_env * const envP, size_t const length, const wchar_t * const value); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_string_w_new_cr(xmlrpc_env * const envP, const wchar_t * const value); #endif /* XMLRPC_HAVE_WCHAR */ XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_base64_new(xmlrpc_env * const envP, size_t const length, const unsigned char * const value); XMLRPC_LIB_EXPORTED void xmlrpc_read_base64(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const unsigned char ** const bytestringValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_base64_size(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_array_new(xmlrpc_env * const envP); /* Return the number of elements in an XML-RPC array. ** Sets XMLRPC_TYPE_ERROR if 'array' is not an array. */ XMLRPC_LIB_EXPORTED int xmlrpc_array_size(xmlrpc_env * const env, const xmlrpc_value * const array); XMLRPC_LIB_EXPORTED void xmlrpc_array_append_item(xmlrpc_env * const envP, xmlrpc_value * const arrayP, xmlrpc_value * const valueP); XMLRPC_LIB_EXPORTED void xmlrpc_array_read_item(xmlrpc_env * const envP, const xmlrpc_value * const arrayP, unsigned int const index, xmlrpc_value ** const valuePP); /* Deprecated. Use xmlrpc_array_read_item() instead. Get an item from an XML-RPC array. Does not increment the reference count of the returned value. Sets XMLRPC_TYPE_ERROR if 'array' is not an array. Sets XMLRPC_INDEX_ERROR if 'index' is out of bounds. */ XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_array_get_item(xmlrpc_env * const envP, const xmlrpc_value * const arrayP, int const index); /* Not implemented--we don't need it yet. XMLRPC_LIB_EXPORTED int xmlrpc_array_set_item(xmlrpc_env * const envP, xmlrpc_value * const arrayP, unsigned int const index, xmlrpc_value * const valueP); */ XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_struct_new(xmlrpc_env * const env); /* Return the number of key/value pairs in a struct. ** Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. */ XMLRPC_LIB_EXPORTED int xmlrpc_struct_size (xmlrpc_env * const env, xmlrpc_value * const strct); /* Returns true iff 'strct' contains 'key'. ** Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. */ XMLRPC_LIB_EXPORTED int xmlrpc_struct_has_key(xmlrpc_env * const envP, xmlrpc_value * const strctP, const char * const key); /* The same as the above, but the key may contain zero bytes. Deprecated. xmlrpc_struct_get_value_v() is more general, and this case is not common enough to warrant a shortcut. */ XMLRPC_LIB_EXPORTED int xmlrpc_struct_has_key_n(xmlrpc_env * const envP, xmlrpc_value * const strctP, const char * const key, size_t const key_len); #if 0 /* Not implemented yet, but needed for completeness. */ XMLRPC_LIB_EXPORTED int xmlrpc_struct_has_key_v(xmlrpc_env * env, xmlrpc_value * strct, xmlrpc_value * const keyval); #endif XMLRPC_LIB_EXPORTED void xmlrpc_struct_find_value(xmlrpc_env * const envP, xmlrpc_value * const structP, const char * const key, xmlrpc_value ** const valuePP); XMLRPC_LIB_EXPORTED void xmlrpc_struct_find_value_v(xmlrpc_env * const envP, xmlrpc_value * const structP, xmlrpc_value * const keyP, xmlrpc_value ** const valuePP); XMLRPC_LIB_EXPORTED void xmlrpc_struct_read_value(xmlrpc_env * const envP, xmlrpc_value * const structP, const char * const key, xmlrpc_value ** const valuePP); XMLRPC_LIB_EXPORTED void xmlrpc_struct_read_value_v(xmlrpc_env * const envP, xmlrpc_value * const structP, xmlrpc_value * const keyP, xmlrpc_value ** const valuePP); /* The "get_value" functions are deprecated. Use the "find_value" and "read_value" functions instead. */ XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_struct_get_value(xmlrpc_env * const envP, xmlrpc_value * const strctP, const char * const key); /* The same as above, but the key may contain zero bytes. Deprecated. xmlrpc_struct_get_value_v() is more general, and this case is not common enough to warrant a shortcut. */ XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_struct_get_value_n(xmlrpc_env * const envP, xmlrpc_value * const strctP, const char * const key, size_t const key_len); /* Set the value associated with 'key' in 'strct' to 'value'. Sets XMLRPC_TYPE_ERROR if 'strct' is not a struct. */ XMLRPC_LIB_EXPORTED void xmlrpc_struct_set_value(xmlrpc_env * const env, xmlrpc_value * const strct, const char * const key, xmlrpc_value * const value); /* The same as above, but the key may contain zero bytes. Deprecated. The general way to set a structure value is xmlrpc_struct_set_value_v(), and this case is not common enough to deserve a shortcut. */ XMLRPC_LIB_EXPORTED void xmlrpc_struct_set_value_n(xmlrpc_env * const env, xmlrpc_value * const strct, const char * const key, size_t const key_len, xmlrpc_value * const value); /* The same as above, but the key must be an XML-RPC string. ** Fails with XMLRPC_TYPE_ERROR if 'keyval' is not a string. */ XMLRPC_LIB_EXPORTED void xmlrpc_struct_set_value_v(xmlrpc_env * const env, xmlrpc_value * const strct, xmlrpc_value * const keyval, xmlrpc_value * const value); /* Given a zero-based index, return the matching key and value. This ** is normally used in conjunction with xmlrpc_struct_size. ** Fails with XMLRPC_TYPE_ERROR if 'struct' is not a struct. ** Fails with XMLRPC_INDEX_ERROR if 'index' is out of bounds. */ XMLRPC_LIB_EXPORTED void xmlrpc_struct_read_member(xmlrpc_env * const envP, xmlrpc_value * const structP, unsigned int const index, xmlrpc_value ** const keyvalP, xmlrpc_value ** const valueP); /* The same as above, but does not increment the reference count of the two values it returns, and return NULL for both if it fails, and takes a signed integer for the index (but fails if it is negative). Deprecated. Use xmlrpc_struct_read_member() instead. */ XMLRPC_LIB_EXPORTED void xmlrpc_struct_get_key_and_value(xmlrpc_env * const env, xmlrpc_value * const strct, int const index, xmlrpc_value ** const out_keyval, xmlrpc_value ** const out_value); /* The "C pointer" type has no relation to XML-RPC. It is here for the convenience of programs that use xmlrpc_value for XML-RPC purposes and can benefit from using it for non-XML-RPC purposes as well. Also, some people use libxmlrpc for xmlrpc_value alone, because sometimes you need to work with basic data types in richer ways than the C types (int, time_t, etc) allow. */ XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_cptr_new(xmlrpc_env * const envP, void * const value); typedef void (*xmlrpc_cptr_dtor_fn)(void *, void *); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_cptr_new_dtor(xmlrpc_env * const envP, void * const value, xmlrpc_cptr_dtor_fn const dtor, void * const dtorContext); XMLRPC_LIB_EXPORTED void xmlrpc_read_cptr(xmlrpc_env * const envP, const xmlrpc_value * const valueP, void ** const ptrValueP); XMLRPC_LIB_EXPORTED void xmlrpc_read_nil(xmlrpc_env * const envP, xmlrpc_value * const valueP); XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_nil_new(xmlrpc_env * const envP); /* Build an xmlrpc_value from a format string. */ XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_build_value(xmlrpc_env * const env, const char * const format, ...); /* The same as the above, but using a va_list and more general */ XMLRPC_LIB_EXPORTED void xmlrpc_build_value_va(xmlrpc_env * const env, const char * const format, va_list const args, xmlrpc_value ** const valPP, const char ** const tailP); XMLRPC_LIB_EXPORTED void xmlrpc_decompose_value(xmlrpc_env * const envP, xmlrpc_value * const value, const char * const format, ...); XMLRPC_LIB_EXPORTED void xmlrpc_decompose_value_va(xmlrpc_env * const envP, xmlrpc_value * const value, const char * const format, va_list const args); /* xmlrpc_parse_value... is the same as xmlrpc_decompose_value... except that it doesn't do proper memory management -- it returns xmlrpc_value's without incrementing the reference count and returns pointers to data inside an xmlrpc_value structure. These are deprecated. Use xmlrpc_decompose_value... instead. */ XMLRPC_LIB_EXPORTED void xmlrpc_parse_value(xmlrpc_env * const envP, xmlrpc_value * const value, const char * const format, ...); /* The same as the above, but using a va_list. */ XMLRPC_LIB_EXPORTED void xmlrpc_parse_value_va(xmlrpc_env * const envP, xmlrpc_value * const value, const char * const format, va_list const args); /*========================================================================= ** Encoding XML **=======================================================================*/ typedef enum xmlrpc_dialect { xmlrpc_dialect_i8, xmlrpc_dialect_apache } xmlrpc_dialect; XMLRPC_LIB_EXPORTED void xmlrpc_serialize_value2(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP, xmlrpc_dialect const dialect); XMLRPC_LIB_EXPORTED void xmlrpc_serialize_value(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP); XMLRPC_LIB_EXPORTED void xmlrpc_serialize_params2(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const paramArrayP, xmlrpc_dialect const dialect); XMLRPC_LIB_EXPORTED void xmlrpc_serialize_params(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const paramArrayP); XMLRPC_LIB_EXPORTED void xmlrpc_serialize_call2(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_dialect const dialect); XMLRPC_LIB_EXPORTED void xmlrpc_serialize_call(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const char * const methodName, xmlrpc_value * const paramArrayP); XMLRPC_LIB_EXPORTED void xmlrpc_serialize_response2(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP, xmlrpc_dialect const dialect); XMLRPC_LIB_EXPORTED void xmlrpc_serialize_response(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP); XMLRPC_LIB_EXPORTED void xmlrpc_serialize_fault(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const xmlrpc_env * const faultP); /*========================================================================= ** Decoding XML **=======================================================================*/ XMLRPC_LIB_EXPORTED void xmlrpc_parse_value_xml(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xmlrpc_value ** const valuePP); XMLRPC_LIB_EXPORTED void xmlrpc_parse_call(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, const char ** const methodNameP, xmlrpc_value ** const paramArrayPP); XMLRPC_LIB_EXPORTED void xmlrpc_parse_response2(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xmlrpc_value ** const resultPP, int * const faultCodeP, const char ** const faultStringP); /* xmlrpc_parse_response() is for backward compatibility */ XMLRPC_LIB_EXPORTED xmlrpc_value * xmlrpc_parse_response(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen); /*========================================================================= ** Authorization Cookie Handling **========================================================================= ** Routines to get and set values for authorizing via authorization ** cookies. Both the client and server use HTTP_COOKIE_AUTH to store ** the representation of the authorization value, which is actually ** just a base64 hash of username:password. (This entire method is ** a cookie replacement of basic authentication.) **/ XMLRPC_LIB_EXPORTED extern void xmlrpc_authcookie_set(xmlrpc_env * const env, const char * const username, const char * const password); XMLRPC_LIB_EXPORTED char *xmlrpc_authcookie(void); /*========================================================================= Resource Limits Ideally, there would be enough resource limits to ensure that XML-RPC partners cannot cause libxmlrpc objects and routines to use more resource than is available for them (either by accident or malice). We have a long way to go to get there. =========================================================================*/ /* These functions are _not_ re-entrant and the limits are per-process (i.e. their values live in static global variables). */ /* Limit IDs. There will be more of these as time goes on. */ #define XMLRPC_NESTING_LIMIT_ID (0) #define XMLRPC_XML_SIZE_LIMIT_ID (1) #define XMLRPC_LAST_LIMIT_ID (XMLRPC_XML_SIZE_LIMIT_ID) /* By default, deserialized data may be no more than 64 levels deep. */ #define XMLRPC_NESTING_LIMIT_DEFAULT (64) /* By default, XML data from the network may be no larger than 512K. ** Some client and server modules may fail to enforce this properly. */ #define XMLRPC_XML_SIZE_LIMIT_DEFAULT (512*1024) /* Set a specific limit to the specified value. */ XMLRPC_LIB_EXPORTED extern void xmlrpc_limit_set (int const limit_id, size_t const value); /* Get the value of a specified limit. */ XMLRPC_LIB_EXPORTED extern size_t xmlrpc_limit_get (int const limit_id); #ifdef __cplusplus } #endif /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #endif xmlrpc-c-1.33.14/include/xmlrpc-c/base.hpp000066400000000000000000000361261236133176700202240ustar00rootroot00000000000000#ifndef XMLRPC_BASE_HPP_INCLUDED #define XMLRPC_BASE_HPP_INCLUDED #include #include #include #include #include #include #include #if defined(__GNUC__) && __GNUC__ < 3 #include #else #include #endif #if XMLRPC_HAVE_TIMEVAL #include #endif #include #include /* XMLRPC_LIBPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc++. XMLRPC_BUILDING_LIBPP says this compilation is part of libxmlrpc++, as opposed to something that _uses_ libxmlrpc++. */ #ifdef XMLRPC_BUILDING_LIBPP #define XMLRPC_LIBPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_LIBPP_EXPORTED #endif namespace xmlrpc_c { class XMLRPC_LIBPP_EXPORTED value { // This is a handle. You don't want to create a pointer to this; // it is in fact a pointer itself. public: value(); // This creates a placeholder. It can't be used for anything, but // holds memory. instantiate() can turn it into a real object. value(xmlrpc_c::value const &value); // copy constructor ~value(); enum type_t { // These are designed to be identical to the values for // enum xmlrpc_type in the C library. TYPE_INT = 0, TYPE_BOOLEAN = 1, TYPE_DOUBLE = 2, TYPE_DATETIME = 3, TYPE_STRING = 4, TYPE_BYTESTRING = 5, TYPE_ARRAY = 6, TYPE_STRUCT = 7, TYPE_C_PTR = 8, TYPE_NIL = 9, TYPE_I8 = 10, TYPE_DEAD = 0xDEAD }; type_t type() const; xmlrpc_c::value& operator=(xmlrpc_c::value const&); bool isInstantiated() const; // The following are not meant to be public to users, but just to // other Xmlrpc-c library modules. If we ever go to a pure C++ // implementation, not based on C xmlrpc_value objects, this shouldn't // be necessary. void appendToCArray(xmlrpc_value * const arrayP) const; void addToCStruct(xmlrpc_value * const structP, std::string const key) const; xmlrpc_value * cValue() const; // Not to be confused with public 'cvalue' method that all the derived // classes have. value(xmlrpc_value * const valueP); void instantiate(xmlrpc_value * const valueP); // Works only on a placeholder object created by the no-argument // constructor. xmlrpc_value * cValueP; // NULL means this is merely a placeholder object. protected: void validateInstantiated() const; }; std::ostream& operator<<(std::ostream& out, xmlrpc_c::value::type_t const& type); class XMLRPC_LIBPP_EXPORTED value_int : public value { public: value_int(int const cvalue); value_int(xmlrpc_c::value const baseValue); operator int() const; int cvalue() const; }; class XMLRPC_LIBPP_EXPORTED value_boolean : public value { public: value_boolean(bool const cvalue); value_boolean(xmlrpc_c::value const baseValue); operator bool() const; bool cvalue() const; }; class XMLRPC_LIBPP_EXPORTED value_string : public value { public: enum nlCode {nlCode_all, nlCode_lf}; value_string(std::string const& cppvalue, nlCode const nlCode); value_string(std::string const& cppvalue); value_string(xmlrpc_c::value const baseValue); std::string crlfValue() const; operator std::string() const; std::string cvalue() const; }; class XMLRPC_LIBPP_EXPORTED value_double : public value { public: value_double(double const cvalue); value_double(xmlrpc_c::value const baseValue); operator double() const; double cvalue() const; }; class XMLRPC_LIBPP_EXPORTED value_datetime : public value { public: value_datetime(std::string const cvalue); value_datetime(xmlrpc_datetime const cvalue); operator xmlrpc_datetime() const; value_datetime(time_t const cvalue); operator time_t() const; #if XMLRPC_HAVE_TIMEVAL value_datetime(struct timeval const& cvalue); operator timeval() const; #endif #if XMLRPC_HAVE_TIMESPEC value_datetime(struct timespec const& cvalue); operator timespec() const; #endif value_datetime(xmlrpc_c::value const baseValue); time_t cvalue() const; std::string iso8601Value() const; }; typedef std::vector cbytestring; class XMLRPC_LIBPP_EXPORTED value_bytestring : public value { public: value_bytestring(cbytestring const& cvalue); value_bytestring(xmlrpc_c::value const baseValue); // You can't cast to a vector because the compiler can't tell which // constructor to use (complains about ambiguity). So we have this: cbytestring vectorUcharValue() const; cbytestring cvalue() const; size_t length() const; }; typedef std::map cstruct; class XMLRPC_LIBPP_EXPORTED value_struct : public value { public: value_struct(cstruct const& cvalue); value_struct(xmlrpc_c::value const baseValue); operator cstruct() const; cstruct cvalue() const; }; typedef std::vector carray; class XMLRPC_LIBPP_EXPORTED value_array : public value { public: value_array(carray const& cvalue); value_array(xmlrpc_c::value const baseValue); // You can't cast to a vector because the compiler can't tell which // constructor to use (complains about ambiguity). So we have this: carray vectorValueValue() const; carray cvalue() const; size_t size() const; }; class XMLRPC_LIBPP_EXPORTED value_nil : public value { public: value_nil(); value_nil(xmlrpc_c::value const baseValue); void * cvalue() const; }; class XMLRPC_LIBPP_EXPORTED value_i8 : public value { public: value_i8(xmlrpc_int64 const cvalue); value_i8(xmlrpc_c::value const baseValue); operator xmlrpc_int64() const; xmlrpc_int64 cvalue() const; }; inline xmlrpc_c::value_string toValue(const char * const x) { return xmlrpc_c::value_string(x); } inline xmlrpc_c::value_string toValue(std::string const& x) { return xmlrpc_c::value_string(x); } inline xmlrpc_c::value_int toValue(int const x) { return xmlrpc_c::value_int(x); } inline xmlrpc_c::value_boolean toValue(bool const x) { return xmlrpc_c::value_boolean(x); } inline xmlrpc_c::value_double toValue(double const x) { return xmlrpc_c::value_double(x); } inline xmlrpc_c::value_bytestring toValue(cbytestring const& x) { return xmlrpc_c::value_bytestring(x); } inline const xmlrpc_c::value & toValue(xmlrpc_c::value const& v) { /*---------------------------------------------------------------------------- This does a null conversion; you use it to catch all the XML-RPC types that have no usable C++ equivalent, so you can do a toValue() of any XML-RPC type at all. In particular: 'value_datetime', 'value_nil'. -----------------------------------------------------------------------------*/ return v; } template xmlrpc_c::value_struct toValue(std::map const& in) { /*---------------------------------------------------------------------------- convert C++ map to XML-RPC structure -----------------------------------------------------------------------------*/ cstruct ret; for (typename std::map::const_iterator p = in.begin(); p != in.end(); ++p) { ret[p->first] = toValue(p->second); } return xmlrpc_c::value_struct(ret); } template xmlrpc_c::value_array arrayValueSlice(InputIterator begin, InputIterator end) { /*---------------------------------------------------------------------------- convert C++ iterator pair to XML-RPC array -----------------------------------------------------------------------------*/ carray ret; for (InputIterator p = begin; p != end; ++p) { ret.push_back(toValue(*p)); } return xmlrpc_c::value_array(ret); } template inline xmlrpc_c::value_array toValue(std::vector const& in) { /*---------------------------------------------------------------------------- convert C++ vector to XML-RPC array -----------------------------------------------------------------------------*/ return arrayValueSlice(in.begin(), in.end()); } // fromValue() returns via reference argument instead of by return value // so the compiler can tell which version of it to invoke based on the // desired output type. inline void fromValue(std::string & y, xmlrpc_c::value const& x) { y = xmlrpc_c::value_string(x); } inline void fromValue(int & y, xmlrpc_c::value const& x) { y = xmlrpc_c::value_int(x); } inline void fromValue(bool & y, xmlrpc_c::value const& x) { y = xmlrpc_c::value_boolean(x); } inline void fromValue(double & y, xmlrpc_c::value const& x) { y = xmlrpc_c::value_double(x); } inline void fromValue(cbytestring & y, xmlrpc_c::value const& x) { y = xmlrpc_c::value_bytestring(x).vectorUcharValue(); } inline void fromValue(xmlrpc_c::value & y, xmlrpc_c::value const& x) { /*---------------------------------------------------------------------------- This does a null conversion; it's so you can use fromValue() with an XML-RPC value or C++ value without having to know which it is. One reason you would have an XML-RPC value lying around with C++ values is that some XML-RPC values don't have a common C++ equivalent. -----------------------------------------------------------------------------*/ y = x; } template inline void fromValue(std::map & y, xmlrpc_c::value const& x) { /*---------------------------------------------------------------------------- Convert XML-RPC structure to C++ map. -----------------------------------------------------------------------------*/ cstruct m = xmlrpc_c::value_struct(x); y.clear(); for (std::map::const_iterator p = m.begin(); p != m.end(); ++p) { fromValue(y[p->first], p->second); } } template inline void fromValue(std::vector & y, xmlrpc_c::value const& x) { /*---------------------------------------------------------------------------- Convert XML-RPC array to C++ vector. -----------------------------------------------------------------------------*/ carray v = xmlrpc_c::value_array(x).vectorValueValue(); y.resize(v.size()); for (unsigned int i = 0; i < v.size(); ++i) { fromValue(y[i], v[i]); } } template inline xmlrpc_c::value_array arrayValueArray(const MemberClass * const in, size_t const size) { /*---------------------------------------------------------------------------- convert C++ array to XML-RPC array -----------------------------------------------------------------------------*/ return arrayValueSlice(in, in + size); } class XMLRPC_LIBPP_EXPORTED fault { /*---------------------------------------------------------------------------- This is an XML-RPC fault. This object is not intended to be used to represent a fault in the execution of XML-RPC client/server software -- just a fault in an XML-RPC RPC as described by the XML-RPC spec. There is no way to represent "no fault" with this object. The object is meaningful only in the context of some fault. -----------------------------------------------------------------------------*/ public: enum code_t { CODE_UNSPECIFIED = 0, CODE_INTERNAL = -500, CODE_TYPE = -501, CODE_INDEX = -502, CODE_PARSE = -503, CODE_NETWORK = -504, CODE_TIMEOUT = -505, CODE_NO_SUCH_METHOD = -506, CODE_REQUEST_REFUSED = -507, CODE_INTROSPECTION_DISABLED = -508, CODE_LIMIT_EXCEEDED = -509, CODE_INVALID_UTF8 = -510 }; fault(); fault(std::string const _faultString, xmlrpc_c::fault::code_t const _faultCode = xmlrpc_c::fault::CODE_UNSPECIFIED ); xmlrpc_c::fault::code_t getCode() const; std::string getDescription() const; private: bool valid; xmlrpc_c::fault::code_t code; std::string description; }; class XMLRPC_LIBPP_EXPORTED rpcOutcome { /*---------------------------------------------------------------------------- The outcome of a validly executed RPC -- either an XML-RPC fault or an XML-RPC value of the result. -----------------------------------------------------------------------------*/ public: rpcOutcome(); rpcOutcome(xmlrpc_c::value const result); rpcOutcome(xmlrpc_c::fault const fault); bool succeeded() const; xmlrpc_c::fault getFault() const; xmlrpc_c::value getResult() const; private: bool valid; // This is false in a placeholder variable -- i.e. an object you // create with the no-argument constructor, which is waiting to be // assigned a value. When false, nothing below is valid. bool _succeeded; xmlrpc_c::value result; // valid if 'succeeded' xmlrpc_c::fault fault; // valid if not 'succeeded' }; class XMLRPC_LIBPP_EXPORTED paramList { /*---------------------------------------------------------------------------- A parameter list of an XML-RPC call. -----------------------------------------------------------------------------*/ public: paramList(unsigned int const paramCount = 0); paramList& add(xmlrpc_c::value const param); paramList& addx(xmlrpc_c::value const param); template paramList& addc(const T & x) { xmlrpc_c::paramList::add(toValue(x)); return *this; } unsigned int size() const; xmlrpc_c::value operator[](unsigned int const subscript) const; int getInt(unsigned int const paramNumber, int const minimum = INT_MIN, int const maximum = INT_MAX) const; bool getBoolean(unsigned int const paramNumber) const; double getDouble(unsigned int const paramNumber, double const minimum = -DBL_MAX, double const maximum = DBL_MAX) const; enum timeConstraint {TC_ANY, TC_NO_PAST, TC_NO_FUTURE}; time_t getDatetime_sec(unsigned int const paramNumber, timeConstraint const constraint = paramList::TC_ANY) const; std::string getString(unsigned int const paramNumber) const; cbytestring getBytestring(unsigned int const paramNumber) const; carray getArray(unsigned int const paramNumber, unsigned int const minSize = 0, unsigned int const maxSize = UINT_MAX) const; cstruct getStruct(unsigned int const paramNumber) const; void getNil(unsigned int const paramNumber) const; xmlrpc_int64 getI8(unsigned int const paramNumber, xmlrpc_int64 const minimum = XMLRPC_INT64_MIN, xmlrpc_int64 const maximum = XMLRPC_INT64_MAX) const; void verifyEnd(unsigned int const paramNumber) const; private: std::vector paramVector; }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/base64.hpp000066400000000000000000000015011236133176700203630ustar00rootroot00000000000000#ifndef XMLRPC_BASE64_HPP_INCLUDED #define XMLRPC_BASE64_HPP_INCLUDED #include #include #include /* XMLRPC_LIBPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc++. XMLRPC_BUILDING_LIBPP says this compilation is part of libxmlrpc++, as opposed to something that _uses_ libxmlrpc++. */ #ifdef XMLRPC_BUILDING_LIBPP #define XMLRPC_LIBPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_LIBPP_EXPORTED #endif namespace xmlrpc_c { enum newlineCtl {NEWLINE_NO, NEWLINE_YES}; XMLRPC_LIBPP_EXPORTED std::string base64FromBytes( std::vector const& bytes, xmlrpc_c::newlineCtl const newlineCtl = xmlrpc_c::NEWLINE_YES); XMLRPC_LIBPP_EXPORTED std::vector bytesFromBase64(std::string const& base64); } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/base64_int.h000066400000000000000000000010601236133176700206750ustar00rootroot00000000000000#ifndef BASE64_INT_H_INCLUDED #define BASE64_INT_H_INCLUDED #include "xmlrpc-c/c_util.h" /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif XMLRPC_UTIL_EXPORTED void xmlrpc_base64Encode(const char * const chars, char * const base64); #endif xmlrpc-c-1.33.14/include/xmlrpc-c/base_int.h000066400000000000000000000202631236133176700205310ustar00rootroot00000000000000/*============================================================================ base_int.h ============================================================================== This header file defines the interface between modules inside xmlrpc-c. Use this in addition to xmlrpc.h, which defines the external interface. Copyright information is at the end of the file. ============================================================================*/ #ifndef XMLRPC_C_BASE_INT_H_INCLUDED #define XMLRPC_C_BASE_INT_H_INCLUDED #include "xmlrpc_config.h" #include "bool.h" #include "int.h" #include #include #include #ifdef __cplusplus extern "C" { #endif /* XMLRPC_LIB_EXPORTED marks a symbol in this file that is exported from libxmlrpc. XMLRPC_BUILDING_LIB says this compilation is part of libxmlrpc, as opposed to something that _uses_ libxmlrpc. */ #ifdef XMLRPC_BUILDING_LIB #define XMLRPC_LIBINT_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_LIBINT_EXPORTED #endif struct _xmlrpc_value { xmlrpc_type _type; struct lock * lockP; unsigned int refcount; /* Certain data types store their data directly in the xmlrpc_value. */ union { xmlrpc_int32 i; xmlrpc_int64 i8; xmlrpc_bool b; double d; xmlrpc_datetime dt; /* NOTE: may be invalid! e.g. February 30 */ struct { void * objectP; xmlrpc_cptr_dtor_fn dtor; // NULL if none void * dtorContext; } cptr; } _value; /* Other data types use a memory block. For a string, this is the characters of the lines of the string in UTF-8, with lines delimited by either CR, LF, or CRLF, plus a NUL added to the end. The characters of the lines may be any character representable in UTF-8, even the ones that are not legal XML (XML doesn't allow ASCII control characters except tab, CR, LF). But note that a line can't contain CR or LF because that would form a line delimiter. To disambiguate: CRLF together is always one line delimiter. This format for string is quite convenient because it is also the format of that part of an XML document which is the contents of a element (except of course that for the non-XML characters, we have to stretch the definition of XML). For base64, this is bytes of the byte string, directly. */ xmlrpc_mem_block _block; xmlrpc_mem_block *_wcs_block; /* This is a copy of the string value in _block, but in UTF-16 instead of UTF-8. This member is not always present. If NULL, it is not present. We keep this copy for convenience. The value is totally redundant with _block. This member is always NULL when the data type is not string. This member is always NULL on a system that does not have Unicode wchar functions. */ void * _cache; /* This is a hack to support the old style memory management in which one gets a pointer into memory that belongs to the xmlrpc_value object; i.e. the caller of xmlrpc_read_datetime_str_old() doesn't get memory that he is responsible for freeing. This is essentially a cached value of the result of a xmlrpc_read_datetime_str_old(). NULL means nothing cached. */ }; #define XMLRPC_ASSERT_VALUE_OK(val) \ XMLRPC_ASSERT((val) != NULL && (val)->_type != XMLRPC_TYPE_DEAD) /* A handy type-checking routine. */ #define XMLRPC_TYPE_CHECK(env,v,t) \ do \ if ((v)->_type != (t)) \ XMLRPC_FAIL(env, XMLRPC_TYPE_ERROR, "Expected " #t); \ while (0) typedef struct { uint32_t keyHash; xmlrpc_value * key; xmlrpc_value * value; } _struct_member; XMLRPC_LIBINT_EXPORTED void xmlrpc_createXmlrpcValue(xmlrpc_env * const envP, xmlrpc_value ** const valPP); XMLRPC_LIBINT_EXPORTED const char * xmlrpc_typeName(xmlrpc_type const type); XMLRPC_LIBINT_EXPORTED void xmlrpc_traceXml(const char * const label, const char * const xml, size_t const xmlLength); XMLRPC_LIBINT_EXPORTED void xmlrpc_destroyString(xmlrpc_value * const stringP); XMLRPC_LIBINT_EXPORTED void xmlrpc_destroyDatetime(xmlrpc_value * const datetimeP); XMLRPC_LIBINT_EXPORTED void xmlrpc_destroyStruct(xmlrpc_value * const structP); XMLRPC_LIBINT_EXPORTED void xmlrpc_destroyArrayContents(xmlrpc_value * const arrayP); /*---------------------------------------------------------------------------- The following are for use by the legacy xmlrpc_parse_value(). They don't do proper memory management, so they aren't appropriate for general use, but there are old users that do xmlrpc_parse_value() and compensate for the memory management, so we have to continue to offer this style of memory management. In particular, the functions that return xmlrpc_values don't increment the reference count, and the functions that return strings don't allocate new memory for them. -----------------------------------------------------------------------------*/ XMLRPC_LIBINT_EXPORTED void xmlrpc_read_datetime_str_old(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP); XMLRPC_LIBINT_EXPORTED void xmlrpc_read_string_old(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP); XMLRPC_LIBINT_EXPORTED void xmlrpc_read_string_lp_old(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const char ** const stringValueP); #if XMLRPC_HAVE_WCHAR XMLRPC_LIBINT_EXPORTED void xmlrpc_read_string_w_old(xmlrpc_env * const envP, xmlrpc_value * const valueP, const wchar_t ** const stringValueP); XMLRPC_LIBINT_EXPORTED void xmlrpc_read_string_w_lp_old(xmlrpc_env * const envP, xmlrpc_value * const valueP, size_t * const lengthP, const wchar_t ** const stringValueP); #endif XMLRPC_LIBINT_EXPORTED void xmlrpc_read_base64_old(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const unsigned char ** const byteStringValueP); /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/c_util.h000066400000000000000000000017271236133176700202300ustar00rootroot00000000000000#ifndef XMLRPC_C_C_UTIL_H_INCLUDED #define XMLRPC_C_C_UTIL_H_INCLUDED /* C language stuff. Doesn't involve any libraries that aren't part of the compiler. */ /* XMLRPC_PRINTF_ATTR lets the GNU compiler check printf-type calls to be sure the arguments match the format string, thus preventing runtime segmentation faults and incorrect messages. */ #ifdef __GNUC__ #define XMLRPC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) #define XMLRPC_NORETURN_ATTR __attribute__((noreturn)) #else #define XMLRPC_PRINTF_ATTR(a,b) #define XMLRPC_NORETURN_ATTR #endif /* XMLRPC_DLLEXPORT is an attribute of an external symbol that says it is to be exported from a library that contains it. XMLRPC_BUILD_DLL says the compilation at hand is for use in an Xmlrpc-c DLL. This is meant to be defined via compiler option. */ #if defined(XMLRPC_BUILD_DLL) && defined(_MSC_VER) #define XMLRPC_DLLEXPORT __declspec(dllexport) #else #define XMLRPC_DLLEXPORT #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/client.h000066400000000000000000000375441236133176700202350ustar00rootroot00000000000000/*============================================================================ xmlrpc_client.h ============================================================================== This header file defines the interface between xmlrpc.c and its users, related to clients. Copyright information is at the end of the file. ============================================================================*/ #ifndef XMLRPC_CLIENT_H_INCLUDED #define XMLRPC_CLIENT_H_INCLUDED #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct xmlrpc_client; struct xmlrpc_client_transport; struct xmlrpc_client_transport_ops; #ifndef __cplusplus typedef struct xmlrpc_client xmlrpc_client; typedef struct xmlrpc_client_transport xmlrpc_client_transport; typedef struct xmlrpc_client_transport_ops xmlrpc_client_transport_ops; #endif /* XMLRPC_CLIENT_EXPORTED marks a symbol in this file that is exported from libxmlrpc_client. XMLRPC_BUILDING_CLIENT says this compilation is part of libxmlrpc_client, as opposed to something that _uses_ libxmlrpc_client. */ #ifdef XMLRPC_BUILDING_CLIENT #define XMLRPC_CLIENT_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_CLIENT_EXPORTED #endif /* libxmlrpc_client typically does _not_ actually include all of the XML transports declared here by xmlrpc_*_transport_ops. Use 'xmlrpc-c-config --features' to determine which features are installed. */ /* Before Xmlrpc-c 1.13 (December 2007), we declared struct xmlrpc_xportparms, as a sort of "base class." The struct was never complete -- you just cast pointer to it it to pointers to other types. It turned out not to be really helpful and casts are ugly, so now we just use void * as a base class pointer. */ XMLRPC_CLIENT_EXPORTED extern struct xmlrpc_client_transport_ops xmlrpc_libwww_transport_ops; XMLRPC_CLIENT_EXPORTED extern struct xmlrpc_client_transport_ops xmlrpc_wininet_transport_ops; XMLRPC_CLIENT_EXPORTED extern struct xmlrpc_client_transport_ops xmlrpc_curl_transport_ops; enum xmlrpc_sslversion { XMLRPC_SSLVERSION_DEFAULT, XMLRPC_SSLVERSION_TLSv1, XMLRPC_SSLVERSION_SSLv2, XMLRPC_SSLVERSION_SSLv3 }; enum xmlrpc_httpauthtype { /* These are just constants. They can be or'ed as integers to create a set. */ XMLRPC_HTTPAUTH_BASIC = (1<<0), XMLRPC_HTTPAUTH_DIGEST = (1<<1), XMLRPC_HTTPAUTH_GSSNEGOTIATE = (1<<2), XMLRPC_HTTPAUTH_NTLM = (1<<3) }; /* The following are useful combinations of the HTTP authentication types above. */ #define XMLRPC_HTTPAUTH_NONE 0 #define XMLRPC_HTTPAUTH_ANY ~0 #define XMLRPC_HTTPAUTH_ANYSAFE (~XMLRPC_HTTPAUTH_BASIC) enum xmlrpc_httpproxytype { XMLRPC_HTTPPROXY_HTTP = 0, XMLRPC_HTTPPROXY_SOCKS5 = 5 }; struct xmlrpc_curl_xportparms { /* This is designed so that zero values are always the defaults. */ const char * network_interface; xmlrpc_bool no_ssl_verifypeer; xmlrpc_bool no_ssl_verifyhost; const char * user_agent; const char * ssl_cert; const char * sslcerttype; const char * sslcertpasswd; const char * sslkey; const char * sslkeytype; const char * sslkeypasswd; const char * sslengine; xmlrpc_bool sslengine_default; enum xmlrpc_sslversion sslversion; const char * cainfo; const char * capath; const char * randomfile; const char * egdsocket; const char * ssl_cipher_list; unsigned int timeout; xmlrpc_bool dont_advertise; const char * proxy; unsigned int proxy_port; enum xmlrpc_httpproxytype proxy_type; unsigned int proxy_auth; /* A set of authentication schemes -- an OR of enum xmlrpc_httpproxyauth values */ const char * proxy_userpwd; xmlrpc_bool gssapi_delegation; const char * referer; }; #define XMLRPC_CXPSIZE(mbrname) \ XMLRPC_STRUCTSIZE(struct xmlrpc_curl_xportparms, mbrname) /* XMLRPC_CXPSIZE(xyz) is analogous to XMLRPC_CPSIZE, below */ struct xmlrpc_wininet_xportparms { int allowInvalidSSLCerts; }; #define XMLRPC_WXPSIZE(mbrname) \ XMLRPC_STRUCTSIZE(struct xmlrpc_wininet_xportparms, mbrname) /* XMLRPC_WXPSIZE(xyz) is analogous to XMLRPC_CPSIZE, below */ struct xmlrpc_transfer_progress { double total; double now; }; struct xmlrpc_progress_data { struct xmlrpc_transfer_progress call; struct xmlrpc_transfer_progress response; }; typedef void xmlrpc_progress_fn(void * const, struct xmlrpc_progress_data const); struct xmlrpc_clientparms { /* (transport, transportparmsP, transportparm_size) and (transportOpsP, transportP) are mutually exclusive. */ const char * transport; const void * transportparmsP; /* This should be type "const struct ..._xportparms *" */ size_t transportparm_size; const struct xmlrpc_client_transport_ops * transportOpsP; xmlrpc_client_transport * transportP; xmlrpc_dialect dialect; xmlrpc_progress_fn * progressFn; }; #define XMLRPC_CPSIZE(mbrname) \ XMLRPC_STRUCTSIZE(struct xmlrpc_clientparms, mbrname) /* XMLRPC_CPSIZE(xyz) is the minimum size a struct xmlrpc_clientparms must be to include the 'xyz' member. This is essential to forward and backward compatbility, as new members will be added to the end of the struct in future releases. This is how the callee knows whether or not the caller is new enough to have supplied a certain parameter. */ XMLRPC_CLIENT_EXPORTED const char * xmlrpc_client_get_default_transport(xmlrpc_env * const env); /* A user's function to handle the response to an asynchronous call. ** If 'fault->fault_occurred' is true, then response will be NULL. All ** arguments except 'userHandle' will be deallocated internally; please do ** not free any of them yourself. ** WARNING: 'paramArray' may (or may not) be NULL if fault->fault_occurred ** is true, and you set up the call using xmlrpc_client_call_asynch. ** WARNING: If asynchronous calls are still pending when the library is ** shut down, your handler may (or may not) be called with a fault. */ typedef void xmlrpc_response_handler(const char * serverUrl, const char * methodName, xmlrpc_value * paramArray, void * userHandle, xmlrpc_env * fault, xmlrpc_value * result); /*========================================================================= xmlrpc_server_info =========================================================================== We normally refer to servers by URL. But sometimes we need to do extra setup for particular servers. In that case, we can create an xmlrpc_server_info object, configure it in various ways, and call the remote server. (This interface is also designed to discourage further multiplication of xmlrpc_client_call APIs. We have enough of those already. Please add future options and flags using xmlrpc_server_info.) =========================================================================*/ typedef struct _xmlrpc_server_info xmlrpc_server_info; /* Create a new server info record, pointing to the specified server. */ XMLRPC_CLIENT_EXPORTED xmlrpc_server_info * xmlrpc_server_info_new(xmlrpc_env * const envP, const char * const serverUrl); /* Create a new server info record, with a copy of the old server. */ XMLRPC_CLIENT_EXPORTED extern xmlrpc_server_info * xmlrpc_server_info_copy(xmlrpc_env * const envP, xmlrpc_server_info * const srcP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_free(xmlrpc_server_info * const serverP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_set_user(xmlrpc_env * const envP, xmlrpc_server_info * const serverInfoP, const char * const username, const char * const password); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_set_basic_auth(xmlrpc_env * const envP, xmlrpc_server_info * const serverP, const char * const username, const char * const password); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_allow_auth_basic(xmlrpc_env * const envP, xmlrpc_server_info * const sP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_disallow_auth_basic(xmlrpc_env * const envP, xmlrpc_server_info * const sP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_allow_auth_digest(xmlrpc_env * const envP, xmlrpc_server_info * const sP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_disallow_auth_digest(xmlrpc_env * const envP, xmlrpc_server_info * const sP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_allow_auth_negotiate(xmlrpc_env * const envP, xmlrpc_server_info * const sP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_disallow_auth_negotiate(xmlrpc_env * const envP, xmlrpc_server_info * const sP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_allow_auth_ntlm(xmlrpc_env * const envP, xmlrpc_server_info * const sP); XMLRPC_CLIENT_EXPORTED void xmlrpc_server_info_disallow_auth_ntlm(xmlrpc_env * const envP, xmlrpc_server_info * const sP); /* These are for backward compatibility -- they can't be exported from a Windows DLL. xmlrpc_server_version() is preferred. */ extern unsigned int const xmlrpc_client_version_major; extern unsigned int const xmlrpc_client_version_minor; extern unsigned int const xmlrpc_client_version_point; XMLRPC_CLIENT_EXPORTED void xmlrpc_client_version(unsigned int * const majorP, unsigned int * const minorP, unsigned int * const pointP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_setup_global_const(xmlrpc_env * const envP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_teardown_global_const(void); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_create(xmlrpc_env * const envP, int const flags, const char * const appname, const char * const appversion, const struct xmlrpc_clientparms * const clientparmsP, unsigned int const parmSize, xmlrpc_client ** const clientPP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_destroy(xmlrpc_client * const clientP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_transport_call2( xmlrpc_env * const envP, xmlrpc_client * const clientP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block ** const respXmlPP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_call2(xmlrpc_env * const envP, struct xmlrpc_client * const clientP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_value ** const resultPP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_call2f(xmlrpc_env * const envP, xmlrpc_client * const clientP, const char * const serverUrl, const char * const methodName, xmlrpc_value ** const resultPP, const char * const format, ...); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_call2f_va(xmlrpc_env * const envP, xmlrpc_client * const clientP, const char * const serverUrl, const char * const methodName, const char * const format, xmlrpc_value ** const resultPP, va_list args); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_event_loop_finish(xmlrpc_client * const clientP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_event_loop_finish_timeout(xmlrpc_client * const clientP, unsigned long const milliseconds); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_start_rpc(xmlrpc_env * const envP, struct xmlrpc_client * const clientP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_response_handler responseHandler, void * const userData); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_start_rpcf(xmlrpc_env * const envP, xmlrpc_client * const clientP, const char * const serverUrl, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userData, const char * const format, ...); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_start_rpcf_va(xmlrpc_env * const envP, xmlrpc_client * const clientP, const char * const serverUrl, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userData, const char * const format, va_list args); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_set_interrupt(xmlrpc_client * const clientP, int * const interruptP); #include /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _XMLRPC_CLIENT_H_ */ xmlrpc-c-1.33.14/include/xmlrpc-c/client.hpp000066400000000000000000000213431236133176700205630ustar00rootroot00000000000000#ifndef CLIENT_HPP_INCLUDED #define CLIENT_HPP_INCLUDED #include #include #include #include #include #include #include #include #include /* XMLRPC_CLIENTPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc_client++. XMLRPC_BUILDING_CLIENTPP says this compilation is part of libxmlrpc_client++, as opposed to something that _uses_ libxmlrpc_client++. */ #ifdef XMLRPC_BUILDING_CLIENTPP #define XMLRPC_CLIENTPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_CLIENTPP_EXPORTED #endif namespace xmlrpc_c { class XMLRPC_CLIENTPP_EXPORTED clientTransactionPtr; class XMLRPC_CLIENTPP_EXPORTED clientTransaction : public girmem::autoObject { friend class clientTransactionPtr; public: virtual void finish(xmlrpc_c::rpcOutcome const& outcome) = 0; virtual void finishErr(girerr::error const& error) = 0; virtual void progress(struct xmlrpc_progress_data const& progressData) const = 0; protected: clientTransaction(); }; class XMLRPC_CLIENTPP_EXPORTED clientTransactionPtr : public girmem::autoObjectPtr { public: clientTransactionPtr(); clientTransactionPtr(clientTransaction * const transP); virtual ~clientTransactionPtr(); virtual xmlrpc_c::clientTransaction * operator->() const; }; class XMLRPC_CLIENTPP_EXPORTED clientPtr; class XMLRPC_CLIENTPP_EXPORTED client : public girmem::autoObject { /*---------------------------------------------------------------------------- A generic client -- a means of performing an RPC. This is so generic that it can be used for clients that are not XML-RPC. This is a base class. Derived classes define things such as that XML and HTTP get used to perform the RPC. -----------------------------------------------------------------------------*/ friend class clientTransactionPtr; public: virtual ~client(); virtual void call(xmlrpc_c::carriageParm * const carriageParmP, std::string const& methodName, xmlrpc_c::paramList const& paramList, xmlrpc_c::rpcOutcome * const outcomeP) = 0; virtual void start(xmlrpc_c::carriageParm * const carriageParmP, std::string const& methodName, xmlrpc_c::paramList const& paramList, xmlrpc_c::clientTransactionPtr const& tranP); void finishAsync(xmlrpc_c::timeout const timeout); virtual void setInterrupt(int *); }; class XMLRPC_CLIENTPP_EXPORTED clientPtr : public girmem::autoObjectPtr { public: clientPtr(); explicit clientPtr(xmlrpc_c::client * const clientP); xmlrpc_c::client * operator->() const; xmlrpc_c::client * get() const; }; class XMLRPC_CLIENTPP_EXPORTED serverAccessor : public girmem::autoObject { public: serverAccessor(xmlrpc_c::clientPtr const clientP, xmlrpc_c::carriageParmPtr const carriageParmP); void call(std::string const& methodName, xmlrpc_c::paramList const& paramList, xmlrpc_c::rpcOutcome * const outcomeP) const; private: xmlrpc_c::clientPtr const clientP; xmlrpc_c::carriageParmPtr const carriageParmP; }; class XMLRPC_CLIENTPP_EXPORTED serverAccessorPtr : public girmem::autoObjectPtr { public: serverAccessorPtr(); explicit serverAccessorPtr(xmlrpc_c::serverAccessor * const serverAccessorP); xmlrpc_c::serverAccessor * operator->() const; xmlrpc_c::serverAccessor * get() const; }; class XMLRPC_CLIENTPP_EXPORTED connection { /*---------------------------------------------------------------------------- A nexus of a particular client and a particular server, along with carriage parameters for performing RPCs between the two. This is a minor convenience for client programs that always talk to the same server the same way. Use this as a parameter to rpc.call(). -----------------------------------------------------------------------------*/ public: connection(xmlrpc_c::client * const clientP, xmlrpc_c::carriageParm * const carriageParmP); ~connection(); xmlrpc_c::client * clientP; xmlrpc_c::carriageParm * carriageParmP; }; class XMLRPC_CLIENTPP_EXPORTED client_xml : public xmlrpc_c::client { /*---------------------------------------------------------------------------- A client that uses XML-RPC XML in the RPC. This class does not define how the XML gets transported, though (i.e. does not require HTTP). -----------------------------------------------------------------------------*/ public: client_xml(xmlrpc_c::clientXmlTransport * const transportP); client_xml(xmlrpc_c::clientXmlTransport * const transportP, xmlrpc_dialect const dialect); client_xml(xmlrpc_c::clientXmlTransportPtr const transportP); client_xml(xmlrpc_c::clientXmlTransportPtr const transportP, xmlrpc_dialect const dialect); ~client_xml(); void call(carriageParm * const carriageParmP, std::string const& methodName, xmlrpc_c::paramList const& paramList, xmlrpc_c::rpcOutcome * const outcomeP); void start(xmlrpc_c::carriageParm * const carriageParmP, std::string const& methodName, xmlrpc_c::paramList const& paramList, xmlrpc_c::clientTransactionPtr const& tranP); void finishAsync(xmlrpc_c::timeout const timeout); virtual void setInterrupt(int * interruptP); private: struct client_xml_impl * implP; }; class XMLRPC_CLIENTPP_EXPORTED xmlTransaction_client : public xmlrpc_c::xmlTransaction { public: xmlTransaction_client(xmlrpc_c::clientTransactionPtr const& tranP); void finish(std::string const& responseXml) const; void finishErr(girerr::error const& error) const; void progress(xmlrpc_progress_data const& progressData) const; private: xmlrpc_c::clientTransactionPtr const tranP; }; class XMLRPC_CLIENTPP_EXPORTED xmlTransaction_clientPtr : public xmlTransactionPtr { public: xmlTransaction_clientPtr(); xmlTransaction_clientPtr(xmlrpc_c::clientTransactionPtr const& tranP); xmlrpc_c::xmlTransaction_client * operator->() const; }; class rpcPtr; class XMLRPC_CLIENTPP_EXPORTED rpc : public clientTransaction { /*---------------------------------------------------------------------------- An RPC. An RPC consists of method name, parameters, and result. It does not specify in any way how the method name and parameters get turned into a result. It does not presume XML or HTTP. You don't normally create or reference an object of this class directly, but rather via an 'rpcPtr' object. That takes care of deleting the object when you are done with it (but not before). This is critical if you plan to use the 'start' method, because without an rpcPtr reference, the system will destroy the object under the covers when the RPC finishes, and there is no way for you to guarantee you won't still access it after it finishes (because of accesses within Xmlrpc-c calls such as the call that finishes the RPC or just rpc::start). In order to do asynchronous RPCs, you normally have to create a derived class that defines a useful notifyComplete(). -----------------------------------------------------------------------------*/ friend class xmlrpc_c::rpcPtr; public: void call(xmlrpc_c::client * const clientP, xmlrpc_c::carriageParm * const carriageParmP); void call(xmlrpc_c::connection const& connection); void start(xmlrpc_c::client * const clientP, xmlrpc_c::carriageParm * const carriageParmP); void start(xmlrpc_c::connection const& connection); void finish(xmlrpc_c::rpcOutcome const& outcome); void finishErr(girerr::error const& error); virtual void notifyComplete(); virtual void progress(struct xmlrpc_progress_data const& progressData) const; bool isFinished() const; bool isSuccessful() const; xmlrpc_c::value getResult() const; xmlrpc_c::fault getFault() const; rpc(std::string const methodName, xmlrpc_c::paramList const& paramList); virtual ~rpc(); private: struct rpc_impl * implP; }; class XMLRPC_CLIENTPP_EXPORTED rpcPtr : public clientTransactionPtr { public: rpcPtr(); explicit rpcPtr(xmlrpc_c::rpc * const rpcP); rpcPtr(std::string const methodName, xmlrpc_c::paramList const& paramList); xmlrpc_c::rpc * operator->() const; }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/client_global.h000066400000000000000000000130121236133176700215350ustar00rootroot00000000000000#ifndef CLIENT_GLOBAL_H_INCLUDED #define CLIENT_GLOBAL_H_INCLUDED #include #include /* XMLRPC_CLIENT_EXPORTED marks a symbol in this file that is exported from libxmlrpc_client. XMLRPC_BUILDING_CLIENT says this compilation is part of libxmlrpc_client, as opposed to something that _uses_ libxmlrpc_client. */ #ifdef XMLRPC_BUILDING_CLIENT #define XMLRPC_CLIENT_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_CLIENT_EXPORTED #endif /*========================================================================= ** Initialization and Shutdown **========================================================================= ** These routines initialize and terminate the XML-RPC client. If you're ** already using libwww on your own, you can pass ** XMLRPC_CLIENT_SKIP_LIBWWW_INIT to avoid initializing it twice. */ #define XMLRPC_CLIENT_NO_FLAGS (0) #define XMLRPC_CLIENT_SKIP_LIBWWW_INIT (1) XMLRPC_CLIENT_EXPORTED extern void xmlrpc_client_init(int const flags, const char * const appname, const char * const appversion); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_init2(xmlrpc_env * const env, int const flags, const char * const appname, const char * const appversion, const struct xmlrpc_clientparms * const clientparms, unsigned int const parm_size); XMLRPC_CLIENT_EXPORTED extern void xmlrpc_client_cleanup(void); /*========================================================================= ** xmlrpc_client_call **=======================================================================*/ XMLRPC_CLIENT_EXPORTED xmlrpc_value * xmlrpc_client_call(xmlrpc_env * const envP, const char * const server_url, const char * const method_name, const char * const format, ...); XMLRPC_CLIENT_EXPORTED xmlrpc_value * xmlrpc_client_call_params(xmlrpc_env * const envP, const char * const serverUrl, const char * const methodName, xmlrpc_value * const paramArrayP); XMLRPC_CLIENT_EXPORTED xmlrpc_value * xmlrpc_client_call_server(xmlrpc_env * const envP, const xmlrpc_server_info * const server, const char * const method_name, const char * const format, ...); XMLRPC_CLIENT_EXPORTED xmlrpc_value * xmlrpc_client_call_server_params( xmlrpc_env * const envP, const xmlrpc_server_info * const serverP, const char * const method_name, xmlrpc_value * const paramArrayP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_transport_call( xmlrpc_env * const envP, void * const reserved, /* for client handle */ const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block ** const respXmlPP); /*========================================================================= ** xmlrpc_client_call_asynch **========================================================================= ** An asynchronous XML-RPC client. */ XMLRPC_CLIENT_EXPORTED void xmlrpc_client_call_asynch(const char * const server_url, const char * const method_name, xmlrpc_response_handler responseHandler, void * const user_data, const char * const format, ...); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_call_server_asynch(xmlrpc_server_info * const server, const char * const method_name, xmlrpc_response_handler responseHandler, void * const user_data, const char * const format, ...); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_call_asynch_params(const char * const server_url, const char * const method_name, xmlrpc_response_handler responseHandler, void * const user_data, xmlrpc_value * const paramArrayP); XMLRPC_CLIENT_EXPORTED void xmlrpc_client_call_server_asynch_params( xmlrpc_server_info * const server, const char * const method_name, xmlrpc_response_handler responseHandler, void * const user_data, xmlrpc_value * const paramArrayP); /*========================================================================= ** Event Loop Interface **========================================================================= ** These functions can be used to run the XML-RPC event loop. If you ** don't like these, you can also run the libwww event loop directly. */ /* Finish all outstanding asynchronous calls. Alternatively, the loop ** will exit if someone calls xmlrpc_client_event_loop_end. */ XMLRPC_CLIENT_EXPORTED extern void xmlrpc_client_event_loop_finish_asynch(void); /* Finish all outstanding asynchronous calls. */ XMLRPC_CLIENT_EXPORTED extern void xmlrpc_client_event_loop_finish_asynch_timeout(unsigned long const milliseconds); #endif xmlrpc-c-1.33.14/include/xmlrpc-c/client_int.h000066400000000000000000000141331236133176700210740ustar00rootroot00000000000000/*============================================================================ xmlrpc_client_int.h ============================================================================== This header file defines the interface between client modules inside xmlrpc-c. Use this in addition to xmlrpc_client.h, which defines the external interface. Copyright information is at the end of the file. ============================================================================*/ #ifndef XMLRPC_CLIENT_INT_H_INCLUDED #define XMLRPC_CLIENT_INT_H_INCLUDED #include "xmlrpc_config.h" #include "bool.h" #include "xmlrpc-c/util.h" #ifdef __cplusplus extern "C" { #endif struct _xmlrpc_server_info { const char * serverUrl; struct { bool basic; bool digest; bool gssnegotiate; bool ntlm; } allowedAuth; const char * userNamePw; /* The username/password value for HTTP, i.e. in "user:password" form This can be NULL to indicate "none", but only if 'allowedAuth' doesn't allow any form of authentication. */ const char * basicAuthHdrValue; /* A complete value for an HTTP Authorization: header that requests HTTP basic authentication. This exists whether or not 'allowedAuth' allows basic authentication, and is completely redundant with 'userNamePw'. It exists mainly for historical reasons, and may also save some computation when the same xmrpc_server_info is used for multiple HTTP connections. This is NULL exactly when 'userNamePw' is NULL. */ }; /*========================================================================= ** Transport Implementation functions. **========================================================================= */ #include "xmlrpc-c/transport.h" /* The generalized event loop. This uses the above flags. For more details, ** see the wrapper functions below. If you're not using the timeout, the ** 'milliseconds' parameter will be ignored. ** Note that ANY event loop call will return immediately if there are ** no outstanding XML-RPC calls. */ extern void xmlrpc_client_event_loop_run_general (int flags, xmlrpc_timeout milliseconds); /* Run the event loop forever. The loop will exit if someone calls ** xmlrpc_client_event_loop_end. */ extern void xmlrpc_client_event_loop_run (void); /* Run the event loop forever. The loop will exit if someone calls ** xmlrpc_client_event_loop_end or the timeout expires. ** (Note that ANY event loop call will return immediately if there are ** no outstanding XML-RPC calls.) */ extern void xmlrpc_client_event_loop_run_timeout (xmlrpc_timeout milliseconds); /* End the running event loop immediately. This can also be accomplished ** by calling the corresponding function in libwww. ** (Note that ANY event loop call will return immediately if there are ** no outstanding XML-RPC calls.) */ extern void xmlrpc_client_event_loop_end (void); /* Return true if there are uncompleted asynchronous calls. ** The exact value of this during a response callback is undefined. */ extern int xmlrpc_client_asynch_calls_are_unfinished (void); /*========================================================================= ** Interface between global client and general client functions. ** (These are necessary because there are some global client functions ** that don't have exported private client versions because we don't like ** them and have them for global functions only for backward compatibility. ** The global client functions existed before any private client ones did). **========================================================================= */ void xmlrpc_client_call_server2_va(xmlrpc_env * const envP, struct xmlrpc_client * const clientP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, const char * const format, va_list args, xmlrpc_value ** const resultPP); void xmlrpc_client_start_rpcf_server_va( xmlrpc_env * const envP, struct xmlrpc_client * const clientP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userData, const char * const format, va_list args); /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif xmlrpc-c-1.33.14/include/xmlrpc-c/client_simple.hpp000066400000000000000000000023541236133176700221350ustar00rootroot00000000000000#ifndef CLIENT_SIMPLE_HPP_INCLUDED #define CLIENT_SIMPLE_HPP_INCLUDED #include #include #include #include /* XMLRPC_CLIENTPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc_client++. XMLRPC_BUILDING_CLIENTPP says this compilation is part of libxmlrpc_client++, as opposed to something that _uses_ libxmlrpc_client++. */ #ifdef XMLRPC_BUILDING_CLIENTPP #define XMLRPC_CLIENTPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_CLIENTPP_EXPORTED #endif namespace xmlrpc_c { class XMLRPC_CLIENTPP_EXPORTED clientSimple { public: clientSimple(); void call(std::string const serverUrl, std::string const methodName, xmlrpc_c::value * const resultP); void call(std::string const serverUrl, std::string const methodName, std::string const format, xmlrpc_c::value * const resultP, ...); void call(std::string const serverUrl, std::string const methodName, xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const resultP); private: xmlrpc_c::clientPtr clientP; }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/client_transport.hpp000066400000000000000000000321561236133176700227030ustar00rootroot00000000000000#ifndef CLIENT_TRANSPORT_HPP_INCLUDED #define CLIENT_TRANSPORT_HPP_INCLUDED #include #include #include #include #include #include #include #include namespace xmlrpc_c { /* XMLRPC_CLIENTPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc_client++. XMLRPC_BUILDING_CLIENTPP says this compilation is part of libxmlrpc_client++, as opposed to something that _uses_ libxmlrpc_client++. */ #ifdef XMLRPC_BUILDING_CLIENTPP #define XMLRPC_CLIENTPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_CLIENTPP_EXPORTED #endif class XMLRPC_CLIENTPP_EXPORTED carriageParmPtr; class XMLRPC_CLIENTPP_EXPORTED carriageParm : public girmem::autoObject { /*---------------------------------------------------------------------------- The parameter to a client for an individual RPC. It tells specifics of how to carry the call to the server and the response back. For example, it may identify the server. It may identify communication protocols to use. It may indicate permission and accounting information. This is a base class; the carriage parameter is specific to the class of client. For example, an HTTP-based client would have a URL and HTTP basic authentication info as parameter. -----------------------------------------------------------------------------*/ protected: virtual ~carriageParm(); carriageParm(); }; class XMLRPC_CLIENTPP_EXPORTED carriageParmPtr : public girmem::autoObjectPtr { public: carriageParmPtr(); explicit carriageParmPtr(xmlrpc_c::carriageParm * const carriageParmP); xmlrpc_c::carriageParm * operator->() const; xmlrpc_c::carriageParm * get() const; }; //---------------------------------------------------------------------------- class XMLRPC_CLIENTPP_EXPORTED xmlTransactionPtr; class XMLRPC_CLIENTPP_EXPORTED xmlTransaction : public girmem::autoObject { friend class xmlTransactionPtr; public: virtual void finish(std::string const& responseXml) const; virtual void finishErr(girerr::error const& error) const; virtual void progress(struct xmlrpc_progress_data const& progressData) const; protected: xmlTransaction(); }; class XMLRPC_CLIENTPP_EXPORTED xmlTransactionPtr : public girmem::autoObjectPtr { public: xmlTransactionPtr(); xmlTransactionPtr(xmlTransaction * xmlTransP); xmlrpc_c::xmlTransaction * operator->() const; }; //---------------------------------------------------------------------------- class XMLRPC_CLIENTPP_EXPORTED clientXmlTransport : public girmem::autoObject { /*---------------------------------------------------------------------------- An object which transports XML to and from an XML-RPC server for an XML-RPC client. This is a base class. Derived classes define methods to perform the transportation in particular ways. -----------------------------------------------------------------------------*/ public: virtual ~clientXmlTransport(); virtual void call(xmlrpc_c::carriageParm * const carriageParmP, std::string const& callXml, std::string * const responseXmlP) = 0; virtual void start(xmlrpc_c::carriageParm * const carriageParmP, std::string const& callXml, xmlrpc_c::xmlTransactionPtr const& xmlTranP); virtual void finishAsync(xmlrpc_c::timeout const timeout); static void asyncComplete( struct xmlrpc_call_info * const callInfoP, xmlrpc_mem_block * const responseXmlMP, xmlrpc_env const transportEnv); static void progress( struct xmlrpc_call_info * const callInfoP, struct xmlrpc_progress_data const progressData); virtual void setInterrupt(int * const interruptP); }; class XMLRPC_CLIENTPP_EXPORTED clientXmlTransportPtr : public girmem::autoObjectPtr { public: clientXmlTransportPtr(); clientXmlTransportPtr(xmlrpc_c::clientXmlTransport * const transportP); xmlrpc_c::clientXmlTransport * operator->() const; xmlrpc_c::clientXmlTransport * get() const; }; /*=========================================================================== HTTP ===========================================================================*/ class XMLRPC_CLIENTPP_EXPORTED carriageParm_http0 : public xmlrpc_c::carriageParm { public: carriageParm_http0(std::string const serverUrl); ~carriageParm_http0(); void setUser(std::string const userid, std::string const password); void allowAuthBasic(); void disallowAuthBasic(); void allowAuthDigest(); void disallowAuthDigest(); void allowAuthNegotiate(); void disallowAuthNegotiate(); void allowAuthNtlm(); void disallowAuthNtlm(); void setBasicAuth(std::string const userid, std::string const password); xmlrpc_server_info * c_serverInfoP; protected: // Only a derived class is allowed to create an object with no // server URL, and the derived class is expected to follow it up // with an instantiate() to establish the server URL. carriageParm_http0(); void instantiate(std::string const serverUrl); }; class XMLRPC_CLIENTPP_EXPORTED carriageParm_http0Ptr : public xmlrpc_c::carriageParmPtr { public: carriageParm_http0Ptr(); carriageParm_http0Ptr(xmlrpc_c::carriageParm_http0 * const carriageParmP); xmlrpc_c::carriageParm_http0 * operator->() const; }; class XMLRPC_CLIENTPP_EXPORTED clientXmlTransport_http : public xmlrpc_c::clientXmlTransport { /*---------------------------------------------------------------------------- A base class for client XML transports that use the simple, classic C HTTP transports. -----------------------------------------------------------------------------*/ public: virtual ~clientXmlTransport_http(); void call(xmlrpc_c::carriageParm * const carriageParmP, std::string const& callXml, std::string * const responseXmlP); void start(xmlrpc_c::carriageParm * const carriageParmP, std::string const& callXml, xmlrpc_c::xmlTransactionPtr const& xmlTranP); virtual void finishAsync(xmlrpc_c::timeout const timeout); virtual void setInterrupt(int * const interruptP); static std::vector availableTypes(); static clientXmlTransportPtr create(); protected: clientXmlTransport_http() {} // ensure no one can create struct xmlrpc_client_transport * c_transportP; const struct xmlrpc_client_transport_ops * c_transportOpsP; }; /*=========================================================================== curl ===========================================================================*/ class XMLRPC_CLIENTPP_EXPORTED carriageParm_curl0 : public xmlrpc_c::carriageParm_http0 { public: carriageParm_curl0(std::string const serverUrl); }; class XMLRPC_CLIENTPP_EXPORTED carriageParm_curl0Ptr : public xmlrpc_c::carriageParm_http0Ptr { public: carriageParm_curl0Ptr(); carriageParm_curl0Ptr(xmlrpc_c::carriageParm_curl0 * const carriageParmP); xmlrpc_c::carriageParm_curl0 * operator->() const; }; class XMLRPC_CLIENTPP_EXPORTED clientXmlTransport_curl : public xmlrpc_c::clientXmlTransport_http { public: struct constrOpt_impl; class XMLRPC_CLIENTPP_EXPORTED constrOpt { public: constrOpt(); ~constrOpt(); constrOpt(constrOpt&); constrOpt & network_interface (std::string const& arg); constrOpt & no_ssl_verifypeer (bool const& arg); constrOpt & no_ssl_verifyhost (bool const& arg); constrOpt & dont_advertise (bool const& arg); constrOpt & user_agent (std::string const& arg); constrOpt & referer (std::string const& arg); constrOpt & ssl_cert (std::string const& arg); constrOpt & sslcerttype (std::string const& arg); constrOpt & sslcertpasswd (std::string const& arg); constrOpt & sslkey (std::string const& arg); constrOpt & sslkeytype (std::string const& arg); constrOpt & sslkeypasswd (std::string const& arg); constrOpt & sslengine (std::string const& arg); constrOpt & sslengine_default (bool const& arg); constrOpt & sslversion (xmlrpc_sslversion const& arg); constrOpt & cainfo (std::string const& arg); constrOpt & capath (std::string const& arg); constrOpt & randomfile (std::string const& arg); constrOpt & egdsocket (std::string const& arg); constrOpt & ssl_cipher_list (std::string const& arg); constrOpt & timeout (unsigned int const& arg); constrOpt & proxy (std::string const& arg); constrOpt & proxy_port (unsigned int const& arg); constrOpt & proxy_auth (unsigned int const& arg); constrOpt & proxy_userpwd (std::string const& arg); constrOpt & proxy_type (xmlrpc_httpproxytype const& arg); constrOpt & gssapi_delegation (bool const& arg); private: struct constrOpt_impl * implP; friend class clientXmlTransport_curl; }; clientXmlTransport_curl(constrOpt const& opt); clientXmlTransport_curl(std::string const networkInterface = "", bool const noSslVerifyPeer = false, bool const noSslVerifyHost = false, std::string const userAgent = ""); ~clientXmlTransport_curl(); private: void initialize(constrOpt const& opt); }; /*=========================================================================== libwww ===========================================================================*/ class XMLRPC_CLIENTPP_EXPORTED carriageParm_libwww0 : public xmlrpc_c::carriageParm_http0 { public: carriageParm_libwww0(std::string const serverUrl); }; class XMLRPC_CLIENTPP_EXPORTED carriageParm_libwww0Ptr : public xmlrpc_c::carriageParm_http0Ptr { public: carriageParm_libwww0Ptr(); carriageParm_libwww0Ptr(xmlrpc_c::carriageParm_libwww0 * const); xmlrpc_c::carriageParm_libwww0 * operator->() const; }; class XMLRPC_CLIENTPP_EXPORTED clientXmlTransport_libwww : public xmlrpc_c::clientXmlTransport_http { public: clientXmlTransport_libwww(std::string const appname = "", std::string const appversion = ""); ~clientXmlTransport_libwww(); }; /*=========================================================================== wininet ===========================================================================*/ class XMLRPC_CLIENTPP_EXPORTED carriageParm_wininet0 : public xmlrpc_c::carriageParm_http0 { public: carriageParm_wininet0(std::string const serverUrl); }; class XMLRPC_CLIENTPP_EXPORTED carriageParm_wininet0Ptr : public xmlrpc_c::carriageParm_http0Ptr { public: carriageParm_wininet0Ptr(); carriageParm_wininet0Ptr(xmlrpc_c::carriageParm_wininet0 * const); xmlrpc_c::carriageParm_wininet0 * operator->() const; }; class XMLRPC_CLIENTPP_EXPORTED clientXmlTransport_wininet : public xmlrpc_c::clientXmlTransport_http { public: clientXmlTransport_wininet(bool const allowInvalidSslCerts = false); ~clientXmlTransport_wininet(); }; /*=========================================================================== pstream ===========================================================================*/ class XMLRPC_CLIENTPP_EXPORTED packetSocket; class XMLRPC_CLIENTPP_EXPORTED carriageParm_pstream : public xmlrpc_c::carriageParm { // There are no parameters for carrying an RPC on a packet stream. // There's only one way to carry it. }; class XMLRPC_CLIENTPP_EXPORTED carriageParm_pstreamPtr : public xmlrpc_c::carriageParmPtr { public: carriageParm_pstreamPtr(); carriageParm_pstreamPtr( xmlrpc_c::carriageParm_pstream * const carriageParmP); xmlrpc_c::carriageParm_pstream * operator->() const; }; class XMLRPC_CLIENTPP_EXPORTED clientXmlTransport_pstream : public xmlrpc_c::clientXmlTransport { public: struct constrOpt_impl; class XMLRPC_CLIENTPP_EXPORTED constrOpt { public: constrOpt(); ~constrOpt(); constrOpt(constrOpt&); constrOpt & fd (int const& arg); private: struct constrOpt_impl * implP; friend class clientXmlTransport_pstream; }; clientXmlTransport_pstream(constrOpt const& opt); ~clientXmlTransport_pstream(); void call(xmlrpc_c::carriageParm * const carriageParmP, std::string const& callXml, std::string * const responseXmlP); private: packetSocket * packetSocketP; }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/girerr.hpp000066400000000000000000000017121236133176700205750ustar00rootroot00000000000000#ifndef GIRERR_HPP_INCLUDED #define GIRERR_HPP_INCLUDED #include #include #include /* XMLRPC_LIBPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc++. XMLRPC_BUILDING_LIBPP says this compilation is part of libxmlrpc++, as opposed to something that _uses_ libxmlrpc++. */ #ifdef XMLRPC_BUILDING_LIBPP #define XMLRPC_LIBPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_LIBPP_EXPORTED #endif #define HAVE_GIRERR_ERROR namespace girerr { class XMLRPC_LIBPP_EXPORTED error : public std::exception { public: error(std::string const& what_arg) : _what(what_arg) {} ~error() throw() {} virtual const char * what() const throw() { return this->_what.c_str(); }; private: std::string _what; }; // throwf() always throws a girerr::error . XMLRPC_LIBPP_EXPORTED void throwf(const char * const format, ...) XMLRPC_PRINTF_ATTR(1,2) XMLRPC_NORETURN_ATTR; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/girmem.hpp000066400000000000000000000035621236133176700205700ustar00rootroot00000000000000/*============================================================================ girmem.hpp ============================================================================== This declares the user interface to memory management facilities (smart pointers, basically) in libxmlrpc. They are used in interfaces to various classes in XML For C/C++. ============================================================================*/ #ifndef GIRMEM_HPP_INCLUDED #define GIRMEM_HPP_INCLUDED #include #include /* XMLRPC_LIBPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc++. XMLRPC_BUILDING_LIBPP says this compilation is part of libxmlrpc++, as opposed to something that _uses_ libxmlrpc++. */ #ifdef XMLRPC_BUILDING_LIBPP #define XMLRPC_LIBPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_LIBPP_EXPORTED #endif namespace girmem { class XMLRPC_LIBPP_EXPORTED autoObjectPtr; class XMLRPC_LIBPP_EXPORTED autoObject { friend class autoObjectPtr; public: void incref(); void decref(bool * const unreferencedP); protected: autoObject(); virtual ~autoObject(); private: class Impl; std::auto_ptr const implP; // Because of 'implP', we cannot allow copy construction, so this is // private: autoObject(autoObject const&); }; class XMLRPC_LIBPP_EXPORTED autoObjectPtr { public: autoObjectPtr(); autoObjectPtr(girmem::autoObject * objectP); autoObjectPtr(girmem::autoObjectPtr const& autoObjectPtr); ~autoObjectPtr(); void point(girmem::autoObject * const objectP); void unpoint(); autoObjectPtr operator=(girmem::autoObjectPtr const& objectPtr); girmem::autoObject * operator->() const; girmem::autoObject * get() const; protected: girmem::autoObject * objectP; }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/inttypes.h000066400000000000000000000006331236133176700206230ustar00rootroot00000000000000#ifndef XMLRPC_INTTYPES_H_INCLUDED #define XMLRPC_INTTYPES_H_INCLUDED #ifdef _MSC_VER typedef unsigned short xmlrpc_uint16_t; typedef unsigned int xmlrpc_uint32_t; typedef unsigned __int64 xmlrpc_uint64_t; #else #include #ifdef __INTERIX # include #endif typedef uint16_t xmlrpc_uint16_t; typedef uint32_t xmlrpc_uint32_t; typedef uint64_t xmlrpc_uint64_t; #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/json.h000066400000000000000000000017161236133176700177200ustar00rootroot00000000000000#ifndef XMLRPC_JSON_H_INCLUDED #define XMLRPC_JSON_H_INCLUDED #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Parse a given string as JSON and return its value as an XML-RPC value object. @param envP xmlrpc environment for error handling @param buf holds a pointer to a ziro terminated string @return the value generated or NULL (check error) */ xmlrpc_value * xmlrpc_parse_json(xmlrpc_env * const envP, const char * const json); /* Serialize an XML-RPC value object into JSON. @param envP holds the xmlrpc execution environment @param valP holds the value to serialize @param out holds a mem block containing the result */ void xmlrpc_serialize_json(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const jsonP); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* XMLRPC_JSON_H_INCLUDED */ xmlrpc-c-1.33.14/include/xmlrpc-c/lock.h000066400000000000000000000010741236133176700176740ustar00rootroot00000000000000#ifndef LOCK_H_INCLUDED #define LOCK_H_INCLUDED typedef struct lock lock; typedef void lockAcquireFn(lock *); typedef void lockReleaseFn(lock *); typedef void lockDestroyFn(lock *); struct lock { /* To finish the job of making an abstract lock class that can use locks other than pthread mutexes, we need to replace 'theLock' with a "void * implementationP" and make curlLock_create_pthread() malloc the mutex. */ void * implementationP; lockAcquireFn * acquire; lockReleaseFn * release; lockDestroyFn * destroy; }; #endif xmlrpc-c-1.33.14/include/xmlrpc-c/lock_none.h000066400000000000000000000001741236133176700207130ustar00rootroot00000000000000#ifndef LOCK_NONE_H_INCLUDED #define LOCK_NONE_H_INCLUDED #include "lock.h" lock * xmlrpc_lock_create_none(void); #endif xmlrpc-c-1.33.14/include/xmlrpc-c/lock_platform.h000066400000000000000000000010671236133176700216020ustar00rootroot00000000000000#ifndef LOCK_PLATFORM_H_INCLUDED #define LOCK_PLATFORM_H_INCLUDED #include "xmlrpc-c/lock.h" /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif #ifdef __cplusplus extern "C" { #endif XMLRPC_UTIL_EXPORTED lock * xmlrpc_lock_create(void); #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/lock_pthread.h000066400000000000000000000007571236133176700214120ustar00rootroot00000000000000#ifndef LOCK_PTHREAD_H_INCLUDED #define LOCK_PTHREAD_H_INCLUDED #include "lock.h" /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif XMLRPC_UTIL_EXPORTED lock * xmlrpc_lock_create_pthread(void); #endif xmlrpc-c-1.33.14/include/xmlrpc-c/lock_windows.h000066400000000000000000000007571236133176700214550ustar00rootroot00000000000000#ifndef LOCK_WINDOWS_H_INCLUDED #define LOCK_WINDOWS_H_INCLUDED #include "lock.h" /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif XMLRPC_UTIL_EXPORTED lock * xmlrpc_lock_create_windows(void); #endif xmlrpc-c-1.33.14/include/xmlrpc-c/oldcppwrapper.hpp000066400000000000000000000335131236133176700221710ustar00rootroot00000000000000// -*- C++ -*- <-- an Emacs control // Copyright information is at the bottom of the file. //========================================================================= // XML-RPC C++ API //========================================================================= #ifndef XMLRPCCPP_H_INCLUDED #define XMLRPCCPP_H_INCLUDED /* XMLRPC_OLDCPPWRAPPER_EXPORTED marks a symbol in this file that is exported from libxmlrpc_cpp. XMLRPC_BUILDING_OLDCPPWRAPPER says this compilation is part of libxmlrpc_cpp, as opposed to something that _uses_ libxmlrpc_cpp. */ #ifdef XMLRPC_BUILDING_OLDCPPWRAPPER #define XMLRPC_OLDCPPWRAPPER_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_OLDCPPWRAPPER_EXPORTED #endif #include #include #include #include #include #include //========================================================================= // XmlRpcFault //========================================================================= // A C++ exception class representing an XML-RPC fault. class XMLRPC_OLDCPPWRAPPER_EXPORTED XmlRpcFault { private: xmlrpc_env mFault; XmlRpcFault& operator= (XmlRpcFault const& f) { if (true || f.getFaultCode()) abort(); return (XmlRpcFault&) f; } public: XmlRpcFault (const XmlRpcFault &fault); XmlRpcFault (const int faultCode, const std::string faultString); XmlRpcFault (const xmlrpc_env *env); ~XmlRpcFault (void); inline int getFaultCode (void) const; std::string getFaultString (void) const; inline xmlrpc_env * getFaultEnv (void); }; inline int XmlRpcFault::getFaultCode (void) const { return mFault.fault_code; } inline xmlrpc_env *XmlRpcFault::getFaultEnv (void) { return &mFault; } //========================================================================= // XmlRpcEnv //========================================================================= // This class can be used to wrap xmlrpc_env object. Use it as follows: // // XmlRpcEnv env; // xmlrpc_parse_value(env, v, "(i)", &i); // env.throwIfFaultOccurred(); class XMLRPC_OLDCPPWRAPPER_EXPORTED XmlRpcEnv { private: xmlrpc_env mEnv; void throwMe (void) const; XmlRpcEnv& operator= (XmlRpcEnv const& e) { if (true || e.faultOccurred()) abort(); return (XmlRpcEnv&) e;} public: XmlRpcEnv (const XmlRpcEnv &env); XmlRpcEnv (void) { xmlrpc_env_init(&mEnv); } ~XmlRpcEnv (void) { xmlrpc_env_clean(&mEnv); } bool faultOccurred (void) const {return (mEnv.fault_occurred != 0);}; bool hasFaultOccurred (void) const { return faultOccurred(); }; /* hasFaultOccurred() is for backward compatibility. faultOccurred() is a superior name for this. */ std::string getFaultString() const { return mEnv.fault_string; }; XmlRpcFault getFault (void) const; void throwIfFaultOccurred (void) const; operator xmlrpc_env * (void) { return &mEnv; } }; inline void XmlRpcEnv::throwIfFaultOccurred (void) const { if (faultOccurred()) throwMe(); } //========================================================================= // XmlRpcValue //========================================================================= // An object in this class is an XML-RPC value. // // We have a complex structure to allow C code mixed in with C++ code // which uses this class to refer to the same XML-RPC value object. // This is especially important because there aren't proper C++ facilities // for much of Xmlrpc-c; you have to use the C facilities even if you'd // rather use proper C++. // // The XmlRpcValue object internally represents the value as an // xmlrpc_value. It holds one reference to the xmlrpc_value. Users // of XmlRpcValue never see that xmlrpc_value, but C code can. the // C code might create the xmlrpc_value and then bind it to an XmlRpcValue, // or it might get the xmlrpc_value handle from the XmlRpcValue. Finally, // C code can simply use the XmlRpcValue where an xmlrpc_value handle is // required and it gets converted automatically. // // So reference counting for the xmlrpc_value is quite a nightmare. class XMLRPC_OLDCPPWRAPPER_EXPORTED XmlRpcValue { private: xmlrpc_value *mValue; public: enum ReferenceBehavior { MAKE_REFERENCE, CONSUME_REFERENCE }; typedef xmlrpc_int32 int32; XmlRpcValue (void); XmlRpcValue (xmlrpc_value *value, ReferenceBehavior behavior = MAKE_REFERENCE); XmlRpcValue (const XmlRpcValue& value); ~XmlRpcValue (void); XmlRpcValue& operator= (const XmlRpcValue& value); // Accessing the value's type (think of this as lightweight RTTI). xmlrpc_type getType(void) const; // We don't supply an automatic conversion operator--you need to say // whether you want to make or borrow this object's reference. // XXX - Is it really OK for these to be const? xmlrpc_value *makeReference (void) const; xmlrpc_value *borrowReference (void) const; // Some static "constructor" functions. static XmlRpcValue makeInt (const XmlRpcValue::int32 i); static XmlRpcValue makeBool (const bool b); static XmlRpcValue makeDouble (const double d); static XmlRpcValue makeDateTime (const std::string& dateTime); static XmlRpcValue makeString (const std::string& str); static XmlRpcValue makeString (const char *const str); static XmlRpcValue makeString (const char *const str, size_t len); static XmlRpcValue makeArray (void); static XmlRpcValue makeStruct (void); static XmlRpcValue makeBase64 (const unsigned char *const data, size_t len); /* // An interface to xmlrpc_build_value. static XmlRpcValue buildValue (const char *const format, ...); */ // Some functions to get the underlying data. // These will throw an XmlRpcFault if the data is the wrong type. XmlRpcValue::int32 getInt (void) const; bool getBool (void) const; double getDouble (void) const; std::string getRawDateTime (void) const; std::string getString (void) const; XmlRpcValue getArray (void) const; XmlRpcValue getStruct (void) const; // This returns an internal pointer which will become invalid when // all references to the underlying value are destroyed. void getBase64 (const unsigned char *& out_data, size_t& out_len) const; /* // An interface to xmlrpc_parse_value. void parseValue (const char *const format, ...); */ // Array functions. These will throw an XmlRpcFault if the value // isn't an array. size_t arraySize (void) const; void arrayAppendItem (const XmlRpcValue& value); XmlRpcValue arrayGetItem (int index) const; // Struct functions. These will throw an XmlRpcFault if the value // isn't a struct. size_t structSize (void) const; bool structHasKey (const std::string& key) const; XmlRpcValue structGetValue (const std::string& key) const; void structSetValue (const std::string& key, const XmlRpcValue& value); void structGetKeyAndValue (const int index, std::string& out_key, XmlRpcValue& out_value) const; }; inline XmlRpcValue::XmlRpcValue (xmlrpc_value *value, ReferenceBehavior behavior) { mValue = value; if (behavior == MAKE_REFERENCE) xmlrpc_INCREF(value); } inline XmlRpcValue::XmlRpcValue (const XmlRpcValue& value) { mValue = value.mValue; xmlrpc_INCREF(mValue); } inline XmlRpcValue::~XmlRpcValue (void) { xmlrpc_DECREF(mValue); } inline XmlRpcValue& XmlRpcValue::operator= (const XmlRpcValue& value) { // Must increment before we decrement, in case of assignment to self. xmlrpc_INCREF(value.mValue); xmlrpc_DECREF(mValue); mValue = value.mValue; return *this; } inline xmlrpc_type XmlRpcValue::getType (void) const { return xmlrpc_value_type(mValue); } inline xmlrpc_value *XmlRpcValue::makeReference (void) const { xmlrpc_INCREF(mValue); return mValue; } inline xmlrpc_value *XmlRpcValue::borrowReference (void) const { return mValue; } //========================================================================= // XmlRpcClient //========================================================================= class XMLRPC_OLDCPPWRAPPER_EXPORTED XmlRpcClient { private: std::string mServerUrl; public: static void Initialize (std::string appname, std::string appversion); static void Terminate (void); XmlRpcClient (const std::string& server_url) : mServerUrl(server_url) {} ~XmlRpcClient (void) {} XmlRpcClient (const XmlRpcClient& client); XmlRpcClient& operator= (const XmlRpcClient& client); XmlRpcValue call (std::string method_name, XmlRpcValue param_array); void call_asynch (std::string method_name, XmlRpcValue param_array, xmlrpc_response_handler callback, void* user_data); void event_loop_asynch (unsigned long milliseconds); }; inline void XmlRpcClient::call_asynch(std::string method_name, XmlRpcValue param_array, xmlrpc_response_handler callback, void* user_data) { xmlrpc_client_call_asynch_params( mServerUrl.c_str(), method_name.c_str(), callback, user_data, param_array.borrowReference()); } inline void XmlRpcClient::event_loop_asynch(unsigned long milliseconds) { xmlrpc_client_event_loop_finish_asynch_timeout(milliseconds); } //========================================================================= // XmlRpcClient Methods //========================================================================= // These are inline for now, so we don't need to screw with linker issues // and build a separate client library. inline XmlRpcClient::XmlRpcClient (const XmlRpcClient& client) : mServerUrl(client.mServerUrl) { } inline XmlRpcClient& XmlRpcClient::operator= (const XmlRpcClient& client) { if (this != &client) mServerUrl = client.mServerUrl; return *this; } inline void XmlRpcClient::Initialize (std::string appname, std::string appversion) { xmlrpc_client_init(XMLRPC_CLIENT_NO_FLAGS, appname.c_str(), appversion.c_str()); } inline void XmlRpcClient::Terminate (void) { xmlrpc_client_cleanup(); } inline XmlRpcValue XmlRpcClient::call (std::string method_name, XmlRpcValue param_array) { XmlRpcEnv env; xmlrpc_value *result = xmlrpc_client_call_params(env, mServerUrl.c_str(), method_name.c_str(), param_array.borrowReference()); env.throwIfFaultOccurred(); return XmlRpcValue(result, XmlRpcValue::CONSUME_REFERENCE); } //========================================================================= // XmlRpcGenSrv //========================================================================= class XMLRPC_OLDCPPWRAPPER_EXPORTED XmlRpcGenSrv { private: xmlrpc_registry* mRegistry; xmlrpc_mem_block* alloc (XmlRpcEnv& env, const std::string& body) const; public: XmlRpcGenSrv (int flags); ~XmlRpcGenSrv (void); xmlrpc_registry* getRegistry (void) const; XmlRpcGenSrv& addMethod (const std::string& name, xmlrpc_method method, void *data); XmlRpcGenSrv& addMethod (const std::string& name, xmlrpc_method method, void* data, const std::string& signature, const std::string& help); std::string handle (const std::string& body) const; }; inline XmlRpcGenSrv::XmlRpcGenSrv (int) { XmlRpcEnv env; mRegistry = xmlrpc_registry_new (env); env.throwIfFaultOccurred(); } inline XmlRpcGenSrv::~XmlRpcGenSrv (void) { xmlrpc_registry_free (mRegistry); } inline xmlrpc_registry* XmlRpcGenSrv::getRegistry () const { return mRegistry; } // Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. #endif /* _XMLRPCCPP_H_ */ xmlrpc-c-1.33.14/include/xmlrpc-c/oldxmlrpc.h000066400000000000000000000000701236133176700207430ustar00rootroot00000000000000#include #include xmlrpc-c-1.33.14/include/xmlrpc-c/packetsocket.hpp000066400000000000000000000065701236133176700217720ustar00rootroot00000000000000#ifndef PACKETSOCKET_HPP_INCLUDED #define PACKETSOCKET_HPP_INCLUDED /*============================================================================ packetsocket ============================================================================== This is a facility for communicating socket-style, with defined packets like a datagram socket but with reliable delivery like a stream socket. It's like a POSIX "sequential packet" socket, except it is built on top of a stream socket, so it is usable on the many systems that have stream sockets but not sequential packet sockets. ============================================================================*/ #include #include #include #include #include /* XMLRPC_PACKETSOCKET_EXPORTED marks a symbol in this file that is exported from libxmlrpc_packetsocket. XMLRPC_BUILDING_PACKETSOCKET says this compilation is part of libxmlrpc_packetsocket, as opposed to something that _uses_ libxmlrpc_packetsocket. */ #ifdef XMLRPC_BUILDING_PACKETSOCKET #define XMLRPC_PACKETSOCKET_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_PACKETSOCKET_EXPORTED #endif namespace xmlrpc_c { class XMLRPC_PACKETSOCKET_EXPORTED packet : public girmem::autoObject { public: packet(); packet(const unsigned char * const data, size_t const dataLength); packet(const char * const data, size_t const dataLength); ~packet(); unsigned char * getBytes() const { return this->bytes; } size_t getLength() const { return this->length; } void addData(const unsigned char * const data, size_t const dataLength); private: unsigned char * bytes; // malloc'ed size_t length; size_t allocSize; void initialize(const unsigned char * const data, size_t const dataLength); }; class XMLRPC_PACKETSOCKET_EXPORTED packetPtr: public girmem::autoObjectPtr { public: packetPtr(); explicit packetPtr(packet * const packetP); packet * operator->() const; }; class XMLRPC_PACKETSOCKET_EXPORTED packetSocket_impl; class XMLRPC_PACKETSOCKET_EXPORTED packetSocket { /*---------------------------------------------------------------------------- This is an Internet communication vehicle that transmits individual variable-length packets of text. It is based on a stream socket. It would be much better to use a kernel SOCK_SEQPACKET socket, but Linux 2.4 does not have them. -----------------------------------------------------------------------------*/ public: packetSocket(int sockFd); ~packetSocket(); void writeWait(packetPtr const& packetPtr) const; void read(bool * const eofP, bool * const gotPacketP, packetPtr * const packetPP); void readWait(volatile const int * const interruptP, bool * const eofP, bool * const gotPacketP, packetPtr * const packetPP); void readWait(volatile const int * const interruptP, bool * const eofP, packetPtr * const packetPP); void readWait(bool * const eofP, packetPtr * const packetPP); private: packetSocket_impl * implP; }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/registry.hpp000066400000000000000000000136741236133176700211650ustar00rootroot00000000000000#ifndef REGISTRY_HPP_INCLUDED #define REGISTRY_HPP_INCLUDED #include #include #include #include #include #include #include #include namespace xmlrpc_c { /* XMLRPC_SERVERPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc_server++. XMLRPC_BUILDING_SERVERPP says this compilation is part of libxmlrpc_server++, as opposed to something that _uses_ libxmlrpc_server++. */ #ifdef XMLRPC_BUILDING_SERVERPP #define XMLRPC_SERVERPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_SERVERPP_EXPORTED #endif class XMLRPC_SERVERPP_EXPORTED callInfo { /*---------------------------------------------------------------------------- Information about how an XML-RPC call arrived. This base class carries no information; Servers that don't have any call information to provide might use this. Servers that do have call information to provide define a derived class of this that contains information pertinent to that kind of server. -----------------------------------------------------------------------------*/ public: virtual ~callInfo(); // This makes it polymorphic callInfo(); }; class XMLRPC_SERVERPP_EXPORTED method : public girmem::autoObject { /*---------------------------------------------------------------------------- An XML-RPC method. This base class is abstract. You can't create an object in it. Define a useful method with this as a base class, with an execute() method. -----------------------------------------------------------------------------*/ public: method(); virtual ~method(); virtual void execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const resultP) = 0; std::string signature() const { return _signature; }; std::string help() const { return _help; }; protected: std::string _signature; std::string _help; }; /* Example of a specific method class: class sample_add : public xmlrpc_c::method { public: sample_add() { this->_signature = "ii"; this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::param_list const paramList, const xmlrpc_c::value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); *retvalP = xmlrpc_c::value(addend, adder); } }; Example of creating such a method: methodPtr const sampleAddMethodP(new sample_add); You pass around, copy, etc. the handle sampleAddMethodP and when the last copy of the handle is gone, the sample_add object itself gets deleted. */ class XMLRPC_SERVERPP_EXPORTED method2 : public method { /*---------------------------------------------------------------------------- An XML-RPC method. This base class is abstract. You can't create an object in it. Define a useful method with this as a base class, with an execute() method. This differs from class 'method' in that the execute() method gets call information ('callInfo'). -----------------------------------------------------------------------------*/ public: method2(); virtual ~method2(); virtual void execute(xmlrpc_c::paramList const& paramList, const xmlrpc_c::callInfo * const callInfoP, xmlrpc_c::value * const resultP) = 0; void execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const resultP); }; class XMLRPC_SERVERPP_EXPORTED methodPtr : public girmem::autoObjectPtr { public: methodPtr(xmlrpc_c::method * const methodP); xmlrpc_c::method * operator->() const; }; class XMLRPC_SERVERPP_EXPORTED defaultMethod : public girmem::autoObject { public: virtual ~defaultMethod(); virtual void execute(std::string const& methodName, xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const resultP) = 0; }; class XMLRPC_SERVERPP_EXPORTED defaultMethodPtr : public girmem::autoObjectPtr { public: defaultMethodPtr(); defaultMethodPtr(xmlrpc_c::defaultMethod * const methodP); xmlrpc_c::defaultMethod * operator->() const; xmlrpc_c::defaultMethod * get() const; }; struct registry_impl; class XMLRPC_SERVERPP_EXPORTED registry : public girmem::autoObject { /*---------------------------------------------------------------------------- An Xmlrpc-c server method registry. An Xmlrpc-c server transport (e.g. an HTTP server) uses this object to process an incoming Xmlrpc-c call. -----------------------------------------------------------------------------*/ public: registry(); ~registry(); void addMethod(std::string const name, xmlrpc_c::methodPtr const methodP); void setDefaultMethod(xmlrpc_c::defaultMethodPtr const methodP); void disableIntrospection(); class XMLRPC_SERVERPP_EXPORTED shutdown { public: virtual ~shutdown() = 0; virtual void doit(std::string const& comment, void * const callInfo) const = 0; }; void setShutdown(const shutdown * const shutdownP); void setDialect(xmlrpc_dialect const dialect); void processCall(std::string const& callXml, std::string * const responseXmlP) const; void processCall(std::string const& callXml, const xmlrpc_c::callInfo * const callInfoP, std::string * const responseXmlP) const; size_t maxStackSize() const; private: registry_impl * implP; }; class XMLRPC_SERVERPP_EXPORTED registryPtr : public girmem::autoObjectPtr { public: registryPtr(); registryPtr(xmlrpc_c::registry * const registryP); xmlrpc_c::registry * operator->() const; xmlrpc_c::registry * get() const; }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/select_int.h000066400000000000000000000032371236133176700211000ustar00rootroot00000000000000/***************************************************************************** select_int.h ****************************************************************************** This file is the interface header for the OS-independent abstraction of the "select" OS services (i.e. services for waiting for events). Nothing may include this header file that also includes , because it conflicts with this file's use of . Furthermore, nothing including this file may include without previously defining WIN32_LEAN_AND_MEAN, because without that macro includes automatically. *****************************************************************************/ #ifndef SELECT_INT_H_INCLUDED #define SELECT_INT_H_INCLUDED #include #include "xmlrpc-c/c_util.h" #include "xmlrpc-c/time_int.h" #if MSVCRT #include #ifndef sigset_t typedef int sigset_t; #endif #endif /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif XMLRPC_UTIL_EXPORTED int xmlrpc_pselect(int const n, fd_set * const readfdsP, fd_set * const writefdsP, fd_set * const exceptfdsP, const xmlrpc_timespec * const timeoutP, sigset_t * const sigmaskP); #endif xmlrpc-c-1.33.14/include/xmlrpc-c/server.h000066400000000000000000000202211236133176700202450ustar00rootroot00000000000000/* Copyright and license information is at the end of the file */ #ifndef XMLRPC_SERVER_H_INCLUDED #define XMLRPC_SERVER_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif /* XMLRPC_SERVER_EXPORTED marks a symbol in this file that is exported from libxmlrpc_server. XMLRPC_BUILDING_SERVER says this compilation is part of libxmlrpc_server, as opposed to something that _uses_ libxmlrpc_server. */ #ifdef XMLRPC_BUILDING_SERVER #define XMLRPC_SERVER_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_SERVER_EXPORTED #endif typedef struct xmlrpc_registry xmlrpc_registry; typedef void (*xmlrpc_preinvoke_method)(xmlrpc_env * const envP, const char * const methodName, xmlrpc_value * const paramArrayP, void * const userData); typedef xmlrpc_value * (*xmlrpc_method1)(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo); typedef xmlrpc_value * (*xmlrpc_method2)(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo); typedef xmlrpc_method1 xmlrpc_method; /* backward compatibility */ typedef xmlrpc_value * (*xmlrpc_default_method)(xmlrpc_env * const envP, const char * const callInfoP, const char * const methodName, xmlrpc_value * const paramArrayP, void * const serverInfo); /* These are for backward compatibility -- they can't be exported from a Windows DLL. xmlrpc_server_version() is preferred. */ extern unsigned int const xmlrpc_server_version_major; extern unsigned int const xmlrpc_server_version_minor; extern unsigned int const xmlrpc_server_version_point; XMLRPC_SERVER_EXPORTED void xmlrpc_server_version(unsigned int * const majorP, unsigned int * const minorP, unsigned int * const pointP); XMLRPC_SERVER_EXPORTED xmlrpc_registry * xmlrpc_registry_new(xmlrpc_env * const envP); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_free(xmlrpc_registry * const registryP); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_disable_introspection(xmlrpc_registry * const registryP); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_add_method(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const host, const char * const methodName, xmlrpc_method const method, void * const serverInfo); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_add_method_w_doc(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const host, const char * const methodName, xmlrpc_method const method, void * const serverInfo, const char * const signatureString, const char * const help); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_add_method2(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const methodName, xmlrpc_method2 method, const char * const signatureString, const char * const help, void * const serverInfo); struct xmlrpc_method_info3 { const char * methodName; xmlrpc_method2 methodFunction; void * serverInfo; size_t stackSize; const char * signatureString; const char * help; }; XMLRPC_SERVER_EXPORTED void xmlrpc_registry_add_method3( xmlrpc_env * const envP, xmlrpc_registry * const registryP, const struct xmlrpc_method_info3 * const infoP); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_set_default_method(xmlrpc_env * const envP, xmlrpc_registry * const registryP, xmlrpc_default_method const handler, void * const userData); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_set_preinvoke_method(xmlrpc_env * const envP, xmlrpc_registry * const registryP, xmlrpc_preinvoke_method const method, void * const userData); typedef void xmlrpc_server_shutdown_fn(xmlrpc_env * const envP, void * const context, const char * const comment, void * const callInfo); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_set_shutdown(xmlrpc_registry * const registryP, xmlrpc_server_shutdown_fn * const shutdownFn, void * const context); XMLRPC_SERVER_EXPORTED void xmlrpc_registry_set_dialect(xmlrpc_env * const envP, xmlrpc_registry * const registryP, xmlrpc_dialect const dialect); /*---------------------------------------------------------------------------- Lower interface -- services to be used by an HTTP request handler -----------------------------------------------------------------------------*/ XMLRPC_SERVER_EXPORTED void xmlrpc_registry_process_call2(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const xmlData, size_t const xmlLen, void * const callInfo, xmlrpc_mem_block ** const outputPP); XMLRPC_SERVER_EXPORTED xmlrpc_mem_block * xmlrpc_registry_process_call(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const host, const char * const xmlData, size_t const xmlLen); XMLRPC_SERVER_EXPORTED size_t xmlrpc_registry_max_stackSize(xmlrpc_registry * const registryP); #ifdef __cplusplus } #endif /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #endif xmlrpc-c-1.33.14/include/xmlrpc-c/server_abyss.h000066400000000000000000000351411236133176700214550ustar00rootroot00000000000000/*============================================================================ server_abyss.h ============================================================================== This declares the user interface to libxmlrpc_server_abyss, which provides facilities for running an XML-RPC server based on the Xmlrpc-c Abyss HTTP server. Nothing may include this header file that also includes , because it conflicts with this file's use of . Furthermore, nothing including this file may include without previously defining WIN32_LEAN_AND_MEAN, because without that macro includes automatically. ============================================================================*/ /* Copyright and license information is at the end of the file */ #ifndef XMLRPC_SERVER_ABYSS_H_INCLUDED #define XMLRPC_SERVER_ABYSS_H_INCLUDED #ifdef _WIN32 /* See restriction above concerning windows.h and winsock.h */ # include /* For XMLRPC_SOCKET (= SOCKET) */ # include #endif #include /* For XMLRPC_SOCKET */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* XMLRPC_SERVER_ABYSS_EXPORTED marks a symbol in this file that is exported from libxmlrpc_server_abyss. XMLRPC_BUILDING_SERVER_ABYSS says this compilation is part of libxmlrpc_server_abyss, as opposed to something that _uses_ libxmlrpc_server_abyss. */ #ifdef XMLRPC_BUILDING_SERVER_ABYSS #define XMLRPC_SERVER_ABYSS_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_SERVER_ABYSS_EXPORTED #endif #define XMLRPC_SERVER_ABYSS_NO_FLAGS (0) /*========================================================================= ** Global Initialization/Termination. ** ** These are not thread-safe. You call them at the beginning and end ** of your program, when it is only one thread. **=======================================================================*/ XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_global_init(xmlrpc_env * const envP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_global_term(void); /*========================================================================= ** Basic Abyss Server Functions **=======================================================================*/ typedef void ((*runfirstFn)(void *)); typedef struct { const char * config_file_name; /* NULL to use preferred proper API-level interface */ xmlrpc_registry * registryP; /* runfirstFn and runfirst_arg are meaningless when config_file_name is NULL */ runfirstFn runfirst; void * runfirst_arg; unsigned int port_number; const char * log_file_name; unsigned int keepalive_timeout; unsigned int keepalive_max_conn; unsigned int timeout; xmlrpc_bool dont_advertise; xmlrpc_bool socket_bound; XMLRPC_SOCKET socket_handle; const char * uri_path; xmlrpc_bool chunk_response; xmlrpc_bool enable_shutdown; const char * allow_origin; xmlrpc_bool access_ctl_expires; unsigned int access_ctl_max_age; const struct sockaddr * sockaddr_p; socklen_t sockaddrlen; unsigned int max_conn; unsigned int max_conn_backlog; } xmlrpc_server_abyss_parms; #define XMLRPC_APSIZE(MBRNAME) \ XMLRPC_STRUCTSIZE(xmlrpc_server_abyss_parms, MBRNAME) /* XMLRPC_APSIZE(xyz) is the minimum size a struct xmlrpc_server_abyss_parms must be to include the 'xyz' member. This is essential to forward and backward compatibility, as new members will be added to the end of the struct in future releases. This is how the callee knows whether or not the caller is new enough to have supplied a certain parameter. */ /*========================================================================= ** Simple server with Abyss under the covers **=======================================================================*/ XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parms, unsigned int const parmSize); /*========================================================================= ** Object-oriented XML-RPC server with Abyss under the covers **=======================================================================*/ typedef struct xmlrpc_server_abyss xmlrpc_server_abyss_t; XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_create(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize, xmlrpc_server_abyss_t ** const serverPP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_destroy(xmlrpc_server_abyss_t * const serverP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_run_server(xmlrpc_env * const envP, xmlrpc_server_abyss_t * const serverP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_terminate(xmlrpc_env * const envP, xmlrpc_server_abyss_t * const serverP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_reset_terminate(xmlrpc_env * const envP, xmlrpc_server_abyss_t * const serverP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_use_sigchld(xmlrpc_server_abyss_t * const serverP); typedef struct xmlrpc_server_abyss_sig xmlrpc_server_abyss_sig; XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_setup_sig( xmlrpc_env * const envP, xmlrpc_server_abyss_t * const serverP, xmlrpc_server_abyss_sig ** const oldHandlersPP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_restore_sig( const xmlrpc_server_abyss_sig * const oldHandlersP); /*========================================================================= ** Functions to make an XML-RPC server out of your own Abyss server **=======================================================================*/ typedef void xmlrpc_call_processor(xmlrpc_env * const envP, void * const processorArg, const char * const callXml, size_t const callXmlLen, TSession * const abyssSessionP, xmlrpc_mem_block ** const responseXmlPP); typedef struct { xmlrpc_call_processor * xml_processor; void * xml_processor_arg; size_t xml_processor_max_stack; const char * uri_path; xmlrpc_bool chunk_response; const char * allow_origin; /* NULL means don't answer HTTP access control query */ xmlrpc_bool access_ctl_expires; unsigned int access_ctl_max_age; } xmlrpc_server_abyss_handler_parms; #define XMLRPC_AHPSIZE(MBRNAME) \ XMLRPC_STRUCTSIZE(xmlrpc_server_abyss_handler_parms, MBRNAME) /* XMLRPC_AHPSIZE(xyz) is the minimum size a struct xmlrpc_server_abyss_handler_parms must be to include the 'xyz' member. This is essential to forward and backward compatibility, as new members will be added to the end of the struct in future releases. This is how the callee knows whether or not the caller is new enough to have supplied a certain parameter. */ XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_set_handler3( xmlrpc_env * const envP, TServer * const srvP, const xmlrpc_server_abyss_handler_parms * const parms, unsigned int const parmSize); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_set_handler2( TServer * const srvP, const char * const uriPath, xmlrpc_call_processor xmlProcessor, void * const xmlProcessorArg, size_t const xmlProcessorMaxStackSize, xmlrpc_bool const chunkResponse); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_set_handlers2(TServer * const srvP, const char * const filename, xmlrpc_registry * const registryP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_set_handlers(TServer * const serverP, xmlrpc_registry * const registryP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_set_handler(xmlrpc_env * const envP, TServer * const serverP, const char * const filename, xmlrpc_registry * const registryP); XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_set_default_handler(TServer * const serverP); /*========================================================================= ** Handy Abyss Extensions **=======================================================================*/ /* These are functions that have nothing to do with Xmlrpc-c, but provide convenient Abyss services beyond those provided by the Abyss library. */ /* Start an Abyss webserver running (previously created and ** initialized). Under Unix, this routine will attempt to do a ** detaching fork, drop root privileges (if any) and create a pid ** file. Under Windows, this routine merely starts the server. This ** routine never returns. ** ** Once you call this routine, it is illegal to modify the server any ** more, including changing any method registry. */ XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_run(void); /* Same as xmlrpc_server_abyss_run(), except you get to specify a "runfirst" ** function. The server runs this just before executing the actual server ** function, after any daemonizing. NULL for 'runfirst' means no runfirst ** function. 'runfirstArg' is the argument the server passes to the runfirst ** function. **/ XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_run_first(runfirstFn const runfirst, void * const runfirstArg); /*========================================================================= ** Method Registry **========================================================================= These functions are for the built-in xmlrpc_server_abyss registry. It's usually simpler to skip all this and use the regular method registry services (from xmlrpc_server.h) to build a registry and pass it to xmlrpc_server_abyss. */ /* Call this function to create a new Abyss webserver with the default ** options and the built-in method registry. If you've already ** initialized Abyss using Abyss functions, you can instead call ** xmlrpc_server_abyss_init_registry() to make it an Xmlrpc-c server. ** Or use a regular method registry and call ** xmlrpc_server_abyss_set_handlers(). **/ XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_init(int const flags, const char * const config_file); /* This is called automatically by xmlrpc_server_abyss_init. */ XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_init_registry (void); /* Fetch the internal registry, if you happen to need it. If you're using this, you really shouldn't be using the built-in registry at all. It exists today only for backward compatibilty. */ XMLRPC_SERVER_ABYSS_EXPORTED extern xmlrpc_registry * xmlrpc_server_abyss_registry (void); /* A quick & easy shorthand for adding a method. Depending on ** how you've configured your copy of Abyss, it's probably not safe to ** call this method after calling xmlrpc_server_abyss_run. */ XMLRPC_SERVER_ABYSS_EXPORTED void xmlrpc_server_abyss_add_method (char * const method_name, xmlrpc_method const method, void * const user_data); /* As above, but provide documentation (see xmlrpc_registry_add_method_w_doc ** for more information). You should really use this one. */ XMLRPC_SERVER_ABYSS_EXPORTED extern void xmlrpc_server_abyss_add_method_w_doc (char * const method_name, xmlrpc_method const method, void * const user_data, char * const signature, char * const help); /*========================================================================= ** Content Handlers **=======================================================================*/ /* Abyss contents handlers xmlrpc_server_abyss_rpc2_handler() and xmlrpc_server_abyss_default_handler() were available in older Xmlrpc-c, but starting with Release 1.01, they are not. Instead, call xmlrpc_server_abyss_set_handlers() to install them. Alternatively, you can write your own handlers that do the same thing. It's not hard, and if you're writing low enough level Abyss code that you can't use xmlrpc_server_abyss_set_handlers(), you probably want to anyway. */ #ifdef __cplusplus } #endif /* __cplusplus */ /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #endif xmlrpc-c-1.33.14/include/xmlrpc-c/server_abyss.hpp000066400000000000000000000156021236133176700220150ustar00rootroot00000000000000/*============================================================================ server_abyss.hpp ============================================================================== This declares the user interface to libxmlrpc_server_abyss++, which provides facilities for running a C++ XML-RPC server based on the Xmlrpc-c Abyss HTTP server. Nothing may include this header file that also includes , because it conflicts with this file's use of . Furthermore, nothing including this file may include without previously defining WIN32_LEAN_AND_MEAN, because without that macro includes automatically. ============================================================================*/ #ifndef SERVER_ABYSS_HPP_INCLUDED #define SERVER_ABYSS_HPP_INCLUDED #ifdef _WIN32 /* See restrictions above on including and */ # include // For XMLRPC_SOCKET (= SOCKET) # include #endif #include // For XMLRPC_SOCKET #include #include #include #include /* XMLRPC_SERVER_ABYSSPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc_server_abyss++. XMLRPC_BUILDING_SERVER_ABYSSPP says this compilation is part of libxmlrpc_server_abyss++, as opposed to something that _uses_ libxmlrpc_server_abyss++. */ #ifdef XMLRPC_BUILDING_SERVER_ABYSSPP #define XMLRPC_SERVER_ABYSSPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_SERVER_ABYSSPP_EXPORTED #endif namespace xmlrpc_c { struct serverAbyss_impl; class XMLRPC_SERVER_ABYSSPP_EXPORTED serverAbyss { public: struct constrOpt_impl; class XMLRPC_SERVER_ABYSSPP_EXPORTED constrOpt { public: constrOpt(); ~constrOpt(); constrOpt & registryPtr (xmlrpc_c::registryPtr const& arg); constrOpt & registryP (const xmlrpc_c::registry * const& arg); constrOpt & socketFd (XMLRPC_SOCKET const& arg); constrOpt & portNumber (unsigned int const& arg); constrOpt & maxConn (unsigned int const& arg); constrOpt & maxConnBacklog (unsigned int const& arg); constrOpt & keepaliveTimeout (unsigned int const& arg); constrOpt & keepaliveMaxConn (unsigned int const& arg); constrOpt & timeout (unsigned int const& arg); constrOpt & dontAdvertise (bool const& arg); constrOpt & uriPath (std::string const& arg); constrOpt & chunkResponse (bool const& arg); constrOpt & allowOrigin (std::string const& arg); constrOpt & accessCtlMaxAge (unsigned int const& arg); constrOpt & sockAddrP (const struct sockaddr * const& arg); constrOpt & sockAddrLen (socklen_t const& arg); constrOpt & logFileName (std::string const& arg); constrOpt & serverOwnsSignals (bool const& arg); constrOpt & expectSigchld (bool const& arg); private: struct constrOpt_impl * implP; friend class serverAbyss; }; serverAbyss(constrOpt const& opt); serverAbyss( xmlrpc_c::registry const& registry, unsigned int const portNumber = 8080, std::string const& logFileName = "", unsigned int const keepaliveTimeout = 0, unsigned int const keepaliveMaxConn = 0, unsigned int const timeout = 0, bool const dontAdvertise = false, bool const socketBound = false, XMLRPC_SOCKET const socketFd = 0 ); ~serverAbyss(); void run(); void runOnce(); void runConn(int const socketFd); #ifndef _WIN32 void sigchld(pid_t pid); #endif void terminate(); class XMLRPC_SERVER_ABYSSPP_EXPORTED shutdown : public xmlrpc_c::registry::shutdown { public: shutdown(xmlrpc_c::serverAbyss * const severAbyssP); virtual ~shutdown(); void doit(std::string const& comment, void * const callInfo) const; private: xmlrpc_c::serverAbyss * const serverAbyssP; }; private: serverAbyss_impl * implP; void initialize(constrOpt const& opt); }; class XMLRPC_SERVER_ABYSSPP_EXPORTED callInfo_serverAbyss : public xmlrpc_c::callInfo { /*---------------------------------------------------------------------------- This is information about how an XML-RPC call arrived via an Abyss server. It is available to the user's XML-RPC method execute() method, so for example an XML-RPC method might execute differently depending upon the IP address of the client. This is for a user of a xmlrpc_c::serverAbyss server. -----------------------------------------------------------------------------*/ public: callInfo_serverAbyss(xmlrpc_c::serverAbyss * const abyssServerP, TSession * const abyssSessionP); xmlrpc_c::serverAbyss * const serverAbyssP; // The server that is processing the RPC. TSession * const abyssSessionP; // The HTTP transaction that embodies the RPC. You can ask this // object things like what the IP address of the client is. }; class XMLRPC_SERVER_ABYSSPP_EXPORTED callInfo_abyss : public xmlrpc_c::callInfo { /*---------------------------------------------------------------------------- This is information about how an XML-RPC call arrived via an Abyss server. It is available to the user's XML-RPC method execute() method, so for example an XML-RPC method might execute differently depending upon the IP address of the client. This is for a user with his own Abyss server, using the "set_handlers" routines to make it into an XML-RPC server. -----------------------------------------------------------------------------*/ public: callInfo_abyss(TSession * const abyssSessionP); TSession * abyssSessionP; // The HTTP transaction that embodies the RPC. You can ask this // object things like what the IP address of the client is. }; XMLRPC_SERVER_ABYSSPP_EXPORTED void server_abyss_set_handlers(TServer * const srvP, xmlrpc_c::registry const& registry, std::string const& uriPath = "/RPC2"); XMLRPC_SERVER_ABYSSPP_EXPORTED void server_abyss_set_handlers(TServer * const srvP, const xmlrpc_c::registry * const registryP, std::string const& uriPath = "/RPC2"); XMLRPC_SERVER_ABYSSPP_EXPORTED void server_abyss_set_handlers(TServer * const srvP, xmlrpc_c::registryPtr const registryPtr, std::string const& uriPath = "/RPC2"); } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/server_cgi.h000066400000000000000000000032331236133176700210730ustar00rootroot00000000000000/* Interface header file for libxmlrpc_server_cgi. By Bryan Henderson, 05.04.27. Contributed to the public domain. */ #ifndef XMLRPC_CGI_H_INCLUDED #define XMLRPC_CGI_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* XMLRPC_SERVER_CGI_EXPORTED marks a symbol in this file that is exported from libxmlrpc_server_cgi. XMLRPC_BUILDING_SERVER_CGI says this compilation is part of libxmlrpc_server_cgi, as opposed to something that _uses_ libxmlrpc_server_cgi. */ #ifdef XMLRPC_BUILDING_SERVER_CGI #define XMLRPC_SERVER_CGI_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_SERVER_CGI_EXPORTED #endif XMLRPC_SERVER_CGI_EXPORTED void xmlrpc_server_cgi_process_call(xmlrpc_registry * const registryP); #define XMLRPC_CGI_NO_FLAGS (0) XMLRPC_SERVER_CGI_EXPORTED extern void xmlrpc_cgi_init(int const flags); XMLRPC_SERVER_CGI_EXPORTED extern xmlrpc_registry * xmlrpc_cgi_registry (void); XMLRPC_SERVER_CGI_EXPORTED void xmlrpc_cgi_add_method(const char * const method_name, xmlrpc_method const method, void * const user_data); XMLRPC_SERVER_CGI_EXPORTED void xmlrpc_cgi_add_method_w_doc(const char * const method_name, xmlrpc_method const method, void * const user_data, const char * const signature, const char * const help); XMLRPC_SERVER_CGI_EXPORTED extern void xmlrpc_cgi_process_call (void); XMLRPC_SERVER_CGI_EXPORTED extern void xmlrpc_cgi_cleanup (void); #ifdef __cplusplus } #endif /* __cplusplus */ #endif xmlrpc-c-1.33.14/include/xmlrpc-c/server_cgi.hpp000066400000000000000000000023551236133176700214370ustar00rootroot00000000000000#ifndef SERVER_CGI_HPP_INCLUDED #define SERVER_CGI_HPP_INCLUDED #include #include namespace xmlrpc_c { /* XMLRPC_SERVER_CGIPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc_server_cgi++. XMLRPC_BUILDING_SERVER_CGIPP says this compilation is part of libxmlrpc_server_cgi++, as opposed to something that _uses_ libxmlrpc_server_cgi++. */ #ifdef XMLRPC_BUILDING_SERVER_CGIPP #define XMLRPC_SERVER_CGIPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_SERVER_CGIPP_EXPORTED #endif class XMLRPC_SERVER_CGIPP_EXPORTED serverCgi { public: class XMLRPC_SERVER_CGIPP_EXPORTED constrOpt { public: constrOpt(); constrOpt & registryPtr (xmlrpc_c::registryPtr const& arg); constrOpt & registryP (const xmlrpc_c::registry * const& arg); struct value { xmlrpc_c::registryPtr registryPtr; const xmlrpc_c::registry * registryP; } value; struct { bool registryPtr; bool registryP; } present; }; serverCgi(constrOpt const& opt); ~serverCgi(); void processCall(); private: struct serverCgi_impl * implP; }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/server_pstream.hpp000066400000000000000000000134741236133176700223540ustar00rootroot00000000000000/*============================================================================ server_pstream.hpp ============================================================================== This declares the user interface to libxmlrpc_server_pstream, which provides facilities for running a pseudo-XML-RPC server based on Xmlrpc-c packet stream sockets (i.e. no HTTP). Nothing may include this header file that also includes , because it conflicts with this file's use of . Furthermore, nothing including this file may include without previously defining WIN32_LEAN_AND_MEAN, because without that macro includes automatically. ============================================================================*/ #ifndef SERVER_PSTREAM_HPP_INCLUDED #define SERVER_PSTREAM_HPP_INCLUDED #ifdef _WIN32 /* See restrictions above on including and */ # include /* For XMLRPC_SOCKET (= SOCKET) */ # include #else #include #endif #include /* For XMLRPC_SOCKET */ #include #include #include /* XMLRPC_SERVER_PSTREAMPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc_server_pstream++. XMLRPC_BUILDING_SERVER_PSTREAMPP says this compilation is part of libxmlrpc_server_pstream++, as opposed to something that _uses_ libxmlrpc_server_pstream++. */ #ifdef XMLRPC_BUILDING_SERVER_PSTREAMPP #define XMLRPC_SERVER_PSTREAMPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_SERVER_PSTREAMPP_EXPORTED #endif namespace xmlrpc_c { class XMLRPC_SERVER_PSTREAMPP_EXPORTED serverPstreamConn { public: struct constrOpt_impl; class XMLRPC_SERVER_PSTREAMPP_EXPORTED constrOpt { public: constrOpt(); ~constrOpt(); constrOpt & registryPtr (xmlrpc_c::registryPtr const& arg); constrOpt & registryP (const xmlrpc_c::registry * const& arg); constrOpt & socketFd (XMLRPC_SOCKET const& arg); private: struct constrOpt_impl * implP; friend class serverPstreamConn; }; serverPstreamConn(constrOpt const& opt); ~serverPstreamConn(); void runOnce(xmlrpc_c::callInfo * const callInfoP, volatile const int * const interruptP, bool * const eofP); void runOnce(volatile const int * const interruptP, bool * const eofP); void runOnce(bool * const eofP); void runOnceNoWait(callInfo * const callInfoP, bool * const eofP, bool * const didOneP); void runOnceNoWait(bool * const eofP, bool * const didOneP); void runOnceNoWait(bool * const eofP); void run(xmlrpc_c::callInfo * const callInfoP, volatile const int * const interruptP); void run(volatile const int * const interruptP); void run(); private: struct serverPstreamConn_impl * implP; }; class XMLRPC_SERVER_PSTREAMPP_EXPORTED serverPstream { public: struct constrOpt_impl; class XMLRPC_SERVER_PSTREAMPP_EXPORTED constrOpt { public: constrOpt(); ~constrOpt(); constrOpt & registryPtr (xmlrpc_c::registryPtr const& arg); constrOpt & registryP (const xmlrpc_c::registry * const& arg); constrOpt & socketFd (XMLRPC_SOCKET const& arg); private: struct constrOpt_impl * implP; friend class serverPstream; }; serverPstream(constrOpt const& opt); virtual ~serverPstream(); // This makes it polymorphic void runSerial(volatile const int * const interruptP); void runSerial(); void terminate(); class shutdown : public xmlrpc_c::registry::shutdown { public: shutdown(xmlrpc_c::serverPstream * const severAbyssP); virtual ~shutdown(); void doit(std::string const& comment, void * const callInfo) const; private: xmlrpc_c::serverPstream * const serverPstreamP; }; private: struct serverPstream_impl * implP; }; // Note: there is no xmlrpc_c::callInfo_serverPstreamConn . That's // because the serverPstreamConn server is so low-level that the user // defines his own derived class of xmlrpc_c::callInfo. He creates an // object of that class and passes it to the 'runOnce' method. The // server then passes it on through to the user's XML-RPC method // execute() method. class XMLRPC_SERVER_PSTREAMPP_EXPORTED callInfo_serverPstream : public xmlrpc_c::callInfo { /*---------------------------------------------------------------------------- This is information about how an XML-RPC call arrived to the server. It is available to the user's XML-RPC method execute() method, so for example an XML-RPC method might execute differently depending upon the IP address of the client. This is for a user of a xmlrpc_c::serverPstream server. -----------------------------------------------------------------------------*/ public: callInfo_serverPstream( xmlrpc_c::serverPstream * const serverP, struct sockaddr const clientAddr, socklen_t const clientAddrSize); xmlrpc_c::serverPstream * const serverP; // The server that is processing the RPC. struct sockaddr const clientAddr; // The address (typically, IP address and TCP port) of the XML-RPC // client. This is a Unix OS type. socklen_t const clientAddrSize; // Size in bytes of the valid part of 'clientAddr'. (Usually implied // by type of socket, as well as the address type member of // 'clientAddr', but here because it's technically part of the POSIX // socket interface). }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/server_w32httpsys.h000066400000000000000000000105711236133176700224060ustar00rootroot00000000000000/* Copyright (C) 2005 by Steven A. Bone, sbone@pobox.com. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /* COMPILATION NOTE: Note that the Platform SDK headers and link libraries for Windows XP SP2 or newer are required to compile xmlrpc-c for this module. If you are not using this server, it is safe to exclude the xmlrpc_server_w32httpsys.c file from the xmlrpc project and these dependencies will not be required. You can get the latest platform SDK at http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ Be sure after installation to choose the program to "register the PSDK directories with Visual Studio" so the newer headers are found. */ #ifndef _XMLRPC_SERVER_HTTPSYS_H_ #define _XMLRPC_SERVER_HTTPSYS_H_ 1 #include "c_util.h" #include "transport_config.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* XMLRPC_SERVER_HTTPSYS_EXPORTED marks a symbol in this file that is exported from libxmlrpc_server_httpsys. XMLRPC_BUILDING_SERVER_HTTPSYS says this compilation is part of libxmlrpc_server_httpsys, as opposed to something that _uses_ libxmlrpc_server_httpsys. */ #ifdef XMLRPC_BUILDING_SERVER_HTTPSYS #define XMLRPC_SERVER_HTTPSYS_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_SERVER_HTTPSYS_EXPORTED #endif /*========================================================================= ** XML-RPC Server (based on HTTP.SYS) **========================================================================= ** A simple XML-RPC server based on the "built-in" Windows web server, ** HTTP.SYS. This is provided by Microsoft in Windows XP SP2 and ** Windows Server 2003. If errors occur during server setup, the server ** will exit. In general, if you want to use this API, you do not really ** need to be familiar with the HTTP.SYS API. */ typedef void (*authorization_function)( xmlrpc_env * envP, char * userid, char * password); typedef struct { xmlrpc_registry * registryP; unsigned int portNum; unsigned int useSSL; /* useSSL, 0 = no SSL, 1 = use SSL */ unsigned int logLevel; /* logLevel, 0 = none, 1 = file, 2 = file+OutputDebugString() */ const char * logFile; /* logFile, NULL or filename */ authorization_function authfn; } xmlrpc_server_httpsys_parms; #define XMLRPC_HSSIZE(MBRNAME) \ XMLRPC_STRUCTSIZE(xmlrpc_server_httpsys_parms, MBRNAME) /* XMLRPC_HSSIZE(xyz) is the minimum size a struct xmlrpc_server_httpsys_parms must be to include the 'xyz' member. This is essential for forward and backward compatbility, as new members will be added to the end of the struct in future releases. This is how the callee knows whether or not the caller is new enough to have supplied a certain parameter. */ XMLRPC_SERVER_HTTPSYS_EXPORTED void xmlrpc_server_httpsys( xmlrpc_env * const envP, const xmlrpc_server_httpsys_parms * const parmsP, unsigned int const parm_size ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif xmlrpc-c-1.33.14/include/xmlrpc-c/sleep_int.h000066400000000000000000000011201236133176700207160ustar00rootroot00000000000000#ifndef SLEEP_INT_H_INCLUDED #define SLEEP_INT_H_INCLUDED #include "xmlrpc-c/c_util.h" #ifdef __cplusplus extern "C" { #endif /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif XMLRPC_UTIL_EXPORTED void xmlrpc_millisecond_sleep(unsigned int const milliseconds); #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/string_int.h000066400000000000000000000065411236133176700211300ustar00rootroot00000000000000#ifndef XMLRPC_C_STRING_INT_H_INCLUDED #define XMLRPC_C_STRING_INT_H_INCLUDED #include #include #include "xmlrpc_config.h" #include "c_util.h" #include "bool.h" #ifdef __cplusplus extern "C" { #endif /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif XMLRPC_UTIL_EXPORTED bool xmlrpc_strnomem(const char * const string); XMLRPC_UTIL_EXPORTED const char * xmlrpc_strnomemval(void); XMLRPC_UTIL_EXPORTED void xmlrpc_vasprintf(const char ** const retvalP, const char * const fmt, va_list varargs); XMLRPC_UTIL_EXPORTED void XMLRPC_PRINTF_ATTR(2,3) xmlrpc_asprintf(const char ** const retvalP, const char * const fmt, ...); XMLRPC_UTIL_EXPORTED const char * xmlrpc_strdupsol(const char * const string); XMLRPC_UTIL_EXPORTED void xmlrpc_strfree(const char * const string); XMLRPC_UTIL_EXPORTED const char * xmlrpc_strdupnull(const char * const string); XMLRPC_UTIL_EXPORTED void xmlrpc_strfreenull(const char * const string); static __inline__ bool xmlrpc_streq(const char * const a, const char * const b) { return (strcmp(a, b) == 0); } static __inline__ bool xmlrpc_memeq(const void * const a, const void * const b, size_t const size) { return (memcmp(a, b, size) == 0); } /* strcasecmp doesn't exist on some systems without _BSD_SOURCE, so xmlrpc_strcaseeq() can't either. */ #ifdef _BSD_SOURCE static __inline__ bool xmlrpc_strcaseeq(const char * const a, const char * const b) { #if HAVE_STRCASECMP return (strcasecmp(a, b) == 0); #elif HAVE__STRICMP return (_stricmp(a, b) == 0); #elif HAVE_STRICMP return (stricmp(a, b) == 0); #else #error "This platform has no known case-independent string compare fn" #endif } #endif static __inline__ bool xmlrpc_strneq(const char * const a, const char * const b, size_t const len) { return (strncmp(a, b, len) == 0); } XMLRPC_UTIL_EXPORTED const char * xmlrpc_makePrintable(const char * const input); XMLRPC_UTIL_EXPORTED const char * xmlrpc_makePrintable_lp(const char * const input, size_t const inputLength); XMLRPC_UTIL_EXPORTED const char * xmlrpc_makePrintableChar(char const input); /*----------------------------------------------------------------*/ /* Standard string functions with destination array size checking */ /*----------------------------------------------------------------*/ #define STRSCPY(A,B) \ (strncpy((A), (B), sizeof(A)), *((A)+sizeof(A)-1) = '\0') #define STRSCMP(A,B) \ (strncmp((A), (B), sizeof(A))) #define STRSCAT(A,B) \ (strncat((A), (B), sizeof(A)-strlen(A)), *((A)+sizeof(A)-1) = '\0') /* We could do this, but it works only in GNU C #define SSPRINTF(TARGET, REST...) \ (snprintf(TARGET, sizeof(TARGET) , ## REST)) Or this, but it works only in C99 compilers, which leaves out MSVC before 2005 and can't handle the zero variable argument case except by an MSVC extension: #define SSPRINTF(TARGET, ...) \ (snprintf(TARGET, sizeof(TARGET) , __VA_ARGS__)) */ #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/string_number.h000066400000000000000000000013021236133176700216140ustar00rootroot00000000000000#ifndef STRING_NUMBER_H_INCLUDED #define STRING_NUMBER_H_INCLUDED #include #include #ifdef __cplusplus extern "C" { #endif /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif XMLRPC_UTIL_EXPORTED void xmlrpc_parse_int64(xmlrpc_env * const envP, const char * const str, xmlrpc_int64 * const i64P); #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/time_int.h000066400000000000000000000022341236133176700205530ustar00rootroot00000000000000#ifndef TIME_H_INCLUDED #define TIME_H_INCLUDED #include #include "xmlrpc_config.h" #include "xmlrpc-c/util.h" #include "int.h" /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif #if HAVE_TIMESPEC # include /* for struct timespec */ typedef struct timespec xmlrpc_timespec; #else typedef struct { uint32_t tv_sec; uint32_t tv_nsec; } xmlrpc_timespec; #endif XMLRPC_UTIL_EXPORTED void xmlrpc_gettimeofday(xmlrpc_timespec * const todP); XMLRPC_UTIL_EXPORTED void xmlrpc_timegm(const struct tm * const brokenTime, time_t * const timeValueP, const char ** const errorP); XMLRPC_UTIL_EXPORTED void xmlrpc_localtime(time_t const datetime, struct tm * const tmP); XMLRPC_UTIL_EXPORTED void xmlrpc_gmtime(time_t const datetime, struct tm * const resultP); #endif xmlrpc-c-1.33.14/include/xmlrpc-c/timeout.hpp000066400000000000000000000014021236133176700207650ustar00rootroot00000000000000#ifndef XMLRPC_TIMEOUT_H_INCLUDED #define XMLRPC_TIMEOUT_H_INCLUDED #include /* XMLRPC_LIBPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc++. XMLRPC_BUILDING_LIBPP says this compilation is part of libxmlrpc++, as opposed to something that _uses_ libxmlrpc++. */ #ifdef XMLRPC_BUILDING_LIBPP #define XMLRPC_LIBPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_LIBPP_EXPORTED #endif namespace xmlrpc_c { struct XMLRPC_LIBPP_EXPORTED timeout { timeout() : finite(false) {} timeout(unsigned int const duration) : finite(true), duration(duration) {} // 'duration' is the timeout time in milliseconds bool finite; unsigned int duration; // in milliseconds }; } // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/transport.h000066400000000000000000000063601236133176700210030ustar00rootroot00000000000000/* Copyright information is at the end of the file */ #ifndef XMLRPC_TRANSPORT_H_INCLUDED #define XMLRPC_TRANSPORT_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #include #include struct xmlrpc_call_info; struct xmlrpc_client_transport; /*========================================================================= ** Transport function type declarations. **========================================================================= */ typedef void (*xmlrpc_transport_setup)(xmlrpc_env * const envP); typedef void (*xmlrpc_transport_teardown)(void); typedef void (*xmlrpc_transport_create)( xmlrpc_env * const envP, int const flags, const char * const appname, const char * const appversion, const void * const transportparmsP, size_t const transportparm_size, struct xmlrpc_client_transport ** const handlePP); typedef void (*xmlrpc_transport_destroy)( struct xmlrpc_client_transport * const clientTransportP); typedef void (*xmlrpc_transport_asynch_complete)( struct xmlrpc_call_info * const callInfoP, xmlrpc_mem_block * const responseXmlP, xmlrpc_env const env); typedef void (*xmlrpc_transport_progress)( struct xmlrpc_call_info * const callInfoP, struct xmlrpc_progress_data const data); typedef void (*xmlrpc_transport_send_request)( xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const xmlP, xmlrpc_transport_asynch_complete complete, xmlrpc_transport_progress progress, struct xmlrpc_call_info * const callInfoP); typedef void (*xmlrpc_transport_call)( xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const xmlP, xmlrpc_mem_block ** const responsePP); typedef enum {timeout_no, timeout_yes} xmlrpc_timeoutType; typedef unsigned long xmlrpc_timeout; /* A timeout in milliseconds. */ typedef void (*xmlrpc_transport_finish_asynch)( struct xmlrpc_client_transport * const clientTransportP, xmlrpc_timeoutType const timeoutType, xmlrpc_timeout const timeout); typedef void (*xmlrpc_transport_set_interrupt)( struct xmlrpc_client_transport * const clientTransportP, int * const interruptP); struct xmlrpc_client_transport_ops { xmlrpc_transport_setup setup_global_const; xmlrpc_transport_teardown teardown_global_const; xmlrpc_transport_create create; xmlrpc_transport_destroy destroy; xmlrpc_transport_send_request send_request; xmlrpc_transport_call call; xmlrpc_transport_finish_asynch finish_asynch; xmlrpc_transport_set_interrupt set_interrupt; }; extern int xmlrpc_trace_transport; // This is nonzero to indicate that client XML transport logic should // be traced. #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/util.h000066400000000000000000000323331236133176700177230ustar00rootroot00000000000000/*============================================================================= xmlrpc-c/util.h =============================================================================== This is the interface to the libxmlrpc_util library, which contains utility routines that have nothing to do with XML-RPC. The library exists primarily because other Xmlrpc-c libraries use the utilities, but the utilities are also documented for use by Xmlrpc-c users. For use by Xmlrpc-c users, they are considered to be part of the libxmlrpc library. libxmlrpc_util is a prerequisite of libxmlrpc. By Bryan Henderson, San Jose, CA 05.09.21. Contributed to the public domain by its author. =============================================================================*/ #ifndef XMLRPC_C_UTIL_H_INCLUDED #define XMLRPC_C_UTIL_H_INCLUDED #include #include #include /* Defines XMLRPC_HAVE_WCHAR */ #include /* for XMLRPC_PRINTF_ATTR */ #if XMLRPC_HAVE_WCHAR #include #endif #ifdef __cplusplus extern "C" { #endif /* XMLRPC_UTIL_EXPORTED marks a symbol in this file that is exported from libxmlrpc_util. XMLRPC_BUILDING_UTIL says this compilation is part of libxmlrpc_util, as opposed to something that _uses_ libxmlrpc_util. */ #ifdef XMLRPC_BUILDING_UTIL #define XMLRPC_UTIL_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_UTIL_EXPORTED #endif /*========================================================================= ** C struct size computations **=======================================================================*/ /* Use XMLRPC_STRUCT_MEMBER_SIZE() to determine how big a structure is up to and including a specified member. E.g. if you have struct mystruct {int red; int green; int blue};, then XMLRPC_STRUCT_MEMBER_SIZE(mystruct, green) is (8). */ #define _XMLRPC_STRUCT_MEMBER_OFFSET(TYPE, MBRNAME) \ ((size_t)(char*)&((TYPE *)0)->MBRNAME) #define _XMLRPC_STRUCT_MEMBER_SIZE(TYPE, MBRNAME) \ sizeof(((TYPE *)0)->MBRNAME) #define XMLRPC_STRUCTSIZE(TYPE, MBRNAME) \ (_XMLRPC_STRUCT_MEMBER_OFFSET(TYPE, MBRNAME) + \ _XMLRPC_STRUCT_MEMBER_SIZE(TYPE, MBRNAME)) /*========================================================================= ** Assertions and Debugging **========================================================================= ** Note that an assertion is _not_ a directive to check a condition and ** crash if it isn't true. It is an assertion that the condition _is_ ** true. This assertion helps people to read the code. The program ** may also check the assertion as it runs, and if it conflicts with reality, ** recognize that the program is incorrect and abort it. In practice, ** it does this checking when the program was compiled without the NDEBUG ** macro defined. */ #ifndef NDEBUG #define XMLRPC_ASSERT(cond) \ do \ if (!(cond)) \ xmlrpc_assertion_failed(__FILE__, __LINE__); \ while (0) #else #define XMLRPC_ASSERT(cond) while (0) {} #endif XMLRPC_UTIL_EXPORTED void xmlrpc_assertion_failed(const char * const fileName, int const lineNumber); /* Validate a pointer. */ #define XMLRPC_ASSERT_PTR_OK(ptr) \ XMLRPC_ASSERT((ptr) != NULL) /*========================================================================= ** xmlrpc_env **========================================================================= ** XML-RPC represents runtime errors as elements. These contain ** and elements. ** ** Since we need as much thread-safety as possible, we borrow an idea from ** CORBA--we store exception information in an "environment" object. ** You'll pass this to many different functions, and it will get filled ** out appropriately. ** ** For example: ** ** xmlrpc_env env; ** ** xmlrpc_env_init(&env); ** ** xmlrpc_do_something(&env); ** if (env.fault_occurred) ** report_error_appropriately(); ** ** xmlrpc_env_clean(&env); */ #define XMLRPC_INTERNAL_ERROR (-500) #define XMLRPC_TYPE_ERROR (-501) #define XMLRPC_INDEX_ERROR (-502) #define XMLRPC_PARSE_ERROR (-503) #define XMLRPC_NETWORK_ERROR (-504) #define XMLRPC_TIMEOUT_ERROR (-505) #define XMLRPC_NO_SUCH_METHOD_ERROR (-506) #define XMLRPC_REQUEST_REFUSED_ERROR (-507) #define XMLRPC_INTROSPECTION_DISABLED_ERROR (-508) #define XMLRPC_LIMIT_EXCEEDED_ERROR (-509) #define XMLRPC_INVALID_UTF8_ERROR (-510) typedef struct _xmlrpc_env { int fault_occurred; int fault_code; char * fault_string; } xmlrpc_env; /* Initialize and destroy the contents of the provided xmlrpc_env object. ** These functions will never fail. */ XMLRPC_UTIL_EXPORTED void xmlrpc_env_init (xmlrpc_env* env); XMLRPC_UTIL_EXPORTED void xmlrpc_env_clean (xmlrpc_env* const env); /* Fill out an xmlrpc_fault with the specified values, and set the ** fault_occurred flag. This function will make a private copy of 'string', ** so you retain responsibility for your copy. */ XMLRPC_UTIL_EXPORTED void xmlrpc_env_set_fault(xmlrpc_env * const env, int const faultCode, const char * const faultDescription); /* The same as the above, but using varargs */ XMLRPC_UTIL_EXPORTED void xmlrpc_set_fault_formatted_v(xmlrpc_env * const envP, int const code, const char * const format, va_list args); /* The same as the above, but using a printf-style format string. */ XMLRPC_UTIL_EXPORTED void xmlrpc_env_set_fault_formatted(xmlrpc_env * const envP, int const code, const char * const format, ...) XMLRPC_PRINTF_ATTR(3,4); /* This one infers XMLRPC_INTERNAL_ERROR and has a shorter name. So a call takes up less source code space. */ XMLRPC_UTIL_EXPORTED void xmlrpc_faultf(xmlrpc_env * const envP, const char * const format, ...) XMLRPC_PRINTF_ATTR(2,3); /* A simple debugging assertion. */ #define XMLRPC_ASSERT_ENV_OK(envP) \ XMLRPC_ASSERT((envP) != NULL && \ (envP->fault_string == NULL) && \ !(envP)->fault_occurred) /* This version must *not* interpret 'str' as a format string, to avoid ** several evil attacks. */ #define XMLRPC_FAIL(env,code,str) \ do { xmlrpc_env_set_fault((env),(code),(str)); goto cleanup; } while (0) #define XMLRPC_FAIL1(env,code,str,arg1) \ do { \ xmlrpc_env_set_fault_formatted((env),(code),(str),(arg1)); \ goto cleanup; \ } while (0) #define XMLRPC_FAIL2(env,code,str,arg1,arg2) \ do { \ xmlrpc_env_set_fault_formatted((env),(code),(str),(arg1),(arg2)); \ goto cleanup; \ } while (0) #define XMLRPC_FAIL3(env,code,str,arg1,arg2,arg3) \ do { \ xmlrpc_env_set_fault_formatted((env),(code), \ (str),(arg1),(arg2),(arg3)); \ goto cleanup; \ } while (0) #if !defined(__cplusplus) #if defined(__GNUC__) #define XMLRPC_FAILF( env, code, fmt, ... ) \ do { \ xmlrpc_env_set_fault_formatted((env), (code), (fmt), \ ##__VA_ARGS__ ); \ goto cleanup; \ } while (0) #endif #endif #define XMLRPC_FAIL_IF_NULL(ptr,env,code,str) \ do { \ if ((ptr) == NULL) \ XMLRPC_FAIL((env),(code),(str)); \ } while (0) #define XMLRPC_FAIL_IF_FAULT(env) \ do { if ((env)->fault_occurred) goto cleanup; } while (0) /*========================================================================= ** xmlrpc_mem_block **========================================================================= ** A resizable chunk of memory. This is mostly used internally, but it is ** also used by the public API in a few places. ** The struct fields are private! */ typedef struct _xmlrpc_mem_block { size_t _size; size_t _allocated; void* _block; } xmlrpc_mem_block; /* Allocate a new xmlrpc_mem_block. */ XMLRPC_UTIL_EXPORTED xmlrpc_mem_block* xmlrpc_mem_block_new (xmlrpc_env* const env, size_t const size); /* Destroy an existing xmlrpc_mem_block, and everything it contains. */ XMLRPC_UTIL_EXPORTED void xmlrpc_mem_block_free (xmlrpc_mem_block* const block); /* Initialize the contents of the provided xmlrpc_mem_block. */ XMLRPC_UTIL_EXPORTED void xmlrpc_mem_block_init (xmlrpc_env* const env, xmlrpc_mem_block* const block, size_t const size); /* Deallocate the contents of the provided xmlrpc_mem_block, but not the ** block itself. */ XMLRPC_UTIL_EXPORTED void xmlrpc_mem_block_clean (xmlrpc_mem_block* const block); /* Get the size and contents of the xmlrpc_mem_block. */ XMLRPC_UTIL_EXPORTED size_t xmlrpc_mem_block_size(const xmlrpc_mem_block * const block); XMLRPC_UTIL_EXPORTED void * xmlrpc_mem_block_contents(const xmlrpc_mem_block * const block); /* Resize an xmlrpc_mem_block, preserving as much of the contents as ** possible. */ XMLRPC_UTIL_EXPORTED void xmlrpc_mem_block_resize (xmlrpc_env* const env, xmlrpc_mem_block* const block, size_t const size); /* Append data to an existing xmlrpc_mem_block. */ XMLRPC_UTIL_EXPORTED void xmlrpc_mem_block_append (xmlrpc_env* const env, xmlrpc_mem_block* const block, const void * const data, size_t const len); #define XMLRPC_MEMBLOCK_NEW(type,env,size) \ xmlrpc_mem_block_new((env), sizeof(type) * (size)) #define XMLRPC_MEMBLOCK_FREE(type,block) \ xmlrpc_mem_block_free(block) #define XMLRPC_MEMBLOCK_INIT(type,env,block,size) \ xmlrpc_mem_block_init((env), (block), sizeof(type) * (size)) #define XMLRPC_MEMBLOCK_CLEAN(type,block) \ xmlrpc_mem_block_clean(block) #define XMLRPC_MEMBLOCK_SIZE(type,block) \ (xmlrpc_mem_block_size(block) / sizeof(type)) #define XMLRPC_MEMBLOCK_CONTENTS(type,block) \ ((type*) xmlrpc_mem_block_contents(block)) #define XMLRPC_MEMBLOCK_RESIZE(type,env,block,size) \ xmlrpc_mem_block_resize(env, block, sizeof(type) * (size)) #define XMLRPC_MEMBLOCK_APPEND(type,env,block,data,size) \ xmlrpc_mem_block_append(env, block, data, sizeof(type) * (size)) /* Here are some backward compatibility definitions. These longer names used to be the only ones and typed memory blocks were considered special. */ #define XMLRPC_TYPED_MEM_BLOCK_NEW(type,env,size) \ XMLRPC_MEMBLOCK_NEW(type,env,size) #define XMLRPC_TYPED_MEM_BLOCK_FREE(type,block) \ XMLRPC_MEMBLOCK_FREE(type,block) #define XMLRPC_TYPED_MEM_BLOCK_INIT(type,env,block,size) \ XMLRPC_MEMBLOCK_INIT(type,env,block,size) #define XMLRPC_TYPED_MEM_BLOCK_CLEAN(type,block) \ XMLRPC_MEMBLOCK_CLEAN(type,block) #define XMLRPC_TYPED_MEM_BLOCK_SIZE(type,block) \ XMLRPC_MEMBLOCK_SIZE(type,block) #define XMLRPC_TYPED_MEM_BLOCK_CONTENTS(type,block) \ XMLRPC_MEMBLOCK_CONTENTS(type,block) #define XMLRPC_TYPED_MEM_BLOCK_RESIZE(type,env,block,size) \ XMLRPC_MEMBLOCK_RESIZE(type,env,block,size) #define XMLRPC_TYPED_MEM_BLOCK_APPEND(type,env,block,data,size) \ XMLRPC_MEMBLOCK_APPEND(type,env,block,data,size) /*========================================================================= ** UTF-8 Encoding and Decoding **=======================================================================*/ XMLRPC_UTIL_EXPORTED void xmlrpc_validate_utf8(xmlrpc_env * const envP, const char * const utf8Data, size_t const utf8Len); /* Decode a UTF-8 string. */ XMLRPC_UTIL_EXPORTED xmlrpc_mem_block * xmlrpc_utf8_to_wcs(xmlrpc_env * const envP, const char * const utf8_data, size_t const utf8_len); /* Encode a UTF-8 string. */ #if XMLRPC_HAVE_WCHAR XMLRPC_UTIL_EXPORTED xmlrpc_mem_block * xmlrpc_wcs_to_utf8(xmlrpc_env * const envP, const wchar_t * const wcsData, size_t const wcsLen); #endif XMLRPC_UTIL_EXPORTED void xmlrpc_force_to_utf8(char * const buffer); XMLRPC_UTIL_EXPORTED void xmlrpc_force_to_xml_chars(char * const buffer); /*========================================================================= ** XML-RPC Base64 Utilities **========================================================================= ** Here are some lightweight utilities which can be used to encode and ** decode Base64 data. These are exported mainly for testing purposes. */ /* This routine inserts newlines every 76 characters, as required by the ** Base64 specification. */ XMLRPC_UTIL_EXPORTED xmlrpc_mem_block * xmlrpc_base64_encode(xmlrpc_env * const envP, const unsigned char * const binData, size_t const binLen); /* This routine encodes everything in one line. This is needed for HTTP ** authentication and similar tasks. */ XMLRPC_UTIL_EXPORTED xmlrpc_mem_block * xmlrpc_base64_encode_without_newlines(xmlrpc_env * const envP, const unsigned char * const binData, size_t const binLen); /* This decodes Base64 data with or without newlines. */ XMLRPC_UTIL_EXPORTED extern xmlrpc_mem_block * xmlrpc_base64_decode(xmlrpc_env * const envP, const char * const asciiData, size_t const asciiLen); #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/include/xmlrpc-c/util_int.h000066400000000000000000000012031236133176700205650ustar00rootroot00000000000000#ifndef XMLRPC_C_UTIL_INT_H_INCLUDED #define XMLRPC_C_UTIL_INT_H_INCLUDED /* This file contains facilities for use by Xmlrpc-c code, but not intended to be included in a user compilation. Names in here might conflict with other names in a user's compilation if included in a user compilation. The facilities may change in future releases. */ #include "util.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) /* When we deallocate a pointer in a struct, we often replace it with ** this and throw in a few assertions here and there. */ #define XMLRPC_BAD_POINTER ((void*) 0xDEADBEEF) #endif xmlrpc-c-1.33.14/include/xmlrpc-c/xml.hpp000066400000000000000000000034561236133176700201120ustar00rootroot00000000000000#ifndef XML_HPP_INCLUDED #define XML_HPP_INCLUDED #include #include #include /* XMLRPC_LIBPP_EXPORTED marks a symbol in this file that is exported from libxmlrpc++. XMLRPC_BUILDING_LIBPP says this compilation is part of libxmlrpc++, as opposed to something that _uses_ libxmlrpc++. */ #ifdef XMLRPC_BUILDING_LIBPP #define XMLRPC_LIBPP_EXPORTED XMLRPC_DLLEXPORT #else #define XMLRPC_LIBPP_EXPORTED #endif namespace xmlrpc_c { namespace xml { XMLRPC_LIBPP_EXPORTED void generateCall(std::string const& methodName, xmlrpc_c::paramList const& paramList, std::string * const callXmlP); XMLRPC_LIBPP_EXPORTED void generateCall(std::string const& methodName, xmlrpc_c::paramList const& paramList, xmlrpc_dialect const dialect, std::string * const callXmlP); XMLRPC_LIBPP_EXPORTED void parseCall(std::string const& callXml, std::string * const methodNameP, xmlrpc_c::paramList * const paramListP); XMLRPC_LIBPP_EXPORTED void generateResponse(xmlrpc_c::rpcOutcome const& outcome, xmlrpc_dialect const dialect, std::string * const respXmlP); XMLRPC_LIBPP_EXPORTED void generateResponse(xmlrpc_c::rpcOutcome const& outcome, std::string * const respXmlP); XMLRPC_LIBPP_EXPORTED void parseSuccessfulResponse(std::string const& responseXml, xmlrpc_c::value * const resultP); XMLRPC_LIBPP_EXPORTED void parseResponse(std::string const& responseXml, xmlrpc_c::rpcOutcome * const outcomeP); XMLRPC_LIBPP_EXPORTED void trace(std::string const& label, std::string const& xml); }} // namespace #endif xmlrpc-c-1.33.14/include/xmlrpc-c/xmlparser.h000066400000000000000000000106331236133176700207620ustar00rootroot00000000000000/* Copyright and license information is at the end of the file */ #ifndef XMLRPC_XMLPARSER_H_INCLUDED #define XMLRPC_XMLPARSER_H_INCLUDED /*========================================================================= ** Abstract XML Parser Interface **========================================================================= ** This file provides an abstract interface to the XML parser. For now, ** this interface is implemented by expat, but feel free to change it ** if necessary. */ /*========================================================================= ** xml_element **========================================================================= ** This data structure represents an XML element. We provide no more API ** than we'll need in xmlrpc_parse.c. ** ** The pointers returned by the various accessor methods belong to the ** xml_element structure. Do not free them, and do not use them after ** the xml_element has been destroyed. */ /* You'll need to finish defining struct _xml_element elsewhere. */ typedef struct _xml_element xml_element; /* Destroy an xml_element. */ void xml_element_free (xml_element * const elem); /* Return a pointer to the element's name. Do not free this pointer! ** This pointer should point to standard ASCII or UTF-8 data. */ const char * xml_element_name(const xml_element * const elemP); /* Return the xml_element's CDATA. Do not free this pointer! ** This pointer should point to standard ASCII or UTF-8 data. ** The implementation is allowed to concatenate all the CDATA in the ** element regardless of child elements. Alternatively, if there are ** any child elements, the implementation is allowed to dispose ** of whitespace characters. ** The value returned by xml_element_cdata should be '\0'-terminated ** (although it may contain other '\0' characters internally). ** xml_element_cdata_size should not include the final '\0'. */ size_t xml_element_cdata_size (xml_element *elem); char *xml_element_cdata (xml_element *elem); /* Return the xml_element's child elements. Do not free this pointer! */ size_t xml_element_children_size(const xml_element * const elemP); xml_element ** xml_element_children(const xml_element * const elemP); /*========================================================================= ** xml_parse **========================================================================= ** Parse a chunk of XML data and return the top-level element. If this ** routine fails, it will return NULL and set up the env appropriately. ** You are responsible for calling xml_element_free on the returned pointer. */ void xml_parse(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xml_element ** const resultPP); /* Initialize and terminate static global parser state. This should be done once per run of a program, and while the program is just one thread. */ void xml_init(xmlrpc_env * const envP); void xml_term(void); /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #endif xmlrpc-c-1.33.14/install-sh000077500000000000000000000127361236133176700154360ustar00rootroot00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 xmlrpc-c-1.33.14/irix-common.mk000066400000000000000000000015461236133176700162210ustar00rootroot00000000000000# -*-makefile-*- <-- an Emacs control # See unix-common.mk for an explanation of this file. This file is # analogous to unix-common.mk, but is for an Irix system. SONAME = $(@:%.$(MAJ):%) SHLIB_CMD = $(CCLD) $(LADD) $(LDFLAGS_SHLIB) -o $@ $^ SHLIB_LE_TARGETS = $(call shliblefn, $(SHARED_LIBS_TO_BUILD)) $(SHLIB_LE_TARGETS):%:%.$(MAJ) rm -f $@ $(LN_S) $< $@ .PHONY: $(SHLIB_INSTALL_TARGETS) .PHONY: install-shared-libraries SHLIB_INSTALL_TARGETS = $(SHARED_LIBS_TO_INSTALL:%=%/install) #SHLIB_INSTALL_TARGETS is like "libfoo/install libbar/install" install-shared-libraries: $(SHLIB_INSTALL_TARGETS) $(SHLIB_INSTALL_TARGETS):%/install:%.$(SHLIB_SUFFIX).$(MAJ) # $< is a library file name, e.g. libfoo.so.3.1 . $(INSTALL_SHLIB) $< $(DESTDIR)$(LIBINST_DIR)/$< cd $(DESTDIR)$(LIBINST_DIR); \ rm -f $< $(<:%.$(MAJ)=%); \ $(LN_S) $< $(<:%.$(MAJ)=%) xmlrpc-c-1.33.14/lib/000077500000000000000000000000001236133176700141675ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/Makefile000066400000000000000000000021751236133176700156340ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') SRCDIR := $(call updir,$(CURDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib include $(BLDDIR)/config.mk # Build up SUBDIRS: SUBDIRS = SUBDIRS += util libutil ifeq ($(ENABLE_ABYSS_SERVER),yes) SUBDIRS += abyss endif ifeq ($(MUST_BUILD_WININET_CLIENT),yes) SUBDIRS += wininet_transport endif ifeq ($(MUST_BUILD_CURL_CLIENT),yes) SUBDIRS += curl_transport endif ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) SUBDIRS += libwww_transport endif ifneq ($(ENABLE_LIBXML2_BACKEND),yes) SUBDIRS += expat endif default: all .PHONY: all clean distclean tags distdir install check dep all: $(SUBDIRS:%=%/all) # Extra dependencies to make parallel make work in spite of all the submakes # (See top level make file for details) abyss/all curl_transport/all: $(BLDDIR)/version.h abyss/all expat/all: $(LIBXMLRPC_UTIL) clean: $(SUBDIRS:%=%/clean) clean-common distclean: $(SUBDIRS:%=%/distclean) distclean-common tags: $(SUBDIRS:%=%/tags) TAGS DISTFILES = distdir: distdir-common install: $(SUBDIRS:%=%/install) check: dep: $(SUBDIRS:%=%/dep) include $(SRCDIR)/common.mk xmlrpc-c-1.33.14/lib/abyss/000077500000000000000000000000001236133176700153105ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/abyss/HISTORY000066400000000000000000000104621236133176700163770ustar00rootroot00000000000000Here is some stuff from the README file of the original Abyss source package in 2000. Abyss used to be an independent package and was included in Xmlrpc-c for convenience when Xmlrpc-c was created. Since then, the code has been greatly modified and extended for Xmlrpc-c. The original Abyss project was a product of Moez Mahfoudh mmoez@bigfoot.com. ABYSS Web Server ------------------ About: ------ ABYSS aims to be a fully HTTP/1.1 compliant web server. Its main design goals are speed, low resource usage and portability. ABYSS works on most UNIX based systems and on Win32 systems (Win95/98/2000/NT). Copyright: ---------- Copyright (C) 2000 Moez Mahfoudh. All rights reserved. Status: ------- ABYSS is still in development stage. Actual version is 0.3. Many features are not implemented yet but the server core works well and seems to be stable. It is fully reliable for serving static files on medium load sites. In fact, primary benchmarks show that ABYSS is 70% as fast as Apache when using the fork system. This rate jumps to 130% when using threads. On UNIX platforms, some problems occurred because of the use of the Pthreads library. This will be corrected in the future versions. That's why only the fork system is usable under UNIX. This lowers performances but guarantees stability. CGI/1.1 support is still absent from the current version but will be included in the near future. Change Log: ----------- * Version 0.3 (March 23,2000): o Handles conditional GET requests (by date) o Conforms to all the MUSTs of the RFC2616 (newer version of the HTTP/1.1 protocol draft) o New configuration options (such as pidfile for UNIX systems...) o Handles HEAD and OPTIONS methods o Many bug fixes o Tested on Sun-OS 5.7 o Second public release * Version 0.2 beta (February 7,2000): o Handles GET on static files o Handles correctly range requests o Conforms to 80% of the MUSTs of the RFC2068 (HTTP/1.1 protocol draft) o Improved code portability (Win32 and UNIX platforms) o Tested on Linux 2.2 and Win95/98 o First public release * Version 0.1 (January 2000): o Completely rewritten in C o Speed improvement o New memory allocation scheme (using pools) o Never released * Version 0.0 (January 2000): o Initial version o Written in C++ o Never released Downloading: ------------ * Version 0.3 (current version): o UNIX package (source) abyss-0.3.tar.gz. o Win32 package is not available but you can extract source files from the UNIX package and compile them on Windows without any modification. (Sorry for this inconvenience: I have no Windows machine now to compile the program and to test it. If someone can do that, please email me the zipped package and I'll add it here). * Version 0.2 beta: o UNIX package (source) abyss-0.2b.tar.gz. o Win32 package (source+binary) abyss-0.2b.zip. Installation: ------------- * For UNIX systems: o Untar/Ungzip the distribution package with a command like tar xvfz abyss-x.y.tar.gz o Edit the Makefile src/Makefile to meet your system requirements. o Go to directory src and execute make. o The server binary is generated and stored in the bin directory. o Edit the conf/abyss.conf to reflect your system configuration (At least change the paths). o Goto to the bin directory and start the server by typing ./abyss -c ../conf/abyss.conf * For Win32 systems: o Unzip the distribution package. o An executable file is already present in the bin directory. o If you wish to recompile the server, open the src/abyss.dsw file with Microsoft Visual C++ 5.0 or higher and rebuild the project. o Edit the conf/abyss.conf to reflect your system configuration (At least change the paths). o Goto to the bin directory and start the server by typing ./abyss -c ../conf/abyss.conf To do: ------ * CGI/1.1 support * Web based configuration/administration * Speed improvement * File caching system * Throttling * PUT method handling * ... xmlrpc-c-1.33.14/lib/abyss/Makefile000066400000000000000000000011671236133176700167550ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') LIBDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/abyss include $(BLDDIR)/config.mk SUBDIRS = src default: all .PHONY: all all: $(SUBDIRS:%=%/all) .PHONY: clean clean: $(SUBDIRS:%=%/clean) clean-common .PHONY: distclean distclean: $(SUBDIRS:%=%/distclean) distclean-common .PHONY: tags tags: $(SUBDIRS:%=%/tags) TAGS DISTFILES = .PHONY: distdir distdir: distdir-common .PHONY: install install: $(SUBDIRS:%=%/install) .PHONY: dep dep: $(SUBDIRS:%=%/dep) include $(SRCDIR)/common.mk xmlrpc-c-1.33.14/lib/abyss/README000066400000000000000000000021111236133176700161630ustar00rootroot00000000000000This directory contains the Abyss HTTP server component of XML-RPC For C/C++ (Xmlrpc-c). This was derived from the independently developed and distributed Abyss web server package in 2001. Since that time, work has stopped on package except for a non-free derivative of it that the original author has done. He uses the Abyss name for that. So this is now strictly a piece of Xmlrpc-c. Some day, we should change the name to avoid confusion with the old code on which it was based and the current non-free version. But for Xmlrpc-c, we don't want to enhance this much. That would duplicate the vast amount of work that has gone into other HTTP (web) servers such as Apache. If someone needs fancy HTTP service for XML-RPC, he should use Apache. One can use Apache with Xmlrpc-c either by using an Apache request handler plugin or by using a CGI script. Abyss is just for very simple servers, where the complexity of using (or even acquiring) Apache would not be warranted. Everything besides what's in the src/ directory is just historical -- it comes from the original Abyss in 2001. xmlrpc-c-1.33.14/lib/abyss/conf/000077500000000000000000000000001236133176700162355ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/abyss/conf/abyss.conf000066400000000000000000000033161236133176700202300ustar00rootroot00000000000000# ABYSS Web Server configuration file # (C) Moez Mahfoudh - 2000 # Cases in option names are ignored, # that means that PORT=port=PoRT=.. # When writing paths, do not worry about / or \ use. # ABYSS will substitute / with \ on Win32 systems. # Options which are system specific (such as User) are # ignored on systems which do not handle them. # The Port option tells the server on which TCP port to listen. # default is 80 Port 8000 # The name or #number of the user to run the server as if it is # launched as root (UNIX specific) User nobody # The Server Root (UNIX systems style) ServerRoot /home/mahfoudh/abyss # The Server Root (Win32 systems style) # ServerRoot c:\abyss # The Path option specifies the web files path. Path htdocs # The Default option contains the name of the files the server should # look for when only a path is given (e.g. http://myserver/info/). Default index.html index.htm INDEX.HTM INDEX.HTML # The KeepAlive option is used to set the maximum number of requests # served using the same persistent connection. KeepAlive 10 # The TimeOut option tells the server how much seconds to wait for # an idle connection before closing it. TimeOut 10 # The MimeTypes option specifies the location of the file # containing the mapping of MIME types and files extensions MimeTypes conf/mime.types # The path of the log file LogFile log/access.log # The file where the pid of the server is logged (UNIX specific) PidFile log/abyss.pid # If AdvertiseServer if set to no, then no server field would be # appended to the responses. This is the way to make the server # identity unknown to some malicious people which can profit from # well known security holes in the software to crash it. AdvertiseServer yes xmlrpc-c-1.33.14/lib/abyss/conf/mime.types000066400000000000000000000162721236133176700202620ustar00rootroot00000000000000# This is a comment. I love comments. # This file controls what Internet media types are sent to the client for # given file extension(s). Sending the correct media type to the client # is important so they know how to handle the content of the file. # Extra types can either be added here or by using an AddType directive # in your config files. For more information about Internet media types, # please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type # registry is at . # MIME type Extension application/EDI-Consent application/EDI-X12 application/EDIFACT application/activemessage application/andrew-inset ez application/applefile application/atomicmail application/cals-1840 application/commonground application/cybercash application/dca-rft application/dec-dx application/eshop application/hyperstudio application/iges application/mac-binhex40 hqx application/mac-compactpro cpt application/macwriteii application/marc application/mathematica application/msword doc application/news-message-id application/news-transmission application/octet-stream bin dms lha lzh exe class application/oda oda application/pdf pdf application/pgp-encrypted application/pgp-keys application/pgp-signature application/pkcs10 application/pkcs7-mime application/pkcs7-signature application/postscript ai eps ps application/prs.alvestrand.titrax-sheet application/prs.cww application/prs.nprend application/remote-printing application/riscos application/rtf rtf application/set-payment application/set-payment-initiation application/set-registration application/set-registration-initiation application/sgml application/sgml-open-catalog application/slate application/smil smi smil application/vemmi application/vnd.3M.Post-it-Notes application/vnd.FloGraphIt application/vnd.acucobol application/vnd.anser-web-certificate-issue-initiation application/vnd.anser-web-funds-transfer-initiation application/vnd.audiograph application/vnd.businessobjects application/vnd.claymore application/vnd.comsocaller application/vnd.dna application/vnd.dxr application/vnd.ecdis-update application/vnd.ecowin.chart application/vnd.ecowin.filerequest application/vnd.ecowin.fileupdate application/vnd.ecowin.series application/vnd.ecowin.seriesrequest application/vnd.ecowin.seriesupdate application/vnd.enliven application/vnd.epson.salt application/vnd.fdf application/vnd.ffsns application/vnd.framemaker application/vnd.fujitsu.oasys application/vnd.fujitsu.oasys2 application/vnd.fujitsu.oasys3 application/vnd.fujitsu.oasysgp application/vnd.fujitsu.oasysprs application/vnd.fujixerox.docuworks application/vnd.hp-HPGL application/vnd.hp-PCL application/vnd.hp-PCLXL application/vnd.hp-hps application/vnd.ibm.MiniPay application/vnd.ibm.modcap application/vnd.intercon.formnet application/vnd.intertrust.digibox application/vnd.intertrust.nncp application/vnd.is-xpr application/vnd.japannet-directory-service application/vnd.japannet-jpnstore-wakeup application/vnd.japannet-payment-wakeup application/vnd.japannet-registration application/vnd.japannet-registration-wakeup application/vnd.japannet-setstore-wakeup application/vnd.japannet-verification application/vnd.japannet-verification-wakeup application/vnd.koan application/vnd.lotus-1-2-3 application/vnd.lotus-approach application/vnd.lotus-freelance application/vnd.lotus-organizer application/vnd.lotus-screencam application/vnd.lotus-wordpro application/vnd.meridian-slingshot application/vnd.mif mif application/vnd.minisoft-hp3000-save application/vnd.mitsubishi.misty-guard.trustweb application/vnd.ms-artgalry application/vnd.ms-asf application/vnd.ms-excel xls application/vnd.ms-powerpoint ppt application/vnd.ms-project application/vnd.ms-tnef application/vnd.ms-works application/vnd.music-niff application/vnd.musician application/vnd.netfpx application/vnd.noblenet-directory application/vnd.noblenet-sealer application/vnd.noblenet-web application/vnd.novadigm.EDM application/vnd.novadigm.EDX application/vnd.novadigm.EXT application/vnd.osa.netdeploy application/vnd.powerbuilder6 application/vnd.powerbuilder6-s application/vnd.rapid application/vnd.seemail application/vnd.shana.informed.formtemplate application/vnd.shana.informed.interchange application/vnd.shana.informed.package application/vnd.street-stream application/vnd.svd application/vnd.swiftview-ics application/vnd.truedoc application/vnd.visio application/vnd.webturbo application/vnd.wrq-hp3000-labelled application/vnd.wt.stf application/vnd.xara application/vnd.yellowriver-custom-menu application/wita application/wordperfect5.1 application/x-bcpio bcpio application/x-cdlink vcd application/x-chess-pgn pgn application/x-compress application/x-cpio cpio application/x-csh csh application/x-director dcr dir dxr application/x-dvi dvi application/x-futuresplash spl application/x-gtar gtar application/x-gzip application/x-hdf hdf application/x-javascript js application/x-koan skp skd skt skm application/x-latex latex application/x-netcdf nc cdf application/x-sh sh application/x-shar shar application/x-shockwave-flash swf application/x-stuffit sit application/x-sv4cpio sv4cpio application/x-sv4crc sv4crc application/x-tar tar application/x-tcl tcl application/x-tex tex application/x-texinfo texinfo texi application/x-troff t tr roff application/x-troff-man man application/x-troff-me me application/x-troff-ms ms application/x-ustar ustar application/x-wais-source src application/x400-bp application/xml application/zip zip audio/32kadpcm audio/basic au snd audio/midi mid midi kar audio/mpeg mpga mp2 mp3 audio/vnd.qcelp audio/x-aiff aif aiff aifc audio/x-pn-realaudio ram rm audio/x-pn-realaudio-plugin rpm audio/x-realaudio ra audio/x-wav wav chemical/x-pdb pdb xyz image/bmp bmp image/cgm image/g3fax image/gif gif image/ief ief image/jpeg jpeg jpg jpe image/naplps image/png png image/prs.btif image/tiff tiff tif image/vnd.dwg image/vnd.dxf image/vnd.fpx image/vnd.net-fpx image/vnd.svf image/vnd.xiff image/x-cmu-raster ras image/x-portable-anymap pnm image/x-portable-bitmap pbm image/x-portable-graymap pgm image/x-portable-pixmap ppm image/x-rgb rgb image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd message/delivery-status message/disposition-notification message/external-body message/http message/news message/partial message/rfc822 model/iges igs iges model/mesh msh mesh silo model/vnd.dwf model/vrml wrl vrml multipart/alternative multipart/appledouble multipart/byteranges multipart/digest multipart/encrypted multipart/form-data multipart/header-set multipart/mixed multipart/parallel multipart/related multipart/report multipart/signed multipart/voice-message text/css css text/directory text/enriched text/html html htm text/plain asc txt text/prs.lines.tag text/rfc822-headers text/richtext rtx text/rtf rtf text/sgml sgml sgm text/tab-separated-values tsv text/uri-list text/vnd.abc text/vnd.flatland.3dml text/vnd.fmi.flexstor text/vnd.in3d.3dml text/vnd.in3d.spot text/vnd.latex-z text/x-setext etx text/xml xml video/mpeg mpeg mpg mpe video/quicktime qt mov video/vnd.motorola.video video/vnd.motorola.videop video/vnd.vivo video/x-msvideo avi video/x-sgi-movie movie x-conference/x-cooltalk ice xmlrpc-c-1.33.14/lib/abyss/example/000077500000000000000000000000001236133176700167435ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/abyss/example/conf/000077500000000000000000000000001236133176700176705ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/abyss/example/conf/abyss.conf000066400000000000000000000033461236133176700216660ustar00rootroot00000000000000# ABYSS Web Server configuration file # (C) Moez Mahfoudh - 2000 # Cases in option names are ignored, # that means that PORT=port=PoRT=.. # When writing paths, do not worry about / or \ use. # ABYSS will substitute / with \ on Win32 systems. # Options which are system specific (such as User) are # ignored on systems which do not handle them. # The Port option tells the server on which TCP port to listen. # default is 80 Port 8080 # The name or #number of the user to run the server as if it is # launched as root (UNIX specific) User nobody # The Server Root (UNIX systems style) ServerRoot conf/abyss_root # The Server Root (Win32 systems style) # ServerRoot G:\XML\xmlrpc-c-0.9.5\conf\abyss_root # The Path option specifies the web files path. Path htdocs # The Default option contains the name of the files the server should # look for when only a path is given (e.g. http://myserver/info/). Default index.html index.htm INDEX.HTM INDEX.HTML # The KeepAlive option is used to set the maximum number of requests # served using the same persistent connection. KeepAlive 10 # The TimeOut option tells the server how much seconds to wait for # an idle connection before closing it. TimeOut 10 # The MimeTypes option specifies the location of the file # containing the mapping of MIME types and files extensions MimeTypes conf/mime.types # The path of the log file LogFile log/access.log # The file where the pid of the server is logged (UNIX specific) PidFile log/abyss.pid # If AdvertiseServer if set to no, then no server field would be # appended to the responses. This is the way to make the server # identity unknown to some malicious people which can profit from # well known security holes in the software to crash it. AdvertiseServer yes xmlrpc-c-1.33.14/lib/abyss/example/conf/mime.types000066400000000000000000000162721236133176700217150ustar00rootroot00000000000000# This is a comment. I love comments. # This file controls what Internet media types are sent to the client for # given file extension(s). Sending the correct media type to the client # is important so they know how to handle the content of the file. # Extra types can either be added here or by using an AddType directive # in your config files. For more information about Internet media types, # please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type # registry is at . # MIME type Extension application/EDI-Consent application/EDI-X12 application/EDIFACT application/activemessage application/andrew-inset ez application/applefile application/atomicmail application/cals-1840 application/commonground application/cybercash application/dca-rft application/dec-dx application/eshop application/hyperstudio application/iges application/mac-binhex40 hqx application/mac-compactpro cpt application/macwriteii application/marc application/mathematica application/msword doc application/news-message-id application/news-transmission application/octet-stream bin dms lha lzh exe class application/oda oda application/pdf pdf application/pgp-encrypted application/pgp-keys application/pgp-signature application/pkcs10 application/pkcs7-mime application/pkcs7-signature application/postscript ai eps ps application/prs.alvestrand.titrax-sheet application/prs.cww application/prs.nprend application/remote-printing application/riscos application/rtf rtf application/set-payment application/set-payment-initiation application/set-registration application/set-registration-initiation application/sgml application/sgml-open-catalog application/slate application/smil smi smil application/vemmi application/vnd.3M.Post-it-Notes application/vnd.FloGraphIt application/vnd.acucobol application/vnd.anser-web-certificate-issue-initiation application/vnd.anser-web-funds-transfer-initiation application/vnd.audiograph application/vnd.businessobjects application/vnd.claymore application/vnd.comsocaller application/vnd.dna application/vnd.dxr application/vnd.ecdis-update application/vnd.ecowin.chart application/vnd.ecowin.filerequest application/vnd.ecowin.fileupdate application/vnd.ecowin.series application/vnd.ecowin.seriesrequest application/vnd.ecowin.seriesupdate application/vnd.enliven application/vnd.epson.salt application/vnd.fdf application/vnd.ffsns application/vnd.framemaker application/vnd.fujitsu.oasys application/vnd.fujitsu.oasys2 application/vnd.fujitsu.oasys3 application/vnd.fujitsu.oasysgp application/vnd.fujitsu.oasysprs application/vnd.fujixerox.docuworks application/vnd.hp-HPGL application/vnd.hp-PCL application/vnd.hp-PCLXL application/vnd.hp-hps application/vnd.ibm.MiniPay application/vnd.ibm.modcap application/vnd.intercon.formnet application/vnd.intertrust.digibox application/vnd.intertrust.nncp application/vnd.is-xpr application/vnd.japannet-directory-service application/vnd.japannet-jpnstore-wakeup application/vnd.japannet-payment-wakeup application/vnd.japannet-registration application/vnd.japannet-registration-wakeup application/vnd.japannet-setstore-wakeup application/vnd.japannet-verification application/vnd.japannet-verification-wakeup application/vnd.koan application/vnd.lotus-1-2-3 application/vnd.lotus-approach application/vnd.lotus-freelance application/vnd.lotus-organizer application/vnd.lotus-screencam application/vnd.lotus-wordpro application/vnd.meridian-slingshot application/vnd.mif mif application/vnd.minisoft-hp3000-save application/vnd.mitsubishi.misty-guard.trustweb application/vnd.ms-artgalry application/vnd.ms-asf application/vnd.ms-excel xls application/vnd.ms-powerpoint ppt application/vnd.ms-project application/vnd.ms-tnef application/vnd.ms-works application/vnd.music-niff application/vnd.musician application/vnd.netfpx application/vnd.noblenet-directory application/vnd.noblenet-sealer application/vnd.noblenet-web application/vnd.novadigm.EDM application/vnd.novadigm.EDX application/vnd.novadigm.EXT application/vnd.osa.netdeploy application/vnd.powerbuilder6 application/vnd.powerbuilder6-s application/vnd.rapid application/vnd.seemail application/vnd.shana.informed.formtemplate application/vnd.shana.informed.interchange application/vnd.shana.informed.package application/vnd.street-stream application/vnd.svd application/vnd.swiftview-ics application/vnd.truedoc application/vnd.visio application/vnd.webturbo application/vnd.wrq-hp3000-labelled application/vnd.wt.stf application/vnd.xara application/vnd.yellowriver-custom-menu application/wita application/wordperfect5.1 application/x-bcpio bcpio application/x-cdlink vcd application/x-chess-pgn pgn application/x-compress application/x-cpio cpio application/x-csh csh application/x-director dcr dir dxr application/x-dvi dvi application/x-futuresplash spl application/x-gtar gtar application/x-gzip application/x-hdf hdf application/x-javascript js application/x-koan skp skd skt skm application/x-latex latex application/x-netcdf nc cdf application/x-sh sh application/x-shar shar application/x-shockwave-flash swf application/x-stuffit sit application/x-sv4cpio sv4cpio application/x-sv4crc sv4crc application/x-tar tar application/x-tcl tcl application/x-tex tex application/x-texinfo texinfo texi application/x-troff t tr roff application/x-troff-man man application/x-troff-me me application/x-troff-ms ms application/x-ustar ustar application/x-wais-source src application/x400-bp application/xml application/zip zip audio/32kadpcm audio/basic au snd audio/midi mid midi kar audio/mpeg mpga mp2 mp3 audio/vnd.qcelp audio/x-aiff aif aiff aifc audio/x-pn-realaudio ram rm audio/x-pn-realaudio-plugin rpm audio/x-realaudio ra audio/x-wav wav chemical/x-pdb pdb xyz image/bmp bmp image/cgm image/g3fax image/gif gif image/ief ief image/jpeg jpeg jpg jpe image/naplps image/png png image/prs.btif image/tiff tiff tif image/vnd.dwg image/vnd.dxf image/vnd.fpx image/vnd.net-fpx image/vnd.svf image/vnd.xiff image/x-cmu-raster ras image/x-portable-anymap pnm image/x-portable-bitmap pbm image/x-portable-graymap pgm image/x-portable-pixmap ppm image/x-rgb rgb image/x-xbitmap xbm image/x-xpixmap xpm image/x-xwindowdump xwd message/delivery-status message/disposition-notification message/external-body message/http message/news message/partial message/rfc822 model/iges igs iges model/mesh msh mesh silo model/vnd.dwf model/vrml wrl vrml multipart/alternative multipart/appledouble multipart/byteranges multipart/digest multipart/encrypted multipart/form-data multipart/header-set multipart/mixed multipart/parallel multipart/related multipart/report multipart/signed multipart/voice-message text/css css text/directory text/enriched text/html html htm text/plain asc txt text/prs.lines.tag text/rfc822-headers text/richtext rtx text/rtf rtf text/sgml sgml sgm text/tab-separated-values tsv text/uri-list text/vnd.abc text/vnd.flatland.3dml text/vnd.fmi.flexstor text/vnd.in3d.3dml text/vnd.in3d.spot text/vnd.latex-z text/x-setext etx text/xml xml video/mpeg mpeg mpg mpe video/quicktime qt mov video/vnd.motorola.video video/vnd.motorola.videop video/vnd.vivo video/x-msvideo avi video/x-sgi-movie movie x-conference/x-cooltalk ice xmlrpc-c-1.33.14/lib/abyss/example/htdocs/000077500000000000000000000000001236133176700202275ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/abyss/example/htdocs/index.htm000066400000000000000000000012201236133176700220430ustar00rootroot00000000000000 ABYSS is working !!!

Congratulations, ABYSS is working !!!


ABYSS Web Server is working correctly on your system. You should now change this page with yours.
Please include in your web pages (at least the first), the 'Powered by ABYSS' banner to promote the use of ABYSS.


Copyright 2000 Moez Mahfoudh. All rights reserved.

xmlrpc-c-1.33.14/lib/abyss/example/htdocs/pwrabyss.gif000066400000000000000000000042261236133176700225740ustar00rootroot00000000000000GIF89a-!!!!!)))))1111199999BBBBBJJJJJRRRZZZZZccccckkkkksssss{{{{{,-MH*\ȰÇ#64!ŋ3jhǏ CIɓ(S<CEbʔɱ&8s /yjcϣH*ae РCэ:)Prי&cL%I8pc_~t 7L?^0SU:#ݸ<Ψ `A^pxGl" 11g ,bG3STc1Tގgާ`EjV䃙?.nq9J:9h<>5/|S[JfqɁ~́V w9xC&z `R{$iЗ}DNeLxJqс1!^#u!PL 5@ GV@tt%^fD  >tTzމUfրd"m'(%h%^@mwQRH^JR҃Ux+LܝM% ET)5s)L L }Wede IaXRH\Fbfj*2NViF(fHkז-Ob)n#q h]y<!6Ydh`LLYՔ` K!C"1H #AF0߀Rb D*A(䞓I G:j|%K/&lWms5$7I (#P9 kDI p@E3эzT hH?*Ғ#MIUҕ0hf:д7MoS5jR ԥ:P%*S;xmlrpc-c-1.33.14/lib/abyss/license.txt000066400000000000000000000030211236133176700174670ustar00rootroot00000000000000 ABYSS Web Server License ------------------------ Copyright (C) 2000 by Moez Mahfoudh . 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. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. xmlrpc-c-1.33.14/lib/abyss/src/000077500000000000000000000000001236133176700160775ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/abyss/src/Makefile000066400000000000000000000054601236133176700175440ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') ABYSSDIR := $(call updir,$(CURDIR)) LIBDIR := $(call updir,$(ABYSSDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/abyss/src include $(BLDDIR)/config.mk default: all TARGET_LIBRARY_NAMES := libxmlrpc_abyss STATIC_LIBRARIES_TO_INSTALL = libxmlrpc_abyss.a SHARED_LIBS_TO_BUILD := libxmlrpc_abyss SHARED_LIBS_TO_INSTALL := libxmlrpc_abyss ifeq ($(findstring mingw,$(HOST_OS)),mingw) THREAD_MODULE = thread_windows SOCKET_MODULE = socket_win else SOCKET_MODULE = socket_unix ifeq ($(ENABLE_ABYSS_THREADS),yes) THREAD_MODULE = thread_pthread else THREAD_MODULE = thread_fork endif endif TARGET_MODS = \ channel \ chanswitch \ conf \ conn \ data \ date \ file \ handler \ http \ init \ response \ server \ session \ socket \ $(SOCKET_MODULE) \ token \ $(THREAD_MODULE) \ trace \ OMIT_ABYSS_LIB_RULE = Y MAJ=3 # Major number of shared libraries in this directory include $(SRCDIR)/common.mk CFLAGS_LOCAL = -D_UNIX INCLUDES = -Iblddir -Isrcdir -Isrcdir/include -Isrcdir/lib/util/include ABYSS_SHLIB = $(call shlibfn,libxmlrpc_abyss) #ABYSS_SHLIB is e.g. libxmlrpc_abyss.so.3.1 ABYSS_SHLIBLE = $(call shliblefn,libxmlrpc_abyss) #ABYSS_SHLIBLE is e.g. libxmlrpc_abyss.so # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir .PHONY: all all: libxmlrpc_abyss.a $(TARGET_SHARED_LIBRARIES) $(TARGET_SHARED_LE_LIBS) # Rule for this is in common.mk, courtesy of TARGET_LIBRARY_NAMES $(ABYSS_SHLIB): $(TARGET_MODS:%=%.osh) \ $(LIBXMLRPC_UTIL) $(ABYSS_SHLIB): LIBOBJECTS = $(TARGET_MODS:%=%.osh) $(ABYSS_SHLIB): LIBDEP = $(LIBXMLRPC_UTIL_LIBDEP) ifeq ($(ENABLE_ABYSS_THREADS),yes) $(ABYSS_SHLIB): LIBDEP += $(THREAD_LIBS) endif ifeq ($(MSVCRT),yes) $(ABYSS_SHLIB): LIBDEP += -lws2_32 -lwsock32 endif # Rule for this is in common.mk, courtesy of TARGET_STATIC_LIBRARIES: libxmlrpc_abyss.a: $(TARGET_MODS:%=%.o) libxmlrpc_abyss.a: LIBOBJECTS = $(TARGET_MODS:%=%.o) #----------------------------------------------------------------------------- # RULES TO COMPILE OBJECT MODULES FOR LIBRARIES #----------------------------------------------------------------------------- # Rules to compile object modules from which to build the static and shared # Abyss library are in common.mk, courtesy of TARGET_MODS. # Need this dependency for those who don't use depend.mk. # Without it, version.h doesn't get created. response.o response.osh handler.o handler.osh: version.h .PHONY: clean clean: clean-common .PHONY: distclean distclean: clean distclean-common .PHONY: tags tags: TAGS .PHONY: distdir distdir: .PHONY: install install: install-common .PHONY: dep dep: dep-common include depend.mk xmlrpc-c-1.33.14/lib/abyss/src/abyss_info.h000066400000000000000000000011001236133176700203740ustar00rootroot00000000000000#ifndef ABYSS_INFO_H_INCLUDED #define ABYSS_INFO_H_INCLUDED #include "version.h" /* defines XMLRPC_C_VERSION */ #define SERVER_HTML_INFO \ "


" \ "ABYSS Web Server for XML-RPC For C/C++ " \ "version " XMLRPC_C_VERSION "
" \ "

" #define SERVER_PLAIN_INFO \ CRLF "----------------------------------------" \ "----------------------------------------" \ CRLF "ABYSS Web Server for XML-RPC For C/C++ " \ "version " XMLRPC_C_VERSION CRLF "See xmlrpc-c.sourceforge.net" #endif xmlrpc-c-1.33.14/lib/abyss/src/channel.c000066400000000000000000000107741236133176700176640ustar00rootroot00000000000000/*============================================================================ socket.c ============================================================================== Implementation of TChannel class: A generic channel over which one can transport a bidirectional stream of bytes. A TChannel is a lot like a POSIX stream socket in "connected" state. ============================================================================*/ #include #include #include #include #include "bool.h" #include "int.h" #include "mallocvar.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/abyss.h" #ifdef _WIN32 #include "socket_win.h" #else #include "socket_unix.h" #endif #include "channel.h" static void socketOsInit(const char ** const errorP) { #ifdef _WIN32 SocketWinInit(errorP); #else SocketUnixInit(errorP); #endif } static void socketOsTerm(void) { #ifdef _WIN32 SocketWinTerm(); #else SocketUnixTerm(); #endif } bool ChannelTraceIsActive; void ChannelInit(const char ** const errorP) { socketOsInit(errorP); if (!*errorP) { ChannelTraceIsActive = (getenv("ABYSS_TRACE_CHANNEL") != NULL); if (ChannelTraceIsActive) fprintf(stderr, "Abyss channel layer will trace channel traffic " "due to ABYSS_TRACE_CHANNEL environment variable\n"); } } void ChannelTerm(void) { socketOsTerm(); } /* ChannelCreate() is not exported to the Abyss user. It is meant to be used by an implementation-specific TChannel generator which is exported to the Abyss user, e.g. ChannelCreateUnix() in socket_unix.c The TChannel generator functions are the _only_ user-accessible functions that are particular to an implementation. */ static unsigned int const channelSignature = 0x06060B; void ChannelCreate(const struct TChannelVtbl * const vtblP, void * const implP, TChannel ** const channelPP) { TChannel * channelP; MALLOCVAR(channelP); if (channelP) { channelP->implP = implP; channelP->vtbl = *vtblP; channelP->signature = channelSignature; *channelPP = channelP; if (ChannelTraceIsActive) fprintf(stderr, "Created channel %p\n", channelP); } } void ChannelDestroy(TChannel * const channelP) { if (ChannelTraceIsActive) fprintf(stderr, "Destroying channel %p\n", channelP); assert(channelP->signature == channelSignature); channelP->vtbl.destroy(channelP); channelP->signature = 0; /* For debuggability */ free(channelP); } void ChannelWrite(TChannel * const channelP, const unsigned char * const buffer, uint32_t const len, bool * const failedP) { if (ChannelTraceIsActive) fprintf(stderr, "Writing %u bytes to channel %p\n", len, channelP); (*channelP->vtbl.write)(channelP, buffer, len, failedP); } void ChannelRead(TChannel * const channelP, unsigned char * const buffer, uint32_t const len, uint32_t * const bytesReceivedP, bool * const failedP) { if (ChannelTraceIsActive) fprintf(stderr, "Reading %u bytes from channel %p\n", len, channelP); (*channelP->vtbl.read)(channelP, buffer, len, bytesReceivedP, failedP); } void ChannelWait(TChannel * const channelP, bool const waitForRead, bool const waitForWrite, uint32_t const timems, bool * const readyToReadP, bool * const readyToWriteP, bool * const failedP) { if (ChannelTraceIsActive) { if (waitForRead) fprintf(stderr, "Waiting %u milliseconds for data from " "channel %p\n", timems, channelP); if (waitForWrite) fprintf(stderr, "Waiting %u milliseconds for channel %p " "to be writable\n", timems, channelP); } (*channelP->vtbl.wait)(channelP, waitForRead, waitForWrite, timems, readyToReadP, readyToWriteP, failedP); } void ChannelInterrupt(TChannel * const channelP) { if (ChannelTraceIsActive) fprintf(stderr, "Interrupting channel waits\n"); (*channelP->vtbl.interrupt)(channelP); } void ChannelFormatPeerInfo(TChannel * const channelP, const char ** const peerStringP) { (*channelP->vtbl.formatPeerInfo)(channelP, peerStringP); } xmlrpc-c-1.33.14/lib/abyss/src/channel.h000066400000000000000000000074661236133176700176750ustar00rootroot00000000000000#ifndef CHANNEL_H_INCLUDED #define CHANNEL_H_INCLUDED /*============================================================================ This is the generic channel interface for Abyss. It includes both the generic interface to a channel from above and the interface between generic channel code and a particular channel implementation (e.g. POSIX socket) below. Abyss uses a channel to converse with an HTTP client. A channel is oblivious to HTTP -- it just transports a byte stream in each direction. ============================================================================*/ #include "bool.h" #include "int.h" #include "xmlrpc-c/abyss.h" struct TChannelVtbl; void ChannelCreate(const struct TChannelVtbl * const vtblP, void * const implP, TChannel ** const channelPP); typedef void ChannelDestroyImpl(TChannel * const channelP); typedef void ChannelWriteImpl(TChannel * const channelP, const unsigned char * const buffer, uint32_t const len, bool * const failedP); typedef void ChannelReadImpl(TChannel * const channelP, unsigned char * const buffer, uint32_t const len, uint32_t * const bytesReceivedP, bool * const failedP); typedef uint32_t ChannelErrorImpl(TChannel * const channelP); typedef void ChannelWaitImpl(TChannel * const channelP, bool const waitForRead, bool const waitForWrite, uint32_t const timems, bool * const readyToReadP, bool * const readyToWriteP, bool * const failedP); typedef void ChannelInterruptImpl(TChannel * const channelP); typedef void ChannelFormatPeerInfoImpl(TChannel * const channelP, const char ** const peerStringP); struct TChannelVtbl { ChannelDestroyImpl * destroy; ChannelWriteImpl * write; ChannelReadImpl * read; ChannelWaitImpl * wait; ChannelInterruptImpl * interrupt; ChannelFormatPeerInfoImpl * formatPeerInfo; }; struct _TChannel { unsigned int signature; /* With both background and foreground use of sockets, and background being both fork and pthread, it is very easy to screw up socket lifetime and try to destroy twice. We use this signature to help catch such bugs. */ void * implP; struct TChannelVtbl vtbl; }; #define TIME_INFINITE 0xffffffff extern bool ChannelTraceIsActive; void ChannelInit(const char ** const errorP); void ChannelTerm(void); void ChannelWrite(TChannel * const channelP, const unsigned char * const buffer, uint32_t const len, bool * const failedP); void ChannelRead(TChannel * const channelP, unsigned char * const buffer, uint32_t const len, uint32_t * const bytesReceivedP, bool * const failedP); void ChannelWait(TChannel * const channelP, bool const waitForRead, bool const waitForWrite, uint32_t const timems, bool * const readyToReadP, bool * const readyToWriteP, bool * const failedP); void ChannelInterrupt(TChannel * const channelP); void ChannelFormatPeerInfo(TChannel * const channelP, const char ** const peerStringP); #endif xmlrpc-c-1.33.14/lib/abyss/src/chanswitch.c000066400000000000000000000075221236133176700204040ustar00rootroot00000000000000/*============================================================================ socket.c ============================================================================== Implementation of TChanSwitch class: A generic channel switch -- an object that brokers a connection between an HTTP client and server. ============================================================================*/ #include #include #include #include #include "bool.h" #include "int.h" #include "mallocvar.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/abyss.h" #ifdef _WIN32 #include "socket_win.h" #else #include "socket_unix.h" #endif #include "chanswitch.h" static void socketOsInit(const char ** const errorP) { #ifdef _WIN32 SocketWinInit(errorP); #else SocketUnixInit(errorP); #endif } static void socketOsTerm(void) { #ifdef _WIN32 SocketWinTerm(); #else SocketUnixTerm(); #endif } bool SwitchTraceIsActive; void ChanSwitchInit(const char ** const errorP) { socketOsInit(errorP); if (!*errorP) { SwitchTraceIsActive = (getenv("ABYSS_TRACE_SWITCH") != NULL); if (SwitchTraceIsActive) fprintf(stderr, "Abyss channel switch layer will trace " "channel connection activity " "due to ABYSS_TRACE_SWITCH environment variable\n"); } } void ChanSwitchTerm(void) { socketOsTerm(); } /* ChanSwitchCreate() is not exported to the Abyss user. It is meant to be used by an implementation-specific TChanSwitch generator which is exported to the Abyss user, e.g. SwitchCreateUnix() in socket_unix.c The TChanSwitch generator functions are the _only_ user-accessible functions that are particular to an implementation. */ static unsigned int const switchSignature = 0x06060A; void ChanSwitchCreate(const struct TChanSwitchVtbl * const vtblP, void * const implP, TChanSwitch ** const chanSwitchPP) { TChanSwitch * chanSwitchP; MALLOCVAR(chanSwitchP); if (chanSwitchP) { chanSwitchP->implP = implP; chanSwitchP->vtbl = *vtblP; chanSwitchP->signature = switchSignature; if (SwitchTraceIsActive) fprintf(stderr, "Created channel switch %p\n", chanSwitchP); *chanSwitchPP = chanSwitchP; } } void ChanSwitchDestroy(TChanSwitch * const chanSwitchP) { if (SwitchTraceIsActive) fprintf(stderr, "Destroying channel switch %p\n", chanSwitchP); assert(chanSwitchP->signature == switchSignature); chanSwitchP->vtbl.destroy(chanSwitchP); chanSwitchP->signature = 0; /* For debuggability */ free(chanSwitchP); } void ChanSwitchListen(TChanSwitch * const chanSwitchP, uint32_t const backlog, const char ** const errorP) { if (SwitchTraceIsActive) fprintf(stderr, "Channel switch %p listening.\n", chanSwitchP); (*chanSwitchP->vtbl.listen)(chanSwitchP, backlog, errorP); } void ChanSwitchAccept(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { if (SwitchTraceIsActive) fprintf(stderr, "Getting a connection from Channel switch %p...\n", chanSwitchP); (*chanSwitchP->vtbl.accept)(chanSwitchP, channelPP, channelInfoPP, errorP); if (SwitchTraceIsActive) fprintf(stderr, "Got connection from channel switch. " "Channel = %p\n", *channelPP); } void ChanSwitchInterrupt(TChanSwitch * const chanSwitchP) { if (SwitchTraceIsActive) fprintf(stderr, "Interrupting wait for a connection " "by Channel switch %p...\n", chanSwitchP); (*chanSwitchP->vtbl.interrupt)(chanSwitchP); } xmlrpc-c-1.33.14/lib/abyss/src/chanswitch.h000066400000000000000000000047131236133176700204100ustar00rootroot00000000000000#ifndef CHANSWITCH_H_INCLUDED #define CHANSWITCH_H_INCLUDED /*============================================================================ This is the generic channel switch interface for Abyss. It includes both the generic interface to a channel switch from above and the interface between generic channel switch code and a particular channel implementation (e.g. POSIX) below. A channel switch is what creates a channel -- it brokers a connection between an HTTP client and server. ============================================================================*/ #include "bool.h" #include "int.h" #include "xmlrpc-c/abyss.h" typedef void SwitchDestroyImpl(TChanSwitch * const socketP); typedef void SwitchListenImpl(TChanSwitch * const chanSwitchP, uint32_t const backlog, const char ** const errorP); typedef void SwitchAcceptImpl(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoP, const char ** const errorP); typedef void SwitchInterruptImpl(TChanSwitch * const chanSwitchP); struct TChanSwitchVtbl { SwitchDestroyImpl * destroy; SwitchListenImpl * listen; SwitchAcceptImpl * accept; SwitchInterruptImpl * interrupt; }; struct _TChanSwitch { unsigned int signature; /* With both background and foreground use of switches, and background being both fork and pthread, it is very easy to screw up switch lifetime and try to destroy twice. We use this signature to help catch such bugs. */ void * implP; struct TChanSwitchVtbl vtbl; }; extern bool SwitchTraceIsActive; void ChanSwitchInit(const char ** const errorP); void ChanSwitchTerm(void); void ChanSwitchCreate(const struct TChanSwitchVtbl * const vtblP, void * const implP, TChanSwitch ** const chanSwitchPP); void ChanSwitchListen(TChanSwitch * const chanSwitchP, uint32_t const backlog, const char ** const errorP); void ChanSwitchAccept(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP); void ChanSwitchInterrupt(TChanSwitch * const chanSwitchP); #endif xmlrpc-c-1.33.14/lib/abyss/src/conf.c000066400000000000000000000261031236133176700171720ustar00rootroot00000000000000/****************************************************************************** ** ** conf.c ** ** This file is part of the ABYSS Web server project. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ #define _XOPEN_SOURCE 600 /* For strdup() */ #define _BSD_SOURCE /* For xmlrpc_strcaseeq */ #include #include #include #if defined(_WIN32) #include #endif #ifndef _WIN32 #include #endif #include "xmlrpc_config.h" #include "bool.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/abyss.h" #include "trace.h" #include "file.h" #include "server.h" #include "http.h" #include "handler.h" /********************************************************************* ** Configuration Files Parsing Functions *********************************************************************/ static bool ConfReadLine(TFile * const fileP, char * const buffer, uint32_t const lenArg) { bool r; char c; char * p; char * z; uint32_t len; len = lenArg; /* initial value */ r = TRUE; /* initial value */ z = buffer; /* initial value */ while (--len > 0) { int32_t bytesRead; bytesRead = FileRead(fileP, z, 1); if (bytesRead < 1) { if (z == buffer) r = FALSE; break; }; if (*z == CR || *z == LF) break; ++z; } if (len == 0) while (FileRead(fileP, &c, 1) == 1) if (c == CR || c == LF) break; *z = '\0'; /* Discard comments */ p = strchr(buffer, '#'); if (p) *p = '\0'; return r; } static bool ConfNextToken(char ** const p) { while (1) switch (**p) { case '\t': case ' ': (*p)++; break; case '\0': return FALSE; default: return TRUE; }; } static char * ConfGetToken(char **p) { char *p0=*p; while (1) switch (**p) { case '\t': case ' ': case CR: case LF: case '\0': if (p0==*p) return NULL; if (**p) { **p='\0'; (*p)++; }; return p0; default: (*p)++; }; } static bool ConfReadInt(const char * const p, int32_t * const n, int32_t const min, int32_t const max) { /*---------------------------------------------------------------------------- Convert string 'p' to integer *n. If it isn't a valid integer or is not with the bounds [min, max], return FALSE. Otherwise, return TRUE. -----------------------------------------------------------------------------*/ char * e; *n = strtol(p, &e, 10); if (min != max) return ((e != p) && (*n >= min) && (*n <= max)); else return (e != p); } static bool ConfReadBool(const char * const token, bool * const bP) { bool succeeded; if (xmlrpc_strcaseeq(token, "yes")) { *bP = TRUE; succeeded = TRUE; } else if (xmlrpc_strcaseeq(token, "no")) { *bP = FALSE; succeeded = TRUE; } else succeeded = FALSE; return succeeded; } /********************************************************************* ** MIME Types File *********************************************************************/ static void readMIMETypesFile(const char * const filename, MIMEType ** const MIMETypePP) { bool success; MIMEType * MIMETypeP; MIMETypeP = MIMETypeCreate(); if (MIMETypeP) { TFile * fileP; bool fileOpened; fileOpened = FileOpen(&fileP, filename, O_RDONLY); if (fileOpened) { char z[512]; while (ConfReadLine(fileP, z, 512)) { char * p; p = &z[0]; if (ConfNextToken(&p)) { const char * mimetype = ConfGetToken(&p); if (mimetype) { while (ConfNextToken(&p)) { const char * const ext = ConfGetToken(&p); if (ext) MIMETypeAdd2(MIMETypeP, mimetype, ext); else break; } } } } FileClose(fileP); success = TRUE; } else success = FALSE; if (!success) MIMETypeDestroy(MIMETypeP); } else success = FALSE; if (success) *MIMETypePP = MIMETypeP; else *MIMETypePP = NULL; } /********************************************************************* ** Server Configuration File *********************************************************************/ static void chdirx(const char * const newdir, bool * const successP) { *successP = XMLRPC_CHDIR(newdir) == 0; } static void parseUser(const char * const p, struct _TServer * const srvP) { #ifdef _WIN32 /* *srvP has no 'uid' or 'gid' member; system has no getpwnam() */ TraceMsg("User option ignored"); #else if (p[0] == '#') { int32_t n; if (!ConfReadInt(&p[1], &n, 0, 0)) TraceExit("Bad user number '%s'", p); else srvP->uid = n; } else { struct passwd * pwd; if (!(pwd = getpwnam(p))) TraceExit("Unknown user '%s'", p); srvP->uid = pwd->pw_uid; if ((int)srvP->gid==(-1)) srvP->gid = pwd->pw_gid; }; #endif } static void parsePidfile(const char * const p, struct _TServer * const srvP) { bool succeeded; succeeded = FileOpenCreate(&srvP->pidfileP, p, O_TRUNC | O_WRONLY); if (!succeeded) { srvP->pidfileP = NULL; TraceMsg("Bad PidFile value '%s'", p); }; } abyss_bool ConfReadServerFile(const char * const filename, TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; BIHandler * const handlerP = srvP->builtinHandlerP; TFile * fileP; char z[512]; char * p; unsigned int lineNum; TFileStat fs; if (!FileOpen(&fileP, filename, O_RDONLY)) return FALSE; lineNum = 0; while (ConfReadLine(fileP, z, 512)) { ++lineNum; p = z; if (ConfNextToken(&p)) { const char * const option = ConfGetToken(&p); if (option) { ConfNextToken(&p); if (xmlrpc_strcaseeq(option, "port")) { int32_t n; if (ConfReadInt(p, &n, 1, 65535)) srvP->port = n; else TraceExit("Invalid port '%s'", p); } else if (xmlrpc_strcaseeq(option, "serverroot")) { bool success; chdirx(p, &success); if (!success) TraceExit("Invalid server root '%s'",p); } else if (xmlrpc_strcaseeq(option, "path")) { if (FileStat(p, &fs)) if (fs.st_mode & S_IFDIR) { HandlerSetFilesPath(handlerP, p); continue; } TraceExit("Invalid path '%s'", p); } else if (xmlrpc_strcaseeq(option, "default")) { const char * filename; while ((filename = ConfGetToken(&p))) { HandlerAddDefaultFN(handlerP, filename); if (!ConfNextToken(&p)) break; } } else if (xmlrpc_strcaseeq(option, "keepalive")) { int32_t n; if (ConfReadInt(p, &n, 1, 65535)) srvP->keepalivemaxconn = n; else TraceExit("Invalid KeepAlive value '%s'", p); } else if (xmlrpc_strcaseeq(option, "timeout")) { int32_t n; if (ConfReadInt(p, &n, 1, 3600)) { srvP->keepalivetimeout = n; /* Must see what to do with that */ srvP->timeout = n; } else TraceExit("Invalid TimeOut value '%s'", p); } else if (xmlrpc_strcaseeq(option, "mimetypes")) { MIMEType * mimeTypeP; readMIMETypesFile(p, &mimeTypeP); if (!mimeTypeP) TraceExit("Can't read MIME Types file '%s'", p); else HandlerSetMimeType(handlerP, mimeTypeP); } else if (xmlrpc_strcaseeq(option,"logfile")) { srvP->logfilename = strdup(p); } else if (xmlrpc_strcaseeq(option,"user")) { parseUser(p, srvP); } else if (xmlrpc_strcaseeq(option, "pidfile")) { parsePidfile(p, srvP); } else if (xmlrpc_strcaseeq(option, "advertiseserver")) { if (!ConfReadBool(p, &srvP->advertise)) TraceExit("Invalid boolean value " "for AdvertiseServer option"); } else TraceExit("Invalid option '%s' at line %u", option, lineNum); } } } FileClose(fileP); return TRUE; } xmlrpc-c-1.33.14/lib/abyss/src/conn.c000066400000000000000000000457061236133176700172140ustar00rootroot00000000000000/* Copyright information is at the end of the file. */ #include #include #include #include #include #include #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/sleep_int.h" #include "xmlrpc-c/abyss.h" #include "channel.h" #include "server.h" #include "thread.h" #include "file.h" #include "conn.h" /********************************************************************* ** Conn *********************************************************************/ static TThreadProc connJob; static void connJob(void * const userHandle) { /*---------------------------------------------------------------------------- This is the root function for a thread that processes a connection (performs HTTP transactions). We never return. We ultimately exit the thread. -----------------------------------------------------------------------------*/ TConn * const connectionP = userHandle; (connectionP->job)(connectionP); connectionP->finished = TRUE; /* Note that if we are running in a forked process, setting connectionP->finished has no effect, because it's just our own copy of *connectionP. In this case, Parent must update his own copy based on a SIGCHLD signal that the OS will generate right after we exit. */ /* Note that ThreadExit() runs a cleanup function, which in our case is connDone(). */ ThreadExit(connectionP->threadP, 0); } /* This is the maximum amount of stack that 'connJob' itself uses -- does not count what user's connection job function uses. */ #define CONNJOB_STACK 1024 static void connDone(TConn * const connectionP) { /* In the forked case, this is designed to run in the parent process after the child has terminated. */ connectionP->finished = TRUE; if (connectionP->done) connectionP->done(connectionP); } static TThreadDoneFn threadDone; static void threadDone(void * const userHandle) { TConn * const connectionP = userHandle; connDone(connectionP); } static void makeThread(TConn * const connectionP, enum abyss_foreback const foregroundBackground, bool const useSigchld, size_t const jobStackSize, const char ** const errorP) { switch (foregroundBackground) { case ABYSS_FOREGROUND: connectionP->hasOwnThread = FALSE; *errorP = NULL; break; case ABYSS_BACKGROUND: { const char * error; connectionP->hasOwnThread = TRUE; ThreadCreate(&connectionP->threadP, connectionP, &connJob, &threadDone, useSigchld, CONNJOB_STACK + jobStackSize, &error); if (error) { xmlrpc_asprintf(errorP, "Unable to create thread to " "process connection. %s", error); xmlrpc_strfree(error); } else *errorP = NULL; } break; } /* switch */ } void ConnCreate(TConn ** const connectionPP, TServer * const serverP, TChannel * const channelP, void * const channelInfoP, TThreadProc * const job, size_t const jobStackSize, TThreadDoneFn * const done, enum abyss_foreback const foregroundBackground, bool const useSigchld, const char ** const errorP) { /*---------------------------------------------------------------------------- Create an HTTP connection. A connection carries one or more HTTP transactions (request/response). *channelP transports the requests and responses. The connection handles those HTTP requests. The connection handles the requests primarily by running the function 'job' once. Some connections can do that autonomously, as soon as the connection is created. Others don't until Caller subsequently calls ConnProcess. Some connections complete the processing before ConnProcess return, while others may run the connection asynchronously to the creator, in the background, via a TThread thread. 'foregroundBackground' determines which. 'job' calls methods of the connection to get requests and send responses. Some time after the HTTP transactions are all done, 'done' gets called in some context. 'channelInfoP' == NULL means no channel info supplied. -----------------------------------------------------------------------------*/ TConn * connectionP; MALLOCVAR(connectionP); if (connectionP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for a connection " "descriptor."); else { connectionP->server = serverP; connectionP->channelP = channelP; connectionP->channelInfoP = channelInfoP; connectionP->buffer.b[0] = '\0'; connectionP->buffersize = 0; connectionP->bufferpos = 0; connectionP->finished = FALSE; connectionP->job = job; connectionP->done = done; connectionP->inbytes = 0; connectionP->outbytes = 0; connectionP->trace = getenv("ABYSS_TRACE_CONN"); makeThread(connectionP, foregroundBackground, useSigchld, jobStackSize, errorP); } *connectionPP = connectionP; } bool ConnProcess(TConn * const connectionP) { /*---------------------------------------------------------------------------- Drive the main processing of a connection -- run the connection's "job" function, which should read HTTP requests from the connection and send HTTP responses. If we succeed, we guarantee the connection's "done" function will get called some time after all processing is complete. It might be before we return or some time after. If we fail, we guarantee the "done" function will not be called. -----------------------------------------------------------------------------*/ bool retval; if (connectionP->hasOwnThread) { /* There's a background thread to handle this connection. Set it running. */ assert(connectionP->threadP); retval = ThreadRun(connectionP->threadP); } else { /* No background thread. We just handle it here while Caller waits. */ (connectionP->job)(connectionP); connDone(connectionP); retval = TRUE; } return retval; } void ConnWaitAndRelease(TConn * const connectionP) { if (connectionP->hasOwnThread) { assert(connectionP->threadP); ThreadWaitAndRelease(connectionP->threadP); } free(connectionP); } bool ConnKill(TConn * const connectionP) { connectionP->finished = TRUE; return ThreadKill(connectionP->threadP); } void ConnReadInit(TConn * const connectionP) { if (connectionP->buffersize > connectionP->bufferpos) { connectionP->buffersize -= connectionP->bufferpos; memmove(connectionP->buffer.b, connectionP->buffer.b + connectionP->bufferpos, connectionP->buffersize); connectionP->bufferpos = 0; } else connectionP->buffersize = connectionP->bufferpos = 0; connectionP->buffer.b[connectionP->buffersize] = '\0'; connectionP->inbytes = connectionP->outbytes = 0; } static void traceReadTimeout(TConn * const connectionP, uint32_t const timeout) { if (connectionP->trace) fprintf(stderr, "TIMED OUT waiting over %u seconds " "for data from client.\n", timeout); } static size_t nextLineSize(const char * const string, size_t const startPos, size_t const stringSize) { /*---------------------------------------------------------------------------- Return the length of the line that starts at offset 'startPos' in the string 'string', which is 'stringSize' characters long. 'string' in not NUL-terminated. A line begins at beginning of string or after a newline character and runs through the next newline character or end of string. The line includes the newline character at the end, if any. -----------------------------------------------------------------------------*/ size_t i; for (i = startPos; i < stringSize && string[i] != '\n'; ++i); if (i < stringSize) ++i; /* Include the newline */ return i - startPos; } static void traceBuffer(const char * const label, const unsigned char * const buffer, unsigned int const size) { const char * const buffer_t = (const char *)buffer; size_t cursor; /* Index into buffer[] */ fprintf(stderr, "%s:\n\n", label); for (cursor = 0; cursor < size; ) { /* Print one line of buffer */ size_t const lineSize = nextLineSize(buffer_t, cursor, size); const char * const printableLine = xmlrpc_makePrintable_lp(&buffer_t[cursor], lineSize); fprintf(stderr, "%s\n", printableLine); cursor += lineSize; xmlrpc_strfree(printableLine); } fprintf(stderr, "\n"); } static void traceBufferText(const char * const label, const char * const buffer, unsigned int const size) { traceBuffer(label, (const unsigned char *)buffer, size); } static void traceChannelRead(TConn * const connectionP, unsigned int const size) { if (connectionP->trace) traceBuffer("READ FROM CHANNEL", connectionP->buffer.b + connectionP->buffersize, size); } static void traceChannelWrite(TConn * const connectionP, const char * const buffer, unsigned int const size, bool const failed) { if (connectionP->trace) { const char * const label = failed ? "FAILED TO WRITE TO CHANNEL" : "WROTE TO CHANNEL"; traceBufferText(label, buffer, size); } } static uint32_t bufferSpace(TConn * const connectionP) { return BUFFER_SIZE - connectionP->buffersize; } static void readFromChannel(TConn * const connectionP, bool * const eofP, const char ** const errorP) { /*---------------------------------------------------------------------------- Read some data from the channel of Connection *connectionP. Iff there is none available to read, return *eofP == true. -----------------------------------------------------------------------------*/ uint32_t bytesRead; bool readError; ChannelRead(connectionP->channelP, connectionP->buffer.b + connectionP->buffersize, bufferSpace(connectionP) - 1, &bytesRead, &readError); if (readError) xmlrpc_asprintf(errorP, "Error reading from channel"); else { *errorP = NULL; if (bytesRead > 0) { *eofP = FALSE; traceChannelRead(connectionP, bytesRead); connectionP->inbytes += bytesRead; connectionP->buffersize += bytesRead; connectionP->buffer.t[connectionP->buffersize] = '\0'; } else *eofP = TRUE; } } static void dealWithReadTimeout(bool * const timedOutP, bool const timedOut, uint32_t const timeout, const char ** const errorP) { if (timedOutP) *timedOutP = timedOut; else { if (timedOut) xmlrpc_asprintf(errorP, "Read from Abyss client " "connection timed out after %u seconds " "or was interrupted", timeout); } } static void dealWithReadEof(bool * const eofP, bool const eof, const char ** const errorP) { if (eofP) *eofP = eof; else { if (eof) xmlrpc_asprintf(errorP, "Read from Abyss client " "connection failed because client closed the " "connection"); } } void ConnRead(TConn * const connectionP, uint32_t const timeout, bool * const eofP, bool * const timedOutP, const char ** const errorP) { /*---------------------------------------------------------------------------- Read some stuff on connection *connectionP from the channel. Read it into the connection's buffer. Don't wait more than 'timeout' seconds for data to arrive. If no data has arrived by then and 'timedOutP' is null, fail. If 'timedOut' is non-null, return as *timedOutP whether 'timeout' seconds passed without any data arriving. Also, stop waiting upon any interruption and treat it the same as a timeout. An interruption is either a signal received (and caught) at an appropriate time or a ChannelInterrupt() call before or during the wait. If 'eofP' is non-null, return *eofP == true, without reading anything, iff there will no more data forthcoming on the connection because client has closed the connection. If 'eofP' is null, fail in that case. -----------------------------------------------------------------------------*/ uint32_t const timeoutMs = timeout * 1000; if (timeoutMs < timeout) /* Arithmetic overflow */ xmlrpc_asprintf(errorP, "Timeout value is too large"); else { bool const waitForRead = TRUE; bool const waitForWrite = FALSE; bool readyForRead; bool failed; ChannelWait(connectionP->channelP, waitForRead, waitForWrite, timeoutMs, &readyForRead, NULL, &failed); if (failed) xmlrpc_asprintf(errorP, "Wait for stuff to arrive from client failed."); else { bool eof; if (readyForRead) { readFromChannel(connectionP, &eof, errorP); } else { /* Wait was interrupted, either by our requested timeout, a (caught) signal, or a ChannelInterrupt(). */ traceReadTimeout(connectionP, timeout); *errorP = NULL; eof = FALSE; } if (!*errorP) dealWithReadTimeout(timedOutP, !readyForRead, timeout, errorP); if (!*errorP) dealWithReadEof(eofP, eof, errorP); } } } bool ConnWrite(TConn * const connectionP, const void * const buffer, uint32_t const size) { bool failed; ChannelWrite(connectionP->channelP, buffer, size, &failed); traceChannelWrite(connectionP, buffer, size, failed); if (!failed) connectionP->outbytes += size; return !failed; } bool ConnWriteFromFile(TConn * const connectionP, const TFile * const fileP, uint64_t const start, uint64_t const last, void * const buffer, uint32_t const buffersize, uint32_t const rate) { /*---------------------------------------------------------------------------- Write the contents of the file stream *fileP, from offset 'start' up through 'last', to the HTTP connection *connectionP. Meter the reading so as not to read more than 'rate' bytes per second. Use the 'bufferSize' bytes at 'buffer' as an internal buffer for this. -----------------------------------------------------------------------------*/ bool retval; uint32_t waittime; bool success; uint32_t readChunkSize; if (rate > 0) { readChunkSize = MIN(buffersize, rate); /* One second's worth */ waittime = (1000 * buffersize) / rate; } else { readChunkSize = buffersize; waittime = 0; } success = FileSeek(fileP, start, SEEK_SET); if (!success) retval = FALSE; else { uint64_t const totalBytesToRead = last - start + 1; uint64_t bytesread; bytesread = 0; /* initial value */ while (bytesread < totalBytesToRead) { uint64_t const bytesLeft = totalBytesToRead - bytesread; uint64_t const bytesToRead64 = MIN(readChunkSize, bytesLeft); uint32_t const bytesToRead = (uint32_t)bytesToRead64; uint32_t bytesReadThisTime; assert(bytesToRead == bytesToRead64); /* readChunkSize is uint32 */ bytesReadThisTime = FileRead(fileP, buffer, bytesToRead); bytesread += bytesReadThisTime; if (bytesReadThisTime > 0) ConnWrite(connectionP, buffer, bytesReadThisTime); else break; if (waittime > 0) xmlrpc_millisecond_sleep(waittime); } retval = (bytesread >= totalBytesToRead); } return retval; } TServer * ConnServer(TConn * const connectionP) { return connectionP->server; } void ConnFormatClientAddr(TConn * const connectionP, const char ** const clientAddrPP) { ChannelFormatPeerInfo(connectionP->channelP, clientAddrPP); } /******************************************************************************* ** ** conn.c ** ** This file is part of the ABYSS Web server project. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ xmlrpc-c-1.33.14/lib/abyss/src/conn.h000066400000000000000000000072461236133176700172160ustar00rootroot00000000000000#ifndef CONN_H_INCLUDED #define CONN_H_INCLUDED #include "bool.h" #include "xmlrpc-c/abyss.h" #include "thread.h" struct TFile; #define BUFFER_SIZE 4096 struct _TConn { struct _TConn * nextOutstandingP; /* Link to the next connection in the list of outstanding connections */ TServer * server; uint32_t buffersize; /* Index into the connection buffer (buffer[], below) where the next byte read on the connection will go. */ uint32_t bufferpos; /* Index into the connection buffer (buffer[], below) where the next byte to be delivered to the user is. */ uint32_t inbytes,outbytes; TChannel * channelP; void * channelInfoP; /* Information about the channel, such as who is on the other end. Format depends on the type of channel. The user of the connection is expected to know that type, because he supplied the channel when he created the channel. NULL means no channel info is available. */ bool hasOwnThread; TThread * threadP; bool finished; /* We have done all the processing there is to do on this connection, other than possibly notifying someone that we're done. One thing this signifies is that any thread or process that the connection spawned is dead or will be dead soon, so one could reasonably wait for it to be dead, e.g. with pthread_join(). Note that one can scan a bunch of processes for 'finished' status, but sometimes can't scan a bunch of threads for liveness. */ const char * trace; TThreadProc * job; /* The function to run, in a connection thread, to conduct business on the connection. It reads stuff and writes stuff and, when it is done with the connection, exits. */ TThreadDoneFn * done; union { unsigned char b[BUFFER_SIZE]; /* Just bytes */ char t[BUFFER_SIZE]; /* Taken as text */ } buffer; }; typedef struct _TConn TConn; TConn * ConnAlloc(void); void ConnFree(TConn * const connectionP); void ConnCreate(TConn ** const connectionPP, TServer * const serverP, TChannel * const channelP, void * const channelInfoP, TThreadProc * const job, size_t const jobStackSize, TThreadDoneFn * const done, enum abyss_foreback const foregroundBackground, bool const useSigchld, const char ** const errorP); bool ConnProcess(TConn * const connectionP); bool ConnKill(TConn * const connectionP); void ConnWaitAndRelease(TConn * const connectionP); bool ConnWrite(TConn * const connectionP, const void * const buffer, uint32_t const size); void ConnRead(TConn * const connectionP, uint32_t const timeout, bool * const eofP, bool * const timedOutP, const char ** const errorP); void ConnReadInit(TConn * const connectionP); bool ConnWriteFromFile(TConn * const connectionP, const struct TFile * const fileP, uint64_t const start, uint64_t const last, void * const buffer, uint32_t const buffersize, uint32_t const rate); TServer * ConnServer(TConn * const connectionP); void ConnFormatClientAddr(TConn * const connectionP, const char ** const clientAddrPP); #endif xmlrpc-c-1.33.14/lib/abyss/src/data.c000066400000000000000000000361461236133176700171660ustar00rootroot00000000000000/****************************************************************************** ** ** list.c ** ** This file is part of the ABYSS Web server project. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** *******************************************************************************/ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_platform.h" #include "xmlrpc-c/abyss.h" #include "token.h" #include "data.h" /********************************************************************* ** List *********************************************************************/ void ListInit(TList * const sl) { sl->item=NULL; sl->size=sl->maxsize=0; sl->autofree=FALSE; } void ListInitAutoFree(TList * const sl) { sl->item=NULL; sl->size=sl->maxsize=0; sl->autofree=TRUE; } void ListFree(TList * const sl) { if (sl->item) { if (sl->autofree) { unsigned int i; for (i = sl->size; i > 0; --i) free(sl->item[i-1]); } free(sl->item); } sl->item = NULL; sl->size = 0; sl->maxsize = 0; } void ListFreeItems(TList * const sl) { if (sl->item) { unsigned int i; for (i = sl->size; i > 0; --i) free(sl->item[i-1]); } } bool ListAdd(TList * const sl, void * const str) { /*---------------------------------------------------------------------------- Add an item to the end of the list. -----------------------------------------------------------------------------*/ bool success; if (sl->size >= sl->maxsize) { uint16_t newSize = sl->maxsize + 16; void **newitem; newitem = realloc(sl->item, newSize * sizeof(void *)); if (newitem) { sl->item = newitem; sl->maxsize = newSize; } } if (sl->size >= sl->maxsize) success = FALSE; else { success = TRUE; sl->item[sl->size++] = str; } return success; } void ListRemove(TList * const sl) { /*---------------------------------------------------------------------------- Remove the last item from the list. -----------------------------------------------------------------------------*/ assert(sl->size > 0); --sl->size; } bool ListAddFromString(TList * const list, const char * const stringArg) { bool retval; if (!stringArg) retval = TRUE; else { char * buffer; buffer = strdup(stringArg); if (!buffer) retval = FALSE; else { bool endOfString; bool error; char * c; for (c = &buffer[0], endOfString = FALSE, error = FALSE; !endOfString && !error; ) { const char * t; NextToken((const char **)&c); while (*c == ',') ++c; t = GetToken(&c); if (!t) endOfString = TRUE; else { char * p; for (p = c - 2; *p == ','; --p) *p = '\0'; if (t[0] != '\0') { bool added; added = ListAdd(list, (void*)t); if (!added) error = TRUE; } } } retval = !error; xmlrpc_strfree(buffer); } } return retval; } bool ListFindString(TList * const listP, const char * const str, uint16_t * const indexP) { if (listP->item && str) { unsigned int i; for (i = 0; i < listP->size; ++i) { if (xmlrpc_streq(str, (char *)(listP->item[i]))) { *indexP = i; return TRUE; } } } return FALSE; } /********************************************************************* ** Buffer *********************************************************************/ bool BufferAlloc(TBuffer * const buf, xmlrpc_uint32_t const memsize) { /* ************** Implement the static buffers ***/ buf->staticid=0; buf->data=(void *)malloc(memsize); if (buf->data) { buf->size=memsize; return TRUE; } else { buf->size=0; return FALSE; }; } void BufferFree(TBuffer * const buf) { if (buf->staticid) { /* ************** Implement the static buffers ***/ } else free(buf->data); buf->size=0; buf->staticid=0; } bool BufferRealloc(TBuffer * const buf, xmlrpc_uint32_t const memsize) { if (buf->staticid) { TBuffer b; if (memsize<=buf->size) return TRUE; if (BufferAlloc(&b,memsize)) { memcpy(b.data,buf->data,buf->size); BufferFree(buf); *buf=b; return TRUE; } } else { void *d; d=realloc(buf->data,memsize); if (d) { buf->data=d; buf->size=memsize; return TRUE; } } return FALSE; } /********************************************************************* ** String *********************************************************************/ bool StringAlloc(TString * const stringP) { bool succeeded; stringP->size = 0; succeeded = BufferAlloc(&stringP->buffer, 256); if (succeeded) { *(char *)(stringP->buffer.data) = '\0'; return TRUE; } else return FALSE; } bool StringConcat(TString * const stringP, const char * const string2) { uint32_t const len = strlen(string2); if (len + stringP->size + 1 > stringP->buffer.size) { bool succeeded; succeeded = BufferRealloc( &stringP->buffer, ((len + stringP->size + 1 + 256) / 256) * 256); if (!succeeded) return FALSE; } strcat((char *)(stringP->buffer.data), string2); stringP->size += len; return TRUE; } bool StringBlockConcat(TString * const stringP, const char * const string2, char ** const ref) { uint32_t const len = strlen(string2) + 1; if (len + stringP->size > stringP->buffer.size) { bool succeeded; succeeded = BufferRealloc( &stringP->buffer, ((len + stringP->size + 1 + 256) / 256) * 256); if (!succeeded) return FALSE; } *ref = (char *)(stringP->buffer.data) + stringP->size; memcpy(*ref, string2, len); stringP->size += len; return TRUE; } void StringFree(TString * const stringP) { stringP->size = 0; BufferFree(&stringP->buffer); } char * StringData(TString * const stringP) { return (char *)stringP->buffer.data; } /********************************************************************* ** Hash *********************************************************************/ static uint16_t Hash16(const char * const start) { const char * s; uint16_t i; s = start; i = 0; while(*s) i = i * 37 + *s++; return i; } /********************************************************************* ** Table *********************************************************************/ void TableInit(TTable * const t) { t->item=NULL; t->size=t->maxsize=0; } void TableFree(TTable * const t) { uint16_t i; if (t->item) { if (t->size) for (i=t->size;i>0;i--) { free(t->item[i-1].name); free(t->item[i-1].value); }; free(t->item); } TableInit(t); } bool TableFindIndex(TTable * const t, const char * const name, uint16_t * const index) { uint16_t i,hash=Hash16(name); if ((t->item) && (t->size>0) && (*indexsize)) { for (i=*index;isize;i++) if (hash==t->item[i].hash) if (xmlrpc_streq(t->item[i].name,name)) { *index=i; return TRUE; }; }; return FALSE; } bool TableAddReplace(TTable * const t, const char * const name, const char * const value) { uint16_t i=0; if (TableFindIndex(t,name,&i)) { free(t->item[i].value); if (value) t->item[i].value=strdup(value); else { free(t->item[i].name); if (--t->size>0) t->item[i]=t->item[t->size]; }; return TRUE; } else return TableAdd(t,name,value); } bool TableAdd(TTable * const t, const char * const name, const char * const value) { if (t->size>=t->maxsize) { TTableItem *newitem; t->maxsize+=16; newitem=(TTableItem *)realloc(t->item,(t->maxsize)*sizeof(TTableItem)); if (newitem) t->item=newitem; else { t->maxsize-=16; return FALSE; } } t->item[t->size].name=strdup(name); t->item[t->size].value=strdup(value); t->item[t->size].hash=Hash16(name); ++t->size; return TRUE; } char * TableFind(TTable * const t, const char * const name) { uint16_t i=0; if (TableFindIndex(t,name,&i)) return t->item[i].value; else return NULL; } /********************************************************************* ** Pool *********************************************************************/ static TPoolZone * PoolZoneAlloc(uint32_t const zonesize) { TPoolZone * poolZoneP; MALLOCARRAY(poolZoneP, zonesize); if (poolZoneP) { poolZoneP->pos = &poolZoneP->data[0]; poolZoneP->maxpos = poolZoneP->pos + zonesize; poolZoneP->next = NULL; poolZoneP->prev = NULL; } return poolZoneP; } static void PoolZoneFree(TPoolZone * const poolZoneP) { free(poolZoneP); } bool PoolCreate(TPool * const poolP, uint32_t const zonesize) { bool success; poolP->zonesize = zonesize; poolP->lockP = xmlrpc_lock_create(); if (poolP->lockP) { TPoolZone * const firstZoneP = PoolZoneAlloc(zonesize); if (firstZoneP != NULL) { poolP->firstzone = firstZoneP; poolP->currentzone = firstZoneP; success = TRUE; } else success = FALSE; if (!success) poolP->lockP->destroy(poolP->lockP); } else success = FALSE; return success; } void * PoolAlloc(TPool * const poolP, uint32_t const size) { /*---------------------------------------------------------------------------- Allocate a block of size 'size' from pool 'poolP'. -----------------------------------------------------------------------------*/ void * retval; if (size == 0) retval = NULL; else { poolP->lockP->acquire(poolP->lockP); { TPoolZone * const curPoolZoneP = poolP->currentzone; if (curPoolZoneP->pos + size < curPoolZoneP->maxpos) { retval = curPoolZoneP->pos; curPoolZoneP->pos += size; } else { uint32_t const zonesize = MAX(size, poolP->zonesize); TPoolZone * const newPoolZoneP = PoolZoneAlloc(zonesize); if (newPoolZoneP) { newPoolZoneP->prev = curPoolZoneP; newPoolZoneP->next = curPoolZoneP->next; curPoolZoneP->next = newPoolZoneP; poolP->currentzone = newPoolZoneP; retval= newPoolZoneP->data; newPoolZoneP->pos = newPoolZoneP->data + size; } else retval = NULL; } } poolP->lockP->release(poolP->lockP); } return retval; } void PoolReturn(TPool * const poolP, void * const blockP) { /*---------------------------------------------------------------------------- Return the block at 'blockP' to the pool 'poolP'. WE ASSUME THAT IS THE MOST RECENTLY ALLOCATED AND NOT RETURNED BLOCK IN THE POOL. -----------------------------------------------------------------------------*/ TPoolZone * const curPoolZoneP = poolP->currentzone; assert((char*)curPoolZoneP->data < (char*)blockP && (char*)blockP < (char*)curPoolZoneP->pos); curPoolZoneP->pos = blockP; if (curPoolZoneP->pos == curPoolZoneP->data) { /* That emptied out the current zone. Free it and make the previous zone current. */ assert(curPoolZoneP->prev); /* entry condition */ curPoolZoneP->prev->next = NULL; PoolZoneFree(curPoolZoneP); } } void PoolFree(TPool * const poolP) { TPoolZone * poolZoneP; TPoolZone * nextPoolZoneP; for (poolZoneP = poolP->firstzone; poolZoneP; poolZoneP = nextPoolZoneP) { nextPoolZoneP = poolZoneP->next; free(poolZoneP); } poolP->lockP->destroy(poolP->lockP); } const char * PoolStrdup(TPool * const poolP, const char * const origString) { char * newString; if (origString == NULL) newString = NULL; else { newString = PoolAlloc(poolP, strlen(origString) + 1); if (newString != NULL) strcpy(newString, origString); } return newString; } xmlrpc-c-1.33.14/lib/abyss/src/data.h000066400000000000000000000065301236133176700171650ustar00rootroot00000000000000#ifndef DATA_H_INCLUDED #define DATA_H_INCLUDED #include "bool.h" #include "int.h" struct lock; /********************************************************************* ** Buffer *********************************************************************/ typedef struct { void *data; xmlrpc_uint32_t size; xmlrpc_uint32_t staticid; } TBuffer; bool BufferAlloc(TBuffer * const buf, xmlrpc_uint32_t const memsize); bool BufferRealloc(TBuffer * const buf, xmlrpc_uint32_t const memsize); void BufferFree(TBuffer * const buf); /********************************************************************* ** String *********************************************************************/ typedef struct { TBuffer buffer; xmlrpc_uint32_t size; } TString; bool StringAlloc(TString * const stringP); bool StringConcat(TString * const stringP, const char * const string2); bool StringBlockConcat(TString * const stringP, const char * const string2, char ** const ref); void StringFree(TString * const stringP); char * StringData(TString * const stringP); /********************************************************************* ** List *********************************************************************/ typedef struct { void **item; uint16_t size; uint16_t maxsize; bool autofree; } TList; void ListInit(TList * const listP); void ListInitAutoFree(TList * const listP); void ListFree(TList * const listP); void ListFreeItems(TList * const listP); bool ListAdd(TList * const listP, void * const str); void ListRemove(TList * const listP); bool ListAddFromString(TList * const listP, const char * const c); bool ListFindString(TList * const listP, const char * const str, uint16_t * const indexP); typedef struct { char *name,*value; uint16_t hash; } TTableItem; typedef struct { TTableItem *item; uint16_t size,maxsize; } TTable; void TableInit(TTable * const t); void TableFree(TTable * const t); bool TableAdd(TTable * const t, const char * const name, const char * const value); bool TableAddReplace(TTable * const t, const char * const name, const char * const value); bool TableFindIndex(TTable * const t, const char * const name, uint16_t * const index); char * TableFind(TTable * const t, const char * const name); /********************************************************************* ** Pool *********************************************************************/ typedef struct _TPoolZone { char * pos; char * maxpos; struct _TPoolZone * next; struct _TPoolZone * prev; /* char data[0]; Some compilers don't accept this */ char data[1]; } TPoolZone; typedef struct { TPoolZone * firstzone; TPoolZone * currentzone; uint32_t zonesize; struct lock * lockP; } TPool; bool PoolCreate(TPool * const poolP, uint32_t const zonesize); void PoolFree(TPool * const poolP); void * PoolAlloc(TPool * const poolP, uint32_t const size); void PoolReturn(TPool * const poolP, void * const blockP); const char * PoolStrdup(TPool * const poolP, const char * const origString); #endif xmlrpc-c-1.33.14/lib/abyss/src/date.c000066400000000000000000000121411236133176700171570ustar00rootroot00000000000000#include #include #include #include #include #include #include "bool.h" #include "int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/time_int.h" #include "xmlrpc-c/abyss.h" #include "date.h" /********************************************************************* ** Date *********************************************************************/ static char *_DateDay[7]= { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" }; static char *_DateMonth[12]= { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; void DateToString(time_t const datetime, const char ** const dateStringP) { struct tm brokenTime; xmlrpc_gmtime(datetime, &brokenTime); if (mktime(&brokenTime) == (time_t)-1) *dateStringP = NULL; else xmlrpc_asprintf(dateStringP, "%s, %02u %s %04u %02u:%02u:%02u UTC", _DateDay[brokenTime.tm_wday], brokenTime.tm_mday, _DateMonth[brokenTime.tm_mon], 1900 + brokenTime.tm_year, brokenTime.tm_hour, brokenTime.tm_min, brokenTime.tm_sec); } static const char * tzOffsetStr(struct tm const tm, time_t const datetime) { const char * retval; time_t timeIfUtc; const char * error; xmlrpc_timegm(&tm, &timeIfUtc, &error); if (error) { xmlrpc_strfree(error); xmlrpc_asprintf(&retval, "%s", "+????"); } else { int const tzOffset = (int)(datetime - timeIfUtc); assert(tzOffset == datetime - timeIfUtc); xmlrpc_asprintf(&retval, "%+03d%02d", tzOffset/3600, abs(tzOffset % 3600)/60); } return retval; } void DateToLogString(time_t const datetime, const char ** const dateStringP) { const char * tzo; struct tm tm; xmlrpc_localtime(datetime, &tm); tzo = tzOffsetStr(tm, datetime); xmlrpc_asprintf(dateStringP, "%02d/%s/%04d:%02d:%02d:%02d %s", tm.tm_mday, _DateMonth[tm.tm_mon], 1900 + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec, tzo); xmlrpc_strfree(tzo); } void DateDecode(const char * const dateString, bool * const validP, time_t * const datetimeP) { /*---------------------------------------------------------------------------- Return the datetime represented by 'dateString', which is in the format used in an HTTP header. We assume that format is always UTC-based; I don't know if HTTP actually requires that -- maybe it could be some local time. -----------------------------------------------------------------------------*/ int rc; const char * s; unsigned int monthOff; struct tm tm; bool error; s = &dateString[0]; /* Ignore spaces, day name and spaces */ while ((*s==' ') || (*s=='\t')) ++s; while ((*s!=' ') && (*s!='\t')) ++s; while ((*s==' ') || (*s=='\t')) ++s; error = false; /* initial value */ /* try to recognize the date format */ rc = sscanf(s, "%*s %d %d:%d:%d %d%*s", &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &tm.tm_year); if (rc == 5) monthOff = 0; else { int rc; rc = sscanf(s, "%d %n%*s %d %d:%d:%d GMT%*s", &tm.tm_mday, &monthOff, &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); if (rc != 5) { int rc; rc = sscanf(s, "%d-%n%*[A-Za-z]-%d %d:%d:%d GMT%*s", &tm.tm_mday, &monthOff, &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); if (rc != 5) error = true; } } if (!error) { const char * monthName = s + monthOff; /* This is actually just the point in 'dateString' where the month name begins -- it's not a nul-terminated string */ unsigned int i; bool gotMonth; for (i = 0, gotMonth = false; i < 12; ++i) { const char * p; p =_DateMonth[i]; if (tolower(*p++) == tolower(monthName[0])) if (*p++ == tolower(monthName[1])) if (*p == tolower(monthName[2])) { gotMonth = true; tm.tm_mon = i; } } if (!gotMonth) error = true; else { if (tm.tm_year > 1900) tm.tm_year -= 1900; else { if (tm.tm_year < 70) tm.tm_year += 100; } tm.tm_isdst = 0; { const char * timeError; xmlrpc_timegm(&tm, datetimeP, &timeError); if (timeError) { error = TRUE; xmlrpc_strfree(timeError); } } } } *validP = !error; } abyss_bool DateInit(void) { return true; } xmlrpc-c-1.33.14/lib/abyss/src/date.h000066400000000000000000000006441236133176700171710ustar00rootroot00000000000000#ifndef DATE_H_INCLUDED #define DATE_H_INCLUDED #include #include "bool.h" void DateToString(time_t const datetime, const char ** const dateStringP); void DateToLogString(time_t const datetime, const char ** const dateStringP); void DateDecode(const char * const dateString, bool * const validP, time_t * const datetimeP); #endif xmlrpc-c-1.33.14/lib/abyss/src/file.c000066400000000000000000000223141236133176700171640ustar00rootroot00000000000000/****************************************************************************** ** ** file.c ** ** This file is part of the ABYSS Web server project. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ #include "xmlrpc_config.h" #include "mallocvar.h" #define _CRT_SECURE_NO_WARNINGS /* Tell msvcrt not to warn about functions that are often misused and cause security exposures. */ #define _FILE_OFFSET_BITS 64 /* Tell GNU libc to make off_t 64 bits and all the POSIX file functions the versions that handle 64 bit file offsets. */ #define _LARGE_FILES /* Same as above, but for AIX */ #include #if MSVCRT #include typedef __int64 readwriterc_t; #else #include #include #include #include typedef ssize_t readwriterc_t; #endif #include "bool.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/abyss.h" #include "file.h" bool const win32 = #ifdef _WIN32 TRUE; #else FALSE; #endif struct TFileFind { #ifdef _WIN32 #if MSVCRT intptr_t handle; #else HANDLE handle; #endif #else char path[NAME_MAX+1]; DIR * handle; #endif }; /********************************************************************* ** File *********************************************************************/ static void createFileImage(TFile ** const filePP, const char * const name, uint32_t const attrib, bool const createFile, bool * const succeededP) { TFile * fileP; MALLOCVAR(fileP); if (fileP == NULL) *succeededP = FALSE; else { int rc; if (createFile) rc = open(name, attrib | O_CREAT, XMLRPC_S_IWUSR | XMLRPC_S_IRUSR); else rc = open(name, attrib); if (rc < 0) *succeededP = FALSE; else { fileP->fd = rc; *succeededP = TRUE; } if (!*succeededP) free(fileP); } *filePP = fileP; } bool FileOpen(TFile ** const filePP, const char * const name, uint32_t const attrib) { bool succeeded; createFileImage(filePP, name, attrib, FALSE, &succeeded); return succeeded; } bool FileOpenCreate(TFile ** const filePP, const char * const name, uint32_t const attrib) { bool succeeded; createFileImage(filePP, name, attrib, TRUE, &succeeded); return succeeded; } bool FileWrite(const TFile * const fileP, const void * const buffer, uint32_t const len) { readwriterc_t rc; rc = write(fileP->fd, buffer, len); return (rc > 0 && (uint32_t)rc == len); } int32_t FileRead(const TFile * const fileP, void * const buffer, uint32_t const len) { return read(fileP->fd, buffer, len); } bool FileSeek(const TFile * const fileP, uint64_t const pos, uint32_t const attrib) { int64_t rc; #if MSVCRT rc = _lseeki64(fileP->fd, pos, attrib); #else rc = lseek(fileP->fd, pos, attrib); #endif return (rc >= 0); } uint64_t FileSize(const TFile * const fileP) { #if MSVCRT return (_filelength(fileP->fd)); #else struct stat fs; fstat(fileP->fd, &fs); return (fs.st_size); #endif } bool FileClose(TFile * const fileP) { int rc; rc = close(fileP->fd); if (rc >= 0) free(fileP); return (rc >= 0); } bool FileStat(const char * const filename, TFileStat * const filestat) { int rc; #if MSVCRT rc = _stati64(filename,filestat); #else rc = stat(filename,filestat); #endif return (rc >= 0); } static void fileFindFirstWin(TFileFind * const filefindP ATTR_UNUSED, const char * const path, TFileInfo * const fileinfo ATTR_UNUSED, bool * const retP ATTR_UNUSED) { const char * search; xmlrpc_asprintf(&search, "%s\\*", path); #if MSVCRT filefindP->handle = _findfirsti64(search, fileinfo); *retP = filefindP->handle != -1; #else #ifdef _WIN32 filefindP->handle = FindFirstFile(search, &fileinfo->data); *retP = filefindP->handle != INVALID_HANDLE_VALUE; if (*retP) { LARGE_INTEGER li; li.LowPart = fileinfo->data.nFileSizeLow; li.HighPart = fileinfo->data.nFileSizeHigh; strcpy( fileinfo->name, fileinfo->data.cFileName ); fileinfo->attrib = fileinfo->data.dwFileAttributes; fileinfo->size = li.QuadPart; fileinfo->time_write = fileinfo->data.ftLastWriteTime.dwLowDateTime; } #endif #endif xmlrpc_strfree(search); } static void fileFindFirstPosix(TFileFind * const filefindP, const char * const path, TFileInfo * const fileinfo, bool * const retP) { #if !MSVCRT strncpy(filefindP->path, path, NAME_MAX); filefindP->path[NAME_MAX] = '\0'; filefindP->handle = opendir(path); if (filefindP->handle) *retP = FileFindNext(filefindP, fileinfo); else *retP = FALSE; #endif } bool FileFindFirst(TFileFind ** const filefindPP, const char * const path, TFileInfo * const fileinfo) { bool succeeded; TFileFind * filefindP; MALLOCVAR(filefindP); if (filefindP == NULL) succeeded = FALSE; else { if (win32) fileFindFirstWin(filefindP, path, fileinfo, &succeeded); else fileFindFirstPosix(filefindP, path, fileinfo, &succeeded); if (!succeeded) free(filefindP); } *filefindPP = filefindP; return succeeded; } static void fileFindNextWin(TFileFind * const filefindP ATTR_UNUSED, TFileInfo * const fileinfo ATTR_UNUSED, bool * const retvalP ATTR_UNUSED) { #if MSVCRT *retvalP = _findnexti64(filefindP->handle, fileinfo) != -1; #else #ifdef _WIN32 bool found; found = FindNextFile(filefindP->handle, &fileinfo->data); if (found) { LARGE_INTEGER li; li.LowPart = fileinfo->data.nFileSizeLow; li.HighPart = fileinfo->data.nFileSizeHigh; strcpy(fileinfo->name, fileinfo->data.cFileName); fileinfo->attrib = fileinfo->data.dwFileAttributes; fileinfo->size = li.QuadPart; fileinfo->time_write = fileinfo->data.ftLastWriteTime.dwLowDateTime; } *retvalP = found; #endif #endif } static void fileFindNextPosix(TFileFind * const filefindP, TFileInfo * const fileinfoP, bool * const retvalP) { #ifndef _WIN32 struct dirent * deP; deP = readdir(filefindP->handle); if (deP) { char z[NAME_MAX+1]; struct stat fs; strcpy(fileinfoP->name, deP->d_name); strcpy(z, filefindP->path); strncat(z, "/",NAME_MAX); strncat(z, fileinfoP->name, NAME_MAX); z[NAME_MAX] = '\0'; stat(z, &fs); if (fs.st_mode & S_IFDIR) fileinfoP->attrib = A_SUBDIR; else fileinfoP->attrib = 0; fileinfoP->size = fs.st_size; fileinfoP->time_write = fs.st_mtime; *retvalP = TRUE; } else *retvalP = FALSE; #endif } bool FileFindNext(TFileFind * const filefindP, TFileInfo * const fileinfo) { bool retval; if (win32) fileFindNextWin(filefindP, fileinfo, &retval); else fileFindNextPosix(filefindP, fileinfo, &retval); return retval; } void FileFindClose(TFileFind * const filefindP) { #ifdef _WIN32 #if MSVCRT _findclose(filefindP->handle); #else FindClose(filefindP->handle); #endif #else closedir(filefindP->handle); #endif free(filefindP); } xmlrpc-c-1.33.14/lib/abyss/src/file.h000066400000000000000000000046051236133176700171740ustar00rootroot00000000000000#ifndef FILE_H_INCLUDED #define FILE_H_INCLUDED #include #include #include #include #include "bool.h" #include "int.h" #include "xmlrpc-c/abyss.h" #ifndef NAME_MAX #define NAME_MAX 1024 #endif #ifdef WIN32 #ifndef __BORLANDC__ #define O_APPEND _O_APPEND #define O_CREAT _O_CREAT #define O_EXCL _O_EXCL #define O_RDONLY _O_RDONLY #define O_RDWR _O_RDWR #define O_TRUNC _O_TRUNC #define O_WRONLY _O_WRONLY #define O_TEXT _O_TEXT #define O_BINARY _O_BINARY #endif #define A_HIDDEN _A_HIDDEN #define A_NORMAL _A_NORMAL #define A_RDONLY _A_RDONLY #define A_SUBDIR _A_SUBDIR #else #define A_SUBDIR 1 #define O_BINARY 0 #define O_TEXT 0 #endif /* WIN32 */ #ifdef WIN32 #if MSVCRT typedef struct _stati64 TFileStat; typedef struct _finddatai64_t TFileInfo; #else /* MSVCRT */ typedef struct stat TFileStat; typedef struct finddata_t { char name[NAME_MAX+1]; int attrib; uint64_t size; time_t time_write; WIN32_FIND_DATA data; } TFileInfo; #endif /* MSVCRT */ #else /* WIN32 */ #include #include typedef struct stat TFileStat; typedef struct finddata_t { char name[NAME_MAX+1]; int attrib; uint64_t size; time_t time_write; } TFileInfo; #endif typedef struct TFileFind TFileFind; typedef struct TFile { int fd; } TFile; bool FileOpen(TFile ** const filePP, const char * const name, uint32_t const attrib); bool FileOpenCreate(TFile ** const filePP, const char * const name, uint32_t const attrib); bool FileClose(TFile * const fileP); bool FileWrite(const TFile * const fileP, const void * const buffer, uint32_t const len); int32_t FileRead(const TFile * const fileP, void * const buffer, uint32_t const len); bool FileSeek(const TFile * const fileP, uint64_t const pos, uint32_t const attrib); uint64_t FileSize(const TFile * const fileP); bool FileStat(const char * const filename, TFileStat * const filestat); bool FileFindFirst(TFileFind ** const filefind, const char * const path, TFileInfo * const fileinfo); bool FileFindNext(TFileFind * const filefind, TFileInfo * const fileinfo); void FileFindClose(TFileFind * const filefind); #endif xmlrpc-c-1.33.14/lib/abyss/src/handler.c000066400000000000000000000541731236133176700176720ustar00rootroot00000000000000/*============================================================================= handler.c =============================================================================== This file contains built-in HTTP request handlers. Copyright information is at end of file =============================================================================*/ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #endif #include #include "xmlrpc_config.h" #include "bool.h" #include "int.h" #include "girmath.h" #include "mallocvar.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/time_int.h" #include "xmlrpc-c/abyss.h" #include "trace.h" #include "session.h" #include "file.h" #include "conn.h" #include "http.h" #include "date.h" #include "abyss_info.h" #include "handler.h" struct BIHandler { const char * filesPath; TList defaultFileNames; MIMEType * mimeTypeP; /* NULL means to use the global MIMEType object */ }; BIHandler * HandlerCreate(void) { struct BIHandler * handlerP; MALLOCVAR(handlerP); if (handlerP) { handlerP->filesPath = strdup(DEFAULT_DOCS); ListInitAutoFree(&handlerP->defaultFileNames); handlerP->mimeTypeP = NULL; } return handlerP; } void HandlerDestroy(BIHandler * const handlerP) { ListFree(&handlerP->defaultFileNames); xmlrpc_strfree(handlerP->filesPath); free(handlerP); } void HandlerSetMimeType(BIHandler * const handlerP, MIMEType * const mimeTypeP) { handlerP->mimeTypeP = mimeTypeP; } void HandlerSetFilesPath(BIHandler * const handlerP, const char * const filesPath) { xmlrpc_strfree(handlerP->filesPath); handlerP->filesPath = strdup(filesPath); } void HandlerAddDefaultFN(BIHandler * const handlerP, const char * const fileName) { ListAdd(&handlerP->defaultFileNames, strdup(fileName)); } typedef int (*TQSortProc)(const void *, const void *); static int cmpfilenames(const TFileInfo **f1,const TFileInfo **f2) { if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR)) return (-1); if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR)) return 1; return strcmp((*f1)->name,(*f2)->name); } static int cmpfiledates(const TFileInfo ** const f1PP, const TFileInfo ** const f2PP) { const TFileInfo * const f1P = *f1PP; const TFileInfo * const f2P = *f2PP; int retval; if ((f1P->attrib & A_SUBDIR) && !(f2P->attrib & A_SUBDIR)) retval = -1; else if (!(f1P->attrib & A_SUBDIR) && (f2P->attrib & A_SUBDIR)) retval = 1; else { assert((int)(f1P->time_write - f2P->time_write) == (f1P->time_write - f2P->time_write)); retval = (int)(f1P->time_write - f2P->time_write); } return retval; } static void determineSortType(const char * const query, bool * const ascendingP, uint16_t * const sortP, bool * const textP, const char ** const errorP) { *ascendingP = TRUE; *sortP = 1; *textP = FALSE; *errorP = NULL; if (query) { if (xmlrpc_streq(query, "plain")) *textP = TRUE; else if (xmlrpc_streq(query, "name-up")) { *sortP = 1; *ascendingP = TRUE; } else if (xmlrpc_streq(query, "name-down")) { *sortP = 1; *ascendingP = FALSE; } else if (xmlrpc_streq(query, "date-up")) { *sortP = 2; *ascendingP = TRUE; } else if (xmlrpc_streq(query, "date-down")) { *sortP = 2; *ascendingP = FALSE; } else { xmlrpc_asprintf(errorP, "invalid query value '%s'", query); } } } static void generateListing(TList * const listP, const char * const dirName, const char * const uri, TPool * const poolP, const char ** const errorP, uint16_t * const responseStatusP) { TFileInfo fileinfo; TFileFind * findhandleP; *errorP = NULL; if (!FileFindFirst(&findhandleP, dirName, &fileinfo)) { *responseStatusP = ResponseStatusFromErrno(errno); xmlrpc_asprintf(errorP, "Can't read first entry in directory"); } else { ListInit(listP); do { TFileInfo * fi; /* Files whose names start with a dot are ignored */ /* This includes implicitly the ./ and ../ */ if (*fileinfo.name == '.') { if (xmlrpc_streq(fileinfo.name, "..")) { if (xmlrpc_streq(uri, "/")) continue; } else continue; } fi = (TFileInfo *)PoolAlloc(poolP, sizeof(fileinfo)); if (fi) { bool success; memcpy(fi, &fileinfo, sizeof(fileinfo)); success = ListAdd(listP, fi); if (!success) xmlrpc_asprintf(errorP, "ListAdd() failed"); } else xmlrpc_asprintf(errorP, "PoolAlloc() failed."); } while (!*errorP && FileFindNext(findhandleP, &fileinfo)); if (*errorP) { *responseStatusP = 500; ListFree(listP); } FileFindClose(findhandleP); } } static void sendDirectoryDocument(TList * const listP, bool const ascending, uint16_t const sort, bool const text, const char * const uri, MIMEType * const mimeTypeP, TSession * const sessionP) { char z[4096]; char *p,z1[26],z2[20],z3[9],u; const char * z4; int16_t i; uint32_t k; if (text) { sprintf(z, "Index of %s" CRLF, uri); i = strlen(z)-2; p = z + i + 2; while (i > 0) { *(p++) = '-'; --i; } *p = '\0'; strcat(z, CRLF CRLF "Name Size " "Date-Time Type" CRLF "------------------------------------" "--------------------------------------------"CRLF); } else { sprintf(z, "Index of %s" "

Index of %s

",
                uri, uri);
        strcat(z, "Name                      Size      "
               "Date-Time             Type
"CRLF); } HTTPWriteBodyChunk(sessionP, z, strlen(z)); /* Sort the files */ qsort(listP->item, listP->size, sizeof(void *), (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates)); /* Write the listing */ if (ascending) i = 0; else i = listP->size - 1; while ((i < listP->size) && (i >= 0)) { TFileInfo * fi; struct tm ftm; fi = listP->item[i]; if (ascending) ++i; else --i; strcpy(z, fi->name); k = strlen(z); if (fi->attrib & A_SUBDIR) { z[k++] = '/'; z[k] = '\0'; } if (k > 24) { z[10] = '\0'; strcpy(z1, z); strcat(z1, "..."); strcat(z1, z + k - 11); k = 24; p = z1 + 24; } else { strcpy(z1, z); ++k; p = z1 + k; while (k < 25) z1[k++] = ' '; z1[25] = '\0'; } xmlrpc_gmtime(fi->time_write, &ftm); sprintf(z2, "%02u/%02u/%04u %02u:%02u:%02u",ftm.tm_mday,ftm.tm_mon+1, ftm.tm_year+1900,ftm.tm_hour,ftm.tm_min,ftm.tm_sec); if (fi->attrib & A_SUBDIR) { strcpy(z3, " -- "); z4 = "Directory"; } else { if (fi->size < 9999) u = 'b'; else { fi->size /= 1024; if (fi->size < 9999) u = 'K'; else { fi->size /= 1024; if (fi->size < 9999) u = 'M'; else u = 'G'; } } sprintf(z3, "%5" PRIu64 " %c", fi->size, u); if (xmlrpc_streq(fi->name, "..")) z4 = ""; else z4 = MIMETypeFromFileName2(mimeTypeP, fi->name); if (!z4) z4 = "Unknown"; } if (text) sprintf(z, "%s%s %s %s %s"CRLF, z1, p, z3, z2, z4); else sprintf(z, "%s%s %s %s %s"CRLF, fi->name, fi->attrib & A_SUBDIR ? "/" : "", z1, p, z3, z2, z4); HTTPWriteBodyChunk(sessionP, z, strlen(z)); } /* Write the tail of the file */ if (text) strcpy(z, SERVER_PLAIN_INFO); else strcpy(z, "
" SERVER_HTML_INFO "" CRLF CRLF); HTTPWriteBodyChunk(sessionP, z, strlen(z)); } static bool notRecentlyModified(TSession * const sessionP, time_t const fileModTime) { bool retval; const char * imsHdr; imsHdr = RequestHeaderValue(sessionP, "if-modified-since"); if (imsHdr) { bool valid; time_t datetime; DateDecode(imsHdr, &valid, &datetime); if (valid) { if (MIN(fileModTime, sessionP->date) <= datetime) retval = TRUE; else retval = FALSE; } else retval = FALSE; } else retval = FALSE; return retval; } static void addLastModifiedHeader(TSession * const sessionP, time_t const fileModTime) { const char * lastModifiedValue; DateToString(MIN(fileModTime, sessionP->date), &lastModifiedValue); if (lastModifiedValue) { ResponseAddField(sessionP, "Last-Modified", lastModifiedValue); xmlrpc_strfree(lastModifiedValue); } } static void handleDirectory(TSession * const sessionP, const char * const dirName, time_t const fileModTime, MIMEType * const mimeTypeP) { bool text; bool ascending; uint16_t sort; /* 1=by name, 2=by date */ const char * error; determineSortType(sessionP->requestInfo.query, &ascending, &sort, &text, &error); if (error) { ResponseStatus(sessionP, 400); xmlrpc_strfree(error); } else if (notRecentlyModified(sessionP, fileModTime)) { ResponseStatus(sessionP, 304); ResponseWriteStart(sessionP); } else { TPool pool; bool succeeded; succeeded = PoolCreate(&pool, 1024); if (!succeeded) ResponseStatus(sessionP, 500); else { TList list; uint16_t responseStatus; const char * error; generateListing(&list, dirName, sessionP->requestInfo.uri, &pool, &error, &responseStatus); if (error) { ResponseStatus(sessionP, responseStatus); xmlrpc_strfree(error); } else { ResponseStatus(sessionP, 200); ResponseContentType(sessionP, text ? "text/plain" : "text/html"); addLastModifiedHeader(sessionP, fileModTime); ResponseChunked(sessionP); ResponseWriteStart(sessionP); if (sessionP->requestInfo.method!=m_head) sendDirectoryDocument(&list, ascending, sort, text, sessionP->requestInfo.uri, mimeTypeP, sessionP); HTTPWriteEndChunk(sessionP); ListFree(&list); } PoolFree(&pool); } } } static void composeEntityHeader(const char ** const entityHeaderP, const char * const mediatype, uint64_t const start, uint64_t const end, uint64_t const filesize) { xmlrpc_asprintf(entityHeaderP, "Content-type: %s" CRLF "Content-range: " "bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64 CRLF "Content-length: %" PRIu64 CRLF CRLF, mediatype, start, end, filesize, end-start+1); } #define BOUNDARY "##123456789###BOUNDARY" static void sendBody(TSession * const sessionP, const TFile * const fileP, uint64_t const filesize, const char * const mediatype, uint64_t const start0, uint64_t const end0) { /*---------------------------------------------------------------------------- 'start0' and 'end0' are meaningful only if the session has ranges. -----------------------------------------------------------------------------*/ char buffer[4096]; if (sessionP->ranges.size == 0) ConnWriteFromFile(sessionP->connP, fileP, 0, filesize - 1, buffer, sizeof(buffer), 0); else if (sessionP->ranges.size == 1) ConnWriteFromFile(sessionP->connP, fileP, start0, end0, buffer, sizeof(buffer), 0); else { uint64_t i; for (i = 0; i <= sessionP->ranges.size; ++i) { ConnWrite(sessionP->connP, "--", 2); ConnWrite(sessionP->connP, BOUNDARY, strlen(BOUNDARY)); ConnWrite(sessionP->connP, CRLF, 2); if (i < sessionP->ranges.size) { uint64_t start; uint64_t end; bool decoded; decoded = RangeDecode((char *)(sessionP->ranges.item[i]), filesize, &start, &end); if (decoded) { /* Entity header, not response header */ const char * entityHeader; composeEntityHeader(&entityHeader, mediatype, start, end, filesize); ConnWrite(sessionP->connP, entityHeader, strlen(entityHeader)); xmlrpc_strfree(entityHeader); ConnWriteFromFile(sessionP->connP, fileP, start, end, buffer, sizeof(buffer), 0); } } } } } static void sendFileAsResponse(TSession * const sessionP, TFile * const fileP, const char * const fileName, time_t const fileModTime, MIMEType * const mimeTypeP) { uint64_t const filesize = FileSize(fileP); const char * const mediatype = MIMETypeGuessFromFile2(mimeTypeP, fileName); uint64_t start; /* Defined only if session has one range */ uint64_t end; /* Defined only if session has one range */ switch (sessionP->ranges.size) { case 0: ResponseStatus(sessionP, 200); break; case 1: { bool decoded; decoded = RangeDecode((char *)(sessionP->ranges.item[0]), filesize, &start, &end); if (!decoded) { ListFree(&sessionP->ranges); ResponseStatus(sessionP, 200); } else { const char * contentRange; xmlrpc_asprintf(&contentRange, "bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64, start, end, filesize); ResponseAddField(sessionP, "Content-range", contentRange); xmlrpc_strfree(contentRange); ResponseContentLength(sessionP, end - start + 1); ResponseStatus(sessionP, 206); } } break; default: ResponseContentType(sessionP, "multipart/ranges; boundary=" BOUNDARY); ResponseStatus(sessionP, 206); break; } if (sessionP->ranges.size == 0) { ResponseContentLength(sessionP, filesize); ResponseContentType(sessionP, mediatype); } addLastModifiedHeader(sessionP, fileModTime); ResponseWriteStart(sessionP); if (sessionP->requestInfo.method != m_head) sendBody(sessionP, fileP, filesize, mediatype, start, end); } static void handleFile(TSession * const sessionP, const char * const fileName, time_t const fileModTime, MIMEType * const mimeTypeP) { /*---------------------------------------------------------------------------- This is an HTTP request handler for a GET. It does the classic web server thing: send the file named in the URL to the client. -----------------------------------------------------------------------------*/ TFile * fileP; bool success; success = FileOpen(&fileP, fileName, O_BINARY | O_RDONLY); if (!success) ResponseStatusErrno(sessionP); else { if (notRecentlyModified(sessionP, fileModTime)) { ResponseStatus(sessionP, 304); ResponseWriteStart(sessionP); } else sendFileAsResponse(sessionP, fileP, fileName, fileModTime, mimeTypeP); FileClose(fileP); } } static void convertToNativeFileName(char * const fileName ATTR_UNUSED) { #ifdef _WIN32 char * p; p = &fileName[0]; while (*p) { if ((*p) == '/') *p= '\\'; ++p; } #endif /* _WIN32 */ } abyss_bool HandlerDefaultBuiltin(TSession * const sessionP) { BIHandler * const handlerP = SessionGetDefaultHandlerCtx(sessionP); char * p; char z[4096]; TFileStat fs; bool endingslash; endingslash = FALSE; /* initial value */ if (!RequestValidURIPath(sessionP)) { ResponseStatus(sessionP, 400); return TRUE; } /* Must check for * (asterisk uri) in the future */ if (sessionP->requestInfo.method == m_options) { ResponseAddField(sessionP, "Allow", "GET, HEAD"); ResponseContentLength(sessionP, 0); ResponseStatus(sessionP, 200); return TRUE; } if ((sessionP->requestInfo.method != m_get) && (sessionP->requestInfo.method != m_head)) { ResponseAddField(sessionP, "Allow", "GET, HEAD"); ResponseStatus(sessionP, 405); return TRUE; } strcpy(z, handlerP->filesPath); strcat(z, sessionP->requestInfo.uri); p = z + strlen(z) - 1; if (*p == '/') { endingslash = TRUE; *p = '\0'; } convertToNativeFileName(z); if (!FileStat(z, &fs)) { ResponseStatusErrno(sessionP); return TRUE; } if (fs.st_mode & S_IFDIR) { /* Redirect to the same directory but with the ending slash ** to avoid problems with some browsers (IE for examples) when ** they generate relative urls */ if (!endingslash) { strcpy(z, sessionP->requestInfo.uri); p = z+strlen(z); *p = '/'; *(p+1) = '\0'; ResponseAddField(sessionP, "Location", z); ResponseStatus(sessionP, 302); ResponseWriteStart(sessionP); return TRUE; } *p = DIRECTORY_SEPARATOR[0]; ++p; { unsigned int i; i = handlerP->defaultFileNames.size; while (i-- > 0) { *p = '\0'; strcat(z, (handlerP->defaultFileNames.item[i])); if (FileStat(z, &fs)) { if (!(fs.st_mode & S_IFDIR)) handleFile(sessionP, z, fs.st_mtime, handlerP->mimeTypeP); } } } *(p-1) = '\0'; if (!FileStat(z, &fs)) { ResponseStatusErrno(sessionP); return TRUE; } handleDirectory(sessionP, z, fs.st_mtime, handlerP->mimeTypeP); } else handleFile(sessionP, z, fs.st_mtime, handlerP->mimeTypeP); return TRUE; } size_t const HandlerDefaultBuiltinStack = 1024; /****************************************************************************** ** ** server.c ** ** This file is part of the ABYSS Web server project. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ xmlrpc-c-1.33.14/lib/abyss/src/handler.h000066400000000000000000000012171236133176700176660ustar00rootroot00000000000000#ifndef HANDLER_H_INCLUDED #define HANDLER_H_INCLUDED #include "bool.h" #include "xmlrpc-c/abyss.h" typedef struct BIHandler BIHandler; BIHandler * HandlerCreate(void); void HandlerDestroy(BIHandler * const handlerP); void HandlerSetMimeType(BIHandler * const handlerP, MIMEType * const mimeTypeP); void HandlerSetFilesPath(BIHandler * const handlerP, const char * const filesPath); void HandlerAddDefaultFN(BIHandler * const handlerP, const char * const fileName); abyss_bool HandlerDefaultBuiltin(TSession * const sessionP); extern size_t const HandlerDefaultBuiltinStack; #endif xmlrpc-c-1.33.14/lib/abyss/src/http.c000066400000000000000000001355711236133176700172360ustar00rootroot00000000000000/* Copyright information is at the end of the file */ #define _XOPEN_SOURCE 600 /* For strdup() */ #define _BSD_SOURCE /* For xmlrpc_strcaseeq() */ #include #include #include #include #include #include #include #include "xmlrpc_config.h" #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/base64_int.h" #include "xmlrpc-c/abyss.h" #include "server.h" #include "session.h" #include "conn.h" #include "token.h" #include "date.h" #include "data.h" #include "http.h" /********************************************************************* ** Request Parser *********************************************************************/ /********************************************************************* ** Request *********************************************************************/ static void initRequestInfo(TRequestInfo * const requestInfoP, httpVersion const httpVersion, const char * const requestLine, TMethod const httpMethod, const char * const host, unsigned int const port, const char * const path, const char * const query) { /*---------------------------------------------------------------------------- Set up the request info structure. For information that is controlled by the header, use the defaults -- I.e. the value that applies if the request contains no applicable header field. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_PTR_OK(requestLine); XMLRPC_ASSERT_PTR_OK(path); requestInfoP->requestline = xmlrpc_strdupsol(requestLine); requestInfoP->method = httpMethod; requestInfoP->host = xmlrpc_strdupnull(host); requestInfoP->port = port; requestInfoP->uri = strdup(path); requestInfoP->query = xmlrpc_strdupnull(query); requestInfoP->from = NULL; requestInfoP->useragent = NULL; requestInfoP->referer = NULL; requestInfoP->user = NULL; if (httpVersion.major > 1 || (httpVersion.major == 1 && httpVersion.minor >= 1)) requestInfoP->keepalive = TRUE; else requestInfoP->keepalive = FALSE; } static void freeRequestInfo(TRequestInfo * const requestInfoP) { xmlrpc_strfreenull(requestInfoP->host); xmlrpc_strfreenull(requestInfoP->user); xmlrpc_strfree(requestInfoP->uri); xmlrpc_strfree(requestInfoP->requestline); } void RequestInit(TSession * const sessionP, TConn * const connectionP) { sessionP->validRequest = false; /* Don't have valid request yet */ time(&sessionP->date); sessionP->connP = connectionP; sessionP->responseStarted = FALSE; sessionP->chunkedwrite = FALSE; sessionP->chunkedwritemode = FALSE; sessionP->continueRequired = FALSE; ListInit(&sessionP->cookies); ListInit(&sessionP->ranges); TableInit(&sessionP->requestHeaderFields); TableInit(&sessionP->responseHeaderFields); sessionP->status = 0; /* No status from handler yet */ StringAlloc(&(sessionP->header)); } void RequestFree(TSession * const sessionP) { if (sessionP->validRequest) freeRequestInfo(&sessionP->requestInfo); ListFree(&sessionP->cookies); ListFree(&sessionP->ranges); TableFree(&sessionP->requestHeaderFields); TableFree(&sessionP->responseHeaderFields); StringFree(&(sessionP->header)); } static char * firstLfPos(TConn * const connectionP, char * const lineStart) { /*---------------------------------------------------------------------------- Return a pointer in the connection's receive buffer to the first LF (linefeed aka newline) character in the buffer at or after 'lineStart'. If there is no LF in the buffer at or after 'lineStart', return NULL. -----------------------------------------------------------------------------*/ const char * const bufferEnd = connectionP->buffer.t + connectionP->buffersize; char * p; for (p = lineStart; p < bufferEnd && *p != LF; ++p); if (p < bufferEnd) return p; else return NULL; } static void getLineInBuffer(TConn * const connectionP, char * const lineStart, time_t const deadline, char ** const lineEndP, bool * const errorP) { /*---------------------------------------------------------------------------- Get a line into the connection's read buffer, starting at position 'lineStart', if there isn't one already there. 'lineStart' is either within the buffer or just after it. Read the channel until we get a full line, except fail if we don't get one by 'deadline'. -----------------------------------------------------------------------------*/ bool error; char * lfPos; assert(lineStart <= connectionP->buffer.t + connectionP->buffersize); error = FALSE; /* initial value */ lfPos = NULL; /* initial value */ while (!error && !lfPos) { int const timeLeft = (int)(deadline - time(NULL)); if (timeLeft <= 0) error = TRUE; else { lfPos = firstLfPos(connectionP, lineStart); if (!lfPos) { const char * readError; ConnRead(connectionP, timeLeft, NULL, NULL, &readError); if (readError) { error = TRUE; xmlrpc_strfree(readError); } } } } *errorP = error; *lineEndP = lfPos + 1; } static bool isContinuationLine(const char * const line) { return (line[0] == ' ' || line[0] == '\t'); } static bool isEmptyLine(const char * const line) { return (line[0] == '\n' || (line[0] == '\r' && line[1] == '\n')); } static void convertLineEnd(char * const lineStart, char * const prevLineStart, char const newVal) { /*---------------------------------------------------------------------------- Assuming a line begins at 'lineStart' and the line before it (the "previous line") begins at 'prevLineStart', replace the line delimiter at the end of the previous line with the character 'newVal'. The line delimiter is either CRLF or LF. In the CRLF case, we replace both CR and LF with 'newVal'. -----------------------------------------------------------------------------*/ assert(lineStart >= prevLineStart + 1); *(lineStart-1) = newVal; if (prevLineStart + 1 < lineStart && *(lineStart-2) == CR) *(lineStart-2) = newVal; } static void getRestOfField(TConn * const connectionP, char * const lineEnd, time_t const deadline, const char ** const fieldEndP, bool * const errorP) { /*---------------------------------------------------------------------------- Given that the read buffer for connection *connectionP contains (at its current read position) the first line of an HTTP header field, which ends at position 'lineEnd', find the rest of it. Some or all of the rest of the field may be in the buffer already; we read more from the connection as necessary, but not if it takes past 'deadline'. In the latter case, we fail. We return the location of the end of the whole field as *headerEndP. We do not remove the field from the buffer, but we do modify the buffer so as to join the multiple lines of the field into a single line, and to NUL-terminate the field. -----------------------------------------------------------------------------*/ char * const fieldStart = connectionP->buffer.t + connectionP->bufferpos; char * fieldEnd; /* End of the field lines we've seen at so far */ bool gotWholeField; bool error; fieldEnd = lineEnd; /* initial value - end of 1st line */ for (gotWholeField = FALSE, error = FALSE; !gotWholeField && !error;) { char * nextLineEnd; /* Note that we are guaranteed, assuming the HTTP stream is valid, that there is at least one more line in it. Worst case, it's the empty line that marks the end of the headers. */ getLineInBuffer(connectionP, fieldEnd, deadline, &nextLineEnd, &error); if (!error) { if (isContinuationLine(fieldEnd)) { /* Join previous line to this one */ convertLineEnd(fieldEnd, fieldStart, ' '); /* Add this line to the header */ fieldEnd = nextLineEnd; } else { gotWholeField = TRUE; /* NUL-terminate the whole field */ convertLineEnd(fieldEnd, fieldStart, '\0'); } } } *fieldEndP = fieldEnd; *errorP = error; } static void readField(TConn * const connectionP, time_t const deadline, bool * const endOfHeaderP, char ** const fieldP, bool * const errorP) { /*---------------------------------------------------------------------------- Read an HTTP header field, or the end of header empty line, on connection *connectionP. An HTTP header field is basically a line, except that if a line starts with white space, it's a continuation of the previous line. A line is delimited by either LF or CRLF. The first line of an HTTP header field is never empty; an empty line signals the end of the HTTP header and beginning of the HTTP body. We call that empty line the EOH mark. We assume the connection is positioned to a header or EOH mark. In the course of reading, we read at least one character past the line delimiter at the end of the field or EOH mark; we may read much more. But we leave everything after the field or EOH (and its line delimiter) in the internal buffer, with the buffer pointer pointing to it. We use stuff already in the internal buffer (perhaps left by a previous call to this subroutine) before reading any more from from the channel. We return as *fieldP the next field as an ASCIIZ string, with no line delimiter. That string is stored in the "unused" portion of the connection's internal buffer. Iff there is no next field, we return *endOfHeaderP == true and nothing meaningful as *fieldP. -----------------------------------------------------------------------------*/ char * const bufferStart = connectionP->buffer.t + connectionP->bufferpos; bool error; char * lineEnd; getLineInBuffer(connectionP, bufferStart, deadline, &lineEnd, &error); if (!error) { if (isContinuationLine(bufferStart)) error = TRUE; else if (isEmptyLine(bufferStart)) { /* Consume the EOH mark from the buffer */ connectionP->bufferpos = lineEnd - connectionP->buffer.t; *endOfHeaderP = TRUE; } else { /* We have the first line of a field; there may be more. */ const char * fieldEnd; *endOfHeaderP = FALSE; getRestOfField(connectionP, lineEnd, deadline, &fieldEnd, &error); if (!error) { *fieldP = bufferStart; /* Consume the header from the buffer (but be careful -- you can't reuse that part of the buffer because the string we will return is in it! */ connectionP->bufferpos = fieldEnd - connectionP->buffer.t; } } } *errorP = error; } static void skipToNonemptyLine(TConn * const connectionP, time_t const deadline, bool * const errorP) { char * const bufferStart = connectionP->buffer.t + connectionP->bufferpos; bool gotNonEmptyLine; bool error; char * lineStart; lineStart = bufferStart; /* initial value */ gotNonEmptyLine = FALSE; /* initial value */ error = FALSE; /* initial value */ while (!gotNonEmptyLine && !error) { char * lineEnd; getLineInBuffer(connectionP, lineStart, deadline, &lineEnd, &error); if (!error) { if (!isEmptyLine(lineStart)) gotNonEmptyLine = TRUE; else lineStart = lineEnd; } } if (!error) { /* Consume all the empty lines; advance buffer pointer to first non-empty line. */ connectionP->bufferpos = lineStart - connectionP->buffer.t; } *errorP = error; } static void readRequestField(TSession * const sessionP, time_t const deadline, char ** const requestLineP, uint16_t * const httpErrorCodeP) { /*---------------------------------------------------------------------------- Read the HTTP request header field from session 'sessionP'. We read through the session's internal buffer; i.e. we may get data that was previously read from the network, or we may read more from the network. We assume the connection is presently positioned to the beginning of the HTTP document. We leave it positioned after the request field. We ignore any empty lines at the beginning of the stream, per RFC2616 Section 4.1. Fail if we can't get the field before 'deadline'. Return as *requestLineP the request field read. This ASCIIZ string is in the session's internal buffer. Return as *httpErrorCodeP the HTTP error code that describes how we are not able to read the request field, or 0 if we can. If we can't, *requestLineP is meaningless. -----------------------------------------------------------------------------*/ char * line; bool error; bool endOfHeader; skipToNonemptyLine(sessionP->connP, deadline, &error); if (!error) { readField(sessionP->connP, deadline, &endOfHeader, &line, &error); /* End of header is delimited by an empty line, and we skipped all the empty lines above, so readField() could not have encountered EOH: */ assert(!endOfHeader); } if (error) *httpErrorCodeP = 408; /* Request Timeout */ else { *httpErrorCodeP = 0; *requestLineP = line; } } static void hexDigitValue(char const digit, unsigned int * const valueP, const char ** const errorP) { if (digit == '\0') xmlrpc_asprintf(errorP, "string ends in the middle of a " "%% escape sequence"); else { char const digitLc = tolower(digit); if ((digitLc >= '0') && (digitLc <= '9')) { *valueP = digitLc - '0'; *errorP = NULL; } else if ((digitLc >= 'a') && (digitLc <= 'f')) { *valueP = 10 + digitLc - 'a'; *errorP = NULL; } else xmlrpc_asprintf(errorP, "Non-hexadecimal digit '%c' in " "%%HH escape sequence", digit); } } static void parsePerCentEscape(const char ** const srcP, char * const unescapedP, const char ** const errorP) { /*----------------------------------------------------------------------------- With *srcP pointing to a supposed %HH escape sequence in a buffer, set *unescapedP to the character that the sequence represents and advance *srcP past it. -----------------------------------------------------------------------------*/ unsigned int digit0; const char * src; src = *srcP; /* initial value */ ++src; /* Move past per cent sign */ if (!*src) xmlrpc_asprintf(errorP, "URI ends after the %%"); else { *errorP = NULL; /* initial assumption */ hexDigitValue(*src++, &digit0, errorP); if (!*errorP) { unsigned int digit1; if (!*src) xmlrpc_asprintf(errorP, "URI ends after the first digit"); else { hexDigitValue(*src++, &digit1, errorP); if (!*errorP) *unescapedP = ((digit0 << 4) | digit1); } } } *srcP = src; } static void unescapeUri(const char * const uriComponent, const char ** const unescapedP, const char ** const errorP) { /*---------------------------------------------------------------------------- Unescape a component of a URI, e.g. the host name. That component may have %HH encoding, especially of characters that are delimiters within a URI like slash and colon. Return the unescaped version as *unescapedP in newly malloced storage. -----------------------------------------------------------------------------*/ char * buffer; buffer = strdup(uriComponent); if (!buffer) xmlrpc_asprintf(errorP, "Couldn't get memory for URI unescape buffer"); else { const char * src; char * dst; src = dst = buffer; *errorP = NULL; /* initial value */ while (*src && !*errorP) { switch (*src) { case '%': { char unescaped; const char * error; parsePerCentEscape(&src, &unescaped, &error); if (error) { xmlrpc_asprintf(errorP, "Invalid %%HH escape sequence. %s", error); xmlrpc_strfree(error); } else *dst++ = unescaped; } break; default: *dst++ = *src++; break; } } *dst = '\0'; if (*errorP) xmlrpc_strfree(buffer); else *unescapedP = buffer; } } static void parseHostPort(const char * const hostport, const char ** const hostP, unsigned short * const portP, const char ** const errorP) { /*---------------------------------------------------------------------------- Parse a 'hostport', a string in the form www.acme.com:8080 . Return the host name part (www.acme.com) as *hostP (in newly malloced storage), and the port part (8080) as *portP. Default the port to 80 if 'hostport' doesn't have the port part. -----------------------------------------------------------------------------*/ char * buffer; buffer = strdup(hostport); if (!buffer) xmlrpc_asprintf(errorP, "Couldn't get memory for host/port buffer"); else { /* Note that the host portion may contain colons. The old RFC says it can't, but a newer one says the host may be an IPv6 address in the form [x:x:x...]. But the port portion may contain only digits, so we use the _last_ colon as the delimiter. */ char * const colonPos = strrchr(buffer, ':'); if (colonPos) { const char * p; uint32_t port; *colonPos = '\0'; /* Split hostport at the colon */ for (p = colonPos + 1, port = 0; isdigit(*p) && port < 65535; (port = port * 10 + (*p - '0')), ++p); if (*p || port == 0) { xmlrpc_asprintf(errorP, "There is nothing, or something " "non-numeric for the port number after the " "colon in '%s'", hostport); } else { *hostP = xmlrpc_strdupsol(buffer); *portP = port; *errorP = NULL; } } else { *hostP = xmlrpc_strdupsol(buffer); *portP = 80; *errorP = NULL; } free(buffer); } } static void splitUriQuery(const char * const requestUri, const char ** const queryP, const char ** const noQueryP, const char ** const errorP) { /*---------------------------------------------------------------------------- Split 'requestUri' at the question mark, returning the stuff after as *queryP and the stuff before as *noQueryP. -----------------------------------------------------------------------------*/ char * buffer; buffer = strdup(requestUri); if (!buffer) xmlrpc_asprintf(errorP, "Couldn't get memory for URI buffer"); else { char * const qmark = strchr(buffer, '?'); if (qmark) { *qmark = '\0'; *queryP = xmlrpc_strdupsol(qmark + 1); } else *queryP = NULL; *errorP = NULL; *noQueryP = buffer; } } static void parseHttpHostPortPath(const char * const hostportpath, const char ** const hostP, unsigned short* const portP, const char ** const pathP, const char ** const errorP) { const char * path; char * buffer; buffer = strdup(hostportpath); if (!buffer) xmlrpc_asprintf(errorP, "Couldn't get memory for host/port/path buffer"); else { char * const slashPos = strchr(buffer, '/'); char * hostport; if (slashPos) { path = xmlrpc_strdupsol(slashPos); /* Includes the initial slash */ *slashPos = '\0'; /* NUL termination for hostport */ } else path = strdup("*"); hostport = buffer; /* The following interprets the port field without taking into account any %HH encoding, as the RFC says may be there. We ignore that remote possibility out of laziness. */ parseHostPort(hostport, hostP, portP, errorP); if (*errorP) xmlrpc_strfree(path); else *pathP = path; free(buffer); } } static void unescapeHostPathQuery(const char * const host, const char * const path, const char * const query, const char ** const hostP, const char ** const pathP, const char ** const queryP, const char ** const errorP) { /*---------------------------------------------------------------------------- Unescape each of the four components of a URI. Each may be NULL, in which case we return NULL. -----------------------------------------------------------------------------*/ if (host) unescapeUri(host, hostP, errorP); else *hostP = NULL; if (!*errorP) { if (path) unescapeUri(path, pathP, errorP); else *pathP = NULL; if (!*errorP) { if (query) unescapeUri(query, queryP, errorP); else *queryP = NULL; if (*errorP) xmlrpc_strfree(*pathP); } else { if (*hostP) xmlrpc_strfree(*hostP); } } } static void parseRequestUri(char * const requestUri, const char ** const hostP, unsigned short * const portP, const char ** const pathP, const char ** const queryP, const char ** const errorP) { /*---------------------------------------------------------------------------- Parse the request URI (in the request line "GET http://www.myserver.com:8080/myfile.cgi?parm HTTP/1.1", "http://www.myserver.com:8080/myfile.cgi?parm" is the request URI). Return as *hostP the "www.myserver.com" in the above example. If that part of the URI doesn't exist, return *hostP == NULL. Return as *portP the 8080 in the above example. If it doesn't exist, return 80. Return as *pathP the "/myfile.cgi" in the above example. If it doesn't exist, return "*". Return as *queryP the "parm" in the above example. If it doesn't exist, return *queryP == NULL. Return strings in newly malloc'ed storage. We can return syntactically invalid entities, e.g. a host name that contains "<", if 'requestUri' is similarly invalid. We should fix that some day. RFC 2396 lists a lot of characters as reserved for certain use in the URI, such as colon, and totally disallowed, such as space. -----------------------------------------------------------------------------*/ const char * requestUriNoQuery; /* The request URI with any query (the stuff marked by a question mark at the end of a request URI) chopped off. */ const char * query; const char * path; const char * host; unsigned short port; splitUriQuery(requestUri, &query, &requestUriNoQuery, errorP); if (!*errorP) { if (requestUriNoQuery[0] == '/') { host = NULL; path = xmlrpc_strdupsol(requestUriNoQuery); port = 80; *errorP = NULL; } else { if (!xmlrpc_strneq(requestUriNoQuery, "http://", 7)) xmlrpc_asprintf(errorP, "Scheme is not http://"); else parseHttpHostPortPath(&requestUriNoQuery[7], &host, &port, &path, errorP); } if (!*errorP) { *portP = port; unescapeHostPathQuery(host, path, query, hostP, pathP, queryP, errorP); if (host) xmlrpc_strfree(host); if (path) xmlrpc_strfree(path); } if (query) xmlrpc_strfree(query); xmlrpc_strfree(requestUriNoQuery); } } static void parseRequestLine(char * const requestLine, TMethod * const httpMethodP, httpVersion * const httpVersionP, const char ** const hostP, unsigned short * const portP, const char ** const pathP, const char ** const queryP, bool * const moreLinesP, uint16_t * const httpErrorCodeP) { /*---------------------------------------------------------------------------- Modifies *requestLine! -----------------------------------------------------------------------------*/ const char * httpMethodName; char * p; p = requestLine; /* Jump over spaces */ NextToken((const char **)&p); httpMethodName = GetToken(&p); if (!httpMethodName) *httpErrorCodeP = 400; /* Bad Request */ else { char * requestUri; if (xmlrpc_streq(httpMethodName, "GET")) *httpMethodP = m_get; else if (xmlrpc_streq(httpMethodName, "PUT")) *httpMethodP = m_put; else if (xmlrpc_streq(httpMethodName, "OPTIONS")) *httpMethodP = m_options; else if (xmlrpc_streq(httpMethodName, "DELETE")) *httpMethodP = m_delete; else if (xmlrpc_streq(httpMethodName, "POST")) *httpMethodP = m_post; else if (xmlrpc_streq(httpMethodName, "TRACE")) *httpMethodP = m_trace; else if (xmlrpc_streq(httpMethodName, "HEAD")) *httpMethodP = m_head; else *httpMethodP = m_unknown; /* URI and Query Decoding */ NextToken((const char **)&p); requestUri = GetToken(&p); if (!requestUri) *httpErrorCodeP = 400; /* Bad Request */ else { const char * host; unsigned short port; const char * path; const char * query; const char * error; parseRequestUri(requestUri, &host, &port, &path, &query, &error); if (error) { *httpErrorCodeP = 400; /* Bad Request */ xmlrpc_strfree(error); /* Someday we should do something with this */ } else { const char * httpVersion; NextToken((const char **)&p); /* HTTP Version Decoding */ httpVersion = GetToken(&p); if (httpVersion) { uint32_t vmin, vmaj; if (sscanf(httpVersion, "HTTP/%d.%d", &vmaj, &vmin) != 2) *httpErrorCodeP = 400; /* Bad Request */ else { httpVersionP->major = vmaj; httpVersionP->minor = vmin; *httpErrorCodeP = 0; /* no error */ } *moreLinesP = TRUE; } else { /* There is no HTTP version, so this is a single line request. */ *httpErrorCodeP = 0; /* no error */ *moreLinesP = FALSE; } if (*httpErrorCodeP) { xmlrpc_strfree(host); xmlrpc_strfree(path); xmlrpc_strfree(query); } *hostP = host; *portP = port; *pathP = path; *queryP = query; } } } } static void strtolower(char * const s) { char * t; t = &s[0]; while (*t) { *t = tolower(*t); ++t; } } static void getFieldNameToken(char ** const pP, char ** const fieldNameP, const char ** const errorP, uint16_t * const httpErrorCodeP) { /*---------------------------------------------------------------------------- Assuming that *pP points to the place in an HTTP header where the field name belongs, return the field name and advance *pP past that token. The field name is the lower case representation of the value of the field name token. -----------------------------------------------------------------------------*/ char * fieldName; NextToken((const char **)pP); fieldName = GetToken(pP); if (!fieldName) { xmlrpc_asprintf(errorP, "The header has no field name token"); *httpErrorCodeP = 400; /* Bad Request */ } else { if (fieldName[strlen(fieldName)-1] != ':') { /* Not a valid field name */ xmlrpc_asprintf(errorP, "The field name token '%s' " "does not end with a colon (:)", fieldName); *httpErrorCodeP = 400; /* Bad Request */ } else { fieldName[strlen(fieldName)-1] = '\0'; /* remove trailing colon */ strtolower(fieldName); *errorP = NULL; } } *fieldNameP = fieldName; } static void processField(const char * const fieldName, char * const fieldValue, TSession * const sessionP, const char ** const errorP, uint16_t * const httpErrorCodeP) { /*---------------------------------------------------------------------------- We may modify *fieldValue, and we put pointers to *fieldValue and *fieldName into *sessionP. We must fix this some day. *sessionP should point to individual malloc'ed strings. -----------------------------------------------------------------------------*/ *errorP = NULL; /* initial assumption */ if (xmlrpc_streq(fieldName, "connection")) { if (xmlrpc_strcaseeq(fieldValue, "keep-alive")) sessionP->requestInfo.keepalive = TRUE; else sessionP->requestInfo.keepalive = FALSE; } else if (xmlrpc_streq(fieldName, "host")) { if (sessionP->requestInfo.host) { xmlrpc_strfree(sessionP->requestInfo.host); sessionP->requestInfo.host = NULL; } parseHostPort(fieldValue, &sessionP->requestInfo.host, &sessionP->requestInfo.port, errorP); } else if (xmlrpc_streq(fieldName, "from")) sessionP->requestInfo.from = fieldValue; else if (xmlrpc_streq(fieldName, "user-agent")) sessionP->requestInfo.useragent = fieldValue; else if (xmlrpc_streq(fieldName, "referer")) sessionP->requestInfo.referer = fieldValue; else if (xmlrpc_streq(fieldName, "range")) { if (xmlrpc_strneq(fieldValue, "bytes=", 6)) { bool succeeded; succeeded = ListAddFromString(&sessionP->ranges, &fieldValue[6]); if (!succeeded) { xmlrpc_asprintf(errorP, "ListAddFromString() failed for " "\"range: bytes=...\" header value '%s'", &fieldValue[6]); *httpErrorCodeP = 400; } } } else if (xmlrpc_streq(fieldName, "cookies")) { bool succeeded; succeeded = ListAddFromString(&sessionP->cookies, fieldValue); if (!succeeded) { xmlrpc_asprintf(errorP, "ListAddFromString() failed for " "cookies: header value '%s'", fieldValue); *httpErrorCodeP = 400; } } else if (xmlrpc_streq(fieldName, "expect")) { if (xmlrpc_strcaseeq(fieldValue, "100-continue")) sessionP->continueRequired = TRUE; } } static void readAndProcessHeaderFields(TSession * const sessionP, time_t const deadline, const char ** const errorP, uint16_t * const httpErrorCodeP) { /*---------------------------------------------------------------------------- Read all the HTTP header fields from the session *sessionP, which has at least one field coming. Update *sessionP to reflect the information in the fields. If we find an error in the fields or while trying to read them, we return a text explanation of the problem as *errorP and an appropriate HTTP error code as *httpErrorCodeP. Otherwise, we return *errorP = NULL and nothing as *httpErrorCodeP. -----------------------------------------------------------------------------*/ bool endOfHeader; assert(!sessionP->validRequest); /* Calling us doesn't make sense if there is already a valid request */ *errorP = NULL; /* initial assumption */ endOfHeader = false; /* Caller assures us there is at least one header */ while (!endOfHeader && !*errorP) { char * field; bool error; readField(sessionP->connP, deadline, &endOfHeader, &field, &error); if (error) { xmlrpc_asprintf(errorP, "Failed to read header from " "client connection."); *httpErrorCodeP = 408; /* Request Timeout */ } else { if (!endOfHeader) { char * p; char * fieldName; p = &field[0]; getFieldNameToken(&p, &fieldName, errorP, httpErrorCodeP); if (!*errorP) { char * fieldValue; NextToken((const char **)&p); fieldValue = p; TableAdd(&sessionP->requestHeaderFields, fieldName, fieldValue); processField(fieldName, fieldValue, sessionP, errorP, httpErrorCodeP); } } } } } void RequestRead(TSession * const sessionP, uint32_t const timeout, const char ** const errorP, uint16_t * const httpErrorCodeP) { /*---------------------------------------------------------------------------- Read the headers of a new HTTP request (assuming nothing has yet been read on the session). Update *sessionP with the information from the headers. Leave the connection positioned to the body of the request, ready to be read by an HTTP request handler (via SessionRefillBuffer() and SessionGetReadData()). -----------------------------------------------------------------------------*/ time_t const deadline = time(NULL) + timeout; uint16_t httpErrorCode; /* zero for no error */ char * requestLine; /* In connection;s internal buffer */ readRequestField(sessionP, deadline, &requestLine, &httpErrorCode); if (httpErrorCode) { xmlrpc_asprintf(errorP, "Problem getting the request header"); *httpErrorCodeP = httpErrorCode; } else { TMethod httpMethod; const char * host; const char * path; const char * query; unsigned short port; bool moreFields; parseRequestLine(requestLine, &httpMethod, &sessionP->version, &host, &port, &path, &query, &moreFields, &httpErrorCode); if (httpErrorCode) { xmlrpc_asprintf(errorP, "Unable to parse the request header " "'%s'", requestLine); *httpErrorCodeP = httpErrorCode; } else { initRequestInfo(&sessionP->requestInfo, sessionP->version, requestLine, httpMethod, host, port, path, query); if (moreFields) { readAndProcessHeaderFields(sessionP, deadline, errorP, httpErrorCodeP); } else *errorP = NULL; if (!*errorP) sessionP->validRequest = true; xmlrpc_strfreenull(host); xmlrpc_strfree(path); xmlrpc_strfreenull(query); } } } char * RequestHeaderValue(TSession * const sessionP, const char * const name) { return (TableFind(&sessionP->requestHeaderFields, name)); } bool RequestValidURI(TSession * const sessionP) { if (!sessionP->requestInfo.uri) return FALSE; if (xmlrpc_streq(sessionP->requestInfo.uri, "*")) return (sessionP->requestInfo.method != m_options); if (strchr(sessionP->requestInfo.uri, '*')) return FALSE; return TRUE; } bool RequestValidURIPath(TSession * const sessionP) { uint32_t i; const char * p; p = sessionP->requestInfo.uri; i = 0; if (*p == '/') { i = 1; while (*p) if (*(p++) == '/') { if (*p == '/') break; else if ((xmlrpc_strneq(p,"./", 2)) || (xmlrpc_streq(p, "."))) ++p; else if ((xmlrpc_strneq(p, "../", 2)) || (xmlrpc_streq(p, ".."))) { p += 2; --i; if (i == 0) break; } /* Prevent accessing hidden files (starting with .) */ else if (*p == '.') return FALSE; else if (*p) ++i; } } return (*p == 0 && i > 0); } abyss_bool RequestAuth(TSession * const sessionP, const char * const credential, const char * const user, const char * const pass) { /*---------------------------------------------------------------------------- Authenticate requester, in a very simplistic fashion. If the request executing on session *sessionP specifies basic authentication (via Authorization header) with username 'user', password 'pass', then return TRUE. Else, return FALSE and set up an authorization failure response (HTTP response status 401) that says user must supply an identity in the 'credential' domain. When we return TRUE, we also set the username in the request info for the session to 'user' so that a future SessionGetRequestInfo can get it. -----------------------------------------------------------------------------*/ bool authorized; char * authHdrPtr; authHdrPtr = RequestHeaderValue(sessionP, "authorization"); if (authHdrPtr) { const char * authType; NextToken((const char **)&authHdrPtr); GetTokenConst(&authHdrPtr, &authType); if (authType) { if (xmlrpc_strcaseeq(authType, "basic")) { const char * userPass; char userPassEncoded[80]; NextToken((const char **)&authHdrPtr); xmlrpc_asprintf(&userPass, "%s:%s", user, pass); xmlrpc_base64Encode(userPass, userPassEncoded); xmlrpc_strfree(userPass); if (xmlrpc_streq(authHdrPtr, userPassEncoded)) { sessionP->requestInfo.user = xmlrpc_strdupsol(user); authorized = TRUE; } else authorized = FALSE; } else authorized = FALSE; } else authorized = FALSE; } else authorized = FALSE; if (!authorized) { const char * hdrValue; xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential); ResponseAddField(sessionP, "WWW-Authenticate", hdrValue); xmlrpc_strfree(hdrValue); ResponseStatus(sessionP, 401); } return authorized; } /********************************************************************* ** Range *********************************************************************/ abyss_bool RangeDecode(char * const strArg, xmlrpc_uint64_t const filesize, xmlrpc_uint64_t * const start, xmlrpc_uint64_t * const end) { char *str; char *ss; str = strArg; /* initial value */ *start=0; *end=filesize-1; if (*str=='-') { *start=filesize-strtol(str+1,&ss,10); return ((ss!=str) && (!*ss)); }; *start=strtol(str,&ss,10); if ((ss==str) || (*ss!='-')) return FALSE; str=ss+1; if (!*str) return TRUE; *end=strtol(str,&ss,10); if ((ss==str) || (*ss) || (*end<*start)) return FALSE; return TRUE; } /********************************************************************* ** HTTP *********************************************************************/ const char * HTTPReasonByStatus(uint16_t const code) { struct _HTTPReasons { uint16_t status; const char * reason; }; static struct _HTTPReasons const reasons[] = { { 100,"Continue" }, { 101,"Switching Protocols" }, { 200,"OK" }, { 201,"Created" }, { 202,"Accepted" }, { 203,"Non-Authoritative Information" }, { 204,"No Content" }, { 205,"Reset Content" }, { 206,"Partial Content" }, { 300,"Multiple Choices" }, { 301,"Moved Permanently" }, { 302,"Moved Temporarily" }, { 303,"See Other" }, { 304,"Not Modified" }, { 305,"Use Proxy" }, { 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" }, { 409,"Conflict" }, { 410,"Gone" }, { 411,"Length Required" }, { 412,"Precondition Failed" }, { 413,"Request Entity Too Large" }, { 414,"Request-URI Too Long" }, { 415,"Unsupported Media Type" }, { 500,"Internal Server Error" }, { 501,"Not Implemented" }, { 502,"Bad Gateway" }, { 503,"Service Unavailable" }, { 504,"Gateway Timeout" }, { 505,"HTTP Version Not Supported" }, { 000, NULL } }; const struct _HTTPReasons * reasonP; reasonP = &reasons[0]; while (reasonP->status <= code) if (reasonP->status == code) return reasonP->reason; else ++reasonP; return "No Reason"; } int32_t HTTPRead(TSession * const s ATTR_UNUSED, const char * const buffer ATTR_UNUSED, uint32_t const len ATTR_UNUSED) { return 0; } bool HTTPWriteBodyChunk(TSession * const sessionP, const char * const buffer, uint32_t const len) { bool succeeded; if (sessionP->chunkedwrite && sessionP->chunkedwritemode) { char chunkHeader[16]; sprintf(chunkHeader, "%x\r\n", len); succeeded = ConnWrite(sessionP->connP, chunkHeader, strlen(chunkHeader)); if (succeeded) { succeeded = ConnWrite(sessionP->connP, buffer, len); if (succeeded) succeeded = ConnWrite(sessionP->connP, "\r\n", 2); } } else succeeded = ConnWrite(sessionP->connP, buffer, len); return succeeded; } bool HTTPWriteEndChunk(TSession * const sessionP) { bool retval; if (sessionP->chunkedwritemode && sessionP->chunkedwrite) { /* May be one day trailer dumping will be added */ sessionP->chunkedwritemode = FALSE; retval = ConnWrite(sessionP->connP, "0\r\n\r\n", 5); } else retval = TRUE; return retval; } bool HTTPKeepalive(TSession * const sessionP) { /*---------------------------------------------------------------------------- Return value: the connection should be kept alive after the session *sessionP is over. -----------------------------------------------------------------------------*/ return (sessionP->requestInfo.keepalive && !sessionP->serverDeniesKeepalive && sessionP->status < 400); } bool HTTPWriteContinue(TSession * const sessionP) { char const continueStatus[] = "HTTP/1.1 100 continue\r\n\r\n"; /* This is a status line plus an end-of-headers empty line */ return ConnWrite(sessionP->connP, continueStatus, strlen(continueStatus)); } /****************************************************************************** ** ** http.c ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ xmlrpc-c-1.33.14/lib/abyss/src/http.h000066400000000000000000000024101236133176700172240ustar00rootroot00000000000000#ifndef HTTP_H_INCLUDED #define HTTP_H_INCLUDED #include #include "bool.h" #include "conn.h" /********************************************************************* ** Request *********************************************************************/ bool RequestValidURI(TSession * const r); bool RequestValidURIPath(TSession * const r); bool RequestUnescapeURI(TSession *r); void RequestRead(TSession * const sessionP, uint32_t const timeout, const char ** const errorP, uint16_t * const httpErrorCodeP); void RequestInit(TSession * const r,TConn * const c); void RequestFree(TSession * const r); /********************************************************************* ** HTTP *********************************************************************/ const char * HTTPReasonByStatus(uint16_t const code); int32_t HTTPRead(TSession * const sessionP, const char * const buffer, uint32_t const len); bool HTTPWriteBodyChunk(TSession * const sessionP, const char * const buffer, uint32_t const len); bool HTTPWriteEndChunk(TSession * const sessionP); bool HTTPKeepalive(TSession * const sessionP); bool HTTPWriteContinue(TSession * const sessionP); #endif xmlrpc-c-1.33.14/lib/abyss/src/init.c000066400000000000000000000042551236133176700172140ustar00rootroot00000000000000/*============================================================================= The functions handle static stuff -- the functions do not operate on any particular Abyss object, but rather on the global environment of the program that uses the Abyss library. abyssInit() is essentially and extension of the program loader. The intent is for any program that uses the Abyss library to call AbyssInit() just as it starts up, and AbyssTerm() just as it exits. It should do both when the program is only one thread, because they are not thread-safe. These functions do the bare minimum they can get away with; we prefer context to be local to invidual objects. =============================================================================*/ #include #include "xmlrpc-c/string_int.h" #include "chanswitch.h" #include "channel.h" #include "xmlrpc-c/abyss.h" static unsigned int AbyssInitCount = 0; static void initAbyss(const char ** const errorP) { const char * error; DateInit(); MIMETypeInit(); ChanSwitchInit(&error); if (error) { xmlrpc_asprintf(errorP, "Could not initialize channel swtich class. %s", error); xmlrpc_strfree(error); } else { const char * error; ChannelInit(&error); if (error) { xmlrpc_asprintf(errorP, "Could not initialize Channel class. %s", error); xmlrpc_strfree(error); } else { AbyssInitCount = 1; *errorP = NULL; if (*errorP) ChannelTerm(); } if (*errorP) ChanSwitchTerm(); } } void AbyssInit(const char ** const errorP) { if (AbyssInitCount > 0) { *errorP = NULL; ++AbyssInitCount; } else { initAbyss(errorP); if (!*errorP) AbyssInitCount = 1; } } static void termAbyss(void) { ChannelTerm(); ChanSwitchTerm(); MIMETypeTerm(); } void AbyssTerm(void) { assert(AbyssInitCount > 0); --AbyssInitCount; if (AbyssInitCount == 0) termAbyss(); } xmlrpc-c-1.33.14/lib/abyss/src/main.c000066400000000000000000000132211236133176700171660ustar00rootroot00000000000000/****************************************************************************** ** ** main.c ** ** This file is part of the ABYSS Web server project. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ #include #include #include #include #ifdef _WIN32 #include #endif /* _WIN32 */ #ifdef _UNIX #include #include #endif #include "xmlrpc-c/abyss.h" void Answer(TSession *r, uint16_t statuscode, char *buffer) { ResponseChunked(r); ResponseStatus(r,statuscode); ResponseContentType(r,"text/html"); ResponseWriteStart(r); HTTPWrite(r,"",12); HTTPWrite(r,buffer,strlen(buffer)); HTTPWrite(r,"",14); HTTPWriteEnd(r); } abyss_bool HandleTime(TSession *r) { char z[50]; time_t ltime; TDate date; const char * dateString; const char * answer; if (!xmlrpc_streq(r->uri,"/time")) return FALSE; if (!RequestAuth(r,"Mot de passe","moez","hello")) return TRUE; time(<ime); DateFromGMT(&date, ltime); DateToString(&date, &dateString); xmlrpc_asprintf(&answer, "The time is %s", dateString); Answer(r, 200, answer); xmlrpc_strfree(dateString); xmlrpc_strfree(answer); return TRUE; } abyss_bool HandleDump(TSession *r) { char z[50]; if (!xmlrpc_streq(r->uri,"/name")) return FALSE; sprintf(z,"Server name is %s", (r->server)->name ); Answer(r,200,z); return TRUE; } abyss_bool HandleStatus(TSession *r) { uint32_t status; if (sscanf(r->uri,"/status/%d",&status)<=0) return FALSE; ResponseStatus(r,(uint16_t)status); return TRUE; } abyss_bool HandleMIMEType(TSession *r) { char *m; if (!xmlrpc_strneq(r->uri, "/mime/", 6)) return FALSE; m=MIMETypeFromExt(r->uri+6); if (!m) m="(none)"; Answer(r,200,m); return TRUE; } #ifdef _UNIX static void sigterm(int sig) { TraceExit("Signal %d received. Exiting...\n",sig); } static void sigchld(int const signalClass) { bool childrenLeft; bool error; childrenLeft = true; error = false; /* Reap defunct children until there aren't any more. */ while (childrenLeft && !error) { int status; pid_t rc; rc = waitpid((pid_t) -1, &status, WNOHANG); if (rc == 0) childrenLeft = false; else if (rc < 0) { /* because of ptrace */ if (errno == EINTR) { /* ptrace causes this */ } else error = true; } else { /* We reaped a child. */ pid_t const pid = rc; ThreadHandleSigchld(pid); } } } #endif _UNIX int main(int argc,char **argv) { const char * const name = argv[0]; TServer srv; char * p; const char * conffile; bool err; conffile = DEFAULT_CONF_FILE; /* initial value */ err = FALSE; /* initial value */ while (p=*(++argv)) { if ((*p=='-') && (*(p+1))) if (*(p+2)=='\0') switch (*(p+1)) { case 'c': argv++; if (*argv) conffile=*argv; else err=TRUE; break; default: err=TRUE; } else err=TRUE; else err=TRUE; }; if (err) { help(name); exit(1); }; DateInit(); MIMETypeInit(); ServerCreate(&srv,"HTTPServer",80,DEFAULT_DOCS,NULL); ConfReadServerFile(conffile,&srv); ServerAddHandler(&srv,HandleTime); ServerAddHandler(&srv,HandleDump); ServerAddHandler(&srv,HandleStatus); ServerAddHandler(&srv,HandleMIMEType); ServerInit(&srv); #ifdef _UNIX /* Catch various termination signals. */ signal(SIGTERM,sigterm); signal(SIGINT,sigterm); signal(SIGHUP,sigterm); signal(SIGUSR1,sigterm); /* Catch defunct children. */ signal(SIGCHLD,sigchld); #endif ServerDaemonize(srv); ServerRun(&srv); return 0; } xmlrpc-c-1.33.14/lib/abyss/src/pthreadx.h000066400000000000000000000054121236133176700200710ustar00rootroot00000000000000/* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #ifndef PTHREADX_H_INCLUDED #define PTHREADX_H_INCLUDED #include "xmlrpc_config.h" #if HAVE_PTHREAD # define _REENTRANT # include #elif HAVE_WINDOWS_THREAD /* We define WIN32_WIN_LEAN_AND_MEAN to make contain less junk; nothing in Xmlrpc-c needs that stuff. One significant thing it cuts out is , which would conflict with the that our includer might use. */ #define WIN32_WIN_LEAN_AND_MEAN #include #ifdef __cplusplus extern "C" { #endif typedef HANDLE pthread_t; typedef struct { int attrs; /* currently unused. placeholder. */ } pthread_attr_t; typedef void * pthread_func(void *); extern int pthread_create(pthread_t * const new_thread_ID, const pthread_attr_t * const attr, pthread_func * start_func, void * const arg); extern int pthread_cancel(pthread_t target_thread); extern int pthread_join(pthread_t target_thread, void **status); extern int pthread_detach(pthread_t target_thread); #ifdef __cplusplus } #endif #else /* HAVE_WINDOWS_THREAD */ #error "You don't have any thread facility. (According to " #error "HAVE_PTHREAD and HAVE_WINDOWS_THREAD macros defined in " #error "xmlrpc_config.h)" #endif #endif xmlrpc-c-1.33.14/lib/abyss/src/response.c000066400000000000000000000466441236133176700201170ustar00rootroot00000000000000/*============================================================================= response =============================================================================== This module contains callbacks from and services for a request handler. Copyright information is at the end of the file =============================================================================*/ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include #include #include #include #include "xmlrpc_config.h" #include "bool.h" #include "int.h" #include "version.h" #include "mallocvar.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/abyss.h" #include "trace.h" #include "server.h" #include "session.h" #include "file.h" #include "conn.h" #include "token.h" #include "date.h" #include "data.h" #include "abyss_info.h" #include "http.h" void ResponseError2(TSession * const sessionP, const char * const explanation) { const char * errorDocument; ResponseAddField(sessionP, "Content-type", "text/html"); ResponseWriteStart(sessionP); xmlrpc_asprintf(&errorDocument, "Error %d" "" "

Error %d

" "

%s

" SERVER_HTML_INFO "" "", sessionP->status, sessionP->status, explanation); ConnWrite(sessionP->connP, errorDocument, strlen(errorDocument)); xmlrpc_strfree(errorDocument); } void ResponseError(TSession * const sessionP) { ResponseError2(sessionP, HTTPReasonByStatus(sessionP->status)); } abyss_bool ResponseChunked(TSession * const sessionP) { /* This is only a hope, things will be real only after a call of ResponseWriteStart() */ assert(!sessionP->responseStarted); sessionP->chunkedwrite = (sessionP->version.major > 1) || (sessionP->version.major == 1 && (sessionP->version.minor >= 1)); sessionP->chunkedwritemode = TRUE; return TRUE; } void ResponseStatus(TSession * const sessionP, unsigned short const code) { sessionP->status = code; } xmlrpc_uint16_t ResponseStatusFromErrno(int const errnoArg) { uint16_t code; switch (errnoArg) { case EACCES: code=403; break; case ENOENT: code=404; break; default: code=500; } return code; } void ResponseStatusErrno(TSession * const sessionP) { ResponseStatus(sessionP, ResponseStatusFromErrno(errno)); } static bool isValidHttpToken(const char * const token) { char const separators[] = "()<>@,;:\\\"/[]?={} \t"; const char * p; bool valid; for (p = &token[0], valid = true; *p; ++p) { if (!isprint(*p) || strchr(separators, *p)) valid = false; } return valid; } static bool isValidHttpText(const char * const text) { const char * p; bool valid; for (p = &text[0], valid = true; *p; ++p) { if (!isprint(*p)) valid = false; } return valid; } abyss_bool ResponseAddField(TSession * const sessionP, const char * const name, const char * const value) { abyss_bool succeeded; if (!isValidHttpToken(name)) { TraceMsg("Supplied HTTP header field name is not a valid HTTP token"); succeeded = false; } else if (!isValidHttpText(value)) { TraceMsg("Supplied HTTP header field value is not valid HTTP text"); succeeded = false; } else { succeeded = TableAdd(&sessionP->responseHeaderFields, name, value); } return succeeded; } static void addConnectionHeaderFld(TSession * const sessionP) { struct _TServer * const srvP = ConnServer(sessionP->connP)->srvP; if (HTTPKeepalive(sessionP)) { const char * keepaliveValue; ResponseAddField(sessionP, "Connection", "Keep-Alive"); xmlrpc_asprintf(&keepaliveValue, "timeout=%u, max=%u", srvP->keepalivetimeout, srvP->keepalivemaxconn); ResponseAddField(sessionP, "Keep-Alive", keepaliveValue); xmlrpc_strfree(keepaliveValue); } else ResponseAddField(sessionP, "Connection", "close"); } static void addDateHeaderFld(TSession * const sessionP) { if (sessionP->status >= 200) { const char * dateValue; DateToString(sessionP->date, &dateValue); if (dateValue) { ResponseAddField(sessionP, "Date", dateValue); xmlrpc_strfree(dateValue); } } } static void addServerHeaderFld(TSession * const sessionP) { const char * serverValue; xmlrpc_asprintf(&serverValue, "Xmlrpc-c_Abyss/%s", XMLRPC_C_VERSION); ResponseAddField(sessionP, "Server", serverValue); xmlrpc_strfree(serverValue); } static unsigned int leadingWsCt(const char * const arg) { unsigned int i; for (i = 0; arg[i] && isspace(arg[i]); ++i); return i; } static unsigned int trailingWsPos(const char * const arg) { unsigned int i; for (i = strlen(arg); i > 0 && isspace(arg[i-1]); --i); return i; } static const char * formatFieldValue(const char * const unformatted) { /*---------------------------------------------------------------------------- Return the string of characters that goes after the colon on the HTTP header field line, given that 'unformatted' is its basic value. -----------------------------------------------------------------------------*/ const char * retval; /* An HTTP header field value may not have leading or trailing white space. */ char * buffer; buffer = malloc(strlen(unformatted) + 1); if (buffer == NULL) retval = xmlrpc_strnomemval(); else { unsigned int const lead = leadingWsCt(unformatted); unsigned int const trail = trailingWsPos(unformatted); assert(trail >= lead); strncpy(buffer, &unformatted[lead], trail - lead); buffer[trail - lead] = '\0'; retval = buffer; } return retval; } static void sendHeader(TConn * const connP, TTable const fields) { /*---------------------------------------------------------------------------- Send the HTTP response header whose fields are fields[]. Don't include the blank line that separates the header from the body. fields[] contains syntactically valid HTTP header field names and values. But to the extent that int contains undefined field names or semantically invalid values, the header we send is invalid. -----------------------------------------------------------------------------*/ unsigned int i; for (i = 0; i < fields.size; ++i) { TTableItem * const fieldP = &fields.item[i]; const char * const fieldValue = formatFieldValue(fieldP->value); const char * line; xmlrpc_asprintf(&line, "%s: %s\r\n", fieldP->name, fieldValue); ConnWrite(connP, line, strlen(line)); xmlrpc_strfree(line); xmlrpc_strfree(fieldValue); } } void ResponseWriteStart(TSession * const sessionP) { /*---------------------------------------------------------------------------- Begin the process of sending the response for an HTTP transaction (i.e. Abyss session). As part of this, send the entire HTTP header for the response. -----------------------------------------------------------------------------*/ struct _TServer * const srvP = ConnServer(sessionP->connP)->srvP; assert(!sessionP->responseStarted); if (sessionP->status == 0) { /* Handler hasn't set status. That's an error */ TraceMsg("Abyss client called ResponseWriteStart() on " "a session for which he has not set the request status " "('status' member of TSession). Using status 500\n"); sessionP->status = 500; } sessionP->responseStarted = TRUE; { const char * const reason = HTTPReasonByStatus(sessionP->status); const char * line; xmlrpc_asprintf(&line,"HTTP/1.1 %u %s\r\n", sessionP->status, reason); ConnWrite(sessionP->connP, line, strlen(line)); xmlrpc_strfree(line); } addConnectionHeaderFld(sessionP); if (sessionP->chunkedwrite && sessionP->chunkedwritemode) ResponseAddField(sessionP, "Transfer-Encoding", "chunked"); addDateHeaderFld(sessionP); if (srvP->advertise) addServerHeaderFld(sessionP); /* Note that sessionP->responseHeaderFields is defined to contain syntactically but not necessarily semantically valid header field names and values. */ sendHeader(sessionP->connP, sessionP->responseHeaderFields); ConnWrite(sessionP->connP, "\r\n", 2); } abyss_bool ResponseWriteBody(TSession * const sessionP, const char * const data, xmlrpc_uint32_t const len) { return HTTPWriteBodyChunk(sessionP, data, len); } abyss_bool ResponseWriteEnd(TSession * const sessionP) { return HTTPWriteEndChunk(sessionP); } abyss_bool ResponseContentType(TSession * const serverP, const char * const type) { return ResponseAddField(serverP, "Content-type", type); } abyss_bool ResponseContentLength(TSession * const sessionP, xmlrpc_uint64_t const len) { char contentLengthValue[32]; sprintf(contentLengthValue, "%" PRIu64, len); return ResponseAddField(sessionP, "Content-length", contentLengthValue); } void ResponseAccessControl(TSession * const abyssSessionP, ResponseAccessCtl const accessControl) { if (accessControl.allowOrigin) { ResponseAddField(abyssSessionP, "Access-Control-Allow-Origin", accessControl.allowOrigin); ResponseAddField(abyssSessionP, "Access-Control-Allow-Methods", "POST"); ResponseAddField(abyssSessionP, "Access-Control-Allow-Headers", "Content-Type"); ResponseAddField(abyssSessionP, "Access-Control-Allow-Headers", "Content-Length"); if (accessControl.expires) { char buffer[64]; sprintf(buffer, "%u", accessControl.maxAge); ResponseAddField(abyssSessionP, "Access-Control-Max-Age", buffer); } } } /********************************************************************* ** MIMEType *********************************************************************/ struct MIMEType { TList typeList; TList extList; TPool pool; }; static MIMEType * globalMimeTypeP = NULL; MIMEType * MIMETypeCreate(void) { MIMEType * MIMETypeP; MALLOCVAR(MIMETypeP); if (MIMETypeP) { ListInit(&MIMETypeP->typeList); ListInit(&MIMETypeP->extList); PoolCreate(&MIMETypeP->pool, 1024); } return MIMETypeP; } void MIMETypeDestroy(MIMEType * const MIMETypeP) { PoolFree(&MIMETypeP->pool); free(MIMETypeP); } void MIMETypeInit(void) { if (globalMimeTypeP != NULL) abort(); globalMimeTypeP = MIMETypeCreate(); } void MIMETypeTerm(void) { if (globalMimeTypeP == NULL) abort(); MIMETypeDestroy(globalMimeTypeP); globalMimeTypeP = NULL; } static void mimeTypeAdd(MIMEType * const MIMETypeP, const char * const type, const char * const ext, bool * const successP) { uint16_t index; void * mimeTypesItem; bool typeIsInList; assert(MIMETypeP != NULL); typeIsInList = ListFindString(&MIMETypeP->typeList, type, &index); if (typeIsInList) mimeTypesItem = MIMETypeP->typeList.item[index]; else mimeTypesItem = (void*)PoolStrdup(&MIMETypeP->pool, type); if (mimeTypesItem) { bool extIsInList; extIsInList = ListFindString(&MIMETypeP->extList, ext, &index); if (extIsInList) { MIMETypeP->typeList.item[index] = mimeTypesItem; *successP = TRUE; } else { void * extItem = (void*)PoolStrdup(&MIMETypeP->pool, ext); if (extItem) { bool addedToMimeTypes; addedToMimeTypes = ListAdd(&MIMETypeP->typeList, mimeTypesItem); if (addedToMimeTypes) { bool addedToExt; addedToExt = ListAdd(&MIMETypeP->extList, extItem); *successP = addedToExt; if (!*successP) ListRemove(&MIMETypeP->typeList); } else *successP = FALSE; if (!*successP) PoolReturn(&MIMETypeP->pool, extItem); } else *successP = FALSE; } } else *successP = FALSE; } abyss_bool MIMETypeAdd2(MIMEType * const MIMETypeArg, const char * const type, const char * const ext) { MIMEType * MIMETypeP = MIMETypeArg ? MIMETypeArg : globalMimeTypeP; bool success; if (MIMETypeP == NULL) success = FALSE; else mimeTypeAdd(MIMETypeP, type, ext, &success); return success; } abyss_bool MIMETypeAdd(const char * const type, const char * const ext) { return MIMETypeAdd2(globalMimeTypeP, type, ext); } static const char * mimeTypeFromExt(MIMEType * const MIMETypeP, const char * const ext) { const char * retval; uint16_t extindex; bool extIsInList; assert(MIMETypeP != NULL); extIsInList = ListFindString(&MIMETypeP->extList, ext, &extindex); if (!extIsInList) retval = NULL; else retval = MIMETypeP->typeList.item[extindex]; return retval; } const char * MIMETypeFromExt2(MIMEType * const MIMETypeArg, const char * const ext) { const char * retval; MIMEType * MIMETypeP = MIMETypeArg ? MIMETypeArg : globalMimeTypeP; if (MIMETypeP == NULL) retval = NULL; else retval = mimeTypeFromExt(MIMETypeP, ext); return retval; } const char * MIMETypeFromExt(const char * const ext) { return MIMETypeFromExt2(globalMimeTypeP, ext); } static void findExtension(const char * const fileName, const char ** const extP) { unsigned int extPos = 0; /* stifle unset variable warning */ /* Running estimation of where in fileName[] the extension starts */ bool extFound; unsigned int i; /* We're looking for the last dot after the last slash */ for (i = 0, extFound = FALSE; fileName[i]; ++i) { char const c = fileName[i]; if (c == '.') { extFound = TRUE; extPos = i + 1; } if (c == '/') extFound = FALSE; } if (extFound) *extP = &fileName[extPos]; else *extP = NULL; } static const char * mimeTypeFromFileName(MIMEType * const MIMETypeP, const char * const fileName) { const char * retval; const char * ext; assert(MIMETypeP != NULL); findExtension(fileName, &ext); if (ext) retval = MIMETypeFromExt2(MIMETypeP, ext); else retval = "application/octet-stream"; return retval; } const char * MIMETypeFromFileName2(MIMEType * const MIMETypeArg, const char * const fileName) { const char * retval; MIMEType * MIMETypeP = MIMETypeArg ? MIMETypeArg : globalMimeTypeP; if (MIMETypeP == NULL) retval = NULL; else retval = mimeTypeFromFileName(MIMETypeP, fileName); return retval; } const char * MIMETypeFromFileName(const char * const fileName) { return MIMETypeFromFileName2(globalMimeTypeP, fileName); } static bool fileContainsText(const char * const fileName) { /*---------------------------------------------------------------------------- Return true iff we can read the contents of the file named 'fileName' and see that it appears to be composed of plain text characters. -----------------------------------------------------------------------------*/ bool retval; bool fileOpened; TFile * fileP; fileOpened = FileOpen(&fileP, fileName, O_BINARY | O_RDONLY); if (fileOpened) { char const ctlZ = 26; unsigned char buffer[80]; int32_t readRc; unsigned int i; readRc = FileRead(fileP, buffer, sizeof(buffer)); if (readRc >= 0) { unsigned int bytesRead = readRc; bool nonTextFound; nonTextFound = FALSE; /* initial value */ for (i = 0; i < bytesRead; ++i) { char const c = buffer[i]; if (c < ' ' && !isspace(c) && c != ctlZ) nonTextFound = TRUE; } retval = !nonTextFound; } else retval = FALSE; FileClose(fileP); } else retval = FALSE; return retval; } static const char * mimeTypeGuessFromFile(MIMEType * const MIMETypeP, const char * const fileName) { const char * retval; const char * ext; findExtension(fileName, &ext); retval = NULL; if (ext && MIMETypeP) retval = MIMETypeFromExt2(MIMETypeP, ext); if (!retval) { if (fileContainsText(fileName)) retval = "text/plain"; else retval = "application/octet-stream"; } return retval; } const char * MIMETypeGuessFromFile2(MIMEType * const MIMETypeArg, const char * const fileName) { return mimeTypeGuessFromFile(MIMETypeArg ? MIMETypeArg : globalMimeTypeP, fileName); } const char * MIMETypeGuessFromFile(const char * const fileName) { return mimeTypeGuessFromFile(globalMimeTypeP, fileName); } /****************************************************************************** ** ** http.c ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ xmlrpc-c-1.33.14/lib/abyss/src/server.c000066400000000000000000001400711236133176700175540ustar00rootroot00000000000000/* Copyright information is at end of file */ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #define _BSD_SOURCE /* Make sure setgroups()is in */ #include #include #include #include #include #include #ifndef _WIN32 #include #endif #include "xmlrpc_config.h" #include "bool.h" #include "girmath.h" #include "mallocvar.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/sleep_int.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_platform.h" #include "xmlrpc-c/abyss.h" #include "trace.h" #include "thread.h" #include "session.h" #include "file.h" #include "conn.h" #include "chanswitch.h" #include "channel.h" #include "socket.h" #ifdef _WIN32 #include "socket_win.h" #else #include "socket_unix.h" #endif #include "http.h" #include "handler.h" #include "server.h" struct uriHandler { initHandlerFn init; termHandlerFn term; handleReq3Fn handleReq3; handleReq2Fn handleReq2; URIHandler handleReq1; void * userdata; }; void ServerTerminate(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; srvP->terminationRequested = true; if (srvP->chanSwitchP) ChanSwitchInterrupt(srvP->chanSwitchP); } void ServerResetTerminate(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; srvP->terminationRequested = false; } static void initUnixStuff(struct _TServer * const srvP) { #ifndef _WIN32 srvP->pidfileP = NULL; srvP->uid = srvP->gid = -1; #endif } static void logOpen(struct _TServer * const srvP, const char ** const errorP) { bool success; success = FileOpenCreate(&srvP->logfileP, srvP->logfilename, O_WRONLY | O_APPEND); if (success) { srvP->logLockP = xmlrpc_lock_create(); *errorP = NULL; srvP->logfileisopen = TRUE; if (*errorP) FileClose(srvP->logfileP); } else xmlrpc_asprintf(errorP, "Can't open log file '%s'", srvP->logfilename); } static void logClose(struct _TServer * const srvP) { if (srvP->logfileisopen) { FileClose(srvP->logfileP); srvP->logLockP->destroy(srvP->logLockP); srvP->logfileisopen = FALSE; } } static void setupTrace(struct _TServer * const srvP) { srvP->traceIsActive = (getenv("ABYSS_TRACE_SERVER") != NULL); if (srvP->traceIsActive) fprintf(stderr, "Abyss server will trace " "basic server activity " "due to ABYSS_TRACE_SERVER environment variable\n"); } static void tracev(const char * const fmt, va_list argptr) { vfprintf(stderr, fmt, argptr); fprintf(stderr, "\n"); } static void trace(struct _TServer * const srvP, const char * const fmt, ...) { if (srvP->traceIsActive) { va_list argptr; va_start(argptr, fmt); tracev(fmt, argptr); va_end(argptr); } } static void initChanSwitchStuff(struct _TServer * const srvP, bool const noAccept, TChanSwitch * const chanSwitchP, bool const userChanSwitch, unsigned short const port, const char ** const errorP) { if (chanSwitchP) { *errorP = NULL; srvP->serverAcceptsConnections = TRUE; srvP->chanSwitchP = chanSwitchP; srvP->weCreatedChanSwitch = !userChanSwitch; } else if (noAccept) { *errorP = NULL; srvP->serverAcceptsConnections = FALSE; srvP->chanSwitchP = NULL; srvP->weCreatedChanSwitch = FALSE; } else { *errorP = NULL; srvP->serverAcceptsConnections = TRUE; srvP->chanSwitchP = NULL; srvP->weCreatedChanSwitch = FALSE; srvP->port = port; } } static void createServer(struct _TServer ** const srvPP, bool const noAccept, TChanSwitch * const chanSwitchP, bool const userChanSwitch, unsigned short const portNumber, const char ** const errorP) { struct _TServer * srvP; MALLOCVAR(srvP); if (srvP == NULL) { xmlrpc_asprintf(errorP, "Unable to allocate space for server descriptor"); } else { setupTrace(srvP); srvP->terminationRequested = false; initChanSwitchStuff(srvP, noAccept, chanSwitchP, userChanSwitch, portNumber, errorP); if (!*errorP) { srvP->builtinHandlerP = HandlerCreate(); if (!srvP->builtinHandlerP) xmlrpc_asprintf(errorP, "Unable to allocate space for " "builtin handler descriptor"); else { srvP->defaultHandler = HandlerDefaultBuiltin; srvP->defaultHandlerContext = srvP->builtinHandlerP; srvP->name = strdup("unnamed"); srvP->logfilename = NULL; srvP->keepalivetimeout = 15; srvP->keepalivemaxconn = 30; srvP->timeout = 15; srvP->advertise = TRUE; srvP->useSigchld = FALSE; srvP->uriHandlerStackSize = 0; srvP->maxConn = 15; srvP->maxConnBacklog = 15; initUnixStuff(srvP); ListInitAutoFree(&srvP->handlers); srvP->logfileisopen = FALSE; *errorP = NULL; if (*errorP) HandlerDestroy(srvP->builtinHandlerP); } } if (*errorP) free(srvP); } *srvPP = srvP; } static void setNamePathLog(TServer * const serverP, const char * const name, const char * const filesPath, const char * const logFileName) { /*---------------------------------------------------------------------------- This odd function exists to help with backward compatibility. Today, we have the expandable model where you create a server with default parameters, then use ServerSet... functions to choose non-default parameters. But before, you specified these three parameters right in the arguments of various create functions. -----------------------------------------------------------------------------*/ if (name) ServerSetName(serverP, name); if (filesPath) ServerSetFilesPath(serverP, filesPath); if (logFileName) ServerSetLogFileName(serverP, logFileName); } abyss_bool ServerCreate(TServer * const serverP, const char * const name, xmlrpc_uint16_t const portNumber, const char * const filesPath, const char * const logFileName) { bool const noAcceptFalse = FALSE; bool const userChanSwitchFalse = FALSE; bool success; const char * error; createServer(&serverP->srvP, noAcceptFalse, NULL, userChanSwitchFalse, portNumber, &error); if (error) { TraceMsg(error); xmlrpc_strfree(error); success = FALSE; } else { success = TRUE; setNamePathLog(serverP, name, filesPath, logFileName); } return success; } static void createSwitchFromOsSocket(TOsSocket const osSocket, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { #ifdef _WIN32 ChanSwitchWinCreateWinsock(osSocket, chanSwitchPP, errorP); #else ChanSwitchUnixCreateFd(osSocket, chanSwitchPP, errorP); #endif } static void createChannelFromOsSocket(TOsSocket const osSocket, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { #ifdef _WIN32 ChannelWinCreateWinsock(osSocket, channelPP, (struct abyss_win_chaninfo**)channelInfoPP, errorP); #else ChannelUnixCreateFd(osSocket, channelPP, (struct abyss_unix_chaninfo**)channelInfoPP, errorP); #endif } abyss_bool ServerCreateSocket(TServer * const serverP, const char * const name, TOsSocket const socketFd, const char * const filesPath, const char * const logFileName) { bool success; TChanSwitch * chanSwitchP; const char * error; createSwitchFromOsSocket(socketFd, &chanSwitchP, &error); if (error) { TraceMsg(error); success = FALSE; xmlrpc_strfree(error); } else { bool const noAcceptFalse = FALSE; bool const userChanSwitchFalse = FALSE; const char * error; createServer(&serverP->srvP, noAcceptFalse, chanSwitchP, userChanSwitchFalse, 0, &error); if (error) { TraceMsg(error); success = FALSE; xmlrpc_strfree(error); } else { success = TRUE; setNamePathLog(serverP, name, filesPath, logFileName); } if (!success) ChanSwitchDestroy(chanSwitchP); } return success; } abyss_bool ServerCreateNoAccept(TServer * const serverP, const char * const name, const char * const filesPath, const char * const logFileName) { bool const noAcceptTrue = TRUE; bool const userChanSwitchFalse = FALSE; bool success; const char * error; createServer(&serverP->srvP, noAcceptTrue, NULL, userChanSwitchFalse, 0, &error); if (error) { TraceMsg(error); success = FALSE; xmlrpc_strfree(error); } else { success = TRUE; setNamePathLog(serverP, name, filesPath, logFileName); } return success; } void ServerCreateSwitch(TServer * const serverP, TChanSwitch * const chanSwitchP, const char ** const errorP) { bool const noAcceptFalse = FALSE; bool const userChanSwitchTrue = TRUE; assert(serverP); assert(chanSwitchP); createServer(&serverP->srvP, noAcceptFalse, chanSwitchP, userChanSwitchTrue, 0, errorP); } void ServerCreateSocket2(TServer * const serverP, TSocket * const socketP, const char ** const errorP) { TChanSwitch * const chanSwitchP = SocketGetChanSwitch(socketP); assert(socketP); if (!chanSwitchP) xmlrpc_asprintf( errorP, "Socket is not a listening socket. " "You should use ServerCreateSwitch() instead, anyway."); else ServerCreateSwitch(serverP, chanSwitchP, errorP); } static void terminateHandlers(TList * const handlersP) { /*---------------------------------------------------------------------------- Terminate all handlers in the list '*handlersP'. I.e. call each handler's terminate function. -----------------------------------------------------------------------------*/ if (handlersP->item) { unsigned int i; for (i = handlersP->size; i > 0; --i) { struct uriHandler * const handlerP = handlersP->item[i-1]; if (handlerP->term) handlerP->term(handlerP->userdata); } } } void ServerFree(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; if (srvP->weCreatedChanSwitch) ChanSwitchDestroy(srvP->chanSwitchP); xmlrpc_strfree(srvP->name); terminateHandlers(&srvP->handlers); ListFree(&srvP->handlers); HandlerDestroy(srvP->builtinHandlerP); logClose(srvP); if (srvP->logfilename) xmlrpc_strfree(srvP->logfilename); free(srvP); } void ServerSetName(TServer * const serverP, const char * const name) { xmlrpc_strfree(serverP->srvP->name); serverP->srvP->name = strdup(name); } void ServerSetFilesPath(TServer * const serverP, const char * const filesPath) { HandlerSetFilesPath(serverP->srvP->builtinHandlerP, filesPath); } void ServerSetLogFileName(TServer * const serverP, const char * const logFileName) { struct _TServer * const srvP = serverP->srvP; if (srvP->logfilename) xmlrpc_strfree(srvP->logfilename); srvP->logfilename = strdup(logFileName); } void ServerSetKeepaliveTimeout(TServer * const serverP, xmlrpc_uint32_t const keepaliveTimeout) { serverP->srvP->keepalivetimeout = MAX(keepaliveTimeout, 1); } void ServerSetKeepaliveMaxConn(TServer * const serverP, xmlrpc_uint32_t const keepaliveMaxConn) { serverP->srvP->keepalivemaxconn = MAX(keepaliveMaxConn, 1); } void ServerSetTimeout(TServer * const serverP, xmlrpc_uint32_t const timeout) { serverP->srvP->timeout = timeout; } void ServerSetAdvertise(TServer * const serverP, abyss_bool const advertise) { serverP->srvP->advertise = advertise; } void ServerSetMimeType(TServer * const serverP, MIMEType * const mimeTypeP) { HandlerSetMimeType(serverP->srvP->builtinHandlerP, mimeTypeP); } void ServerSetMaxConn(TServer * const serverP, unsigned int const maxConn) { if (maxConn > 0) { serverP->srvP->maxConn = maxConn; } } void ServerSetMaxConnBacklog(TServer * const serverP, unsigned int const maxConnBacklog) { if (maxConnBacklog > 0) { serverP->srvP->maxConnBacklog = maxConnBacklog; } } static URIHandler2 makeUriHandler2(const struct uriHandler * const handlerP) { URIHandler2 retval; retval.init = handlerP->init; retval.term = handlerP->term; retval.handleReq2 = handlerP->handleReq2; retval.handleReq1 = handlerP->handleReq1; retval.userdata = handlerP->userdata; return retval; } static void runUserHandler(TSession * const sessionP, struct _TServer * const srvP) { abyss_bool handled; int i; for (i = srvP->handlers.size-1, handled = FALSE; i >= 0 && !handled; --i) { const struct uriHandler * const handlerP = srvP->handlers.item[i]; if (handlerP->handleReq3) handlerP->handleReq3(handlerP->userdata, sessionP, &handled); if (handlerP->handleReq2) { URIHandler2 handler2 = makeUriHandler2(handlerP); handlerP->handleReq2(&handler2, sessionP, &handled); } else if (handlerP->handleReq1) handled = handlerP->handleReq1(sessionP); } assert(srvP->defaultHandler); if (!handled) srvP->defaultHandler(sessionP); } static void handleReqTooNewHttpVersion(TSession * const sessionP) { const char * msg; ResponseStatus(sessionP, 505); xmlrpc_asprintf(&msg, "Request is in HTTP Version %u" "We understand only HTTP 1", sessionP->version.major); ResponseError2(sessionP, msg); xmlrpc_strfree(msg); } static void handleReqInvalidURI(TSession * const sessionP) { ResponseStatus(sessionP, 400); ResponseError2(sessionP, "Invalid URI"); } static void processRequestFromClient(TConn * const connectionP, bool const lastReqOnConn, uint32_t const timeout, bool * const keepAliveP) { /*---------------------------------------------------------------------------- Get and execute one HTTP request from client connection *connectionP, through the connection buffer. I.e. Some of the request may already be in the connection buffer, and we may leave some of later requests in the connection buffer. In fact, due to timing considerations, we assume the client has begun sending the request, which as a practical matter means Caller has already deposited some of it in the connection buffer. If there isn't one full request in the buffer now, we wait for one full request to come through the buffer, up to 'timeout'. We return as *keepAliveP whether Caller should keep the connection alive for a while for possible future requests from the client, based on 'lastReqOnConn' and the content of the HTTP request. Executing the request consists primarily of calling the URI handlers that are associated with the connection (*connectionP), passing each the request information we read. Each handler can respond according to the HTTP method (GET, POST, etc) and URL etc, and that response may be either to execute the request and send the response or refuse the request and let us call the next one in the list. -----------------------------------------------------------------------------*/ TSession session; const char * error; uint16_t httpErrorCode; RequestInit(&session, connectionP); session.serverDeniesKeepalive = lastReqOnConn; RequestRead(&session, timeout, &error, &httpErrorCode); if (error) { ResponseStatus(&session, httpErrorCode); ResponseError2(&session, error); xmlrpc_strfree(error); } else { if (session.version.major >= 2) handleReqTooNewHttpVersion(&session); else if (!RequestValidURI(&session)) handleReqInvalidURI(&session); else runUserHandler(&session, connectionP->server->srvP); } assert(session.status != 0); if (session.responseStarted) HTTPWriteEndChunk(&session); else ResponseError(&session); *keepAliveP = HTTPKeepalive(&session); SessionLog(&session); RequestFree(&session); } static TThreadProc serverFunc; static void serverFunc(void * const userHandle) { /*---------------------------------------------------------------------------- Do server stuff on one connection. At its simplest, this means do one HTTP request. But with keepalive, it can be many requests. -----------------------------------------------------------------------------*/ TConn * const connectionP = userHandle; struct _TServer * const srvP = connectionP->server->srvP; unsigned int requestCount; /* Number of requests we've handled so far on this connection */ bool connectionDone; /* No more need for this HTTP connection */ trace(srvP, "Thread starting to handle requests on a new connection. " "PID = %d", getpid()); requestCount = 0; connectionDone = FALSE; while (!connectionDone) { bool timedOut, eof; const char * readError; /* Wait for and get beginning (at least ) of next request. We do this separately from getting the rest of the request because we treat dead time between requests differently from dead time in the middle of a request. */ ConnRead(connectionP, srvP->keepalivetimeout, &timedOut, &eof, &readError); if (srvP->terminationRequested) { connectionDone = TRUE; } else if (readError) { TraceMsg("Failed to read from Abyss connection. %s", readError); xmlrpc_strfree(readError); connectionDone = TRUE; } else if (timedOut) { connectionDone = TRUE; } else if (eof) { connectionDone = TRUE; } else { bool const lastReqOnConn = requestCount + 1 >= srvP->keepalivemaxconn; bool keepalive; trace(srvP, "HTTP request %u at least partially received. " "Receiving the rest and processing", requestCount); processRequestFromClient(connectionP, lastReqOnConn, srvP->timeout, &keepalive); trace(srvP, "Done processing the HTTP request. Keepalive = %s", keepalive ? "YES" : "NO"); ++requestCount; if (!keepalive) connectionDone = TRUE; /**************** Must adjust the read buffer *****************/ ConnReadInit(connectionP); } } trace(srvP, "PID %d done with connection", getpid()); } /* This is the maximum amount of stack space, in bytes, serverFunc() itself requires -- not counting what the user's request handler (which serverFunc() calls) requires. */ #define SERVER_FUNC_STACK 1024 static void createSwitchFromPortNum(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { #ifdef _WIN32 ChanSwitchWinCreate(portNumber, chanSwitchPP, errorP); #else ChanSwitchUnixCreate(portNumber, chanSwitchPP, errorP); #endif } static void createChanSwitch(struct _TServer * const srvP, const char ** const errorP) { TChanSwitch * chanSwitchP; const char * error; /* Not valid to call this when channel switch already exists: */ assert(srvP->chanSwitchP == NULL); createSwitchFromPortNum(srvP->port, &chanSwitchP, &error); if (error) { xmlrpc_asprintf(errorP, "Can't create channel switch. %s", error); xmlrpc_strfree(error); } else { *errorP = NULL; srvP->weCreatedChanSwitch = TRUE; srvP->chanSwitchP = chanSwitchP; } } void ServerInit2(TServer * const serverP, const char ** const errorP) { /*---------------------------------------------------------------------------- Initialize a server to accept connections. Do not confuse this with creating the server -- ServerCreate(). Not necessary or valid with a server that doesn't accept connections (i.e. user supplies the channels (TCP connections)). -----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; if (!srvP->serverAcceptsConnections) xmlrpc_asprintf(errorP, "ServerInit() is not valid on a server that doesn't " "accept connections " "(i.e. created with ServerCreateNoAccept)"); else { *errorP = NULL; /* initial value */ if (!srvP->chanSwitchP) { const char * error; createChanSwitch(srvP, &error); if (error) { xmlrpc_asprintf(errorP, "Unable to create a channel switch " "for the server. %s", error); xmlrpc_strfree(error); } } if (!*errorP) { const char * error; assert(srvP->chanSwitchP); ChanSwitchListen(srvP->chanSwitchP, srvP->maxConnBacklog, &error); if (error) { xmlrpc_asprintf(errorP, "Failed to listen on bound socket. %s", error); xmlrpc_strfree(error); } } } } void ServerInit(TServer * const serverP) { const char * error; ServerInit2(serverP, &error); if (error) { TraceExit("ServerInit() failed. %s", error); xmlrpc_strfree(error); } } /* We don't do any locking on the outstanding connections list, so we must make sure that only the master thread (the one that listens for connections) ever accesses it. That's why when a thread completes, it places the connection in "finished" status, but doesn't destroy the connection. */ typedef struct { TConn * firstP; unsigned int count; /* Redundant with 'firstP', for quick access */ } outstandingConnList; static void createOutstandingConnList(outstandingConnList ** const listPP) { outstandingConnList * listP; MALLOCVAR_NOFAIL(listP); listP->firstP = NULL; /* empty list */ listP->count = 0; *listPP = listP; } static void destroyOutstandingConnList(outstandingConnList * const listP) { assert(listP->firstP == NULL); assert(listP->count == 0); free(listP); } static void addToOutstandingConnList(outstandingConnList * const listP, TConn * const connectionP) { connectionP->nextOutstandingP = listP->firstP; listP->firstP = connectionP; ++listP->count; } static void freeFinishedConns(outstandingConnList * const listP) { /*---------------------------------------------------------------------------- Garbage-collect the resources associated with connections that are finished with their jobs. Thread resources, connection pool descriptor, etc. -----------------------------------------------------------------------------*/ TConn ** pp; pp = &listP->firstP; while (*pp) { TConn * const connectionP = (*pp); ThreadUpdateStatus(connectionP->threadP); if (connectionP->finished) { /* Take it out of the list */ *pp = connectionP->nextOutstandingP; --listP->count; ConnWaitAndRelease(connectionP); } else { /* Move to next connection in list */ pp = &connectionP->nextOutstandingP; } } } static void waitForConnectionFreed(outstandingConnList * const outstandingConnListP ATTR_UNUSED) { /*---------------------------------------------------------------------------- Wait for a connection descriptor in 'connectionPool' to be probably freed. -----------------------------------------------------------------------------*/ /* TODO: We should do something more sophisticated here. For pthreads, we can have a thread signal us by semaphore when it terminates. For fork, we might be able to use the "done" handler argument to ConnCreate() to get interrupted when the death of a child signal happens. */ xmlrpc_millisecond_sleep(2000); } static void waitForNoConnections(outstandingConnList * const outstandingConnListP) { while (outstandingConnListP->firstP) { freeFinishedConns(outstandingConnListP); if (outstandingConnListP->firstP) waitForConnectionFreed(outstandingConnListP); } } static void waitForConnectionCapacity(outstandingConnList * const outstandingConnListP, unsigned int const maxConn) { /*---------------------------------------------------------------------------- Wait until there are fewer than 'maxConn' connections in progress. -----------------------------------------------------------------------------*/ while (outstandingConnListP->count >= maxConn) { freeFinishedConns(outstandingConnListP); if (outstandingConnListP->firstP) waitForConnectionFreed(outstandingConnListP); } } static void interruptChannels(outstandingConnList * const outstandingConnListP) { /*---------------------------------------------------------------------------- Get every thread that is waiting to read a request or write a response for a connection to stop waiting. -----------------------------------------------------------------------------*/ TConn * connP; for (connP = outstandingConnListP->firstP; connP; connP = connP->nextOutstandingP) { if (connP->finished) { /* The connection couldn't be waiting on the channel, and the channel probably doesn't even exit anymore. */ } else ChannelInterrupt(connP->channelP); } } #ifndef _WIN32 void ServerHandleSigchld(pid_t const pid) { ThreadHandleSigchld(pid); } #endif void ServerUseSigchld(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; srvP->useSigchld = TRUE; } static TThreadDoneFn destroyChannel; static void destroyChannel(void * const userHandle) { /*---------------------------------------------------------------------------- This is a "connection done" function for the connection the server serves. It gets called some time after the connection has done its thing. Its job is to clean up stuff the server created for use by the connection, but the server can't clean up because the connection might be processed asynchronously in a background thread. To wit, we destroy the connection's channel and release the memory for the information about that channel. -----------------------------------------------------------------------------*/ TConn * const connectionP = userHandle; ChannelDestroy(connectionP->channelP); free(connectionP->channelInfoP); } static void processNewChannel(TServer * const serverP, TChannel * const channelP, void * const channelInfoP, outstandingConnList * const outstandingConnListP, const char ** const errorP) { struct _TServer * const srvP = serverP->srvP; TConn * connectionP; const char * error; freeFinishedConns(outstandingConnListP); trace(srvP, "Waiting for there to be fewer than the maximum " "%u sessions in progress", srvP->maxConn); waitForConnectionCapacity(outstandingConnListP, srvP->maxConn); ConnCreate(&connectionP, serverP, channelP, channelInfoP, &serverFunc, SERVER_FUNC_STACK + srvP->uriHandlerStackSize, &destroyChannel, ABYSS_BACKGROUND, srvP->useSigchld, &error); if (!error) { addToOutstandingConnList(outstandingConnListP, connectionP); ConnProcess(connectionP); /* When connection is done (which could be later, courtesy of a background thread), destroyChannel() will destroy *channelP. */ *errorP = NULL; } else { xmlrpc_asprintf( errorP, "Failed to create an Abyss connection. %s", error); xmlrpc_strfree(error); } } static void acceptAndProcessNextConnection( TServer * const serverP, outstandingConnList * const outstandingConnListP, const char ** const errorP) { struct _TServer * const srvP = serverP->srvP; const char * error; TChannel * channelP; void * channelInfoP; trace(srvP, "Waiting for a new channel from channel switch"); ChanSwitchAccept(srvP->chanSwitchP, &channelP, &channelInfoP, &error); if (error) { xmlrpc_asprintf(errorP, "Failed to accept the next connection from a client " "at the channel level. %s", error); xmlrpc_strfree(error); } else { if (channelP) { const char * error; trace(srvP, "Got a new channel from channel switch"); processNewChannel(serverP, channelP, channelInfoP, outstandingConnListP, &error); if (error) { xmlrpc_asprintf(errorP, "Failed to use new channel %lx", (unsigned long) channelP); ChannelDestroy(channelP); free(channelInfoP); } else { trace(srvP, "successfully processed newly accepted channel"); /* Connection created above will destroy *channelP and *channelInfoP as it terminates. */ } } else { /* Accept function was interrupted before it got a connection */ trace(srvP, "Wait for new channel from switch was interrupted"); *errorP = NULL; } } } static void serverRun2(TServer * const serverP, const char ** const errorP) { struct _TServer * const srvP = serverP->srvP; outstandingConnList * outstandingConnListP; createOutstandingConnList(&outstandingConnListP); *errorP = NULL; /* initial value */ trace(srvP, "Starting main connection accepting loop"); while (!srvP->terminationRequested && !*errorP) acceptAndProcessNextConnection(serverP, outstandingConnListP, errorP); trace(srvP, "Main connection accepting loop is done"); if (!*errorP) { trace(srvP, "Interrupting and waiting for %u existing connections " "to finish", outstandingConnListP->count); interruptChannels(outstandingConnListP); waitForNoConnections(outstandingConnListP); trace(srvP, "No connections left"); destroyOutstandingConnList(outstandingConnListP); } } void ServerRun(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; trace(srvP, "%s entered", __FUNCTION__); if (!srvP->chanSwitchP) TraceMsg("This server is not set up to accept connections " "on its own, so you can't use ServerRun(). " "Try ServerRunConn() or ServerInit()"); else { const char * error; serverRun2(serverP, &error); if (error) { TraceMsg("Server failed. %s", error); xmlrpc_strfree(error); } } trace(srvP, "%s exiting", __FUNCTION__); } static void serverRunChannel(TServer * const serverP, TChannel * const channelP, void * const channelInfoP, const char ** const errorP) { /*---------------------------------------------------------------------------- Do the HTTP transaction on the channel 'channelP'. (channel must be at the beginning of the HTTP request -- nothing having been read or written yet). channelInfoP == NULL means no channel info supplied. -----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; TConn * connectionP; const char * error; trace(srvP, "%s entered", __FUNCTION__); srvP->keepalivemaxconn = 1; ConnCreate(&connectionP, serverP, channelP, channelInfoP, &serverFunc, SERVER_FUNC_STACK + srvP->uriHandlerStackSize, NULL, ABYSS_FOREGROUND, srvP->useSigchld, &error); if (error) { xmlrpc_asprintf(errorP, "Couldn't create HTTP connection out of " "channel (connected socket). %s", error); xmlrpc_strfree(error); } else { *errorP = NULL; ConnProcess(connectionP); ConnWaitAndRelease(connectionP); } trace(srvP, "%s exiting", __FUNCTION__); } void ServerRunChannel(TServer * const serverP, TChannel * const channelP, void * const channelInfoP, const char ** const errorP) { /*---------------------------------------------------------------------------- Do the HTTP transaction on the channel 'channelP'. (channel must be at the beginning of the HTTP request -- nothing having been read or written yet). -----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; trace(srvP, "%s entered", __FUNCTION__); if (srvP->serverAcceptsConnections) xmlrpc_asprintf(errorP, "This server is configured to accept connections on " "its own socket. " "Try ServerRun() or ServerCreateNoAccept()."); else serverRunChannel(serverP, channelP, channelInfoP, errorP); trace(srvP, "%s exiting", __FUNCTION__); } void ServerRunConn2(TServer * const serverP, TSocket * const connectedSocketP, const char ** const errorP) { /*---------------------------------------------------------------------------- Do the HTTP transaction on the TCP connection on the socket *connectedSocketP. (socket must be connected state, with nothing having been read or written on the connection yet). -----------------------------------------------------------------------------*/ TChannel * const channelP = SocketGetChannel(connectedSocketP); if (!channelP) xmlrpc_asprintf(errorP, "The socket supplied is not a connected " "socket. You should use ServerRunChannel() instead, " "anyway."); else ServerRunChannel(serverP, channelP, SocketGetChannelInfo(connectedSocketP), errorP); } void ServerRunConn(TServer * const serverP, TOsSocket const connectedOsSocket) { TChannel * channelP; void * channelInfoP; const char * error; createChannelFromOsSocket(connectedOsSocket, &channelP, &channelInfoP, &error); if (error) { TraceExit("Unable to use supplied socket"); xmlrpc_strfree(error); } else { const char * error; ServerRunChannel(serverP, channelP, channelInfoP, &error); if (error) { TraceExit("Failed to run server on connection on file " "descriptor %d. %s", connectedOsSocket, error); xmlrpc_strfree(error); } ChannelDestroy(channelP); free(channelInfoP); } } void ServerRunOnce(TServer * const serverP) { /*---------------------------------------------------------------------------- Accept a connection from the channel switch and do the HTTP transaction that comes over it. If no connection is presently waiting at the switch, wait for one. But return immediately if we receive a signal during the wait. -----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; trace(srvP, "%s entered", __FUNCTION__); if (!srvP->chanSwitchP) TraceMsg("This server is not set up to accept connections " "on its own, so you can't use ServerRunOnce(). " "Try ServerRunChannel() or ServerInit()"); else { const char * error; TChannel * channelP; void * channelInfoP; srvP->keepalivemaxconn = 1; ChanSwitchAccept(srvP->chanSwitchP, &channelP, &channelInfoP, &error); if (error) { TraceMsg("Failed to accept the next connection from a client " "at the channel level. %s", error); xmlrpc_strfree(error); } else { if (channelP) { const char * error; serverRunChannel(serverP, channelP, channelInfoP, &error); if (error) { const char * peerDesc; ChannelFormatPeerInfo(channelP, &peerDesc); TraceExit("Got a connection from '%s', but failed to " "run server on it. %s", peerDesc, error); xmlrpc_strfree(peerDesc); xmlrpc_strfree(error); } ChannelDestroy(channelP); free(channelInfoP); } } } trace(srvP, "%s exiting", __FUNCTION__); } void ServerRunOnce2(TServer * const serverP, enum abyss_foreback const foregroundBackground ATTR_UNUSED) { /*---------------------------------------------------------------------------- This is a backward compatibility interface to ServerRunOnce(). 'foregroundBackground' is meaningless. We always process the connection in the foreground. The parameter exists because we once thought we could do them in the background, but we really can't do that in any clean way. If Caller wants background execution, he can spin his own thread or process to call us. It makes much more sense in Caller's context. -----------------------------------------------------------------------------*/ ServerRunOnce(serverP); } static void setGroups(const char ** const errorP) { #if HAVE_SETGROUPS if (setgroups(0, NULL) == -1) xmlrpc_asprintf(errorP, "setgroups() errno = %d (%s)", errno, strerror(errno)); #else *errorP = NULL; #endif } void ServerDaemonize(TServer * const serverP) { /*---------------------------------------------------------------------------- Turn Caller into a daemon (i.e. fork a child, then exit; the child returns to Caller). NOTE: It's ridiculous, but conventional, for us to do this. It's ridiculous because the task of daemonizing is not something particular to Abyss. It ought to be done by a higher level. In fact, it should be done before the Abyss server program is even execed. The user should run a "daemonize" program that creates a daemon which execs the Abyss server program. -----------------------------------------------------------------------------*/ struct _TServer * const srvP = serverP->srvP; #ifndef _WIN32 /* Become a daemon */ switch (fork()) { case 0: break; case -1: TraceExit("Unable to become a daemon"); default: /* We are the parent */ exit(0); } setsid(); /* Change the current user if we are root */ if (getuid()==0) { const char * error; if (srvP->uid == (uid_t)-1) TraceExit("Can't run under root privileges. " "Please add a User option in your " "Abyss configuration file."); setGroups(&error); if (error) { TraceExit("Failed to set groups. %s", error); xmlrpc_strfree(error); } if (srvP->gid != (gid_t)-1) if (setgid(srvP->gid)==(-1)) TraceExit("Failed to change the group."); if (setuid(srvP->uid) == -1) TraceExit("Failed to change the user."); } if (srvP->pidfileP) { char z[16]; sprintf(z, "%d", getpid()); FileWrite(srvP->pidfileP, z, strlen(z)); FileClose(srvP->pidfileP); } #endif /* _WIN32 */ } static void serverAddHandler(TServer * const serverP, initHandlerFn init, termHandlerFn term, URIHandler handleReq1, handleReq2Fn handleReq2, handleReq3Fn handleReq3, void * const userdata, size_t const handleReqStackSizeReq, abyss_bool * const successP) { struct _TServer * const srvP = serverP->srvP; size_t handleReqStackSize = handleReqStackSizeReq ? handleReqStackSizeReq : 128*1024; struct uriHandler * handlerP; MALLOCVAR(handlerP); if (handlerP == NULL) *successP = FALSE; else { handlerP->init = init; handlerP->term = term; handlerP->handleReq1 = handleReq1; handlerP->handleReq2 = handleReq2; handlerP->handleReq3 = handleReq3; handlerP->userdata = userdata; srvP->uriHandlerStackSize = MAX(srvP->uriHandlerStackSize, handleReqStackSize); if (handlerP->init == NULL) *successP = TRUE; else { URIHandler2 handler2 = makeUriHandler2(handlerP); handlerP->init(&handler2, successP); } if (*successP) *successP = ListAdd(&serverP->srvP->handlers, handlerP); if (!*successP) free(handlerP); } } void ServerAddHandler3(TServer * const serverP, const struct ServerReqHandler3 * const handlerP, abyss_bool * const successP) { serverAddHandler(serverP, NULL, handlerP->term, NULL, NULL, handlerP->handleReq, handlerP->userdata, handlerP->handleReqStackSize, successP); } void ServerAddHandler2(TServer * const serverP, URIHandler2 * const handlerArgP, abyss_bool * const successP) { /* This generation of the URI handler interface is strange because it went through an unfortunate evolution. So it halfway looks like the use supplies a handler object and Abyss calls its methods, and halfway looks like the user simply describes his handler. Abyss calls handleReq2 with a pointer to a URIHandler2 like the one which is our argument, but it isn't the same one. User can discard *handlerArgP as soon as we return. */ serverAddHandler(serverP, handlerArgP->init, handlerArgP->term, NULL, handlerArgP->handleReq2, NULL, handlerArgP->userdata, 0, successP); } abyss_bool ServerAddHandler(TServer * const serverP, URIHandler const function) { URIHandler2 handler; abyss_bool success; handler.init = NULL; handler.term = NULL; handler.userdata = NULL; handler.handleReq2 = NULL; handler.handleReq1 = function; ServerAddHandler2(serverP, &handler, &success); return success; } /* This is the maximum amount of stack we allow a user's default URI handler to use. (If he exceeds this, results are undefined). We really ought to provide user a way to set this, as he can for his non-default URI handlers. */ #define USER_DEFAULT_HANDLER_STACK 128*1024 void ServerDefaultHandler(TServer * const serverP, URIHandler const handler) { struct _TServer * const srvP = serverP->srvP; if (handler) { srvP->defaultHandler = handler; srvP->uriHandlerStackSize = MAX(srvP->uriHandlerStackSize, USER_DEFAULT_HANDLER_STACK); } else { srvP->defaultHandler = HandlerDefaultBuiltin; srvP->defaultHandlerContext = srvP->builtinHandlerP; srvP->uriHandlerStackSize = MAX(srvP->uriHandlerStackSize, HandlerDefaultBuiltinStack); } } void LogWrite(TServer * const serverP, const char * const msg) { struct _TServer * const srvP = serverP->srvP; if (!srvP->logfileisopen && srvP->logfilename) { const char * error; logOpen(srvP, &error); if (error) { TraceMsg("Failed to open log file. %s", error); xmlrpc_strfree(error); } } if (srvP->logfileisopen) { const char * const lbr = "\n"; srvP->logLockP->acquire(srvP->logLockP); FileWrite(srvP->logfileP, msg, strlen(msg)); FileWrite(srvP->logfileP, lbr, strlen(lbr)); srvP->logLockP->release(srvP->logLockP); } } /******************************************************************************* ** ** server.c ** ** This file is part of the ABYSS Web server project. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ xmlrpc-c-1.33.14/lib/abyss/src/server.h000066400000000000000000000073401236133176700175620ustar00rootroot00000000000000#ifndef SERVER_H_INCLUDED #define SERVER_H_INCLUDED #include #include "bool.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/abyss.h" #include "data.h" struct TFile; struct _TServer { bool traceIsActive; /* We should report to Standard Error our internal activities */ bool terminationRequested; /* User wants this server to terminate as soon as possible, in particular before accepting any more connections and without waiting for any. */ bool chanSwitchBound; /* The channel switch exists and is bound to a local address (may already be listening as well) */ TChanSwitch * chanSwitchP; /* Meaningful only when 'chanSwitchBound' is true: the channel switch which directs connections from clients to this server. */ bool weCreatedChanSwitch; /* We created the channel switch 'chanSwitchP', as opposed to 1) User supplied it; or 2) there isn't one. */ const char * logfilename; bool logfileisopen; struct TFile * logfileP; lock * logLockP; const char * name; bool serverAcceptsConnections; /* We listen for and accept TCP connections for HTTP transactions. (The alternative is the user supplies a TCP-connected socket for each transaction) */ uint16_t port; /* Meaningful only when 'chanSwitchBound' is false: TCP port number to which we should bind the switch. */ uint32_t keepalivetimeout; uint32_t keepalivemaxconn; uint32_t timeout; /* Maximum time in seconds the server will wait to read a header or a data chunk from the channel. */ uint32_t maxConn; /* Maximum number of connections the server allows to exist (i.e. HTTP transactions in progress) at once. Server will not accept a connection if it already has this many. */ uint32_t maxConnBacklog; /* Maximum number of connections the server allows the OS to queue waiting for the server to accept it. The OS accepts this many TCP connections on the server's behalf and holds them waiting for the server to accept them from the OS. */ TList handlers; /* Ordered list of HTTP request handlers. For each HTTP request, Server calls each one in order until one reports that it handled it. Each item in the list of of type 'uriHandler'. */ URIHandler defaultHandler; /* The handler for HTTP requests that aren't claimed by any handler in the list 'handlers'. This can't be null; if user doesn't supply anything better, it is a built-in basic web server handler. */ void * defaultHandlerContext; /* This is opaque data to be given to the default handler when it requests it. */ void * builtinHandlerP; bool advertise; bool useSigchld; /* Meaningless if not using forking for threads. TRUE means user will call ServerHandleSigchld to indicate that a SIGCHLD signal was received, and server shall use that as its indication that a child has died. FALSE means server will not be aware of SIGCHLD and will instead poll for existence of PIDs to determine if a child has died. */ size_t uriHandlerStackSize; /* The maximum amount of stack any URI handler request handler function will use. Note that this is just the requirement of the function itself, not the stack size for the thread that runs it. */ #ifndef _WIN32 uid_t uid; gid_t gid; #endif struct TFile * pidfileP; }; #endif xmlrpc-c-1.33.14/lib/abyss/src/session.c000066400000000000000000000105611236133176700177310ustar00rootroot00000000000000#include #include #include #include #include "bool.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/abyss.h" #include "server.h" #include "http.h" #include "conn.h" #include "session.h" abyss_bool SessionRefillBuffer(TSession * const sessionP) { /*---------------------------------------------------------------------------- Get the next chunk of HTTP request body from the connection into the buffer. I.e. read data from the socket. -----------------------------------------------------------------------------*/ struct _TServer * const srvP = sessionP->connP->server->srvP; bool failed; failed = FALSE; /* initial value */ /* Reset our read buffer & flush data from previous reads. */ ConnReadInit(sessionP->connP); if (sessionP->continueRequired) failed = !HTTPWriteContinue(sessionP); if (!failed) { const char * readError; sessionP->continueRequired = FALSE; /* Read more network data into our buffer. Fail if we time out before client sends any data or client closes the connection or there's some network error. We're very forgiving about the timeout here. We allow a full timeout per network read, which would allow somebody to keep a connection alive nearly indefinitely. But it's hard to do anything intelligent here without very complicated code. */ ConnRead(sessionP->connP, srvP->timeout, NULL, NULL, &readError); if (readError) { failed = TRUE; xmlrpc_strfree(readError); } } return !failed; } size_t SessionReadDataAvail(TSession * const sessionP) { return sessionP->connP->buffersize - sessionP->connP->bufferpos; } void SessionGetReadData(TSession * const sessionP, size_t const max, const char ** const outStartP, size_t * const outLenP) { /*---------------------------------------------------------------------------- Extract some HTTP request body which the server has read and buffered for the session. Don't get or wait for any data that has not yet arrived. Do not return more than 'max'. We return a pointer to the first byte as *outStartP, and the length in bytes as *outLenP. The memory pointed to belongs to the session. -----------------------------------------------------------------------------*/ uint32_t const bufferPos = sessionP->connP->bufferpos; *outStartP = &sessionP->connP->buffer.t[bufferPos]; assert(bufferPos <= sessionP->connP->buffersize); *outLenP = MIN(max, sessionP->connP->buffersize - bufferPos); /* move pointer past the bytes we are returning */ sessionP->connP->bufferpos += *outLenP; assert(sessionP->connP->bufferpos <= sessionP->connP->buffersize); } void SessionGetRequestInfo(TSession * const sessionP, const TRequestInfo ** const requestInfoPP) { *requestInfoPP = &sessionP->requestInfo; } void SessionGetChannelInfo(TSession * const sessionP, void ** const channelInfoPP) { *channelInfoPP = sessionP->connP->channelInfoP; } abyss_bool SessionLog(TSession * const sessionP) { const char * logline; const char * user; const char * date; const char * peerInfo; if (sessionP->validRequest) { if (sessionP->requestInfo.user) user = sessionP->requestInfo.user; else user = "no_user"; } else user = "???"; DateToLogString(sessionP->date, &date); ConnFormatClientAddr(sessionP->connP, &peerInfo); xmlrpc_asprintf(&logline, "%s - %s - [%s] \"%s\" %d %u", peerInfo, user, date, sessionP->validRequest ? sessionP->requestInfo.requestline : "???", sessionP->status, sessionP->connP->outbytes ); xmlrpc_strfree(peerInfo); xmlrpc_strfree(date); LogWrite(sessionP->connP->server, logline); xmlrpc_strfree(logline); return true; } void * SessionGetDefaultHandlerCtx(TSession * const sessionP) { struct _TServer * const srvP = sessionP->connP->server->srvP; return srvP->defaultHandlerContext; } xmlrpc-c-1.33.14/lib/abyss/src/session.h000066400000000000000000000053501236133176700177360ustar00rootroot00000000000000#ifndef SESSION_H_INCLUDED #define SESSION_H_INCLUDED #include "xmlrpc-c/abyss.h" #include "bool.h" #include "date.h" #include "data.h" typedef struct { uint8_t major; uint8_t minor; } httpVersion; struct _TSession { bool validRequest; /* Client has sent, and server has recognized, a valid HTTP request. This is false when the session is new. If and when the server reads the request from the client and finds it to be valid HTTP, it becomes true. */ TRequestInfo requestInfo; /* Some of the strings this references are in individually malloc'ed memory, but some are pointers into arbitrary other data structures that happen to live as long as the session. Some day, we will fix that. 'requestInfo' is valid only if 'validRequest' is true. */ uint32_t nbfileds; TList cookies; TList ranges; uint16_t status; /* Response status from handler. Zero means session is not ready for a response yet. This can mean that we ran a handler and it did not call ResponseStatus() to declare this fact. */ TString header; bool serverDeniesKeepalive; /* Server doesn't want keepalive for this session, regardless of what happens in the session. E.g. because the connection has already been kept alive long enough. */ bool responseStarted; /* Handler has at least started the response (i.e. called ResponseWriteStart()) */ struct _TConn * connP; httpVersion version; TTable requestHeaderFields; /* All the fields of the header of the HTTP request. The key is the field name in lower case. The value is the verbatim value from the field. */ TTable responseHeaderFields; /* All the fields of the header of the HTTP response. This gets successively computed; at any moment, it is the list of fields the user has requested so far. It also includes fields Abyss itself has decided to include. (Blechh. This needs to be cleaned up). Each table item is an HTTP header field. The Name component of the table item is the header field name (it is syntactically valid but not necessarily a defined field name) and the Value comonent is the header field value (it is syntactically valid but not necessarily semantically valid). */ time_t date; bool chunkedwrite; bool chunkedwritemode; bool continueRequired; /* This client must receive 100 (continue) status before it will send more of the body of the request. */ }; #endif xmlrpc-c-1.33.14/lib/abyss/src/socket.c000066400000000000000000000050261236133176700175360ustar00rootroot00000000000000/*============================================================================ socket.c ============================================================================== Implementation of obsolete TSocket class. Use TChannel and TChanSwitch instead for new work. ============================================================================*/ #include #include #include "int.h" #include "mallocvar.h" #include "xmlrpc-c/abyss.h" #include "channel.h" #include "chanswitch.h" #include "socket.h" /* SocketCreate...() is not exported to the Abyss user. It is meant to be used by an implementation-specific TSocket generator which is exported to the Abyss user, e.g. SocketCreateUnix() in socket_unix.c The TSocket generator functions are the _only_ user-accessible functions that are particular to an implementation. */ static unsigned int const socketSignature = 0x060609; static void socketCreate(TSocket ** const socketPP) { TSocket * socketP; MALLOCVAR(socketP); if (socketP) { socketP->signature = socketSignature; *socketPP = socketP; } else *socketPP = NULL; } void SocketCreateChannel(TChannel * const channelP, void * const channelInfoP, TSocket ** const socketPP) { TSocket * socketP; socketCreate(&socketP); if (socketP) { socketP->channelP = channelP; socketP->chanSwitchP = NULL; socketP->channelInfoP = channelInfoP; *socketPP = socketP; } else *socketPP = NULL; } void SocketCreateChanSwitch(TChanSwitch * const chanSwitchP, TSocket ** const socketPP) { TSocket * socketP; socketCreate(&socketP); if (socketP) { socketP->channelP = NULL; socketP->chanSwitchP = chanSwitchP; *socketPP = socketP; } else *socketPP = NULL; } void SocketDestroy(TSocket * const socketP) { assert(socketP->signature == socketSignature); if (socketP->channelP) { ChannelDestroy(socketP->channelP); free(socketP->channelInfoP); } if (socketP->chanSwitchP) ChanSwitchDestroy(socketP->chanSwitchP); socketP->signature = 0; /* For debuggability */ free(socketP); } TChanSwitch * SocketGetChanSwitch(TSocket * const socketP) { return socketP->chanSwitchP; } TChannel * SocketGetChannel(TSocket * const socketP) { return socketP->channelP; } void * SocketGetChannelInfo(TSocket * const socketP) { return socketP->channelInfoP; } xmlrpc-c-1.33.14/lib/abyss/src/socket.h000066400000000000000000000036601236133176700175450ustar00rootroot00000000000000#ifndef SOCKET_H_INCLUDED #define SOCKET_H_INCLUDED /*============================================================================ This is for backward compatibility. Abyss used to have a socket concept modelled after POSIX sockets, in which a single class (TSocket) contained two very different kinds of objects: some analogous to a TChanSwitch and analogout to a TChannel. Now that we have TChanSwitch and TChannel, users should use those, but there may be old programs that use TSocket, and we want them to continue working. Actually, this may not be necessary. There was only one release (1.06) that had the TSocket interface, and that release didn't provide any incentive to upgrade an older program to use TSocket, so there may be few or no users of TSocket. ============================================================================*/ #include "int.h" #include "xmlrpc-c/abyss.h" struct _TSocket { unsigned int signature; /* With both background and foreground use of sockets, and background being both fork and pthread, it is very easy to screw up socket lifetime and try to destroy twice. We use this signature to help catch such bugs. */ /* Exactly one of 'chanSwitchP' and 'channelP' is non-null. That's how you know which of the two varieties of socket this is. */ TChanSwitch * chanSwitchP; TChannel * channelP; void * channelInfoP; /* Defined only for a channel socket */ }; void SocketCreateChannel(TChannel * const channelP, void * const channelInfoP, TSocket ** const socketPP); void SocketCreateChanSwitch(TChanSwitch * const chanSwitchP, TSocket ** const socketPP); TChanSwitch * SocketGetChanSwitch(TSocket * const socketP); TChannel * SocketGetChannel(TSocket * const socketP); void * SocketGetChannelInfo(TSocket * const socketP); #endif xmlrpc-c-1.33.14/lib/abyss/src/socket_openssl.c000066400000000000000000000435421236133176700213060ustar00rootroot00000000000000/*============================================================================= socket_openssl.c =============================================================================== This is the implementation of TChanSwitch and TChannel for an SSL (Secure Sockets Layer) connection based on an OpenSSL connection object -- what you create with SSL_new(). This is just a template for future development. It does not function (or even compile) today. =============================================================================*/ #include "xmlrpc_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "bool.h" #include "mallocvar.h" #include "trace.h" #include "chanswitch.h" #include "channel.h" #include "socket.h" #include "xmlrpc-c/abyss.h" #include "socket_openssl.h" struct channelOpenSsl { /*---------------------------------------------------------------------------- The properties/state of a TChannel unique to the OpenSSL variety. -----------------------------------------------------------------------------*/ SSL * sslP; /* SSL connection handle (such as is created by SSL_new() in the openssl library). */ bool userSuppliedConn; /* The SSL connection belongs to the user; we did not create it. */ }; static bool connected(int const fd) { /*---------------------------------------------------------------------------- Return TRUE iff the socket on file descriptor 'fd' is in the connected state. If 'fd' does not identify a stream socket or we are unable to determine the state of the stream socket, the answer is "false". -----------------------------------------------------------------------------*/ bool connected; struct sockaddr sockaddr; socklen_t nameLen; int rc; nameLen = sizeof(sockaddr); rc = getpeername(fd, &sockaddr, &nameLen); if (rc == 0) connected = TRUE; else connected = FALSE; return connected; } void SocketOpensslInit(const char ** const errorP) { SSL_load_error_strings(); /* readable error messages, don't call this if memory is tight */ SSL_library_init(); /* initialize library */ /* actions_to_seed_PRNG(); */ *errorP = NULL; } void SocketOpenSslTerm(void) { ERR_free_string(); } /*============================================================================= TChannel =============================================================================*/ static ChannelDestroyImpl channelDestroy; static void channelDestroy(TChannel * const channelP) { struct channelOpenssl * const channelOpensslP = channelP->implP; if (!socketUnixP->userSuppliedConn) SSL_shutdown(channelOpensslP->sslP); free(channelOpensslP); } static ChannelWriteImpl channelWrite; static void channelWrite(TChannel * const channelP, const unsigned char * const buffer, uint32_t const len, bool * const failedP) { struct channelOpenssl * const channelOpensslP = channelP->implP; int bytesLeft; bool error; assert(sizeof(int) >= sizeof(len)); for (bytesLeft = len, error = FALSE; bytesLeft > 0 && !error; ) { int const maxSend = (int)(-1) >> 1; int rc; rc = SSL_write(channelOpensslP->ssl, &buffer[len-bytesLeft], MIN(maxSend, bytesLeft)); if (ChannelTraceIsActive) { if (rc <= 0) fprintf(stderr, "Abyss socket: SSL_write() failed. rc=%d (%s)", rc, SSL_get_error(rc)); else fprintf(stderr, "Abyss socket: sent %u bytes: '%.*s'\n", rc, rc, &buffer[len-bytesLeft]); } if (rc <= 0) /* 0 means connection closed; < 0 means severe error */ error = TRUE; else bytesLeft -= rc; } *failedP = error; } ChannelReadImpl channelRead; static void channelRead(TChannel * const channelP, unsigned char * const buffer, uint32_t const bufferSize, uint32_t * const bytesReceivedP, bool * const failedP) { struct channelOpenssl * const channelOpensslP = channelP->implP; int rc; rc = SSL_read(channelOpensslP->sslP, buf, len); if (rc < 0) { *failedP = TRUE; if (ChannelTraceIsActive) fprintf(stderr, "Failed to receive data from OpenSSL connection. " "SSL_read() failed with rc %d (%s)\n", rc, SSL_get_error(rc)); } else { *failedP = FALSE; *bytesReceivedP = rc; if (ChannelTraceIsActive) fprintf(stderr, "Abyss channel: read %u bytes: '%.*s'\n", *bytesReceivedP, (int)(*bytesReceivedP), buffer); } } static ChannelWaitImpl channelWait; static void channelWait(TChannel * const channelP, bool const waitForRead, bool const waitForWrite, uint32_t const timeoutMs, bool * const readyToReadP, bool * const readyToWriteP, bool * const failedP) { /*---------------------------------------------------------------------------- See socket_unix.c for an explanation of the purpose of this subroutine. We don't actually fulfill that purpose, though, because we don't know how yet. Instead, we return immediately and hope that if Caller subsequently does a read or write, it blocks until it can do its thing. -----------------------------------------------------------------------------*/ } static ChannelInterruptImpl channelInterrupt; static void channelInterrupt(TChannel * const channelP) { /*---------------------------------------------------------------------------- Interrupt any waiting that a thread might be doing in channelWait() now or in the future. -----------------------------------------------------------------------------*/ /* This is trivial, since channelWait() doesn't actually wait */ } static struct TChannelVtbl const channelVtbl = { &channelDestroy, &channelWrite, &channelRead, &channelWait, &channelInterrupt, &channelFormatPeerInfo, }; static void makeChannelInfo(struct abyss_openssl_chaninfo ** const channelInfoPP, SSL * const sslP, const char ** const errorP) { struct abyss_openssl_chaninfo * channelInfoP; MALLOCVAR(channelInfoP); if (channelInfoP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory"); else { *channelInfoPP = channelInfoP; *errorP = NULL; } } static void makeChannelFromSsl(SSL * const sslP, TChannel ** const channelPP, const char ** const errorP) { struct channelOpenssl * channelOpensslP; MALLOCVAR(channelOpensslP); if (channelOpensslP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for OpenSSL " "socket descriptor"); else { TChannel * channelP; channelOpensslP->sslP = sslP; channelOpensslP->userSuppliedSsl = TRUE; /* This should be ok as far as I can tell */ ChannelCreate(&channelVtbl, channelOpensslP, &channelP); if (channelP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for " "channel descriptor."); else { *channelPP = channelP; *errorP = NULL; } if (*errorP) free(channelOpensslP); } } void ChannelOpensslCreateSsl(SSL * const sslP, TChannel ** const channelPP, struct abyss_openssl_chaninfo ** const channelInfoPP, const char ** const errorP) { assert(sslP); makeChannelInfo(channelInfoPP, sslP, errorP); if (!*errorP) { makeChannelFromSsl(ssl, channelPP, errorP); if (*errorP) { free(*channelInfoPP); } } } /*============================================================================= TChanSwitch =============================================================================*/ struct opensslSwitch { /*---------------------------------------------------------------------------- The properties/state of a TChanSwitch uniqe to the OpenSSL variety. Note that OpenSSL deals only in connected sockets, so this switch doesn't really have anything to do with OpenSSL except that it creates OpenSSL TChannels. The switch is just a POSIX listening socket, and is almost identical to the Abyss Unix channel switch. -----------------------------------------------------------------------------*/ int fd; /* File descriptor of the POSIX socket (such as is created by socket() in the C library) for the socket. */ bool userSuppliedFd; /* The file descriptor and associated POSIX socket belong to the user; we did not create it. */ }; static SwitchDestroyImpl chanSwitchDestroy; static void chanSwitchDestroy(TChanSwitch * const chanSwitchP) { static void chanSwitchDestroy(TChanSwitch * const chanSwitchP) { struct opensslSwitch * const opensslSwitchP = chanSwitchP->implP; if (!opensslSwitchP->userSuppliedFd) close(opensslSwitchP->fd); free(opensslSwitchP); } static SwitchListenImpl chanSwitchListen; static void chanSwitchListen(TChanSwitch * const chanSwitchP, uint32_t const backlog, const char ** const errorP) { struct opensslSwitch * const opensslSwitchP = chanSwitchP->implP; int32_t const minus1 = -1; int rc; /* Disable the Nagle algorithm to make persistant connections faster */ setsockopt(opensslSwitchP->fd, IPPROTO_TCP, TCP_NODELAY, &minus1, sizeof(minus1)); rc = listen(opensslSwitchP->fd, backlog); if (rc == -1) xmlrpc_asprintf(errorP, "listen() failed with errno %d (%s)", errno, strerror(errno)); else *errorP = NULL; } static SwitchAcceptImpl chanSwitchAccept; static void chanSwitchAccept(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Accept a connection via the channel switch *chanSwitchP. Return as *channelPP the channel for the accepted connection. If no connection is waiting at *chanSwitchP, wait until one is. If we receive a signal while waiting, return immediately with *channelPP == NULL. -----------------------------------------------------------------------------*/ struct opensslSwitch * const listenSocketP = chanSwitchP->implP; bool interrupted; TChannel * channelP; interrupted = FALSE; /* Haven't been interrupted yet */ channelP = NULL; /* No connection yet */ *errorP = NULL; /* No error yet */ while (!channelP && !*errorP && !interrupted) { struct sockaddr peerAddr; socklen_t size = sizeof(peerAddr); int rc; rc = accept(listenSocketP->fd, &peerAddr, &size); if (rc >= 0) { int const acceptedFd = rc; struct channelOpenssl * opensslChannelP; MALLOCVAR(opensslChannelP); if (!opensslChannelP) xmlrpc_asprintf(errorP, "Unable to allocate memory"); else { struct abyss_openssl_chaninfo * channelInfoP; openChannelP->userSuppliedFd = FALSE; TODO("turn connected socket 'acceptedFd' into an OpenSSL " "connection opensslChannelP->sslP"); makeChannelInfo(&channelInfoP, peerAddr, size, errorP); if (!*errorP) { *channelInfoPP = channelInfoP; ChannelCreate(&channelVtbl, opensslChannelP, &channelP); if (!channelP) xmlrpc_asprintf(errorP, "Failed to create TChannel object."); else *errorP = NULL; if (*errorP) free(channelInfoP); } if (*errorP) free(opensslChannelP); } if (*errorP) close(acceptedFd); } else if (errno == EINTR) interrupted = TRUE; else xmlrpc_asprintf(errorP, "accept() failed, errno = %d (%s)", errno, strerror(errno)); } *channelPP = channelP; } static SwitchInterruptImpl chanSwitchInterrupt; static void chanSwitchInterrupt(TChanSwitch * const chanSwitchP) { /*---------------------------------------------------------------------------- Interrupt any waiting that a thread might be doing in chanSwitchAccept() now or in the future. Actually, this is a no-op, since we don't yet know how to accomplish that. -----------------------------------------------------------------------------*/ } static struct TChanSwitchVtbl const chanSwitchVtbl = { &chanSwitchDestroy, &chanSwitchListen, &chanSwitchAccept, }; static void setSocketOptions(int const fd, const char ** const errorP) { int32_t n = 1; int rc; rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof(n)); if (rc < 0) xmlrpc_asprintf(errorP, "Failed to set socket options. " "setsockopt() failed with errno %d (%s)", errno, strerror(errno)); else *errorP = NULL; } static void bindSocketToPort(int const fd, struct in_addr * const addrP, uint16_t const portNumber, const char ** const errorP) { struct sockaddr_in name; int rc; name.sin_family = AF_INET; name.sin_port = htons(portNumber); if (addrP) name.sin_addr = *addrP; else name.sin_addr.s_addr = INADDR_ANY; rc = bind(fd, (struct sockaddr *)&name, sizeof(name)); if (rc == -1) xmlrpc_asprintf(errorP, "Unable to bind socket to port number %hu. " "bind() failed with errno %d (%s)", portNumber, errno, strerror(errno)); else *errorP = NULL; } void ChanSwitchOpensslCreate(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Create an OpenSSL-based channel switch. Use an IP socket. Set the socket's local address so that a subsequent "listen" will listen on all IP addresses, port number 'portNumber'. -----------------------------------------------------------------------------*/ struct opensslSwitch * opensslSwitchP; MALLOCVAR(opensslSwitchP); if (!opensslSwitchP) xmlrpc_asprintf(errorP, "Unable to allocate memory for Openssl " "channel switch descriptor structure."); else { int rc; rc = socket(AF_INET, SOCK_STREAM, 0); if (rc < 0) xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)", errno, strerror(errno)); else { opensslSwitchP->fd = rc; opensslSwitchP->userSuppliedFd = FALSE; setSocketOptions(opensslSwitchP->fd, errorP); if (!*errorP) { bindSocketToPort(opensslSwitchP->fd, NULL, portNumber, errorP); if (!*errorP) ChanSwitchCreate(&chanSwitchVtbl, opensslSwitchP, chanSwitchPP); } if (*errorP) close(opensslSwitchP->fd); } if (*errorP) free(opensslSwitchP); } } void ChanSwitchOpensslCreateFd(int const fd, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Create an OpenSSL-based channel switch, based on a POSIX socket that is in listen state. -----------------------------------------------------------------------------*/ struct opensslSwitch * opensslSwitchP; if (connected(fd)) xmlrpc_asprintf(errorP, "Socket (file descriptor %d) is in connected " "state.", fd); else { MALLOCVAR(opensslSwitchP); if (opensslSwitchP == NULL) xmlrpc_asprintf(errorP, "unable to allocate memory for Openssl " "channel switch descriptor."); else { TChanSwitch * chanSwitchP; opensslSwitchP->fd = fd; opensslSwitchP->userSuppliedFd = TRUE; ChanSwitchCreate(&chanSwitchVtbl, opensslSwitchP, &chanSwitchP); if (chanSwitchP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for " "channel switch descriptor"); else { *chanSwitchPP = chanSwitchP; *errorP = NULL; } if (*errorP) free(opensslSwitchP); } } } xmlrpc-c-1.33.14/lib/abyss/src/socket_unix.c000066400000000000000000001047731236133176700206120ustar00rootroot00000000000000/*============================================================================= socket_unix.c =============================================================================== This is the implementation of TChanSwitch and TChannel (and obsolete TSocket) for a standard Unix (POSIX) stream socket -- what you create with a socket() C library call. =============================================================================*/ #include "xmlrpc_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_FILIO_H #include #endif #include "c_util.h" #include "int.h" #include "girstring.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "mallocvar.h" #include "trace.h" #include "chanswitch.h" #include "channel.h" #include "socket.h" #include "netinet/in.h" #include "xmlrpc-c/abyss.h" #include "socket_unix.h" typedef struct { int interruptorFd; int interrupteeFd; } interruptPipe; static void initInterruptPipe(interruptPipe * const pipeP, const char ** const errorP) { int pipeFd[2]; int rc; rc = pipe(pipeFd); if (rc != 0) xmlrpc_asprintf(errorP, "Unable to create a pipe to use to interrupt " "waits. pipe() failed with errno %d (%s)", errno, strerror(errno)); else { *errorP = NULL; pipeP->interruptorFd = pipeFd[1]; pipeP->interrupteeFd = pipeFd[0]; } } static void termInterruptPipe(interruptPipe const pipe) { close(pipe.interruptorFd); close(pipe.interrupteeFd); } struct socketUnix { /*---------------------------------------------------------------------------- The properties/state of a TChanSwitch or TChannel unique to the Unix variety. -----------------------------------------------------------------------------*/ int fd; /* File descriptor of the POSIX socket (such as is created by socket() in the C library) for the socket. */ bool userSuppliedFd; /* The file descriptor and associated POSIX socket belong to the user; we did not create it. */ interruptPipe interruptPipe; }; static bool connected(int const fd) { /*---------------------------------------------------------------------------- Return TRUE iff the socket on file descriptor 'fd' is in the connected state. If 'fd' does not identify a stream socket or we are unable to determine the state of the stream socket, the answer is "false". -----------------------------------------------------------------------------*/ bool connected; struct sockaddr sockaddr; socklen_t nameLen; int rc; nameLen = sizeof(sockaddr); rc = getpeername(fd, &sockaddr, &nameLen); if (rc == 0) connected = TRUE; else connected = FALSE; return connected; } void SocketUnixInit(const char ** const errorP) { *errorP = NULL; } void SocketUnixTerm(void) { } /*============================================================================= TChannel =============================================================================*/ static void channelDestroy(TChannel * const channelP) { struct socketUnix * const socketUnixP = channelP->implP; termInterruptPipe(socketUnixP->interruptPipe); if (!socketUnixP->userSuppliedFd) close(socketUnixP->fd); free(socketUnixP); } static ChannelWriteImpl channelWrite; static void channelWrite(TChannel * const channelP, const unsigned char * const buffer, uint32_t const len, bool * const failedP) { struct socketUnix * const socketUnixP = channelP->implP; size_t bytesLeft; bool error; assert(sizeof(size_t) >= sizeof(len)); for (bytesLeft = len, error = FALSE; bytesLeft > 0 && !error; ) { size_t const maxSend = (size_t)(-1) >> 1; ssize_t rc; rc = send(socketUnixP->fd, &buffer[len-bytesLeft], MIN(maxSend, bytesLeft), 0); if (ChannelTraceIsActive) { if (rc < 0) fprintf(stderr, "Abyss channel: send() failed. errno=%d (%s)", errno, strerror(errno)); else if (rc == 0) fprintf(stderr, "Abyss channel: send() failed. " "Socket closed.\n"); else { size_t const bytesTransferred = rc; fprintf(stderr, "Abyss channel: sent %u bytes: '%.*s'\n", (unsigned)bytesTransferred, (int)(MIN(bytesTransferred, 4096)), &buffer[len-bytesLeft]); } } if (rc <= 0) /* 0 means connection closed; < 0 means severe error */ error = TRUE; else bytesLeft -= rc; } *failedP = error; } static ChannelReadImpl channelRead; static void channelRead(TChannel * const channelP, unsigned char * const buffer, uint32_t const bufferSize, uint32_t * const bytesReceivedP, bool * const failedP) { struct socketUnix * const socketUnixP = channelP->implP; int rc; rc = recv(socketUnixP->fd, buffer, bufferSize, 0); if (rc < 0) { *failedP = TRUE; if (ChannelTraceIsActive) fprintf(stderr, "Abyss channel: " "Failed to receive data from socket. " "recv() failed with errno %d (%s)\n", errno, strerror(errno)); } else { *failedP = FALSE; *bytesReceivedP = rc; if (ChannelTraceIsActive) fprintf(stderr, "Abyss channel: read %u bytes: '%.*s'\n", *bytesReceivedP, (int)(*bytesReceivedP), buffer); } } static ChannelWaitImpl channelWait; static void channelWait(TChannel * const channelP, bool const waitForRead, bool const waitForWrite, uint32_t const timeoutMs, bool * const readyToReadP, bool * const readyToWriteP, bool * const failedP) { /*---------------------------------------------------------------------------- Wait for the channel to be immediately readable or writable. Readable means there is at least one byte of data to read or the partner has disconnected. Writable means the channel will take at least one byte of data to send or the partner has disconnected. 'waitForRead' and 'waitForWrite' determine which of these conditions for which to wait; if both are true, we wait for either one. We return before the requested condition holds if 'timeoutMs' milliseconds pass. timeoutMs == TIME_INFINITE means infinity. We return before the requested condition holds if the process receives (and catches) a signal, but only if it receives that signal a certain time after we start running. (That means this function isn't useful for most purposes). Return *readyToReadP == true if the reason for returning is that the channel is immediately readable. *readyToWriteP is analogous for writable. Both may be true. Return *failedP true iff we fail to wait for the requested condition because of some unusual problem. Being interrupted by a signal is not a failure. If one of these return value pointers is NULL, don't return that value. -----------------------------------------------------------------------------*/ struct socketUnix * const socketUnixP = channelP->implP; /* Design note: some old systems may not have poll(). We're assuming that we don't have to run on any such system. select() is more universal, but can't handle a file descriptor with a high number. pselect() and ppoll() would allow us to be properly interruptible by a signal -- we would add a signal mask to our arguments. But ppoll() is fairly rare. pselect() is more common, but in older Linux systems it doesn't actually work. */ bool readyToRead, readyToWrite, failed; struct pollfd pollfds[2]; int rc; pollfds[0].fd = socketUnixP->fd; pollfds[0].events = (waitForRead ? POLLIN : 0) | (waitForWrite ? POLLOUT : 0); pollfds[1].fd = socketUnixP->interruptPipe.interrupteeFd; pollfds[1].events = POLLIN; rc = poll(pollfds, ARRAY_SIZE(pollfds), timeoutMs == TIME_INFINITE ? -1 : (int)timeoutMs); if (rc < 0) { if (errno == EINTR) { failed = FALSE; readyToRead = FALSE; readyToWrite = FALSE; } else { failed = TRUE; readyToRead = FALSE; /* quiet compiler warning */ readyToWrite = FALSE; /* quiet compiler warning */ } } else { failed = FALSE; readyToRead = !!(pollfds[0].revents & POLLIN); readyToWrite = !!(pollfds[0].revents & POLLOUT); } if (failedP) *failedP = failed; if (readyToReadP) *readyToReadP = readyToRead; if (readyToWriteP) *readyToWriteP = readyToWrite; } static ChannelInterruptImpl channelInterrupt; static void channelInterrupt(TChannel * const channelP) { /*---------------------------------------------------------------------------- Interrupt any waiting that a thread might be doing in channelWait() now or in the future. TODO: Make a way to reset this so that future channelWait()s can once again wait. -----------------------------------------------------------------------------*/ struct socketUnix * const socketUnixP = channelP->implP; unsigned char const zero[1] = {0u}; write(socketUnixP->interruptPipe.interruptorFd, &zero, sizeof(zero)); } void ChannelUnixGetPeerName(TChannel * const channelP, struct sockaddr ** const sockaddrPP, size_t * const sockaddrLenP, const char ** const errorP) { struct socketUnix * const socketUnixP = channelP->implP; unsigned char * peerName; socklen_t nameSize; nameSize = sizeof(struct sockaddr) + 1; peerName = malloc(nameSize); if (peerName == NULL) xmlrpc_asprintf(errorP, "Unable to allocate space for peer name"); else { int rc; socklen_t nameLen; nameLen = nameSize; /* initial value */ rc = getpeername(socketUnixP->fd, (struct sockaddr *)peerName, &nameLen); if (rc < 0) xmlrpc_asprintf(errorP, "getpeername() failed. errno=%d (%s)", errno, strerror(errno)); else { if (nameLen > nameSize-1) xmlrpc_asprintf(errorP, "getpeername() says the socket name is " "larger than %u bytes, which means it is " "not in the expected format.", nameSize-1); else { *sockaddrPP = (struct sockaddr *)peerName; *sockaddrLenP = nameLen; *errorP = NULL; } } if (*errorP) free(peerName); } } static void formatPeerInfoInet(const struct sockaddr_in * const sockaddrInP, socklen_t const sockaddrLen, const char ** const peerStringP) { if (sockaddrLen < sizeof(*sockaddrInP)) xmlrpc_asprintf(peerStringP, "??? getpeername() returned " "the wrong size"); else { unsigned char * const ipaddr = (unsigned char *) &sockaddrInP->sin_addr.s_addr; xmlrpc_asprintf(peerStringP, "%u.%u.%u.%u:%hu", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3], ntohs(sockaddrInP->sin_port)); } } static void formatPeerInfoInet6(const struct sockaddr_in6 * const sockaddrIn6P, socklen_t const sockaddrLen, const char ** const peerStringP) { if (sockaddrLen < sizeof(*sockaddrIn6P)) xmlrpc_asprintf(peerStringP, "??? getpeername() returned " "the wrong size"); else { /* Gcc on Debian 6 gives a bewildering error message about aliasing if we try to dereference sockaddrIn6P in various ways, regardless of casts to void * or anything else. So we copy the data structure as raw memory contents and then access the copy. 12.02.05. */ struct sockaddr_in6 sockaddr; MEMSCPY(&sockaddr, sockaddrIn6P); { char buffer[256]; const char * rc; rc = inet_ntop(AF_INET6, &sockaddr.sin6_addr, buffer, sizeof(buffer)); /* Punt the supposedly impossible error */ if (rc == NULL) STRSCPY(buffer, "???"); xmlrpc_asprintf(peerStringP, "[%s]:%hu", buffer, sockaddr.sin6_port); } } } static ChannelFormatPeerInfoImpl channelFormatPeerInfo; static void channelFormatPeerInfo(TChannel * const channelP, const char ** const peerStringP) { struct socketUnix * const socketUnixP = channelP->implP; struct sockaddr sockaddr; socklen_t sockaddrLen; int rc; sockaddrLen = sizeof(sockaddr); rc = getpeername(socketUnixP->fd, &sockaddr, &sockaddrLen); if (rc < 0) xmlrpc_asprintf(peerStringP, "?? getpeername() failed. errno=%d (%s)", errno, strerror(errno)); else { switch (sockaddr.sa_family) { case AF_INET: formatPeerInfoInet((const struct sockaddr_in *) &sockaddr, sockaddrLen, peerStringP); break; case AF_INET6: formatPeerInfoInet6((const struct sockaddr_in6 *) &sockaddr, sockaddrLen, peerStringP); break; default: xmlrpc_asprintf(peerStringP, "??? AF=%u", sockaddr.sa_family); } } } static struct TChannelVtbl const channelVtbl = { &channelDestroy, &channelWrite, &channelRead, &channelWait, &channelInterrupt, &channelFormatPeerInfo, }; static void makeChannelInfo(struct abyss_unix_chaninfo ** const channelInfoPP, struct sockaddr const peerAddr, socklen_t const peerAddrLen, const char ** const errorP) { struct abyss_unix_chaninfo * channelInfoP; MALLOCVAR(channelInfoP); if (channelInfoP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory"); else { channelInfoP->peerAddrLen = peerAddrLen; channelInfoP->peerAddr = peerAddr; *errorP = NULL; } *channelInfoPP = channelInfoP; } static void makeChannelFromFd(int const fd, TChannel ** const channelPP, const char ** const errorP) { struct socketUnix * socketUnixP; MALLOCVAR(socketUnixP); if (socketUnixP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for Unix " "channel descriptor"); else { TChannel * channelP; socketUnixP->fd = fd; socketUnixP->userSuppliedFd = TRUE; initInterruptPipe(&socketUnixP->interruptPipe, errorP); if (!*errorP) { ChannelCreate(&channelVtbl, socketUnixP, &channelP); if (channelP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for " "channel descriptor."); else { *channelPP = channelP; *errorP = NULL; } if (*errorP) termInterruptPipe(socketUnixP->interruptPipe); } if (*errorP) free(socketUnixP); } } void ChannelUnixCreateFd(int const fd, TChannel ** const channelPP, struct abyss_unix_chaninfo ** const channelInfoPP, const char ** const errorP) { struct sockaddr peerAddr; socklen_t peerAddrLen; int rc; peerAddrLen = sizeof(peerAddr); rc = getpeername(fd, &peerAddr, &peerAddrLen); if (rc != 0) { if (errno == ENOTCONN) xmlrpc_asprintf(errorP, "Socket on file descriptor %d is not in " "connected state.", fd); else xmlrpc_asprintf(errorP, "getpeername() failed on fd %d. " "errno=%d (%s)", fd, errno, strerror(errno)); } else { makeChannelInfo(channelInfoPP, peerAddr, peerAddrLen, errorP); if (!*errorP) { makeChannelFromFd(fd, channelPP, errorP); if (*errorP) free(*channelInfoPP); } } } /*============================================================================= TChanSwitch =============================================================================*/ static SwitchDestroyImpl chanSwitchDestroy; static void chanSwitchDestroy(TChanSwitch * const chanSwitchP) { struct socketUnix * const socketUnixP = chanSwitchP->implP; termInterruptPipe(socketUnixP->interruptPipe); if (!socketUnixP->userSuppliedFd) close(socketUnixP->fd); free(socketUnixP); } static SwitchListenImpl chanSwitchListen; static void chanSwitchListen(TChanSwitch * const chanSwitchP, uint32_t const backlog, const char ** const errorP) { struct socketUnix * const socketUnixP = chanSwitchP->implP; int32_t const minus1 = -1; int rc; /* Disable the Nagle algorithm to make persistant connections faster */ setsockopt(socketUnixP->fd, IPPROTO_TCP, TCP_NODELAY, &minus1, sizeof(minus1)); rc = listen(socketUnixP->fd, backlog); if (rc == -1) xmlrpc_asprintf(errorP, "listen() failed with errno %d (%s)", errno, strerror(errno)); else *errorP = NULL; } static void waitForConnection(struct socketUnix * const listenSocketP, bool * const interruptedP, const char ** const errorP) { /*---------------------------------------------------------------------------- Wait for the listening socket to have a connection ready to accept. We return before the requested condition holds if the process receives (and catches) a signal, but only if it receives that signal a certain time after we start running. (That means this behavior isn't useful for most purposes). We furthermore return before the requested condition holds if someone sends a byte through the listening socket's interrupt pipe (or has sent one previously since the most recent time the pipe was drained). Return *interruptedP == true if we return before there is a connection ready to accept. -----------------------------------------------------------------------------*/ struct pollfd pollfds[2]; int rc; pollfds[0].fd = listenSocketP->fd; pollfds[0].events = POLLIN; pollfds[1].fd = listenSocketP->interruptPipe.interrupteeFd; pollfds[1].events = POLLIN; rc = poll(pollfds, ARRAY_SIZE(pollfds), -1); if (rc < 0) { if (errno == EINTR) { *errorP = NULL; *interruptedP = TRUE; } else { xmlrpc_asprintf(errorP, "poll() failed, errno = %d (%s)", errno, strerror(errno)); *interruptedP = FALSE; /* quiet compiler warning */ } } else if (pollfds[0].revents & POLLHUP) { xmlrpc_asprintf(errorP, "INTERNAL ERROR: listening socket " "is not listening"); } else if (pollfds[1].revents & POLLHUP) { xmlrpc_asprintf(errorP, "INTERNAL ERROR: interrupt socket hung up"); } else if (pollfds[0].revents & POLLERR) { xmlrpc_asprintf(errorP, "listening socket is in POLLERR status"); } else if (pollfds[1].revents & POLLHUP) { xmlrpc_asprintf(errorP, "interrupt socket is in POLLERR status"); } else { *errorP = NULL; *interruptedP = !(pollfds[0].revents & POLLIN); } } static void createChannelForAccept(int const acceptedFd, struct sockaddr const peerAddr, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Make a channel object (TChannel) out of a socket just created by accept() on a listening socket -- i.e. a socket for a client connection. 'acceptedFd' is the file descriptor of the socket. 'peerAddr' is the address of the client, from accept(). -----------------------------------------------------------------------------*/ struct abyss_unix_chaninfo * channelInfoP; makeChannelInfo(&channelInfoP, peerAddr, sizeof(peerAddr), errorP); if (!*errorP) { struct socketUnix * acceptedSocketP; MALLOCVAR(acceptedSocketP); if (!acceptedSocketP) xmlrpc_asprintf(errorP, "Unable to allocate memory"); else { acceptedSocketP->fd = acceptedFd; acceptedSocketP->userSuppliedFd = FALSE; initInterruptPipe(&acceptedSocketP->interruptPipe, errorP); if (!*errorP) { TChannel * channelP; ChannelCreate(&channelVtbl, acceptedSocketP, &channelP); if (!channelP) xmlrpc_asprintf(errorP, "Failed to create TChannel object."); else { *errorP = NULL; *channelPP = channelP; *channelInfoPP = channelInfoP; } if (*errorP) termInterruptPipe(acceptedSocketP->interruptPipe); } if (*errorP) free(acceptedSocketP); } if (*errorP) free(channelInfoP); } } static SwitchAcceptImpl chanSwitchAccept; static void chanSwitchAccept(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Accept a connection via the channel switch *chanSwitchP. Return as *channelPP the channel for the accepted connection. If no connection is waiting at *chanSwitchP, wait until one is. If we receive a signal while waiting, return immediately with *channelPP == NULL. -----------------------------------------------------------------------------*/ struct socketUnix * const listenSocketP = chanSwitchP->implP; bool interrupted; TChannel * channelP; interrupted = FALSE; /* Haven't been interrupted yet */ channelP = NULL; /* No connection yet */ *errorP = NULL; /* No error yet */ while (!channelP && !*errorP && !interrupted) { waitForConnection(listenSocketP, &interrupted, errorP); if (!*errorP && !interrupted) { struct sockaddr peerAddr; socklen_t size = sizeof(peerAddr); int rc; rc = accept(listenSocketP->fd, &peerAddr, &size); if (rc >= 0) { int const acceptedFd = rc; createChannelForAccept(acceptedFd, peerAddr, &channelP, channelInfoPP, errorP); if (*errorP) close(acceptedFd); } else if (errno == EINTR) interrupted = TRUE; else xmlrpc_asprintf(errorP, "accept() failed, errno = %d (%s)", errno, strerror(errno)); } } *channelPP = channelP; } static SwitchInterruptImpl chanSwitchInterrupt; static void chanSwitchInterrupt(TChanSwitch * const chanSwitchP) { /*---------------------------------------------------------------------------- Interrupt any waiting that a thread might be doing in chanSwitchAccept() now or in the future. TODO: Make a way to reset this so that future chanSwitchAccept()s can once again wait. -----------------------------------------------------------------------------*/ struct socketUnix * const listenSocketP = chanSwitchP->implP; unsigned char const zero[1] = {0u}; write(listenSocketP->interruptPipe.interruptorFd, &zero, sizeof(zero)); } static struct TChanSwitchVtbl const chanSwitchVtbl = { &chanSwitchDestroy, &chanSwitchListen, &chanSwitchAccept, &chanSwitchInterrupt, }; static void createChanSwitch(int const fd, bool const userSuppliedFd, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { struct socketUnix * socketUnixP; assert(!connected(fd)); if (SwitchTraceIsActive) fprintf(stderr, "Creating Unix listen-socket based channel switch\n"); MALLOCVAR(socketUnixP); if (socketUnixP == NULL) xmlrpc_asprintf(errorP, "unable to allocate memory for Unix " "channel switch descriptor."); else { TChanSwitch * chanSwitchP; socketUnixP->fd = fd; socketUnixP->userSuppliedFd = userSuppliedFd; initInterruptPipe(&socketUnixP->interruptPipe, errorP); if (!*errorP) { ChanSwitchCreate(&chanSwitchVtbl, socketUnixP, &chanSwitchP); if (*errorP) termInterruptPipe(socketUnixP->interruptPipe); if (chanSwitchP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for " "channel switch descriptor"); else { *chanSwitchPP = chanSwitchP; *errorP = NULL; } } if (*errorP) free(socketUnixP); } } static void setSocketOptions(int const fd, const char ** const errorP) { int32_t n = 1; int rc; rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof(n)); if (rc < 0) xmlrpc_asprintf(errorP, "Failed to set socket options. " "setsockopt() failed with errno %d (%s)", errno, strerror(errno)); else *errorP = NULL; } static void traceSocketBound(const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen) { if (sockAddrP->sa_family == AF_INET && sockAddrLen >= sizeof(struct sockaddr_in)) { const struct sockaddr_in * const sockAddrInP = (const struct sockaddr_in *)sockAddrP; unsigned char * const ipaddr = (unsigned char *) &sockAddrInP->sin_addr.s_addr; fprintf(stderr, "Bound socket for channel switch to " "AF_INET port %u.%u.%u.%u:%hu\n", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3], ntohs(sockAddrInP->sin_port)); } else { fprintf(stderr, "Bound socket for channel switch to address of " "family %d\n", sockAddrP->sa_family); } } static void bindSocketToPort(int const fd, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, const char ** const errorP) { int rc; rc = bind(fd, sockAddrP, sockAddrLen); if (rc == -1) xmlrpc_asprintf(errorP, "Unable to bind socket " "to the socket address. " "bind() failed with errno %d (%s)", errno, strerror(errno)); else { *errorP = NULL; if (SwitchTraceIsActive) traceSocketBound(sockAddrP, sockAddrLen); } } static void bindSocketToPortInet(int const fd, uint16_t const portNumber, const char ** const errorP) { struct sockaddr_in name; int rc; name.sin_family = AF_INET; name.sin_port = htons(portNumber); name.sin_addr.s_addr = INADDR_ANY; rc = bind(fd, (struct sockaddr *)&name, sizeof(name)); if (rc == -1) xmlrpc_asprintf(errorP, "Unable to bind IPv4 socket " "to port number %hu. " "bind() failed with errno %d (%s)", portNumber, errno, strerror(errno)); else *errorP = NULL; } static void bindSocketToPortInet6(int const fd, uint16_t const portNumber, const char ** const errorP) { struct sockaddr_in6 name; int rc; name.sin6_family = AF_INET6; name.sin6_port = htons(portNumber); name.sin6_addr = in6addr_any; rc = bind(fd, (struct sockaddr *)&name, sizeof(name)); if (rc == -1) xmlrpc_asprintf(errorP, "Unable to bind IPv6 socket " "to port number %hu. " "bind() failed with errno %d (%s)", portNumber, errno, strerror(errno)); else *errorP = NULL; } static void switchCreateIpV4Port(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Create a POSIX-socket-based channel switch for an IPv4 endpoint. Set the socket's local address so that a subsequent "listen" will listen on all interfaces, port number 'portNumber'. -----------------------------------------------------------------------------*/ int rc; rc = socket(PF_INET, SOCK_STREAM, 0); if (rc < 0) xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)", errno, strerror(errno)); else { int const socketFd = rc; setSocketOptions(socketFd, errorP); if (!*errorP) { bindSocketToPortInet(socketFd, portNumber, errorP); if (!*errorP) { bool const userSupplied = false; createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP); } } if (*errorP) close(socketFd); } } static void switchCreateIpV6Port(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Same as switchCreateIpV4Port(), except for IPv6. -----------------------------------------------------------------------------*/ int rc; rc = socket(PF_INET6, SOCK_STREAM, 0); if (rc < 0) xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)", errno, strerror(errno)); else { int const socketFd = rc; setSocketOptions(socketFd, errorP); if (!*errorP) { bindSocketToPortInet6(socketFd, portNumber, errorP); if (!*errorP) { bool const userSupplied = false; createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP); } } if (*errorP) close(socketFd); } } void ChanSwitchUnixCreate(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { switchCreateIpV4Port(portNumber, chanSwitchPP, errorP); } void ChanSwitchUnixCreate2(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { int rc; rc = socket(protocolFamily, SOCK_STREAM, 0); if (rc < 0) xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)", errno, strerror(errno)); else { int const socketFd = rc; if (SwitchTraceIsActive) fprintf(stderr, "Created socket for protocol family %d\n", protocolFamily); setSocketOptions(socketFd, errorP); if (!*errorP) { bindSocketToPort(socketFd, sockAddrP, sockAddrLen, errorP); if (!*errorP) { bool const userSupplied = false; createChanSwitch(socketFd, userSupplied, chanSwitchPP, errorP); } } if (*errorP) close(socketFd); } } void ChanSwitchUnixCreateIpV6Port(unsigned short const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { switchCreateIpV6Port(portNumber, chanSwitchPP, errorP); } void ChanSwitchUnixCreateFd(int const fd, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { if (connected(fd)) xmlrpc_asprintf(errorP, "Socket (file descriptor %d) is in connected " "state.", fd); else { bool const userSupplied = true; createChanSwitch(fd, userSupplied, chanSwitchPP, errorP); } } /*============================================================================= obsolete TSocket interface =============================================================================*/ void SocketUnixCreateFd(int const fd, TSocket ** const socketPP) { TSocket * socketP; const char * error; if (connected(fd)) { TChannel * channelP; struct abyss_unix_chaninfo * channelInfoP; ChannelUnixCreateFd(fd, &channelP, &channelInfoP, &error); if (!error) SocketCreateChannel(channelP, channelInfoP, &socketP); } else { TChanSwitch * chanSwitchP; ChanSwitchUnixCreateFd(fd, &chanSwitchP, &error); if (!error) SocketCreateChanSwitch(chanSwitchP, &socketP); } if (error) { *socketPP = NULL; xmlrpc_strfree(error); } else *socketPP = socketP; } xmlrpc-c-1.33.14/lib/abyss/src/socket_unix.h000066400000000000000000000003121236133176700205770ustar00rootroot00000000000000#ifndef SOCKET_UNIX_H_INCLUDED #define SOCKET_UNIX_H_INCLUDED #include #include void SocketUnixInit(const char ** const errorP); void SocketUnixTerm(void); #endif xmlrpc-c-1.33.14/lib/abyss/src/socket_win.c000066400000000000000000000764251236133176700204260ustar00rootroot00000000000000/*============================================================================= socket_win.c =============================================================================== This is the implementation of TChanSwitch and TChannel for a Winsock socket. =============================================================================*/ #include #include #include #include #include #include "xmlrpc_config.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "mallocvar.h" #include "trace.h" #include "chanswitch.h" #include "channel.h" #include "socket.h" #include "xmlrpc-c/abyss.h" #include "socket_win.h" #ifndef socklen_t typedef int socklen_t; #endif /* ============================================================= Provided nice error strings, NOT available in system errors. ============================================================= */ typedef struct tagSOCKERRS { int err; // WSAGetLastError() value char * desc; // description of error } SOCKERR; /* could/should perhaps be by the actual call, but for now, just one big list, with some repeats */ SOCKERR sSockErr[] = { { WSANOTINITIALISED, "WSANOTINITIALISED - " "WSAStartup must be called before using this function." }, { WSAENETDOWN, "WSAENETDOWN - " "The network subsystem has failed." }, { WSAEACCES, "WSAEACCES - " "Attempt to connect datagram socket to broadcast address failed " "because setsockopt option SO_BROADCAST is not enabled." }, { WSAEADDRINUSE, "WSAEADDRINUSE - " "A process on the computer is already bound to the same fully-qualified " "address and the socket has not been marked to allow address reuse with " "SO_REUSEADDR. For example, the IP address and port are bound in the " "af_inet case). (See the SO_REUSEADDR socket option under setsockopt.)" }, { WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL - " "The specified address is not a valid address for this computer." }, { WSAEFAULT, "WSAEFAULT - " "The name or namelen parameter is not a valid part of the user " "address space, the namelen parameter is too small, the name parameter " "contains an incorrect address format for the associated " "address family, or the first two bytes of the memory block " "specified by name does not match the address family associated with " "the socket descriptor s." }, { WSAEINPROGRESS, "WSAEINPROGRESS - " "A blocking Windows Sockets 1.1 call is in progress, or the " "service provider is still processing a callback function." }, { WSAEINVAL, "WSAEINVAL - " "The socket is already bound to an address." }, { WSAENOBUFS, "WSAENOBUFS - " "Not enough buffers available, too many connections." }, { WSAENOTSOCK, "WSAENOTSOCK - " "The descriptor is not a socket." }, // setsocketopt { WSAENETRESET, "WSAENETRESET - " "Connection has timed out when SO_KEEPALIVE is set." }, { WSAENOPROTOOPT, "WSAENOPROTOOPT - " "The option is unknown or the specified provider " "or socket is not capable of implementing it " "(see SO_GROUP_PRIORITY limitations)." }, { WSAENOTCONN, "WSAENOTCONN - " "Connection has been reset when SO_KEEPALIVE is set." }, // WSAStartup { WSASYSNOTREADY, "WSASYSNOTREADY - " "The underlying network subsystem is not ready for " "network communication." }, { WSAVERNOTSUPPORTED, "WSAVERNOTSUPPORTED - " "The version of Windows Sockets function requested is not provided " "by this particular Windows Sockets implementation." }, { WSAEINPROGRESS, "WSAEINPROGRESS - " "A blocking Windows Sockets 1.1 operation is in progress." }, { WSAEPROCLIM, "WSAEPROCLIM - " "Limit on the number of tasks allowed by the Windows Sockets " "implementation has been reached." }, { WSAEFAULT, "WSAEFAULT - " "The lpWSAData is not a valid pointer." }, // listen { WSANOTINITIALISED, "WSANOTINITIALISED - " "A successful WSAStartup call must occur before using this function." }, { WSAENETDOWN, "WSAENETDOWN - " "The network subsystem has failed." }, { WSAEADDRINUSE, "WSAEADDRINUSE - " "The socket's local address is already in use and the socket " "was not marked to allow address reuse with SO_REUSEADDR. " "This error usually occurs during execution of the bind function, " "but could be delayed until this function if the bind was to " "a partially wildcard address (involving ADDR_ANY) " "and if a specific address needs to be committed at the time " "of this function call." }, { WSAEINPROGRESS, "WSAEINPROGRESS - " "A blocking Windows Sockets 1.1 call is in progress, " "or the service provider is still processing a callback function." }, { WSAEINVAL, "WSAEINVAL - " "The socket has not been bound with bind." }, { WSAEISCONN, "WSAEISCONN - " "The socket is already connected." }, { WSAEMFILE, "WSAEMFILE - " "No more socket descriptors are available." }, { WSAENOBUFS, "WSAENOBUFS - " "No buffer space is available." }, { WSAENOTSOCK, "WSAENOTSOCK - " "The descriptor is not a socket." }, { WSAEOPNOTSUPP, "WSAEOPNOTSUPP - " "The referenced socket is not of a type that has a listen operation." }, // getpeername { WSANOTINITIALISED, "WSANOTINITIALISED - " "A successful WSAStartup call must occur before using this function." }, { WSAENETDOWN, "WSAENETDOWN - " "The network subsystem has failed." }, { WSAEFAULT, "WSAEFAULT - " "The name or the namelen parameter is not a valid part of the " "user address space, or the namelen parameter is too small." }, { WSAEINPROGRESS, "WSAEINPROGRESS - " "A blocking Windows Sockets 1.1 call is in progress, " "or the service provider is still processing a callback function." }, { WSAENOTCONN, "WSAENOTCONN - " "The socket is not connected." }, { WSAENOTSOCK, "WSAENOTSOCK - " "The descriptor is not a socket." }, // accept { WSANOTINITIALISED, "WSANOTINITIALISED - " "A successful WSAStartup call must occur before using this function." }, { WSAENETDOWN, "WSAENETDOWN - " "The network subsystem has failed." }, { WSAEFAULT, "WSAEFAULT - " "The addrlen parameter is too small or addr is not a valid part " "of the user address space." }, { WSAEINTR, "WSAEINTR - " "A blocking Windows Sockets 1.1 call was canceled through " "WSACancelBlockingCall." }, { WSAEINPROGRESS, "WSAEINPROGRESS - " "A blocking Windows Sockets 1.1 call is in progress, " "or the service provider is still processing a callback function." }, { WSAEINVAL, "WSAEINVAL - " "The listen function was not invoked prior to accept." }, { WSAEMFILE, "WSAEMFILE - " "The queue is nonempty upon entry to accept and " "there are no descriptors available." }, { WSAENOBUFS, "WSAENOBUFS - " "No buffer space is available." }, { WSAENOTSOCK, "WSAENOTSOCK - " "The descriptor is not a socket." }, { WSAEOPNOTSUPP, "WSAEOPNOTSUPP - " "The referenced socket is not a type that offers connection-oriented " "service." }, { WSAEWOULDBLOCK, "WSAEWOULDBLOCK - " "The socket is marked as nonblocking and no connections are present " "to be accepted." }, /* must be last entry */ { 0, 0 } }; static const char * getWSAError(int const wsaErrno) { SOCKERR * pseP; pseP = &sSockErr[0]; // initial value while (pseP->desc) { if (pseP->err == wsaErrno) return pseP->desc; ++pseP; } return "(no description available)"; } struct socketWin { /*---------------------------------------------------------------------------- The properties/state of a TSocket unique to a Unix TSocket. -----------------------------------------------------------------------------*/ SOCKET winsock; bool userSuppliedWinsock; /* 'socket' was supplied by the user; it belongs to him */ HANDLE interruptEvent; }; static bool connected(SOCKET const fd) { /*---------------------------------------------------------------------------- Return TRUE iff the socket on file descriptor 'fd' is in the connected state. If 'fd' does not identify a stream socket or we are unable to determine the state of the stream socket, the answer is "false". -----------------------------------------------------------------------------*/ bool connected; struct sockaddr sockaddr; socklen_t nameLen; int rc; nameLen = sizeof(sockaddr); rc = getpeername(fd, &sockaddr, &nameLen); if (rc == 0) connected = TRUE; else connected = FALSE; return connected; } void SocketWinInit(const char ** const errorP) { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 0); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "WSAStartup() faild with error %d (%s)", lastError, getWSAError(lastError)); } else *errorP = NULL; } void SocketWinTerm(void) { WSACleanup(); } /*============================================================================= TChannel =============================================================================*/ static ChannelDestroyImpl channelDestroy; static void channelDestroy(TChannel * const channelP) { struct socketWin * const socketWinP = channelP->implP; if (!socketWinP->userSuppliedWinsock) closesocket(socketWinP->winsock); CloseHandle(socketWinP->interruptEvent); free(socketWinP); } static ChannelWriteImpl channelWrite; static void channelWrite(TChannel * const channelP, const unsigned char * const buffer, uint32_t const len, bool * const failedP) { struct socketWin * const socketWinP = channelP->implP; size_t bytesLeft; bool error; assert(sizeof(size_t) >= sizeof(len)); for (bytesLeft = len, error = FALSE; bytesLeft > 0 && !error; ) { size_t const maxSend = (size_t)(-1) >> 1; int rc; rc = send(socketWinP->winsock, &buffer[len-bytesLeft], MIN(maxSend, bytesLeft), 0); if (rc <= 0) /* 0 means connection closed; < 0 means severe error */ error = TRUE; else bytesLeft -= rc; } *failedP = error; } static ChannelReadImpl channelRead; static void channelRead(TChannel * const channelP, unsigned char * const buffer, uint32_t const bufferSize, uint32_t * const bytesReceivedP, bool * const failedP) { struct socketWin * const socketWinP = channelP->implP; int rc; rc = recv(socketWinP->winsock, buffer, bufferSize, 0); if (rc < 0) { *failedP = TRUE; } else { *failedP = FALSE; *bytesReceivedP = rc; } } static ChannelWaitImpl channelWait; static void channelWait(TChannel * const channelP, bool const waitForRead, bool const waitForWrite, uint32_t const timems, bool * const readyToReadP, bool * const readyToWriteP, bool * const failedP) { struct socketWin * const socketWinP = channelP->implP; fd_set rfds, wfds; TIMEVAL tv; bool failed, readRdy, writeRdy, timedOut; FD_ZERO(&rfds); FD_ZERO(&wfds); if (waitForRead) FD_SET(socketWinP->winsock, &rfds); if (waitForWrite) FD_SET(socketWinP->winsock, &wfds); tv.tv_sec = timems / 1000; tv.tv_usec = timems % 1000; for (failed = FALSE, readRdy = FALSE, writeRdy = FALSE, timedOut = FALSE; !failed && !readRdy && !writeRdy && !timedOut; ) { int rc; rc = select(socketWinP->winsock + 1, &rfds, &wfds, NULL, (timems == TIME_INFINITE ? NULL : &tv)); switch(rc) { case 0: timedOut = TRUE; break; case -1: /* socket error */ if (WSAGetLastError() != WSAEINTR) failed = TRUE; break; default: if (FD_ISSET(socketWinP->winsock, &rfds)) readRdy = TRUE; if (FD_ISSET(socketWinP->winsock, &wfds)) writeRdy = TRUE; } } if (failedP) *failedP = failed; if (readyToReadP) *readyToReadP = readRdy; if (readyToWriteP) *readyToWriteP = writeRdy; } static ChannelInterruptImpl channelInterrupt; static void channelInterrupt(TChannel * const channelP) { /*---------------------------------------------------------------------------- Interrupt any waiting that a thread might be doing in channelWait() now or in the future. Actually, this is just a no-op because we don't yet know how to accomplish that. (But we could probably do it the same way chanSwitchInterrupt() works -- no one has needed it enough yet to do that work). -----------------------------------------------------------------------------*/ } void ChannelWinGetPeerName(TChannel * const channelP, struct sockaddr_in * const inAddrP, const char ** const errorP) { struct socketWin * const socketWinP = channelP->implP; socklen_t addrlen; int rc; struct sockaddr sockAddr; addrlen = sizeof(sockAddr); rc = getpeername(socketWinP->winsock, &sockAddr, &addrlen); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "getpeername() failed. WSA error = %d (%s)", lastError, getWSAError(lastError)); } else { if (addrlen != sizeof(sockAddr)) xmlrpc_asprintf(errorP, "getpeername() returned a socket address " "of the wrong size: %u. Expected %u", addrlen, sizeof(sockAddr)); else { if (sockAddr.sa_family != AF_INET) xmlrpc_asprintf(errorP, "Socket does not use the Inet (IP) address " "family. Instead it uses family %d", sockAddr.sa_family); else { *inAddrP = *(struct sockaddr_in *)&sockAddr; *errorP = NULL; } } } } static ChannelFormatPeerInfoImpl channelFormatPeerInfo; static void channelFormatPeerInfo(TChannel * const channelP, const char ** const peerStringP) { struct socketWin * const socketWinP = channelP->implP; struct sockaddr sockaddr; socklen_t sockaddrLen; int rc; sockaddrLen = sizeof(sockaddr); rc = getpeername(socketWinP->winsock, &sockaddr, &sockaddrLen); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(peerStringP, "?? getpeername() failed. " "WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else { switch (sockaddr.sa_family) { case AF_INET: { struct sockaddr_in * const sockaddrInP = (struct sockaddr_in *) &sockaddr; if (sockaddrLen < sizeof(*sockaddrInP)) xmlrpc_asprintf(peerStringP, "??? getpeername() returned " "the wrong size"); else { unsigned char * const ipaddr = (unsigned char *) &sockaddrInP->sin_addr.s_addr; xmlrpc_asprintf(peerStringP, "%u.%u.%u.%u:%hu", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3], sockaddrInP->sin_port); } } break; default: xmlrpc_asprintf(peerStringP, "??? AF=%u", sockaddr.sa_family); } } } static struct TChannelVtbl const channelVtbl = { &channelDestroy, &channelWrite, &channelRead, &channelWait, &channelInterrupt, &channelFormatPeerInfo, }; static void makeChannelFromWinsock(SOCKET const winsock, TChannel ** const channelPP, const char ** const errorP) { struct socketWin * socketWinP; MALLOCVAR(socketWinP); if (socketWinP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for Windows " "socket descriptor"); else { TChannel * channelP; socketWinP->winsock = winsock; socketWinP->userSuppliedWinsock = TRUE; socketWinP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ChannelCreate(&channelVtbl, socketWinP, &channelP); if (channelP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for " "channel descriptor."); else { *channelPP = channelP; *errorP = NULL; } if (*errorP) { CloseHandle(socketWinP->interruptEvent); free(socketWinP); } } } static void makeChannelInfo(struct abyss_win_chaninfo ** const channelInfoPP, struct sockaddr const peerAddr, socklen_t const peerAddrLen, const char ** const errorP) { struct abyss_win_chaninfo * channelInfoP; MALLOCVAR(channelInfoP); if (channelInfoP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory"); else { channelInfoP->peerAddrLen = peerAddrLen; channelInfoP->peerAddr = peerAddr; *channelInfoPP = channelInfoP; *errorP = NULL; } } void ChannelWinCreateWinsock(SOCKET const fd, TChannel ** const channelPP, struct abyss_win_chaninfo ** const channelInfoPP, const char ** const errorP) { struct sockaddr peerAddr; socklen_t peerAddrLen; int rc; peerAddrLen = sizeof(peerAddr); rc = getpeername(fd, &peerAddr, &peerAddrLen); if (rc != 0) { int const lastError = WSAGetLastError(); if (lastError == WSAENOTCONN) { /* NOTE: This specific string 'not in connected' is required by one of the rpctest suite items, in abyss.c (line 186), hence the separation of the error messages in this case ... */ xmlrpc_asprintf(errorP, "Socket on file descriptor %d " "is not in connected state. WSAERROR = %d (%s)", fd, lastError, getWSAError(lastError)); } else xmlrpc_asprintf(errorP, "getpeername() failed. WSAERROR = %d (%s)", lastError, getWSAError(lastError)); } else { makeChannelInfo(channelInfoPP, peerAddr, peerAddrLen, errorP); if (!*errorP) { makeChannelFromWinsock(fd, channelPP, errorP); if (*errorP) free(*channelInfoPP); } } } /*============================================================================= TChanSwitch =============================================================================*/ static SwitchDestroyImpl chanSwitchDestroy; void chanSwitchDestroy(TChanSwitch * const chanSwitchP) { struct socketWin * const socketWinP = chanSwitchP->implP; if (!socketWinP->userSuppliedWinsock) closesocket(socketWinP->winsock); CloseHandle(socketWinP->interruptEvent); free(socketWinP); } static SwitchListenImpl chanSwitchListen; static void chanSwitchListen(TChanSwitch * const chanSwitchP, uint32_t const backlog, const char ** const errorP) { struct socketWin * const socketWinP = chanSwitchP->implP; int32_t const minus1 = -1; int rc; /* Disable the Nagle algorithm to make persistant connections faster */ setsockopt(socketWinP->winsock, IPPROTO_TCP, TCP_NODELAY, (const char *)&minus1, sizeof(minus1)); rc = listen(socketWinP->winsock, backlog); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "setsockopt() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else *errorP = NULL; } static void createChannelForAccept(int const acceptedWinsock, struct sockaddr const peerAddr, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { struct abyss_win_chaninfo * channelInfoP; makeChannelInfo(&channelInfoP, peerAddr, sizeof(peerAddr), errorP); if (!*errorP) { struct socketWin * acceptedSocketP; MALLOCVAR(acceptedSocketP); if (!acceptedSocketP) xmlrpc_asprintf(errorP, "Unable to allocate memory"); else { TChannel * channelP; acceptedSocketP->winsock = acceptedWinsock; acceptedSocketP->userSuppliedWinsock = FALSE; acceptedSocketP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ChannelCreate(&channelVtbl, acceptedSocketP, &channelP); if (!channelP) xmlrpc_asprintf(errorP, "Failed to create TChannel object."); else { *errorP = NULL; *channelPP = channelP; *channelInfoPP = channelInfoP; } if (*errorP) { CloseHandle(acceptedSocketP->interruptEvent); free(acceptedSocketP); } } } } static SwitchAcceptImpl chanSwitchAccept; static void chanSwitchAccept(TChanSwitch * const chanSwitchP, TChannel ** const channelPP, void ** const channelInfoPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Accept a connection via the channel switch *chanSwitchP. Return as *channelPP the channel for the accepted connection. If no connection is waiting at *chanSwitchP, wait until one is. If we receive a signal while waiting, return immediately with *channelPP == NULL. -----------------------------------------------------------------------------*/ struct socketWin * const listenSocketP = chanSwitchP->implP; HANDLE acceptEvent = WSACreateEvent(); bool interrupted; TChannel * channelP; interrupted = FALSE; /* Haven't been interrupted yet */ channelP = NULL; /* No connection yet */ *errorP = NULL; /* No error yet */ WSAEventSelect(listenSocketP->winsock, acceptEvent, FD_ACCEPT | FD_CLOSE | FD_READ); while (!channelP && !*errorP && !interrupted) { HANDLE interrupts[2] = {acceptEvent, listenSocketP->interruptEvent}; int rc; struct sockaddr peerAddr; socklen_t size = sizeof(peerAddr); rc = WaitForMultipleObjects(2, interrupts, FALSE, INFINITE); if (WAIT_OBJECT_0 + 1 == rc) { interrupted = TRUE; continue; }; rc = accept(listenSocketP->winsock, &peerAddr, &size); if (rc >= 0) { int const acceptedWinsock = rc; createChannelForAccept(acceptedWinsock, peerAddr, &channelP, channelInfoPP, errorP); if (*errorP) closesocket(acceptedWinsock); } else { int const lastError = WSAGetLastError(); if (lastError == WSAEINTR) interrupted = TRUE; else xmlrpc_asprintf(errorP, "accept() failed, WSA error = %d (%s)", lastError, getWSAError(lastError)); } } *channelPP = channelP; CloseHandle(acceptEvent); } static SwitchInterruptImpl chanSwitchInterrupt; static void chanSwitchInterrupt(TChanSwitch * const chanSwitchP) { /*---------------------------------------------------------------------------- Interrupt any waiting that a thread might be doing in chanSwitchAccept() now or in the future. -----------------------------------------------------------------------------*/ struct socketWin * const listenSocketP = chanSwitchP->implP; SetEvent(listenSocketP->interruptEvent); } static struct TChanSwitchVtbl const chanSwitchVtbl = { &chanSwitchDestroy, &chanSwitchListen, &chanSwitchAccept, &chanSwitchInterrupt, }; static void setSocketOptions(SOCKET const fd, const char ** const errorP) { int32_t const n = 1; int rc; rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof(n)); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "Failed to set socket options. " "setsockopt() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else *errorP = NULL; } void bindSocketToPort(SOCKET const winsock, struct in_addr * const addrP, uint16_t const portNumber, const char ** const errorP) { struct sockaddr_in name; int rc; ZeroMemory(&name, sizeof(name)); name.sin_family = AF_INET; name.sin_port = htons(portNumber); if (addrP) name.sin_addr = *addrP; rc = bind(winsock, (struct sockaddr *)&name, sizeof(name)); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "Unable to bind socket to port number %u. " "bind() failed with WSAERROR %i (%s)", portNumber, lastError, getWSAError(lastError)); } else *errorP = NULL; } void ChanSwitchWinCreate(uint16_t const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { /*---------------------------------------------------------------------------- Create a Winsock-based channel switch. Set the socket's local address so that a subsequent "listen" will listen on all IP addresses, port number 'portNumber'. -----------------------------------------------------------------------------*/ struct socketWin * socketWinP; MALLOCVAR(socketWinP); if (!socketWinP) xmlrpc_asprintf(errorP, "Unable to allocate memory for Windows socket " "descriptor structure."); else { SOCKET winsock; winsock = socket(AF_INET, SOCK_STREAM, 0); if (winsock == 0 || winsock == INVALID_SOCKET) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "socket() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else { socketWinP->winsock = winsock; socketWinP->userSuppliedWinsock = FALSE; socketWinP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); setSocketOptions(socketWinP->winsock, errorP); if (!*errorP) { bindSocketToPort(socketWinP->winsock, NULL, portNumber, errorP); if (!*errorP) ChanSwitchCreate(&chanSwitchVtbl, socketWinP, chanSwitchPP); } if (*errorP) { CloseHandle(socketWinP->interruptEvent); closesocket(winsock); } } if (*errorP) free(socketWinP); } } void ChanSwitchWinCreateWinsock(SOCKET const winsock, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { struct socketWin * socketWinP; if (connected(winsock)) xmlrpc_asprintf(errorP, "Socket is in connected state."); else { MALLOCVAR(socketWinP); if (socketWinP == NULL) xmlrpc_asprintf(errorP, "unable to allocate memory for Windows " "socket descriptor."); else { TChanSwitch * chanSwitchP; socketWinP->winsock = winsock; socketWinP->userSuppliedWinsock = TRUE; socketWinP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ChanSwitchCreate(&chanSwitchVtbl, socketWinP, &chanSwitchP); if (chanSwitchP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for " "channel switch descriptor"); else { *chanSwitchPP = chanSwitchP; *errorP = NULL; } if (*errorP) { CloseHandle(socketWinP->interruptEvent); free(socketWinP); } } } } static void bindSocketToAddr(SOCKET const winsock, const struct sockaddr * const addrP, socklen_t const sockAddrLen, const char ** const errorP) { int rc; rc = bind(winsock, (struct sockaddr *)addrP, sockAddrLen); if (rc != 0) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "Unable to bind socket to the socket address. " "bind() failed with WSAERROR %i (%s)", lastError, getWSAError(lastError)); } else *errorP = NULL; } void ChanSwitchWinCreate2(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { struct socketWin * socketWinP; MALLOCVAR(socketWinP); if (!socketWinP) xmlrpc_asprintf(errorP, "Unable to allocate memory for Windows socket " "descriptor structure."); else { SOCKET winsock; winsock = socket(protocolFamily, SOCK_STREAM, 0); if (winsock == 0 || winsock == INVALID_SOCKET) { int const lastError = WSAGetLastError(); xmlrpc_asprintf(errorP, "socket() failed with WSAERROR %d (%s)", lastError, getWSAError(lastError)); } else { socketWinP->winsock = winsock; socketWinP->userSuppliedWinsock = FALSE; socketWinP->interruptEvent = CreateEvent(NULL, FALSE, FALSE, NULL); setSocketOptions(socketWinP->winsock, errorP); if (!*errorP) { bindSocketToAddr(socketWinP->winsock, sockAddrP, sockAddrLen, errorP); if (!*errorP) ChanSwitchCreate(&chanSwitchVtbl, socketWinP, chanSwitchPP); } if (*errorP) { CloseHandle(socketWinP->interruptEvent); closesocket(winsock); } } if (*errorP) free(socketWinP); } } xmlrpc-c-1.33.14/lib/abyss/src/socket_win.h000066400000000000000000000002201236133176700204070ustar00rootroot00000000000000#ifndef SOCKET_WIN_H_INCLUDED #define SOCKET_WIN_H_INCLUDED void SocketWinInit(const char ** const errorP); void SocketWinTerm(void); #endif xmlrpc-c-1.33.14/lib/abyss/src/thread.h000066400000000000000000000022301236133176700175140ustar00rootroot00000000000000#ifndef THREAD_H_INCLUDED #define THREAD_H_INCLUDED /********************************************************************* ** Thread *********************************************************************/ #include "bool.h" typedef struct abyss_thread TThread; void ThreadPoolInit(void); typedef void TThreadProc(void * const userHandleP); typedef void TThreadDoneFn(void * const userHandleP); void ThreadCreate(TThread ** const threadPP, void * const userHandle, TThreadProc * const func, TThreadDoneFn * const threadDone, bool const useSigchld, size_t const stackSize, const char ** const errorP); bool ThreadRun(TThread * const threadP); bool ThreadStop(TThread * const threadP); bool ThreadKill(TThread * const threadP); void ThreadWaitAndRelease(TThread * const threadP); void ThreadExit(TThread * const threadP, int const retValue); void ThreadRelease(TThread * const threadP); bool ThreadForks(void); void ThreadUpdateStatus(TThread * const threadP); #ifndef WIN32 void ThreadHandleSigchld(pid_t const pid); #endif #endif xmlrpc-c-1.33.14/lib/abyss/src/thread_fork.c000066400000000000000000000145721236133176700205440ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "xmlrpc_config.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/abyss.h" #include "mallocvar.h" #include "thread.h" static void blockSignalClass(int const signalClass, sigset_t * const oldBlockedSetP) { sigset_t newBlockedSet; sigemptyset(&newBlockedSet); sigaddset(&newBlockedSet, signalClass); sigprocmask(SIG_BLOCK, &newBlockedSet, oldBlockedSetP); } struct abyss_thread { struct abyss_thread * nextInPoolP; TThreadDoneFn * threadDone; void * userHandle; pid_t pid; bool useSigchld; /* This means that user is going to call ThreadHandleSigchld() when it gets a death of a child signal for this process. If false, he's going to leave us in the dark, so we'll have to poll to know if the process is dead or not. */ }; /* Because signals are global, we need this global variable in order for the signal handler to figure out to what thread the signal belongs. */ /* We use a singly linked list. Every time we access it, we have to run the whole chain. To make this scale up, we should replace it with a doubly linked list and some kind of index by PID. But large scale systems probably aren't using fork threads anyway. */ static struct { struct abyss_thread * firstP; } ThreadPool; void ThreadPoolInit(void) { ThreadPool.firstP = NULL; } static struct abyss_thread * findThread(pid_t const pid) { struct abyss_thread * p; for (p = ThreadPool.firstP; p && p->pid != pid; p = p->nextInPoolP); return p; } static void addToPool(struct abyss_thread * const threadP) { if (ThreadPool.firstP == NULL) ThreadPool.firstP = threadP; else { struct abyss_thread * p; for (p = ThreadPool.firstP; p->nextInPoolP; p = p->nextInPoolP); /* p points to the last thread in the list */ p->nextInPoolP = threadP; } } static void removeFromPool(struct abyss_thread * const threadP) { if (threadP == ThreadPool.firstP) ThreadPool.firstP = threadP->nextInPoolP; else { struct abyss_thread * p; for (p = ThreadPool.firstP; p && p->nextInPoolP != threadP; p = p->nextInPoolP); if (p) /* p points to thread right before the one we want to remove */ p->nextInPoolP = threadP->nextInPoolP; } } void ThreadHandleSigchld(pid_t const pid) { /*---------------------------------------------------------------------------- Handle a death of a child signal for process 'pid', which may be one of our threads. -----------------------------------------------------------------------------*/ struct abyss_thread * const threadP = findThread(pid); if (threadP) { if (threadP->threadDone) threadP->threadDone(threadP->userHandle); threadP->pid = 0; } /* Note that threadDone might free *threadP */ } void ThreadUpdateStatus(TThread * const threadP) { if (!threadP->useSigchld) { if (threadP->pid) { if (kill(threadP->pid, 0) != 0) { if (threadP->threadDone) threadP->threadDone(threadP->userHandle); threadP->pid = 0; } } } } void ThreadCreate(TThread ** const threadPP, void * const userHandle, TThreadProc * const func, TThreadDoneFn * const threadDone, bool const useSigchld, size_t const stackSize, const char ** const errorP) { TThread * threadP; MALLOCVAR(threadP); if (threadP == NULL) xmlrpc_asprintf(errorP, "Can't allocate memory for thread descriptor."); else { sigset_t oldBlockedSet; pid_t rc; threadP->nextInPoolP = NULL; threadP->threadDone = threadDone; threadP->userHandle = userHandle; threadP->useSigchld = useSigchld; threadP->pid = 0; /* We have to be sure we don't get the SIGCHLD for this child's death until the child is properly registered in the thread pool so that the handler will know who he is. */ blockSignalClass(SIGCHLD, &oldBlockedSet); rc = fork(); if (rc < 0) xmlrpc_asprintf(errorP, "fork() failed, errno=%d (%s)", errno, strerror(errno)); else if (rc == 0) { /* This is the child */ (*func)(userHandle); /* Note that thread cleanup (threadDone) is done by the _parent_, upon seeing our exit. */ exit(0); } else { /* This is the parent */ threadP->pid = rc; addToPool(threadP); sigprocmask(SIG_SETMASK, &oldBlockedSet, NULL); /* restore */ *errorP = NULL; *threadPP = threadP; } if (*errorP) { removeFromPool(threadP); free(threadP); } } } bool ThreadRun(TThread * const threadP ATTR_UNUSED) { return TRUE; } bool ThreadStop(TThread * const threadP ATTR_UNUSED) { return TRUE; } bool ThreadKill(TThread * const threadP ATTR_UNUSED) { return TRUE; } void ThreadWaitAndRelease(TThread * const threadP) { if (threadP->pid) { int exitStatus; waitpid(threadP->pid, &exitStatus, 0); threadP->threadDone(threadP->userHandle); threadP->pid = 0; } ThreadRelease(threadP); } void ThreadExit(TThread * const threadP ATTR_UNUSED, int const retValue) { /* Note that the OS will automatically send a SIGCHLD signal to the parent process after we exit. The handler for that signal will run threadDone in parent's context. Alternatively, if the parent is set up for signals, the parent will eventually poll for the existence of our PID and call threadDone when he sees we've gone. */ /* Note that thread cleanup (threadDone) is done by the _parent_, upon seeing our exit. */ exit(retValue); } void ThreadRelease(TThread * const threadP) { removeFromPool(threadP); free(threadP); } bool ThreadForks(void) { return TRUE; } xmlrpc-c-1.33.14/lib/abyss/src/thread_pthread.c000066400000000000000000000102101236133176700212130ustar00rootroot00000000000000#include #include #include #include #include "xmlrpc_config.h" #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "pthreadx.h" #include "xmlrpc-c/abyss.h" #include "thread.h" struct abyss_thread { pthread_t thread; void * userHandle; TThreadProc * func; TThreadDoneFn * threadDone; }; /* We used to have MIN_STACK_SIZE = 16K, which was said to be the minimum stack size on Win32. Scott Kolodzeski found in November 2005 that this was insufficient for 64 bit Solaris -- we fail when creating the first thread. So we changed to 128K. */ #define MIN_STACK_SIZE (128*1024L) typedef void * (pthreadStartRoutine)(void *); static pthreadStartRoutine execute; static void * execute(void * const arg) { /* We make sure the user's "thread done" function runs as the thread exits, whether it exits by directly calling ThreadExit() or by returning to caller. In the direct exit case, the OS calls the "thread done" function by virtual of a cleanup that we set up. In the return to caller case, we get control back and our call to pthread_cleanup_pop() calls the "thread done" function. */ struct abyss_thread * const threadP = arg; bool const executeTrue = true; pthread_cleanup_push(threadP->threadDone, threadP->userHandle); threadP->func(threadP->userHandle); pthread_cleanup_pop(executeTrue); return NULL; } void ThreadCreate(TThread ** const threadPP, void * const userHandle, TThreadProc * const func, TThreadDoneFn * const threadDone, bool const useSigchld ATTR_UNUSED, size_t const stackSize, const char ** const errorP) { if ((size_t)(int)stackSize != stackSize) xmlrpc_asprintf(errorP, "Stack size %lu is too big", (unsigned long)stackSize); else { TThread * threadP; MALLOCVAR(threadP); if (threadP == NULL) xmlrpc_asprintf(errorP, "Can't allocate memory for thread descriptor."); else { pthread_attr_t attr; int rc; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, MAX(MIN_STACK_SIZE, stackSize)); threadP->userHandle = userHandle; threadP->func = func; threadP->threadDone = threadDone; rc = pthread_create(&threadP->thread, &attr, execute, threadP); if (rc == 0) { *errorP = NULL; *threadPP = threadP; } else xmlrpc_asprintf( errorP, "pthread_create() failed, errno = %d (%s)", errno, strerror(errno)); pthread_attr_destroy(&attr); if (*errorP) free(threadP); } } } bool ThreadRun(TThread * const threadP ATTR_UNUSED) { return TRUE; } bool ThreadStop(TThread * const threadP ATTR_UNUSED) { return TRUE; } bool ThreadKill(TThread * const threadP ATTR_UNUSED) { return (pthread_kill(threadP->thread, SIGTERM) == 0); } void ThreadWaitAndRelease(TThread * const threadP) { void * threadReturn; pthread_join(threadP->thread, &threadReturn); free(threadP); } void ThreadExit(TThread * const threadP ATTR_UNUSED, int const retValue) { pthread_exit((void*)&retValue); /* Note that the above runs our cleanup routine (which we registered with pthread_cleanup_push() before exiting. */ } void ThreadRelease(TThread * const threadP) { pthread_detach(threadP->thread); free(threadP); } bool ThreadForks(void) { return FALSE; } void ThreadUpdateStatus(TThread * const threadP ATTR_UNUSED) { /* Threads keep their own statuses up to date, so there's nothing to do here. */ } void ThreadHandleSigchld(pid_t const pid ATTR_UNUSED) { /* Death of a child signals have nothing to do with pthreads */ } xmlrpc-c-1.33.14/lib/abyss/src/thread_windows.c000066400000000000000000000063261236133176700212730ustar00rootroot00000000000000/* This code is just a first draft by someone who doesn't know anything about Windows. It has never been compiled. It is just a framework for someone who knows Windows to pick and finish. Bryan Henderson redesigned the threading structure for Abyss in April 2006 and wrote this file then. He use the former threading code, which did work on Windows, as a basis. */ #define WIN32_LEAN_AND_MEAN #include #include #include #include "xmlrpc_config.h" #include "bool.h" #include "int.h" #include "xmlrpc-c/util_int.h" #include "mallocvar.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/abyss.h" #include "trace.h" #include "thread.h" struct abyss_thread { HANDLE handle; void * userHandle; TThreadProc * func; TThreadDoneFn * threadDone; }; #define MIN_THREAD_STACK_SIZE (16*1024L) typedef uint32_t (WINAPI WinThreadProc)(void *); static WinThreadProc threadRun; static uint32_t WINAPI threadRun(void * const arg) { struct abyss_thread * const threadP = arg; threadP->func(threadP->userHandle); threadP->threadDone(threadP->userHandle); return 0; } void ThreadCreate(TThread ** const threadPP, void * const userHandle, TThreadProc * const func, TThreadDoneFn * const threadDone, bool const useSigchld, size_t const stackSize, const char ** const errorP) { TThread * threadP; MALLOCVAR(threadP); if (threadP == NULL) xmlrpc_asprintf(errorP, "Can't allocate memory for thread descriptor."); else { DWORD z; threadP->userHandle = userHandle; threadP->func = func; threadP->threadDone = threadDone; threadP->handle = (HANDLE) _beginthreadex(NULL, MAX(stackSize, MIN_THREAD_STACK_SIZE), threadRun, threadP, CREATE_SUSPENDED, &z); if (threadP->handle == NULL) xmlrpc_asprintf(errorP, "_beginthreadex() failed."); else { *errorP = NULL; *threadPP = threadP; } if (*errorP) free(threadP); } } bool ThreadRun(TThread * const threadP) { return (ResumeThread(threadP->handle) != 0xFFFFFFFF); } bool ThreadStop(TThread * const threadP) { return (SuspendThread(threadP->handle) != 0xFFFFFFFF); } bool ThreadKill(TThread * const threadP) { return (TerminateThread(threadP->handle, 0) != 0); } void ThreadWaitAndRelease(TThread * const threadP) { WaitForSingleObject(threadP->handle, INFINITE); ThreadRelease(threadP); } void ThreadExit(TThread * const threadP, int const retValue) { threadP->threadDone(threadP->userHandle); _endthreadex(retValue); } void ThreadRelease(TThread * const threadP) { CloseHandle(threadP->handle); free(threadP); } bool ThreadForks(void) { return FALSE; } void ThreadUpdateStatus(TThread * const threadP ATTR_UNUSED) { /* Threads keep their own statuses up to date, so there's nothing to do here. */ } xmlrpc-c-1.33.14/lib/abyss/src/token.c000066400000000000000000000016101236133176700173610ustar00rootroot00000000000000#include "xmlrpc-c/abyss.h" #include "bool.h" #include "token.h" void NextToken(const char ** const pP) { bool gotToken; gotToken = FALSE; while (!gotToken) { switch (**pP) { case '\t': case ' ': ++(*pP); break; default: gotToken = TRUE; }; } } char * GetToken(char ** const pP) { char * p0; p0 = *pP; while (1) { switch (**pP) { case '\t': case ' ': case CR: case LF: case '\0': if (p0 == *pP) return NULL; if (**pP) { **pP = '\0'; ++(*pP); }; return p0; default: ++(*pP); }; } } void GetTokenConst(char ** const pP, const char ** const tokenP) { *tokenP = GetToken(pP); } xmlrpc-c-1.33.14/lib/abyss/src/token.h000066400000000000000000000003521236133176700173700ustar00rootroot00000000000000#ifndef ABYSS_TOKEN_H_INCLUDED #define ABYSS_TOKEN_H_INCLUDED void NextToken(const char ** const pP); char * GetToken(char ** const pP); void GetTokenConst(char ** const pP, const char ** const tokenP); #endif xmlrpc-c-1.33.14/lib/abyss/src/trace.c000066400000000000000000000046131236133176700173450ustar00rootroot00000000000000/****************************************************************************** ** ** trace.c ** ** This file is part of the ABYSS Web server project. ** ** Copyright (C) 2000 by Moez Mahfoudh . ** 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ******************************************************************************/ #include #include #include #include "trace.h" /********************************************************************* ** Tracing functions *********************************************************************/ static void TraceVMsg(const char * const fmt, va_list argptr) { vprintf(fmt,argptr); printf("\n"); } void TraceMsg(const char * const fmt, ...) { va_list argptr; va_start(argptr,fmt); TraceVMsg(fmt,argptr); va_end(argptr); } void TraceExit(const char * const fmt, ...) { va_list argptr; va_start(argptr,fmt); TraceVMsg(fmt,argptr); va_end(argptr); exit(1); } xmlrpc-c-1.33.14/lib/abyss/src/trace.h000066400000000000000000000002261236133176700173460ustar00rootroot00000000000000#ifndef TRACE_H_INCLUDED #define TRACE_H_INCLUDED void TraceMsg(const char * const fmt, ...); void TraceExit(const char * const fmt, ...); #endif xmlrpc-c-1.33.14/lib/curl_transport/000077500000000000000000000000001236133176700172505ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/curl_transport/Makefile000066400000000000000000000036341236133176700207160ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') LIBDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/curl_transport include $(BLDDIR)/config.mk default: all MODS := xmlrpc_curl_transport curltransaction curlmulti .PHONY: all all: $(MODS:%=%.o) $(MODS:%=%.osh) # Rules for the above dependencies are in common.mk, # courtesy of TARGET_MODS. TARGET_MODS = $(MODS) OMIT_CURL_TRANSPORT_RULE=Y include $(SRCDIR)/common.mk # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir CURL_VERSION := $(shell curl-config --vernum) # Some time at or before Curl 7.12, became an empty file # (no-op). Some time after Curl 7.18, ceased to exist. # curl-config --vernum yields a string of 6 digits; the first two are the # major version in hexadecimal; the second two are the minor version number # and so on. So "071000" means 7.16.0. NEED_CURL_TYPES_H := $(shell if test $(CURL_VERSION) '<' 071000; then echo Y; fi) ifeq ($(NEED_CURL_TYPES_H),Y) CFLAGS_LOCAL += -DNEED_CURL_TYPES_H endif CURL_INCLUDES := $(shell curl-config --cflags) # We expect that curl-config --cflags just gives us -I options, because # we need just the -I options for 'make dep'. Plus, it's scary to think # of what any other compiler flag would do to our compile. INCLUDES = \ -I$(BLDDIR) \ -I$(BLDDIR)/include \ -Isrcdir/include \ -Isrcdir/lib/util/include \ $(CURL_INCLUDES) .PHONY: clean clean: clean-common .PHONY: distclean distclean: clean distclean-common .PHONY: tags tags: TAGS .PHONY: distdir distdir: .PHONY: install install: .PHONY: dep dep: dep-common include depend.mk # Need this dependency for those who don't use depend.mk. # Without it, version.h doesn't get created. xmlrpc_curl_transport.o xmlrpc_curl_transport.osh: version.h xmlrpc-c-1.33.14/lib/curl_transport/curlmulti.c000066400000000000000000000237701236133176700214450ustar00rootroot00000000000000/*============================================================================= curlMulti =============================================================================== This is an extension to Curl's CURLM object. The extensions are: 1) It has a lock so multiple threads can use it simultaneously. 2) Its "select" file descriptor vectors are self-contained. CURLM requires the user to maintain them separately. =============================================================================*/ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include "xmlrpc_config.h" #include #if HAVE_SYS_SELECT_H #include #endif #include #ifdef NEED_CURL_TYPES_H #include #endif #include #include #include "mallocvar.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_platform.h" #include "curlversion.h" #include "curlmulti.h" static void interpretCurlMultiError(const char ** const descriptionP, CURLMcode const code) { #if HAVE_CURL_STRERROR *descriptionP = strdup(curl_multi_strerror(code)); #else xmlrpc_asprintf(descriptionP, "Curl error code (CURLMcode) %d", code); #endif } struct curlMulti { CURLM * curlMultiP; lock * lockP; /* Hold this lock while accessing or using *curlMultiP. You're using the multi manager whenever you're calling a Curl library multi manager function. */ /* The following file descriptor sets are an integral part of the CURLM object; Our curlMulti_fdset() routine binds them to the CURLM object, and said object expects us to use them in a very specific way, including doing a select() on them. It is very, very messy. */ fd_set readFdSet; fd_set writeFdSet; fd_set exceptFdSet; }; curlMulti * curlMulti_create(void) { curlMulti * retval; curlMulti * curlMultiP; MALLOCVAR(curlMultiP); if (curlMultiP == NULL) retval = NULL; else { curlMultiP->lockP = xmlrpc_lock_create(); if (curlMultiP->lockP == NULL) retval = NULL; else { curlMultiP->curlMultiP = curl_multi_init(); if (curlMultiP->curlMultiP == NULL) retval = NULL; else retval = curlMultiP; if (retval == NULL) curlMultiP->lockP->destroy(curlMultiP->lockP); } if (retval == NULL) free(curlMultiP); } return retval; } void curlMulti_destroy(curlMulti * const curlMultiP) { curl_multi_cleanup(curlMultiP->curlMultiP); curlMultiP->lockP->destroy(curlMultiP->lockP); free(curlMultiP); } void curlMulti_perform(xmlrpc_env * const envP, curlMulti * const curlMultiP, bool * const immediateWorkToDoP, int * const runningHandleCtP) { /*---------------------------------------------------------------------------- Do whatever work is ready to be done under the control of multi manager 'curlMultiP'. E.g. if HTTP response data has recently arrived from the network, process it as an HTTP response. Iff this results in some work being finished from our point of view, return *immediateWorkToDoP true. (Caller can query the multi manager for messages and find out what it is). Return as *runningHandleCtP the number of Curl easy handles under the multi manager's control that are still running -- yet to finish. -----------------------------------------------------------------------------*/ CURLMcode rc; curlMultiP->lockP->acquire(curlMultiP->lockP); rc = curl_multi_perform(curlMultiP->curlMultiP, runningHandleCtP); curlMultiP->lockP->release(curlMultiP->lockP); if (rc == CURLM_CALL_MULTI_PERFORM) { *immediateWorkToDoP = true; } else { *immediateWorkToDoP = false; if (rc != CURLM_OK) { const char * reason; interpretCurlMultiError(&reason, rc); xmlrpc_faultf(envP, "Impossible failure of curl_multi_perform(): " "%s", reason); xmlrpc_strfree(reason); } } } void curlMulti_addHandle(xmlrpc_env * const envP, curlMulti * const curlMultiP, CURL * const curlSessionP) { CURLMcode rc; curlMultiP->lockP->acquire(curlMultiP->lockP); rc = curl_multi_add_handle(curlMultiP->curlMultiP, curlSessionP); curlMultiP->lockP->release(curlMultiP->lockP); /* Old libcurl (e.g. 7.12) actually returns CURLM_CALL_MULTI_PERFORM (by design) when it succeeds. Current libcurl returns CURLM_OK. */ if (rc != CURLM_OK && rc != CURLM_CALL_MULTI_PERFORM) { const char * reason; interpretCurlMultiError(&reason, rc); xmlrpc_faultf(envP, "Could not add Curl session to the " "curl multi manager. curl_multi_add_handle() " "failed: %s", reason); xmlrpc_strfree(reason); } } void curlMulti_removeHandle(curlMulti * const curlMultiP, CURL * const curlSessionP) { curlMultiP->lockP->acquire(curlMultiP->lockP); curl_multi_remove_handle(curlMultiP->curlMultiP, curlSessionP); curlMultiP->lockP->release(curlMultiP->lockP); } void curlMulti_getMessage(curlMulti * const curlMultiP, bool * const endOfMessagesP, CURLMsg * const curlMsgP) { /*---------------------------------------------------------------------------- Get the next message from the queue of things the Curl multi manager wants to say to us. Return the message as *curlMsgP. Iff there are no messages in the queue, return *endOfMessagesP == true. -----------------------------------------------------------------------------*/ int remainingMsgCount; CURLMsg * privateCurlMsgP; /* Note that this is a pointer into the multi manager's memory, so we have to use it under lock. */ curlMultiP->lockP->acquire(curlMultiP->lockP); privateCurlMsgP = curl_multi_info_read(curlMultiP->curlMultiP, &remainingMsgCount); if (privateCurlMsgP == NULL) *endOfMessagesP = true; else { *endOfMessagesP = false; *curlMsgP = *privateCurlMsgP; } curlMultiP->lockP->release(curlMultiP->lockP); } void curlMulti_fdset(xmlrpc_env * const envP, curlMulti * const curlMultiP, fd_set * const readFdSetP, fd_set * const writeFdSetP, fd_set * const exceptFdSetP, int * const maxFdP) { /*---------------------------------------------------------------------------- Set the CURLM object's file descriptor sets to those in the curlMulti object, update those file descriptor sets with the current needs of the multi manager, and return the resulting values of the file descriptor sets. This is a bizarre operation, but is necessary because of the nonmodular way in which the Curl multi interface works with respect to waiting for work with select(). -----------------------------------------------------------------------------*/ CURLMcode rc; curlMultiP->lockP->acquire(curlMultiP->lockP); /* curl_multi_fdset() doesn't _set_ the fdsets. It adds to existing ones (so you can easily do a select() on other fds and Curl fds at the same time). So we have to clear first: */ FD_ZERO(&curlMultiP->readFdSet); FD_ZERO(&curlMultiP->writeFdSet); FD_ZERO(&curlMultiP->exceptFdSet); /* WARNING: curl_multi_fdset() doesn't just update the fdsets pointed to by its arguments. It makes the CURLM object remember those pointers and refer back to them later! In fact, curl_multi_perform expects its caller to have done a select() on those masks. No, really. The man page even admits it. Inspection of the Libcurl code in March 2007 indicates that this isn't actually true -- curl_multi_fdset() updates your fdset and doesn't remember the pointer at all. I.e. it's just what you would expect. The man pages still says it's as described above. My guess is that Libcurl was fixed at some time and the man page not updated. In any case, we have to work with old Libcurl if at all possible, so we still maintain these fdsets as if they belong to the CURLM object. */ rc = curl_multi_fdset(curlMultiP->curlMultiP, &curlMultiP->readFdSet, &curlMultiP->writeFdSet, &curlMultiP->exceptFdSet, maxFdP); *readFdSetP = curlMultiP->readFdSet; *writeFdSetP = curlMultiP->writeFdSet; *exceptFdSetP = curlMultiP->exceptFdSet; curlMultiP->lockP->release(curlMultiP->lockP); if (rc != CURLM_OK) { const char * reason; interpretCurlMultiError(&reason, rc); xmlrpc_faultf(envP, "Impossible failure of curl_multi_fdset(): %s", reason); xmlrpc_strfree(reason); } } void curlMulti_updateFdSet(curlMulti * const curlMultiP, fd_set const readFdSet, fd_set const writeFdSet, fd_set const exceptFdSet) { /*---------------------------------------------------------------------------- curl_multi_perform() expects the file descriptor sets, which were bound to the CURLM object via a prior curlMulti_fdset(), to contain the results of a recent select(). This subroutine provides you a way to supply those. -----------------------------------------------------------------------------*/ curlMultiP->readFdSet = readFdSet; curlMultiP->writeFdSet = writeFdSet; curlMultiP->exceptFdSet = exceptFdSet; } xmlrpc-c-1.33.14/lib/curl_transport/curlmulti.h000066400000000000000000000026411236133176700214440ustar00rootroot00000000000000#ifndef CURLMULTI_H_INCLUDED #define CURLMULTI_H_INCLUDED #include "bool.h" #include "xmlrpc-c/util.h" #include "curltransaction.h" typedef struct curlMulti curlMulti; curlMulti * curlMulti_create(void); void curlMulti_destroy(curlMulti * const curlMultiP); void curlMulti_perform(xmlrpc_env * const envP, curlMulti * const curlMultiP, bool * const immediateWorkToDoP, int * const runningHandlesP); void curlMulti_addHandle(xmlrpc_env * const envP, curlMulti * const curlMultiP, CURL * const curlSessionP); void curlMulti_removeHandle(curlMulti * const curlMultiP, CURL * const curlSessionP); void curlMulti_getMessage(curlMulti * const curlMultiP, bool * const endOfMessagesP, CURLMsg * const curlMsgP); void curlMulti_fdset(xmlrpc_env * const envP, curlMulti * const curlMultiP, fd_set * const readFdSetP, fd_set * const writeFdSetP, fd_set * const exceptFdSetP, int * const maxFdP); void curlMulti_updateFdSet(curlMulti * const curlMultiP, fd_set const readFdSet, fd_set const writeFdSet, fd_set const exceptFdSet); #endif xmlrpc-c-1.33.14/lib/curl_transport/curltransaction.c000066400000000000000000001065311236133176700226350ustar00rootroot00000000000000/*============================================================================= curlTransaction =============================================================================*/ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include "mallocvar.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/client_int.h" #include "version.h" #include #ifdef NEED_CURL_TYPES_H #include #endif #include #include "curlversion.h" #include "curltransaction.h" struct curlTransaction { /* This is all stuff that really ought to be in a Curl object, but the Curl library is a little too simple for that. So we build a layer on top of Curl, and define this "transaction," as an object subordinate to a Curl "session." A Curl session has zero or one transactions in progress. The Curl session "private data" is a pointer to the CurlTransaction object for the current transaction. */ CURL * curlSessionP; /* Handle for the Curl session that hosts this transaction. Note that only one transaction at a time can use a particular Curl session, so this had better not be a session that some other transaction is using simultaneously. */ curlt_finishFn * finish; curlt_progressFn * progress; void * userContextP; /* Meaningful to our client; opaque to us */ CURLcode result; /* Result of the transaction (succeeded, TCP connect failed, etc.). A properly executed HTTP transaction (request & response) counts as a successful transaction. When 'result' show success, curl_easy_get_info() tells you whether the transaction succeeded at the HTTP level. */ char curlError[CURL_ERROR_SIZE]; /* Error message from Curl */ struct curl_slist * headerList; /* The HTTP headers for the transaction */ const char * serverUrl; /* malloc'ed - belongs to this object */ xmlrpc_mem_block * postDataP; /* The data to send for the POST method */ xmlrpc_mem_block * responseDataP; /* This is normally where to put the body of the HTTP response. But do to a quirk of Curl, if the response is not valid HTTP, rather than this just being irrelevant, it is the place that Curl puts the server's non-HTTP response. That can be useful for error reporting. */ }; static void addHeader(xmlrpc_env * const envP, struct curl_slist ** const headerListP, const char * const headerText) { struct curl_slist * newHeaderList; newHeaderList = curl_slist_append(*headerListP, headerText); if (newHeaderList == NULL) xmlrpc_faultf(envP, "Could not add header '%s'. " "curl_slist_append() failed.", headerText); else *headerListP = newHeaderList; } static void addContentTypeHeader(xmlrpc_env * const envP, struct curl_slist ** const headerListP) { addHeader(envP, headerListP, "Content-Type: text/xml"); } static const char * xmlrpcUserAgentPart(bool const reportIt) { const char * retval; if (reportIt) { curl_version_info_data * const curlInfoP = curl_version_info(CURLVERSION_NOW); char curlVersion[32]; snprintf(curlVersion, sizeof(curlVersion), "%u.%u.%u", (curlInfoP->version_num >> 16) & 0xff, (curlInfoP->version_num >> 8) & 0xff, (curlInfoP->version_num >> 0) & 0xff ); xmlrpc_asprintf(&retval, "Xmlrpc-c/%s Curl/%s", XMLRPC_C_VERSION, curlVersion); } else xmlrpc_asprintf(&retval, "%s", ""); return retval; } static void addUserAgentHeader(xmlrpc_env * const envP, struct curl_slist ** const headerListP, bool const reportXmlrpc, const char * const userAgent) { /*---------------------------------------------------------------------------- Add a User-Agent HTTP header to the Curl header list *headerListP, if appropriate. 'reportXmlrpc' means we want to tell the client what XML-RPC agent is being used -- Xmlrpc-c and layers below. 'userAgent' is a string describing the layers above Xmlrpc-c. We assume it is in the proper format to be included in a User-Agent header. (We should probably fix that some day -- take ownership of that format). -----------------------------------------------------------------------------*/ if (reportXmlrpc || userAgent) { /* Add the header */ /* Note: Curl has a CURLOPT_USERAGENT option that does some of this work. We prefer to be totally in control, though, so we build the header explicitly. */ const char * const xmlrpcPart = xmlrpcUserAgentPart(reportXmlrpc); if (xmlrpc_strnomem(xmlrpcPart)) xmlrpc_faultf(envP, "Couldn't allocate memory for " "User-Agent header"); else { const char * const userPart = userAgent ? userAgent : ""; const char * const space = userAgent && reportXmlrpc ? " " : ""; const char * userAgentHeader; xmlrpc_asprintf(&userAgentHeader, "User-Agent: %s%s%s", userPart, space, xmlrpcPart); if (xmlrpc_strnomem(userAgentHeader)) xmlrpc_faultf(envP, "Couldn't allocate memory for " "User-Agent header"); else { addHeader(envP, headerListP, userAgentHeader); xmlrpc_strfree(userAgentHeader); } xmlrpc_strfree(xmlrpcPart); } } } static void addAuthorizationHeader(xmlrpc_env * const envP, struct curl_slist ** const headerListP, const char * const hdrValue) { const char * authorizationHeader; xmlrpc_asprintf(&authorizationHeader, "Authorization: %s", hdrValue); if (xmlrpc_strnomem(authorizationHeader)) xmlrpc_faultf(envP, "Couldn't allocate memory for " "Authorization header"); else { addHeader(envP, headerListP, authorizationHeader); xmlrpc_strfree(authorizationHeader); } } /* In HTTP 1.1, the client can send the header "Expect: 100-continue", which tells the server that the client isn't going to send the body until the server tells it to by sending a "continue" response (HTTP response code 100). The server is obligated to send that response. However, many servers are broken and don't send the Continue response. Early libcurl did not send the Expect: header, thus worked fine with such broken servers. But as of ca. 2007, libcurl sends the Expect:, and waits for the response, when the body is large. It gives up after 3 seconds and sends the body anyway. To accomodate the broken servers and for backward compatibility, we always force libcurl not to send the Expect and consequently not to wait for the response, using the hackish (but according to libcurl design) method of including an entry in our explicit header list that is an Expect: header with an empty argument. This causes libcurl not to send any Expect: header. This is since 1.19; we may find there are also servers and/or libcurl levels that can't work with that. We may find a case where the Expect/Continue protocol is desirable. If we do, we should add a transport option to request the function and let libcurl do its thing when the user requests it. The purpose of Expect/Continue is to save the client the trouble of generating and/or sending the body when the server is just going to reject the transaction based on the headers -- like maybe because the body is too big. */ static void addExpectHeader(xmlrpc_env * const envP, struct curl_slist ** const headerListP) { addHeader(envP, headerListP, "Expect:"); /* Don't send Expect header. See explanation above. */ } static void createCurlHeaderList(xmlrpc_env * const envP, const char * const authHdrValue, bool const dontAdvertise, const char * const userAgent, struct curl_slist ** const headerListP) { struct curl_slist * headerList; headerList = NULL; /* initial value - empty list */ addContentTypeHeader(envP, &headerList); if (!envP->fault_occurred) { addUserAgentHeader(envP, &headerList, !dontAdvertise, userAgent); if (!envP->fault_occurred) { if (authHdrValue) addAuthorizationHeader(envP, &headerList, authHdrValue); } if (!envP->fault_occurred) addExpectHeader(envP, &headerList); } if (envP->fault_occurred) curl_slist_free_all(headerList); *headerListP = headerList; } static size_t collect(void * const ptr, size_t const size, size_t const nmemb, void * const streamP) { /*---------------------------------------------------------------------------- This is a Curl write function. Curl calls this to deliver the HTTP response body to the Curl client. But as a design quirk, Curl also calls this when there is no HTTP body because the response from the server is not valid HTTP. In that case, Curl calls this to deliver the raw contents of the response. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * const responseXmlP = streamP; char * const buffer = ptr; size_t const length = nmemb * size; size_t retval; xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_mem_block_append(&env, responseXmlP, buffer, length); if (env.fault_occurred) retval = (size_t)-1; else /* Really? Shouldn't it be like fread() and return 'nmemb'? */ retval = length; return retval; } static int curlProgress(void * const contextP, double const dltotal, double const dlnow, double const ultotal, double const ulnow) { /*---------------------------------------------------------------------------- This is a Curl "progress function." It's something various Curl functions call every so often, including whenever something gets interrupted by the process receiving, and catching, a signal. There are two purposes of a Curl progress function: 1) lets us log the progress of a long-running transaction such as a big download, e.g. by displaying a progress bar somewhere. 2) allows us to tell the Curl function, via our return code, that calls it that we don't want to wait anymore for the operation to complete. In Curl versions before March 2007, we get called once per second and signals have no effect. In current Curl, we usually get called immediately after a signal gets caught while Curl is waiting to receive a response from the server. But Curl doesn't properly synchronize with signals, so it may miss one and then we don't get called until the next scheduled one-per-second call. All we do is pass the call through to the curlTransaction's progress function (the one that the creator of the curlTransaction registered). This function is not as important as it once was for interrupting purposes. This module used to use curl_easy_perform(), which can be interrupted only via this progress function. But because of the above-mentioned failure of Curl to properly synchronize signals (and Bryan's failure to get Curl developers to accept code to fix it), we now use the Curl "multi" facility instead and do our own pselect(). But this function still normally gets called by curl_multi_perform(), which the transport tries to call even when the user has requested interruption, because we don't trust our ability to abort a running Curl transaction. curl_multi_perform() reliably winds up a Curl transaction when this function tells it to. -----------------------------------------------------------------------------*/ curlTransaction * const curlTransactionP = contextP; bool abort; /* We require anyone setting us up as the Curl progress function to supply a progress function: */ assert(curlTransactionP); assert(curlTransactionP->progress); curlTransactionP->progress(curlTransactionP->userContextP, dltotal, dlnow, ultotal, ulnow, &abort); return abort; } static void setupAuth(xmlrpc_env * const envP ATTR_UNUSED, CURL * const curlSessionP, const xmlrpc_server_info * const serverInfoP, const char ** const authHdrValueP) { /*---------------------------------------------------------------------------- Set the options in the Curl session 'curlSessionP' to set up the HTTP authentication described by *serverInfoP. But we have an odd special function for backward compatibility, because this code dates to a time when libcurl did not have the ability to handle authentication, but we provided such function nonetheless by building our own Authorization: header. But we did this only for HTTP basic authentication. So the special function is this: if libcurl is too old to have authorization options and *serverInfoP allows basic authentication, return as *authHdrValueP an appropriate parameter for the Authorization: Basic: HTTP header. Otherwise, return *authHdrValueP == NULL. -----------------------------------------------------------------------------*/ CURLcode rc; /* We don't worry if libcurl is too old for specific kinds of authentication; they're defined only as _allowed_ authentication methods, for when client and server are capable of using it, and unlike with basic authentication, we have no historical commitment to consider an old libcurl as capable of doing these. Note that curl_easy_setopt(CURLOPT_HTTPAUTH) succeeds even if there are flags in it argument that weren't defined when it was written. */ if (serverInfoP->userNamePw) curl_easy_setopt(curlSessionP, CURLOPT_USERPWD, serverInfoP->userNamePw); rc = curl_easy_setopt( curlSessionP, CURLOPT_HTTPAUTH, (serverInfoP->allowedAuth.basic ? CURLAUTH_BASIC : 0) | (serverInfoP->allowedAuth.digest ? CURLAUTH_DIGEST : 0) | (serverInfoP->allowedAuth.gssnegotiate ? CURLAUTH_GSSNEGOTIATE : 0) | (serverInfoP->allowedAuth.ntlm ? CURLAUTH_NTLM : 0)); if (rc != CURLE_OK) { /* Curl is too old to do authentication, so we do it ourselves with an explicit header if we have to. */ if (serverInfoP->allowedAuth.basic) { *authHdrValueP = strdup(serverInfoP->basicAuthHdrValue); if (*authHdrValueP == NULL) xmlrpc_faultf(envP, "Unable to allocate memory for basic " "authentication header"); } else *authHdrValueP = NULL; } else *authHdrValueP = NULL; } static void setCurlTimeout(CURL * const curlSessionP ATTR_UNUSED, unsigned int const timeout ATTR_UNUSED) { #if HAVE_CURL_NOSIGNAL unsigned int const timeoutMs = (timeout + 999)/1000; curl_easy_setopt(curlSessionP, CURLOPT_NOSIGNAL, 1); assert((long)timeoutMs == (int)timeoutMs); /* Calling requirement */ curl_easy_setopt(curlSessionP, CURLOPT_TIMEOUT, (long)timeoutMs); #else abort(); #endif } static void assertConstantsMatch(void) { /*---------------------------------------------------------------------------- There are some constants that we define as part of the Xmlrpc-c interface that are identical to constants in the Curl interface to make curl option setting work. This function asserts such formally. -----------------------------------------------------------------------------*/ assert(XMLRPC_SSLVERSION_DEFAULT == CURL_SSLVERSION_DEFAULT); assert(XMLRPC_SSLVERSION_TLSv1 == CURL_SSLVERSION_TLSv1 ); assert(XMLRPC_SSLVERSION_SSLv2 == CURL_SSLVERSION_SSLv2 ); assert(XMLRPC_SSLVERSION_SSLv3 == CURL_SSLVERSION_SSLv3 ); assert(XMLRPC_HTTPAUTH_BASIC == CURLAUTH_BASIC ); assert(XMLRPC_HTTPAUTH_DIGEST == CURLAUTH_DIGEST ); assert(XMLRPC_HTTPAUTH_GSSNEGOTIATE == CURLAUTH_GSSNEGOTIATE); assert(XMLRPC_HTTPAUTH_NTLM == CURLAUTH_NTLM ); assert(XMLRPC_HTTPPROXY_HTTP == CURLPROXY_HTTP ); assert(XMLRPC_HTTPPROXY_SOCKS5 == CURLPROXY_SOCKS5 ); } /* About Curl and GSSAPI credential delegation: Up through Curl 7.21.6, libcurl always delegates GSSAPI credentials, which means it gives the client's secrets to the server so the server can operate on the client's behalf. In mid-2011, this was noticed to be a major security exposure, because the server is not necessarily trustworthy. One is supposed to delegate one's credentials only to a server one trusts. So in 7.21.7, Curl never delegates GSSAPI credentials. But that causes problems for clients that _do_ trust their server, which had always relied upon Curl's delegation. So starting in 7.22.0, Curl gives the user the choice. The default is no delegation, but the Curl user can set the CURLOPT_GSSAPI_DELEGATION flag to order delegation. Complicating matters is that some people made local variations of Curl during the transition phase, so the version number alone isn't determinative, so we rely on it only where we have to. So Xmlrpc-c gives the same choice to its own user, via its 'gssapi_delegation' Curl transport option. Current Xmlrpc-c can be linked with, and compiled with, any version of Curl, so it has to carefully consider all the possibilities. */ static bool curlAlwaysDelegatesGssapi(void) { /*---------------------------------------------------------------------------- The Curl library we're using always delegates GSSAPI credentials (we don't have a choice). This works with Curl as distributed by the Curl project, but there are other versions of Curl for which it doesn't -- those versions report older version numbers but in fact don't always delegate. Some never delegate, and some give the user the option. -----------------------------------------------------------------------------*/ curl_version_info_data * const curlInfoP = curl_version_info(CURLVERSION_NOW); return (curlInfoP->version_num <= 0x071506); /* 7.21.6 */ } static void requestGssapiDelegation(CURL * const curlSessionP ATTR_UNUSED, bool * const gotItP) { /*---------------------------------------------------------------------------- Set up the Curl session *curlSessionP to delegate its GSSAPI credentials to the server. Return *gotitP is true iff we succeed. We fail when the version of libcurl for which we are compiled or to which we are linked is not capable of such delegation. -----------------------------------------------------------------------------*/ #if HAVE_CURL_GSSAPI_DELEGATION int rc; rc = curl_easy_setopt(curlSessionP, CURLOPT_GSSAPI_DELEGATION, CURLGSSAPI_DELEGATION_FLAG); if (rc == CURLE_OK) *gotItP = true; else { /* The only way curl_easy_setopt() could have failed is that we are running with an old libcurl from before CURLOPT_GSSAPI_DELEGATION was invented. */ if (curlAlwaysDelegatesGssapi()) { /* No need to request delegation; we got it anyway */ *gotItP = true; } else *gotItP = false; } #else if (curlAlwaysDelegatesGssapi()) *gotItP = true; else { /* The library may be able to do credential delegation on request, but we have no way to request it; the Curl for which we are compiled is too old. */ *gotItP = false; } #endif } static void setupCurlSession(xmlrpc_env * const envP, curlTransaction * const transP, const xmlrpc_server_info * const serverInfoP, bool const dontAdvertise, const char * const userAgent, const struct curlSetup * const curlSetupP) { /*---------------------------------------------------------------------------- Set up the Curl session for the transaction *transP so that a subsequent curl_easy_perform() would perform said transaction. The data curl_easy_perform() would send for that transaction would be the contents of *callXmlP; the data curl_easy_perform() gets back would go into *responseXmlP. *serverInfoP tells what sort of authentication to set up. This is an embarassment, as the xmlrpc_server_info type is part of the Xmlrpc-c interface. Some day, we need to replace this with a type (probably identical) not tied to Xmlrpc-c. -----------------------------------------------------------------------------*/ CURL * const curlSessionP = transP->curlSessionP; assertConstantsMatch(); /* A Curl session is serial -- it processes zero or one transaction at a time. We use the "private" attribute of the Curl session to indicate which transaction it is presently processing. This is important when the transaction finishes, because libcurl will just tell us that something finished on a particular session, not that a particular transaction finished. */ /* It is our policy to do a libcurl call only where necessary, I.e. not to set what is the default anyhow. The reduction in calls may save some time, but mostly, it will save us encountering rare bugs or suffering from backward incompatibilities in future libcurl. I.e. we don't exercise any more of libcurl than we have to. */ curl_easy_setopt(curlSessionP, CURLOPT_PRIVATE, transP); curl_easy_setopt(curlSessionP, CURLOPT_POST, 1); curl_easy_setopt(curlSessionP, CURLOPT_URL, transP->serverUrl); XMLRPC_MEMBLOCK_APPEND(char, envP, transP->postDataP, "\0", 1); if (!envP->fault_occurred) { curl_easy_setopt(curlSessionP, CURLOPT_POSTFIELDS, XMLRPC_MEMBLOCK_CONTENTS(char, transP->postDataP)); curl_easy_setopt(curlSessionP, CURLOPT_WRITEFUNCTION, collect); curl_easy_setopt(curlSessionP, CURLOPT_FILE, transP->responseDataP); curl_easy_setopt(curlSessionP, CURLOPT_HEADER, 0); curl_easy_setopt(curlSessionP, CURLOPT_ERRORBUFFER, transP->curlError); if (transP->progress) { curl_easy_setopt(curlSessionP, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(curlSessionP, CURLOPT_PROGRESSFUNCTION, curlProgress); curl_easy_setopt(curlSessionP, CURLOPT_PROGRESSDATA, transP); } else curl_easy_setopt(curlSessionP, CURLOPT_NOPROGRESS, 1); curl_easy_setopt(curlSessionP, CURLOPT_SSL_VERIFYPEER, curlSetupP->sslVerifyPeer); curl_easy_setopt(curlSessionP, CURLOPT_SSL_VERIFYHOST, curlSetupP->sslVerifyHost ? 2 : 0); if (curlSetupP->networkInterface) curl_easy_setopt(curlSessionP, CURLOPT_INTERFACE, curlSetupP->networkInterface); if (curlSetupP->referer) curl_easy_setopt(curlSessionP, CURLOPT_REFERER, curlSetupP->referer); if (curlSetupP->sslCert) curl_easy_setopt(curlSessionP, CURLOPT_SSLCERT, curlSetupP->sslCert); if (curlSetupP->sslCertType) curl_easy_setopt(curlSessionP, CURLOPT_SSLCERTTYPE, curlSetupP->sslCertType); if (curlSetupP->sslCertPasswd) curl_easy_setopt(curlSessionP, CURLOPT_SSLCERTPASSWD, curlSetupP->sslCertPasswd); if (curlSetupP->sslKey) curl_easy_setopt(curlSessionP, CURLOPT_SSLKEY, curlSetupP->sslKey); if (curlSetupP->sslKeyType) curl_easy_setopt(curlSessionP, CURLOPT_SSLKEYTYPE, curlSetupP->sslKeyType); if (curlSetupP->sslKeyPasswd) curl_easy_setopt(curlSessionP, CURLOPT_SSLKEYPASSWD, curlSetupP->sslKeyPasswd); if (curlSetupP->sslEngine) curl_easy_setopt(curlSessionP, CURLOPT_SSLENGINE, curlSetupP->sslEngine); if (curlSetupP->sslEngineDefault) /* 3rd argument seems to be required by some Curl */ curl_easy_setopt(curlSessionP, CURLOPT_SSLENGINE_DEFAULT, 1l); if (curlSetupP->sslVersion != XMLRPC_SSLVERSION_DEFAULT) curl_easy_setopt(curlSessionP, CURLOPT_SSLVERSION, curlSetupP->sslVersion); if (curlSetupP->caInfo) curl_easy_setopt(curlSessionP, CURLOPT_CAINFO, curlSetupP->caInfo); if (curlSetupP->caPath) curl_easy_setopt(curlSessionP, CURLOPT_CAPATH, curlSetupP->caPath); if (curlSetupP->randomFile) curl_easy_setopt(curlSessionP, CURLOPT_RANDOM_FILE, curlSetupP->randomFile); if (curlSetupP->egdSocket) curl_easy_setopt(curlSessionP, CURLOPT_EGDSOCKET, curlSetupP->egdSocket); if (curlSetupP->sslCipherList) curl_easy_setopt(curlSessionP, CURLOPT_SSL_CIPHER_LIST, curlSetupP->sslCipherList); if (curlSetupP->proxy) curl_easy_setopt(curlSessionP, CURLOPT_PROXY, curlSetupP->proxy); if (curlSetupP->proxyAuth != CURLAUTH_BASIC) /* Note that the Xmlrpc-c default and the Curl default are different. Xmlrpc-c is none, while Curl is basic. One reason for this is that it makes our extensible parameter list scheme, wherein zero always means default, easier. */ curl_easy_setopt(curlSessionP, CURLOPT_PROXYAUTH, curlSetupP->proxyAuth); if (curlSetupP->proxyPort) curl_easy_setopt(curlSessionP, CURLOPT_PROXYPORT, curlSetupP->proxyPort); if (curlSetupP->proxyUserPwd) curl_easy_setopt(curlSessionP, CURLOPT_PROXYUSERPWD, curlSetupP->proxyUserPwd); if (curlSetupP->proxyType) curl_easy_setopt(curlSessionP, CURLOPT_PROXYTYPE, curlSetupP->proxyType); if (curlSetupP->verbose) curl_easy_setopt(curlSessionP, CURLOPT_VERBOSE, 1l); if (curlSetupP->timeout) setCurlTimeout(curlSessionP, curlSetupP->timeout); if (curlSetupP->gssapiDelegation) { bool gotIt; requestGssapiDelegation(curlSessionP, &gotIt); if (!gotIt) xmlrpc_faultf(envP, "Cannot honor 'gssapi_delegation' " "Curl transport option. " "This version of libcurl is not " "capable of delegating GSSAPI credentials"); } if (!envP->fault_occurred) { const char * authHdrValue; /* NULL means we don't have to construct an explicit Authorization: header. non-null means we have to construct one with this as its value. */ setupAuth(envP, curlSessionP, serverInfoP, &authHdrValue); if (!envP->fault_occurred) { struct curl_slist * headerList; createCurlHeaderList(envP, authHdrValue, dontAdvertise, userAgent, &headerList); if (!envP->fault_occurred) { curl_easy_setopt( curlSessionP, CURLOPT_HTTPHEADER, headerList); transP->headerList = headerList; } if (authHdrValue) xmlrpc_strfree(authHdrValue); } } } } void curlTransaction_create(xmlrpc_env * const envP, CURL * const curlSessionP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block * const responseXmlP, bool const dontAdvertise, const char * const userAgent, const struct curlSetup * const curlSetupStuffP, void * const userContextP, curlt_finishFn * const finish, curlt_progressFn * const progress, curlTransaction ** const curlTransactionPP) { curlTransaction * curlTransactionP; MALLOCVAR(curlTransactionP); if (curlTransactionP == NULL) xmlrpc_faultf(envP, "No memory to create Curl transaction."); else { curlTransactionP->finish = finish; curlTransactionP->curlSessionP = curlSessionP; curlTransactionP->userContextP = userContextP; curlTransactionP->progress = progress; curlTransactionP->serverUrl = strdup(serverP->serverUrl); if (curlTransactionP->serverUrl == NULL) xmlrpc_faultf(envP, "Out of memory to store server URL."); else { curlTransactionP->postDataP = callXmlP; curlTransactionP->responseDataP = responseXmlP; setupCurlSession(envP, curlTransactionP, serverP, dontAdvertise, userAgent, curlSetupStuffP); if (envP->fault_occurred) xmlrpc_strfree(curlTransactionP->serverUrl); } if (envP->fault_occurred) free(curlTransactionP); } *curlTransactionPP = curlTransactionP; } void curlTransaction_destroy(curlTransaction * const curlTransactionP) { curl_slist_free_all(curlTransactionP->headerList); xmlrpc_strfree(curlTransactionP->serverUrl); free(curlTransactionP); } static void interpretCurlEasyError(const char ** const descriptionP, CURLcode const code) { #if HAVE_CURL_STRERROR *descriptionP = strdup(curl_easy_strerror(code)); #else xmlrpc_asprintf(descriptionP, "Curl error code (CURLcode) %d", code); #endif } /* CURL quirks: We have seen Curl report that the transaction completed OK (CURLE_OK) when the server sent back garbage instead of an HTTP response (because it wasn't an HTTP server). In that case Curl reports zero in place of the response code. It's strange that Curl doesn't report that protocol violation at a higher level (perhaps with more detail), but apparently it does not, so we go by the HTTP_CODE value. Note that if the server closes the connection without responding at all, Curl calls the transaction failed with an "empty reply from server" error code. It appears to be the case that when the server sends non-HTTP garbage, Curl reports it as the HTTP response body. E.g. we had an inetd server respond with a "library not found" error message because the server connected Standard Error to the socket. The 'curl' program typed out the error message, naked, and exited with exit status zero. We exploit this discovery to give better error reporting to our user. We saw this with Curl 7.16.1. */ static const char * formatDataReceived(curlTransaction * const curlTransactionP) { const char * retval; if (XMLRPC_MEMBLOCK_SIZE(char, curlTransactionP->responseDataP) == 0) retval = xmlrpc_strdupsol(""); else { xmlrpc_asprintf( &retval, "Raw data from server: '%s'\n", XMLRPC_MEMBLOCK_CONTENTS(char, curlTransactionP->responseDataP)); } return retval; } void curlTransaction_getError(curlTransaction * const curlTransactionP, xmlrpc_env * const envP) { /*---------------------------------------------------------------------------- Determine whether the transaction *curlTransactionP was successful in HTTP terms. Assume the transaction did complete. Return as *envP an indication of whether the transaction failed and if so, how. -----------------------------------------------------------------------------*/ if (curlTransactionP->result != CURLE_OK) { /* We've seen Curl just return a null string for an explanation (e.g. when TCP connect() fails because IP address doesn't exist). */ const char * explanation; if (strlen(curlTransactionP->curlError) == 0) interpretCurlEasyError(&explanation, curlTransactionP->result); else xmlrpc_asprintf(&explanation, "%s", curlTransactionP->curlError); xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "libcurl failed to execute the " "HTTP POST transaction, explaining: %s", explanation); xmlrpc_strfree(explanation); } else { CURLcode res; long http_result; res = curl_easy_getinfo(curlTransactionP->curlSessionP, CURLINFO_HTTP_CODE, &http_result); if (res != CURLE_OK) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR, "Curl performed the HTTP POST request, but was " "unable to say what the HTTP result code was. " "curl_easy_getinfo(CURLINFO_HTTP_CODE) says: %s", curlTransactionP->curlError); else { if (http_result == 0) { /* See above for what this case means */ const char * const dataReceived = formatDataReceived(curlTransactionP); xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "Server is not an XML-RPC server. Its response to our " "call is not valid HTTP. Or it's valid HTTP with a " "response code of zero. %s", dataReceived); xmlrpc_strfree(dataReceived); } else if (http_result != 200) xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "HTTP response code is %ld, not 200", http_result); } } } void curlTransaction_finish(xmlrpc_env * const envP, curlTransaction * const curlTransactionP, CURLcode const result) { curlTransactionP->result = result; if (curlTransactionP->finish) curlTransactionP->finish(envP, curlTransactionP->userContextP); } CURL * curlTransaction_curlSession(curlTransaction * const curlTransactionP) { return curlTransactionP->curlSessionP; } xmlrpc-c-1.33.14/lib/curl_transport/curltransaction.h000066400000000000000000000111621236133176700226350ustar00rootroot00000000000000#ifndef CURLTRANSACTION_H_INCLUDED #define CURLTRANSACTION_H_INCLUDED #include "bool.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/client.h" #include typedef struct curlTransaction curlTransaction; typedef void curlt_finishFn(xmlrpc_env * const, void * const); typedef void curlt_progressFn( void * const, double const, double const, double const, double const, bool * const); struct curlSetup { /* This is all client transport properties that are implemented as simple Curl session properties (i.e. the transport basically just passes them through to Curl without looking at them). People occasionally want to replace all this with something where the Xmlrpc-c user simply does the curl_easy_setopt() call and this code need not know about all these options. Unfortunately, that's a significant modularity violation. Either the Xmlrpc-c user controls the Curl object or he doesn't. If he does, then he shouldn't use libxmlrpc_client -- he should just copy some of this code into his own program. If he doesn't, then he should never see the Curl library. Speaking of modularity: the only reason this is a separate struct is to make the code easier to manage. Ideally, the fact that these particular properties of the transport are implemented by simple Curl session setup would be known only at the lowest level code that does that setup. */ const char * networkInterface; /* This identifies the network interface on the local side to use for the session. It is an ASCIIZ string in the form that the Curl recognizes for setting its CURLOPT_INTERFACE option (also the --interface option of the Curl program). E.g. "9.1.72.189" or "giraffe-data.com" or "eth0". It isn't necessarily valid, but it does have a terminating NUL. NULL means we have no preference. */ const char * referer; bool sslVerifyPeer; /* In an SSL connection, we should authenticate the server's SSL certificate -- refuse to talk to him if it isn't authentic. This is equivalent to Curl's CURLOPT_SSL_VERIFY_PEER option. */ bool sslVerifyHost; /* In an SSL connection, we should verify that the server's certificate (independently of whether the certificate is authentic) indicates the host name that is in the URL we are using for the server. */ const char * sslCert; const char * sslCertType; const char * sslCertPasswd; const char * sslKey; const char * sslKeyType; const char * sslKeyPasswd; const char * sslEngine; bool sslEngineDefault; unsigned int sslVersion; const char * caInfo; const char * caPath; const char * randomFile; const char * egdSocket; const char * sslCipherList; const char * proxy; unsigned int proxyPort; unsigned int proxyAuth; /* e.g. CURLAUTH_BASIC, CURLAUTH_NTLM, ... */ const char * proxyUserPwd; unsigned int proxyType; /* see enum curl_proxytype: CURLPROXY_HTTP, CURLPROXY_SOCKS4, ... */ bool gssapiDelegation; /* allow GSSAPI credential delegation */ unsigned int timeout; /* 0 = no Curl timeout. This is in milliseconds. */ bool verbose; }; void curlTransaction_create(xmlrpc_env * const envP, CURL * const curlSessionP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block * const responseXmlP, bool const dontAdvertise, const char * const userAgent, const struct curlSetup * const curlSetupStuffP, void * const userContextP, curlt_finishFn * const finish, curlt_progressFn * const progress, curlTransaction ** const curlTransactionPP); void curlTransaction_destroy(curlTransaction * const curlTransactionP); void curlTransaction_finish(xmlrpc_env * const envP, curlTransaction * const curlTransactionP, CURLcode const result); void curlTransaction_getError(curlTransaction * const curlTransactionP, xmlrpc_env * const envP); CURL * curlTransaction_curlSession(curlTransaction * const curlTransactionP); #endif xmlrpc-c-1.33.14/lib/curl_transport/curlversion.h000066400000000000000000000010401236133176700217670ustar00rootroot00000000000000#ifndef CURLVERSION_H_INCLUDED #define CURLVERSION_H_INCLUDED #define CMAJOR LIBCURL_VERSION_MAJOR #define CMINOR LIBCURL_VERSION_MINOR #if CMAJOR > 7 || (CMAJOR == 7 && CMINOR >= 10) #define HAVE_CURL_NOSIGNAL 1 #else #define HAVE_CURL_NOSIGNAL 0 #endif #if CMAJOR > 7 || (CMAJOR == 7 && CMINOR >= 12) #define HAVE_CURL_STRERROR 1 #else #define HAVE_CURL_STRERROR 0 #endif #ifdef CURLGSSAPI_DELEGATION_FLAG #define HAVE_CURL_GSSAPI_DELEGATION 1 #else #define HAVE_CURL_GSSAPI_DELEGATION 0 #endif #undef CMAJOR #undef CMINOR #endif xmlrpc-c-1.33.14/lib/curl_transport/xmlrpc_curl_transport.c000066400000000000000000001561511236133176700240730ustar00rootroot00000000000000/*============================================================================= xmlrpc_curl_transport =============================================================================== Curl-based client transport for Xmlrpc-c By Bryan Henderson 04.12.10. Contributed to the public domain by its author. =============================================================================*/ /*---------------------------------------------------------------------------- Curl global variables: Curl maintains some minor information in process-global variables. One must call curl_global_init() to initialize them before calling any other Curl library function. This is not state information -- it is constants. They just aren't the kind of constants that the library loader knows how to set, so there has to be this explicit call to set them up. The matching function curl_global_cleanup() returns resources these use (to wit, the constants live in malloc'ed storage and curl_global_cleanup() frees the storage). So our setup_global_const transport operation calls curl_global_init() and our teardown_global_const calls curl_global_cleanup(). The Curl library is supposed to maintain a reference count for the global constants so that multiple modules using the library and independently calling curl_global_init() and curl_global_cleanup() are not a problem. But today, it just keeps a flag "I have been initialized" and the first call to curl_global_cleanup() destroys the constants for everybody. Therefore, the user of the Xmlrpc-c Curl client XML transport must make sure not to call teardownGlobalConstants until everything else in his program is done using the Curl library. Note that curl_global_init() is not threadsafe (with or without the reference count), therefore our setup_global_const is not, and must be called when no other thread in the process is running. Typically, one calls it right at the beginning of the program. There are actually two other classes of global variables in the Curl library, which we are ignoring: debug options and custom memory allocator function identities. Our code never changes these global variables from default. If something else in the user's program does, User is responsible for making sure it doesn't interfere with our use of the library. Note that when we say what the Curl library does, we're also talking about various other libraries Curl uses internally, and in fact much of what we're saying about global variables springs from such subordinate libraries as OpenSSL and Winsock. -----------------------------------------------------------------------------*/ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include "xmlrpc_config.h" #include #include #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif #include #include #include "bool.h" #include "girmath.h" #include "mallocvar.h" #include "linklist.h" #include "girstring.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/select_int.h" #include "xmlrpc-c/client_int.h" #include "xmlrpc-c/transport.h" #include "xmlrpc-c/time_int.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_platform.h" #include #ifdef NEED_CURL_TYPES_H #include #endif #include #include #include "curltransaction.h" #include "curlmulti.h" #include "curlversion.h" #if MSVCRT #if defined(_DEBUG) # include # define new DEBUG_NEW # define malloc(size) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__) # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #endif typedef struct rpc rpc; static void tracev(const char * const fmt, va_list args) { vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } static void trace(const char * const fmt, ...) { if (xmlrpc_trace_transport) { va_list args; va_start(args, fmt); tracev(fmt, args); va_end(args); } } static int timeDiffMillisec(xmlrpc_timespec const minuend, xmlrpc_timespec const subtractor) { unsigned int const million = 1000000; return (minuend.tv_sec - subtractor.tv_sec) * 1000 + (minuend.tv_nsec - subtractor.tv_nsec + million/2) / million; } static bool timeIsAfter(xmlrpc_timespec const comparator, xmlrpc_timespec const comparand) { if (comparator.tv_sec > comparand.tv_sec) return true; else if (comparator.tv_sec < comparand.tv_sec) return false; else { /* Seconds are equal */ if (comparator.tv_nsec > comparand.tv_nsec) return true; else return false; } } static void addMilliseconds(xmlrpc_timespec const addend, unsigned int const adder, xmlrpc_timespec * const sumP) { unsigned int const million = 1000000; unsigned int const billion = 1000000000; xmlrpc_timespec sum; sum.tv_sec = addend.tv_sec + adder / 1000; sum.tv_nsec = addend.tv_nsec + (adder % 1000) * million; if ((uint32_t)sum.tv_nsec >= billion) { sum.tv_sec += 1; sum.tv_nsec -= billion; } *sumP = sum; } struct xmlrpc_client_transport { CURL * syncCurlSessionP; /* Handle for a Curl library session object that we use for all synchronous RPCs. An async RPC has one of its own, and consequently does not share things such as persistent connections and cookies with any other RPC. */ lock * syncCurlSessionLockP; /* Hold this lock while accessing or using *syncCurlSessionP. You're using the session from the time you set any attributes in it or start a transaction with it until any transaction has finished and you've lost interest in any attributes of the session. */ curlMulti * syncCurlMultiP; /* The Curl multi manager that this transport uses to execute Curl transactions for RPCs requested via the synchronous interface. The fact that there is never more than one such transaction going at a time might make you wonder why a "multi" manager is needed. The reason is that it is the only interface in libcurl that gives us the flexibility to execute the transaction with proper interruptibility. The only Curl transaction ever attached to this multi manager is 'syncCurlSessionP'. This is constant (the handle, not the object). */ curlMulti * asyncCurlMultiP; /* The Curl multi manager that this transport uses to execute Curl transactions for RPCs requested via the asynchronous interface. Note that there may be multiple such Curl transactions simultaneously and one can't wait for a particular one to finish; the collection of asynchronous RPCs are an indivisible mass. This is constant (the handle, not the object). */ bool dontAdvertise; /* Don't identify to the server the XML-RPC engine we are using. If false, include a User-Agent HTTP header in all requests that identifies the Xmlrpc-c and Curl libraries. See also 'userAgent'. This is constant. */ const char * userAgent; /* Information to include in a User-Agent HTTP header, reflecting facilities outside of Xmlrpc-c. Null means none. The full User-Agent header value is this information (if 'userAgent' is non-null) followed by identification of Xmlrpc-c and Curl (if 'dontAdvertise' is false). If 'userAgent' is null and 'dontAdvertise' is true, we put no User-Agent header at all in the request. This is constant. */ struct curlSetup curlSetupStuff; /* This is constant */ int * interruptP; /* Pointer to a value that user sets to nonzero to indicate he wants the transport to give up on whatever it is doing and return ASAP. NULL means none -- transport never gives up. This is constant. */ }; struct rpc { struct xmlrpc_client_transport * transportP; /* The client XML transport that transports this RPC */ curlTransaction * curlTransactionP; /* The object which does the HTTP transaction, with no knowledge of XML-RPC or Xmlrpc-c. */ CURL * curlSessionP; /* The Curl session to use for the Curl transaction to perform the RPC. */ xmlrpc_mem_block * responseXmlP; /* Where the response XML for this RPC should go or has gone. */ xmlrpc_transport_asynch_complete complete; /* Routine to call to complete the RPC after it is complete HTTP-wise. NULL if none. */ xmlrpc_transport_progress progress; /* Routine to call periodically to report the progress of transporting the call and response. NULL if none. */ struct xmlrpc_call_info * callInfoP; /* User's identifier for this RPC */ }; static void lockSyncCurlSession(struct xmlrpc_client_transport * const transportP) { transportP->syncCurlSessionLockP->acquire( transportP->syncCurlSessionLockP); } static void unlockSyncCurlSession(struct xmlrpc_client_transport * const transportP) { transportP->syncCurlSessionLockP->release( transportP->syncCurlSessionLockP); } static void initWindowsStuff(xmlrpc_env * const envP ATTR_UNUSED) { #if MSVCRT /* This is CRITICAL so that cURL-Win32 works properly! */ /* So this commenter says, but I wonder why. libcurl should do the required WSAStartup() itself, and it looks to me like it does. -Bryan 06.01.01 */ WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD(1, 1); err = WSAStartup(wVersionRequested, &wsaData); if (err) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR, "Winsock startup failed. WSAStartup returned rc %d", err); else { if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { /* Tell the user that we couldn't find a useable */ /* winsock.dll. */ xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR, "Winsock reported that " "it does not implement the requested version 1.1."); } if (envP->fault_occurred) WSACleanup(); } #endif } static void termWindowsStuff(void) { #if MSVCRT WSACleanup(); #endif } static bool curlHasNosignal(void) { bool retval; #if HAVE_CURL_NOSIGNAL curl_version_info_data * const curlInfoP = curl_version_info(CURLVERSION_NOW); retval = (curlInfoP->version_num >= 0x070A00); /* 7.10.0 */ #else retval = false; #endif return retval; } static xmlrpc_timespec pselectTimeout(xmlrpc_timeoutType const timeoutType, xmlrpc_timespec const timeoutDt) { /*---------------------------------------------------------------------------- Return the value that should be used in the select() call to wait for there to be work for the Curl multi manager to do, given that the user wants to timeout according to 'timeoutType' and 'timeoutDt'. -----------------------------------------------------------------------------*/ unsigned int const million = 1000000; unsigned int selectTimeoutMillisec; xmlrpc_timespec retval; /* We assume there is work to do at least every 3 seconds, because the Curl multi manager often has retries and other scheduled work that doesn't involve file handles on which we can select(). */ switch (timeoutType) { case timeout_no: selectTimeoutMillisec = 3000; break; case timeout_yes: { xmlrpc_timespec nowTime; int timeLeft; xmlrpc_gettimeofday(&nowTime); timeLeft = timeDiffMillisec(timeoutDt, nowTime); selectTimeoutMillisec = MIN(3000, MAX(0, timeLeft)); } break; } retval.tv_sec = selectTimeoutMillisec / 1000; retval.tv_nsec = (uint32_t)((selectTimeoutMillisec % 1000) * million); return retval; } static void processCurlMessages(xmlrpc_env * const envP, curlMulti * const curlMultiP) { bool endOfMessages; endOfMessages = false; /* initial assumption */ while (!endOfMessages && !envP->fault_occurred) { CURLMsg curlMsg; curlMulti_getMessage(curlMultiP, &endOfMessages, &curlMsg); if (!endOfMessages) { if (curlMsg.msg == CURLMSG_DONE) { curlTransaction * curlTransactionP; curl_easy_getinfo(curlMsg.easy_handle, CURLINFO_PRIVATE, (void *)&curlTransactionP); curlTransaction_finish(envP, curlTransactionP, curlMsg.data.result); } } } } static void waitForWork(xmlrpc_env * const envP, curlMulti * const curlMultiP, xmlrpc_timeoutType const timeoutType, xmlrpc_timespec const deadline, sigset_t * const sigmaskP) { /*---------------------------------------------------------------------------- Wait for the Curl multi manager to have work to do, time to run out, or a signal to be received (and caught), whichever comes first. Update the Curl multi manager's file descriptor sets to indicate what work we found for it to do. Wait under signal mask *sigmaskP. The point of this is that Caller can make sure that arrival of a signal of a certain class interrupts our wait, even if the signal arrives shortly before we begin waiting. Caller blocks that signal class, then checks whether a signal of that class has already been received. If not, he calls us with *sigmaskP indicating that class NOT blocked. Thus, if a signal of that class arrived any time after Caller checked, we will return immediately and if it arrives while we're waiting, we will return then. Note that we can provide this service only because pselect() has the same atomic unblock/wait feature. If sigmaskP is NULL, wait under whatever the current signal mask is. -----------------------------------------------------------------------------*/ fd_set readFdSet; fd_set writeFdSet; fd_set exceptFdSet; int maxFd; trace("Waiting for work"); curlMulti_fdset(envP, curlMultiP, &readFdSet, &writeFdSet, &exceptFdSet, &maxFd); if (!envP->fault_occurred) { if (maxFd == -1) { /* There are no Curl file descriptors on which to wait. So either there's work to do right now or all transactions are already complete. */ } else { xmlrpc_timespec const pselectTimeoutArg = pselectTimeout(timeoutType, deadline); int rc; trace("No work available; waiting for a Curl file descriptor to " "be ready or %u.%03u sec", pselectTimeoutArg.tv_sec, pselectTimeoutArg.tv_nsec/1000000); rc = xmlrpc_pselect(maxFd+1, &readFdSet, &writeFdSet, &exceptFdSet, &pselectTimeoutArg, sigmaskP); if (rc < 0 && errno != EINTR) xmlrpc_faultf(envP, "Impossible failure of pselect() " "with errno %d (%s)", errno, strerror(errno)); else { /* Believe it or not, the Curl multi manager needs the results of our pselect(). So hand them over: */ curlMulti_updateFdSet(curlMultiP, readFdSet, writeFdSet, exceptFdSet); } } trace("Wait is over"); } } static void waitForWorkInt(xmlrpc_env * const envP, curlMulti * const curlMultiP, xmlrpc_timeoutType const timeoutType, xmlrpc_timespec const deadline, int * const interruptP) { /*---------------------------------------------------------------------------- Same as waitForWork(), except we guarantee to return if a signal handler sets or has set *interruptP, whereas waitForWork() can miss a signal that happens before or just after it starts. We mess with global state -- the signal mask -- so we might mess up a multithreaded program. Therefore, don't call this if waitForWork() will suffice. -----------------------------------------------------------------------------*/ sigset_t callerBlockSet; #ifdef _WIN32 waitForWork(envP, curlMultiP, timeoutType, deadline, &callerBlockSet); #else sigset_t allSignals; assert(interruptP != NULL); sigfillset(&allSignals); sigprocmask(SIG_BLOCK, &allSignals, &callerBlockSet); if (*interruptP == 0) waitForWork(envP, curlMultiP, timeoutType, deadline, &callerBlockSet); else trace("Not waiting because interrupt flag is set\n"); sigprocmask(SIG_SETMASK, &callerBlockSet, NULL); #endif } static void doCurlWork(xmlrpc_env * const envP, curlMulti * const curlMultiP, bool * const transStillRunningP) { /*---------------------------------------------------------------------------- Do whatever work is ready to be done by the Curl multi manager identified by 'curlMultiP'. This typically is transferring data on an HTTP connection because the server is ready. For each transaction for which the multi manager finishes all the required work, complete the transaction by calling its "finish" routine. Return *transStillRunningP false if this work completes all of the manager's transactions so that there is no reason to call us ever again. -----------------------------------------------------------------------------*/ bool immediateWorkToDo; int runningHandleCt; trace("Calling libcurl to perform all immediate work"); immediateWorkToDo = true; /* initial assumption */ while (immediateWorkToDo && !envP->fault_occurred) { curlMulti_perform(envP, curlMultiP, &immediateWorkToDo, &runningHandleCt); } /* We either did all the work that's ready to do or hit an error. */ if (!envP->fault_occurred) { trace("libcurl has performed all immediate work; %d tasks " "(file handles) still running", runningHandleCt); /* The work we did may have resulted in asynchronous messages (asynchronous to the thing they refer to, not to us, of course). In particular the message "Curl transaction has completed". So we process those now. */ processCurlMessages(envP, curlMultiP); *transStillRunningP = runningHandleCt > 0; } } static void finishCurlMulti(xmlrpc_env * const envP, curlMulti * const curlMultiP, xmlrpc_timeoutType const timeoutType, xmlrpc_timespec const deadline, int * const interruptP) { /*---------------------------------------------------------------------------- Prosecute all the Curl transactions under the control of *curlMultiP. E.g. send data if server is ready to take it, get data if server has sent some, wind up the transaction if it is done. Don't return until all the Curl transactions are done or we time out. if 'interruptP' is non-null, it points to a value which is normally zero, but is nonzero when Caller wants us to abort all the transactions and return ASAP. The *interruptP flag alone will not interrupt us. We will wait in spite of it for all Curl transactions to complete. *interruptP just gives us a hint that the Curl transactions are being interrupted, so we know there is work to do for them. (The way it works is Caller sets up a "progress" function that checks the same interrupt flag and reports "kill me." When we see the interrupt flag, we tell libcurl to do whatever work there is to do, and as part of that, libcurl calls the progress function, gets the "kill me" message, and passes that on to us). -----------------------------------------------------------------------------*/ /* For integrity, we make sure we don't let *interruptP interrupt our wait for work more than once. That way, if for any reason libcurl fails to call the progress function, or the progress function fails to notice the interrupt flag and tell libcurl to abort, or libcurl does abort as told, we don't have a busy loop of calls to doCurlWork(). 'curlCalledSinceInterrupt' is part of this logic. */ bool rpcStillRunning; bool timedOut; bool curlCalledSinceInterrupt; rpcStillRunning = true; /* initial assumption */ timedOut = false; curlCalledSinceInterrupt = false; while (rpcStillRunning && !timedOut && !envP->fault_occurred) { if (interruptP && !curlCalledSinceInterrupt) { waitForWorkInt(envP, curlMultiP, timeoutType, deadline, interruptP); } else waitForWork(envP, curlMultiP, timeoutType, deadline, NULL); if (!envP->fault_occurred) { xmlrpc_timespec nowTime; /* doCurlWork() (among other things) finds Curl transactions that user wants to abort and finishes them. (This is by virtue of libcurl calling its progress function when we tell it to do all available work). */ if (interruptP && *interruptP) curlCalledSinceInterrupt = true; doCurlWork(envP, curlMultiP, &rpcStillRunning); xmlrpc_gettimeofday(&nowTime); timedOut = (timeoutType == timeout_yes && timeIsAfter(nowTime, deadline)); } } } static void getTimeoutParm(xmlrpc_env * const envP, const struct xmlrpc_curl_xportparms * const curlXportParmsP, size_t const parmSize, unsigned int * const timeoutP) { if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(timeout)) *timeoutP = 0; else { if (curlHasNosignal()) { /* libcurl takes a 'long' in milliseconds for the timeout value */ if ((unsigned)(long)(curlXportParmsP->timeout) != curlXportParmsP->timeout) xmlrpc_faultf(envP, "Timeout value %u is too large.", curlXportParmsP->timeout); else *timeoutP = curlXportParmsP->timeout; } else xmlrpc_faultf(envP, "You cannot specify a 'timeout' parameter " "because the Curl library is too old and is not " "capable of doing timeouts except by using " "signals. You need at least Curl 7.10"); } } static void setVerbose(bool * const verboseP) { const char * const xmlrpcTraceCurl = getenv("XMLRPC_TRACE_CURL"); if (xmlrpcTraceCurl) *verboseP = true; else *verboseP = false; } static void getXportParms(xmlrpc_env * const envP, const struct xmlrpc_curl_xportparms * const curlXportParmsP, size_t const parmSize, struct xmlrpc_client_transport * const transportP) { /*---------------------------------------------------------------------------- Get the parameters out of *curlXportParmsP and update *transportP to reflect them. *curlXportParmsP is a 'parmSize' bytes long prefix of struct xmlrpc_curl_xportparms. curlXportParmsP is something the user created. It's designed to be friendly to the user, not to this program, and is encumbered by lots of backward compatibility constraints. In particular, the user may have coded and/or compiled it at a time that struct xmlrpc_curl_xportparms was smaller than it is now! Also, the user might have specified something invalid. So that's why we don't simply attach a copy of *curlXportParmsP to *transportP. To the extent that *curlXportParmsP is too small to contain a parameter, we return the default value for that parameter. Special case: curlXportParmsP == NULL means there is no input at all. In that case, we return default values for everything. -----------------------------------------------------------------------------*/ struct curlSetup * const curlSetupP = &transportP->curlSetupStuff; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(user_agent)) transportP->userAgent = NULL; else if (curlXportParmsP->user_agent == NULL) transportP->userAgent = NULL; else transportP->userAgent = strdup(curlXportParmsP->user_agent); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(dont_advertise)) transportP->dontAdvertise = false; else transportP->dontAdvertise = curlXportParmsP->dont_advertise; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(network_interface)) curlSetupP->networkInterface = NULL; else if (curlXportParmsP->network_interface == NULL) curlSetupP->networkInterface = NULL; else curlSetupP->networkInterface = strdup(curlXportParmsP->network_interface); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(no_ssl_verifypeer)) curlSetupP->sslVerifyPeer = true; else curlSetupP->sslVerifyPeer = !curlXportParmsP->no_ssl_verifypeer; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(no_ssl_verifyhost)) curlSetupP->sslVerifyHost = true; else curlSetupP->sslVerifyHost = !curlXportParmsP->no_ssl_verifyhost; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(ssl_cert)) curlSetupP->sslCert = NULL; else if (curlXportParmsP->ssl_cert == NULL) curlSetupP->sslCert = NULL; else curlSetupP->sslCert = strdup(curlXportParmsP->ssl_cert); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslcerttype)) curlSetupP->sslCertType = NULL; else if (curlXportParmsP->sslcerttype == NULL) curlSetupP->sslCertType = NULL; else curlSetupP->sslCertType = strdup(curlXportParmsP->sslcerttype); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslcertpasswd)) curlSetupP->sslCertPasswd = NULL; else if (curlXportParmsP->sslcertpasswd == NULL) curlSetupP->sslCertPasswd = NULL; else curlSetupP->sslCertPasswd = strdup(curlXportParmsP->sslcertpasswd); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslkey)) curlSetupP->sslKey = NULL; else if (curlXportParmsP->sslkey == NULL) curlSetupP->sslKey = NULL; else curlSetupP->sslKey = strdup(curlXportParmsP->sslkey); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslkeytype)) curlSetupP->sslKeyType = NULL; else if (curlXportParmsP->sslkeytype == NULL) curlSetupP->sslKeyType = NULL; else curlSetupP->sslKeyType = strdup(curlXportParmsP->sslkeytype); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslkeypasswd)) curlSetupP->sslKeyPasswd = NULL; else if (curlXportParmsP->sslkeypasswd == NULL) curlSetupP->sslKeyPasswd = NULL; else curlSetupP->sslKeyPasswd = strdup(curlXportParmsP->sslkeypasswd); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslengine)) curlSetupP->sslEngine = NULL; else if (curlXportParmsP->sslengine == NULL) curlSetupP->sslEngine = NULL; else curlSetupP->sslEngine = strdup(curlXportParmsP->sslengine); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslengine_default)) curlSetupP->sslEngineDefault = false; else curlSetupP->sslEngineDefault = !!curlXportParmsP->sslengine_default; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(sslversion)) curlSetupP->sslVersion = XMLRPC_SSLVERSION_DEFAULT; else curlSetupP->sslVersion = curlXportParmsP->sslversion; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(cainfo)) curlSetupP->caInfo = NULL; else if (curlXportParmsP->cainfo == NULL) curlSetupP->caInfo = NULL; else curlSetupP->caInfo = strdup(curlXportParmsP->cainfo); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(capath)) curlSetupP->caPath = NULL; else if (curlXportParmsP->capath == NULL) curlSetupP->caPath = NULL; else curlSetupP->caPath = strdup(curlXportParmsP->capath); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(randomfile)) curlSetupP->randomFile = NULL; else if (curlXportParmsP->randomfile == NULL) curlSetupP->randomFile = NULL; else curlSetupP->randomFile = strdup(curlXportParmsP->randomfile); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(egdsocket)) curlSetupP->egdSocket = NULL; else if (curlXportParmsP->egdsocket == NULL) curlSetupP->egdSocket = NULL; else curlSetupP->egdSocket = strdup(curlXportParmsP->egdsocket); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(ssl_cipher_list)) curlSetupP->sslCipherList = NULL; else if (curlXportParmsP->ssl_cipher_list == NULL) curlSetupP->sslCipherList = NULL; else curlSetupP->sslCipherList = strdup(curlXportParmsP->ssl_cipher_list); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(proxy)) curlSetupP->proxy = NULL; else if (curlXportParmsP->proxy == NULL) curlSetupP->proxy = NULL; else curlSetupP->proxy = strdup(curlXportParmsP->proxy); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(proxy_port)) curlSetupP->proxyPort = 8080; else curlSetupP->proxyPort = curlXportParmsP->proxy_port; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(proxy_auth)) curlSetupP->proxyAuth = CURLAUTH_BASIC; else curlSetupP->proxyAuth = curlXportParmsP->proxy_auth; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(proxy_userpwd)) curlSetupP->proxyUserPwd = NULL; else if (curlXportParmsP->proxy_userpwd == NULL) curlSetupP->proxyUserPwd = NULL; else curlSetupP->proxyUserPwd = strdup(curlXportParmsP->proxy_userpwd); if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(proxy_type)) curlSetupP->proxyType = CURLPROXY_HTTP; else curlSetupP->proxyType = curlXportParmsP->proxy_type; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(gssapi_delegation)) curlSetupP->gssapiDelegation = false; else curlSetupP->gssapiDelegation = !!curlXportParmsP->gssapi_delegation; if (!curlXportParmsP || parmSize < XMLRPC_CXPSIZE(referer)) curlSetupP->referer = NULL; else if (curlXportParmsP->referer == NULL) curlSetupP->referer = NULL; else curlSetupP->referer = strdup(curlXportParmsP->referer); getTimeoutParm(envP, curlXportParmsP, parmSize, &curlSetupP->timeout); } static void freeXportParms(const struct xmlrpc_client_transport * const transportP) { const struct curlSetup * const curlSetupP = &transportP->curlSetupStuff; if (curlSetupP->sslCipherList) xmlrpc_strfree(curlSetupP->sslCipherList); if (curlSetupP->egdSocket) xmlrpc_strfree(curlSetupP->egdSocket); if (curlSetupP->randomFile) xmlrpc_strfree(curlSetupP->randomFile); if (curlSetupP->caPath) xmlrpc_strfree(curlSetupP->caPath); if (curlSetupP->caInfo) xmlrpc_strfree(curlSetupP->caInfo); if (curlSetupP->sslEngine) xmlrpc_strfree(curlSetupP->sslEngine); if (curlSetupP->sslKeyPasswd) xmlrpc_strfree(curlSetupP->sslKeyPasswd); if (curlSetupP->sslKeyType) xmlrpc_strfree(curlSetupP->sslKeyType); if (curlSetupP->sslKey) xmlrpc_strfree(curlSetupP->sslKey); if (curlSetupP->sslCertPasswd) xmlrpc_strfree(curlSetupP->sslCertPasswd); if (curlSetupP->sslCertType) xmlrpc_strfree(curlSetupP->sslCertType); if (curlSetupP->sslCert) xmlrpc_strfree(curlSetupP->sslCert); if (curlSetupP->networkInterface) xmlrpc_strfree(curlSetupP->networkInterface); if (transportP->userAgent) xmlrpc_strfree(transportP->userAgent); if (curlSetupP->proxy) xmlrpc_strfree(curlSetupP->proxy); if (curlSetupP->proxyUserPwd) xmlrpc_strfree(curlSetupP->proxyUserPwd); if (curlSetupP->referer) xmlrpc_strfree(curlSetupP->referer); } static void createSyncCurlSession(xmlrpc_env * const envP, CURL ** const curlSessionPP) { /*---------------------------------------------------------------------------- Create a Curl session to be used for multiple serial transactions. The Curl session we create is not complete -- it still has to be further set up for each particular transaction. We can't set up anything here that changes from one transaction to the next. We don't bother setting up anything that has to be set up for an asynchronous transaction because code that is common between synchronous and asynchronous transactions takes care of that anyway. That leaves things, such as cookies, that don't exist for asynchronous transactions, and are common to multiple serial synchronous transactions. -----------------------------------------------------------------------------*/ CURL * const curlSessionP = curl_easy_init(); if (curlSessionP == NULL) xmlrpc_faultf(envP, "Could not create Curl session. " "curl_easy_init() failed."); else { /* The following is a trick. CURLOPT_COOKIEFILE is the name of the file containing the initial cookies for the Curl session. But setting it is also what turns on the cookie function itself, whereby the Curl library accepts and stores cookies from the server and sends them back on future requests. We don't have a file of initial cookies, but we want to turn on cookie function, so we set the option to something we know does not validly name a file. Curl will ignore the error and just start up cookie function with no initial cookies. */ curl_easy_setopt(curlSessionP, CURLOPT_COOKIEFILE, ""); *curlSessionPP = curlSessionP; } } static void destroySyncCurlSession(CURL * const curlSessionP) { curl_easy_cleanup(curlSessionP); } static void makeSyncCurlSession(xmlrpc_env * const envP, struct xmlrpc_client_transport * const transportP) { transportP->syncCurlSessionLockP = xmlrpc_lock_create(); if (transportP->syncCurlSessionLockP == NULL) xmlrpc_faultf(envP, "Unable to create lock for " "synchronous Curl session."); else { createSyncCurlSession(envP, &transportP->syncCurlSessionP); if (!envP->fault_occurred) { /* We'll need a multi manager to actually execute this session: */ transportP->syncCurlMultiP = curlMulti_create(); if (transportP->syncCurlMultiP == NULL) xmlrpc_faultf(envP, "Unable to create Curl multi manager for " "synchronous RPCs"); if (envP->fault_occurred) destroySyncCurlSession(transportP->syncCurlSessionP); } if (envP->fault_occurred) transportP->syncCurlSessionLockP->destroy( transportP->syncCurlSessionLockP); } } static void unmakeSyncCurlSession(struct xmlrpc_client_transport * const transportP) { curlMulti_destroy(transportP->syncCurlMultiP); destroySyncCurlSession(transportP->syncCurlSessionP); transportP->syncCurlSessionLockP->destroy( transportP->syncCurlSessionLockP); } static void create(xmlrpc_env * const envP, int const flags ATTR_UNUSED, const char * const appname ATTR_UNUSED, const char * const appversion ATTR_UNUSED, const void * const transportparmsP, size_t const parm_size, struct xmlrpc_client_transport ** const handlePP) { /*---------------------------------------------------------------------------- This does the 'create' operation for a Curl client transport. -----------------------------------------------------------------------------*/ const struct xmlrpc_curl_xportparms * const curlXportParmsP = transportparmsP; struct xmlrpc_client_transport * transportP; MALLOCVAR(transportP); if (transportP == NULL) xmlrpc_faultf(envP, "Unable to allocate transport descriptor."); else { setVerbose(&transportP->curlSetupStuff.verbose); transportP->interruptP = NULL; transportP->asyncCurlMultiP = curlMulti_create(); if (transportP->asyncCurlMultiP == NULL) xmlrpc_faultf(envP, "Unable to create Curl multi manager for " "asynchronous RPCs"); else { getXportParms(envP, curlXportParmsP, parm_size, transportP); if (!envP->fault_occurred) { makeSyncCurlSession(envP, transportP); if (envP->fault_occurred) freeXportParms(transportP); } if (envP->fault_occurred) curlMulti_destroy(transportP->asyncCurlMultiP); } if (envP->fault_occurred) free(transportP); } *handlePP = transportP; } static void setInterrupt(struct xmlrpc_client_transport * const clientTransportP, int * const interruptP) { clientTransportP->interruptP = interruptP; } static void assertNoOutstandingCurlWork(curlMulti * const curlMultiP) { xmlrpc_env env; bool immediateWorkToDo; int runningHandles; xmlrpc_env_init(&env); curlMulti_perform(&env, curlMultiP, &immediateWorkToDo, &runningHandles); /* We know the above was a no-op, since we're asserting that there is no outstanding work. */ XMLRPC_ASSERT(!env.fault_occurred); XMLRPC_ASSERT(!immediateWorkToDo); XMLRPC_ASSERT(runningHandles == 0); xmlrpc_env_clean(&env); } static void destroy(struct xmlrpc_client_transport * const clientTransportP) { /*---------------------------------------------------------------------------- This does the 'destroy' operation for a Curl client transport. An RPC is a reference to a client XML transport, so you may not destroy a transport while RPCs are running. To ensure no asynchronous RPCs are running, you must successfully execute the transport 'finishAsync' method, with no interruptions or timeouts allowed. To speed that up, you can set the transport's interrupt flag to 1 first, which will make all outstanding RPCs fail immediately. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT(clientTransportP != NULL); assertNoOutstandingCurlWork(clientTransportP->asyncCurlMultiP); /* We know this is true because a condition of destroying the transport is that there be no outstanding asynchronous RPCs. */ assertNoOutstandingCurlWork(clientTransportP->syncCurlMultiP); /* This is because a condition of destroying the transport is that no transport method be running. The only way a synchronous RPC can be in progress is for the 'perform' method to be running. */ unmakeSyncCurlSession(clientTransportP); curlMulti_destroy(clientTransportP->asyncCurlMultiP); freeXportParms(clientTransportP); free(clientTransportP); } static void performCurlTransaction(xmlrpc_env * const envP, curlTransaction * const curlTransactionP, curlMulti * const curlMultiP, int * const interruptP) { curlMulti_addHandle(envP, curlMultiP, curlTransaction_curlSession(curlTransactionP)); /* Failure here just means something screwy in the multi manager; Above does not even begin to perform the HTTP transaction */ if (!envP->fault_occurred) { xmlrpc_timespec const dummy = {0,0}; finishCurlMulti(envP, curlMultiP, timeout_no, dummy, interruptP); /* Failure here just means something screwy in the multi manager; any failure of the HTTP transaction would have been recorded in *curlTransactionP. */ if (!envP->fault_occurred) { /* Curl session completed OK. But did HTTP transaction it prosecuted work? */ curlTransaction_getError(curlTransactionP, envP); } /* If the CURL transaction is still going, removing the handle here aborts it. At least it's supposed to. From what I've seen in the Curl code in 2007, I don't think it does. I couldn't get Curl maintainers interested in the problem, except to say, "If you're right, there's a bug." */ curlMulti_removeHandle(curlMultiP, curlTransaction_curlSession(curlTransactionP)); } } static void startRpc(xmlrpc_env * const envP, rpc * const rpcP) { curlMulti_addHandle(envP, rpcP->transportP->asyncCurlMultiP, curlTransaction_curlSession(rpcP->curlTransactionP)); } static curlt_finishFn finishRpcCurlTransaction; static curlt_progressFn curlTransactionProgress; static void createRpc(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, CURL * const curlSessionP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block * const responseXmlP, xmlrpc_transport_asynch_complete complete, xmlrpc_transport_progress progress, struct xmlrpc_call_info * const callInfoP, rpc ** const rpcPP) { rpc * rpcP; MALLOCVAR(rpcP); if (rpcP == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for rpc object"); else { curlt_progressFn * curlProgressFn; if (progress || clientTransportP->interruptP) curlProgressFn = &curlTransactionProgress; else { /* There's nothing for curlTransactionProgress() to do, so save the time and complexity of calling it. */ curlProgressFn = NULL; } rpcP->transportP = clientTransportP; rpcP->curlSessionP = curlSessionP; rpcP->callInfoP = callInfoP; rpcP->complete = complete; rpcP->progress = progress; rpcP->responseXmlP = responseXmlP; curlTransaction_create(envP, curlSessionP, serverP, callXmlP, responseXmlP, clientTransportP->dontAdvertise, clientTransportP->userAgent, &clientTransportP->curlSetupStuff, rpcP, complete ? &finishRpcCurlTransaction : NULL, curlProgressFn, &rpcP->curlTransactionP); if (!envP->fault_occurred) { if (envP->fault_occurred) curlTransaction_destroy(rpcP->curlTransactionP); } if (envP->fault_occurred) free(rpcP); } *rpcPP = rpcP; } static void destroyRpc(rpc * const rpcP) { XMLRPC_ASSERT_PTR_OK(rpcP); curlTransaction_destroy(rpcP->curlTransactionP); free(rpcP); } static void performRpc(xmlrpc_env * const envP, rpc * const rpcP, curlMulti * const curlMultiP, int * const interruptP) { performCurlTransaction(envP, rpcP->curlTransactionP, curlMultiP, interruptP); } static curlt_finishFn finishRpcCurlTransaction; static void finishRpcCurlTransaction(xmlrpc_env * const envP ATTR_UNUSED, void * const userContextP) { /*---------------------------------------------------------------------------- Handle the event that a Curl transaction for an asynchronous RPC has completed on the Curl session identified by 'curlSessionP'. Tell the requester of the RPC the results. Remove the Curl session from its Curl multi manager and destroy the Curl session, the XML response buffer, the Curl transaction, and the RPC. -----------------------------------------------------------------------------*/ rpc * const rpcP = userContextP; curlTransaction * const curlTransactionP = rpcP->curlTransactionP; struct xmlrpc_client_transport * const transportP = rpcP->transportP; curlMulti_removeHandle(transportP->asyncCurlMultiP, curlTransaction_curlSession(curlTransactionP)); { xmlrpc_env env; xmlrpc_env_init(&env); curlTransaction_getError(curlTransactionP, &env); rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env); xmlrpc_env_clean(&env); } curl_easy_cleanup(rpcP->curlSessionP); XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP); destroyRpc(rpcP); } static curlt_progressFn curlTransactionProgress; static void curlTransactionProgress(void * const context, double const dlTotal, double const dlNow, double const ulTotal, double const ulNow, bool * const abortP) { /*---------------------------------------------------------------------------- This is equivalent to a Curl "progress function" (the curlTransaction object just passes through the call from libcurl). The curlTransaction calls this once a second telling us how much data has transferred. If the transport user has set up a progress function, we call that with this progress information. That function might e.g. display a progress bar. Additionally, the curlTransaction gives us the opportunity to tell it to abort the transaction, which we do if the user has set his "interrupt" flag (which he registered with the transport when he created it). -----------------------------------------------------------------------------*/ rpc * const rpcP = context; struct xmlrpc_client_transport * const transportP = rpcP->transportP; assert(rpcP); assert(transportP); trace("Progress function called back by libcurl"); if (rpcP->progress) { struct xmlrpc_progress_data progressData; trace("Calling transport client's progress function with %u %u %u %u", dlTotal, dlNow, ulTotal, ulNow); progressData.response.total = dlTotal; progressData.response.now = dlNow; progressData.call.total = ulTotal; progressData.call.now = ulNow; rpcP->progress(rpcP->callInfoP, progressData); } if (transportP->interruptP) { trace("Interrupt flag is set; " "directing libcurl to abort the transaction"); *abortP = *transportP->interruptP; } else *abortP = false; } static void sendRequest(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_transport_asynch_complete complete, xmlrpc_transport_progress progress, struct xmlrpc_call_info * const callInfoP) { /*---------------------------------------------------------------------------- Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to the server. Unless we return failure, we arrange to have complete() called when the rpc completes. This does the 'send_request' operation for a Curl client transport. -----------------------------------------------------------------------------*/ rpc * rpcP; xmlrpc_mem_block * responseXmlP; responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); if (!envP->fault_occurred) { CURL * const curlSessionP = curl_easy_init(); if (curlSessionP == NULL) xmlrpc_faultf(envP, "Could not create Curl session. " "curl_easy_init() failed."); else { createRpc(envP, clientTransportP, curlSessionP, serverP, callXmlP, responseXmlP, complete, progress, callInfoP, &rpcP); if (!envP->fault_occurred) { startRpc(envP, rpcP); if (envP->fault_occurred) destroyRpc(rpcP); } if (envP->fault_occurred) curl_easy_cleanup(curlSessionP); } if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, responseXmlP); } /* If we're returning success, the user's eventual finish_asynch call will destroy this RPC, Curl session, and response buffer and remove the Curl session from the Curl multi manager. (If we're returning failure, we didn't create any of those). */ } static void finishAsynch( struct xmlrpc_client_transport * const clientTransportP, xmlrpc_timeoutType const timeoutType, xmlrpc_timeout const timeout) { /*---------------------------------------------------------------------------- Wait for the Curl multi manager to finish the Curl transactions for all outstanding RPCs and destroy those RPCs. But give up if a) too much time passes as defined by 'timeoutType' and 'timeout'; or b) the transport client requests interruption (i.e. the transport's interrupt flag becomes nonzero). Normally, a signal must get our attention for us to notice the interrupt flag. This does the 'finish_asynch' operation for a Curl client transport. It would be cool to replace this with something analogous to the Curl asynchronous interface: Have something like curl_multi_fdset() that returns a bunch of file descriptors on which the user can wait (along with possibly other file descriptors of his own) and something like curl_multi_perform() to finish whatever RPCs are ready to finish at that moment. The implementation would be little more than wrapping curl_multi_fdset() and curl_multi_perform(). Note that the user can call this multiple times, due to timeouts, but must eventually call it once with no timeout so he knows that all the RPCs are finished. Either that or terminate the process so it doesn't matter if RPCs are still going. -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_timespec waitTimeoutTime; /* The datetime after which we should quit waiting */ xmlrpc_env_init(&env); if (timeoutType == timeout_yes) { xmlrpc_timespec waitStartTime; xmlrpc_gettimeofday(&waitStartTime); addMilliseconds(waitStartTime, timeout, &waitTimeoutTime); } finishCurlMulti(&env, clientTransportP->asyncCurlMultiP, timeoutType, waitTimeoutTime, clientTransportP->interruptP); /* If the above fails, it is catastrophic, because it means there is no way to complete outstanding Curl transactions and RPCs, and no way to release their resources. We should at least expand this interface some day to push the problem back up to the user, but for now we just do this Hail Mary response. Note that a failure of finish_curlMulti() does not mean that a session completed with an error or an RPC completed with an error. Those things are reported up through the user's xmlrpc_transport_asynch_complete routine. A failure here is something that stopped us from calling that. Note that a timeout causes a successful completion, but without finishing all the RPCs! */ if (env.fault_occurred) fprintf(stderr, "finishAsync() failed. Xmlrpc-c Curl transport " "is now in an unknown state and may not be able to " "continue functioning. Specifics of the failure: %s\n", env.fault_string); xmlrpc_env_clean(&env); } static void call(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block ** const responseXmlPP) { xmlrpc_mem_block * responseXmlP; rpc * rpcP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(serverP); XMLRPC_ASSERT_PTR_OK(callXmlP); XMLRPC_ASSERT_PTR_OK(responseXmlPP); responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); if (!envP->fault_occurred) { /* Only one RPC at a time can use a Curl session, so we have to hold the lock as long as our RPC exists. */ lockSyncCurlSession(clientTransportP); createRpc(envP, clientTransportP, clientTransportP->syncCurlSessionP, serverP, callXmlP, responseXmlP, NULL, NULL, NULL, &rpcP); if (!envP->fault_occurred) { performRpc(envP, rpcP, clientTransportP->syncCurlMultiP, clientTransportP->interruptP); *responseXmlPP = responseXmlP; destroyRpc(rpcP); } unlockSyncCurlSession(clientTransportP); if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, responseXmlP); } } static void setupGlobalConstants(xmlrpc_env * const envP) { /*---------------------------------------------------------------------------- See longwinded discussion of the global constant issue at the top of this file. -----------------------------------------------------------------------------*/ initWindowsStuff(envP); if (!envP->fault_occurred) { CURLcode rc; rc = curl_global_init(CURL_GLOBAL_ALL); if (rc != CURLE_OK) xmlrpc_faultf(envP, "curl_global_init() failed with code %d", rc); } } static void teardownGlobalConstants(void) { /*---------------------------------------------------------------------------- See longwinded discussion of the global constant issue at the top of this file. -----------------------------------------------------------------------------*/ curl_global_cleanup(); termWindowsStuff(); } struct xmlrpc_client_transport_ops xmlrpc_curl_transport_ops = { &setupGlobalConstants, &teardownGlobalConstants, &create, &destroy, &sendRequest, &call, &finishAsynch, &setInterrupt, }; xmlrpc-c-1.33.14/lib/expat/000077500000000000000000000000001236133176700153105ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/expat/Makefile000066400000000000000000000014631236133176700167540ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') LIBDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/expat include $(BLDDIR)/config.mk # Build up SUBDIRS: SUBDIRS = gennmtab xmlparse xmltok default: all .PHONY: all clean distclean tags distdir intall check dep all: $(SUBDIRS:%=%/all) # Extra dependencies to make parallel make work in spite of all the submakes # (See top level make file for details) xmlparse/all: gennmtab/all xmltok/all xmltok/all: gennmtab/all clean: $(SUBDIRS:%=%/clean) clean-common distclean: $(SUBDIRS:%=%/distclean) distclean-common tags: $(SUBDIRS:%=%/tags) TAGS DISTFILES = distdir: distdir-common install: $(SUBDIRS:%=%/install) check: dep: $(SUBDIRS:%=%/dep) include $(SRCDIR)/common.mk xmlrpc-c-1.33.14/lib/expat/expat.html000066400000000000000000000071251236133176700173240ustar00rootroot00000000000000 expat

expat - XML Parser Toolkit

This is outdated stuff from the independently developed Expat which was forked in 2001 to make the Xmlrpc-c embedded version.

Version 1.2

Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd. Expat is freely available with source under a very liberal license (the MIT license).

This is a production version of expat. Relative to expat 1.1, it adds support for parsing external DTDs and parameter entities. Compiling with -DXML_DTD enables this support. There's a new -p option for xmlwf which will cause it to process external DTDs and parameter entities; this implies the -x option. See the comment above XML_SetParamEntityParsing in xmlparse.h for the API addition that enables this.

For Xmlrpc-c, we find no reason to exclude this function from the library, and ifdefs make code harder to maintain, so we include the function unconditionally. (i.e. -DXML_DTD does nothing).

Expat is an XML 1.0 parser written in C. It aims to be fully conforming. It is currently not a validating XML processor. The current production version of expat 1.X can be downloaded from ftp://ftp.jclark.com/pub/xml/expat.zip.

Development of expat 2.0 is being handled by a team led by Clark Cooper, hosted by sourceforge.net. See http://expat.sourceforge.net for the latest on expat 2.0.

The directory xmltok contains a low-level library for tokenizing XML. The interface is documented in xmltok/xmltok.h.

The directory xmlparse contains an XML parser library which is built on top of the xmltok library. The interface is documented in xmlparse/xmlparse.h. The directory sample contains a simple example program using this interface; sample/build.bat is a batch file to build the example using Visual C++.

The directory xmlwf contains the xmlwf application, which uses the xmlparse library. The arguments to xmlwf are one or more files which are each to be checked for well-formedness. An option -d dir can be specified; for each well-formed input file the corresponding canonical XML will be written to dir/f, where f is the filename (without any path) of the input file. A -x option will cause references to external general entities to be processed. A -s option will make documents that are not standalone cause an error (a document is considered standalone if either it is intrinsically standalone because it has no external subset and no references to parameter entities in the internal subset or it is declared as standalone in the XML declaration).

The bin directory contains Win32 executables. The lib directory contains Win32 import libraries.

Answers to some frequently asked questions about expat can be found in the expat FAQ.

James Clark
xmlrpc-c-1.33.14/lib/expat/gennmtab/000077500000000000000000000000001236133176700171035ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/expat/gennmtab/Makefile000066400000000000000000000014221236133176700205420ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') EXPATDIR := $(call updir,$(CURDIR)) LIBDIR := $(call updir,$(EXPATDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/expat/gennmtab include $(BLDDIR)/config.mk LDFLAGS = $(LADD) INCLUDES = -I$(BLDDIR) -Isrcdir/lib/util/include default: all include $(SRCDIR)/common.mk .PHONY: all all: gennmtab .PHONY: clean clean: clean-common rm -f gennmtab .PHONY: distclean distclean: clean distclean-common .PHONY: tags tags: TAGS .PHONY: distdir distdir: .PHONY: install install: .PHONY: dep dep: dep-common gennmtab.o:%.o:%.c $(BUILDTOOL_CC) -c $< -o $@ $(CFLAGS_ALL) $(INCLUDES) gennmtab:%:%.o $(BUILDTOOL_CCLD) -o $@ $(LDFLAGS_PERSONAL) $(LDFLAGS) $^ include depend.mk xmlrpc-c-1.33.14/lib/expat/gennmtab/gennmtab.c000066400000000000000000000224531236133176700210500ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include #include #include #include "xmlrpc_config.h" struct range { int start; int end; }; struct range nmstrt[] = { { '_', 0 }, { ':', 0 }, /* BaseChar */ { 0x0041, 0x005a }, { 0x0061, 0x007a }, { 0x00c0, 0x00d6 }, { 0x00d8, 0x00f6 }, { 0x00f8, 0x00ff }, { 0x0100, 0x0131 }, { 0x0134, 0x013e }, { 0x0141, 0x0148 }, { 0x014a, 0x017e }, { 0x0180, 0x01c3 }, { 0x01cd, 0x01f0 }, { 0x01f4, 0x01f5 }, { 0x01fa, 0x0217 }, { 0x0250, 0x02a8 }, { 0x02bb, 0x02c1 }, { 0x0386, 0 }, { 0x0388, 0x038a }, { 0x038c, 0 }, { 0x038e, 0x03a1 }, { 0x03a3, 0x03ce }, { 0x03d0, 0x03d6 }, { 0x03da, 0 }, { 0x03dc, 0 }, { 0x03de, 0 }, { 0x03e0, 0 }, { 0x03e2, 0x03f3 }, { 0x0401, 0x040c }, { 0x040e, 0x044f }, { 0x0451, 0x045c }, { 0x045e, 0x0481 }, { 0x0490, 0x04c4 }, { 0x04c7, 0x04c8 }, { 0x04cb, 0x04cc }, { 0x04d0, 0x04eb }, { 0x04ee, 0x04f5 }, { 0x04f8, 0x04f9 }, { 0x0531, 0x0556 }, { 0x0559, 0 }, { 0x0561, 0x0586 }, { 0x05d0, 0x05ea }, { 0x05f0, 0x05f2 }, { 0x0621, 0x063a }, { 0x0641, 0x064a }, { 0x0671, 0x06b7 }, { 0x06ba, 0x06be }, { 0x06c0, 0x06ce }, { 0x06d0, 0x06d3 }, { 0x06d5, 0 }, { 0x06e5, 0x06e6 }, { 0x0905, 0x0939 }, { 0x093d, 0 }, { 0x0958, 0x0961 }, { 0x0985, 0x098c }, { 0x098f, 0x0990 }, { 0x0993, 0x09a8 }, { 0x09aa, 0x09b0 }, { 0x09b2, 0 }, { 0x09b6, 0x09b9 }, { 0x09dc, 0x09dd }, { 0x09df, 0x09e1 }, { 0x09f0, 0x09f1 }, { 0x0a05, 0x0a0a }, { 0x0a0f, 0x0a10 }, { 0x0a13, 0x0a28 }, { 0x0a2a, 0x0a30 }, { 0x0a32, 0x0a33 }, { 0x0a35, 0x0a36 }, { 0x0a38, 0x0a39 }, { 0x0a59, 0x0a5c }, { 0x0a5e, 0 }, { 0x0a72, 0x0a74 }, { 0x0a85, 0x0a8b }, { 0x0a8d, 0 }, { 0x0a8f, 0x0a91 }, { 0x0a93, 0x0aa8 }, { 0x0aaa, 0x0ab0 }, { 0x0ab2, 0x0ab3 }, { 0x0ab5, 0x0ab9 }, { 0x0abd, 0 }, { 0x0ae0, 0 }, { 0x0b05, 0x0b0c }, { 0x0b0f, 0x0b10 }, { 0x0b13, 0x0b28 }, { 0x0b2a, 0x0b30 }, { 0x0b32, 0x0b33 }, { 0x0b36, 0x0b39 }, { 0x0b3d, 0 }, { 0x0b5c, 0x0b5d }, { 0x0b5f, 0x0b61 }, { 0x0b85, 0x0b8a }, { 0x0b8e, 0x0b90 }, { 0x0b92, 0x0b95 }, { 0x0b99, 0x0b9a }, { 0x0b9c, 0 }, { 0x0b9e, 0x0b9f }, { 0x0ba3, 0x0ba4 }, { 0x0ba8, 0x0baa }, { 0x0bae, 0x0bb5 }, { 0x0bb7, 0x0bb9 }, { 0x0c05, 0x0c0c }, { 0x0c0e, 0x0c10 }, { 0x0c12, 0x0c28 }, { 0x0c2a, 0x0c33 }, { 0x0c35, 0x0c39 }, { 0x0c60, 0x0c61 }, { 0x0c85, 0x0c8c }, { 0x0c8e, 0x0c90 }, { 0x0c92, 0x0ca8 }, { 0x0caa, 0x0cb3 }, { 0x0cb5, 0x0cb9 }, { 0x0cde, 0 }, { 0x0ce0, 0x0ce1 }, { 0x0d05, 0x0d0c }, { 0x0d0e, 0x0d10 }, { 0x0d12, 0x0d28 }, { 0x0d2a, 0x0d39 }, { 0x0d60, 0x0d61 }, { 0x0e01, 0x0e2e }, { 0x0e30, 0 }, { 0x0e32, 0x0e33 }, { 0x0e40, 0x0e45 }, { 0x0e81, 0x0e82 }, { 0x0e84, 0 }, { 0x0e87, 0x0e88 }, { 0x0e8a, 0 }, { 0x0e8d, 0 }, { 0x0e94, 0x0e97 }, { 0x0e99, 0x0e9f }, { 0x0ea1, 0x0ea3 }, { 0x0ea5, 0 }, { 0x0ea7, 0 }, { 0x0eaa, 0x0eab }, { 0x0ead, 0x0eae }, { 0x0eb0, 0 }, { 0x0eb2, 0x0eb3 }, { 0x0ebd, 0 }, { 0x0ec0, 0x0ec4 }, { 0x0f40, 0x0f47 }, { 0x0f49, 0x0f69 }, { 0x10a0, 0x10c5 }, { 0x10d0, 0x10f6 }, { 0x1100, 0 }, { 0x1102, 0x1103 }, { 0x1105, 0x1107 }, { 0x1109, 0 }, { 0x110b, 0x110c }, { 0x110e, 0x1112 }, { 0x113c, 0 }, { 0x113e, 0 }, { 0x1140, 0 }, { 0x114c, 0 }, { 0x114e, 0 }, { 0x1150, 0 }, { 0x1154, 0x1155 }, { 0x1159, 0 }, { 0x115f, 0x1161 }, { 0x1163, 0 }, { 0x1165, 0 }, { 0x1167, 0 }, { 0x1169, 0 }, { 0x116d, 0x116e }, { 0x1172, 0x1173 }, { 0x1175, 0 }, { 0x119e, 0 }, { 0x11a8, 0 }, { 0x11ab, 0 }, { 0x11ae, 0x11af }, { 0x11b7, 0x11b8 }, { 0x11ba, 0 }, { 0x11bc, 0x11c2 }, { 0x11eb, 0 }, { 0x11f0, 0 }, { 0x11f9, 0 }, { 0x1e00, 0x1e9b }, { 0x1ea0, 0x1ef9 }, { 0x1f00, 0x1f15 }, { 0x1f18, 0x1f1d }, { 0x1f20, 0x1f45 }, { 0x1f48, 0x1f4d }, { 0x1f50, 0x1f57 }, { 0x1f59, 0 }, { 0x1f5b, 0 }, { 0x1f5d, 0 }, { 0x1f5f, 0x1f7d }, { 0x1f80, 0x1fb4 }, { 0x1fb6, 0x1fbc }, { 0x1fbe, 0 }, { 0x1fc2, 0x1fc4 }, { 0x1fc6, 0x1fcc }, { 0x1fd0, 0x1fd3 }, { 0x1fd6, 0x1fdb }, { 0x1fe0, 0x1fec }, { 0x1ff2, 0x1ff4 }, { 0x1ff6, 0x1ffc }, { 0x2126, 0 }, { 0x212a, 0x212b }, { 0x212e, 0 }, { 0x2180, 0x2182 }, { 0x3041, 0x3094 }, { 0x30a1, 0x30fa }, { 0x3105, 0x312c }, { 0xac00, 0xd7a3 }, /* Ideographic */ { 0x4e00, 0x9fa5 }, { 0x3007, 0 }, { 0x3021, 0x3029 }, }; /* name chars that are not name start chars */ struct range name[] = { { '.', 0 }, { '-', 0 }, /* CombiningChar */ { 0x0300, 0x0345 }, { 0x0360, 0x0361 }, { 0x0483, 0x0486 }, { 0x0591, 0x05a1 }, { 0x05a3, 0x05b9 }, { 0x05bb, 0x05bd }, { 0x05bf, 0 }, { 0x05c1, 0x05c2 }, { 0x05c4, 0 }, { 0x064b, 0x0652 }, { 0x0670, 0 }, { 0x06d6, 0x06dc }, { 0x06dd, 0x06df }, { 0x06e0, 0x06e4 }, { 0x06e7, 0x06e8 }, { 0x06ea, 0x06ed }, { 0x0901, 0x0903 }, { 0x093c, 0 }, { 0x093e, 0x094c }, { 0x094d, 0 }, { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0983 }, { 0x09bc, 0 }, { 0x09be, 0 }, { 0x09bf, 0 }, { 0x09c0, 0x09c4 }, { 0x09c7, 0x09c8 }, { 0x09cb, 0x09cd }, { 0x09d7, 0 }, { 0x09e2, 0x09e3 }, { 0x0a02, 0 }, { 0x0a3c, 0 }, { 0x0a3e, 0 }, { 0x0a3f, 0 }, { 0x0a40, 0x0a42 }, { 0x0a47, 0x0a48 }, { 0x0a4b, 0x0a4d }, { 0x0a70, 0x0a71 }, { 0x0a81, 0x0a83 }, { 0x0abc, 0 }, { 0x0abe, 0x0ac5 }, { 0x0ac7, 0x0ac9 }, { 0x0acb, 0x0acd }, { 0x0b01, 0x0b03 }, { 0x0b3c, 0 }, { 0x0b3e, 0x0b43 }, { 0x0b47, 0x0b48 }, { 0x0b4b, 0x0b4d }, { 0x0b56, 0x0b57 }, { 0x0b82, 0x0b83 }, { 0x0bbe, 0x0bc2 }, { 0x0bc6, 0x0bc8 }, { 0x0bca, 0x0bcd }, { 0x0bd7, 0 }, { 0x0c01, 0x0c03 }, { 0x0c3e, 0x0c44 }, { 0x0c46, 0x0c48 }, { 0x0c4a, 0x0c4d }, { 0x0c55, 0x0c56 }, { 0x0c82, 0x0c83 }, { 0x0cbe, 0x0cc4 }, { 0x0cc6, 0x0cc8 }, { 0x0cca, 0x0ccd }, { 0x0cd5, 0x0cd6 }, { 0x0d02, 0x0d03 }, { 0x0d3e, 0x0d43 }, { 0x0d46, 0x0d48 }, { 0x0d4a, 0x0d4d }, { 0x0d57, 0 }, { 0x0e31, 0 }, { 0x0e34, 0x0e3a }, { 0x0e47, 0x0e4e }, { 0x0eb1, 0 }, { 0x0eb4, 0x0eb9 }, { 0x0ebb, 0x0ebc }, { 0x0ec8, 0x0ecd }, { 0x0f18, 0x0f19 }, { 0x0f35, 0 }, { 0x0f37, 0 }, { 0x0f39, 0 }, { 0x0f3e, 0 }, { 0x0f3f, 0 }, { 0x0f71, 0x0f84 }, { 0x0f86, 0x0f8b }, { 0x0f90, 0x0f95 }, { 0x0f97, 0 }, { 0x0f99, 0x0fad }, { 0x0fb1, 0x0fb7 }, { 0x0fb9, 0 }, { 0x20d0, 0x20dc }, { 0x20e1, 0 }, { 0x302a, 0x302f }, { 0x3099, 0 }, { 0x309a, 0 }, /* Digit */ { 0x0030, 0x0039 }, { 0x0660, 0x0669 }, { 0x06f0, 0x06f9 }, { 0x0966, 0x096f }, { 0x09e6, 0x09ef }, { 0x0a66, 0x0a6f }, { 0x0ae6, 0x0aef }, { 0x0b66, 0x0b6f }, { 0x0be7, 0x0bef }, { 0x0c66, 0x0c6f }, { 0x0ce6, 0x0cef }, { 0x0d66, 0x0d6f }, { 0x0e50, 0x0e59 }, { 0x0ed0, 0x0ed9 }, { 0x0f20, 0x0f29 }, /* Extender */ { 0xb7 , 0 }, { 0x02d0, 0 }, { 0x02d1, 0 }, { 0x0387, 0 }, { 0x0640, 0 }, { 0x0e46, 0 }, { 0x0ec6, 0 }, { 0x3005, 0 }, { 0x3031, 0x3035 }, { 0x309d, 0x309e }, { 0x30fc, 0x30fe }, }; static void setTab(char *tab, struct range *ranges, size_t nRanges) { size_t i; int j; for (i = 0; i < nRanges; i++) { if (ranges[i].end) { for (j = ranges[i].start; j <= ranges[i].end; j++) tab[j] = 1; } else tab[ranges[i].start] = 1; } } static void printTabs(char *tab) { int nBitmaps = 2; int i, j, k; unsigned char pageIndex[512]; printf( "static const unsigned namingBitmap[] = {\n\ 0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\ 0x00000000, 0x00000000, 0x00000000, 0x00000000,\n\ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,\n\ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,\n"); for (i = 0; i < 512; i++) { int kind = tab[i*256]; for (j = 1; j < 256; j++) if (tab[i*256 +j] != kind) { kind = -1; break; } if (i >= 256 && memcmp(tab + (i - 256)*256, tab + i*256, 256) == 0) pageIndex[i] = pageIndex[i - 256]; else if (kind == -1) { pageIndex[i] = nBitmaps++; for (j = 0; j < 8; j++) { unsigned val = 0; for (k = 0; k < 32; k++) { if (tab[i*256 + j*32 +k]) val |= (1 << k); } printf("0x%08X,", val); putchar((((j + 1) & 3) == 0) ? '\n' : ' '); } } else pageIndex[i] = kind; } printf("};\n"); printf("static const unsigned char nmstrtPages[] = {\n"); for (i = 0; i < 512; i++) { if (i == 256) printf("};\nstatic const unsigned char namePages[] = {\n"); printf("0x%02X,", pageIndex[i]); putchar((((i + 1) & 7) == 0) ? '\n' : ' '); } printf("};\n"); } int main(int const argc ATTR_UNUSED, char ** const argv ATTR_UNUSED) { char tab[2*65536]; memset(tab, 0, 65536); setTab(tab, nmstrt, sizeof(nmstrt)/sizeof(nmstrt[0])); memcpy(tab + 65536, tab, 65536); setTab(tab + 65536, name, sizeof(name)/sizeof(name[0])); printTabs(tab); return 0; } xmlrpc-c-1.33.14/lib/expat/xmlparse/000077500000000000000000000000001236133176700171435ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/expat/xmlparse/Makefile000066400000000000000000000053151236133176700206070ustar00rootroot00000000000000############################################################################### # This directory builds libxmlrpc_xmlparse, an XML parser. This is # essentially the separately distributed Expat library from 2001, but # with slight changes. The main reason it is bundled with Xmlrpc-c is # to make the latter easier to build and use. # # The library is about XML in general. There is nothing specific to # XML-RPC here. ############################################################################### ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') EXPATDIR := $(call updir,$(CURDIR)) LIBDIR := $(call updir,$(EXPATDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/expat/xmlparse XMLTOKDIR = srcdir/lib/expat/xmltok UTILDIR = srcdir/lib/util default: all include $(BLDDIR)/config.mk TARGET_LIBRARY_NAMES := libxmlrpc_xmlparse STATIC_LIBRARIES_TO_INSTALL = libxmlrpc_xmlparse.a SHARED_LIBS_TO_BUILD := libxmlrpc_xmlparse SHARED_LIBS_TO_INSTALL := libxmlrpc_xmlparse TARGET_MODS = xmlparse OMIT_XMLPARSE_LIB_RULE=Y MAJ=3 # Major number of shared libraries in this directory include $(SRCDIR)/common.mk INCLUDES = \ -I$(BLDDIR) \ -I$(XMLTOKDIR) \ -I$(UTILDIR)/include \ -Isrcdir/include \ # LIBDEP is the shared libraries on which libxmlrpc_abyss depends. # The runtime loader should load these libraries when it loads libxmlrpc_abyss. LIBDEP = $(LIBXMLRPC_XMLTOK) $(LIBXMLRPC_UTIL) XMLPARSE_SHLIB = $(call shlibfn,libxmlrpc_xmlparse) #XMLPARSE_SHLIB is e.g. libxmlrpc_xmlparse.so.3.1 XMLPARSE_SHLIBLE = $(call shliblefn,libxmlrpc_xmlparse) #XMLPARSE_SHLIBLE is e.g. libxmlrpc_xmlparse.so .PHONY: all all: libxmlrpc_xmlparse.a $(TARGET_SHARED_LIBRARIES) $(TARGET_SHARED_LE_LIBS) # Rule for this is in common.mk, courtesy of TARGET_LIBRARY_NAMES: $(XMLPARSE_SHLIB): $(TARGET_MODS:%=%.osh) $(LIBDEP) $(XMLPARSE_SHLIB): LIBOBJECTS = $(TARGET_MODS:%=%.osh) $(LIBDEP) # Rule for this is in common.mk, courtesy of TARGET_STATIC_LIBRARIES: libxmlrpc_xmlparse.a: $(TARGET_MODS:%=%.o) libxmlrpc_xmlparse.a: LIBOBJECTS = $(TARGET_MODS:%=%.o) #----------------------------------------------------------------------------- # RULES TO COMPILE OBJECT MODULES FOR LIBRARIES #----------------------------------------------------------------------------- # Rules to compile object modules from which to build the static and shared # library are in common.mk, courtesy of TARGET_MODS. .PHONY: install install: install-common .PHONY: clean distclean clean: clean-common distclean: clean distclean-common .PHONY: dep dep: dep-common # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir include depend.mk xmlrpc-c-1.33.14/lib/expat/xmlparse/xmlparse.c000066400000000000000000004323461236133176700211560ustar00rootroot00000000000000/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ /* In 2001, this was part of the Expat package. We copied it into Xmlrpc-c because it's easier on the user than making him get and link Expat separately, and we don't expect to benefit from separate maintenance of Expat. But we changed all the external symbols that in Expat are named "XML_xxxx" to "xmlrpc_XML_xxxx" because people do link Xmlrpc-c libraries into programs that also link Expat (a good example is where an Apache module uses Xmlrpc-c). We don't want our names to collide with Expat's. */ #include #include #include /* UINT_MAX */ #include /* time() */ #include "xmlrpc_config.h" #include "c_util.h" #include "girmath.h" #include "mallocvar.h" #include "xmlrpc-c/string_int.h" #include "xmldef.h" #include "xmlparse.h" static const char * extractXmlSample(const char * const start, const char * const end, size_t const maximumLen) { size_t const len = MIN(maximumLen, (size_t)(end - start)); return xmlrpc_makePrintable_lp(start, len); } #define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX #define XmlConvert XmlUtf8Convert #define XmlGetInternalEncoding xmlrpc_XmlGetUtf8InternalEncoding #define XmlGetInternalEncodingNS xmlrpc_XmlGetUtf8InternalEncodingNS #define XmlEncode xmlrpc_XmlUtf8Encode #define MUST_CONVERT(enc, s) (!(enc)->isUtf8) typedef char ICHAR; #ifndef XML_NS #define XmlInitEncodingNS XmlInitEncoding #define XmlInitUnknownEncodingNS XmlInitUnknownEncoding #undef XmlGetInternalEncodingNS #define XmlGetInternalEncodingNS XmlGetInternalEncoding #define XmlParseXmlDeclNS XmlParseXmlDecl #endif /* XML_T is a vestige of conditionally compiled code that was never used in Xmlrpc-c that made characters 16 bits. In that case, XML_T was defined differently. */ #define XML_T(x) x /* Round up n to be a multiple of sz, where sz is a power of 2. */ #define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) #include "xmltok.h" #include "xmlrole.h" typedef const XML_Char *KEY; typedef struct { KEY name; } NAMED; typedef struct { NAMED **v; size_t size; size_t used; size_t usedLim; } HASH_TABLE; typedef struct { NAMED **p; NAMED **end; } HASH_TABLE_ITER; #define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ #define INIT_DATA_BUF_SIZE 1024 #define INIT_ATTS_SIZE 16 #define INIT_BLOCK_SIZE 1024 #define INIT_BUFFER_SIZE 1024 #define EXPAND_SPARE 24 typedef struct binding { struct prefix *prefix; struct binding *nextTagBinding; struct binding *prevPrefixBinding; const struct attribute_id *attId; XML_Char *uri; int uriLen; int uriAlloc; } BINDING; typedef struct prefix { const XML_Char *name; BINDING *binding; } PREFIX; typedef struct { const XML_Char *str; const XML_Char *localPart; int uriLen; } TAG_NAME; typedef struct tag { struct tag *parent; const char *rawName; int rawNameLength; TAG_NAME name; char *buf; char *bufEnd; BINDING *bindings; } TAG; typedef struct { const XML_Char *name; const XML_Char *textPtr; size_t textLen; const XML_Char *systemId; const XML_Char *base; const XML_Char *publicId; const XML_Char *notation; char open; } ENTITY; typedef struct block { struct block *next; int size; XML_Char s[1]; } BLOCK; typedef struct { BLOCK *blocks; BLOCK *freeBlocks; const XML_Char *end; XML_Char *ptr; XML_Char *start; } STRING_POOL; /* The XML_Char before the name is used to determine whether an attribute has been specified. */ typedef struct attribute_id { XML_Char *name; PREFIX *prefix; char maybeTokenized; char xmlns; } ATTRIBUTE_ID; typedef struct { const ATTRIBUTE_ID *id; char isCdata; const XML_Char *value; } DEFAULT_ATTRIBUTE; typedef struct { const XML_Char *name; PREFIX *prefix; const ATTRIBUTE_ID *idAtt; int nDefaultAtts; int allocDefaultAtts; DEFAULT_ATTRIBUTE *defaultAtts; } ELEMENT_TYPE; typedef struct { HASH_TABLE generalEntities; HASH_TABLE elementTypes; HASH_TABLE attributeIds; HASH_TABLE prefixes; STRING_POOL pool; int complete; int standalone; HASH_TABLE paramEntities; PREFIX defaultPrefix; } DTD; typedef struct open_internal_entity { const char *internalEventPtr; const char *internalEventEndPtr; struct open_internal_entity *next; ENTITY *entity; } OPEN_INTERNAL_ENTITY; typedef void Processor(XML_Parser parser, const char * const start, const char * const end, const char ** const endPtr, enum XML_Error * const errorCodeP, const char ** const errorP); static int setContext(XML_Parser parser, const XML_Char *context); #define poolStart(pool) ((pool)->start) #define poolEnd(pool) ((pool)->ptr) #define poolLength(pool) ((pool)->ptr - (pool)->start) #define poolChop(pool) ((void)--(pool->ptr)) #define poolLastChar(pool) (((pool)->ptr)[-1]) #define poolDiscard(pool) ((pool)->ptr = (pool)->start) #define poolFinish(pool) ((pool)->start = (pool)->ptr) #define poolAppendChar(pool, c) \ (((pool)->ptr == (pool)->end && !poolGrow(pool)) \ ? 0 \ : ((*((pool)->ptr)++ = c), 1)) typedef struct { /* The first member must be userData so that the XML_GetUserData macro works. */ void *m_userData; void *m_handlerArg; char *m_buffer; /* first character to be parsed */ const char *m_bufferPtr; /* past last character to be parsed */ char *m_bufferEnd; /* allocated end of buffer */ const char *m_bufferLim; long m_parseEndByteIndex; const char *m_parseEndPtr; XML_Char *m_dataBuf; XML_Char *m_dataBufEnd; XML_StartElementHandler m_startElementHandler; XML_EndElementHandler m_endElementHandler; XML_CharacterDataHandler m_characterDataHandler; XML_ProcessingInstructionHandler m_processingInstructionHandler; XML_CommentHandler m_commentHandler; XML_StartCdataSectionHandler m_startCdataSectionHandler; XML_EndCdataSectionHandler m_endCdataSectionHandler; XML_DefaultHandler m_defaultHandler; XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; XML_NotationDeclHandler m_notationDeclHandler; XML_ExternalParsedEntityDeclHandler m_externalParsedEntityDeclHandler; XML_InternalParsedEntityDeclHandler m_internalParsedEntityDeclHandler; XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; XML_NotStandaloneHandler m_notStandaloneHandler; XML_ExternalEntityRefHandler m_externalEntityRefHandler; void *m_externalEntityRefHandlerArg; XML_UnknownEncodingHandler m_unknownEncodingHandler; const ENCODING *m_encoding; INIT_ENCODING m_initEncoding; const ENCODING *m_internalEncoding; const XML_Char *m_protocolEncodingName; /* NULL if no encoding assigned */ int m_ns; void *m_unknownEncodingMem; void *m_unknownEncodingData; void *m_unknownEncodingHandlerData; void (*m_unknownEncodingRelease)(void *); PROLOG_STATE m_prologState; Processor *m_processor; /* The next processor to run */ enum XML_Error m_errorCode; /* Explanation of the failure of the most recent call to Expat. XML_ERROR_NONE means it didn't fail. This is redundant with m_errorString if the latter is non-null. The latter is newer and better. */ const char * m_errorString; /* malloc'ed string describing the failure of the most recent call to Expat. NULL means m_errorCode is the only error information available. */ const char *m_eventPtr; const char *m_eventEndPtr; const char *m_positionPtr; OPEN_INTERNAL_ENTITY *m_openInternalEntities; int m_defaultExpandInternalEntities; int m_tagLevel; ENTITY *m_declEntity; const XML_Char *m_declNotationName; const XML_Char *m_declNotationPublicId; ELEMENT_TYPE *m_declElementType; ATTRIBUTE_ID *m_declAttributeId; char m_declAttributeIsCdata; char m_declAttributeIsId; DTD m_dtd; const XML_Char *m_curBase; TAG *m_tagStack; TAG *m_freeTagList; BINDING *m_inheritedBindings; BINDING *m_freeBindingList; int m_attsSize; int m_nSpecifiedAtts; int m_idAttIndex; ATTRIBUTE *m_atts; POSITION m_position; STRING_POOL m_tempPool; STRING_POOL m_temp2Pool; char *m_groupConnector; unsigned m_groupSize; int m_hadExternalDoctype; XML_Char m_namespaceSeparator; enum XML_ParamEntityParsing m_paramEntityParsing; XML_Parser m_parentParser; unsigned long m_hash_secret_salt; } Parser; #define userData (((Parser *)parser)->m_userData) #define handlerArg (((Parser *)parser)->m_handlerArg) #define startElementHandler (((Parser *)parser)->m_startElementHandler) #define endElementHandler (((Parser *)parser)->m_endElementHandler) #define characterDataHandler (((Parser *)parser)->m_characterDataHandler) #define processingInstructionHandler (((Parser *)parser)->m_processingInstructionHandler) #define commentHandler (((Parser *)parser)->m_commentHandler) #define startCdataSectionHandler (((Parser *)parser)->m_startCdataSectionHandler) #define endCdataSectionHandler (((Parser *)parser)->m_endCdataSectionHandler) #define defaultHandler (((Parser *)parser)->m_defaultHandler) #define startDoctypeDeclHandler (((Parser *)parser)->m_startDoctypeDeclHandler) #define endDoctypeDeclHandler (((Parser *)parser)->m_endDoctypeDeclHandler) #define unparsedEntityDeclHandler (((Parser *)parser)->m_unparsedEntityDeclHandler) #define notationDeclHandler (((Parser *)parser)->m_notationDeclHandler) #define externalParsedEntityDeclHandler (((Parser *)parser)->m_externalParsedEntityDeclHandler) #define internalParsedEntityDeclHandler (((Parser *)parser)->m_internalParsedEntityDeclHandler) #define startNamespaceDeclHandler (((Parser *)parser)->m_startNamespaceDeclHandler) #define endNamespaceDeclHandler (((Parser *)parser)->m_endNamespaceDeclHandler) #define notStandaloneHandler (((Parser *)parser)->m_notStandaloneHandler) #define externalEntityRefHandler (((Parser *)parser)->m_externalEntityRefHandler) #define externalEntityRefHandlerArg (((Parser *)parser)->m_externalEntityRefHandlerArg) #define unknownEncodingHandler (((Parser *)parser)->m_unknownEncodingHandler) #define initEncoding (((Parser *)parser)->m_initEncoding) #define internalEncoding (((Parser *)parser)->m_internalEncoding) #define unknownEncodingMem (((Parser *)parser)->m_unknownEncodingMem) #define unknownEncodingData (((Parser *)parser)->m_unknownEncodingData) #define unknownEncodingHandlerData \ (((Parser *)parser)->m_unknownEncodingHandlerData) #define unknownEncodingRelease (((Parser *)parser)->m_unknownEncodingRelease) #define ns (((Parser *)parser)->m_ns) #define prologState (((Parser *)parser)->m_prologState) #define processor (((Parser *)parser)->m_processor) #define errorCode (((Parser *)parser)->m_errorCode) #define errorString (((Parser *)parser)->m_errorString) #define eventPtr (((Parser *)parser)->m_eventPtr) #define eventEndPtr (((Parser *)parser)->m_eventEndPtr) #define positionPtr (((Parser *)parser)->m_positionPtr) #define position (((Parser *)parser)->m_position) #define openInternalEntities (((Parser *)parser)->m_openInternalEntities) #define defaultExpandInternalEntities (((Parser *)parser)->m_defaultExpandInternalEntities) #define tagLevel (((Parser *)parser)->m_tagLevel) #define buffer (((Parser *)parser)->m_buffer) #define bufferPtr (((Parser *)parser)->m_bufferPtr) #define bufferEnd (((Parser *)parser)->m_bufferEnd) #define parseEndByteIndex (((Parser *)parser)->m_parseEndByteIndex) #define parseEndPtr (((Parser *)parser)->m_parseEndPtr) #define bufferLim (((Parser *)parser)->m_bufferLim) #define dataBuf (((Parser *)parser)->m_dataBuf) #define dataBufEnd (((Parser *)parser)->m_dataBufEnd) #define dtd (((Parser *)parser)->m_dtd) #define curBase (((Parser *)parser)->m_curBase) #define declEntity (((Parser *)parser)->m_declEntity) #define declNotationName (((Parser *)parser)->m_declNotationName) #define declNotationPublicId (((Parser *)parser)->m_declNotationPublicId) #define declElementType (((Parser *)parser)->m_declElementType) #define declAttributeId (((Parser *)parser)->m_declAttributeId) #define declAttributeIsCdata (((Parser *)parser)->m_declAttributeIsCdata) #define declAttributeIsId (((Parser *)parser)->m_declAttributeIsId) #define freeTagList (((Parser *)parser)->m_freeTagList) #define freeBindingList (((Parser *)parser)->m_freeBindingList) #define inheritedBindings (((Parser *)parser)->m_inheritedBindings) #define tagStack (((Parser *)parser)->m_tagStack) #define atts (((Parser *)parser)->m_atts) #define attsSize (((Parser *)parser)->m_attsSize) #define nSpecifiedAtts (((Parser *)parser)->m_nSpecifiedAtts) #define idAttIndex (((Parser *)parser)->m_idAttIndex) #define tempPool (((Parser *)parser)->m_tempPool) #define temp2Pool (((Parser *)parser)->m_temp2Pool) #define groupConnector (((Parser *)parser)->m_groupConnector) #define groupSize (((Parser *)parser)->m_groupSize) #define hadExternalDoctype (((Parser *)parser)->m_hadExternalDoctype) #define namespaceSeparator (((Parser *)parser)->m_namespaceSeparator) #define parentParser (((Parser *)parser)->m_parentParser) #define hash_secret_salt (((Parser *)parser)->m_hash_secret_salt) static void poolInit(STRING_POOL *pool) { pool->blocks = 0; pool->freeBlocks = 0; pool->start = 0; pool->ptr = 0; pool->end = 0; } static void poolClear(STRING_POOL *pool) { if (!pool->freeBlocks) pool->freeBlocks = pool->blocks; else { BLOCK *p = pool->blocks; while (p) { BLOCK *tem = p->next; p->next = pool->freeBlocks; pool->freeBlocks = p; p = tem; } } pool->blocks = 0; pool->start = 0; pool->ptr = 0; pool->end = 0; } static void poolDestroy(STRING_POOL *pool) { BLOCK *p = pool->blocks; while (p) { BLOCK *tem = p->next; free(p); p = tem; } pool->blocks = 0; p = pool->freeBlocks; while (p) { BLOCK *tem = p->next; free(p); p = tem; } pool->freeBlocks = 0; pool->ptr = 0; pool->start = 0; pool->end = 0; } static int poolGrow(STRING_POOL *pool) { if (pool->freeBlocks) { if (pool->start == 0) { pool->blocks = pool->freeBlocks; pool->freeBlocks = pool->freeBlocks->next; pool->blocks->next = 0; pool->start = pool->blocks->s; pool->end = pool->start + pool->blocks->size; pool->ptr = pool->start; return 1; } if (pool->end - pool->start < pool->freeBlocks->size) { BLOCK *tem = pool->freeBlocks->next; pool->freeBlocks->next = pool->blocks; pool->blocks = pool->freeBlocks; pool->freeBlocks = tem; memcpy(pool->blocks->s, pool->start, (pool->end - pool->start) * sizeof(XML_Char)); pool->ptr = pool->blocks->s + (pool->ptr - pool->start); pool->start = pool->blocks->s; pool->end = pool->start + pool->blocks->size; return 1; } } if (pool->blocks && pool->start == pool->blocks->s) { size_t const blockSize = (pool->end - pool->start)*2; BLOCK *temp = realloc(pool->blocks, offsetof(BLOCK, s) + blockSize * sizeof(XML_Char)); if (!temp) return 0; pool->blocks = temp; pool->blocks->size = blockSize; pool->ptr = pool->blocks->s + (pool->ptr - pool->start); pool->start = pool->blocks->s; pool->end = pool->start + blockSize; } else { size_t const poolLen = pool->end - pool->start; size_t const blockSize = poolLen < INIT_BLOCK_SIZE ? INIT_BLOCK_SIZE : poolLen * 2; BLOCK *tem; tem = malloc(offsetof(BLOCK, s) + blockSize * sizeof(XML_Char)); if (!tem) return 0; tem->size = blockSize; tem->next = pool->blocks; pool->blocks = tem; if (pool->ptr != pool->start) memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char)); pool->ptr = tem->s + (pool->ptr - pool->start); pool->start = tem->s; pool->end = tem->s + blockSize; } return 1; } static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end) { if (!pool->ptr && !poolGrow(pool)) return 0; for (;;) { XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); if (ptr == end) break; if (!poolGrow(pool)) return 0; } return pool->start; } static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s) { do { if (!poolAppendChar(pool, *s)) return 0; } while (*s++); s = pool->start; poolFinish(pool); return s; } static const XML_Char * poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) { if (!pool->ptr && !poolGrow(pool)) return 0; for (; n > 0; --n, s++) { if (!poolAppendChar(pool, *s)) return 0; } s = pool->start; poolFinish(pool); return s; } static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc, const char *ptr, const char *end) { if (!poolAppend(pool, enc, ptr, end)) return 0; if (pool->ptr == pool->end && !poolGrow(pool)) return 0; *(pool->ptr)++ = 0; return pool->start; } static unsigned long generate_hash_secret_salt(void) { unsigned int seed = time(NULL) % UINT_MAX; srand(seed); return rand(); } static int /* only valid for root parser */ startParsing(XML_Parser parser) { static const XML_Char implicitContext[] = { XML_T('x'), XML_T('m'), XML_T('l'), XML_T('='), XML_T('h'), XML_T('t'), XML_T('t'), XML_T('p'), XML_T(':'), XML_T('/'), XML_T('/'), XML_T('w'), XML_T('w'), XML_T('w'), XML_T('.'), XML_T('w'), XML_T('3'), XML_T('.'), XML_T('o'), XML_T('r'), XML_T('g'), XML_T('/'), XML_T('X'), XML_T('M'), XML_T('L'), XML_T('/'), XML_T('1'), XML_T('9'), XML_T('9'), XML_T('8'), XML_T('/'), XML_T('n'), XML_T('a'), XML_T('m'), XML_T('e'), XML_T('s'), XML_T('p'), XML_T('a'), XML_T('c'), XML_T('e'), XML_T('\0') }; /* hash functions must be initialized before setContext() is called */ if (hash_secret_salt == 0) hash_secret_salt = generate_hash_secret_salt(); if (parser) return setContext(parser, implicitContext); return 0; } #define INIT_SIZE 64 static int keyeq(KEY s1, KEY s2) { for (; *s1 == *s2; s1++, s2++) if (*s1 == 0) return 1; return 0; } static unsigned long hash(XML_Parser parser, KEY s) { unsigned long h = hash_secret_salt; while (*s) h = (h << 5) + h + (unsigned char)*s++; return h; } static NAMED *lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { size_t i; if (table->size == 0) { if (!createSize) return 0; table->v = calloc(INIT_SIZE, sizeof(NAMED *)); if (!table->v) return 0; table->size = INIT_SIZE; table->usedLim = INIT_SIZE / 2; i = hash(parser, name) & (table->size - 1); } else { unsigned long h = hash(parser, name); for (i = h & (table->size - 1); table->v[i]; i == 0 ? i = table->size - 1 : --i) { if (keyeq(name, table->v[i]->name)) return table->v[i]; } if (!createSize) return 0; if (table->used == table->usedLim) { /* check for overflow */ size_t newSize = table->size * 2; NAMED **newV = calloc(newSize, sizeof(NAMED *)); if (!newV) return 0; for (i = 0; i < table->size; i++) if (table->v[i]) { size_t j; for (j = hash(parser, table->v[i]->name) & (newSize - 1); newV[j]; j == 0 ? j = newSize - 1 : --j) ; newV[j] = table->v[i]; } free(table->v); table->v = newV; table->size = newSize; table->usedLim = newSize/2; for (i = h & (table->size - 1); table->v[i]; i == 0 ? i = table->size - 1 : --i) ; } } table->v[i] = calloc(1, createSize); if (!table->v[i]) return 0; table->v[i]->name = name; (table->used)++; return table->v[i]; } static void hashTableDestroy(HASH_TABLE *table) { size_t i; for (i = 0; i < table->size; i++) { NAMED *p = table->v[i]; if (p) free(p); } if (table->v) free(table->v); } static void hashTableInit(HASH_TABLE *p) { p->size = 0; p->usedLim = 0; p->used = 0; p->v = 0; } static void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) { iter->p = table->v; iter->end = iter->p + table->size; } static NAMED *hashTableIterNext(HASH_TABLE_ITER *iter) { while (iter->p != iter->end) { NAMED *tem = *(iter->p)++; if (tem) return tem; } return 0; } static int dtdInit(DTD *p) { poolInit(&(p->pool)); hashTableInit(&(p->generalEntities)); hashTableInit(&(p->elementTypes)); hashTableInit(&(p->attributeIds)); hashTableInit(&(p->prefixes)); p->complete = 1; p->standalone = 0; hashTableInit(&(p->paramEntities)); p->defaultPrefix.name = 0; p->defaultPrefix.binding = 0; return 1; } static void dtdSwap(DTD *p1, DTD *p2) { DTD tem; memcpy(&tem, p1, sizeof(DTD)); memcpy(p1, p2, sizeof(DTD)); memcpy(p2, &tem, sizeof(DTD)); } static void dtdDestroy(DTD *p) { HASH_TABLE_ITER iter; hashTableIterInit(&iter, &(p->elementTypes)); for (;;) { ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); if (!e) break; if (e->allocDefaultAtts != 0) free(e->defaultAtts); } hashTableDestroy(&(p->generalEntities)); hashTableDestroy(&(p->paramEntities)); hashTableDestroy(&(p->elementTypes)); hashTableDestroy(&(p->attributeIds)); hashTableDestroy(&(p->prefixes)); poolDestroy(&(p->pool)); } static int copyEntityTable(XML_Parser oldParser, HASH_TABLE *newTable, STRING_POOL *newPool, const HASH_TABLE *oldTable) { HASH_TABLE_ITER iter; const XML_Char *cachedOldBase = 0; const XML_Char *cachedNewBase = 0; hashTableIterInit(&iter, oldTable); for (;;) { ENTITY *newE; const XML_Char *name; const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); if (!oldE) break; name = poolCopyString(newPool, oldE->name); if (!name) return 0; newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); if (!newE) return 0; if (oldE->systemId) { const XML_Char *tem = poolCopyString(newPool, oldE->systemId); if (!tem) return 0; newE->systemId = tem; if (oldE->base) { if (oldE->base == cachedOldBase) newE->base = cachedNewBase; else { cachedOldBase = oldE->base; tem = poolCopyString(newPool, cachedOldBase); if (!tem) return 0; cachedNewBase = newE->base = tem; } } } else { const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr, oldE->textLen); if (!tem) return 0; newE->textPtr = tem; newE->textLen = oldE->textLen; } if (oldE->notation) { const XML_Char *tem = poolCopyString(newPool, oldE->notation); if (!tem) return 0; newE->notation = tem; } } return 1; } /* Do a deep copy of the DTD. Return 0 for out of memory; non-zero otherwise. The new DTD has already been initialized. */ static int dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd) { HASH_TABLE_ITER iter; /* Copy the prefix table. */ hashTableIterInit(&iter, &(oldDtd->prefixes)); for (;;) { const XML_Char *name; const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter); if (!oldP) break; name = poolCopyString(&(newDtd->pool), oldP->name); if (!name) return 0; if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) return 0; } hashTableIterInit(&iter, &(oldDtd->attributeIds)); /* Copy the attribute id table. */ for (;;) { ATTRIBUTE_ID *newA; const XML_Char *name; const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); if (!oldA) break; /* Remember to allocate the scratch byte before the name. */ if (!poolAppendChar(&(newDtd->pool), XML_T('\0'))) return 0; name = poolCopyString(&(newDtd->pool), oldA->name); if (!name) return 0; ++name; newA = (ATTRIBUTE_ID *) lookup(oldParser, &(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID)); if (!newA) return 0; newA->maybeTokenized = oldA->maybeTokenized; if (oldA->prefix) { newA->xmlns = oldA->xmlns; if (oldA->prefix == &oldDtd->defaultPrefix) newA->prefix = &newDtd->defaultPrefix; else newA->prefix = (PREFIX *) lookup(oldParser, &(newDtd->prefixes), oldA->prefix->name, 0); } } /* Copy the element type table. */ hashTableIterInit(&iter, &(oldDtd->elementTypes)); for (;;) { int i; ELEMENT_TYPE *newE; const XML_Char *name; const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); if (!oldE) break; name = poolCopyString(&(newDtd->pool), oldE->name); if (!name) return 0; newE = (ELEMENT_TYPE *) lookup(oldParser, &(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE)); if (!newE) return 0; if (oldE->nDefaultAtts) { newE->defaultAtts = (DEFAULT_ATTRIBUTE *) malloc(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); if (!newE->defaultAtts) return 0; } if (oldE->idAtt) newE->idAtt = (ATTRIBUTE_ID *) lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; if (oldE->prefix) newE->prefix = (PREFIX *) lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { newE->defaultAtts[i].id = (ATTRIBUTE_ID *) lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); if (!newE->defaultAtts[i].value) return 0; } else newE->defaultAtts[i].value = 0; } } /* Copy the entity tables. */ if (!copyEntityTable(oldParser, &(newDtd->generalEntities), &(newDtd->pool), &(oldDtd->generalEntities))) return 0; if (!copyEntityTable(oldParser, &(newDtd->paramEntities), &(newDtd->pool), &(oldDtd->paramEntities))) return 0; newDtd->complete = oldDtd->complete; newDtd->standalone = oldDtd->standalone; return 1; } static int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr) { BINDING *b; int len; for (len = 0; uri[len]; len++) ; if (namespaceSeparator) len++; if (freeBindingList) { b = freeBindingList; if (len > b->uriAlloc) { XML_Char *temp = realloc(b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE)); if (!temp) return 0; b->uri = temp; b->uriAlloc = len + EXPAND_SPARE; } freeBindingList = b->nextTagBinding; } else { b = malloc(sizeof(BINDING)); if (!b) return 0; b->uri = malloc(sizeof(XML_Char) * (len + EXPAND_SPARE)); if (!b->uri) { free(b); return 0; } b->uriAlloc = len + EXPAND_SPARE; } b->uriLen = len; memcpy(b->uri, uri, len * sizeof(XML_Char)); if (namespaceSeparator) b->uri[len - 1] = namespaceSeparator; b->prefix = prefix; b->attId = attId; b->prevPrefixBinding = prefix->binding; if (*uri == XML_T('\0') && prefix == &dtd.defaultPrefix) prefix->binding = 0; else prefix->binding = b; b->nextTagBinding = *bindingsPtr; *bindingsPtr = b; if (startNamespaceDeclHandler) startNamespaceDeclHandler(handlerArg, prefix->name, prefix->binding ? uri : 0); return 1; } #define CONTEXT_SEP XML_T('\f') static const XML_Char *getContext(XML_Parser parser) { HASH_TABLE_ITER iter; int needSep = 0; if (dtd.defaultPrefix.binding) { int i; int len; if (!poolAppendChar(&tempPool, XML_T('='))) return 0; len = dtd.defaultPrefix.binding->uriLen; if (namespaceSeparator != XML_T('\0')) len--; for (i = 0; i < len; i++) if (!poolAppendChar(&tempPool, dtd.defaultPrefix.binding->uri[i])) return 0; needSep = 1; } hashTableIterInit(&iter, &(dtd.prefixes)); for (;;) { int i; int len; const XML_Char *s; PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); if (!prefix) break; if (!prefix->binding) continue; if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) return 0; for (s = prefix->name; *s; s++) if (!poolAppendChar(&tempPool, *s)) return 0; if (!poolAppendChar(&tempPool, XML_T('='))) return 0; len = prefix->binding->uriLen; if (namespaceSeparator != XML_T('\0')) len--; for (i = 0; i < len; i++) if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) return 0; needSep = 1; } hashTableIterInit(&iter, &(dtd.generalEntities)); for (;;) { const XML_Char *s; ENTITY *e = (ENTITY *)hashTableIterNext(&iter); if (!e) break; if (!e->open) continue; if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) return 0; for (s = e->name; *s; s++) if (!poolAppendChar(&tempPool, *s)) return 0; needSep = 1; } if (!poolAppendChar(&tempPool, XML_T('\0'))) return 0; return tempPool.start; } static int setContext(XML_Parser parser, const XML_Char *context) { const XML_Char *s = context; while (*context != XML_T('\0')) { if (*s == CONTEXT_SEP || *s == XML_T('\0')) { ENTITY *e; if (!poolAppendChar(&tempPool, XML_T('\0'))) return 0; e = (ENTITY *)lookup(parser, &dtd.generalEntities, poolStart(&tempPool), 0); if (e) e->open = 1; if (*s != XML_T('\0')) s++; context = s; poolDiscard(&tempPool); } else if (*s == '=') { PREFIX *prefix; if (poolLength(&tempPool) == 0) prefix = &dtd.defaultPrefix; else { if (!poolAppendChar(&tempPool, XML_T('\0'))) return 0; prefix = (PREFIX *) lookup(parser, &dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX)); if (!prefix) return 0; if (prefix->name == poolStart(&tempPool)) { prefix->name = poolCopyString(&dtd.pool, prefix->name); if (!prefix->name) return 0; } poolDiscard(&tempPool); } for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0'); ++context) if (!poolAppendChar(&tempPool, *context)) return 0; if (!poolAppendChar(&tempPool, XML_T('\0'))) return 0; if (!addBinding(parser, prefix, 0, poolStart(&tempPool), &inheritedBindings)) return 0; poolDiscard(&tempPool); if (*context != XML_T('\0')) ++context; s = context; } else { if (!poolAppendChar(&tempPool, *s)) return 0; s++; } } return 1; } static void normalizeLines(XML_Char *s) { XML_Char *p; for (;; s++) { if (*s == XML_T('\0')) return; if (*s == 0xD) break; } p = s; do { if (*s == 0xD) { *p++ = 0xA; if (*++s == 0xA) s++; } else *p++ = *s++; } while (*s); *p = XML_T('\0'); } struct EventPtr { const char ** startP; const char ** endP; }; static struct EventPtr getEventPtr(XML_Parser const xmlParserP, const ENCODING * const encoderP) { Parser * const parserP = xmlParserP; struct EventPtr retval; if (encoderP == parserP->m_encoding) { retval.startP = &parserP->m_eventPtr; retval.endP = &parserP->m_eventEndPtr; } else { retval.startP = &parserP->m_openInternalEntities->internalEventPtr; retval.endP = &parserP->m_openInternalEntities->internalEventEndPtr; } return retval; } static void reportDefault(XML_Parser const xmlParserP, const ENCODING * const encoderP, const char * const start, const char * const end) { Parser * const parser = (Parser *)xmlParserP; if (MUST_CONVERT(encoderP, start)) { struct EventPtr const evPtr = getEventPtr(xmlParserP, encoderP); const char * inCursor; inCursor = start; do { ICHAR * dataPtr; dataPtr = (ICHAR *)parser->m_dataBuf; /* initial value */ XmlConvert(encoderP, &inCursor, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd); *evPtr.endP = inCursor; { size_t const len = dataPtr - (ICHAR *)parser->m_dataBuf; assert((size_t)(int)len == len); /* parser requirement */ defaultHandler(parser->m_handlerArg, parser->m_dataBuf, (int)len); } *evPtr.startP = inCursor; } while (inCursor != end); } else { size_t const len = (XML_Char *)end - (XML_Char *)start; assert((size_t)(int)len == len); /* parser requirement */ defaultHandler(parser->m_handlerArg, (XML_Char *)start, len); } } static void processDataCharsToken(XML_Parser * const xmlParserP, const ENCODING * const encoderP, const char * const tokenStart, const char * const tokenEnd) { Parser * const parser = (Parser *)xmlParserP; /* For use by macros */ if (characterDataHandler) { if (MUST_CONVERT(encoderP, tokenStart)) { struct EventPtr const evPtr = getEventPtr(xmlParserP, encoderP); const char * inCursor; for (inCursor = tokenStart; inCursor < tokenEnd;) { ICHAR * outCursor; outCursor = (ICHAR *)dataBuf; *evPtr.startP = inCursor; assert((ICHAR *)dataBufEnd - (ICHAR *)dataBuf >= 4); XmlConvert(encoderP, &inCursor, tokenEnd, &outCursor, (ICHAR *)dataBufEnd); *evPtr.endP = inCursor; { size_t const len = outCursor - (ICHAR *)dataBuf; assert((size_t)(int)len == len); /* parser reqt */ characterDataHandler(handlerArg, dataBuf, (int)len); } } } else { size_t const len = (XML_Char *)tokenEnd - (XML_Char *)tokenStart; assert((size_t)(int)len == len); /* parser reqt */ characterDataHandler(handlerArg, (XML_Char *)tokenStart, len); } } else if (defaultHandler) reportDefault(xmlParserP, encoderP, tokenStart, tokenEnd); } static int reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) { const XML_Char *target; XML_Char *data; const char *tem; if (!processingInstructionHandler) { if (defaultHandler) reportDefault(parser, enc, start, end); return 1; } start += enc->minBytesPerChar * 2; tem = start + XmlNameLength(enc, start); target = poolStoreString(&tempPool, enc, start, tem); if (!target) return 0; poolFinish(&tempPool); data = poolStoreString(&tempPool, enc, XmlSkipS(enc, tem), end - enc->minBytesPerChar*2); if (!data) return 0; normalizeLines(data); processingInstructionHandler(handlerArg, target, data); poolClear(&tempPool); return 1; } static int reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) { XML_Char *data; if (!commentHandler) { if (defaultHandler) reportDefault(parser, enc, start, end); return 1; } data = poolStoreString(&tempPool, enc, start + enc->minBytesPerChar * 4, end - enc->minBytesPerChar * 3); if (!data) return 0; normalizeLines(data); commentHandler(handlerArg, data); poolClear(&tempPool); return 1; } static void initXmlEncoding(XML_Encoding * const xmlEncP) { unsigned int i; for (i = 0; i < ARRAY_SIZE(xmlEncP->map); ++i) xmlEncP->map[i] = -1; xmlEncP->convert = 0; xmlEncP->data = 0; xmlEncP->release = 0; } static enum XML_Error handleUnknownEncoding(XML_Parser const xmlParserP, const XML_Char * const encodingName) { Parser * const parser = (Parser *) xmlParserP; if (unknownEncodingHandler) { XML_Encoding info; initXmlEncoding(&info); if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, &info)) { ENCODING * enc; unknownEncodingMem = malloc(xmlrpc_XmlSizeOfUnknownEncoding()); if (!unknownEncodingMem) { if (info.release) info.release(info.data); return XML_ERROR_NO_MEMORY; } enc = (ns ? xmlrpc_XmlInitUnknownEncodingNS : xmlrpc_XmlInitUnknownEncoding)(unknownEncodingMem, info.map, info.convert, info.data); if (enc) { unknownEncodingData = info.data; unknownEncodingRelease = info.release; parser->m_encoding = enc; return XML_ERROR_NONE; } } if (info.release) info.release(info.data); } return XML_ERROR_UNKNOWN_ENCODING; } static enum XML_Error initializeEncoding(XML_Parser const xmlParserP) { Parser * const parser = (Parser *) xmlParserP; enum XML_Error retval; int rc; rc = (ns ? xmlrpc_XmlInitEncodingNS : xmlrpc_XmlInitEncoding)( &parser->m_initEncoding, &parser->m_encoding, parser->m_protocolEncodingName); if (rc == 0) { /* 'parser->m_protocolEncodingName' is not a recognized name */ retval = handleUnknownEncoding(xmlParserP, parser->m_protocolEncodingName); } else retval = XML_ERROR_NONE; return retval; } static void handleUnknownEncoding0(XML_Parser const xmlParserP, const char * const encodingName, const ENCODING * const encoding, STRING_POOL * const tempPoolP, enum XML_Error * const resultP) { const XML_Char * const s = poolStoreString(tempPoolP, encoding, encodingName, encodingName + XmlNameLength(encoding, encodingName)); if (s) { *resultP = handleUnknownEncoding(xmlParserP, s); poolDiscard(tempPoolP); } else *resultP = XML_ERROR_NO_MEMORY; } static void processXmlDecl(XML_Parser const xmlParserP, int const isGeneralTextEntity, const char * const s, const char * const next, enum XML_Error * const resultP) { /*---------------------------------------------------------------------------- Process an XML declaration processing instruction (PI), i.e. If *xmlParserP does not already have an encoding assigned and the declaration names an encoding, set that up as the encoding for the parser if possible. If *xmlParserP already has an encoding assigned, ignore any encoding specification in the declaration, even errors in it. -----------------------------------------------------------------------------*/ Parser * const parserP = (Parser *) xmlParserP; const char *encodingName = 0; const ENCODING *newEncodingP = 0; const char *version; int standalone = -1; bool validSyntax; validSyntax = (parserP->m_ns ? xmlrpc_XmlParseXmlDeclNS : xmlrpc_XmlParseXmlDecl)(isGeneralTextEntity, parserP->m_encoding, s, next, &parserP->m_eventPtr, &version, &encodingName, &newEncodingP, &standalone); if (!validSyntax) { *resultP = XML_ERROR_SYNTAX; /* parserP->m_eventPtr points to the invalid part */ } else { if (!isGeneralTextEntity && standalone == 1) { parserP->m_dtd.standalone = 1; if (parserP->m_paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) parserP->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; } if (parserP->m_defaultHandler) reportDefault(xmlParserP, parserP->m_encoding, s, next); if (parserP->m_protocolEncodingName) *resultP = XML_ERROR_NONE; else { if (newEncodingP) { /* The declaration names an encoding and the parser recognized the name as referring to 'newEncodingP'. */ if (newEncodingP->minBytesPerChar != parserP->m_encoding->minBytesPerChar) { parserP->m_eventPtr = encodingName; *resultP = XML_ERROR_INCORRECT_ENCODING; } else { parserP->m_encoding = newEncodingP; *resultP = XML_ERROR_NONE; } } else { if (encodingName) { /* The declaration names an encoding, but the parser didn't recognize the name. */ enum XML_Error result; handleUnknownEncoding0(xmlParserP, encodingName, parserP->m_encoding, &parserP->m_tempPool, &result); if (result == XML_ERROR_UNKNOWN_ENCODING) parserP->m_eventPtr = encodingName; *resultP = result; } else /* The declaration doesn't name an encoding */ *resultP = XML_ERROR_NONE; } } } } static ATTRIBUTE_ID * getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end) { ATTRIBUTE_ID *id; const XML_Char *name; if (!poolAppendChar(&dtd.pool, XML_T('\0'))) return 0; name = poolStoreString(&dtd.pool, enc, start, end); if (!name) return 0; ++name; id = (ATTRIBUTE_ID *)lookup(parser, &dtd.attributeIds, name, sizeof(ATTRIBUTE_ID)); if (!id) return 0; if (id->name != name) poolDiscard(&dtd.pool); else { poolFinish(&dtd.pool); if (!ns) ; else if (name[0] == 'x' && name[1] == 'm' && name[2] == 'l' && name[3] == 'n' && name[4] == 's' && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) { if (name[5] == '\0') id->prefix = &dtd.defaultPrefix; else id->prefix = (PREFIX *)lookup(parser, &dtd.prefixes, name + 6, sizeof(PREFIX)); id->xmlns = 1; } else { int i; for (i = 0; name[i]; i++) { if (name[i] == XML_T(':')) { int j; for (j = 0; j < i; j++) { if (!poolAppendChar(&dtd.pool, name[j])) return 0; } if (!poolAppendChar(&dtd.pool, XML_T('\0'))) return 0; id->prefix = (PREFIX *) lookup(parser, &dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); if (id->prefix->name == poolStart(&dtd.pool)) poolFinish(&dtd.pool); else poolDiscard(&dtd.pool); break; } } } } return id; } static void normalizePublicId(XML_Char *publicId) { XML_Char *p = publicId; XML_Char *s; for (s = publicId; *s; s++) { switch (*s) { case 0x20: case 0xD: case 0xA: if (p != publicId && p[-1] != 0x20) *p++ = 0x20; break; default: *p++ = *s; } } if (p != publicId && p[-1] == 0x20) --p; *p = XML_T('\0'); } static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) { const XML_Char *name; for (name = elementType->name; *name; name++) { if (*name == XML_T(':')) { PREFIX *prefix; const XML_Char *s; for (s = elementType->name; s != name; s++) { if (!poolAppendChar(&dtd.pool, *s)) return 0; } if (!poolAppendChar(&dtd.pool, XML_T('\0'))) return 0; prefix = (PREFIX *) lookup(parser, &dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX)); if (!prefix) return 0; if (prefix->name == poolStart(&dtd.pool)) poolFinish(&dtd.pool); else poolDiscard(&dtd.pool); elementType->prefix = prefix; } } return 1; } static enum XML_Error appendAttributeValue(XML_Parser const xmlParserP, const ENCODING * const enc, int const isCdata, const char * const ptrArg, const char * const end, STRING_POOL * const pool) { Parser * const parser = (Parser *) xmlParserP; const char * ptr; ptr = ptrArg; for (;;) { const char *next; int tok = XmlAttributeValueTok(enc, ptr, end, &next); switch (tok) { case XML_TOK_NONE: return XML_ERROR_NONE; case XML_TOK_INVALID: if (enc == parser->m_encoding) eventPtr = next; return XML_ERROR_INVALID_TOKEN; case XML_TOK_PARTIAL: if (enc == parser->m_encoding) eventPtr = ptr; return XML_ERROR_INVALID_TOKEN; case XML_TOK_CHAR_REF: { XML_Char buf[XML_ENCODE_MAX]; int i; int n = XmlCharRefNumber(enc, ptr); if (n < 0) { if (enc == parser->m_encoding) eventPtr = ptr; return XML_ERROR_BAD_CHAR_REF; } if (!isCdata && n == 0x20 /* space */ && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) break; n = XmlEncode(n, (ICHAR *)buf); if (!n) { if (enc == parser->m_encoding) eventPtr = ptr; return XML_ERROR_BAD_CHAR_REF; } for (i = 0; i < n; i++) { if (!poolAppendChar(pool, buf[i])) return XML_ERROR_NO_MEMORY; } } break; case XML_TOK_DATA_CHARS: if (!poolAppend(pool, enc, ptr, next)) return XML_ERROR_NO_MEMORY; break; break; case XML_TOK_TRAILING_CR: next = ptr + enc->minBytesPerChar; /* fall through */ case XML_TOK_ATTRIBUTE_VALUE_S: case XML_TOK_DATA_NEWLINE: if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) break; if (!poolAppendChar(pool, 0x20)) return XML_ERROR_NO_MEMORY; break; case XML_TOK_ENTITY_REF: { const XML_Char *name; ENTITY *entity; XML_Char ch = XmlPredefinedEntityName(enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar); if (ch) { if (!poolAppendChar(pool, ch)) return XML_ERROR_NO_MEMORY; break; } name = poolStoreString(&temp2Pool, enc, ptr + enc->minBytesPerChar, next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; entity = (ENTITY *)lookup(parser, &dtd.generalEntities, name, 0); poolDiscard(&temp2Pool); if (!entity) { if (dtd.complete) { if (enc == parser->m_encoding) eventPtr = ptr; return XML_ERROR_UNDEFINED_ENTITY; } } else if (entity->open) { if (enc == parser->m_encoding) eventPtr = ptr; return XML_ERROR_RECURSIVE_ENTITY_REF; } else if (entity->notation) { if (enc == parser->m_encoding) eventPtr = ptr; return XML_ERROR_BINARY_ENTITY_REF; } else if (!entity->textPtr) { if (enc == parser->m_encoding) eventPtr = ptr; return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; } else { enum XML_Error result; const XML_Char *textEnd = entity->textPtr + entity->textLen; entity->open = 1; result = appendAttributeValue(xmlParserP, internalEncoding, isCdata, (char *)entity->textPtr, (char *)textEnd, pool); entity->open = 0; if (result) return result; } } break; default: abort(); } ptr = next; } /* not reached */ } static enum XML_Error storeAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata, const char *ptr, const char *end, STRING_POOL *pool) { enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, end, pool); if (result) return result; if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) poolChop(pool); if (!poolAppendChar(pool, XML_T('\0'))) return XML_ERROR_NO_MEMORY; return XML_ERROR_NONE; } static enum XML_Error storeEntityValue(XML_Parser const xmlParserP, const ENCODING * const enc, const char * const entityTextPtrArg, const char * const entityTextEnd) { Parser * const parser = (Parser *) xmlParserP; STRING_POOL * const pool = &(dtd.pool); const char * entityTextPtr; entityTextPtr = entityTextPtrArg; for (;;) { const char * next; int tok; tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); switch (tok) { case XML_TOK_PARAM_ENTITY_REF: if (parentParser || enc != parser->m_encoding) { enum XML_Error result; const XML_Char *name; ENTITY *entity; name = poolStoreString(&tempPool, enc, entityTextPtr + enc->minBytesPerChar, next - enc->minBytesPerChar); if (!name) return XML_ERROR_NO_MEMORY; entity = (ENTITY *)lookup(parser, &dtd.paramEntities, name, 0); poolDiscard(&tempPool); if (!entity) { if (enc == parser->m_encoding) eventPtr = entityTextPtr; return XML_ERROR_UNDEFINED_ENTITY; } if (entity->open) { if (enc == parser->m_encoding) eventPtr = entityTextPtr; return XML_ERROR_RECURSIVE_ENTITY_REF; } if (entity->systemId) { if (enc == parser->m_encoding) eventPtr = entityTextPtr; return XML_ERROR_PARAM_ENTITY_REF; } entity->open = 1; result = storeEntityValue(parser, internalEncoding, (char *)entity->textPtr, (char *)(entity->textPtr + entity->textLen)); entity->open = 0; if (result) return result; break; } eventPtr = entityTextPtr; return XML_ERROR_SYNTAX; case XML_TOK_NONE: return XML_ERROR_NONE; case XML_TOK_ENTITY_REF: case XML_TOK_DATA_CHARS: if (!poolAppend(pool, enc, entityTextPtr, next)) return XML_ERROR_NO_MEMORY; break; case XML_TOK_TRAILING_CR: next = entityTextPtr + enc->minBytesPerChar; /* fall through */ case XML_TOK_DATA_NEWLINE: if (pool->end == pool->ptr && !poolGrow(pool)) return XML_ERROR_NO_MEMORY; *(pool->ptr)++ = 0xA; break; case XML_TOK_CHAR_REF: { XML_Char buf[XML_ENCODE_MAX]; int i; int n = XmlCharRefNumber(enc, entityTextPtr); if (n < 0) { if (enc == parser->m_encoding) eventPtr = entityTextPtr; return XML_ERROR_BAD_CHAR_REF; } n = XmlEncode(n, (ICHAR *)buf); if (!n) { if (enc == parser->m_encoding) eventPtr = entityTextPtr; return XML_ERROR_BAD_CHAR_REF; } for (i = 0; i < n; i++) { if (pool->end == pool->ptr && !poolGrow(pool)) return XML_ERROR_NO_MEMORY; *(pool->ptr)++ = buf[i]; } } break; case XML_TOK_PARTIAL: if (enc == parser->m_encoding) eventPtr = entityTextPtr; return XML_ERROR_INVALID_TOKEN; case XML_TOK_INVALID: if (enc == parser->m_encoding) eventPtr = next; return XML_ERROR_INVALID_TOKEN; default: abort(); } entityTextPtr = next; } /* not reached */ } static int defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, int isCdata, int isId, const XML_Char *value) { DEFAULT_ATTRIBUTE *att; if (value || isId) { /* The handling of default attributes gets messed up if we have a default which duplicates a non-default. */ int i; for (i = 0; i < type->nDefaultAtts; i++) if (attId == type->defaultAtts[i].id) return 1; if (isId && !type->idAtt && !attId->xmlns) type->idAtt = attId; } if (type->nDefaultAtts == type->allocDefaultAtts) { if (type->allocDefaultAtts == 0) { type->allocDefaultAtts = 8; type->defaultAtts = malloc(type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); if (!type->defaultAtts) return 0; } else { DEFAULT_ATTRIBUTE *temp; type->allocDefaultAtts *= 2; temp = realloc(type->defaultAtts, type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE)); if (!temp) return 0; type->defaultAtts = temp; } } att = type->defaultAtts + type->nDefaultAtts; att->id = attId; att->value = value; att->isCdata = isCdata; if (!isCdata) attId->maybeTokenized = 1; type->nDefaultAtts += 1; return 1; } /* If tagNamePtr is non-null, build a real list of attributes, otherwise just check the attributes for well-formedness. */ static enum XML_Error storeAtts(XML_Parser const xmlParserP, const ENCODING * const enc, const char * const attStr, TAG_NAME * const tagNamePtr, BINDING ** const bindingsPtr) { Parser * const parser = (Parser *)xmlParserP; ELEMENT_TYPE *elementType = 0; int nDefaultAtts = 0; const XML_Char ** appAtts; /* the attribute list to pass to the application */ int attIndex = 0; int i; int n; int nPrefixes = 0; BINDING *binding; const XML_Char *localPart; /* lookup the element type name */ if (tagNamePtr) { elementType = (ELEMENT_TYPE *) lookup(parser, &dtd.elementTypes, tagNamePtr->str, 0); if (!elementType) { tagNamePtr->str = poolCopyString(&dtd.pool, tagNamePtr->str); if (!tagNamePtr->str) return XML_ERROR_NO_MEMORY; elementType = (ELEMENT_TYPE *) lookup(parser, &dtd.elementTypes, tagNamePtr->str, sizeof(ELEMENT_TYPE)); if (!elementType) return XML_ERROR_NO_MEMORY; if (ns && !setElementTypePrefix(xmlParserP, elementType)) return XML_ERROR_NO_MEMORY; } nDefaultAtts = elementType->nDefaultAtts; } /* get the attributes from the tokenizer */ n = XmlGetAttributes(enc, attStr, attsSize, atts); if (n + nDefaultAtts > attsSize) { int oldAttsSize = attsSize; ATTRIBUTE *temp; attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; temp = realloc((void *)atts, attsSize * sizeof(ATTRIBUTE)); if (!temp) return XML_ERROR_NO_MEMORY; atts = temp; if (n > oldAttsSize) XmlGetAttributes(enc, attStr, n, atts); } appAtts = (const XML_Char **)atts; for (i = 0; i < n; i++) { /* add the name and value to the attribute list */ ATTRIBUTE_ID *attId = getAttributeId(xmlParserP, enc, atts[i].name, atts[i].name + XmlNameLength(enc, atts[i].name)); if (!attId) return XML_ERROR_NO_MEMORY; /* detect duplicate attributes */ if ((attId->name)[-1]) { if (enc == parser->m_encoding) eventPtr = atts[i].name; return XML_ERROR_DUPLICATE_ATTRIBUTE; } (attId->name)[-1] = 1; appAtts[attIndex++] = attId->name; if (!atts[i].normalized) { enum XML_Error result; int isCdata = 1; /* figure out whether declared as other than CDATA */ if (attId->maybeTokenized) { int j; for (j = 0; j < nDefaultAtts; j++) { if (attId == elementType->defaultAtts[j].id) { isCdata = elementType->defaultAtts[j].isCdata; break; } } } /* normalize the attribute value */ result = storeAttributeValue(xmlParserP, enc, isCdata, atts[i].valuePtr, atts[i].valueEnd, &tempPool); if (result) return result; if (tagNamePtr) { appAtts[attIndex] = poolStart(&tempPool); poolFinish(&tempPool); } else poolDiscard(&tempPool); } else if (tagNamePtr) { /* the value did not need normalizing */ appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd); if (appAtts[attIndex] == 0) return XML_ERROR_NO_MEMORY; poolFinish(&tempPool); } /* handle prefixed attribute names */ if (attId->prefix && tagNamePtr) { if (attId->xmlns) { /* deal with namespace declarations here */ if (!addBinding(xmlParserP, attId->prefix, attId, appAtts[attIndex], bindingsPtr)) return XML_ERROR_NO_MEMORY; --attIndex; } else { /* deal with other prefixed names later */ attIndex++; nPrefixes++; (attId->name)[-1] = 2; } } else attIndex++; } if (tagNamePtr) { int j; nSpecifiedAtts = attIndex; if (elementType->idAtt && (elementType->idAtt->name)[-1]) { for (i = 0; i < attIndex; i += 2) if (appAtts[i] == elementType->idAtt->name) { idAttIndex = i; break; } } else idAttIndex = -1; /* do attribute defaulting */ for (j = 0; j < nDefaultAtts; j++) { const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + j; if (!(da->id->name)[-1] && da->value) { if (da->id->prefix) { if (da->id->xmlns) { if (!addBinding(xmlParserP, da->id->prefix, da->id, da->value, bindingsPtr)) return XML_ERROR_NO_MEMORY; } else { (da->id->name)[-1] = 2; nPrefixes++; appAtts[attIndex++] = da->id->name; appAtts[attIndex++] = da->value; } } else { (da->id->name)[-1] = 1; appAtts[attIndex++] = da->id->name; appAtts[attIndex++] = da->value; } } } appAtts[attIndex] = 0; } i = 0; if (nPrefixes) { /* expand prefixed attribute names */ for (; i < attIndex; i += 2) { if (appAtts[i][-1] == 2) { ATTRIBUTE_ID *id; ((XML_Char *)(appAtts[i]))[-1] = 0; id = (ATTRIBUTE_ID *)lookup(parser, &dtd.attributeIds, appAtts[i], 0); if (id->prefix->binding) { int j; const BINDING *b = id->prefix->binding; const XML_Char *s = appAtts[i]; for (j = 0; j < b->uriLen; j++) { if (!poolAppendChar(&tempPool, b->uri[j])) return XML_ERROR_NO_MEMORY; } while (*s++ != ':') ; do { if (!poolAppendChar(&tempPool, *s)) return XML_ERROR_NO_MEMORY; } while (*s++); appAtts[i] = poolStart(&tempPool); poolFinish(&tempPool); } if (!--nPrefixes) break; } else ((XML_Char *)(appAtts[i]))[-1] = 0; } } /* clear the flags that say whether attributes were specified */ for (; i < attIndex; i += 2) ((XML_Char *)(appAtts[i]))[-1] = 0; if (!tagNamePtr) return XML_ERROR_NONE; for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) binding->attId->name[-1] = 0; /* expand the element type name */ if (elementType->prefix) { binding = elementType->prefix->binding; if (!binding) return XML_ERROR_NONE; localPart = tagNamePtr->str; while (*localPart++ != XML_T(':')) ; } else if (dtd.defaultPrefix.binding) { binding = dtd.defaultPrefix.binding; localPart = tagNamePtr->str; } else return XML_ERROR_NONE; tagNamePtr->localPart = localPart; tagNamePtr->uriLen = binding->uriLen; for (i = 0; localPart[i++];) ; n = i + binding->uriLen; if (n > binding->uriAlloc) { TAG *p; XML_Char *uri = malloc((n + EXPAND_SPARE) * sizeof(XML_Char)); if (!uri) return XML_ERROR_NO_MEMORY; binding->uriAlloc = n + EXPAND_SPARE; memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); for (p = tagStack; p; p = p->parent) if (p->name.str == binding->uri) p->name.str = uri; free(binding->uri); binding->uri = uri; } memcpy(binding->uri + binding->uriLen, localPart, i * sizeof(XML_Char)); tagNamePtr->str = binding->uri; return XML_ERROR_NONE; } static Processor epilogProcessor; static void epilogProcessor(XML_Parser const xmlParserP, const char * const startArg, const char * const end, const char ** const nextPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; const char * s; *errorP = NULL; s = startArg; processor = epilogProcessor; eventPtr = s; for (;;) { const char *next; int tok = XmlPrologTok(parser->m_encoding, s, end, &next); eventEndPtr = next; switch (tok) { case -XML_TOK_PROLOG_S: if (defaultHandler) { eventEndPtr = end; reportDefault(xmlParserP, parser->m_encoding, s, end); } /* fall through */ case XML_TOK_NONE: if (nextPtr) *nextPtr = end; *errorCodeP = XML_ERROR_NONE; return; case XML_TOK_PROLOG_S: if (defaultHandler) reportDefault(xmlParserP, parser->m_encoding, s, next); break; case XML_TOK_PI: if (!reportProcessingInstruction(xmlParserP, parser->m_encoding, s, next)) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } break; case XML_TOK_COMMENT: if (!reportComment(xmlParserP, parser->m_encoding, s, next)) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } break; case XML_TOK_INVALID: eventPtr = next; *errorCodeP = XML_ERROR_INVALID_TOKEN; return; case XML_TOK_PARTIAL: if (nextPtr) { *nextPtr = s; *errorCodeP = XML_ERROR_NONE; } else *errorCodeP = XML_ERROR_UNCLOSED_TOKEN; return; case XML_TOK_PARTIAL_CHAR: if (nextPtr) { *nextPtr = s; *errorCodeP = XML_ERROR_NONE; } else *errorCodeP = XML_ERROR_PARTIAL_CHAR; return; default: *errorCodeP = XML_ERROR_JUNK_AFTER_DOC_ELEMENT; return; } eventPtr = s = next; } } static enum XML_Error doCdataSection(XML_Parser const xmlParserP, const ENCODING * const encoderP, const char ** const startPtr, const char * const end, const char ** const nextPtr) { Parser * const parser = (Parser *) xmlParserP; struct EventPtr const evPtr = getEventPtr(xmlParserP, encoderP); const char * s; s = *startPtr; /* initial value */ *evPtr.startP = s; *startPtr = 0; for (;;) { const char *next; int tok = XmlCdataSectionTok(encoderP, s, end, &next); *evPtr.endP = next; switch (tok) { case XML_TOK_CDATA_SECT_CLOSE: if (endCdataSectionHandler) endCdataSectionHandler(handlerArg); else if (defaultHandler) reportDefault(xmlParserP, encoderP, s, next); *startPtr = next; return XML_ERROR_NONE; case XML_TOK_DATA_NEWLINE: if (characterDataHandler) { XML_Char c = 0xA; characterDataHandler(handlerArg, &c, 1); } else if (defaultHandler) reportDefault(xmlParserP, encoderP, s, next); break; case XML_TOK_DATA_CHARS: processDataCharsToken(xmlParserP, encoderP, s, next); break; case XML_TOK_INVALID: *evPtr.startP = next; return XML_ERROR_INVALID_TOKEN; case XML_TOK_PARTIAL_CHAR: if (nextPtr) { *nextPtr = s; return XML_ERROR_NONE; } return XML_ERROR_PARTIAL_CHAR; case XML_TOK_PARTIAL: case XML_TOK_NONE: if (nextPtr) { *nextPtr = s; return XML_ERROR_NONE; } return XML_ERROR_UNCLOSED_CDATA_SECTION; default: abort(); } *evPtr.startP = s = next; } /* not reached */ } /* Forward declaration for recursive reference: */ static void doContent(XML_Parser const xmlParserP, int const startTagLevel, const ENCODING * const enc, const char * const startArg, const char * const end, const char ** const nextPtr, enum XML_Error * const errorCodeP, const char ** const errorP); static Processor contentProcessor; static void contentProcessor(XML_Parser const xmlParserP, const char * const start, const char * const end, const char ** const endPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; const char * error; parser->m_errorString = NULL; doContent(xmlParserP, 0, parser->m_encoding, start, end, endPtr, errorCodeP, &error); if (*errorCodeP != XML_ERROR_NONE) { if (error) { xmlrpc_asprintf(errorP, "Invalid XML \"content\". %s", error); xmlrpc_strfree(error); } else { const char * const sampleXml = extractXmlSample(start, end, 40); xmlrpc_asprintf(errorP, "Invalid XML \"content\" starting " "with '%s'. %s", sampleXml, xmlrpc_XML_ErrorString(*errorCodeP)); xmlrpc_strfree(sampleXml); } } else *errorP = NULL; } /* The idea here is to avoid using stack for each CDATA section when the whole file is parsed with one call. */ static Processor cdataSectionProcessor; static void cdataSectionProcessor(XML_Parser const xmlParserP, const char * const startArg, const char * const end, const char ** const endPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; enum XML_Error result; const char * start; start = startArg; result = doCdataSection(xmlParserP, parser->m_encoding, &start, end, endPtr); if (start) { processor = contentProcessor; contentProcessor(xmlParserP, start, end, endPtr, errorCodeP, errorP); } else { *errorCodeP = result; *errorP = NULL; } } static void doEntityRef(XML_Parser const xmlParserP, const ENCODING * const enc, const char * const s, const char * const next, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; XML_Char const ch = XmlPredefinedEntityName(enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); const XML_Char *name; ENTITY *entity; *errorP = NULL; if (ch) { if (characterDataHandler) characterDataHandler(handlerArg, &ch, 1); else if (defaultHandler) reportDefault(xmlParserP, enc, s, next); *errorCodeP = XML_ERROR_NONE; return; } name = poolStoreString(&dtd.pool, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); if (!name) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } entity = (ENTITY *)lookup(parser, &dtd.generalEntities, name, 0); poolDiscard(&dtd.pool); if (!entity) { if (dtd.complete || dtd.standalone) *errorCodeP = XML_ERROR_UNDEFINED_ENTITY; else { if (defaultHandler) reportDefault(xmlParserP, enc, s, next); *errorCodeP = XML_ERROR_NONE; } return; } if (entity->open) { *errorCodeP = XML_ERROR_RECURSIVE_ENTITY_REF; return; } if (entity->notation) { *errorCodeP = XML_ERROR_BINARY_ENTITY_REF; return; } if (entity) { if (entity->textPtr) { OPEN_INTERNAL_ENTITY openEntity; if (defaultHandler && !defaultExpandInternalEntities) { reportDefault(xmlParserP, enc, s, next); *errorCodeP = XML_ERROR_NONE; return; } entity->open = 1; openEntity.next = openInternalEntities; openInternalEntities = &openEntity; openEntity.entity = entity; openEntity.internalEventPtr = 0; openEntity.internalEventEndPtr = 0; doContent(xmlParserP, tagLevel, internalEncoding, (char *)entity->textPtr, (char *)(entity->textPtr + entity->textLen), 0, errorCodeP, errorP); entity->open = 0; openInternalEntities = openEntity.next; if (*errorCodeP != XML_ERROR_NONE) return; } else if (externalEntityRefHandler) { const XML_Char *context; entity->open = 1; context = getContext(xmlParserP); entity->open = 0; if (!context) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } if (!externalEntityRefHandler(externalEntityRefHandlerArg, context, entity->base, entity->systemId, entity->publicId)) { *errorCodeP = XML_ERROR_EXTERNAL_ENTITY_HANDLING; return; } poolDiscard(&tempPool); } else if (defaultHandler) reportDefault(xmlParserP, enc, s, next); } *errorCodeP = XML_ERROR_NONE; } static void doStartTagNoAtts(XML_Parser const xmlParserP, const ENCODING * const enc, const char * const s, const char * const next, const char ** const nextPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; TAG *tag; *errorP = NULL; if (freeTagList) { tag = freeTagList; freeTagList = freeTagList->parent; } else { tag = malloc(sizeof(TAG)); if (!tag) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } tag->buf = malloc(INIT_TAG_BUF_SIZE); if (!tag->buf) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; } tag->bindings = NULL; tag->parent = tagStack; tagStack = tag; tag->name.localPart = 0; tag->rawName = s + enc->minBytesPerChar; tag->rawNameLength = XmlNameLength(enc, tag->rawName); if (nextPtr) { /* Need to guarantee that: tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)) <= tag->bufEnd - sizeof(XML_Char) */ if (tag->rawNameLength + (int)(sizeof(XML_Char) - 1) + (int)sizeof(XML_Char) > tag->bufEnd - tag->buf) { char *temp; int bufSize = tag->rawNameLength * 4; bufSize = ROUND_UP(bufSize, sizeof(XML_Char)); temp = realloc(tag->buf, bufSize); if (!temp) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } tag->buf = temp; tag->bufEnd = tag->buf + bufSize; } memcpy(tag->buf, tag->rawName, tag->rawNameLength); tag->rawName = tag->buf; } ++tagLevel; if (startElementHandler) { enum XML_Error result; XML_Char *toPtr; for (;;) { const char *rawNameEnd = tag->rawName + tag->rawNameLength; const char *fromPtr = tag->rawName; if (nextPtr) toPtr = (XML_Char *) (tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char))); else toPtr = (XML_Char *)tag->buf; tag->name.str = toPtr; XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); if (fromPtr == rawNameEnd) break; else { size_t const bufSize = (tag->bufEnd - tag->buf) << 1; char *temp = realloc(tag->buf, bufSize); if (!temp) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } tag->buf = temp; tag->bufEnd = tag->buf + bufSize; if (nextPtr) tag->rawName = tag->buf; } } *toPtr = XML_T('\0'); result = storeAtts(xmlParserP, enc, s, &(tag->name), &(tag->bindings)); if (result) { *errorCodeP = result; return; } startElementHandler(handlerArg, tag->name.str, (const XML_Char **)atts); poolClear(&tempPool); } else { tag->name.str = 0; if (defaultHandler) reportDefault(xmlParserP, enc, s, next); } } static void doEmptyElementNoAtts(XML_Parser const xmlParserP, const ENCODING * const enc, const char * const s, const char * const end, const char * const next, const char ** const nextPtr, const char ** const eventPP, const char ** const eventEndPP, bool * const doneP, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; if (startElementHandler || endElementHandler) { const char * const rawName = s + enc->minBytesPerChar; enum XML_Error result; BINDING * bindings; TAG_NAME name; bindings = NULL; /* initial value */ name.str = poolStoreString(&tempPool, enc, rawName, rawName + XmlNameLength(enc, rawName)); if (!name.str) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } poolFinish(&tempPool); result = storeAtts(xmlParserP, enc, s, &name, &bindings); if (result) { *errorCodeP = result; return; } poolFinish(&tempPool); if (startElementHandler) startElementHandler(handlerArg, name.str, (const XML_Char **)atts); if (endElementHandler) { if (startElementHandler) *eventPP = *eventEndPP; endElementHandler(handlerArg, name.str); } poolClear(&tempPool); while (bindings) { BINDING * const b = bindings; if (endNamespaceDeclHandler) endNamespaceDeclHandler(handlerArg, b->prefix->name); bindings = bindings->nextTagBinding; b->nextTagBinding = freeBindingList; freeBindingList = b; b->prefix->binding = b->prevPrefixBinding; } } else if (defaultHandler) reportDefault(xmlParserP, enc, s, next); if (tagLevel == 0) { epilogProcessor(xmlParserP, next, end, nextPtr, errorCodeP, errorP); *doneP = true; } else *doneP = false; } static void doEndTag(XML_Parser const xmlParserP, const ENCODING * const enc, const char * const s, const char * const end, const char * const next, const char ** const nextPtr, int const startTagLevel, const char ** const eventPP, bool * const doneP, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; if (tagLevel == startTagLevel) *errorCodeP = XML_ERROR_ASYNC_ENTITY; else { TAG * const tag = tagStack; int len; const char * rawName; tagStack = tag->parent; tag->parent = freeTagList; freeTagList = tag; rawName = s + enc->minBytesPerChar*2; len = XmlNameLength(enc, rawName); if (len != tag->rawNameLength || memcmp(tag->rawName, rawName, len) != 0) { *eventPP = rawName; *errorCodeP = XML_ERROR_TAG_MISMATCH; } else { --tagLevel; if (endElementHandler && tag->name.str) { if (tag->name.localPart) { XML_Char * to; const XML_Char * from; to = (XML_Char *)tag->name.str + tag->name.uriLen; from = tag->name.localPart; while ((*to++ = *from++) != 0) ; } endElementHandler(handlerArg, tag->name.str); } else if (defaultHandler) reportDefault(xmlParserP, enc, s, next); while (tag->bindings) { BINDING * const b = tag->bindings; if (endNamespaceDeclHandler) endNamespaceDeclHandler(handlerArg, b->prefix->name); tag->bindings = tag->bindings->nextTagBinding; b->nextTagBinding = freeBindingList; freeBindingList = b; b->prefix->binding = b->prevPrefixBinding; } if (tagLevel == 0) { epilogProcessor(xmlParserP, next, end, nextPtr, errorCodeP, errorP); *doneP = true; } else { *errorCodeP = XML_ERROR_NONE; *doneP = false; } } } } static void processContentToken(XML_Parser const xmlParserP, int const tok, const ENCODING * const enc, const char * const s, const char * const end, const char ** const nextP, const char ** const nextPtr, int const startTagLevel, bool * const doneP, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; struct EventPtr const evPtr = getEventPtr(xmlParserP, enc); *errorP = NULL; *errorCodeP = XML_ERROR_NONE; switch (tok) { case XML_TOK_TRAILING_CR: if (nextPtr) { *nextPtr = s; *doneP = true; } else { *evPtr.endP = end; if (characterDataHandler) { XML_Char c = 0xA; characterDataHandler(handlerArg, &c, 1); } else if (defaultHandler) reportDefault(xmlParserP, enc, s, end); if (startTagLevel == 0) *errorCodeP = XML_ERROR_NO_ELEMENTS; else if (tagLevel != startTagLevel) { *errorCodeP = XML_ERROR_ASYNC_ENTITY; } else *doneP = true; } break; case XML_TOK_NONE: if (nextPtr) { *nextPtr = s; *doneP = true; } else if (startTagLevel > 0) { if (tagLevel != startTagLevel) *errorCodeP = XML_ERROR_ASYNC_ENTITY; else *doneP = true; } else *errorCodeP = XML_ERROR_NO_ELEMENTS; break; case XML_TOK_INVALID: *evPtr.startP = *nextP; *errorCodeP = XML_ERROR_INVALID_TOKEN; xmlrpc_asprintf(errorP, "Invalid token, starting %ld bytes in", (long)(*nextP - s)); break; case XML_TOK_PARTIAL: if (nextPtr) { *nextPtr = s; *doneP = true; } else *errorCodeP = XML_ERROR_UNCLOSED_TOKEN; break; case XML_TOK_PARTIAL_CHAR: if (nextPtr) { *nextPtr = s; *doneP = true; } else *errorCodeP = XML_ERROR_PARTIAL_CHAR; break; case XML_TOK_ENTITY_REF: doEntityRef(xmlParserP, enc, s, *nextP, errorCodeP, errorP); break; case XML_TOK_START_TAG_WITH_ATTS: if (!startElementHandler) *errorCodeP = storeAtts(xmlParserP, enc, s, 0, 0); if (*errorCodeP == XML_ERROR_NONE) doStartTagNoAtts(xmlParserP, enc, s, *nextP, nextPtr, errorCodeP, errorP); break; case XML_TOK_START_TAG_NO_ATTS: doStartTagNoAtts(xmlParserP, enc, s, *nextP, nextPtr, errorCodeP, errorP); break; case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: if (!startElementHandler) *errorCodeP = storeAtts(xmlParserP, enc, s, 0, 0); if (*errorCodeP == XML_ERROR_NONE) doEmptyElementNoAtts(xmlParserP, enc, s, end, *nextP, nextPtr, evPtr.startP, evPtr.endP, doneP, errorCodeP, errorP); break; case XML_TOK_EMPTY_ELEMENT_NO_ATTS: doEmptyElementNoAtts(xmlParserP, enc, s, end, *nextP, nextPtr, evPtr.startP, evPtr.endP, doneP, errorCodeP, errorP); break; case XML_TOK_END_TAG: doEndTag(xmlParserP, enc, s, end, *nextP, nextPtr, startTagLevel, evPtr.startP, doneP, errorCodeP, errorP); break; case XML_TOK_CHAR_REF: { int const n = XmlCharRefNumber(enc, s); if (n < 0) *errorCodeP = XML_ERROR_BAD_CHAR_REF; else { if (characterDataHandler) { XML_Char buf[XML_ENCODE_MAX]; characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); } else if (defaultHandler) reportDefault(xmlParserP, enc, s, *nextP); } } break; case XML_TOK_XML_DECL: *errorCodeP = XML_ERROR_MISPLACED_XML_PI; break; case XML_TOK_DATA_NEWLINE: if (characterDataHandler) { XML_Char c = 0xA; characterDataHandler(handlerArg, &c, 1); } else if (defaultHandler) reportDefault(xmlParserP, enc, s, *nextP); break; case XML_TOK_CDATA_SECT_OPEN: { enum XML_Error result; if (startCdataSectionHandler) startCdataSectionHandler(handlerArg); else if (defaultHandler) reportDefault(xmlParserP, enc, s, *nextP); result = doCdataSection(xmlParserP, enc, nextP, end, nextPtr); if (!*nextP) { processor = cdataSectionProcessor; *errorCodeP = result; } } break; case XML_TOK_TRAILING_RSQB: if (nextPtr) { *nextPtr = s; *errorCodeP = XML_ERROR_NONE; } else { if (characterDataHandler) { if (MUST_CONVERT(enc, s)) { const char * from; ICHAR * dataPtr; from = s; dataPtr = (ICHAR *)dataBuf; XmlConvert(enc, &from, end, &dataPtr, (ICHAR *)dataBufEnd); { size_t const len = dataPtr - (ICHAR *)dataBuf; assert((size_t)(int)len == len); /* parser reqt */ characterDataHandler(handlerArg, dataBuf, (int)len); } } else { size_t const len = (XML_Char *)end - (XML_Char *)s; assert((size_t)(int)len == len); /* parser reqt */ characterDataHandler(handlerArg, (XML_Char *)s, (int)len); } } else if (defaultHandler) reportDefault(xmlParserP, enc, s, end); if (startTagLevel == 0) { *evPtr.startP = end; *errorCodeP = XML_ERROR_NO_ELEMENTS; } else if (tagLevel != startTagLevel) { *evPtr.startP = end; *errorCodeP = XML_ERROR_ASYNC_ENTITY; } else *doneP = true; } break; case XML_TOK_DATA_CHARS: processDataCharsToken(xmlParserP, enc, s, *nextP); break; case XML_TOK_PI: if (!reportProcessingInstruction(xmlParserP, enc, s, *nextP)) *errorCodeP = XML_ERROR_NO_MEMORY; break; case XML_TOK_COMMENT: if (!reportComment(xmlParserP, enc, s, *nextP)) *errorCodeP = XML_ERROR_NO_MEMORY; break; default: if (defaultHandler) reportDefault(xmlParserP, enc, s, *nextP); break; } } static void doContent(XML_Parser const xmlParserP, int const startTagLevel, const ENCODING * const enc, const char * const startArg, const char * const end, const char ** const nextPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { struct EventPtr const evPtr = getEventPtr(xmlParserP, enc); const char * s; bool done; s = startArg; *evPtr.startP = s; done = false; *errorCodeP = XML_ERROR_NONE; *errorP = NULL; while (*errorCodeP == XML_ERROR_NONE && !done) { int tok; const char * next; const char * error; next = s; /* XmlContentTok doesn't always set the last arg */ /* XmlContentTok() is normally normal_contentTok(), aka PREFIX(contentTok)() in xmltok/xmltok_impl.c */ tok = XmlContentTok(enc, s, end, &next); *evPtr.endP = next; processContentToken(xmlParserP, tok, enc, s, end, &next, nextPtr, startTagLevel, &done, errorCodeP, &error); if (*errorCodeP != XML_ERROR_NONE) { const char * const xmlSample = extractXmlSample(s, end, 40); if (error) { xmlrpc_asprintf(errorP, "Problem with token at '%s...': %s", xmlSample, error); xmlrpc_strfree(error); } else xmlrpc_asprintf(errorP, "Problem with token at '%s...': %s", xmlSample, xmlrpc_XML_ErrorString(*errorCodeP)); xmlrpc_strfree(xmlSample); } *evPtr.startP = s = next; } } static Processor externalEntityContentProcessor; static void externalEntityContentProcessor(XML_Parser const xmlParserP, const char * const start, const char * const end, const char ** const endPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; *errorP = NULL; doContent(xmlParserP, 1, parser->m_encoding, start, end, endPtr, errorCodeP, errorP); } static Processor externalEntityInitProcessor3; static void externalEntityInitProcessor3(XML_Parser const xmlParserP, const char * const startArg, const char * const end, const char ** const endPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; const char * start; const char *next; int tok; tok = XmlContentTok(parser->m_encoding, startArg, end, &next); *errorP = NULL; start = startArg; switch (tok) { case XML_TOK_XML_DECL: { enum XML_Error result; processXmlDecl(xmlParserP, 1, start, next, &result); if (result != XML_ERROR_NONE) { *errorCodeP = result; return; } start = next; } break; case XML_TOK_PARTIAL: if (endPtr) { *endPtr = start; *errorCodeP = XML_ERROR_NONE; return; } eventPtr = start; *errorCodeP = XML_ERROR_UNCLOSED_TOKEN; return; case XML_TOK_PARTIAL_CHAR: if (endPtr) { *endPtr = start; *errorCodeP = XML_ERROR_NONE; return; } eventPtr = start; *errorCodeP = XML_ERROR_PARTIAL_CHAR; return; } processor = externalEntityContentProcessor; tagLevel = 1; doContent(xmlParserP, 1, parser->m_encoding, start, end, endPtr, errorCodeP, errorP); } static Processor externalEntityInitProcessor2; static void externalEntityInitProcessor2(XML_Parser const xmlParserP, const char * const startArg, const char * const end, const char ** const endPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *)xmlParserP; const char * start; const char * next; int tok; tok = XmlContentTok(parser->m_encoding, startArg, end, &next); start = startArg; switch (tok) { case XML_TOK_BOM: start = next; break; case XML_TOK_PARTIAL: if (endPtr) { *endPtr = start; *errorCodeP = XML_ERROR_NONE; *errorP = NULL; } else { eventPtr = start; *errorCodeP = XML_ERROR_UNCLOSED_TOKEN; *errorP = NULL; } return; case XML_TOK_PARTIAL_CHAR: if (endPtr) { *endPtr = start; *errorCodeP = XML_ERROR_NONE; *errorP = NULL; } else { eventPtr = start; *errorCodeP = XML_ERROR_PARTIAL_CHAR; *errorP = NULL; } return; } processor = externalEntityInitProcessor3; externalEntityInitProcessor3(xmlParserP, start, end, endPtr, errorCodeP, errorP); } static Processor externalEntityInitProcessor; static void externalEntityInitProcessor(XML_Parser const parser, const char * const start, const char * const end, const char ** const endPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { enum XML_Error result; result = initializeEncoding(parser); if (result != XML_ERROR_NONE) { *errorCodeP = result; *errorP = NULL; } else { processor = externalEntityInitProcessor2; externalEntityInitProcessor2(parser, start, end, endPtr, errorCodeP, errorP); } } static enum XML_Error doIgnoreSection(XML_Parser const xmlParserP, const ENCODING * const enc, const char ** const startPtr, const char * const end, const char ** const nextPtr) { /*---------------------------------------------------------------------------- We set *startPtr to non-null is the section is closed, and to null if the section is not yet closed. -----------------------------------------------------------------------------*/ Parser * const parser = xmlParserP; struct EventPtr const evPtr = getEventPtr(xmlParserP, enc); const char * const s = *startPtr; enum XML_Error retval; const char * next; int tok; *evPtr.startP = s; *startPtr = '\0'; tok = XmlIgnoreSectionTok(enc, s, end, &next); *evPtr.endP = next; switch (tok) { case XML_TOK_IGNORE_SECT: if (defaultHandler) reportDefault(xmlParserP, enc, s, next); *startPtr = next; retval = XML_ERROR_NONE; break; case XML_TOK_INVALID: *evPtr.startP = next; retval = XML_ERROR_INVALID_TOKEN; break; case XML_TOK_PARTIAL_CHAR: if (nextPtr) { *nextPtr = s; retval = XML_ERROR_NONE; } else retval = XML_ERROR_PARTIAL_CHAR; break; case XML_TOK_PARTIAL: case XML_TOK_NONE: if (nextPtr) { *nextPtr = s; retval = XML_ERROR_NONE; } else retval = XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ break; default: assert(false); /* All possibilities are handled above */ retval = 99; /* quiet compiler warning */ } return retval; } static Processor prologProcessor; /* The idea here is to avoid using stack for each IGNORE section when the whole file is parsed with one call. */ static Processor ignoreSectionProcessor; static void ignoreSectionProcessor(XML_Parser const xmlParserP, const char * const startArg, const char * const end, const char ** const endPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; enum XML_Error result; const char * start; start = startArg; /* initial value */ result = doIgnoreSection(parser, parser->m_encoding, &start, end, endPtr); if (start) { processor = prologProcessor; prologProcessor(xmlParserP, start, end, endPtr, errorCodeP, errorP); } else { *errorCodeP = result; *errorP = NULL; } } /* Forward declaration for recursive reference: */ static void processInternalParamEntity(XML_Parser const parser, ENTITY * const entity, enum XML_Error * const errorCodeP, const char ** const errorP); static void doProlog(XML_Parser const xmlParserP, const ENCODING * const encArg, const char * const startArg, const char * const end, int const tokArg, const char * const nextArg, const char ** const nextPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = xmlParserP; struct EventPtr const evPtr = getEventPtr(xmlParserP, encArg); int tok; const char * next; const ENCODING * enc; const char * s; static const XML_Char externalSubsetName[] = { '#' , '\0' }; *errorP = NULL; tok = tokArg; next = nextArg; enc = encArg; s = startArg; for (;;) { int role; *evPtr.startP = s; *evPtr.endP = next; if (tok <= 0) { if (nextPtr != 0 && tok != XML_TOK_INVALID) { *nextPtr = s; *errorCodeP = XML_ERROR_NONE; return; } switch (tok) { case XML_TOK_INVALID: *evPtr.startP = next; *errorCodeP = XML_ERROR_INVALID_TOKEN; return; case XML_TOK_PARTIAL: *errorCodeP = XML_ERROR_UNCLOSED_TOKEN; return; case XML_TOK_PARTIAL_CHAR: *errorCodeP = XML_ERROR_PARTIAL_CHAR; return; case XML_TOK_NONE: if (enc != parser->m_encoding) *errorCodeP = XML_ERROR_NONE; else { if (parentParser) { if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc) == XML_ROLE_ERROR) { *errorCodeP = XML_ERROR_SYNTAX; } else { *errorCodeP = XML_ERROR_NONE; hadExternalDoctype = 0; } } else *errorCodeP = XML_ERROR_NO_ELEMENTS; } return; default: tok = -tok; next = end; break; } } role = XmlTokenRole(&prologState, tok, s, next, enc); switch (role) { case XML_ROLE_XML_DECL: { enum XML_Error result; processXmlDecl(xmlParserP, 0, s, next, &result); if (result != XML_ERROR_NONE) { *errorCodeP = result; return; } enc = parser->m_encoding; } break; case XML_ROLE_DOCTYPE_NAME: if (startDoctypeDeclHandler) { const XML_Char *name = poolStoreString(&tempPool, enc, s, next); if (!name) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } startDoctypeDeclHandler(handlerArg, name); poolClear(&tempPool); } break; case XML_ROLE_TEXT_DECL: { enum XML_Error result; processXmlDecl(xmlParserP, 1, s, next, &result); if (result != XML_ERROR_NONE) { *errorCodeP = result; return; } enc = parser->m_encoding; } break; case XML_ROLE_DOCTYPE_PUBLIC_ID: declEntity = (ENTITY *)lookup(parser, &dtd.paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } /* fall through */ case XML_ROLE_ENTITY_PUBLIC_ID: if (!XmlIsPublicId(enc, s, next, evPtr.startP)) { *errorCodeP = XML_ERROR_SYNTAX; return; } if (declEntity) { XML_Char *tem = poolStoreString(&dtd.pool, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); if (!tem) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } normalizePublicId(tem); declEntity->publicId = tem; poolFinish(&dtd.pool); } break; case XML_ROLE_DOCTYPE_CLOSE: if (dtd.complete && hadExternalDoctype) { dtd.complete = 0; if (parser->m_paramEntityParsing && externalEntityRefHandler) { ENTITY *entity = (ENTITY *)lookup(parser, &dtd.paramEntities, externalSubsetName, 0); if (!externalEntityRefHandler(externalEntityRefHandlerArg, 0, entity->base, entity->systemId, entity->publicId)) { *errorCodeP = XML_ERROR_EXTERNAL_ENTITY_HANDLING; return; } } if (!dtd.complete && !dtd.standalone && notStandaloneHandler && !notStandaloneHandler(handlerArg)) { *errorCodeP = XML_ERROR_NOT_STANDALONE; return; } } if (endDoctypeDeclHandler) endDoctypeDeclHandler(handlerArg); break; case XML_ROLE_INSTANCE_START: { processor = contentProcessor; contentProcessor(xmlParserP, s, end, nextPtr, errorCodeP, errorP); return; } case XML_ROLE_ATTLIST_ELEMENT_NAME: { const XML_Char *name = poolStoreString(&dtd.pool, enc, s, next); if (!name) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } declElementType = (ELEMENT_TYPE *) lookup(parser, &dtd.elementTypes, name, sizeof(ELEMENT_TYPE)); if (!declElementType) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } if (declElementType->name != name) poolDiscard(&dtd.pool); else { poolFinish(&dtd.pool); if (!setElementTypePrefix(xmlParserP, declElementType)) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } } break; } case XML_ROLE_ATTRIBUTE_NAME: declAttributeId = getAttributeId(xmlParserP, enc, s, next); if (!declAttributeId) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } declAttributeIsCdata = 0; declAttributeIsId = 0; break; case XML_ROLE_ATTRIBUTE_TYPE_CDATA: declAttributeIsCdata = 1; break; case XML_ROLE_ATTRIBUTE_TYPE_ID: declAttributeIsId = 1; break; case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: if (dtd.complete && !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, declAttributeIsId, 0)) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } break; case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: case XML_ROLE_FIXED_ATTRIBUTE_VALUE: { const XML_Char *attVal; enum XML_Error result = storeAttributeValue(xmlParserP, enc, declAttributeIsCdata, s + enc->minBytesPerChar, next - enc->minBytesPerChar, &dtd.pool); if (result) { *errorCodeP = result; return; } attVal = poolStart(&dtd.pool); poolFinish(&dtd.pool); if (dtd.complete /* ID attributes aren't allowed to have a default */ && !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, 0, attVal)) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } break; } case XML_ROLE_ENTITY_VALUE: { enum XML_Error result = storeEntityValue(xmlParserP, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); if (declEntity) { declEntity->textPtr = poolStart(&dtd.pool); declEntity->textLen = poolLength(&dtd.pool); poolFinish(&dtd.pool); if (internalParsedEntityDeclHandler /* Check it's not a parameter entity */ && ((ENTITY *)lookup(parser, &dtd.generalEntities, declEntity->name, 0) == declEntity)) { *evPtr.endP = s; internalParsedEntityDeclHandler(handlerArg, declEntity->name, declEntity->textPtr, declEntity->textLen); } } else poolDiscard(&dtd.pool); if (result != XML_ERROR_NONE) { *errorCodeP = result; return; } } break; case XML_ROLE_DOCTYPE_SYSTEM_ID: if (!dtd.standalone && !parser->m_paramEntityParsing && notStandaloneHandler && !notStandaloneHandler(handlerArg)) { *errorCodeP = XML_ERROR_NOT_STANDALONE; return; } hadExternalDoctype = 1; if (!declEntity) { declEntity = (ENTITY *)lookup(parser, &dtd.paramEntities, externalSubsetName, sizeof(ENTITY)); if (!declEntity) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } } /* fall through */ case XML_ROLE_ENTITY_SYSTEM_ID: if (declEntity) { declEntity->systemId = poolStoreString(&dtd.pool, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); if (!declEntity->systemId) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } declEntity->base = curBase; poolFinish(&dtd.pool); } break; case XML_ROLE_ENTITY_NOTATION_NAME: if (declEntity) { declEntity->notation = poolStoreString(&dtd.pool, enc, s, next); if (!declEntity->notation) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } poolFinish(&dtd.pool); if (unparsedEntityDeclHandler) { *evPtr.endP = s; unparsedEntityDeclHandler(handlerArg, declEntity->name, declEntity->base, declEntity->systemId, declEntity->publicId, declEntity->notation); } } break; case XML_ROLE_EXTERNAL_GENERAL_ENTITY_NO_NOTATION: if (declEntity && externalParsedEntityDeclHandler) { *evPtr.endP = s; externalParsedEntityDeclHandler(handlerArg, declEntity->name, declEntity->base, declEntity->systemId, declEntity->publicId); } break; case XML_ROLE_GENERAL_ENTITY_NAME: { const XML_Char *name; if (XmlPredefinedEntityName(enc, s, next)) { declEntity = 0; break; } name = poolStoreString(&dtd.pool, enc, s, next); if (!name) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } if (dtd.complete) { declEntity = (ENTITY *) lookup(parser, &dtd.generalEntities, name, sizeof(ENTITY)); if (!declEntity) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } if (declEntity->name != name) { poolDiscard(&dtd.pool); declEntity = 0; } else poolFinish(&dtd.pool); } else { poolDiscard(&dtd.pool); declEntity = 0; } } break; case XML_ROLE_PARAM_ENTITY_NAME: if (dtd.complete) { const XML_Char *name = poolStoreString(&dtd.pool, enc, s, next); if (!name) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } declEntity = (ENTITY *) lookup(parser, &dtd.paramEntities, name, sizeof(ENTITY)); if (!declEntity) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } if (declEntity->name != name) { poolDiscard(&dtd.pool); declEntity = 0; } else poolFinish(&dtd.pool); } break; case XML_ROLE_NOTATION_NAME: declNotationPublicId = 0; declNotationName = 0; if (notationDeclHandler) { declNotationName = poolStoreString(&tempPool, enc, s, next); if (!declNotationName) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } poolFinish(&tempPool); } break; case XML_ROLE_NOTATION_PUBLIC_ID: if (!XmlIsPublicId(enc, s, next, evPtr.startP)) { *errorCodeP = XML_ERROR_SYNTAX; return; } if (declNotationName) { XML_Char *tem = poolStoreString(&tempPool, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); if (!tem) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } normalizePublicId(tem); declNotationPublicId = tem; poolFinish(&tempPool); } break; case XML_ROLE_NOTATION_SYSTEM_ID: if (declNotationName && notationDeclHandler) { const XML_Char *systemId = poolStoreString(&tempPool, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); if (!systemId) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } *evPtr.endP = s; notationDeclHandler(handlerArg, declNotationName, curBase, systemId, declNotationPublicId); } poolClear(&tempPool); break; case XML_ROLE_NOTATION_NO_SYSTEM_ID: if (declNotationPublicId && notationDeclHandler) { *evPtr.endP = s; notationDeclHandler(handlerArg, declNotationName, curBase, 0, declNotationPublicId); } poolClear(&tempPool); break; case XML_ROLE_ERROR: switch (tok) { case XML_TOK_PARAM_ENTITY_REF: *errorCodeP = XML_ERROR_PARAM_ENTITY_REF; case XML_TOK_XML_DECL: *errorCodeP = XML_ERROR_MISPLACED_XML_PI; default: *errorCodeP = XML_ERROR_SYNTAX; } return; case XML_ROLE_IGNORE_SECT: { enum XML_Error result; if (defaultHandler) reportDefault(xmlParserP, enc, s, next); result = doIgnoreSection(xmlParserP, enc, &next, end, nextPtr); if (!next) { processor = ignoreSectionProcessor; *errorCodeP = result; return; } } break; case XML_ROLE_GROUP_OPEN: if (prologState.level >= groupSize) { if (groupSize) { char *temp = realloc(groupConnector, groupSize *= 2); if (!temp) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } groupConnector = temp; } else { groupConnector = malloc(groupSize = 32); if (!groupConnector) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } } } groupConnector[prologState.level] = 0; break; case XML_ROLE_GROUP_SEQUENCE: if (groupConnector[prologState.level] == '|') { *errorCodeP = XML_ERROR_SYNTAX; return; } groupConnector[prologState.level] = ','; break; case XML_ROLE_GROUP_CHOICE: if (groupConnector[prologState.level] == ',') { *errorCodeP = XML_ERROR_SYNTAX; return; } groupConnector[prologState.level] = '|'; break; case XML_ROLE_PARAM_ENTITY_REF: case XML_ROLE_INNER_PARAM_ENTITY_REF: if (parser->m_paramEntityParsing && (dtd.complete || role == XML_ROLE_INNER_PARAM_ENTITY_REF)) { const XML_Char *name; ENTITY *entity; name = poolStoreString(&dtd.pool, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar); if (!name) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } entity = (ENTITY *)lookup(parser, &dtd.paramEntities, name, 0); poolDiscard(&dtd.pool); if (!entity) { /* FIXME what to do if !dtd.complete? */ *errorCodeP = XML_ERROR_UNDEFINED_ENTITY; return; } if (entity->open) { *errorCodeP = XML_ERROR_RECURSIVE_ENTITY_REF; return; } if (entity->textPtr) { processInternalParamEntity(xmlParserP, entity, errorCodeP, errorP); if (*errorCodeP != XML_ERROR_NONE) return; break; } if (role == XML_ROLE_INNER_PARAM_ENTITY_REF) { *errorCodeP = XML_ERROR_PARAM_ENTITY_REF; return; } if (externalEntityRefHandler) { dtd.complete = 0; entity->open = 1; if (!externalEntityRefHandler(externalEntityRefHandlerArg, 0, entity->base, entity->systemId, entity->publicId)) { entity->open = 0; *errorCodeP = XML_ERROR_EXTERNAL_ENTITY_HANDLING; return; } entity->open = 0; if (dtd.complete) break; } } if (!dtd.standalone && notStandaloneHandler && !notStandaloneHandler(handlerArg)) { *errorCodeP = XML_ERROR_NOT_STANDALONE; return; } dtd.complete = 0; if (defaultHandler) reportDefault(xmlParserP, enc, s, next); break; case XML_ROLE_NONE: switch (tok) { case XML_TOK_PI: if (!reportProcessingInstruction(xmlParserP, enc, s, next)) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } break; case XML_TOK_COMMENT: if (!reportComment(xmlParserP, enc, s, next)) { *errorCodeP = XML_ERROR_NO_MEMORY; return; } break; } break; } if (defaultHandler) { switch (tok) { case XML_TOK_PI: case XML_TOK_COMMENT: case XML_TOK_BOM: case XML_TOK_XML_DECL: case XML_TOK_IGNORE_SECT: case XML_TOK_PARAM_ENTITY_REF: break; default: if (role != XML_ROLE_IGNORE_SECT) reportDefault(xmlParserP, enc, s, next); } } s = next; tok = XmlPrologTok(enc, s, end, &next); } /* not reached */ } static Processor prologProcessor; static void prologProcessor(XML_Parser const xmlParserP, const char * const s, const char * const end, const char ** const nextPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { Parser * const parser = (Parser *) xmlParserP; const char * next; int tok; *errorP = NULL; tok = XmlPrologTok(parser->m_encoding, s, end, &next); doProlog(xmlParserP, parser->m_encoding, s, end, tok, next, nextPtr, errorCodeP, errorP); } static Processor prologInitProcessor; static void prologInitProcessor(XML_Parser const parser, const char * const s, const char * const end, const char ** const nextPtr, enum XML_Error * const errorCodeP, const char ** const errorP) { enum XML_Error result; *errorP = NULL; result = initializeEncoding(parser); if (result != XML_ERROR_NONE) *errorCodeP = result; else { processor = prologProcessor; prologProcessor(parser, s, end, nextPtr, errorCodeP, errorP); } } static void processInternalParamEntity(XML_Parser const parser, ENTITY * const entity, enum XML_Error * const errorCodeP, const char ** const errorP) { const char *s, *end, *next; int tok; OPEN_INTERNAL_ENTITY openEntity; entity->open = 1; openEntity.next = openInternalEntities; openInternalEntities = &openEntity; openEntity.entity = entity; openEntity.internalEventPtr = 0; openEntity.internalEventEndPtr = 0; s = (char *)entity->textPtr; end = (char *)(entity->textPtr + entity->textLen); tok = XmlPrologTok(internalEncoding, s, end, &next); doProlog(parser, internalEncoding, s, end, tok, next, 0, errorCodeP, errorP); entity->open = 0; openInternalEntities = openEntity.next; } XML_Parser xmlrpc_XML_ParserCreate(const XML_Char * const encodingName) { XML_Parser const xmlParserP = malloc(sizeof(Parser)); bool error; if (xmlParserP) { Parser * const parser = (Parser *)xmlParserP; parser->m_processor = prologInitProcessor; xmlrpc_XmlPrologStateInit(&parser->m_prologState); parser->m_userData = 0; parser->m_handlerArg = 0; parser->m_startElementHandler = 0; parser->m_endElementHandler = 0; parser->m_characterDataHandler = 0; parser->m_processingInstructionHandler = 0; parser->m_commentHandler = 0; parser->m_startCdataSectionHandler = 0; parser->m_endCdataSectionHandler = 0; parser->m_defaultHandler = 0; parser->m_startDoctypeDeclHandler = 0; parser->m_endDoctypeDeclHandler = 0; parser->m_unparsedEntityDeclHandler = 0; parser->m_notationDeclHandler = 0; parser->m_externalParsedEntityDeclHandler = 0; parser->m_internalParsedEntityDeclHandler = 0; parser->m_startNamespaceDeclHandler = 0; parser->m_endNamespaceDeclHandler = 0; parser->m_notStandaloneHandler = 0; parser->m_externalEntityRefHandler = 0; parser->m_externalEntityRefHandlerArg = parser; parser->m_unknownEncodingHandler = 0; parser->m_buffer = 0; parser->m_bufferPtr = 0; parser->m_bufferEnd = 0; parser->m_parseEndByteIndex = 0; parser->m_parseEndPtr = 0; parser->m_bufferLim = 0; parser->m_declElementType = 0; parser->m_declAttributeId = 0; parser->m_declEntity = 0; parser->m_declNotationName = 0; parser->m_declNotationPublicId = 0; memset(&parser->m_position, 0, sizeof(POSITION)); parser->m_errorCode = XML_ERROR_NONE; parser->m_errorString = NULL; parser->m_eventPtr = 0; parser->m_eventEndPtr = 0; parser->m_positionPtr = 0; parser->m_openInternalEntities = 0; parser->m_tagLevel = 0; parser->m_tagStack = 0; parser->m_freeTagList = 0; parser->m_freeBindingList = 0; parser->m_inheritedBindings = 0; parser->m_attsSize = INIT_ATTS_SIZE; parser->m_atts = malloc(attsSize * sizeof(ATTRIBUTE)); parser->m_nSpecifiedAtts = 0; parser->m_dataBuf = malloc(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); parser->m_groupSize = 0; parser->m_groupConnector = 0; parser->m_hadExternalDoctype = 0; parser->m_unknownEncodingMem = 0; parser->m_unknownEncodingRelease = 0; parser->m_unknownEncodingData = 0; parser->m_unknownEncodingHandlerData = 0; parser->m_namespaceSeparator = '!'; parser->m_parentParser = 0; parser->m_paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; parser->m_hash_secret_salt = 0; parser->m_ns = 0; poolInit(&parser->m_tempPool); poolInit(&parser->m_temp2Pool); parser->m_protocolEncodingName = encodingName ? poolCopyString(&parser->m_tempPool, encodingName) : NULL; parser->m_curBase = 0; if (!dtdInit(&parser->m_dtd) || !parser->m_atts || !parser->m_dataBuf || (encodingName && !parser->m_protocolEncodingName)) error = true; else { parser->m_dataBufEnd = parser->m_dataBuf + INIT_DATA_BUF_SIZE; xmlrpc_XmlInitEncoding(&parser->m_initEncoding, &parser->m_encoding, 0); parser->m_internalEncoding = XmlGetInternalEncoding(); error = false; } if (error) xmlrpc_XML_ParserFree(xmlParserP); } else error =true; return error ? NULL : xmlParserP; } XML_Parser xmlrpc_XML_ParserCreateNS(const XML_Char * const encodingName, XML_Char const nsSep) { XML_Parser const xmlParserP = xmlrpc_XML_ParserCreate(encodingName); Parser * const parser = (Parser *)xmlParserP; if (xmlParserP) { xmlrpc_XmlInitEncodingNS(&initEncoding, &parser->m_encoding, 0); ns = 1; internalEncoding = XmlGetInternalEncodingNS(); namespaceSeparator = nsSep; } return xmlParserP; } static void resetErrorString(Parser * const parserP) { if (parserP->m_errorString) { xmlrpc_strfree(parserP->m_errorString); parserP->m_errorString = NULL; } } int xmlrpc_XML_SetEncoding(XML_Parser const xmlParserP, const XML_Char * const encodingName) { Parser * const parser = (Parser *) xmlParserP; int retval; if (!encodingName) { parser->m_protocolEncodingName = NULL; retval = 1; } else { parser->m_protocolEncodingName = poolCopyString(&tempPool, encodingName); if (parser->m_protocolEncodingName) retval = 1; else retval = 0; } return retval; } XML_Parser xmlrpc_XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, const XML_Char *encodingName) { XML_Parser xmlParserP = oldParser; Parser * parser = xmlParserP; DTD *oldDtd = &dtd; XML_StartElementHandler oldStartElementHandler = startElementHandler; XML_EndElementHandler oldEndElementHandler = endElementHandler; XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler; XML_ProcessingInstructionHandler oldProcessingInstructionHandler = processingInstructionHandler; XML_CommentHandler oldCommentHandler = commentHandler; XML_StartCdataSectionHandler oldStartCdataSectionHandler = startCdataSectionHandler; XML_EndCdataSectionHandler oldEndCdataSectionHandler = endCdataSectionHandler; XML_DefaultHandler oldDefaultHandler = defaultHandler; XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler; XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler; XML_ExternalParsedEntityDeclHandler oldExternalParsedEntityDeclHandler = externalParsedEntityDeclHandler; XML_InternalParsedEntityDeclHandler oldInternalParsedEntityDeclHandler = internalParsedEntityDeclHandler; XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler = startNamespaceDeclHandler; XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler = endNamespaceDeclHandler; XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler; XML_ExternalEntityRefHandler oldExternalEntityRefHandler = externalEntityRefHandler; XML_UnknownEncodingHandler oldUnknownEncodingHandler = unknownEncodingHandler; void *oldUserData = userData; void *oldHandlerArg = handlerArg; int oldDefaultExpandInternalEntities = defaultExpandInternalEntities; void *oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg; int oldParamEntityParsing = parser->m_paramEntityParsing; /* Note that the new parser shares the same hash secret as the old parser, so that dtdCopy and copyEntityTable can lookup values from hash tables associated with either parser without us having to worry which hash secrets each table has. */ unsigned long oldhash_secret_salt = hash_secret_salt; parser = (ns ? xmlrpc_XML_ParserCreateNS(encodingName, namespaceSeparator) : xmlrpc_XML_ParserCreate(encodingName)); if (!parser) return 0; startElementHandler = oldStartElementHandler; endElementHandler = oldEndElementHandler; characterDataHandler = oldCharacterDataHandler; processingInstructionHandler = oldProcessingInstructionHandler; commentHandler = oldCommentHandler; startCdataSectionHandler = oldStartCdataSectionHandler; endCdataSectionHandler = oldEndCdataSectionHandler; defaultHandler = oldDefaultHandler; unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; notationDeclHandler = oldNotationDeclHandler; externalParsedEntityDeclHandler = oldExternalParsedEntityDeclHandler; internalParsedEntityDeclHandler = oldInternalParsedEntityDeclHandler; startNamespaceDeclHandler = oldStartNamespaceDeclHandler; endNamespaceDeclHandler = oldEndNamespaceDeclHandler; notStandaloneHandler = oldNotStandaloneHandler; externalEntityRefHandler = oldExternalEntityRefHandler; unknownEncodingHandler = oldUnknownEncodingHandler; userData = oldUserData; if (oldUserData == oldHandlerArg) handlerArg = userData; else handlerArg = parser; if (oldExternalEntityRefHandlerArg != oldParser) externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; defaultExpandInternalEntities = oldDefaultExpandInternalEntities; hash_secret_salt = oldhash_secret_salt; parser->m_paramEntityParsing = oldParamEntityParsing; if (context) { if (!dtdCopy(oldParser, &dtd, oldDtd) || !setContext(parser, context)) { xmlrpc_XML_ParserFree(parser); return 0; } processor = externalEntityInitProcessor; } else { dtdSwap(&dtd, oldDtd); parentParser = oldParser; xmlrpc_XmlPrologStateInitExternalEntity(&prologState); dtd.complete = 1; hadExternalDoctype = 1; } return parser; } static void destroyBindings(BINDING *bindings) { for (;;) { BINDING *b = bindings; if (!b) break; bindings = b->nextTagBinding; free(b->uri); free(b); } } void xmlrpc_XML_ParserFree(XML_Parser parser) { for (;;) { TAG *p; if (tagStack == 0) { if (freeTagList == 0) break; tagStack = freeTagList; freeTagList = 0; } p = tagStack; tagStack = tagStack->parent; free(p->buf); destroyBindings(p->bindings); free(p); } destroyBindings(freeBindingList); destroyBindings(inheritedBindings); poolDestroy(&tempPool); poolDestroy(&temp2Pool); if (parentParser) { if (hadExternalDoctype) dtd.complete = 0; dtdSwap(&dtd, &((Parser *)parentParser)->m_dtd); } dtdDestroy(&dtd); free((void *)atts); free(groupConnector); free(buffer); free(dataBuf); free(unknownEncodingMem); if (unknownEncodingRelease) unknownEncodingRelease(unknownEncodingData); resetErrorString(parser); free(parser); } void xmlrpc_XML_UseParserAsHandlerArg(XML_Parser parser) { handlerArg = parser; } void xmlrpc_XML_SetUserData(XML_Parser parser, void *p) { if (handlerArg == userData) handlerArg = userData = p; else userData = p; } int xmlrpc_XML_SetBase(XML_Parser parser, const XML_Char *p) { if (p) { p = poolCopyString(&dtd.pool, p); if (!p) return 0; curBase = p; } else curBase = 0; return 1; } const XML_Char * xmlrpc_XML_GetBase(XML_Parser parser) { return curBase; } int xmlrpc_XML_GetSpecifiedAttributeCount(XML_Parser parser) { return nSpecifiedAtts; } int xmlrpc_XML_GetIdAttributeIndex(XML_Parser parser) { return idAttIndex; } void xmlrpc_XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end) { startElementHandler = start; endElementHandler = end; } void xmlrpc_XML_SetCharacterDataHandler(XML_Parser parser, XML_CharacterDataHandler handler) { characterDataHandler = handler; } void xmlrpc_XML_SetProcessingInstructionHandler( XML_Parser parser, XML_ProcessingInstructionHandler handler) { processingInstructionHandler = handler; } void xmlrpc_XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler) { commentHandler = handler; } void xmlrpc_XML_SetCdataSectionHandler(XML_Parser parser, XML_StartCdataSectionHandler start, XML_EndCdataSectionHandler end) { startCdataSectionHandler = start; endCdataSectionHandler = end; } void xmlrpc_XML_SetDefaultHandler(XML_Parser parser, XML_DefaultHandler handler) { defaultHandler = handler; defaultExpandInternalEntities = 0; } void xmlrpc_XML_SetDefaultHandlerExpand(XML_Parser parser, XML_DefaultHandler handler) { defaultHandler = handler; defaultExpandInternalEntities = 1; } void xmlrpc_XML_SetDoctypeDeclHandler(XML_Parser parser, XML_StartDoctypeDeclHandler start, XML_EndDoctypeDeclHandler end) { startDoctypeDeclHandler = start; endDoctypeDeclHandler = end; } void xmlrpc_XML_SetUnparsedEntityDeclHandler(XML_Parser parser, XML_UnparsedEntityDeclHandler handler) { unparsedEntityDeclHandler = handler; } void xmlrpc_XML_SetExternalParsedEntityDeclHandler( XML_Parser parser, XML_ExternalParsedEntityDeclHandler handler) { externalParsedEntityDeclHandler = handler; } void xmlrpc_XML_SetInternalParsedEntityDeclHandler( XML_Parser parser, XML_InternalParsedEntityDeclHandler handler) { internalParsedEntityDeclHandler = handler; } void xmlrpc_XML_SetNotationDeclHandler(XML_Parser parser, XML_NotationDeclHandler handler) { notationDeclHandler = handler; } void xmlrpc_XML_SetNamespaceDeclHandler(XML_Parser parser, XML_StartNamespaceDeclHandler start, XML_EndNamespaceDeclHandler end) { startNamespaceDeclHandler = start; endNamespaceDeclHandler = end; } void xmlrpc_XML_SetNotStandaloneHandler(XML_Parser parser, XML_NotStandaloneHandler handler) { notStandaloneHandler = handler; } void xmlrpc_XML_SetExternalEntityRefHandler(XML_Parser parser, XML_ExternalEntityRefHandler handler) { externalEntityRefHandler = handler; } void xmlrpc_XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) { if (arg) externalEntityRefHandlerArg = arg; else externalEntityRefHandlerArg = parser; } void xmlrpc_XML_SetUnknownEncodingHandler(XML_Parser parser, XML_UnknownEncodingHandler handler, void *data) { unknownEncodingHandler = handler; unknownEncodingHandlerData = data; } int xmlrpc_XML_SetParamEntityParsing( XML_Parser const xmlParserP, enum XML_ParamEntityParsing const parsing) { Parser * const parserP = (Parser *) xmlParserP; int retval; parserP->m_paramEntityParsing = parsing; retval = 1; return retval; } static Processor errorProcessor; static void errorProcessor(XML_Parser const parser ATTR_UNUSED, const char * const s ATTR_UNUSED, const char * const end ATTR_UNUSED, const char ** const nextPtr ATTR_UNUSED, enum XML_Error * const errorCodeP, const char ** const errorP) { *errorP = errorString; *errorCodeP = errorCode; } static void parseFinalLen0(Parser * const parser, int * const retvalP) { positionPtr = bufferPtr; parseEndPtr = bufferEnd; processor(parser, bufferPtr, bufferEnd, 0, &errorCode, &errorString); if (errorCode == XML_ERROR_NONE) *retvalP = 1; else { eventEndPtr = eventPtr; processor = errorProcessor; *retvalP = 0; } } static void parseNoBuffer(Parser * const parser, const char * const s, size_t const len, bool const isFinal, int * const succeededP) { parser->m_parseEndByteIndex += len; parser->m_positionPtr = s; if (isFinal) { parser->m_parseEndPtr = s + len; parser->m_processor(parser, s, parser->m_parseEndPtr, 0, &parser->m_errorCode, &parser->m_errorString); if (parser->m_errorCode == XML_ERROR_NONE) *succeededP = true; else { parser->m_eventEndPtr = parser->m_eventPtr; parser->m_processor = errorProcessor; *succeededP = false; } } else { const char * end; parser->m_parseEndPtr = s + len; parser->m_processor(parser, s, s + len, &end, &parser->m_errorCode, &parser->m_errorString); if (parser->m_errorCode != XML_ERROR_NONE) { parser->m_eventEndPtr = parser->m_eventPtr; parser->m_processor = errorProcessor; *succeededP = false; } else { int const nLeftOver = s + len - end; XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, end, &parser->m_position); if (nLeftOver > 0) { if (buffer == 0 || nLeftOver > parser->m_bufferLim - parser->m_buffer) { REALLOCARRAY(parser->m_buffer, len * 2); if (parser->m_buffer) parser->m_bufferLim = parser->m_buffer + len * 2; } if (parser->m_buffer) { memcpy(parser->m_buffer, end, nLeftOver); parser->m_bufferPtr = parser->m_buffer; parser->m_bufferEnd = parser->m_buffer + nLeftOver; *succeededP = true; } else { parser->m_errorCode = XML_ERROR_NO_MEMORY; parser->m_eventPtr = 0; parser->m_eventEndPtr = 0; parser->m_processor = errorProcessor; *succeededP = false; } } else *succeededP = true; } } } int XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) { hash_secret_salt = hash_salt; return 1; } int xmlrpc_XML_Parse(XML_Parser const xmlParserP, const char * const s, size_t const len, int const isFinal) { Parser * const parser = (Parser *) xmlParserP; int retval; resetErrorString(parser); if (parser->m_parentParser == NULL && !startParsing(parser)) { errorCode = XML_ERROR_NO_MEMORY; return 0; } if (len == 0) { if (!isFinal) retval = 1; else parseFinalLen0(parser, &retval); } else if (parser->m_bufferPtr == parser->m_bufferEnd) parseNoBuffer(parser, s, len, isFinal, &retval); else { memcpy(xmlrpc_XML_GetBuffer(parser, len), s, len); retval = xmlrpc_XML_ParseBuffer(parser, len, isFinal); } return retval; } int xmlrpc_XML_ParseBuffer(XML_Parser const xmlParserP, int const len, int const isFinal) { Parser * const parser = (Parser *)xmlParserP; const char * const start = bufferPtr; resetErrorString(parser); if (parser->m_parentParser == NULL && !startParsing(parser)) { errorCode = XML_ERROR_NO_MEMORY; return 0; } parser->m_positionPtr = start; parser->m_bufferEnd += len; parser->m_parseEndByteIndex += len; parser->m_parseEndPtr = parser->m_bufferEnd; parser->m_processor(xmlParserP, start, parser->m_parseEndPtr, isFinal ? NULL : &parser->m_bufferPtr, &parser->m_errorCode, &parser->m_errorString); if (parser->m_errorCode == XML_ERROR_NONE) { if (!isFinal) XmlUpdatePosition(parser->m_encoding, parser->m_positionPtr, parser->m_bufferPtr, &parser->m_position); return 1; } else { parser->m_eventEndPtr = parser->m_eventPtr; parser->m_processor = errorProcessor; return 0; } } void * xmlrpc_XML_GetBuffer(XML_Parser const xmlParserP, size_t const len) { Parser * const parser = (Parser *)xmlParserP; assert(bufferLim >= bufferEnd); if (len > (size_t)(bufferLim - bufferEnd)) { /* FIXME avoid integer overflow */ size_t neededSize = len + (bufferEnd - bufferPtr); assert(bufferLim >= buffer); if (neededSize <= (size_t)(bufferLim - buffer)) { memmove(buffer, bufferPtr, bufferEnd - bufferPtr); bufferEnd = buffer + (bufferEnd - bufferPtr); bufferPtr = buffer; } else { size_t bufferSize; char * newBuf; bufferSize = bufferLim > bufferPtr ? bufferLim - bufferPtr : INIT_BUFFER_SIZE; do { bufferSize *= 2; } while (bufferSize < neededSize); newBuf = malloc(bufferSize); if (newBuf == 0) { errorCode = XML_ERROR_NO_MEMORY; return 0; } bufferLim = newBuf + bufferSize; if (bufferPtr) { memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); free(buffer); } bufferEnd = newBuf + (bufferEnd - bufferPtr); bufferPtr = buffer = newBuf; } } return bufferEnd; } enum XML_Error xmlrpc_XML_GetErrorCode(XML_Parser const parser) { return errorCode; } const char * xmlrpc_XML_GetErrorString(XML_Parser const parser) { if (errorString) return errorString; else if (errorCode == XML_ERROR_NONE) return NULL; else return xmlrpc_XML_ErrorString(errorCode); } long xmlrpc_XML_GetCurrentByteIndex(XML_Parser const parser) { long retval; if (eventPtr) { size_t const bytesLeft = parseEndPtr - eventPtr; if ((size_t)(long)(bytesLeft) != bytesLeft) retval = -1; else retval = parseEndByteIndex - (long)bytesLeft; } else retval = -1; return retval; } int xmlrpc_XML_GetCurrentByteCount(XML_Parser const parser) { int retval; if (eventEndPtr && eventPtr) { size_t const byteCount = eventEndPtr - eventPtr; assert((size_t)(int)byteCount == byteCount); retval = (int)byteCount; } else retval = 0; return retval; } int xmlrpc_XML_GetCurrentLineNumber(XML_Parser const xmlParserP) { Parser * const parser = (Parser *) xmlParserP; if (eventPtr) { XmlUpdatePosition(parser->m_encoding, positionPtr, eventPtr, &position); positionPtr = eventPtr; } return position.lineNumber + 1; } int xmlrpc_XML_GetCurrentColumnNumber(XML_Parser const xmlParserP) { Parser * const parser = (Parser *) xmlParserP; if (eventPtr) { XmlUpdatePosition(parser->m_encoding, positionPtr, eventPtr, &position); positionPtr = eventPtr; } return position.columnNumber; } void xmlrpc_XML_DefaultCurrent(XML_Parser const xmlParserP) { Parser * const parser = (Parser *) xmlParserP; if (defaultHandler) { if (openInternalEntities) reportDefault(xmlParserP, internalEncoding, openInternalEntities->internalEventPtr, openInternalEntities->internalEventEndPtr); else reportDefault(xmlParserP, parser->m_encoding, eventPtr, eventEndPtr); } } const XML_LChar * xmlrpc_XML_ErrorString(int const code) { static const XML_LChar * const message[] = { /* NONE */ NULL, /* NO_MEMORY */ XML_T("out of memory"), /* SYNTAX */ XML_T("syntax error"), /* NO_ELEMENTS */ XML_T("no element found"), /* INVALID_TOKEN */ XML_T("not well-formed"), /* UNCLOSED_TOKEN */ XML_T("unclosed token"), /* PARTIAL_CHAR */ XML_T("unclosed token"), /* TAG_MISMATCH */ XML_T("mismatched tag"), /* DUPLICATE_ATTRIBUTE */ XML_T("duplicate attribute"), /* JUNK_AFTER_DOC_ELEMENT */ XML_T("junk after document element"), /* PARAM_ENTITY_REF */ XML_T("illegal parameter entity reference"), /* UNDEFINED_ENTITY */ XML_T("undefined entity"), /* RECURSIVE_ENTITY_REF */ XML_T("recursive entity reference"), /* ASYNC_ENTITY */ XML_T("asynchronous entity"), /* BAD_CHAR_REF */ XML_T("reference to invalid character number"), /* BINARY_ENTITY_REF */ XML_T("reference to binary entity"), /* ATTRIBUTE_EXTERNAL_ENTITY_REF */ XML_T("reference to external entity in attribute"), /* MISPLACED_XML_PI */ XML_T("xml processing instruction not at start " "of external entity"), /* UNKNOWN_ENCODING */ XML_T("unknown encoding"), /* INCORRECT_ENCODING */ XML_T("encoding specified in XML declaration is incorrect"), /* UNCLOSED_CDATA_SECTION */ XML_T("unclosed CDATA section"), /* EXTERNAL_ENTITY_HANDLING */ XML_T("error in processing external entity reference"), /* NOT_STANDALONE */ XML_T("document is not standalone") }; const XML_LChar * retval; if (code > 0 && (unsigned)code < ARRAY_SIZE(message)) retval = message[code]; else retval = NULL; return retval; } xmlrpc-c-1.33.14/lib/expat/xmlparse/xmlparse.h000066400000000000000000000526021236133176700211540ustar00rootroot00000000000000/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #ifndef XMLPARSE_H_INCLUDED #define XMLPARSE_H_INCLUDED #include "xmlrpc-c/c_util.h" #ifdef __cplusplus extern "C" { #endif typedef void *XML_Parser; /* Information is UTF-8 encoded. */ typedef char XML_Char; typedef char XML_LChar; /* Constructs a new parser; encoding is the encoding specified by the external protocol or null if there is none specified. */ XMLRPC_DLLEXPORT XML_Parser xmlrpc_XML_ParserCreate(const XML_Char * const encoding); /* Constructs a new parser and namespace processor. Element type names and attribute names that belong to a namespace will be expanded; unprefixed attribute names are never expanded; unprefixed element type names are expanded only if there is a default namespace. The expanded name is the concatenation of the namespace URI, the namespace separator character, and the local part of the name. If the namespace separator is '\0' then the namespace URI and the local part will be concatenated without any separator. When a namespace is not declared, the name and prefix will be passed through without expansion. */ XMLRPC_DLLEXPORT XML_Parser xmlrpc_XML_ParserCreateNS(const XML_Char * const encoding, XML_Char const namespaceSeparator); /* atts is array of name/value pairs, terminated by 0; names and values are 0 terminated. */ typedef void (*XML_StartElementHandler)(void *userData, const XML_Char *name, const XML_Char **atts); typedef void (*XML_EndElementHandler)(void *userData, const XML_Char *name); /* s is not 0 terminated. */ typedef void (*XML_CharacterDataHandler)(void *userData, const XML_Char *s, int len); /* target and data are 0 terminated */ typedef void (*XML_ProcessingInstructionHandler)(void *userData, const XML_Char *target, const XML_Char *data); /* data is 0 terminated */ typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); typedef void (*XML_StartCdataSectionHandler)(void *userData); typedef void (*XML_EndCdataSectionHandler)(void *userData); /* This is called for any characters in the XML document for which there is no applicable handler. This includes both characters that are part of markup which is of a kind that is not reported (comments, markup declarations), or characters that are part of a construct which could be reported but for which no handler has been supplied. The characters are passed exactly as they were in the XML document except that they will be encoded in UTF-8. Line boundaries are not normalized. Note that a byte order mark character is not passed to the default handler. There are no guarantees about how characters are divided between calls to the default handler: for example, a comment might be split between multiple calls. */ typedef void (*XML_DefaultHandler)(void *userData, const XML_Char *s, int len); /* This is called for the start of the DOCTYPE declaration when the name of the DOCTYPE is encountered. */ typedef void (*XML_StartDoctypeDeclHandler)(void *userData, const XML_Char *doctypeName); /* This is called for the start of the DOCTYPE declaration when the closing > is encountered, but after processing any external subset. */ typedef void (*XML_EndDoctypeDeclHandler)(void *userData); /* This is called for a declaration of an unparsed (NDATA) entity. The base argument is whatever was set by XML_SetBase. The entityName, systemId and notationName arguments will never be null. The other arguments may be. */ typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, const XML_Char *entityName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName); /* This is called for a declaration of notation. The base argument is whatever was set by XML_SetBase. The notationName will never be null. The other arguments can be. */ typedef void (*XML_NotationDeclHandler)(void *userData, const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId); typedef void (*XML_ExternalParsedEntityDeclHandler)(void *userData, const XML_Char *entityName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId); typedef void (*XML_InternalParsedEntityDeclHandler)(void *userData, const XML_Char *entityName, const XML_Char *replacementText, int replacementTextLength); /* When namespace processing is enabled, these are called once for each namespace declaration. The call to the start and end element handlers occur between the calls to the start and end namespace declaration handlers. For an xmlns attribute, prefix will be null. For an xmlns="" attribute, uri will be null. */ typedef void (*XML_StartNamespaceDeclHandler)(void *userData, const XML_Char *prefix, const XML_Char *uri); typedef void (*XML_EndNamespaceDeclHandler)(void *userData, const XML_Char *prefix); /* This is called if the document is not standalone (it has an external subset or a reference to a parameter entity, but does not have standalone="yes"). If this handler returns 0, then processing will not continue, and the parser will return a XML_ERROR_NOT_STANDALONE error. */ typedef int (*XML_NotStandaloneHandler)(void *userData); /* This is called for a reference to an external parsed general entity. The referenced entity is not automatically parsed. The application can parse it immediately or later using XML_ExternalEntityParserCreate. The parser argument is the parser parsing the entity containing the reference; it can be passed as the parser argument to XML_ExternalEntityParserCreate. The systemId argument is the system identifier as specified in the entity declaration; it will not be null. The base argument is the system identifier that should be used as the base for resolving systemId if systemId was relative; this is set by XML_SetBase; it may be null. The publicId argument is the public identifier as specified in the entity declaration, or null if none was specified; the whitespace in the public identifier will have been normalized as required by the XML spec. The context argument specifies the parsing context in the format expected by the context argument to XML_ExternalEntityParserCreate; context is valid only until the handler returns, so if the referenced entity is to be parsed later, it must be copied. The handler should return 0 if processing should not continue because of a fatal error in the handling of the external entity. In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING error. Note that unlike other handlers the first argument is the parser, not userData. */ typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId); /* This structure is filled in by the XML_UnknownEncodingHandler to provide information to the parser about encodings that are unknown to the parser. The map[b] member gives information about byte sequences whose first byte is b. If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar value c. If map[b] is -1, then the byte sequence is malformed. If map[b] is -n, where n >= 2, then b is the first byte of an n-byte sequence that encodes a single Unicode scalar value. The data member will be passed as the first argument to the convert function. The convert function is used to convert multibyte sequences; s will point to a n-byte sequence where map[(unsigned char)*s] == -n. The convert function must return the Unicode scalar value represented by this byte sequence or -1 if the byte sequence is malformed. The convert function may be null if the encoding is a single-byte encoding, that is if map[b] >= -1 for all bytes b. When the parser is finished with the encoding, then if release is not null, it will call release passing it the data member; once release has been called, the convert function will not be called again. Expat places certain restrictions on the encodings that are supported using this mechanism. 1. Every ASCII character that can appear in a well-formed XML document, other than the characters $@\^`{}~ must be represented by a single byte, and that byte must be the same byte that represents that character in ASCII. 2. No character may require more than 4 bytes to encode. 3. All characters encoded must have Unicode scalar values <= 0xFFFF, (ie characters that would be encoded by surrogates in UTF-16 are not allowed). Note that this restriction doesn't apply to the built-in support for UTF-8 and UTF-16. 4. No Unicode character may be encoded by more than one distinct sequence of bytes. */ typedef struct { int map[256]; void *data; int (*convert)(void *data, const char *s); void (*release)(void *data); } XML_Encoding; /* This is called for an encoding that is unknown to the parser. The encodingHandlerData argument is that which was passed as the second argument to XML_SetUnknownEncodingHandler. The name argument gives the name of the encoding as specified in the encoding declaration. If the callback can provide information about the encoding, it must fill in the XML_Encoding structure, and return 1. Otherwise it must return 0. If info does not describe a suitable encoding, then the parser will return an XML_UNKNOWN_ENCODING error. */ typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, const XML_Char *name, XML_Encoding *info); XMLRPC_DLLEXPORT void xmlrpc_XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end); XMLRPC_DLLEXPORT void xmlrpc_XML_SetCharacterDataHandler(XML_Parser parser, XML_CharacterDataHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetProcessingInstructionHandler( XML_Parser parser, XML_ProcessingInstructionHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetCommentHandler(XML_Parser parser, XML_CommentHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetCdataSectionHandler(XML_Parser parser, XML_StartCdataSectionHandler start, XML_EndCdataSectionHandler end); /* This sets the default handler and also inhibits expansion of internal entities. The entity reference will be passed to the default handler. */ XMLRPC_DLLEXPORT void xmlrpc_XML_SetDefaultHandler(XML_Parser parser, XML_DefaultHandler handler); /* This sets the default handler but does not inhibit expansion of internal entities. The entity reference will not be passed to the default handler. */ XMLRPC_DLLEXPORT void xmlrpc_XML_SetDefaultHandlerExpand(XML_Parser parser, XML_DefaultHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetDoctypeDeclHandler(XML_Parser parser, XML_StartDoctypeDeclHandler start, XML_EndDoctypeDeclHandler end); XMLRPC_DLLEXPORT void xmlrpc_XML_SetUnparsedEntityDeclHandler(XML_Parser parser, XML_UnparsedEntityDeclHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetNotationDeclHandler(XML_Parser parser, XML_NotationDeclHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetExternalParsedEntityDeclHandler( XML_Parser parser, XML_ExternalParsedEntityDeclHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetInternalParsedEntityDeclHandler( XML_Parser parser, XML_InternalParsedEntityDeclHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetNamespaceDeclHandler(XML_Parser parser, XML_StartNamespaceDeclHandler start, XML_EndNamespaceDeclHandler end); XMLRPC_DLLEXPORT void xmlrpc_XML_SetNotStandaloneHandler(XML_Parser parser, XML_NotStandaloneHandler handler); XMLRPC_DLLEXPORT void xmlrpc_XML_SetExternalEntityRefHandler(XML_Parser parser, XML_ExternalEntityRefHandler handler); /* If a non-null value for arg is specified here, then it will be passed as the first argument to the external entity ref handler instead of the parser object. */ XMLRPC_DLLEXPORT void xmlrpc_XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); XMLRPC_DLLEXPORT void xmlrpc_XML_SetUnknownEncodingHandler(XML_Parser parser, XML_UnknownEncodingHandler handler, void *encodingHandlerData); /* This can be called within a handler for a start element, end element, processing instruction or character data. It causes the corresponding markup to be passed to the default handler. */ XMLRPC_DLLEXPORT void xmlrpc_XML_DefaultCurrent(XML_Parser parser); /* This value is passed as the userData argument to callbacks. */ XMLRPC_DLLEXPORT void xmlrpc_XML_SetUserData(XML_Parser parser, void *userData); /* Returns the last value set by XML_SetUserData or null. */ #define XML_GetUserData(parser) (*(void **)(parser)) /* This is equivalent to supplying an encoding argument to XML_ParserCreate. It must not be called after XML_Parse or XML_ParseBuffer. */ XMLRPC_DLLEXPORT int xmlrpc_XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); /* If this function is called, then the parser will be passed as the first argument to callbacks instead of userData. The userData will still be accessible using XML_GetUserData. */ XMLRPC_DLLEXPORT void xmlrpc_XML_UseParserAsHandlerArg(XML_Parser parser); /* Sets the base to be used for resolving relative URIs in system identifiers in declarations. Resolving relative identifiers is left to the application: this value will be passed through as the base argument to the XML_ExternalEntityRefHandler, XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base argument will be copied. Returns zero if out of memory, non-zero otherwise. */ XMLRPC_DLLEXPORT int xmlrpc_XML_SetBase(XML_Parser parser, const XML_Char *base); XMLRPC_DLLEXPORT const XML_Char * xmlrpc_XML_GetBase(XML_Parser parser); /* Returns the number of the attribute/value pairs passed in last call to the XML_StartElementHandler that were specified in the start-tag rather than defaulted. Each attribute/value pair counts as 2; thus this correspondds to an index into the atts array passed to the XML_StartElementHandler. */ XMLRPC_DLLEXPORT int xmlrpc_XML_GetSpecifiedAttributeCount(XML_Parser parser); /* Returns the index of the ID attribute passed in the last call to XML_StartElementHandler, or -1 if there is no ID attribute. Each attribute/value pair counts as 2; thus this correspondds to an index into the atts array passed to the XML_StartElementHandler. */ XMLRPC_DLLEXPORT int xmlrpc_XML_GetIdAttributeIndex(XML_Parser parser); /* Parses some input. Returns 0 if a fatal error is detected. The last call to XML_Parse must have isFinal true; len may be zero for this call (or any other). */ XMLRPC_DLLEXPORT int xmlrpc_XML_Parse(XML_Parser const xmlParserP, const char * const s, size_t const len, int const isFinal); XMLRPC_DLLEXPORT void * xmlrpc_XML_GetBuffer(XML_Parser const xmlParserP, size_t const len); XMLRPC_DLLEXPORT int xmlrpc_XML_ParseBuffer(XML_Parser const parser, int const len, int const isFinal); /* Creates an XML_Parser object that can parse an external general entity; context is a '\0'-terminated string specifying the parse context; encoding is a '\0'-terminated string giving the name of the externally specified encoding, or null if there is no externally specified encoding. The context string consists of a sequence of tokens separated by formfeeds (\f); a token consisting of a name specifies that the general entity of the name is open; a token of the form prefix=uri specifies the namespace for a particular prefix; a token of the form =uri specifies the default namespace. This can be called at any point after the first call to an ExternalEntityRefHandler so longer as the parser has not yet been freed. The new parser is completely independent and may safely be used in a separate thread. The handlers and userData are initialized from the parser argument. Returns 0 if out of memory. Otherwise returns a new XML_Parser object. */ XMLRPC_DLLEXPORT XML_Parser xmlrpc_XML_ExternalEntityParserCreate(XML_Parser parser, const XML_Char *context, const XML_Char *encoding); enum XML_ParamEntityParsing { XML_PARAM_ENTITY_PARSING_NEVER, XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, XML_PARAM_ENTITY_PARSING_ALWAYS }; /* Controls parsing of parameter entities (including the external DTD subset). If parsing of parameter entities is enabled, then references to external parameter entities (including the external DTD subset) will be passed to the handler set with XML_SetExternalEntityRefHandler. The context passed will be 0. Unlike external general entities, external parameter entities can only be parsed synchronously. If the external parameter entity is to be parsed, it must be parsed during the call to the external entity ref handler: the complete sequence of XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and XML_ParserFree calls must be made during this call. After XML_ExternalEntityParserCreate has been called to create the parser for the external parameter entity (context must be 0 for this call), it is illegal to make any calls on the old parser until XML_ParserFree has been called on the newly created parser. If the library has been compiled without support for parameter entity parsing (ie without XML_DTD being defined), then XML_SetParamEntityParsing will return 0 if parsing of parameter entities is requested; otherwise it will return non-zero. */ XMLRPC_DLLEXPORT int xmlrpc_XML_SetParamEntityParsing(XML_Parser parser, enum XML_ParamEntityParsing parsing); /* Sets the hash salt to use for internal hash calculations. Helps in preventing DoS attacks based on predicting hash function behavior. This must be called before parsing is started. Returns 1 if successful, 0 when called after parsing has started. */ int XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt); enum XML_Error { XML_ERROR_NONE, XML_ERROR_NO_MEMORY, XML_ERROR_SYNTAX, XML_ERROR_NO_ELEMENTS, XML_ERROR_INVALID_TOKEN, XML_ERROR_UNCLOSED_TOKEN, XML_ERROR_PARTIAL_CHAR, XML_ERROR_TAG_MISMATCH, XML_ERROR_DUPLICATE_ATTRIBUTE, XML_ERROR_JUNK_AFTER_DOC_ELEMENT, XML_ERROR_PARAM_ENTITY_REF, XML_ERROR_UNDEFINED_ENTITY, XML_ERROR_RECURSIVE_ENTITY_REF, XML_ERROR_ASYNC_ENTITY, XML_ERROR_BAD_CHAR_REF, XML_ERROR_BINARY_ENTITY_REF, XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, XML_ERROR_MISPLACED_XML_PI, XML_ERROR_UNKNOWN_ENCODING, XML_ERROR_INCORRECT_ENCODING, XML_ERROR_UNCLOSED_CDATA_SECTION, XML_ERROR_EXTERNAL_ENTITY_HANDLING, XML_ERROR_NOT_STANDALONE }; /* If xmlrpc_XML_Parse or xmlrpc_XML_ParseBuffer have returned 0, then xmlrpc_XML_GetErrorString and xmlrpc_XML_GetErrorCode return information about the error. */ XMLRPC_DLLEXPORT enum XML_Error xmlrpc_XML_GetErrorCode(XML_Parser const parser); XMLRPC_DLLEXPORT const char * xmlrpc_XML_GetErrorString(XML_Parser const parser); /* These functions return information about the current parse location. They may be called when XML_Parse or XML_ParseBuffer return 0; in this case the location is the location of the character at which the error was detected. They may also be called from any other callback called to report some parse event; in this the location is the location of the first of the sequence of characters that generated the event. */ XMLRPC_DLLEXPORT int xmlrpc_XML_GetCurrentLineNumber(XML_Parser parser); XMLRPC_DLLEXPORT int xmlrpc_XML_GetCurrentColumnNumber(XML_Parser parser); XMLRPC_DLLEXPORT long xmlrpc_XML_GetCurrentByteIndex(XML_Parser parser); /* Return the number of bytes in the current event. Returns 0 if the event is in an internal entity. */ XMLRPC_DLLEXPORT int xmlrpc_XML_GetCurrentByteCount(XML_Parser parser); /* For backwards compatibility with previous versions. */ #define XML_GetErrorLineNumber XML_GetCurrentLineNumber #define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber #define XML_GetErrorByteIndex XML_GetCurrentByteIndex /* Frees memory used by the parser. */ XMLRPC_DLLEXPORT void xmlrpc_XML_ParserFree(XML_Parser parser); /* Returns a string describing the error. */ XMLRPC_DLLEXPORT const XML_LChar * xmlrpc_XML_ErrorString(int const code); #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/lib/expat/xmltok/000077500000000000000000000000001236133176700166265ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/expat/xmltok/Makefile000066400000000000000000000057261236133176700203000ustar00rootroot00000000000000############################################################################### # This directory builds libxmlrpc_xmltok, an XML token parser. This is # essentially the separately distributed Expat library from 2001, but # with slight changes. The main reason it is bundled with Xmlrpc-c is # to make the latter easier to build and use. # # The library is about XML in general. There is nothing specific to # XML-RPC here. ############################################################################### ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') EXPATDIR := $(call updir,$(CURDIR)) LIBDIR := $(call updir,$(EXPATDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/expat/xmltok include $(BLDDIR)/config.mk # I can't figure out what XML_BYTE_ORDER is, but it doesn't look like the # code has ever defined it. That means it's treated like 0 in #if. Since # we started using the Gcc -Wundef option, that generates a warning, so # se set it explicitly to 0 here. CFLAGS_LOCAL = -DXML_BYTE_ORDER=0 # -I. is necessary when blddir != srcdir INCLUDES = -I. -I$(BLDDIR) -Isrcdir/lib/util/include -Isrcdir/include default: all TARGET_LIBRARY_NAMES := libxmlrpc_xmltok STATIC_LIBRARIES_TO_INSTALL = libxmlrpc_xmltok.a SHARED_LIBS_TO_BUILD := libxmlrpc_xmltok SHARED_LIBS_TO_INSTALL := libxmlrpc_xmltok TARGET_MODS = xmltok xmlrole OMIT_XMLTOK_LIB_RULE = Y MAJ=3 # Major number of shared libraries in this directory include $(SRCDIR)/common.mk # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir XMLTOK_SHLIB = $(call shlibfn,libxmlrpc_xmltok) #XMLTOK_SHLIB is e.g. libxmlrpc_xmltok.so.3.1 XMLTOK_SHLIBLE = $(call shliblefn,libxmlrpc_xmltok) #XMLTOK_SHLIBLE is e.g. libxmlrpc_xmltok.so .PHONY: all all: libxmlrpc_xmltok.a $(TARGET_SHARED_LIBRARIES) $(TARGET_SHARED_LE_LIBS) # Rule for this is in common.mk, courtesy of TARGET_LIBRARY_NAMES $(XMLTOK_SHLIB): $(TARGET_MODS:%=%.osh) $(XMLTOK_SHLIB): LIBOBJECTS = $(TARGET_MODS:%=%.osh) # Rule for this is in common.mk, courtesy of TARGET_STATIC_LIBRARIES: libxmlrpc_xmltok.a: $(TARGET_MODS:%=%.o) libxmlrpc_xmltok.a: LIBOBJECTS = $(TARGET_MODS:%=%.o) #----------------------------------------------------------------------------- # RULES TO COMPILE OBJECT MODULES FOR LIBRARIES #----------------------------------------------------------------------------- # Rules to compile object modules from which to build the static and shared # library are in common.mk, courtesy of TARGET_MODS. .PHONY: clean clean: clean-common rm -f nametab.h .PHONY: distclean distclean: clean distclean-common .PHONY: tags tags: TAGS .PHONY: distdir distdir: .PHONY: install install: install-common .PHONY: dep dep: dep-common GENNMTAB = ../gennmtab/gennmtab nametab.h: $(GENNMTAB) rm -f $@ $(GENNMTAB) >$@ $(GENNMTAB): $(MAKE) -C $(dir $@) $(notdir $@) xmltok.o xmltok.osh: nametab.h xmltok_impl.c include depend.mk xmlrpc-c-1.33.14/lib/expat/xmltok/ascii.h000066400000000000000000000034271236133176700200750ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #define ASCII_A 0x41 #define ASCII_B 0x42 #define ASCII_C 0x43 #define ASCII_D 0x44 #define ASCII_E 0x45 #define ASCII_F 0x46 #define ASCII_G 0x47 #define ASCII_H 0x48 #define ASCII_I 0x49 #define ASCII_J 0x4A #define ASCII_K 0x4B #define ASCII_L 0x4C #define ASCII_M 0x4D #define ASCII_N 0x4E #define ASCII_O 0x4F #define ASCII_P 0x50 #define ASCII_Q 0x51 #define ASCII_R 0x52 #define ASCII_S 0x53 #define ASCII_T 0x54 #define ASCII_U 0x55 #define ASCII_V 0x56 #define ASCII_W 0x57 #define ASCII_X 0x58 #define ASCII_Y 0x59 #define ASCII_Z 0x5A #define ASCII_a 0x61 #define ASCII_b 0x62 #define ASCII_c 0x63 #define ASCII_d 0x64 #define ASCII_e 0x65 #define ASCII_f 0x66 #define ASCII_g 0x67 #define ASCII_h 0x68 #define ASCII_i 0x69 #define ASCII_j 0x6A #define ASCII_k 0x6B #define ASCII_l 0x6C #define ASCII_m 0x6D #define ASCII_n 0x6E #define ASCII_o 0x6F #define ASCII_p 0x70 #define ASCII_q 0x71 #define ASCII_r 0x72 #define ASCII_s 0x73 #define ASCII_t 0x74 #define ASCII_u 0x75 #define ASCII_v 0x76 #define ASCII_w 0x77 #define ASCII_x 0x78 #define ASCII_y 0x79 #define ASCII_z 0x7A #define ASCII_0 0x30 #define ASCII_1 0x31 #define ASCII_2 0x32 #define ASCII_3 0x33 #define ASCII_4 0x34 #define ASCII_5 0x35 #define ASCII_6 0x36 #define ASCII_7 0x37 #define ASCII_8 0x38 #define ASCII_9 0x39 #define ASCII_TAB 0x09 #define ASCII_SPACE 0x20 #define ASCII_EXCL 0x21 #define ASCII_QUOT 0x22 #define ASCII_AMP 0x26 #define ASCII_APOS 0x27 #define ASCII_MINUS 0x2D #define ASCII_PERIOD 0x2E #define ASCII_COLON 0x3A #define ASCII_SEMI 0x3B #define ASCII_LT 0x3C #define ASCII_EQUALS 0x3D #define ASCII_GT 0x3E #define ASCII_LSQB 0x5B #define ASCII_RSQB 0x5D #define ASCII_UNDERSCORE 0x5F xmlrpc-c-1.33.14/lib/expat/xmltok/asciitab.h000066400000000000000000000033411236133176700205570ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ /* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, /* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, /* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, /* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, /* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, /* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, /* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, /* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, /* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, xmlrpc-c-1.33.14/lib/expat/xmltok/dllmain.c000066400000000000000000000004351236133176700204140ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #define STRICT 1 #define WIN32_LEAN_AND_MEAN #include BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { return TRUE; } xmlrpc-c-1.33.14/lib/expat/xmltok/iasciitab.h000066400000000000000000000034471236133176700207370ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ /* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ /* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, /* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, /* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, /* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, /* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, /* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, /* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, /* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, /* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, /* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, /* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, /* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, /* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, /* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, /* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, /* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, /* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, /* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, xmlrpc-c-1.33.14/lib/expat/xmltok/latin1tab.h000066400000000000000000000034261236133176700206630ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ /* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, /* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, /* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, /* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, /* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, /* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, /* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, /* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, xmlrpc-c-1.33.14/lib/expat/xmltok/utf8tab.h000066400000000000000000000033441236133176700203600ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ /* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, /* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, /* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, /* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, /* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, /* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, /* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, /* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, /* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, /* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, /* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, /* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, /* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, /* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, /* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, /* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, /* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, xmlrpc-c-1.33.14/lib/expat/xmltok/xmldef.h000066400000000000000000000021061236133176700202550ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include #ifdef XML_WINLIB #define WIN32_LEAN_AND_MEAN #ifndef STRICT #define STRICT 1 #endif #include #define malloc(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define calloc(x, y) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x)*(y)) #define free(x) HeapFree(GetProcessHeap(), 0, (x)) #define realloc(x, y) HeapReAlloc(GetProcessHeap(), 0, x, y) #define abort() /* as nothing */ #else /* not XML_WINLIB */ #include #endif /* not XML_WINLIB */ /* This file can be used for any definitions needed in particular environments. */ /* Mozilla specific defines */ #ifdef MOZILLA_CLIENT #include "nspr.h" #define malloc(x) PR_Malloc((size_t)(x)) #define realloc(x, y) PR_Realloc((x), (size_t)(y)) #define calloc(x, y) PR_Calloc((x),(y)) #define free(x) PR_Free(x) #if PR_BYTES_PER_INT != 4 #define int int32 #endif /* Enable Unicode string processing in expat. */ #ifndef XML_UNICODE #define XML_UNICODE #endif #endif /* MOZILLA_CLIENT */ xmlrpc-c-1.33.14/lib/expat/xmltok/xmlrole.c000066400000000000000000000717171236133176700204710ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include "xmlrpc_config.h" #include "xmldef.h" #include "xmlrole.h" #include "ascii.h" /* Doesn't check: that ,| are not mixed in a model group content of literals */ static const char KW_ANY[] = { ASCII_A, ASCII_N, ASCII_Y, '\0' }; static const char KW_ATTLIST[] = { ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' }; static const char KW_CDATA[] = { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; static const char KW_DOCTYPE[] = { ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' }; static const char KW_ELEMENT[] = { ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' }; static const char KW_EMPTY[] = { ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' }; static const char KW_ENTITIES[] = { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' }; static const char KW_ENTITY[] = { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; static const char KW_FIXED[] = { ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' }; static const char KW_ID[] = { ASCII_I, ASCII_D, '\0' }; static const char KW_IDREF[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; static const char KW_IDREFS[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; static const char KW_IGNORE[] = { ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' }; static const char KW_IMPLIED[] = { ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' }; static const char KW_INCLUDE[] = { ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' }; static const char KW_NDATA[] = { ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; static const char KW_NMTOKEN[] = { ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; static const char KW_NMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' }; static const char KW_NOTATION[] = { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, '\0' }; static const char KW_PCDATA[] = { ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; static const char KW_PUBLIC[] = { ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' }; static const char KW_REQUIRED[] = { ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D, '\0' }; static const char KW_SYSTEM[] = { ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' }; #ifndef MIN_BYTES_PER_CHAR #define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) #endif #define setTopLevel(state) \ ((state)->handler = ((state)->documentEntity \ ? internalSubset \ : externalSubset1)) typedef int PROLOG_HANDLER(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc); static PROLOG_HANDLER prolog0, prolog1, prolog2, doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, internalSubset, entity0, entity1, entity2, entity3, entity4, entity5, entity6, entity7, entity8, entity9, notation0, notation1, notation2, notation3, notation4, attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, attlist7, attlist8, attlist9, element0, element1, element2, element3, element4, element5, element6, element7, externalSubset0, externalSubset1, condSect0, condSect1, condSect2, declClose, error; static int common(PROLOG_STATE *state, int tok); static int prolog0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: state->handler = prolog1; return XML_ROLE_NONE; case XML_TOK_XML_DECL: state->handler = prolog1; return XML_ROLE_XML_DECL; case XML_TOK_PI: state->handler = prolog1; return XML_ROLE_NONE; case XML_TOK_COMMENT: state->handler = prolog1; case XML_TOK_BOM: return XML_ROLE_NONE; case XML_TOK_DECL_OPEN: if (!XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, KW_DOCTYPE)) break; state->handler = doctype0; return XML_ROLE_NONE; case XML_TOK_INSTANCE_START: state->handler = error; return XML_ROLE_INSTANCE_START; } return common(state, tok); } static int prolog1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_PI: case XML_TOK_COMMENT: case XML_TOK_BOM: return XML_ROLE_NONE; case XML_TOK_DECL_OPEN: if (!XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, KW_DOCTYPE)) break; state->handler = doctype0; return XML_ROLE_NONE; case XML_TOK_INSTANCE_START: state->handler = error; return XML_ROLE_INSTANCE_START; } return common(state, tok); } static int prolog2(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_PI: case XML_TOK_COMMENT: return XML_ROLE_NONE; case XML_TOK_INSTANCE_START: state->handler = error; return XML_ROLE_INSTANCE_START; } return common(state, tok); } static int doctype0(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: case XML_TOK_PREFIXED_NAME: state->handler = doctype1; return XML_ROLE_DOCTYPE_NAME; } return common(state, tok); } static int doctype1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_OPEN_BRACKET: state->handler = internalSubset; return XML_ROLE_NONE; case XML_TOK_DECL_CLOSE: state->handler = prolog2; return XML_ROLE_DOCTYPE_CLOSE; case XML_TOK_NAME: if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { state->handler = doctype3; return XML_ROLE_NONE; } if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { state->handler = doctype2; return XML_ROLE_NONE; } break; } return common(state, tok); } static int doctype2(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = doctype3; return XML_ROLE_DOCTYPE_PUBLIC_ID; } return common(state, tok); } static int doctype3(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = doctype4; return XML_ROLE_DOCTYPE_SYSTEM_ID; } return common(state, tok); } static int doctype4(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_OPEN_BRACKET: state->handler = internalSubset; return XML_ROLE_NONE; case XML_TOK_DECL_CLOSE: state->handler = prolog2; return XML_ROLE_DOCTYPE_CLOSE; } return common(state, tok); } static int doctype5(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_DECL_CLOSE: state->handler = prolog2; return XML_ROLE_DOCTYPE_CLOSE; } return common(state, tok); } static int internalSubset(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_DECL_OPEN: if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, KW_ENTITY)) { state->handler = entity0; return XML_ROLE_NONE; } if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, KW_ATTLIST)) { state->handler = attlist0; return XML_ROLE_NONE; } if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, KW_ELEMENT)) { state->handler = element0; return XML_ROLE_NONE; } if (XmlNameMatchesAscii(enc, ptr + 2 * MIN_BYTES_PER_CHAR(enc), end, KW_NOTATION)) { state->handler = notation0; return XML_ROLE_NONE; } break; case XML_TOK_PI: case XML_TOK_COMMENT: return XML_ROLE_NONE; case XML_TOK_PARAM_ENTITY_REF: return XML_ROLE_PARAM_ENTITY_REF; case XML_TOK_CLOSE_BRACKET: state->handler = doctype5; return XML_ROLE_NONE; } return common(state, tok); } static int externalSubset0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { state->handler = externalSubset1; if (tok == XML_TOK_XML_DECL) return XML_ROLE_TEXT_DECL; return externalSubset1(state, tok, ptr, end, enc); } static int externalSubset1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_COND_SECT_OPEN: state->handler = condSect0; return XML_ROLE_NONE; case XML_TOK_COND_SECT_CLOSE: if (state->includeLevel == 0) break; state->includeLevel -= 1; return XML_ROLE_NONE; case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_CLOSE_BRACKET: break; case XML_TOK_NONE: if (state->includeLevel) break; return XML_ROLE_NONE; default: return internalSubset(state, tok, ptr, end, enc); } return common(state, tok); } static int entity0(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_PERCENT: state->handler = entity1; return XML_ROLE_NONE; case XML_TOK_NAME: state->handler = entity2; return XML_ROLE_GENERAL_ENTITY_NAME; } return common(state, tok); } static int entity1(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: state->handler = entity7; return XML_ROLE_PARAM_ENTITY_NAME; } return common(state, tok); } static int entity2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { state->handler = entity4; return XML_ROLE_NONE; } if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { state->handler = entity3; return XML_ROLE_NONE; } break; case XML_TOK_LITERAL: state->handler = declClose; return XML_ROLE_ENTITY_VALUE; } return common(state, tok); } static int entity3(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = entity4; return XML_ROLE_ENTITY_PUBLIC_ID; } return common(state, tok); } static int entity4(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = entity5; return XML_ROLE_ENTITY_SYSTEM_ID; } return common(state, tok); } static int entity5(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_DECL_CLOSE: setTopLevel(state); return XML_ROLE_EXTERNAL_GENERAL_ENTITY_NO_NOTATION; case XML_TOK_NAME: if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) { state->handler = entity6; return XML_ROLE_NONE; } break; } return common(state, tok); } static int entity6(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: state->handler = declClose; return XML_ROLE_ENTITY_NOTATION_NAME; } return common(state, tok); } static int entity7(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { state->handler = entity9; return XML_ROLE_NONE; } if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { state->handler = entity8; return XML_ROLE_NONE; } break; case XML_TOK_LITERAL: state->handler = declClose; return XML_ROLE_ENTITY_VALUE; } return common(state, tok); } static int entity8(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = entity9; return XML_ROLE_ENTITY_PUBLIC_ID; } return common(state, tok); } static int entity9(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = declClose; return XML_ROLE_ENTITY_SYSTEM_ID; } return common(state, tok); } static int notation0(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: state->handler = notation1; return XML_ROLE_NOTATION_NAME; } return common(state, tok); } static int notation1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { state->handler = notation3; return XML_ROLE_NONE; } if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { state->handler = notation2; return XML_ROLE_NONE; } break; } return common(state, tok); } static int notation2(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = notation4; return XML_ROLE_NOTATION_PUBLIC_ID; } return common(state, tok); } static int notation3(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = declClose; return XML_ROLE_NOTATION_SYSTEM_ID; } return common(state, tok); } static int notation4(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = declClose; return XML_ROLE_NOTATION_SYSTEM_ID; case XML_TOK_DECL_CLOSE: setTopLevel(state); return XML_ROLE_NOTATION_NO_SYSTEM_ID; } return common(state, tok); } static int attlist0(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: case XML_TOK_PREFIXED_NAME: state->handler = attlist1; return XML_ROLE_ATTLIST_ELEMENT_NAME; } return common(state, tok); } static int attlist1(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_DECL_CLOSE: setTopLevel(state); return XML_ROLE_NONE; case XML_TOK_NAME: case XML_TOK_PREFIXED_NAME: state->handler = attlist2; return XML_ROLE_ATTRIBUTE_NAME; } return common(state, tok); } static int attlist2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: { static const char *types[] = { KW_CDATA, KW_ID, KW_IDREF, KW_IDREFS, KW_ENTITY, KW_ENTITIES, KW_NMTOKEN, KW_NMTOKENS, }; int i; for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) if (XmlNameMatchesAscii(enc, ptr, end, types[i])) { state->handler = attlist8; return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; } } if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) { state->handler = attlist5; return XML_ROLE_NONE; } break; case XML_TOK_OPEN_PAREN: state->handler = attlist3; return XML_ROLE_NONE; } return common(state, tok); } static int attlist3(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NMTOKEN: case XML_TOK_NAME: case XML_TOK_PREFIXED_NAME: state->handler = attlist4; return XML_ROLE_ATTRIBUTE_ENUM_VALUE; } return common(state, tok); } static int attlist4(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_CLOSE_PAREN: state->handler = attlist8; return XML_ROLE_NONE; case XML_TOK_OR: state->handler = attlist3; return XML_ROLE_NONE; } return common(state, tok); } static int attlist5(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_OPEN_PAREN: state->handler = attlist6; return XML_ROLE_NONE; } return common(state, tok); } static int attlist6(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: state->handler = attlist7; return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; } return common(state, tok); } static int attlist7(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_CLOSE_PAREN: state->handler = attlist8; return XML_ROLE_NONE; case XML_TOK_OR: state->handler = attlist6; return XML_ROLE_NONE; } return common(state, tok); } /* default value */ static int attlist8(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_POUND_NAME: if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end, KW_IMPLIED)) { state->handler = attlist1; return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; } if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end, KW_REQUIRED)) { state->handler = attlist1; return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; } if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end, KW_FIXED)) { state->handler = attlist9; return XML_ROLE_NONE; } break; case XML_TOK_LITERAL: state->handler = attlist1; return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; } return common(state, tok); } static int attlist9(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_LITERAL: state->handler = attlist1; return XML_ROLE_FIXED_ATTRIBUTE_VALUE; } return common(state, tok); } static int element0(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: case XML_TOK_PREFIXED_NAME: state->handler = element1; return XML_ROLE_ELEMENT_NAME; } return common(state, tok); } static int element1(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) { state->handler = declClose; return XML_ROLE_CONTENT_EMPTY; } if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) { state->handler = declClose; return XML_ROLE_CONTENT_ANY; } break; case XML_TOK_OPEN_PAREN: state->handler = element2; state->level = 1; return XML_ROLE_GROUP_OPEN; } return common(state, tok); } static int element2(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_POUND_NAME: if (XmlNameMatchesAscii(enc, ptr + MIN_BYTES_PER_CHAR(enc), end, KW_PCDATA)) { state->handler = element3; return XML_ROLE_CONTENT_PCDATA; } break; case XML_TOK_OPEN_PAREN: state->level = 2; state->handler = element6; return XML_ROLE_GROUP_OPEN; case XML_TOK_NAME: case XML_TOK_PREFIXED_NAME: state->handler = element7; return XML_ROLE_CONTENT_ELEMENT; case XML_TOK_NAME_QUESTION: state->handler = element7; return XML_ROLE_CONTENT_ELEMENT_OPT; case XML_TOK_NAME_ASTERISK: state->handler = element7; return XML_ROLE_CONTENT_ELEMENT_REP; case XML_TOK_NAME_PLUS: state->handler = element7; return XML_ROLE_CONTENT_ELEMENT_PLUS; } return common(state, tok); } static int element3(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_CLOSE_PAREN: case XML_TOK_CLOSE_PAREN_ASTERISK: state->handler = declClose; return XML_ROLE_GROUP_CLOSE_REP; case XML_TOK_OR: state->handler = element4; return XML_ROLE_NONE; } return common(state, tok); } static int element4(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: case XML_TOK_PREFIXED_NAME: state->handler = element5; return XML_ROLE_CONTENT_ELEMENT; } return common(state, tok); } static int element5(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_CLOSE_PAREN_ASTERISK: state->handler = declClose; return XML_ROLE_GROUP_CLOSE_REP; case XML_TOK_OR: state->handler = element4; return XML_ROLE_NONE; } return common(state, tok); } static int element6(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_OPEN_PAREN: state->level += 1; return XML_ROLE_GROUP_OPEN; case XML_TOK_NAME: case XML_TOK_PREFIXED_NAME: state->handler = element7; return XML_ROLE_CONTENT_ELEMENT; case XML_TOK_NAME_QUESTION: state->handler = element7; return XML_ROLE_CONTENT_ELEMENT_OPT; case XML_TOK_NAME_ASTERISK: state->handler = element7; return XML_ROLE_CONTENT_ELEMENT_REP; case XML_TOK_NAME_PLUS: state->handler = element7; return XML_ROLE_CONTENT_ELEMENT_PLUS; } return common(state, tok); } static int element7(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_CLOSE_PAREN: state->level -= 1; if (state->level == 0) state->handler = declClose; return XML_ROLE_GROUP_CLOSE; case XML_TOK_CLOSE_PAREN_ASTERISK: state->level -= 1; if (state->level == 0) state->handler = declClose; return XML_ROLE_GROUP_CLOSE_REP; case XML_TOK_CLOSE_PAREN_QUESTION: state->level -= 1; if (state->level == 0) state->handler = declClose; return XML_ROLE_GROUP_CLOSE_OPT; case XML_TOK_CLOSE_PAREN_PLUS: state->level -= 1; if (state->level == 0) state->handler = declClose; return XML_ROLE_GROUP_CLOSE_PLUS; case XML_TOK_COMMA: state->handler = element6; return XML_ROLE_GROUP_SEQUENCE; case XML_TOK_OR: state->handler = element6; return XML_ROLE_GROUP_CHOICE; } return common(state, tok); } static int condSect0(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_NAME: if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) { state->handler = condSect1; return XML_ROLE_NONE; } if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) { state->handler = condSect2; return XML_ROLE_NONE; } break; } return common(state, tok); } static int condSect1(PROLOG_STATE * state, int tok, const char * ptr ATTR_UNUSED, const char * end ATTR_UNUSED, const ENCODING * enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_OPEN_BRACKET: state->handler = externalSubset1; state->includeLevel += 1; return XML_ROLE_NONE; } return common(state, tok); } static int condSect2(PROLOG_STATE * state, int tok, const char * ptr ATTR_UNUSED, const char * end ATTR_UNUSED, const ENCODING * enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_OPEN_BRACKET: state->handler = externalSubset1; return XML_ROLE_IGNORE_SECT; } return common(state, tok); } static int declClose(PROLOG_STATE *state, int tok, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { switch (tok) { case XML_TOK_PROLOG_S: return XML_ROLE_NONE; case XML_TOK_DECL_CLOSE: setTopLevel(state); return XML_ROLE_NONE; } return common(state, tok); } #if 0 static int ignore(PROLOG_STATE *state, int tok, const char *ptr, const char *end, const ENCODING *enc) { switch (tok) { case XML_TOK_DECL_CLOSE: state->handler = internalSubset; return 0; default: return XML_ROLE_NONE; } return common(state, tok); } #endif static int error(PROLOG_STATE *state ATTR_UNUSED, int tok ATTR_UNUSED, const char *ptr ATTR_UNUSED, const char *end ATTR_UNUSED, const ENCODING *enc ATTR_UNUSED) { return XML_ROLE_NONE; } static int common(PROLOG_STATE *state, int tok ATTR_UNUSED) { if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) return XML_ROLE_INNER_PARAM_ENTITY_REF; state->handler = error; return XML_ROLE_ERROR; } void xmlrpc_XmlPrologStateInit(PROLOG_STATE * const state) { state->handler = prolog0; state->documentEntity = 1; state->includeLevel = 0; } void xmlrpc_XmlPrologStateInitExternalEntity(PROLOG_STATE * const state) { state->handler = externalSubset0; state->documentEntity = 0; state->includeLevel = 0; } xmlrpc-c-1.33.14/lib/expat/xmltok/xmlrole.h000066400000000000000000000046041236133176700204650ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #ifndef XMLROLE_H_INCLUDED #define XMLROLE_H_INCLUDED #include "xmlrpc-c/c_util.h" #include "xmltok.h" #ifdef __cplusplus extern "C" { #endif enum { XML_ROLE_ERROR = -1, XML_ROLE_NONE = 0, XML_ROLE_XML_DECL, XML_ROLE_INSTANCE_START, XML_ROLE_DOCTYPE_NAME, XML_ROLE_DOCTYPE_SYSTEM_ID, XML_ROLE_DOCTYPE_PUBLIC_ID, XML_ROLE_DOCTYPE_CLOSE, XML_ROLE_GENERAL_ENTITY_NAME, XML_ROLE_PARAM_ENTITY_NAME, XML_ROLE_ENTITY_VALUE, XML_ROLE_ENTITY_SYSTEM_ID, XML_ROLE_ENTITY_PUBLIC_ID, XML_ROLE_ENTITY_NOTATION_NAME, XML_ROLE_NOTATION_NAME, XML_ROLE_NOTATION_SYSTEM_ID, XML_ROLE_NOTATION_NO_SYSTEM_ID, XML_ROLE_NOTATION_PUBLIC_ID, XML_ROLE_ATTRIBUTE_NAME, XML_ROLE_ATTRIBUTE_TYPE_CDATA, XML_ROLE_ATTRIBUTE_TYPE_ID, XML_ROLE_ATTRIBUTE_TYPE_IDREF, XML_ROLE_ATTRIBUTE_TYPE_IDREFS, XML_ROLE_ATTRIBUTE_TYPE_ENTITY, XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, XML_ROLE_ATTRIBUTE_ENUM_VALUE, XML_ROLE_ATTRIBUTE_NOTATION_VALUE, XML_ROLE_ATTLIST_ELEMENT_NAME, XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, XML_ROLE_FIXED_ATTRIBUTE_VALUE, XML_ROLE_ELEMENT_NAME, XML_ROLE_CONTENT_ANY, XML_ROLE_CONTENT_EMPTY, XML_ROLE_CONTENT_PCDATA, XML_ROLE_GROUP_OPEN, XML_ROLE_GROUP_CLOSE, XML_ROLE_GROUP_CLOSE_REP, XML_ROLE_GROUP_CLOSE_OPT, XML_ROLE_GROUP_CLOSE_PLUS, XML_ROLE_GROUP_CHOICE, XML_ROLE_GROUP_SEQUENCE, XML_ROLE_CONTENT_ELEMENT, XML_ROLE_CONTENT_ELEMENT_REP, XML_ROLE_CONTENT_ELEMENT_OPT, XML_ROLE_CONTENT_ELEMENT_PLUS, XML_ROLE_TEXT_DECL, XML_ROLE_IGNORE_SECT, XML_ROLE_INNER_PARAM_ENTITY_REF, XML_ROLE_PARAM_ENTITY_REF, XML_ROLE_EXTERNAL_GENERAL_ENTITY_NO_NOTATION }; typedef struct prolog_state { int (*handler)(struct prolog_state *state, int tok, const char *ptr, const char *end, const ENCODING *enc); unsigned level; unsigned includeLevel; int documentEntity; } PROLOG_STATE; XMLRPC_DLLEXPORT void xmlrpc_XmlPrologStateInit(PROLOG_STATE * const state); XMLRPC_DLLEXPORT void xmlrpc_XmlPrologStateInitExternalEntity(PROLOG_STATE * const state); #define XmlTokenRole(state, tok, ptr, end, enc) \ (((state)->handler)(state, tok, ptr, end, enc)) #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/lib/expat/xmltok/xmltok.c000066400000000000000000001157121236133176700203170ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include #include "xmlrpc_config.h" #include "bool.h" #include "c_util.h" #include "xmldef.h" #include "xmltok.h" #include "nametab.h" #define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok) #define VTABLE1 \ { PREFIX(prologTok), PREFIX(contentTok), \ PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \ { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ PREFIX(sameName), \ PREFIX(nameMatchesAscii), \ PREFIX(nameLength), \ PREFIX(skipS), \ PREFIX(getAtts), \ PREFIX(charRefNumber), \ PREFIX(predefinedEntityName), \ PREFIX(updatePosition), \ PREFIX(isPublicId) #define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) #define UCS2_GET_NAMING(pages, hi, lo) \ (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) /* A 2 byte UTF-8 representation splits the characters 11 bits between the bottom 5 and 6 bits of the bytes. We need 8 bits to index into pages, 3 bits to add to that index and 5 bits to generate the mask. */ #define UTF8_GET_NAMING2(pages, byte) \ (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + ((((byte)[0]) & 3) << 1) \ + ((((byte)[1]) >> 5) & 1)] \ & (1 << (((byte)[1]) & 0x1F))) /* A 3 byte UTF-8 representation splits the characters 16 bits between the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index into pages, 3 bits to add to that index and 5 bits to generate the mask. */ #define UTF8_GET_NAMING3(pages, byte) \ (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ + ((((byte)[1]) >> 2) & 0xF)] \ << 3) \ + ((((byte)[1]) & 3) << 1) \ + ((((byte)[2]) >> 5) & 1)] \ & (1 << (((byte)[2]) & 0x1F))) #define UTF8_GET_NAMING(pages, p, n) \ ((n) == 2 \ ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ : ((n) == 3 \ ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ : 0)) #define UTF8_INVALID3(p) \ ((*p) == 0xED \ ? (((p)[1] & 0x20) != 0) \ : ((*p) == 0xEF \ ? ((p)[1] == 0xBF && ((p)[2] == 0xBF || (p)[2] == 0xBE)) \ : 0)) #define UTF8_INVALID4(p) ((*p) == 0xF4 && ((p)[1] & 0x30) != 0) static int isNever(const ENCODING *enc ATTR_UNUSED, const char *p ATTR_UNUSED) { return 0; } static int utf8_isName2(const ENCODING *enc ATTR_UNUSED, const char *p) { return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); } static int utf8_isName3(const ENCODING *enc ATTR_UNUSED, const char *p) { return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); } #define utf8_isName4 isNever static int utf8_isNmstrt2(const ENCODING *enc ATTR_UNUSED, const char *p) { return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); } static int utf8_isNmstrt3(const ENCODING *enc ATTR_UNUSED, const char *p) { return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); } #define utf8_isNmstrt4 isNever #define utf8_isInvalid2 isNever static int utf8_isInvalid3(const ENCODING *enc ATTR_UNUSED, const char *p) { return UTF8_INVALID3((const unsigned char *)p); } static int utf8_isInvalid4(const ENCODING *enc ATTR_UNUSED, const char *p) { return UTF8_INVALID4((const unsigned char *)p); } struct normal_encoding { ENCODING enc; unsigned char type[256]; #ifdef XML_MIN_SIZE int (*byteType)(const ENCODING *, const char *); int (*isNameMin)(const ENCODING *, const char *); int (*isNmstrtMin)(const ENCODING *, const char *); int (*byteToAscii)(const ENCODING *, const char *); int (*charMatches)(const ENCODING *, const char *, int); #endif /* XML_MIN_SIZE */ int (*isName2)(const ENCODING *, const char *); int (*isName3)(const ENCODING *, const char *); int (*isName4)(const ENCODING *, const char *); int (*isNmstrt2)(const ENCODING *, const char *); int (*isNmstrt3)(const ENCODING *, const char *); int (*isNmstrt4)(const ENCODING *, const char *); int (*isInvalid2)(const ENCODING *, const char *); int (*isInvalid3)(const ENCODING *, const char *); int (*isInvalid4)(const ENCODING *, const char *); }; #ifdef XML_MIN_SIZE #define STANDARD_VTABLE(E) \ E ## byteType, \ E ## isNameMin, \ E ## isNmstrtMin, \ E ## byteToAscii, \ E ## charMatches, #else #define STANDARD_VTABLE(E) /* as nothing */ #endif #define NORMAL_VTABLE(E) \ E ## isName2, \ E ## isName3, \ E ## isName4, \ E ## isNmstrt2, \ E ## isNmstrt3, \ E ## isNmstrt4, \ E ## isInvalid2, \ E ## isInvalid3, \ E ## isInvalid4 #define NULL_NORMAL_VTABLE \ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL static int checkCharRefNumber(int); #include "xmltok_impl.h" #include "ascii.h" #ifdef XML_MIN_SIZE #define sb_isNameMin isNever #define sb_isNmstrtMin isNever #endif #ifdef XML_MIN_SIZE #define MINBPC(enc) ((enc)->minBytesPerChar) #else /* minimum bytes per character */ #define MINBPC(enc) 1 #endif #define SB_BYTE_TYPE(enc, p) \ (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) #ifdef XML_MIN_SIZE static int sb_byteType(const ENCODING *enc, const char *p) { return SB_BYTE_TYPE(enc, p); } #define BYTE_TYPE(enc, p) \ (((const struct normal_encoding *)(enc))->byteType(enc, p)) #else #define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) #endif #ifdef XML_MIN_SIZE #define BYTE_TO_ASCII(enc, p) \ (((const struct normal_encoding *)(enc))->byteToAscii(enc, p)) static int sb_byteToAscii(const ENCODING *enc, const char *p) { return *p; } #else #define BYTE_TO_ASCII(enc, p) (*(p)) #endif #define IS_NAME_CHAR(enc, p, n) \ (((const struct normal_encoding *)(enc))->isName ## n(enc, p)) #define IS_NMSTRT_CHAR(enc, p, n) \ (((const struct normal_encoding *)(enc))->isNmstrt ## n(enc, p)) #define IS_INVALID_CHAR(enc, p, n) \ (((const struct normal_encoding *)(enc))->isInvalid ## n(enc, p)) #ifdef XML_MIN_SIZE #define IS_NAME_CHAR_MINBPC(enc, p) \ (((const struct normal_encoding *)(enc))->isNameMin(enc, p)) #define IS_NMSTRT_CHAR_MINBPC(enc, p) \ (((const struct normal_encoding *)(enc))->isNmstrtMin(enc, p)) #else #define IS_NAME_CHAR_MINBPC(enc, p) (0) #define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) #endif #ifdef XML_MIN_SIZE #define CHAR_MATCHES(enc, p, c) \ (((const struct normal_encoding *)(enc))->charMatches(enc, p, c)) static int sb_charMatches(const ENCODING *enc, const char *p, int c) { return *p == c; } #else /* c is an ASCII character */ #define CHAR_MATCHES(enc, p, c) (*(p) == c) #endif #define PREFIX(ident) normal_ ## ident #include "xmltok_impl.c" #undef MINBPC #undef BYTE_TYPE #undef BYTE_TO_ASCII #undef CHAR_MATCHES #undef IS_NAME_CHAR #undef IS_NAME_CHAR_MINBPC #undef IS_NMSTRT_CHAR #undef IS_NMSTRT_CHAR_MINBPC #undef IS_INVALID_CHAR enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ UTF8_cval1 = 0x00, UTF8_cval2 = 0xc0, UTF8_cval3 = 0xe0, UTF8_cval4 = 0xf0 }; static void utf8_toUtf8(const ENCODING * enc ATTR_UNUSED, const char **fromP, const char *fromLim, char **toP, const char *toLim) { char *to; const char *from; if (fromLim - *fromP > toLim - *toP) { /* Avoid copying partial characters. */ for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) break; } for (to = *toP, from = *fromP; from != fromLim; from++, to++) *to = *from; *fromP = from; *toP = to; } static void utf8_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, unsigned short **toP, const unsigned short *toLim) { unsigned short *to = *toP; const char *from = *fromP; while (from != fromLim && to != toLim) { switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { case BT_LEAD2: *to++ = ((from[0] & 0x1f) << 6) | (from[1] & 0x3f); from += 2; break; case BT_LEAD3: *to++ = ((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f); from += 3; break; case BT_LEAD4: { unsigned long n; if (to + 1 == toLim) break; n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); n -= 0x10000; to[0] = (unsigned short)((n >> 10) | 0xD800); to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); to += 2; from += 4; } break; default: *to++ = *from++; break; } } *fromP = from; *toP = to; } static const struct normal_encoding utf8_encoding_ns = { { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, { #include "asciitab.h" #include "utf8tab.h" }, STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) }; static const struct normal_encoding utf8_encoding = { { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, { #define BT_COLON BT_NMSTRT #include "asciitab.h" #undef BT_COLON #include "utf8tab.h" }, STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) }; static const struct normal_encoding internal_utf8_encoding_ns = { { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, { #include "iasciitab.h" #include "utf8tab.h" }, STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) }; static const struct normal_encoding internal_utf8_encoding = { { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, { #define BT_COLON BT_NMSTRT #include "iasciitab.h" #undef BT_COLON #include "utf8tab.h" }, STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) }; static Utf8Converter latin1_toUtf8; static void latin1_toUtf8(const ENCODING * const enc ATTR_UNUSED, const char ** const fromP, const char * const fromLim, char ** const toP, const char * const toLim) { /*---------------------------------------------------------------------------- Convert the Latin1 string to UTF-8. This is a Utf8Converter subroutine. See documentation of the Utf8Converter type for details. Note: a latin1 input character converts to 1 or 2 UTF-8 output bytes. -----------------------------------------------------------------------------*/ bool bufferIsFull; assert(toLim - *toP >= 2); /* Calling condition */ for (bufferIsFull = false; *fromP != fromLim && !bufferIsFull;) { unsigned char const c = (unsigned char)**fromP; if (c & 0x80) { if (toLim - *toP < 2) bufferIsFull = true; else { *(*toP)++ = ((c >> 6) | UTF8_cval2); *(*toP)++ = ((c & 0x3f) | 0x80); ++(*fromP); } } else { if (*toP == toLim) bufferIsFull = true; else *(*toP)++ = *(*fromP)++; } } } static void latin1_toUtf16(const ENCODING *enc ATTR_UNUSED, const char **fromP, const char *fromLim, unsigned short **toP, const unsigned short *toLim) { while (*fromP != fromLim && *toP != toLim) *(*toP)++ = (unsigned char)*(*fromP)++; } static const struct normal_encoding latin1_encoding_ns = { { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, { #include "asciitab.h" #include "latin1tab.h" }, STANDARD_VTABLE(sb_) NULL_NORMAL_VTABLE }; static const struct normal_encoding latin1_encoding = { { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, { #define BT_COLON BT_NMSTRT #include "asciitab.h" #undef BT_COLON #include "latin1tab.h" }, STANDARD_VTABLE(sb_) NULL_NORMAL_VTABLE }; static void ascii_toUtf8(const ENCODING *enc ATTR_UNUSED, const char **fromP, const char *fromLim, char **toP, const char *toLim) { while (*fromP != fromLim && *toP != toLim) *(*toP)++ = *(*fromP)++; } static const struct normal_encoding ascii_encoding_ns = { { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, { #include "asciitab.h" /* BT_NONXML == 0 */ }, STANDARD_VTABLE(sb_) NULL_NORMAL_VTABLE }; static const struct normal_encoding ascii_encoding = { { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, { #define BT_COLON BT_NMSTRT #include "asciitab.h" #undef BT_COLON /* BT_NONXML == 0 */ }, STANDARD_VTABLE(sb_) NULL_NORMAL_VTABLE }; static int unicode_byte_type(char hi, char lo) { switch ((unsigned char)hi) { case 0xD8: case 0xD9: case 0xDA: case 0xDB: return BT_LEAD4; case 0xDC: case 0xDD: case 0xDE: case 0xDF: return BT_TRAIL; case 0xFF: switch ((unsigned char)lo) { case 0xFF: case 0xFE: return BT_NONXML; } break; } return BT_NONASCII; } #define DEFINE_UTF16_TO_UTF8(E) \ static \ void E ## toUtf8(const ENCODING *enc ATTR_UNUSED, \ const char **fromP, const char *fromLim, \ char **toP, const char *toLim) \ { \ const char *from; \ for (from = *fromP; from != fromLim; from += 2) { \ int plane; \ unsigned char lo2; \ unsigned char lo = GET_LO(from); \ unsigned char hi = GET_HI(from); \ switch (hi) { \ case 0: \ if (lo < 0x80) { \ if (*toP == toLim) { \ *fromP = from; \ return; \ } \ *(*toP)++ = lo; \ break; \ } \ /* fall through */ \ case 0x1: case 0x2: case 0x3: \ case 0x4: case 0x5: case 0x6: case 0x7: \ if (toLim - *toP < 2) { \ *fromP = from; \ return; \ } \ *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ *(*toP)++ = ((lo & 0x3f) | 0x80); \ break; \ default: \ if (toLim - *toP < 3) { \ *fromP = from; \ return; \ } \ /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ *(*toP)++ = ((lo & 0x3f) | 0x80); \ break; \ case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ if (toLim - *toP < 4) { \ *fromP = from; \ return; \ } \ plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ from += 2; \ lo2 = GET_LO(from); \ *(*toP)++ = (((lo & 0x3) << 4) \ | ((GET_HI(from) & 0x3) << 2) \ | (lo2 >> 6) \ | 0x80); \ *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ break; \ } \ } \ *fromP = from; \ } #define DEFINE_UTF16_TO_UTF16(E) \ static \ void E ## toUtf16(const ENCODING *enc ATTR_UNUSED, \ const char **fromP, const char *fromLim, \ unsigned short **toP, const unsigned short *toLim) \ { \ /* Avoid copying first half only of surrogate */ \ if (fromLim - *fromP > ((toLim - *toP) << 1) \ && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ fromLim -= 2; \ for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ } #define SET2(ptr, ch) \ (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) #define GET_LO(ptr) ((unsigned char)(ptr)[0]) #define GET_HI(ptr) ((unsigned char)(ptr)[1]) DEFINE_UTF16_TO_UTF8(little2_) DEFINE_UTF16_TO_UTF16(little2_) #undef SET2 #undef GET_LO #undef GET_HI #define SET2(ptr, ch) \ (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) #define GET_LO(ptr) ((unsigned char)(ptr)[1]) #define GET_HI(ptr) ((unsigned char)(ptr)[0]) DEFINE_UTF16_TO_UTF8(big2_) DEFINE_UTF16_TO_UTF16(big2_) #undef SET2 #undef GET_LO #undef GET_HI #define LITTLE2_BYTE_TYPE(enc, p) \ ((p)[1] == 0 \ ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ : unicode_byte_type((p)[1], (p)[0])) #define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) #define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) #define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \ UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) #define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) #ifdef XML_MIN_SIZE static int little2_byteType(const ENCODING *enc, const char *p) { return LITTLE2_BYTE_TYPE(enc, p); } static int little2_byteToAscii(const ENCODING *enc, const char *p) { return LITTLE2_BYTE_TO_ASCII(enc, p); } static int little2_charMatches(const ENCODING *enc, const char *p, int c) { return LITTLE2_CHAR_MATCHES(enc, p, c); } static int little2_isNameMin(const ENCODING *enc, const char *p) { return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p); } static int little2_isNmstrtMin(const ENCODING *enc, const char *p) { return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p); } #undef VTABLE #define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 #else /* not XML_MIN_SIZE */ #undef PREFIX #define PREFIX(ident) little2_ ## ident #define MINBPC(enc) 2 /* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ #define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) #define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p) #define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c) #define IS_NAME_CHAR(enc, p, n) 0 #define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) #define IS_NMSTRT_CHAR(enc, p, n) (0) #define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) #include "xmltok_impl.c" #undef MINBPC #undef BYTE_TYPE #undef BYTE_TO_ASCII #undef CHAR_MATCHES #undef IS_NAME_CHAR #undef IS_NAME_CHAR_MINBPC #undef IS_NMSTRT_CHAR #undef IS_NMSTRT_CHAR_MINBPC #undef IS_INVALID_CHAR #endif /* not XML_MIN_SIZE */ static const struct normal_encoding little2_encoding_ns = { { VTABLE, 2, 0, #if XML_BYTE_ORDER == 12 1 #else 0 #endif }, { #include "asciitab.h" #include "latin1tab.h" }, STANDARD_VTABLE(little2_) NULL_NORMAL_VTABLE }; static const struct normal_encoding little2_encoding = { { VTABLE, 2, 0, #if XML_BYTE_ORDER == 12 1 #else 0 #endif }, { #define BT_COLON BT_NMSTRT #include "asciitab.h" #undef BT_COLON #include "latin1tab.h" }, STANDARD_VTABLE(little2_) NULL_NORMAL_VTABLE }; #if XML_BYTE_ORDER != 21 static const struct normal_encoding internal_little2_encoding_ns = { { VTABLE, 2, 0, 1 }, { #include "iasciitab.h" #include "latin1tab.h" }, STANDARD_VTABLE(little2_) NULL_NORMAL_VTABLE }; static const struct normal_encoding internal_little2_encoding = { { VTABLE, 2, 0, 1 }, { #define BT_COLON BT_NMSTRT #include "iasciitab.h" #undef BT_COLON #include "latin1tab.h" }, STANDARD_VTABLE(little2_) NULL_NORMAL_VTABLE }; #endif #define BIG2_BYTE_TYPE(enc, p) \ ((p)[0] == 0 \ ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ : unicode_byte_type((p)[0], (p)[1])) #define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) #define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) #define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \ UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) #define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) #ifdef XML_MIN_SIZE static int big2_byteType(const ENCODING *enc, const char *p) { return BIG2_BYTE_TYPE(enc, p); } static int big2_byteToAscii(const ENCODING *enc, const char *p) { return BIG2_BYTE_TO_ASCII(enc, p); } static int big2_charMatches(const ENCODING *enc, const char *p, int c) { return BIG2_CHAR_MATCHES(enc, p, c); } static int big2_isNameMin(const ENCODING *enc, const char *p) { return BIG2_IS_NAME_CHAR_MINBPC(enc, p); } static int big2_isNmstrtMin(const ENCODING *enc, const char *p) { return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p); } #undef VTABLE #define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 #else /* not XML_MIN_SIZE */ #undef PREFIX #define PREFIX(ident) big2_ ## ident #define MINBPC(enc) 2 /* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ #define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) #define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p) #define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c) #define IS_NAME_CHAR(enc, p, n) 0 #define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p) #define IS_NMSTRT_CHAR(enc, p, n) (0) #define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) #include "xmltok_impl.c" #undef MINBPC #undef BYTE_TYPE #undef BYTE_TO_ASCII #undef CHAR_MATCHES #undef IS_NAME_CHAR #undef IS_NAME_CHAR_MINBPC #undef IS_NMSTRT_CHAR #undef IS_NMSTRT_CHAR_MINBPC #undef IS_INVALID_CHAR #endif /* not XML_MIN_SIZE */ static const struct normal_encoding big2_encoding_ns = { { VTABLE, 2, 0, #if XML_BYTE_ORDER == 21 1 #else 0 #endif }, { #include "asciitab.h" #include "latin1tab.h" }, STANDARD_VTABLE(big2_) NULL_NORMAL_VTABLE }; static const struct normal_encoding big2_encoding = { { VTABLE, 2, 0, #if XML_BYTE_ORDER == 21 1 #else 0 #endif }, { #define BT_COLON BT_NMSTRT #include "asciitab.h" #undef BT_COLON #include "latin1tab.h" }, STANDARD_VTABLE(big2_) NULL_NORMAL_VTABLE }; #if XML_BYTE_ORDER != 12 static const struct normal_encoding internal_big2_encoding_ns = { { VTABLE, 2, 0, 1 }, { #include "iasciitab.h" #include "latin1tab.h" }, STANDARD_VTABLE(big2_) NULL_NORMAL_VTABLE }; static const struct normal_encoding internal_big2_encoding = { { VTABLE, 2, 0, 1 }, { #define BT_COLON BT_NMSTRT #include "iasciitab.h" #undef BT_COLON #include "latin1tab.h" }, STANDARD_VTABLE(big2_) NULL_NORMAL_VTABLE }; #endif #undef PREFIX static int streqci(const char *s1, const char *s2) { for (;;) { char c1 = *s1++; char c2 = *s2++; if (ASCII_a <= c1 && c1 <= ASCII_z) c1 += ASCII_A - ASCII_a; if (ASCII_a <= c2 && c2 <= ASCII_z) c2 += ASCII_A - ASCII_a; if (c1 != c2) return 0; if (!c1) break; } return 1; } static void initUpdatePosition(const ENCODING *enc ATTR_UNUSED, const char *ptr, const char *end, POSITION *pos) { normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); } static int toAscii(const ENCODING *enc, const char *ptr, const char *end) { char buf[1]; char *p = buf; XmlUtf8Convert(enc, &ptr, end, &p, p + 1); if (p == buf) return -1; else return buf[0]; } static int isSpace(int c) { switch (c) { case 0x20: case 0xD: case 0xA: case 0x9: return 1; } return 0; } /* Return 1 if there's just optional white space or there's an S followed by name=val. */ static int parsePseudoAttribute(const ENCODING *enc, const char *ptr, const char *end, const char **namePtr, const char **nameEndPtr, const char **valPtr, const char **nextTokPtr) { int c; char open; if (ptr == end) { *namePtr = 0; return 1; } if (!isSpace(toAscii(enc, ptr, end))) { *nextTokPtr = ptr; return 0; } do { ptr += enc->minBytesPerChar; } while (isSpace(toAscii(enc, ptr, end))); if (ptr == end) { *namePtr = 0; return 1; } *namePtr = ptr; for (;;) { c = toAscii(enc, ptr, end); if (c == -1) { *nextTokPtr = ptr; return 0; } if (c == ASCII_EQUALS) { *nameEndPtr = ptr; break; } if (isSpace(c)) { *nameEndPtr = ptr; do { ptr += enc->minBytesPerChar; } while (isSpace(c = toAscii(enc, ptr, end))); if (c != ASCII_EQUALS) { *nextTokPtr = ptr; return 0; } break; } ptr += enc->minBytesPerChar; } if (ptr == *namePtr) { *nextTokPtr = ptr; return 0; } ptr += enc->minBytesPerChar; c = toAscii(enc, ptr, end); while (isSpace(c)) { ptr += enc->minBytesPerChar; c = toAscii(enc, ptr, end); } if (c != ASCII_QUOT && c != ASCII_APOS) { *nextTokPtr = ptr; return 0; } open = c; ptr += enc->minBytesPerChar; *valPtr = ptr; for (;; ptr += enc->minBytesPerChar) { c = toAscii(enc, ptr, end); if (c == open) break; if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z) && !(ASCII_0 <= c && c <= ASCII_9) && c != ASCII_PERIOD && c != ASCII_MINUS && c != ASCII_UNDERSCORE) { *nextTokPtr = ptr; return 0; } } *nextTokPtr = ptr + enc->minBytesPerChar; return 1; } static const char KW_version[] = { ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0' }; static const char KW_encoding[] = { ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0' }; static const char KW_standalone[] = { ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o, ASCII_n, ASCII_e, '\0' }; static const char KW_yes[] = { ASCII_y, ASCII_e, ASCII_s, '\0' }; static const char KW_no[] = { ASCII_n, ASCII_o, '\0' }; static int doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, const char *, const char *), int isGeneralTextEntity, const ENCODING *enc, const char *ptr, const char *end, const char **badPtr, const char **versionPtr, const char **encodingName, const ENCODING **encoding, int *standalone) { const char *val = 0; const char *name = 0; const char *nameEnd = 0; ptr += 5 * enc->minBytesPerChar; end -= 2 * enc->minBytesPerChar; if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) || !name) { *badPtr = ptr; return 0; } if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) { if (!isGeneralTextEntity) { *badPtr = name; return 0; } } else { if (versionPtr) *versionPtr = val; if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { *badPtr = ptr; return 0; } if (!name) { if (isGeneralTextEntity) { /* a TextDecl must have an EncodingDecl */ *badPtr = ptr; return 0; } return 1; } } if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) { int c = toAscii(enc, val, end); if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) { *badPtr = val; return 0; } if (encodingName) *encodingName = val; if (encoding) *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { *badPtr = ptr; return 0; } if (!name) return 1; } if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) || isGeneralTextEntity) { *badPtr = name; return 0; } if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) { if (standalone) *standalone = 1; } else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) { if (standalone) *standalone = 0; } else { *badPtr = val; return 0; } while (isSpace(toAscii(enc, ptr, end))) ptr += enc->minBytesPerChar; if (ptr != end) { *badPtr = ptr; return 0; } return 1; } static int checkCharRefNumber(int result) { switch (result >> 8) { case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: return -1; case 0: if (latin1_encoding.type[result] == BT_NONXML) return -1; break; case 0xFF: if (result == 0xFFFE || result == 0xFFFF) return -1; break; } return result; } int xmlrpc_XmlUtf8Encode(int const c, char * const buf) { enum { /* minN is minimum legal resulting value for N byte sequence */ min2 = 0x80, min3 = 0x800, min4 = 0x10000 }; if (c < 0) return 0; if (c < min2) { buf[0] = (c | UTF8_cval1); return 1; } if (c < min3) { buf[0] = ((c >> 6) | UTF8_cval2); buf[1] = ((c & 0x3f) | 0x80); return 2; } if (c < min4) { buf[0] = ((c >> 12) | UTF8_cval3); buf[1] = (((c >> 6) & 0x3f) | 0x80); buf[2] = ((c & 0x3f) | 0x80); return 3; } if (c < 0x110000) { buf[0] = ((c >> 18) | UTF8_cval4); buf[1] = (((c >> 12) & 0x3f) | 0x80); buf[2] = (((c >> 6) & 0x3f) | 0x80); buf[3] = ((c & 0x3f) | 0x80); return 4; } return 0; } int xmlrpc_XmlUtf16Encode(int const charNumArg, unsigned short * const buf) { int charNum; charNum = charNumArg; /* initial value */ if (charNum < 0) return 0; if (charNum < 0x10000) { buf[0] = charNum; return 1; } if (charNum < 0x110000) { charNum -= 0x10000; buf[0] = (charNum >> 10) + 0xD800; buf[1] = (charNum & 0x3FF) + 0xDC00; return 2; } return 0; } struct unknown_encoding { struct normal_encoding normal; int (*convert)(void *userData, const char *p); void *userData; unsigned short utf16[256]; char utf8[256][4]; }; int xmlrpc_XmlSizeOfUnknownEncoding(void) { return sizeof(struct unknown_encoding); } static int unknown_isName(const ENCODING *enc, const char *p) { int c = ((const struct unknown_encoding *)enc) ->convert(((const struct unknown_encoding *)enc)->userData, p); if (c & ~0xFFFF) return 0; return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); } static int unknown_isNmstrt(const ENCODING *enc, const char *p) { int c = ((const struct unknown_encoding *)enc) ->convert(((const struct unknown_encoding *)enc)->userData, p); if (c & ~0xFFFF) return 0; return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); } static int unknown_isInvalid(const ENCODING *enc, const char *p) { int c = ((const struct unknown_encoding *)enc) ->convert(((const struct unknown_encoding *)enc)->userData, p); return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; } static void unknown_toUtf8(const ENCODING *enc, const char **fromP, const char *fromLim, char **toP, const char *toLim) { char buf[XML_UTF8_ENCODE_MAX]; for (;;) { const char *utf8; int n; if (*fromP == fromLim) break; utf8 = ((const struct unknown_encoding *)enc)->utf8[(unsigned char)**fromP]; n = *utf8++; if (n == 0) { int c = ((const struct unknown_encoding *)enc) ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); n = xmlrpc_XmlUtf8Encode(c, buf); if (n > toLim - *toP) break; utf8 = buf; *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] - (BT_LEAD2 - 2); } else { if (n > toLim - *toP) break; (*fromP)++; } do { *(*toP)++ = *utf8++; } while (--n != 0); } } static void unknown_toUtf16(const ENCODING *enc, const char **fromP, const char *fromLim, unsigned short **toP, const unsigned short *toLim) { while (*fromP != fromLim && *toP != toLim) { unsigned short c = ((const struct unknown_encoding *)enc)->utf16[(unsigned char)**fromP]; if (c == 0) { c = (unsigned short)((const struct unknown_encoding *)enc) ->convert(((const struct unknown_encoding *)enc)->userData, *fromP); *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP] - (BT_LEAD2 - 2); } else (*fromP)++; *(*toP)++ = c; } } ENCODING * xmlrpc_XmlInitUnknownEncoding(void * const mem, int * const table, int (*convert)(void *userData, const char *p), void * const userData) { int i; struct unknown_encoding *e = mem; for (i = 0; i < (int)sizeof(struct normal_encoding); i++) ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; for (i = 0; i < 128; i++) if (latin1_encoding.type[i] != BT_OTHER && latin1_encoding.type[i] != BT_NONXML && table[i] != i) return 0; for (i = 0; i < 256; i++) { int c = table[i]; if (c == -1) { e->normal.type[i] = BT_MALFORM; /* This shouldn't really get used. */ e->utf16[i] = 0xFFFF; e->utf8[i][0] = 1; e->utf8[i][1] = 0; } else if (c < 0) { if (c < -4) return 0; e->normal.type[i] = BT_LEAD2 - (c + 2); e->utf8[i][0] = 0; e->utf16[i] = 0; } else if (c < 0x80) { if (latin1_encoding.type[c] != BT_OTHER && latin1_encoding.type[c] != BT_NONXML && c != i) return 0; e->normal.type[i] = latin1_encoding.type[c]; e->utf8[i][0] = 1; e->utf8[i][1] = (char)c; e->utf16[i] = c == 0 ? 0xFFFF : c; } else if (checkCharRefNumber(c) < 0) { e->normal.type[i] = BT_NONXML; /* This shouldn't really get used. */ e->utf16[i] = 0xFFFF; e->utf8[i][0] = 1; e->utf8[i][1] = 0; } else { if (c > 0xFFFF) return 0; if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) e->normal.type[i] = BT_NMSTRT; else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) e->normal.type[i] = BT_NAME; else e->normal.type[i] = BT_OTHER; e->utf8[i][0] = (char)xmlrpc_XmlUtf8Encode(c, e->utf8[i] + 1); e->utf16[i] = c; } } e->userData = userData; e->convert = convert; if (convert) { e->normal.isName2 = unknown_isName; e->normal.isName3 = unknown_isName; e->normal.isName4 = unknown_isName; e->normal.isNmstrt2 = unknown_isNmstrt; e->normal.isNmstrt3 = unknown_isNmstrt; e->normal.isNmstrt4 = unknown_isNmstrt; e->normal.isInvalid2 = unknown_isInvalid; e->normal.isInvalid3 = unknown_isInvalid; e->normal.isInvalid4 = unknown_isInvalid; } e->normal.enc.utf8Convert = unknown_toUtf8; e->normal.enc.utf16Convert = unknown_toUtf16; return &(e->normal.enc); } /* If this enumeration is changed, getEncodingIndex and encodings must also be changed. */ enum { UNKNOWN_ENC = -1, ISO_8859_1_ENC = 0, US_ASCII_ENC, UTF_8_ENC, UTF_16_ENC, UTF_16BE_ENC, UTF_16LE_ENC, /* must match encodingNames up to here */ NO_ENC }; static const char KW_ISO_8859_1[] = { ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9, ASCII_MINUS, ASCII_1, '\0' }; static const char KW_US_ASCII[] = { ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I, '\0' }; static const char KW_UTF_8[] = { ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0' }; static const char KW_UTF_16[] = { ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0' }; static const char KW_UTF_16BE[] = { ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E, '\0' }; static const char KW_UTF_16LE[] = { ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, '\0' }; static int getEncodingIndex(const char * const name) { /*---------------------------------------------------------------------------- Return the index into the encodings[] table of the encoding named 'name'. If 'name' is NULL, return NO_ENC. If the name is non-NULL, but not one we recognize, return UNKNOWN_ENC. Note that UNKNOWN_ENC is not actually an index (but NO_ENC is). -----------------------------------------------------------------------------*/ if (name == NULL) return NO_ENC; else { static const char * const encodingNames[] = { KW_ISO_8859_1, KW_US_ASCII, KW_UTF_8, KW_UTF_16, KW_UTF_16BE, KW_UTF_16LE, }; unsigned int i; for (i = 0; i < (unsigned int)(ARRAY_SIZE(encodingNames)); i++) { if (streqci(name, encodingNames[i])) return i; } return UNKNOWN_ENC; } } /* For binary compatibility, we store the index of the encoding specified at initialization in the isUtf16 member. */ #define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16) #define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i) /* This is what detects the encoding. encodingTable maps from encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of the external (protocol) specified encoding; state is XML_CONTENT_STATE if we're parsing an external text entity, and XML_PROLOG_STATE otherwise. */ static int initScan(const ENCODING **encodingTable, const INIT_ENCODING *enc, int state, const char *ptr, const char *end, const char **nextTokPtr) { const ENCODING **encPtr; if (ptr == end) return XML_TOK_NONE; encPtr = enc->encPtr; if (ptr + 1 == end) { /* only a single byte available for auto-detection */ /* so we're parsing an external text entity... */ /* if UTF-16 was externally specified, then we need at least 2 bytes */ switch (INIT_ENC_INDEX(enc)) { case UTF_16_ENC: case UTF_16LE_ENC: case UTF_16BE_ENC: return XML_TOK_PARTIAL; } switch ((unsigned char)*ptr) { case 0xFE: case 0xFF: case 0xEF: /* possibly first byte of UTF-8 BOM */ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE) break; /* fall through */ case 0x00: case 0x3C: return XML_TOK_PARTIAL; } } else { switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { case 0xFEFF: if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE) break; *nextTokPtr = ptr + 2; *encPtr = encodingTable[UTF_16BE_ENC]; return XML_TOK_BOM; /* 00 3C is handled in the default case */ case 0x3C00: if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC || INIT_ENC_INDEX(enc) == UTF_16_ENC) && state == XML_CONTENT_STATE) break; *encPtr = encodingTable[UTF_16LE_ENC]; return XmlTok(*encPtr, state, ptr, end, nextTokPtr); case 0xFFFE: if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE) break; *nextTokPtr = ptr + 2; *encPtr = encodingTable[UTF_16LE_ENC]; return XML_TOK_BOM; case 0xEFBB: /* Maybe a UTF-8 BOM (EF BB BF) */ /* If there's an explicitly specified (external) encoding of ISO-8859-1 or some flavour of UTF-16 and this is an external text entity, don't look for the BOM, because it might be a legal data. */ if (state == XML_CONTENT_STATE) { int e = INIT_ENC_INDEX(enc); if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC || e == UTF_16LE_ENC || e == UTF_16_ENC) break; } if (ptr + 2 == end) return XML_TOK_PARTIAL; if ((unsigned char)ptr[2] == 0xBF) { *encPtr = encodingTable[UTF_8_ENC]; return XML_TOK_BOM; } break; default: if (ptr[0] == '\0') { /* 0 isn't a legal data character. Furthermore a document entity can only start with ASCII characters. So the only way this can fail to be big-endian UTF-16 if it it's an external parsed general entity that's labelled as UTF-16LE. */ if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) break; *encPtr = encodingTable[UTF_16BE_ENC]; return XmlTok(*encPtr, state, ptr, end, nextTokPtr); } else if (ptr[1] == '\0') { /* We could recover here in the case: - parsing an external entity - second byte is 0 - no externally specified encoding - no encoding declaration by assuming UTF-16LE. But we don't, because this would mean when presented just with a single byte, we couldn't reliably determine whether we needed further bytes. */ if (state == XML_CONTENT_STATE) break; *encPtr = encodingTable[UTF_16LE_ENC]; return XmlTok(*encPtr, state, ptr, end, nextTokPtr); } break; } } *encPtr = encodingTable[INIT_ENC_INDEX(enc)]; return XmlTok(*encPtr, state, ptr, end, nextTokPtr); } #define NS(x) x #define ns(x) x #include "xmltok_ns.c" #undef NS #undef ns #define NS(x) x ## NS #define ns(x) x ## _ns #include "xmltok_ns.c" #undef NS #undef ns ENCODING * xmlrpc_XmlInitUnknownEncodingNS(void * const mem, int * const table, int (*convert)(void *userData, const char *p), void * const userData) { ENCODING * const enc = xmlrpc_XmlInitUnknownEncoding(mem, table, convert, userData); if (enc) ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON; return enc; } xmlrpc-c-1.33.14/lib/expat/xmltok/xmltok.h000066400000000000000000000276471236133176700203350ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #ifndef XMLTOK_H_INCLUDED #define XMLTOK_H_INCLUDED #include "xmlrpc-c/c_util.h" #ifdef __cplusplus extern "C" { #endif /* The following token may be returned by XmlContentTok */ #define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be start of illegal ]]> sequence */ /* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ #define XML_TOK_NONE -4 /* The string to be scanned is empty */ #define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; might be part of CRLF sequence */ #define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ #define XML_TOK_PARTIAL -1 /* only part of a token */ #define XML_TOK_INVALID 0 /* The following tokens are returned by XmlContentTok; some are also returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok */ #define XML_TOK_START_TAG_WITH_ATTS 1 #define XML_TOK_START_TAG_NO_ATTS 2 #define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag */ #define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 #define XML_TOK_END_TAG 5 #define XML_TOK_DATA_CHARS 6 #define XML_TOK_DATA_NEWLINE 7 #define XML_TOK_CDATA_SECT_OPEN 8 #define XML_TOK_ENTITY_REF 9 #define XML_TOK_CHAR_REF 10 /* numeric character reference */ /* The following tokens may be returned by both XmlPrologTok and XmlContentTok */ #define XML_TOK_PI 11 /* processing instruction */ #define XML_TOK_XML_DECL 12 /* XML decl or text decl */ #define XML_TOK_COMMENT 13 #define XML_TOK_BOM 14 /* Byte order mark */ /* The following tokens are returned only by XmlPrologTok */ #define XML_TOK_PROLOG_S 15 #define XML_TOK_DECL_OPEN 16 /* */ #define XML_TOK_NAME 18 #define XML_TOK_NMTOKEN 19 #define XML_TOK_POUND_NAME 20 /* #name */ #define XML_TOK_OR 21 /* | */ #define XML_TOK_PERCENT 22 #define XML_TOK_OPEN_PAREN 23 #define XML_TOK_CLOSE_PAREN 24 #define XML_TOK_OPEN_BRACKET 25 #define XML_TOK_CLOSE_BRACKET 26 #define XML_TOK_LITERAL 27 #define XML_TOK_PARAM_ENTITY_REF 28 #define XML_TOK_INSTANCE_START 29 /* The following occur only in element type declarations */ #define XML_TOK_NAME_QUESTION 30 /* name? */ #define XML_TOK_NAME_ASTERISK 31 /* name* */ #define XML_TOK_NAME_PLUS 32 /* name+ */ #define XML_TOK_COND_SECT_OPEN 33 /* */ #define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ #define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ #define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ #define XML_TOK_COMMA 38 /* The following token is returned only by XmlAttributeValueTok */ #define XML_TOK_ATTRIBUTE_VALUE_S 39 /* The following token is returned only by XmlCdataSectionTok */ #define XML_TOK_CDATA_SECT_CLOSE 40 /* With namespace processing this is returned by XmlPrologTok for a name with a colon. */ #define XML_TOK_PREFIXED_NAME 41 #define XML_TOK_IGNORE_SECT 42 #define XML_N_STATES 4 #define XML_PROLOG_STATE 0 #define XML_CONTENT_STATE 1 #define XML_CDATA_SECTION_STATE 2 #define XML_IGNORE_SECTION_STATE 3 #define XML_N_LITERAL_TYPES 2 #define XML_ATTRIBUTE_VALUE_LITERAL 0 #define XML_ENTITY_VALUE_LITERAL 1 /* The size of the buffer passed to XmlUtf8Encode must be at least this. */ #define XML_UTF8_ENCODE_MAX 4 /* The size of the buffer passed to XmlUtf16Encode must be at least this. */ #define XML_UTF16_ENCODE_MAX 2 typedef struct position { /* first line and first column are 0 not 1 */ unsigned long lineNumber; unsigned long columnNumber; } POSITION; typedef struct { const char *name; const char *valuePtr; const char *valueEnd; char normalized; } ATTRIBUTE; struct encoding; typedef struct encoding ENCODING; /* It's pretty silly to have the 'const' on the argument names below, but MSVC thinks the definitions of Utf8Converter functions that do have that qualifier on the argument variables don't match this declaration if we don't. */ typedef void Utf8Converter(const ENCODING * const encP, const char ** const fromP, const char * const fromLim, char ** const toP, const char * const toLim); /*---------------------------------------------------------------------------- A Utf8Converter is an encoder method that converts from the encoder's code to UTF-8: Convert the string that starts at *fromP and ends at 'fromLim' to UTF8 in the buffer that starts at *toP and ends at 'toLim'. Go from left to right and stop when the output buffer is full. Note that the buffer can be full while still having a few bytes left in it because an input character may require multiple bytes of the output buffer. The encoding may require up to 4 UTF-8 bytes for a single input character. Leave *fromP and *toP pointing after the last character converted. The output buffer must be at least 4 bytes. Results are undefined if not. We necessarily advance *fromP at least one character if 'fromLim' allows. -----------------------------------------------------------------------------*/ struct encoding { int (*scanners[XML_N_STATES])(const ENCODING *, const char *, const char *, const char **); int (*literalScanners[XML_N_LITERAL_TYPES])(const ENCODING *, const char *, const char *, const char **); int (*sameName)(const ENCODING *, const char *, const char *); int (*nameMatchesAscii)(const ENCODING *, const char *, const char *, const char *); size_t (*nameLength)(const ENCODING *, const char *); const char *(*skipS)(const ENCODING *, const char *); int (*getAtts)(const ENCODING *enc, const char *ptr, int attsMax, ATTRIBUTE *atts); int (*charRefNumber)(const ENCODING *enc, const char *ptr); int (*predefinedEntityName)(const ENCODING *, const char *, const char *); void (*updatePosition)(const ENCODING *, const char *ptr, const char *end, POSITION *); int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end, const char **badPtr); Utf8Converter * utf8Convert; void (*utf16Convert)(const ENCODING *enc, const char **fromP, const char *fromLim, unsigned short **toP, const unsigned short *toLim); int minBytesPerChar; char isUtf8; char isUtf16; }; /* Scan the string starting at ptr until the end of the next complete token, but do not scan past eptr. Return an integer giving the type of token. Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. Return XML_TOK_PARTIAL when the string does not contain a complete token; nextTokPtr will not be set. Return XML_TOK_INVALID when the string does not start a valid token; nextTokPtr will be set to point to the character which made the token invalid. Otherwise the string starts with a valid token; nextTokPtr will be set to point to the character following the end of that token. Each data character counts as a single token, but adjacent data characters may be returned together. Similarly for characters in the prolog outside literals, comments and processing instructions. */ #define XmlTok(enc, state, ptr, end, nextTokPtr) \ (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) #define XmlPrologTok(enc, ptr, end, nextTokPtr) \ XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) #define XmlContentTok(enc, ptr, end, nextTokPtr) \ XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) #define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) #define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) /* This is used for performing a 2nd-level tokenization on the content of a literal that has already been returned by XmlTok. */ #define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) #define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) #define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) #define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) #define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) #define XmlNameLength(enc, ptr) \ (((enc)->nameLength)(enc, ptr)) #define XmlSkipS(enc, ptr) \ (((enc)->skipS)(enc, ptr)) #define XmlGetAttributes(enc, ptr, attsMax, atts) \ (((enc)->getAtts)(enc, ptr, attsMax, atts)) #define XmlCharRefNumber(enc, ptr) \ (((enc)->charRefNumber)(enc, ptr)) #define XmlPredefinedEntityName(enc, ptr, end) \ (((enc)->predefinedEntityName)(enc, ptr, end)) #define XmlUpdatePosition(enc, ptr, end, pos) \ (((enc)->updatePosition)(enc, ptr, end, pos)) #define XmlIsPublicId(enc, ptr, end, badPtr) \ (((enc)->isPublicId)(enc, ptr, end, badPtr)) #define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) #define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) typedef struct { ENCODING initEnc; const ENCODING **encPtr; } INIT_ENCODING; XMLRPC_DLLEXPORT int xmlrpc_XmlParseXmlDecl(int const isGeneralTextEntity, const ENCODING * const enc, const char * const ptr, const char * const end, const char ** const badPtr, const char ** const versionPtr, const char ** const encodingNamePtr, const ENCODING ** const namedEncodingPtr, int * const standalonePtr); XMLRPC_DLLEXPORT const ENCODING * xmlrpc_XmlGetUtf8InternalEncoding(void); XMLRPC_DLLEXPORT const ENCODING * xmlrpc_XmlGetUtf16InternalEncoding(void); XMLRPC_DLLEXPORT int xmlrpc_XmlInitEncoding(INIT_ENCODING * const p, const ENCODING ** const encPtr, const char * const name); XMLRPC_DLLEXPORT int xmlrpc_XmlUtf8Encode(int const c, char * const buf); XMLRPC_DLLEXPORT int xmlrpc_XmlUtf16Encode(int const charNum, unsigned short * const buf); XMLRPC_DLLEXPORT int xmlrpc_XmlSizeOfUnknownEncoding(void); XMLRPC_DLLEXPORT ENCODING * xmlrpc_XmlInitUnknownEncoding(void * const mem, int * const table, int (*convert)(void *userData, const char *p), void * const userData); XMLRPC_DLLEXPORT int xmlrpc_XmlParseXmlDeclNS(int const isGeneralTextEntity, const ENCODING * const enc, const char * const ptr, const char * const end, const char ** const badPtr, const char ** const versionPtr, const char ** const encodingNamePtr, const ENCODING ** const namedEncodingPtr, int * const standalonePtr); XMLRPC_DLLEXPORT int xmlrpc_XmlInitEncodingNS(INIT_ENCODING * const p, const ENCODING ** const encPtr, const char * const name); XMLRPC_DLLEXPORT const ENCODING * xmlrpc_XmlGetUtf8InternalEncodingNS(void); XMLRPC_DLLEXPORT const ENCODING * xmlrpc_XmlGetUtf16InternalEncodingNS(void); XMLRPC_DLLEXPORT ENCODING * xmlrpc_XmlInitUnknownEncodingNS(void * const mem, int * const table, int (*convert)(void *userData, const char *p), void * const userData); #ifdef __cplusplus } #endif #endif /* not XmlTok_INCLUDED */ xmlrpc-c-1.33.14/lib/expat/xmltok/xmltok_impl.c000066400000000000000000001301201236133176700213260ustar00rootroot00000000000000/*============================================================================= xmltok_impl.c =============================================================================== This is an inclusion for xmltok.c. You define various macros to control what code this file generates. xmltok.c includes it multiple times with different macro definitions to get different code. For example, the PREFIX macro becomes part of the symbol names we define, and can be "normal_", "little2_", or "big2_". =============================================================================*/ /* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #ifndef IS_INVALID_CHAR #define IS_INVALID_CHAR(enc, ptr, n) (0) #endif #define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ case BT_LEAD ## n: \ if (end - ptr < n) \ return XML_TOK_PARTIAL_CHAR; \ if (IS_INVALID_CHAR(enc, ptr, n)) { \ *(nextTokPtr) = (ptr); \ return XML_TOK_INVALID; \ } \ ptr += n; \ break; #define INVALID_CASES(ptr, nextTokPtr) \ INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ case BT_NONXML: \ case BT_MALFORM: \ case BT_TRAIL: \ *(nextTokPtr) = (ptr); \ return XML_TOK_INVALID #define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ case BT_LEAD ## n: \ if (end - ptr < n) \ return XML_TOK_PARTIAL_CHAR; \ if (!IS_NAME_CHAR(enc, ptr, n)) { \ *nextTokPtr = ptr; \ return XML_TOK_INVALID; \ } \ ptr += n; \ break; #define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ case BT_NONASCII: \ if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ *nextTokPtr = ptr; \ return XML_TOK_INVALID; \ } \ case BT_NMSTRT: \ case BT_HEX: \ case BT_DIGIT: \ case BT_NAME: \ case BT_MINUS: \ ptr += MINBPC(enc); \ break; \ CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) #define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ case BT_LEAD ## n: \ if (end - ptr < n) \ return XML_TOK_PARTIAL_CHAR; \ if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ *nextTokPtr = ptr; \ return XML_TOK_INVALID; \ } \ ptr += n; \ break; #define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ case BT_NONASCII: \ if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ *nextTokPtr = ptr; \ return XML_TOK_INVALID; \ } \ case BT_NMSTRT: \ case BT_HEX: \ ptr += MINBPC(enc); \ break; \ CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) #ifndef PREFIX #define PREFIX(ident) ident #endif /* ptr points to character following " */ switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: *nextTokPtr = ptr; return XML_TOK_INVALID; } /* fall through */ case BT_S: case BT_CR: case BT_LF: *nextTokPtr = ptr; return XML_TOK_DECL_OPEN; case BT_NMSTRT: case BT_HEX: ptr += MINBPC(enc); break; default: *nextTokPtr = ptr; return XML_TOK_INVALID; } } return XML_TOK_PARTIAL; } static int PREFIX(checkPiTarget)(const ENCODING * enc ATTR_UNUSED, const char * ptr, const char * end, int * tokPtr) { int upper = 0; *tokPtr = XML_TOK_PI; if (end - ptr != MINBPC(enc)*3) return 1; switch (BYTE_TO_ASCII(enc, ptr)) { case ASCII_x: break; case ASCII_X: upper = 1; break; default: return 1; } ptr += MINBPC(enc); switch (BYTE_TO_ASCII(enc, ptr)) { case ASCII_m: break; case ASCII_M: upper = 1; break; default: return 1; } ptr += MINBPC(enc); switch (BYTE_TO_ASCII(enc, ptr)) { case ASCII_l: break; case ASCII_L: upper = 1; break; default: return 1; } if (upper) return 0; *tokPtr = XML_TOK_XML_DECL; return 1; } /* ptr points to character following " 1) { size_t n = end - ptr; if (n & (MINBPC(enc) - 1)) { n &= ~(MINBPC(enc) - 1); if (n == 0) return XML_TOK_PARTIAL; end = ptr + n; } } switch (BYTE_TYPE(enc, ptr)) { case BT_RSQB: ptr += MINBPC(enc); if (ptr == end) return XML_TOK_PARTIAL; if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) break; ptr += MINBPC(enc); if (ptr == end) return XML_TOK_PARTIAL; if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { ptr -= MINBPC(enc); break; } *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_CDATA_SECT_CLOSE; case BT_CR: ptr += MINBPC(enc); if (ptr == end) return XML_TOK_PARTIAL; if (BYTE_TYPE(enc, ptr) == BT_LF) ptr += MINBPC(enc); *nextTokPtr = ptr; return XML_TOK_DATA_NEWLINE; case BT_LF: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_DATA_NEWLINE; INVALID_CASES(ptr, nextTokPtr); default: ptr += MINBPC(enc); break; } while (ptr != end) { switch (BYTE_TYPE(enc, ptr)) { #define LEAD_CASE(n) \ case BT_LEAD ## n: \ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ *nextTokPtr = ptr; \ return XML_TOK_DATA_CHARS; \ } \ ptr += n; \ break; LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) #undef LEAD_CASE case BT_NONXML: case BT_MALFORM: case BT_TRAIL: case BT_CR: case BT_LF: case BT_RSQB: *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; default: ptr += MINBPC(enc); break; } } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; } /* ptr points to character following " 1) { size_t const length = inputEnd - inputStart; if (length & (MINBPC(enc) - 1)) { size_t const roundedLen = length & ~(MINBPC(enc) - 1); *choppedEndP = inputStart + roundedLen; } else *choppedEndP = inputEnd; } else *choppedEndP = inputEnd; } static void PREFIX(processBtRsqb)(const ENCODING * const enc ATTR_UNUSED, const char * const start, const char * const end, unsigned int * const countP, bool * const invalidP) { if (start + MINBPC(enc) < end) { if (!CHAR_MATCHES(enc, start + MINBPC(enc), ASCII_RSQB)) { *countP = MINBPC(enc); *invalidP = false; } else { if (start + 2*MINBPC(enc) < end) { if (!CHAR_MATCHES(enc, start + 2*MINBPC(enc), ASCII_GT)) { *countP = MINBPC(enc); *invalidP = false; } else { *countP = 2 * MINBPC(enc); *invalidP = true; } } else { *countP = 0; *invalidP = false; } } } else { *countP = 0; *invalidP = false; } } static int PREFIX(contentTok)(const ENCODING * const enc, const char * const inputStart, const char * const inputEnd, const char ** const nextTokPtr) { /*---------------------------------------------------------------------------- Parse off a token from the string that starts at 'inputStart' and ends at 'inputEnd'. Return the class of that token. Return *nextTokPtr pointing just after the parsed-off token in the string. Sometimes, there is no token we can parse, so our return value is a disposition code indicating that situation and *nextTokPtr points to the beginning of the string. -----------------------------------------------------------------------------*/ if (inputEnd == inputStart) { *nextTokPtr = inputStart; return XML_TOK_NONE; } else { const char * ptr; const char * end; /* The virtual end of the string; we look at only whole characters; e.g. if there are 2 bytes per character and the buffer is 9 bytes, we look at only the first 8 and 'end' points after the 8th byte. */ PREFIX(chopToWholeCharacters)(inputStart, inputEnd, &end); if (end == inputStart) { *nextTokPtr = inputStart; return XML_TOK_PARTIAL; } ptr = inputStart; /* Start at the beginning */ switch (BYTE_TYPE(enc, ptr)) { case BT_LT: return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); case BT_AMP: return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); case BT_CR: ptr += MINBPC(enc); if (ptr == end) return XML_TOK_TRAILING_CR; if (BYTE_TYPE(enc, ptr) == BT_LF) ptr += MINBPC(enc); *nextTokPtr = ptr; return XML_TOK_DATA_NEWLINE; case BT_LF: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_DATA_NEWLINE; case BT_RSQB: ptr += MINBPC(enc); if (ptr == end) return XML_TOK_TRAILING_RSQB; if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) break; ptr += MINBPC(enc); if (ptr == end) return XML_TOK_TRAILING_RSQB; if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { ptr -= MINBPC(enc); break; } *nextTokPtr = ptr; return XML_TOK_INVALID; INVALID_CASES(ptr, nextTokPtr); default: ptr += MINBPC(enc); break; } while (ptr < end) { switch (BYTE_TYPE(enc, ptr)) { LEAD_CASE(2); LEAD_CASE(3); LEAD_CASE(4); case BT_RSQB: { bool invalid; unsigned int count; PREFIX(processBtRsqb)(enc, ptr, end, &count, &invalid); ptr += count; if (invalid) { *nextTokPtr = ptr; return XML_TOK_INVALID; } } /* fall through */ case BT_AMP: case BT_LT: case BT_NONXML: case BT_MALFORM: case BT_TRAIL: case BT_CR: case BT_LF: *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; default: ptr += MINBPC(enc); break; } } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; } } #undef LEAD_CASE /* ptr points to character following "%" */ static int PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { if (ptr == end) return XML_TOK_PARTIAL; switch (BYTE_TYPE(enc, ptr)) { CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: *nextTokPtr = ptr; return XML_TOK_PERCENT; default: *nextTokPtr = ptr; return XML_TOK_INVALID; } while (ptr != end) { switch (BYTE_TYPE(enc, ptr)) { CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) case BT_SEMI: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_PARAM_ENTITY_REF; default: *nextTokPtr = ptr; return XML_TOK_INVALID; } } return XML_TOK_PARTIAL; } static int PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { if (ptr == end) return XML_TOK_PARTIAL; switch (BYTE_TYPE(enc, ptr)) { CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) default: *nextTokPtr = ptr; return XML_TOK_INVALID; } while (ptr != end) { switch (BYTE_TYPE(enc, ptr)) { CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) case BT_CR: case BT_LF: case BT_S: case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: *nextTokPtr = ptr; return XML_TOK_POUND_NAME; default: *nextTokPtr = ptr; return XML_TOK_INVALID; } } return -XML_TOK_POUND_NAME; } static int PREFIX(scanLit)(int open, const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { while (ptr != end) { int t = BYTE_TYPE(enc, ptr); switch (t) { INVALID_CASES(ptr, nextTokPtr); case BT_QUOT: case BT_APOS: ptr += MINBPC(enc); if (t != open) break; if (ptr == end) return -XML_TOK_LITERAL; *nextTokPtr = ptr; switch (BYTE_TYPE(enc, ptr)) { case BT_S: case BT_CR: case BT_LF: case BT_GT: case BT_PERCNT: case BT_LSQB: return XML_TOK_LITERAL; default: return XML_TOK_INVALID; } default: ptr += MINBPC(enc); break; } } return XML_TOK_PARTIAL; } static int PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { int tok; if (ptr == end) return XML_TOK_NONE; if (MINBPC(enc) > 1) { size_t n = end - ptr; if (n & (MINBPC(enc) - 1)) { n &= ~(MINBPC(enc) - 1); if (n == 0) return XML_TOK_PARTIAL; end = ptr + n; } } switch (BYTE_TYPE(enc, ptr)) { case BT_QUOT: return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); case BT_APOS: return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); case BT_LT: { ptr += MINBPC(enc); if (ptr == end) return XML_TOK_PARTIAL; switch (BYTE_TYPE(enc, ptr)) { case BT_EXCL: return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); case BT_QUEST: return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); case BT_NMSTRT: case BT_HEX: case BT_NONASCII: case BT_LEAD2: case BT_LEAD3: case BT_LEAD4: *nextTokPtr = ptr - MINBPC(enc); return XML_TOK_INSTANCE_START; } *nextTokPtr = ptr; return XML_TOK_INVALID; } case BT_CR: if (ptr + MINBPC(enc) == end) return -XML_TOK_PROLOG_S; /* fall through */ case BT_S: case BT_LF: for (;;) { ptr += MINBPC(enc); if (ptr == end) break; switch (BYTE_TYPE(enc, ptr)) { case BT_S: case BT_LF: break; case BT_CR: /* don't split CR/LF pair */ if (ptr + MINBPC(enc) != end) break; /* fall through */ default: *nextTokPtr = ptr; return XML_TOK_PROLOG_S; } } *nextTokPtr = ptr; return XML_TOK_PROLOG_S; case BT_PERCNT: return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); case BT_COMMA: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_COMMA; case BT_LSQB: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_OPEN_BRACKET; case BT_RSQB: ptr += MINBPC(enc); if (ptr == end) return -XML_TOK_CLOSE_BRACKET; if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { if (ptr + MINBPC(enc) == end) return XML_TOK_PARTIAL; if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) { *nextTokPtr = ptr + 2*MINBPC(enc); return XML_TOK_COND_SECT_CLOSE; } } *nextTokPtr = ptr; return XML_TOK_CLOSE_BRACKET; case BT_LPAR: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_OPEN_PAREN; case BT_RPAR: ptr += MINBPC(enc); if (ptr == end) return -XML_TOK_CLOSE_PAREN; switch (BYTE_TYPE(enc, ptr)) { case BT_AST: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_CLOSE_PAREN_ASTERISK; case BT_QUEST: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_CLOSE_PAREN_QUESTION; case BT_PLUS: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_CLOSE_PAREN_PLUS; case BT_CR: case BT_LF: case BT_S: case BT_GT: case BT_COMMA: case BT_VERBAR: case BT_RPAR: *nextTokPtr = ptr; return XML_TOK_CLOSE_PAREN; } *nextTokPtr = ptr; return XML_TOK_INVALID; case BT_VERBAR: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_OR; case BT_GT: *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_DECL_CLOSE; case BT_NUM: return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); #define LEAD_CASE(n) \ case BT_LEAD ## n: \ if (end - ptr < n) \ return XML_TOK_PARTIAL_CHAR; \ if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ ptr += n; \ tok = XML_TOK_NAME; \ break; \ } \ if (IS_NAME_CHAR(enc, ptr, n)) { \ ptr += n; \ tok = XML_TOK_NMTOKEN; \ break; \ } \ *nextTokPtr = ptr; \ return XML_TOK_INVALID; LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) #undef LEAD_CASE case BT_NMSTRT: case BT_HEX: tok = XML_TOK_NAME; ptr += MINBPC(enc); break; case BT_DIGIT: case BT_NAME: case BT_MINUS: case BT_COLON: tok = XML_TOK_NMTOKEN; ptr += MINBPC(enc); break; case BT_NONASCII: if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { ptr += MINBPC(enc); tok = XML_TOK_NAME; break; } if (IS_NAME_CHAR_MINBPC(enc, ptr)) { ptr += MINBPC(enc); tok = XML_TOK_NMTOKEN; break; } /* fall through */ default: *nextTokPtr = ptr; return XML_TOK_INVALID; } while (ptr != end) { switch (BYTE_TYPE(enc, ptr)) { CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) case BT_GT: case BT_RPAR: case BT_COMMA: case BT_VERBAR: case BT_LSQB: case BT_PERCNT: case BT_S: case BT_CR: case BT_LF: *nextTokPtr = ptr; return tok; case BT_COLON: ptr += MINBPC(enc); switch (tok) { case XML_TOK_NAME: if (ptr == end) return XML_TOK_PARTIAL; tok = XML_TOK_PREFIXED_NAME; switch (BYTE_TYPE(enc, ptr)) { CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) default: tok = XML_TOK_NMTOKEN; break; } break; case XML_TOK_PREFIXED_NAME: tok = XML_TOK_NMTOKEN; break; } break; case BT_PLUS: if (tok == XML_TOK_NMTOKEN) { *nextTokPtr = ptr; return XML_TOK_INVALID; } *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_NAME_PLUS; case BT_AST: if (tok == XML_TOK_NMTOKEN) { *nextTokPtr = ptr; return XML_TOK_INVALID; } *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_NAME_ASTERISK; case BT_QUEST: if (tok == XML_TOK_NMTOKEN) { *nextTokPtr = ptr; return XML_TOK_INVALID; } *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_NAME_QUESTION; default: *nextTokPtr = ptr; return XML_TOK_INVALID; } } return -tok; } static int PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { const char *start; if (ptr == end) return XML_TOK_NONE; start = ptr; while (ptr != end) { switch (BYTE_TYPE(enc, ptr)) { #define LEAD_CASE(n) \ case BT_LEAD ## n: ptr += n; break; LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) #undef LEAD_CASE case BT_AMP: if (ptr == start) return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; case BT_LT: /* this is for inside entity references */ *nextTokPtr = ptr; return XML_TOK_INVALID; case BT_LF: if (ptr == start) { *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_DATA_NEWLINE; } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; case BT_CR: if (ptr == start) { ptr += MINBPC(enc); if (ptr == end) return XML_TOK_TRAILING_CR; if (BYTE_TYPE(enc, ptr) == BT_LF) ptr += MINBPC(enc); *nextTokPtr = ptr; return XML_TOK_DATA_NEWLINE; } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; case BT_S: if (ptr == start) { *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_ATTRIBUTE_VALUE_S; } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; default: ptr += MINBPC(enc); break; } } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; } static int PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { const char *start; if (ptr == end) return XML_TOK_NONE; start = ptr; while (ptr != end) { switch (BYTE_TYPE(enc, ptr)) { #define LEAD_CASE(n) \ case BT_LEAD ## n: ptr += n; break; LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) #undef LEAD_CASE case BT_AMP: if (ptr == start) return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; case BT_PERCNT: if (ptr == start) return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; case BT_LF: if (ptr == start) { *nextTokPtr = ptr + MINBPC(enc); return XML_TOK_DATA_NEWLINE; } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; case BT_CR: if (ptr == start) { ptr += MINBPC(enc); if (ptr == end) return XML_TOK_TRAILING_CR; if (BYTE_TYPE(enc, ptr) == BT_LF) ptr += MINBPC(enc); *nextTokPtr = ptr; return XML_TOK_DATA_NEWLINE; } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; default: ptr += MINBPC(enc); break; } } *nextTokPtr = ptr; return XML_TOK_DATA_CHARS; } static int PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { int level = 0; if (MINBPC(enc) > 1) { size_t n = end - ptr; if (n & (MINBPC(enc) - 1)) { n &= ~(MINBPC(enc) - 1); end = ptr + n; } } while (ptr != end) { switch (BYTE_TYPE(enc, ptr)) { INVALID_CASES(ptr, nextTokPtr); case BT_LT: if ((ptr += MINBPC(enc)) == end) return XML_TOK_PARTIAL; if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) { if ((ptr += MINBPC(enc)) == end) return XML_TOK_PARTIAL; if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) { ++level; ptr += MINBPC(enc); } } break; case BT_RSQB: if ((ptr += MINBPC(enc)) == end) return XML_TOK_PARTIAL; if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { if ((ptr += MINBPC(enc)) == end) return XML_TOK_PARTIAL; if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { ptr += MINBPC(enc); if (level == 0) { *nextTokPtr = ptr; return XML_TOK_IGNORE_SECT; } --level; } } break; default: ptr += MINBPC(enc); break; } } return XML_TOK_PARTIAL; } static int PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, const char **badPtr) { ptr += MINBPC(enc); end -= MINBPC(enc); for (; ptr != end; ptr += MINBPC(enc)) { switch (BYTE_TYPE(enc, ptr)) { case BT_DIGIT: case BT_HEX: case BT_MINUS: case BT_APOS: case BT_LPAR: case BT_RPAR: case BT_PLUS: case BT_COMMA: case BT_SOL: case BT_EQUALS: case BT_QUEST: case BT_CR: case BT_LF: case BT_SEMI: case BT_EXCL: case BT_AST: case BT_PERCNT: case BT_NUM: case BT_COLON: break; case BT_S: if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) { *badPtr = ptr; return 0; } break; case BT_NAME: case BT_NMSTRT: if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) break; default: switch (BYTE_TO_ASCII(enc, ptr)) { case 0x24: /* $ */ case 0x40: /* @ */ break; default: *badPtr = ptr; return 0; } break; } } return 1; } /* This must only be called for a well-formed start-tag or empty element tag. Returns the number of attributes. Pointers to the first attsMax attributes are stored in atts. */ static int PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax, ATTRIBUTE *atts) { enum { other, inName, inValue } state = inName; int nAtts = 0; int open = 0; /* defined when state == inValue; initialization just to shut up compilers */ for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { switch (BYTE_TYPE(enc, ptr)) { #define START_NAME \ if (state == other) { \ if (nAtts < attsMax) { \ atts[nAtts].name = ptr; \ atts[nAtts].normalized = 1; \ } \ state = inName; \ } #define LEAD_CASE(n) \ case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break; LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) #undef LEAD_CASE case BT_NONASCII: case BT_NMSTRT: case BT_HEX: START_NAME break; #undef START_NAME case BT_QUOT: if (state != inValue) { if (nAtts < attsMax) atts[nAtts].valuePtr = ptr + MINBPC(enc); state = inValue; open = BT_QUOT; } else if (open == BT_QUOT) { state = other; if (nAtts < attsMax) atts[nAtts].valueEnd = ptr; nAtts++; } break; case BT_APOS: if (state != inValue) { if (nAtts < attsMax) atts[nAtts].valuePtr = ptr + MINBPC(enc); state = inValue; open = BT_APOS; } else if (open == BT_APOS) { state = other; if (nAtts < attsMax) atts[nAtts].valueEnd = ptr; nAtts++; } break; case BT_AMP: if (nAtts < attsMax) atts[nAtts].normalized = 0; break; case BT_S: if (state == inName) state = other; else if (state == inValue && nAtts < attsMax && atts[nAtts].normalized && (ptr == atts[nAtts].valuePtr || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) atts[nAtts].normalized = 0; break; case BT_CR: case BT_LF: /* This case ensures that the first attribute name is counted Apart from that we could just change state on the quote. */ if (state == inName) state = other; else if (state == inValue && nAtts < attsMax) atts[nAtts].normalized = 0; break; case BT_GT: case BT_SOL: if (state != inValue) return nAtts; break; default: break; } } /* not reached */ } static int PREFIX(charRefNumber)(const ENCODING *enc ATTR_UNUSED, const char *ptr) { int result = 0; /* skip &# */ ptr += 2*MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_x)) { for (ptr += MINBPC(enc); !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { int c = BYTE_TO_ASCII(enc, ptr); switch (c) { case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4: case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9: result <<= 4; result |= (c - ASCII_0); break; case ASCII_A: case ASCII_B: case ASCII_C: case ASCII_D: case ASCII_E: case ASCII_F: result <<= 4; result += 10 + (c - ASCII_A); break; case ASCII_a: case ASCII_b: case ASCII_c: case ASCII_d: case ASCII_e: case ASCII_f: result <<= 4; result += 10 + (c - ASCII_a); break; } if (result >= 0x110000) return -1; } } else { for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { int c = BYTE_TO_ASCII(enc, ptr); result *= 10; result += (c - ASCII_0); if (result >= 0x110000) return -1; } } return checkCharRefNumber(result); } static int PREFIX(predefinedEntityName)(const ENCODING * enc ATTR_UNUSED, const char * ptr, const char * end) { switch ((end - ptr)/MINBPC(enc)) { case 2: if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) { switch (BYTE_TO_ASCII(enc, ptr)) { case ASCII_l: return ASCII_LT; case ASCII_g: return ASCII_GT; } } break; case 3: if (CHAR_MATCHES(enc, ptr, ASCII_a)) { ptr += MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_m)) { ptr += MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_p)) return ASCII_AMP; } } break; case 4: switch (BYTE_TO_ASCII(enc, ptr)) { case ASCII_q: ptr += MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_u)) { ptr += MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_o)) { ptr += MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_t)) return ASCII_QUOT; } } break; case ASCII_a: ptr += MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_p)) { ptr += MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_o)) { ptr += MINBPC(enc); if (CHAR_MATCHES(enc, ptr, ASCII_s)) return ASCII_APOS; } } break; } } return 0; } static int PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) { for (;;) { switch (BYTE_TYPE(enc, ptr1)) { #define LEAD_CASE(n) \ case BT_LEAD ## n: \ if (*ptr1++ != *ptr2++) \ return 0; LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) #undef LEAD_CASE /* fall through */ if (*ptr1++ != *ptr2++) return 0; break; case BT_NONASCII: case BT_NMSTRT: case BT_COLON: case BT_HEX: case BT_DIGIT: case BT_NAME: case BT_MINUS: if (*ptr2++ != *ptr1++) return 0; if (MINBPC(enc) > 1) { if (*ptr2++ != *ptr1++) return 0; if (MINBPC(enc) > 2) { if (*ptr2++ != *ptr1++) return 0; if (MINBPC(enc) > 3) { if (*ptr2++ != *ptr1++) return 0; } } } break; default: if (MINBPC(enc) == 1 && *ptr1 == *ptr2) return 1; switch (BYTE_TYPE(enc, ptr2)) { case BT_LEAD2: case BT_LEAD3: case BT_LEAD4: case BT_NONASCII: case BT_NMSTRT: case BT_COLON: case BT_HEX: case BT_DIGIT: case BT_NAME: case BT_MINUS: return 0; default: return 1; } } } /* not reached */ } static int PREFIX(nameMatchesAscii)(const ENCODING * enc ATTR_UNUSED, const char * ptr1, const char * end1, const char * ptr2) { for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { if (ptr1 == end1) return 0; if (!CHAR_MATCHES(enc, ptr1, *ptr2)) return 0; } return ptr1 == end1; } #define LEAD_CASE(n) case BT_LEAD ## n: ptr += n; break static size_t PREFIX(nameLength)(const ENCODING * const enc, const char * const start) { const char * ptr; for (ptr = start;;) { switch (BYTE_TYPE(enc, ptr)) { LEAD_CASE(2); LEAD_CASE(3); LEAD_CASE(4); case BT_NONASCII: case BT_NMSTRT: case BT_COLON: case BT_HEX: case BT_DIGIT: case BT_NAME: case BT_MINUS: ptr += MINBPC(enc); break; default: return ptr - start; } } } #undef LEAD_CASE static const char *PREFIX(skipS)(const ENCODING *enc, const char *ptr) { for (;;) { switch (BYTE_TYPE(enc, ptr)) { case BT_LF: case BT_CR: case BT_S: ptr += MINBPC(enc); break; default: return ptr; } } } #define LEAD_CASE(n) \ case BT_LEAD ## n: \ ptr += n; \ break static void PREFIX(updatePosition)(const ENCODING * const enc, const char * const start, const char * const end, POSITION * const posP) { const char * ptr; for (ptr = start; ptr < end;) { switch (BYTE_TYPE(enc, ptr)) { LEAD_CASE(2); LEAD_CASE(3); LEAD_CASE(4); case BT_LF: posP->columnNumber = (unsigned)-1; ++posP->lineNumber; ptr += MINBPC(enc); break; case BT_CR: ++posP->lineNumber; ptr += MINBPC(enc); if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) ptr += MINBPC(enc); posP->columnNumber = (unsigned)-1; break; default: ptr += MINBPC(enc); break; } ++posP->columnNumber; } } #undef LEAD_CASE #undef DO_LEAD_CASE #undef MULTIBYTE_CASES #undef INVALID_CASES #undef CHECK_NAME_CASE #undef CHECK_NAME_CASES #undef CHECK_NMSTRT_CASE #undef CHECK_NMSTRT_CASES xmlrpc-c-1.33.14/lib/expat/xmltok/xmltok_impl.h000066400000000000000000000012311236133176700213330ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ enum { BT_NONXML, BT_MALFORM, BT_LT, BT_AMP, BT_RSQB, BT_LEAD2, BT_LEAD3, BT_LEAD4, BT_TRAIL, BT_CR, BT_LF, BT_GT, BT_QUOT, BT_APOS, BT_EQUALS, BT_QUEST, BT_EXCL, BT_SOL, BT_SEMI, BT_NUM, BT_LSQB, BT_S, BT_NMSTRT, BT_COLON, BT_HEX, BT_DIGIT, BT_NAME, BT_MINUS, BT_OTHER, /* known not to be a name or name start character */ BT_NONASCII, /* might be a name or name start character */ BT_PERCNT, BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, BT_COMMA, BT_VERBAR }; #include xmlrpc-c-1.33.14/lib/expat/xmltok/xmltok_ns.c000066400000000000000000000106431236133176700210140ustar00rootroot00000000000000const ENCODING * NS(xmlrpc_XmlGetUtf8InternalEncoding)(void) { return &ns(internal_utf8_encoding).enc; } const ENCODING * NS(xmlrpc_XmlGetUtf16InternalEncoding)(void) { #if XML_BYTE_ORDER == 12 return &ns(internal_little2_encoding).enc; #elif XML_BYTE_ORDER == 21 return &ns(internal_big2_encoding).enc; #else const short n = 1; return *(const char *)&n ? &ns(internal_little2_encoding).enc : &ns(internal_big2_encoding).enc; #endif } static const ENCODING *NS(encodings)[] = { &ns(latin1_encoding).enc, &ns(ascii_encoding).enc, &ns(utf8_encoding).enc, &ns(big2_encoding).enc, &ns(big2_encoding).enc, &ns(little2_encoding).enc, &ns(utf8_encoding).enc /* NO_ENC */ }; static int NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE, ptr, end, nextTokPtr); } static int NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, const char **nextTokPtr) { return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE, ptr, end, nextTokPtr); } int NS(xmlrpc_XmlInitEncoding)(INIT_ENCODING * const p, const ENCODING ** const encPP, const char * const name) { int const index = getEncodingIndex(name); int retval; if (index == UNKNOWN_ENC) retval = 0; else { SET_INIT_ENC_INDEX(p, index); p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); p->initEnc.updatePosition = initUpdatePosition; p->encPtr = encPP; *encPP = &(p->initEnc); retval = 1; } return retval; } static const ENCODING *NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) { #define ENCODING_MAX 128 char buf[ENCODING_MAX]; char *p = buf; int i; XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); if (ptr != end) return 0; *p = 0; if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) return enc; i = getEncodingIndex(buf); if (i == UNKNOWN_ENC) return 0; return NS(encodings)[i]; } int NS(xmlrpc_XmlParseXmlDecl)(int const isGeneralTextEntity, const ENCODING * const encodingOfDecl, const char * const piText, const char * const end, const char ** const badP, const char ** const versionP, const char ** const encodingNameP, const ENCODING ** const encodingPP, int * const standaloneP) { /*---------------------------------------------------------------------------- Parse an XML declaration XML Processing Instruction (PI), i.e. ". 'piText' points to the beginning of the PI (to the "<"). 'end' points to the end of the PI (just past the ">"). 'encodingOfDecl' is the character encoding of the declaration. Return as *encodingNameP the value of the "encoding" pseudo-attribute in the declaration. Furthermore, return as *encodingPP a handle for the encoding so named, or NULL if we don't recognize the name. Return as *standaloneP 1 if the value of the "standalone" pseudo-attribute in the declaration is "yes"; 0 if it is "no". Return as *versionP the value of the "version" pseudo-attribute in the declaration. For all the return values, the pointer may be null, and in that case we just don't return that information. For all the return values, if the pseudo-attribute does not appear in the declaration, we just leave the pointed-to variable unchanged. (THIS IS WRONG; WE NEED TO FIX THIS). Iff the declaration has invalid syntax, return return value 1 and return as *badP a pointer to the part of the declaration that is bad. -----------------------------------------------------------------------------*/ return doParseXmlDecl(NS(findEncoding), isGeneralTextEntity, encodingOfDecl, piText, end, badP, versionP, encodingNameP, encodingPP, standaloneP); } xmlrpc-c-1.33.14/lib/expat/xmlwf/000077500000000000000000000000001236133176700164455ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/expat/xmlwf/Makefile.in000066400000000000000000000125131236133176700205140ustar00rootroot00000000000000# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = ../../.. ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : host_alias = @host_alias@ host_triplet = @host@ ABYSS_SUBDIR = @ABYSS_SUBDIR@ AS = @AS@ ASYNCH_CLIENT = @ASYNCH_CLIENT@ AUTH_CLIENT = @AUTH_CLIENT@ AVAILABLE_MODULES = @AVAILABLE_MODULES@ CC = @CC@ CC_WARN_FLAGS = @CC_WARN_FLAGS@ CLIENTTEST = @CLIENTTEST@ CONFIGURE_DATE = @CONFIGURE_DATE@ CPPTEST = @CPPTEST@ CPP_WARN_FLAGS = @CPP_WARN_FLAGS@ CXX = @CXX@ DLLTOOL = @DLLTOOL@ EFRPCTEST = @EFRPCTEST@ EFRPCTEST_WRAPPER = @EFRPCTEST_WRAPPER@ INTEROP_CGI = @INTEROP_CGI@ INTEROP_CLIENT_SUBDIR = @INTEROP_CLIENT_SUBDIR@ LIBTOOL = @LIBTOOL@ LIBWWW_CFLAGS = @LIBWWW_CFLAGS@ LIBWWW_CONFIG = @LIBWWW_CONFIG@ LIBWWW_LDADD = @LIBWWW_LDADD@ LIBWWW_LIBDIR = @LIBWWW_LIBDIR@ LIBWWW_RPATH = @LIBWWW_RPATH@ LIBWWW_WL_RPATH = @LIBWWW_WL_RPATH@ LIBXMLRPC_ABYSS_SERVER_LA = @LIBXMLRPC_ABYSS_SERVER_LA@ LIBXMLRPC_CGI_LA = @LIBXMLRPC_CGI_LA@ LIBXMLRPC_CLIENT_LA = @LIBXMLRPC_CLIENT_LA@ LIBXMLRPC_CPP_A = @LIBXMLRPC_CPP_A@ LN_S = @LN_S@ MAKEINFO = @MAKEINFO@ MEERKAT_APP_LIST = @MEERKAT_APP_LIST@ OBJDUMP = @OBJDUMP@ PACKAGE = @PACKAGE@ QUERY_MEERKAT = @QUERY_MEERKAT@ RANLIB = @RANLIB@ SAMPLE_CGI_CGI = @SAMPLE_CGI_CGI@ SERVER = @SERVER@ SERVERTEST = @SERVERTEST@ SYNCH_CLIENT = @SYNCH_CLIENT@ VALIDATEE = @VALIDATEE@ VERSION = @VERSION@ VERSION_INFO = @VERSION_INFO@ XMLRPCCPP_H = @XMLRPCCPP_H@ XMLRPC_ABYSS_H = @XMLRPC_ABYSS_H@ XMLRPC_CGI_H = @XMLRPC_CGI_H@ XMLRPC_CLIENT_H = @XMLRPC_CLIENT_H@ XML_RPC_API2CPP_SUBDIR = @XML_RPC_API2CPP_SUBDIR@ EXTRA_DIST = codepage.c filemap.h unixfilemap.c xmlfile.c xmltchar.h xmlwf.dsp codepage.h readfilemap.c win32filemap.c xmlfile.h xmlwf.c mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = ../../../xmlrpc_config.h CONFIG_CLEAN_FILES = DIST_COMMON = Makefile.in DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) TAR = gtar GZIP_ENV = --best all: all-redirect .SUFFIXES: Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status tags: TAGS TAGS: distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) subdir = lib/expat/xmlwf distdir: $(DISTFILES) @for file in $(DISTFILES); do \ d=$(srcdir); \ if test -d $$d/$$file; then \ cp -pr $$d/$$file $(distdir)/$$file; \ else \ test -f $(distdir)/$$file \ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done info-am: info: info-am dvi-am: dvi: dvi-am check-am: all-am check: check-am installcheck-am: installcheck: installcheck-am install-exec-am: install-exec: install-exec-am install-data-am: install-data: install-data-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am uninstall-am: uninstall: uninstall-am all-am: Makefile all-redirect: all-am install-strip: $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install installdirs: mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: mostlyclean-am: mostlyclean-generic mostlyclean: mostlyclean-am clean-am: clean-generic mostlyclean-am clean: clean-am distclean-am: distclean-generic clean-am -rm -f libtool distclean: distclean-am maintainer-clean-am: maintainer-clean-generic distclean-am @echo "This command is intended for maintainers to use;" @echo "it deletes files that may require special tools to rebuild." maintainer-clean: maintainer-clean-am .PHONY: tags distdir info-am info dvi-am dvi check check-am \ installcheck-am installcheck install-exec-am install-exec \ install-data-am install-data install-am install uninstall-am uninstall \ all-redirect all-am all installdirs mostlyclean-generic \ distclean-generic clean-generic maintainer-clean-generic clean \ mostlyclean distclean maintainer-clean # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: xmlrpc-c-1.33.14/lib/expat/xmlwf/codepage.c000066400000000000000000000023751236133176700203670ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include "xmlrpc_config.h" #include "codepage.h" #if MSVCRT #define STRICT 1 #define WIN32_LEAN_AND_MEAN #include int codepageMap(int cp, int *map) { int i; CPINFO info; if (!GetCPInfo(cp, &info) || info.MaxCharSize > 2) return 0; for (i = 0; i < 256; i++) map[i] = -1; if (info.MaxCharSize > 1) { for (i = 0; i < MAX_LEADBYTES; i++) { int j, lim; if (info.LeadByte[i] == 0 && info.LeadByte[i + 1] == 0) break; lim = info.LeadByte[i + 1]; for (j = info.LeadByte[i]; j < lim; j++) map[j] = -2; } } for (i = 0; i < 256; i++) { if (map[i] == -1) { char c = i; unsigned short n; if (MultiByteToWideChar(cp, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, &c, 1, &n, 1) == 1) map[i] = n; } } return 1; } int codepageConvert(int cp, const char *p) { unsigned short c; if (MultiByteToWideChar(cp, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, p, 2, &c, 1) == 1) return c; return -1; } #else /* MSVCRT */ int codepageMap(int cp, int *map) { return 0; } int codepageConvert(int cp, const char *p) { return -1; } #endif /* MSVCRT */ xmlrpc-c-1.33.14/lib/expat/xmlwf/codepage.h000066400000000000000000000003051236133176700203630ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ int codepageMap(int cp, int *map); int codepageConvert(int cp, const char *p); xmlrpc-c-1.33.14/lib/expat/xmlwf/filemap.h000066400000000000000000000006361236133176700202400ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include #ifdef XML_UNICODE int filemap(const wchar_t *name, void (*processor)(const void *, size_t, const wchar_t *, void *arg), void *arg); #else int filemap(const char *name, void (*processor)(const void *, size_t, const char *, void *arg), void *arg); #endif xmlrpc-c-1.33.14/lib/expat/xmlwf/readfilemap.c000066400000000000000000000025201236133176700210610ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include #include #include #include #include #ifndef S_ISREG #ifndef S_IFREG #define S_IFREG _S_IFREG #endif #ifndef S_IFMT #define S_IFMT _S_IFMT #endif #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif /* not S_ISREG */ #ifndef O_BINARY #ifdef _O_BINARY #define O_BINARY _O_BINARY #else #define O_BINARY 0 #endif #endif int filemap(const char *name, void (*processor)(const void *, size_t, const char *, void *arg), void *arg) { size_t nbytes; int fd; int n; struct stat sb; void *p; fd = open(name, O_RDONLY|O_BINARY); if (fd < 0) { perror(name); return 0; } if (fstat(fd, &sb) < 0) { perror(name); return 0; } if (!S_ISREG(sb.st_mode)) { fprintf(stderr, "%s: not a regular file\n", name); return 0; } nbytes = sb.st_size; p = malloc(nbytes); if (!p) { fprintf(stderr, "%s: out of memory\n", name); return 0; } n = read(fd, p, nbytes); if (n < 0) { perror(name); close(fd); return 0; } if (n != nbytes) { fprintf(stderr, "%s: read unexpected number of bytes\n", name); close(fd); return 0; } processor(p, nbytes, name, arg); free(p); close(fd); return 1; } xmlrpc-c-1.33.14/lib/expat/xmlwf/unixfilemap.c000066400000000000000000000020651236133176700211350ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include #include #include #include #include #include #include #ifndef MAP_FILE #define MAP_FILE 0 #endif #include "filemap.h" int filemap(const char *name, void (*processor)(const void *, size_t, const char *, void *arg), void *arg) { int fd; size_t nbytes; struct stat sb; void *p; fd = open(name, O_RDONLY); if (fd < 0) { perror(name); return 0; } if (fstat(fd, &sb) < 0) { perror(name); close(fd); return 0; } if (!S_ISREG(sb.st_mode)) { close(fd); fprintf(stderr, "%s: not a regular file\n", name); return 0; } nbytes = sb.st_size; p = (void *)mmap((caddr_t)0, (size_t)nbytes, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, (off_t)0); if (p == (void *)-1) { perror(name); close(fd); return 0; } processor(p, nbytes, name, arg); munmap((caddr_t)p, nbytes); close(fd); return 1; } xmlrpc-c-1.33.14/lib/expat/xmlwf/win32filemap.c000066400000000000000000000037711236133176700211210ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #define STRICT 1 #define WIN32_LEAN_AND_MEAN 1 #ifdef XML_UNICODE_WCHAR_T #ifndef XML_UNICODE #define XML_UNICODE #endif #endif #ifdef XML_UNICODE #define UNICODE #define _UNICODE #endif /* XML_UNICODE */ #define WIN32_LEAN_AND_MEAN #include #include #include #include "filemap.h" static void win32perror(const TCHAR *); int filemap(const TCHAR *name, void (*processor)(const void *, size_t, const TCHAR *, void *arg), void *arg) { HANDLE f; HANDLE m; DWORD size; DWORD sizeHi; void *p; f = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (f == INVALID_HANDLE_VALUE) { win32perror(name); return 0; } size = GetFileSize(f, &sizeHi); if (size == (DWORD)-1) { win32perror(name); return 0; } if (sizeHi) { _ftprintf(stderr, _T("%s: bigger than 2Gb\n"), name); return 0; } /* CreateFileMapping barfs on zero length files */ if (size == 0) { static const char c = '\0'; processor(&c, 0, name, arg); CloseHandle(f); return 1; } m = CreateFileMapping(f, NULL, PAGE_READONLY, 0, 0, NULL); if (m == NULL) { win32perror(name); CloseHandle(f); return 0; } p = MapViewOfFile(m, FILE_MAP_READ, 0, 0, 0); if (p == NULL) { win32perror(name); CloseHandle(m); CloseHandle(f); return 0; } processor(p, size, name, arg); UnmapViewOfFile(p); CloseHandle(m); CloseHandle(f); return 1; } static void win32perror(const TCHAR *s) { LPVOID buf; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL)) { _ftprintf(stderr, _T("%s: %s"), s, buf); fflush(stderr); LocalFree(buf); } else _ftprintf(stderr, _T("%s: unknown Windows error\n"), s); } xmlrpc-c-1.33.14/lib/expat/xmlwf/xmlfile.c000066400000000000000000000112131236133176700202470ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include #include #include #include #include #include "xmlrpc_config.h" #include "xmlparse.h" #include "xmlfile.h" #include "xmltchar.h" #include "filemap.h" #if MSVCRT #include #endif #ifdef _XOPEN_SOURCE 600 #include #endif #ifndef O_BINARY #ifdef _O_BINARY #define O_BINARY _O_BINARY #else #define O_BINARY 0 #endif #endif #ifdef _DEBUG #define READ_SIZE 16 #else #define READ_SIZE (1024*8) #endif typedef struct { XML_Parser parser; int *retPtr; } PROCESS_ARGS; static void reportError(XML_Parser parser, const XML_Char *filename) { int code = XML_GetErrorCode(parser); const XML_Char *message = XML_ErrorString(code); if (message) ftprintf(stdout, T("%s:%d:%d: %s\n"), filename, XML_GetErrorLineNumber(parser), XML_GetErrorColumnNumber(parser), message); else ftprintf(stderr, T("%s: (unknown message %d)\n"), filename, code); } static void processFile(const void *data, size_t size, const XML_Char *filename, void *args) { XML_Parser parser = ((PROCESS_ARGS *)args)->parser; int *retPtr = ((PROCESS_ARGS *)args)->retPtr; if (!XML_Parse(parser, data, size, 1)) { reportError(parser, filename); *retPtr = 0; } else *retPtr = 1; } #if MSVCRT static int isAsciiLetter(XML_Char c) { return (T('a') <= c && c <= T('z')) || (T('A') <= c && c <= T('Z')); } #endif /* MSVCRT */ static const XML_Char * resolveSystemId(const XML_Char *base, const XML_Char *systemId, XML_Char **toFree) { XML_Char *s; *toFree = 0; if (!base || *systemId == T('/') #if MSVCRT || *systemId == T('\\') || (isAsciiLetter(systemId[0]) && systemId[1] == T(':')) #endif ) return systemId; *toFree = (XML_Char *) malloc((tcslen(base) + tcslen(systemId) + 2)*sizeof(XML_Char)); if (!*toFree) return systemId; tcscpy(*toFree, base); s = *toFree; if (tcsrchr(s, T('/'))) s = tcsrchr(s, T('/')) + 1; #if MSVCRT if (tcsrchr(s, T('\\'))) s = tcsrchr(s, T('\\')) + 1; #endif tcscpy(s, systemId); return *toFree; } static int externalEntityRefFilemap(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { int result; XML_Char *s; const XML_Char *filename; XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); PROCESS_ARGS args; args.retPtr = &result; args.parser = entParser; filename = resolveSystemId(base, systemId, &s); XML_SetBase(entParser, filename); if (!filemap(filename, processFile, &args)) result = 0; free(s); XML_ParserFree(entParser); return result; } static int processStream(const XML_Char *filename, XML_Parser parser) { int fd = topen(filename, O_BINARY|O_RDONLY); if (fd < 0) { tperror(filename); return 0; } for (;;) { int nread; char *buf = XML_GetBuffer(parser, READ_SIZE); if (!buf) { close(fd); ftprintf(stderr, T("%s: out of memory\n"), filename); return 0; } nread = read(fd, buf, READ_SIZE); if (nread < 0) { tperror(filename); close(fd); return 0; } if (!XML_ParseBuffer(parser, nread, nread == 0)) { reportError(parser, filename); close(fd); return 0; } if (nread == 0) { close(fd); break;; } } return 1; } static int externalEntityRefStream(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XML_Char *s; const XML_Char *filename; int ret; XML_Parser entParser = XML_ExternalEntityParserCreate(parser, context, 0); filename = resolveSystemId(base, systemId, &s); XML_SetBase(entParser, filename); ret = processStream(filename, entParser); free(s); XML_ParserFree(entParser); return ret; } int XML_ProcessFile(XML_Parser parser, const XML_Char *filename, unsigned flags) { int result; if (!XML_SetBase(parser, filename)) { ftprintf(stderr, T("%s: out of memory"), filename); exit(1); } if (flags & XML_EXTERNAL_ENTITIES) XML_SetExternalEntityRefHandler(parser, (flags & XML_MAP_FILE) ? externalEntityRefFilemap : externalEntityRefStream); if (flags & XML_MAP_FILE) { PROCESS_ARGS args; args.retPtr = &result; args.parser = parser; if (!filemap(filename, processFile, &args)) result = 0; } else result = processStream(filename, parser); return result; } xmlrpc-c-1.33.14/lib/expat/xmlwf/xmlfile.h000066400000000000000000000004251236133176700202570ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #define XML_MAP_FILE 01 #define XML_EXTERNAL_ENTITIES 02 extern int XML_ProcessFile(XML_Parser parser, const XML_Char *filename, unsigned flags); xmlrpc-c-1.33.14/lib/expat/xmlwf/xmltchar.h000066400000000000000000000014711236133176700204430ustar00rootroot00000000000000#ifdef XML_UNICODE #ifndef XML_UNICODE_WCHAR_T #error xmlwf requires a 16-bit Unicode-compatible wchar_t #endif #define T(x) L ## x #define ftprintf fwprintf #define tfopen _wfopen #define fputts fputws #define puttc putwc #define tcscmp wcscmp #define tcscpy wcscpy #define tcscat wcscat #define tcschr wcschr #define tcsrchr wcsrchr #define tcslen wcslen #define tperror _wperror #define topen _wopen #define tmain wmain #define tremove _wremove #else /* not XML_UNICODE */ #define T(x) x #define ftprintf fprintf #define tfopen fopen #define fputts fputs #define puttc putc #define tcscmp strcmp #define tcscpy strcpy #define tcscat strcat #define tcschr strchr #define tcsrchr strrchr #define tcslen strlen #define tperror perror #define topen open #define tmain main #define tremove remove #endif /* not XML_UNICODE */ xmlrpc-c-1.33.14/lib/expat/xmlwf/xmlwf.c000066400000000000000000000430041236133176700177470ustar00rootroot00000000000000/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd See the file copying.txt for copying permission. */ #include #include #include #include #include "xmlrpc_config.h" #include "xmlparse.h" #include "codepage.h" #include "xmlfile.h" #include "xmltchar.h" #if MSVCRT #include #endif /* This ensures proper sorting. */ #define NSSEP T('\001') static void characterData(void *userData, const XML_Char *s, int len) { FILE *fp = userData; for (; len > 0; --len, ++s) { switch (*s) { case T('&'): fputts(T("&"), fp); break; case T('<'): fputts(T("<"), fp); break; case T('>'): fputts(T(">"), fp); break; #ifdef W3C14N case 13: fputts(T(" "), fp); break; #else case T('"'): fputts(T("""), fp); break; case 9: case 10: case 13: ftprintf(fp, T("&#%d;"), *s); break; #endif default: puttc(*s, fp); break; } } } static void attributeValue(FILE *fp, const XML_Char *s) { puttc(T('='), fp); puttc(T('"'), fp); for (;;) { switch (*s) { case 0: case NSSEP: puttc(T('"'), fp); return; case T('&'): fputts(T("&"), fp); break; case T('<'): fputts(T("<"), fp); break; case T('"'): fputts(T("""), fp); break; #ifdef W3C14N case 9: fputts(T(" "), fp); break; case 10: fputts(T(" "), fp); break; case 13: fputts(T(" "), fp); break; #else case T('>'): fputts(T(">"), fp); break; case 9: case 10: case 13: ftprintf(fp, T("&#%d;"), *s); break; #endif default: puttc(*s, fp); break; } s++; } } /* Lexicographically comparing UTF-8 encoded attribute values, is equivalent to lexicographically comparing based on the character number. */ static int attcmp(const void *att1, const void *att2) { return tcscmp(*(const XML_Char **)att1, *(const XML_Char **)att2); } static void startElement(void *userData, const XML_Char *name, const XML_Char **atts) { int nAtts; const XML_Char **p; FILE *fp = userData; puttc(T('<'), fp); fputts(name, fp); p = atts; while (*p) ++p; nAtts = (p - atts) >> 1; if (nAtts > 1) qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, attcmp); while (*atts) { puttc(T(' '), fp); fputts(*atts++, fp); attributeValue(fp, *atts); atts++; } puttc(T('>'), fp); } static void endElement(void *userData, const XML_Char *name) { FILE *fp = userData; puttc(T('<'), fp); puttc(T('/'), fp); fputts(name, fp); puttc(T('>'), fp); } static int nsattcmp(const void *p1, const void *p2) { const XML_Char *att1 = *(const XML_Char **)p1; const XML_Char *att2 = *(const XML_Char **)p2; int sep1 = (tcsrchr(att1, NSSEP) != 0); int sep2 = (tcsrchr(att1, NSSEP) != 0); if (sep1 != sep2) return sep1 - sep2; return tcscmp(att1, att2); } static void startElementNS(void *userData, const XML_Char *name, const XML_Char **atts) { int nAtts; int nsi; const XML_Char **p; FILE *fp = userData; const XML_Char *sep; puttc(T('<'), fp); sep = tcsrchr(name, NSSEP); if (sep) { fputts(T("n1:"), fp); fputts(sep + 1, fp); fputts(T(" xmlns:n1"), fp); attributeValue(fp, name); nsi = 2; } else { fputts(name, fp); nsi = 1; } p = atts; while (*p) ++p; nAtts = (p - atts) >> 1; if (nAtts > 1) qsort((void *)atts, nAtts, sizeof(XML_Char *) * 2, nsattcmp); while (*atts) { name = *atts++; sep = tcsrchr(name, NSSEP); puttc(T(' '), fp); if (sep) { ftprintf(fp, T("n%d:"), nsi); fputts(sep + 1, fp); } else fputts(name, fp); attributeValue(fp, *atts); if (sep) { ftprintf(fp, T(" xmlns:n%d"), nsi++); attributeValue(fp, name); } atts++; } puttc(T('>'), fp); } static void endElementNS(void *userData, const XML_Char *name) { FILE *fp = userData; const XML_Char *sep; puttc(T('<'), fp); puttc(T('/'), fp); sep = tcsrchr(name, NSSEP); if (sep) { fputts(T("n1:"), fp); fputts(sep + 1, fp); } else fputts(name, fp); puttc(T('>'), fp); } #ifndef W3C14N static void processingInstruction(void *userData, const XML_Char *target, const XML_Char *data) { FILE *fp = userData; puttc(T('<'), fp); puttc(T('?'), fp); fputts(target, fp); puttc(T(' '), fp); fputts(data, fp); puttc(T('?'), fp); puttc(T('>'), fp); } #endif /* not W3C14N */ static void defaultCharacterData(XML_Parser parser, const XML_Char *s, int len) { XML_DefaultCurrent(parser); } static void defaultStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts) { XML_DefaultCurrent(parser); } static void defaultEndElement(XML_Parser parser, const XML_Char *name) { XML_DefaultCurrent(parser); } static void defaultProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data) { XML_DefaultCurrent(parser); } static void nopCharacterData(XML_Parser parser, const XML_Char *s, int len) { } static void nopStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts) { } static void nopEndElement(XML_Parser parser, const XML_Char *name) { } static void nopProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data) { } static void markup(XML_Parser parser, const XML_Char *s, int len) { FILE *fp = XML_GetUserData(parser); for (; len > 0; --len, ++s) puttc(*s, fp); } static void metaLocation(XML_Parser parser) { const XML_Char *uri = XML_GetBase(parser); if (uri) ftprintf(XML_GetUserData(parser), T(" uri=\"%s\""), uri); ftprintf(XML_GetUserData(parser), T(" byte=\"%ld\" nbytes=\"%d\" line=\"%d\" col=\"%d\""), XML_GetCurrentByteIndex(parser), XML_GetCurrentByteCount(parser), XML_GetCurrentLineNumber(parser), XML_GetCurrentColumnNumber(parser)); } static void metaStartDocument(XML_Parser parser) { fputts(T("\n"), XML_GetUserData(parser)); } static void metaEndDocument(XML_Parser parser) { fputts(T("\n"), XML_GetUserData(parser)); } static void metaStartElement(XML_Parser parser, const XML_Char *name, const XML_Char **atts) { FILE *fp = XML_GetUserData(parser); const XML_Char **specifiedAttsEnd = atts + XML_GetSpecifiedAttributeCount(parser); const XML_Char **idAttPtr; int idAttIndex = XML_GetIdAttributeIndex(parser); if (idAttIndex < 0) idAttPtr = 0; else idAttPtr = atts + idAttIndex; ftprintf(fp, T("\n"), fp); do { ftprintf(fp, T("= specifiedAttsEnd) fputts(T("\" defaulted=\"yes\"/>\n"), fp); else if (atts == idAttPtr) fputts(T("\" id=\"yes\"/>\n"), fp); else fputts(T("\"/>\n"), fp); } while (*(atts += 2)); fputts(T("\n"), fp); } else fputts(T("/>\n"), fp); } static void metaEndElement(XML_Parser parser, const XML_Char *name) { FILE *fp = XML_GetUserData(parser); ftprintf(fp, T("\n"), fp); } static void metaProcessingInstruction(XML_Parser parser, const XML_Char *target, const XML_Char *data) { FILE *fp = XML_GetUserData(parser); ftprintf(fp, T("\n"), fp); } static void metaComment(XML_Parser parser, const XML_Char *data) { FILE *fp = XML_GetUserData(parser); fputts(T("\n"), fp); } static void metaStartCdataSection(XML_Parser parser) { FILE *fp = XML_GetUserData(parser); fputts(T("\n"), fp); } static void metaEndCdataSection(XML_Parser parser) { FILE *fp = XML_GetUserData(parser); fputts(T("\n"), fp); } static void metaCharacterData(XML_Parser parser, const XML_Char *s, int len) { FILE *fp = XML_GetUserData(parser); fputts(T("\n"), fp); } static void metaStartDoctypeDecl(XML_Parser parser, const XML_Char *doctypeName) { FILE *fp = XML_GetUserData(parser); ftprintf(fp, T("\n"), fp); } static void metaEndDoctypeDecl(XML_Parser parser) { FILE *fp = XML_GetUserData(parser); fputts(T("\n"), fp); } static void metaUnparsedEntityDecl(XML_Parser parser, const XML_Char *entityName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId, const XML_Char *notationName) { FILE *fp = XML_GetUserData(parser); ftprintf(fp, T("\n"), fp); } static void metaNotationDecl(XML_Parser parser, const XML_Char *notationName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { FILE *fp = XML_GetUserData(parser); ftprintf(fp, T("\n"), fp); } static void metaExternalParsedEntityDecl(XML_Parser parser, const XML_Char *entityName, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { FILE *fp = XML_GetUserData(parser); ftprintf(fp, T("\n"), fp); } static void metaInternalParsedEntityDecl(XML_Parser parser, const XML_Char *entityName, const XML_Char *text, int textLen) { FILE *fp = XML_GetUserData(parser); ftprintf(fp, T("'), fp); characterData(fp, text, textLen); fputts(T("\n"), fp); } static void metaStartNamespaceDecl(XML_Parser parser, const XML_Char *prefix, const XML_Char *uri) { FILE *fp = XML_GetUserData(parser); fputts(T("\n"), fp); } else fputts(T("/>\n"), fp); } static void metaEndNamespaceDecl(XML_Parser parser, const XML_Char *prefix) { FILE *fp = XML_GetUserData(parser); if (!prefix) fputts(T("\n"), fp); else ftprintf(fp, T("\n"), prefix); } static int unknownEncodingConvert(void *data, const char *p) { return codepageConvert(*(int *)data, p); } static int unknownEncoding(void *userData, const XML_Char *name, XML_Encoding *info) { int cp; static const XML_Char prefixL[] = T("windows-"); static const XML_Char prefixU[] = T("WINDOWS-"); int i; for (i = 0; prefixU[i]; i++) if (name[i] != prefixU[i] && name[i] != prefixL[i]) return 0; cp = 0; for (; name[i]; i++) { static const XML_Char digits[] = T("0123456789"); const XML_Char *s = tcschr(digits, name[i]); if (!s) return 0; cp *= 10; cp += s - digits; if (cp >= 0x10000) return 0; } if (!codepageMap(cp, info->map)) return 0; info->convert = unknownEncodingConvert; /* We could just cast the code page integer to a void *, and avoid the use of release. */ info->release = free; info->data = malloc(sizeof(int)); if (!info->data) return 0; *(int *)info->data = cp; return 1; } static int notStandalone(void *userData) { return 0; } static void usage(const XML_Char *prog) { ftprintf(stderr, T("usage: %s [-n] [-p] [-r] [-s] [-w] [-x] [-d output-dir] [-e encoding] file ...\n"), prog); exit(1); } int tmain(int argc, XML_Char **argv) { int i, j; const XML_Char *outputDir = 0; const XML_Char *encoding = 0; unsigned processFlags = XML_MAP_FILE; int windowsCodePages = 0; int outputType = 0; int useNamespaces = 0; int requireStandalone = 0; int paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; #if MSVCRT _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF); #endif i = 1; j = 0; while (i < argc) { if (j == 0) { if (argv[i][0] != T('-')) break; if (argv[i][1] == T('-') && argv[i][2] == T('\0')) { i++; break; } j++; } switch (argv[i][j]) { case T('r'): processFlags &= ~XML_MAP_FILE; j++; break; case T('s'): requireStandalone = 1; j++; break; case T('n'): useNamespaces = 1; j++; break; case T('p'): paramEntityParsing = XML_PARAM_ENTITY_PARSING_ALWAYS; /* fall through */ case T('x'): processFlags |= XML_EXTERNAL_ENTITIES; j++; break; case T('w'): windowsCodePages = 1; j++; break; case T('m'): outputType = 'm'; j++; break; case T('c'): outputType = 'c'; useNamespaces = 0; j++; break; case T('t'): outputType = 't'; j++; break; case T('d'): if (argv[i][j + 1] == T('\0')) { if (++i == argc) usage(argv[0]); outputDir = argv[i]; } else outputDir = argv[i] + j + 1; i++; j = 0; break; case T('e'): if (argv[i][j + 1] == T('\0')) { if (++i == argc) usage(argv[0]); encoding = argv[i]; } else encoding = argv[i] + j + 1; i++; j = 0; break; case T('\0'): if (j > 1) { i++; j = 0; break; } /* fall through */ default: usage(argv[0]); } } if (i == argc) usage(argv[0]); for (; i < argc; i++) { FILE *fp = 0; XML_Char *outName = 0; int result; XML_Parser parser; if (useNamespaces) parser = XML_ParserCreateNS(encoding, NSSEP); else parser = XML_ParserCreate(encoding); if (requireStandalone) XML_SetNotStandaloneHandler(parser, notStandalone); XML_SetParamEntityParsing(parser, paramEntityParsing); if (outputType == 't') { /* This is for doing timings; this gives a more realistic estimate of the parsing time. */ outputDir = 0; XML_SetElementHandler(parser, nopStartElement, nopEndElement); XML_SetCharacterDataHandler(parser, nopCharacterData); XML_SetProcessingInstructionHandler(parser, nopProcessingInstruction); } else if (outputDir) { const XML_Char *file = argv[i]; if (tcsrchr(file, T('/'))) file = tcsrchr(file, T('/')) + 1; #if MSVCRT if (tcsrchr(file, T('\\'))) file = tcsrchr(file, T('\\')) + 1; #endif outName = malloc((tcslen(outputDir) + tcslen(file) + 2) * sizeof(XML_Char)); tcscpy(outName, outputDir); tcscat(outName, T("/")); tcscat(outName, file); fp = tfopen(outName, T("wb")); if (!fp) { tperror(outName); exit(1); } setvbuf(fp, NULL, _IOFBF, 16384); #ifdef XML_UNICODE puttc(0xFEFF, fp); #endif XML_SetUserData(parser, fp); switch (outputType) { case 'm': XML_UseParserAsHandlerArg(parser); XML_SetElementHandler(parser, metaStartElement, metaEndElement); XML_SetProcessingInstructionHandler(parser, metaProcessingInstruction); XML_SetCommentHandler(parser, metaComment); XML_SetCdataSectionHandler(parser, metaStartCdataSection, metaEndCdataSection); XML_SetCharacterDataHandler(parser, metaCharacterData); XML_SetDoctypeDeclHandler(parser, metaStartDoctypeDecl, metaEndDoctypeDecl); XML_SetUnparsedEntityDeclHandler(parser, metaUnparsedEntityDecl); XML_SetNotationDeclHandler(parser, metaNotationDecl); XML_SetExternalParsedEntityDeclHandler(parser, metaExternalParsedEntityDecl); XML_SetInternalParsedEntityDeclHandler(parser, metaInternalParsedEntityDecl); XML_SetNamespaceDeclHandler(parser, metaStartNamespaceDecl, metaEndNamespaceDecl); metaStartDocument(parser); break; case 'c': XML_UseParserAsHandlerArg(parser); XML_SetDefaultHandler(parser, markup); XML_SetElementHandler(parser, defaultStartElement, defaultEndElement); XML_SetCharacterDataHandler(parser, defaultCharacterData); XML_SetProcessingInstructionHandler(parser, defaultProcessingInstruction); break; default: if (useNamespaces) XML_SetElementHandler(parser, startElementNS, endElementNS); else XML_SetElementHandler(parser, startElement, endElement); XML_SetCharacterDataHandler(parser, characterData); #ifndef W3C14N XML_SetProcessingInstructionHandler(parser, processingInstruction); #endif /* not W3C14N */ break; } } if (windowsCodePages) XML_SetUnknownEncodingHandler(parser, unknownEncoding, 0); result = XML_ProcessFile(parser, argv[i], processFlags); if (outputDir) { if (outputType == 'm') metaEndDocument(parser); fclose(fp); if (!result) tremove(outName); free(outName); } XML_ParserFree(parser); } return 0; } xmlrpc-c-1.33.14/lib/expat/xmlwf/xmlwf.dsp000066400000000000000000000107121236133176700203130ustar00rootroot00000000000000# Microsoft Developer Studio Project File - Name="xmlwf" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=xmlwf - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "xmlwf.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "xmlwf.mak" CFG="xmlwf - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "xmlwf - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "xmlwf - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "xmlwf - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir ".\Release" # PROP BASE Intermediate_Dir ".\Release" # PROP BASE Target_Dir "." # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir ".\Release" # PROP Intermediate_Dir ".\Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "." # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c # ADD CPP /nologo /W3 /GX /O2 /I "..\xmlparse" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D XMLTOKAPI=__declspec(dllimport) /D XMLPARSEAPI=__declspec(dllimport) /YX /FD /c # ADD BASE RSC /l 0x809 /d "NDEBUG" # ADD RSC /l 0x809 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 setargv.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\bin\xmlwf.exe" !ELSEIF "$(CFG)" == "xmlwf - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir ".\Debug" # PROP BASE Intermediate_Dir ".\Debug" # PROP BASE Target_Dir "." # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir ".\Debug" # PROP Intermediate_Dir ".\Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "." # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\xmlparse" /I "..\xmlparse" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D XMLTOKAPI=__declspec(dllimport) /D XMLPARSEAPI=__declspec(dllimport) /YX /FD /c # ADD BASE RSC /l 0x809 /d "_DEBUG" # ADD RSC /l 0x809 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 # ADD LINK32 setargv.obj kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\dbgbin\xmlwf.exe" !ENDIF # Begin Target # Name "xmlwf - Win32 Release" # Name "xmlwf - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" # Begin Source File SOURCE=.\codepage.c # End Source File # Begin Source File SOURCE=.\readfilemap.c # PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\unixfilemap.c # PROP Exclude_From_Build 1 # End Source File # Begin Source File SOURCE=.\win32filemap.c # End Source File # Begin Source File SOURCE=.\xmlfile.c # End Source File # Begin Source File SOURCE=.\xmlwf.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" # Begin Source File SOURCE=.\codepage.h # End Source File # Begin Source File SOURCE=.\xmlfile.h # End Source File # Begin Source File SOURCE=.\xmltchar.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" # End Group # End Target # End Project xmlrpc-c-1.33.14/lib/libutil/000077500000000000000000000000001236133176700156335ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/libutil/Makefile000066400000000000000000000054161236133176700173010ustar00rootroot00000000000000############################################################################### # This directory builds libxmlrpc_util, which contains utility # functions that are used by the Xmlprc-c libraries, and also # directly by Xmlrpc-c programs. Some of them are documented for use # by Xmlrpc-c users, as facilities of the libxmlrpc library (which # prerequires libxmlrpc_util). # # The functions in this library are characterized by being general purpose # programming functions, such as one might wish were in the standard C # library, which have nothing in particular to do with XML-RPC. ############################################################################### ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') LIBDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/libutil include $(BLDDIR)/config.mk default: all TARGET_LIBRARY_NAMES := libxmlrpc_util STATIC_LIBRARIES_TO_INSTALL = libxmlrpc_util.a SHARED_LIBS_TO_BUILD := libxmlrpc_util SHARED_LIBS_TO_INSTALL := libxmlrpc_util TARGET_MODS = \ asprintf \ base64 \ error \ lock_platform \ lock_pthread \ lock_none \ make_printable \ memblock \ select \ sleep \ string_number \ time \ utf8 \ OMIT_LIBXMLRPC_UTIL_RULE=Y MAJ=3 # Major number of shared libraries in this directory include $(SRCDIR)/common.mk INCLUDES = -I$(BLDDIR) -Isrcdir \ -I$(BLDDIR)/include -Isrcdir/include -Isrcdir/lib/util/include UTIL_SHLIB = $(call shlibfn,libxmlrpc_util) #UTIL_SHLIB is e.g. libxmlrpc_util.so.3.1 UTIL_SHLIBLE = $(call shliblefn,libxmlrpc_util) #UTIL_SHLIBLE is e.g. libxmlrpc_util.so # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir .PHONY: all all: libxmlrpc_util.a $(TARGET_SHARED_LIBRARIES) $(TARGET_SHARED_LE_LIBS) # Rule for this is in common.mk, courtesy of TARGET_LIBRARY_NAMES: $(UTIL_SHLIB): $(TARGET_MODS:%=%.osh) $(UTIL_SHLIB): LIBOBJECTS = $(TARGET_MODS:%=%.osh) $(UTIL_SHLIB): LIBDEP += -lpthread ifeq ($(MSVCRT), yes) $(UTIL_SHLIB): LIBDEP += -lws2_32 -lwsock32 endif # Rule for this is in common.mk, courtesy of TARGET_LIBRARY_NAMES: libxmlrpc_util.a: $(TARGET_MODS:%=%.o) libxmlrpc_util.a: LIBOBJECTS = $(TARGET_MODS:%=%.o) #----------------------------------------------------------------------------- # RULES TO COMPILE OBJECT MODULES FOR LIBRARIES #----------------------------------------------------------------------------- # Rules to compile object modules from which to build the static and shared # library are in common.mk, courtesy of TARGET_MODS. .PHONY: install install: install-common .PHONY: clean distclean clean: clean-common distclean: clean distclean-common .PHONY: dep dep: dep-common include depend.mk xmlrpc-c-1.33.14/lib/libutil/asprintf.c000066400000000000000000000113761236133176700176350ustar00rootroot00000000000000#define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #define _GNU_SOURCE /* But only when HAVE_ASPRINTF */ #include #include #include #include #include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */ #include "xmlrpc-c/string_int.h" #include "bool.h" static __inline__ void newVsnprintf(char * const buffer, size_t const bufferSize, const char * const fmt, va_list varargs, size_t * const formattedSizeP) { /*---------------------------------------------------------------------------- This is vsnprintf() with the new behavior, where not fitting in the buffer is not a failure. Unfortunately, we can't practically return the size of the formatted string if the C library has old vsnprintf() and the formatted string doesn't fit in the buffer, so in that case we just return something larger than the buffer. -----------------------------------------------------------------------------*/ if (bufferSize > INT_MAX/2) { /* There's a danger we won't be able to coerce the return value of XMLRPC_VSNPRINTF to an integer (which we have to do because, while for POSIX its return value is ssize_t, on Windows it is int), or return double the buffer size. */ *formattedSizeP = 0; } else { int rc; rc = XMLRPC_VSNPRINTF(buffer, bufferSize, fmt, varargs); if (rc < 0) { /* We have old vsnprintf() (or Windows) and the formatted value doesn't fit in the buffer, but we don't know how big a buffer it needs. */ *formattedSizeP = bufferSize * 2; } else { /* Either the string fits in the buffer or we have new vsnprintf() which tells us how big the string is regardless. */ *formattedSizeP = rc; } } } static __inline__ void simpleVasprintf(char ** const retvalP, const char * const fmt, va_list varargs) { /*---------------------------------------------------------------------------- This is a poor man's implementation of vasprintf(), of GNU fame. -----------------------------------------------------------------------------*/ char * result; size_t bufferSize; bool outOfMemory; for (result = NULL, bufferSize = 4096, outOfMemory = false; !result && !outOfMemory; ) { result = malloc(bufferSize); if (!result) outOfMemory = true; else { size_t bytesNeeded; newVsnprintf(result, bufferSize, fmt, varargs, &bytesNeeded); if (bytesNeeded > bufferSize) { free(result); result = NULL; bufferSize = bytesNeeded; } } } *retvalP = result; } static const char * const xmlrpc_strsol = "[insufficient memory to build string]"; bool xmlrpc_strnomem(const char * const string) { /*---------------------------------------------------------------------------- The string 'string' was generated by a function in this file because it couldn't get enough memory to generate the string that it was supposed to generate. I.e. a preceding call to a string function failed. -----------------------------------------------------------------------------*/ return string == xmlrpc_strsol; } const char * xmlrpc_strnomemval() { return xmlrpc_strsol; } void xmlrpc_vasprintf(const char ** const retvalP, const char * const fmt, va_list varargs) { char * string; #if HAVE_ASPRINTF vasprintf(&string, fmt, varargs); #else simpleVasprintf(&string, fmt, varargs); #endif if (string == NULL) *retvalP = xmlrpc_strsol; else *retvalP = string; } void XMLRPC_PRINTF_ATTR(2,3) xmlrpc_asprintf(const char ** const retvalP, const char * const fmt, ...) { va_list varargs; /* mysterious structure used by variable arg facility */ va_start(varargs, fmt); /* start up the mysterious variable arg facility */ xmlrpc_vasprintf(retvalP, fmt, varargs); va_end(varargs); } const char * xmlrpc_strdupsol(const char * const string) { const char * retvalOrNull; retvalOrNull = strdup(string); return retvalOrNull ? retvalOrNull : xmlrpc_strsol; } void xmlrpc_strfree(const char * const string) { if (string != xmlrpc_strsol) free((void *)string); } const char * xmlrpc_strdupnull(const char * const string) { if (string) return strdup(string); else return NULL; } void xmlrpc_strfreenull(const char * const string) { if (string) xmlrpc_strfree(string); } xmlrpc-c-1.33.14/lib/libutil/base64.c000066400000000000000000000262701236133176700170720ustar00rootroot00000000000000#include #include "xmlrpc_config.h" #include "bool.h" #include "xmlrpc-c/util.h" #include "int.h" #include "xmlrpc-c/base64_int.h" void xmlrpc_base64Encode(const char * const chars, char * const base64) { /*---------------------------------------------------------------------------- This is for internal use by Xmlrpc-c libraries. It is useful for libraries such as Abyss that don't use xmlrpc_memblock and xmlrpc_env. -----------------------------------------------------------------------------*/ /* Conversion table. */ static char tbl[64] = { 'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/' }; unsigned int i; uint32_t length; char * p; const char * s; length = strlen(chars); /* initial value */ s = &chars[0]; /* initial value */ p = &base64[0]; /* initial value */ /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ for (i = 0; i < length; i += 3) { *p++ = tbl[s[0] >> 2]; *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; *p++ = tbl[s[2] & 0x3f]; s += 3; } /* Pad the result if necessary... */ if (i == length + 1) *(p - 1) = '='; else if (i == length + 2) *(p - 1) = *(p - 2) = '='; /* ...and zero-terminate it. */ *p = '\0'; } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ** There is more copyright information in the bottom half of this file. ** Please see it for more details. */ /*========================================================================= ** XML-RPC Base64 Utilities **========================================================================= ** This code was swiped from Jack Jansen's code in Python 1.5.2 and ** modified to work with our data types. */ #define CRLF "\015\012" #define CR '\015' #define LF '\012' /*********************************************************** Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI or Corporation for National Research Initiatives or CNRI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. While CWI is the initial source for this software, a modified version is made available by the Corporation for National Research Initiatives (CNRI) at the Internet address ftp://ftp.python.org. STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ static char table_a2b_base64[] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, /* Note PAD->0 */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 }; #define BASE64_PAD '=' #define BASE64_MAXBIN 57 /* Max binary chunk size (76 char line) */ #define BASE64_LINE_SZ 128 /* Buffer size for a single line. */ static unsigned char const table_b2a_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static xmlrpc_mem_block * base64Encode(xmlrpc_env * const envP, const unsigned char * const binData, size_t const binLen, bool const wantNewlines) { size_t chunkStart, chunkLeft; unsigned char * asciiData; int leftbits; unsigned char thisCh; unsigned int leftchar; xmlrpc_mem_block * outputP; unsigned char lineBuffer[BASE64_LINE_SZ]; const unsigned char * cursor; /* Create a block to hold our lines when we finish them. */ outputP = xmlrpc_mem_block_new(envP, 0); XMLRPC_FAIL_IF_FAULT(envP); /* Deal with empty data blocks gracefully. Yuck. */ if (binLen == 0) { if (wantNewlines) XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, CRLF, 2); goto cleanup; } /* Process our binary data in line-sized chunks. */ for (chunkStart = 0, cursor = &binData[0]; chunkStart < binLen; chunkStart += BASE64_MAXBIN) { /* Set up our per-line state. */ asciiData = &lineBuffer[0]; chunkLeft = binLen - chunkStart; if (chunkLeft > BASE64_MAXBIN) chunkLeft = BASE64_MAXBIN; leftbits = 0; leftchar = 0; for(; chunkLeft > 0; --chunkLeft, ++cursor) { /* Shift the data into our buffer */ leftchar = (leftchar << 8) | *cursor; leftbits += 8; /* See if there are 6-bit groups ready */ while (leftbits >= 6) { thisCh = (leftchar >> (leftbits-6)) & 0x3f; leftbits -= 6; *asciiData++ = table_b2a_base64[thisCh]; } } if (leftbits == 2) { *asciiData++ = table_b2a_base64[(leftchar&3) << 4]; *asciiData++ = BASE64_PAD; *asciiData++ = BASE64_PAD; } else if (leftbits == 4) { *asciiData++ = table_b2a_base64[(leftchar&0xf) << 2]; *asciiData++ = BASE64_PAD; } /* Append a courtesy CRLF. */ if (wantNewlines) { *asciiData++ = CR; *asciiData++ = LF; } /* Save our line. */ XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, lineBuffer, asciiData - &lineBuffer[0]); XMLRPC_FAIL_IF_FAULT(envP); } cleanup: if (envP->fault_occurred) { if (outputP) xmlrpc_mem_block_free(outputP); return NULL; } return outputP; } xmlrpc_mem_block * xmlrpc_base64_encode(xmlrpc_env * const envP, const unsigned char * const binData, size_t const binLen) { return base64Encode(envP, binData, binLen, true); } xmlrpc_mem_block * xmlrpc_base64_encode_without_newlines(xmlrpc_env * const envP, const unsigned char * const binData, size_t const binLen) { return base64Encode(envP, binData, binLen, false); } xmlrpc_mem_block * xmlrpc_base64_decode(xmlrpc_env * const envP, const char * const asciiData, size_t const acsiiLen) { unsigned char * binData; int leftbits; unsigned char thisCh; unsigned int leftchar; size_t npad; size_t binLen, bufferSize; xmlrpc_mem_block * outputP; const char * nextCharP; size_t remainingLen; /* Create a block to hold our chunks when we finish them. ** We overestimate the size now, and fix it later. */ bufferSize = ((acsiiLen + 3) / 4) * 3; outputP = xmlrpc_mem_block_new(envP, bufferSize); XMLRPC_FAIL_IF_FAULT(envP); /* Set up our decoder state. */ leftbits = 0; leftchar = 0; npad = 0; binData = XMLRPC_MEMBLOCK_CONTENTS(unsigned char, outputP); binLen = 0; for (remainingLen = acsiiLen, nextCharP = asciiData; remainingLen > 0; --remainingLen, ++nextCharP) { /* Skip some punctuation. */ thisCh = (*nextCharP & 0x7f); if (thisCh == '\r' || thisCh == '\n' || thisCh == ' ') continue; if (thisCh == BASE64_PAD) ++npad; thisCh = table_a2b_base64[(*nextCharP) & 0x7f]; /* XXX - We just throw away invalid characters. Is this right? */ if (thisCh == (unsigned char) -1) continue; /* Shift it in on the low end, and see if there's a byte ready for output. */ leftchar = (leftchar << 6) | (thisCh); leftbits += 6; if (leftbits >= 8) { leftbits -= 8; XMLRPC_ASSERT(binLen < bufferSize); *binData++ = (leftchar >> leftbits) & 0xFF; leftchar &= ((1 << leftbits) - 1); ++binLen; } } /* Check that no bits are left. */ if (leftbits) XMLRPC_FAIL(envP, XMLRPC_PARSE_ERROR, "Incorrect Base64 padding"); /* Check to make sure we have a sane amount of padding. */ if (npad > binLen || npad > 2) XMLRPC_FAIL(envP, XMLRPC_PARSE_ERROR, "Malformed Base64 data"); /* Remove any padding and set the correct size. */ binLen -= npad; XMLRPC_MEMBLOCK_RESIZE(char, envP, outputP, binLen); XMLRPC_ASSERT(!envP->fault_occurred); cleanup: if (envP->fault_occurred) { if (outputP) xmlrpc_mem_block_free(outputP); return NULL; } return outputP; } xmlrpc-c-1.33.14/lib/libutil/error.c000066400000000000000000000113261236133176700171330ustar00rootroot00000000000000/* Copyright information is at end of file */ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include "xmlrpc_config.h" #include #include #include #include #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/util.h" void xmlrpc_assertion_failed(const char * const fileName, int const lineNumber) { fprintf(stderr, "%s:%d: assertion failed\n", fileName, lineNumber); abort(); } static const char * const default_fault_string = "Not enough memory for error message"; void xmlrpc_env_init (xmlrpc_env* env) { XMLRPC_ASSERT(env != NULL); env->fault_occurred = 0; env->fault_code = 0; env->fault_string = NULL; } void xmlrpc_env_clean(xmlrpc_env * const envP) { XMLRPC_ASSERT(envP != NULL); XMLRPC_ASSERT(envP->fault_string != XMLRPC_BAD_POINTER); /* env->fault_string may be one of three things: ** 1) a NULL pointer ** 2) a pointer to the default_fault_string ** 3) a pointer to a malloc'd fault string ** If we have case (3), we'll need to free it. */ if (envP->fault_string && envP->fault_string != default_fault_string) free(envP->fault_string); envP->fault_string = XMLRPC_BAD_POINTER; } void xmlrpc_env_set_fault(xmlrpc_env * const envP, int const faultCode, const char * const faultDescription) { char * buffer; XMLRPC_ASSERT(envP != NULL); XMLRPC_ASSERT(faultDescription != NULL); /* Clean up any leftover pointers. */ xmlrpc_env_clean(envP); envP->fault_occurred = 1; envP->fault_code = faultCode; /* Try to copy the fault string. If this fails, use a default. */ buffer = strdup(faultDescription); if (buffer == NULL) envP->fault_string = (char *)default_fault_string; else { xmlrpc_force_to_utf8(buffer); xmlrpc_force_to_xml_chars(buffer); envP->fault_string = buffer; } } void xmlrpc_set_fault_formatted_v(xmlrpc_env * const envP, int const code, const char * const format, va_list args) { const char * faultDescription; xmlrpc_vasprintf(&faultDescription, format, args); xmlrpc_env_set_fault(envP, code, faultDescription); xmlrpc_strfree(faultDescription); } void xmlrpc_env_set_fault_formatted(xmlrpc_env * const envP, int const code, const char * const format, ...) { va_list args; XMLRPC_ASSERT(envP != NULL); XMLRPC_ASSERT(format != NULL); /* Print our error message to the buffer. */ va_start(args, format); xmlrpc_set_fault_formatted_v(envP, code, format, args); va_end(args); } void xmlrpc_faultf(xmlrpc_env * const envP, const char * const format, ...) { va_list args; XMLRPC_ASSERT(envP != NULL); XMLRPC_ASSERT(format != NULL); /* Print our error message to the buffer. */ va_start(args, format); xmlrpc_set_fault_formatted_v(envP, XMLRPC_INTERNAL_ERROR, format, args); va_end(args); } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/lib/libutil/lock_none.c000066400000000000000000000022231236133176700177450ustar00rootroot00000000000000/*============================================================================= lock_none =============================================================================== This is an inter-thread lock class for a system in which there is no inter-thread conflict, e.g. where no two threads every share memory. The locking is therefore trivial: no-op =============================================================================*/ #include #include "mallocvar.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_none.h" static lockAcquireFn acquire; static void acquire(struct lock * const lockP ATTR_UNUSED) { } static lockReleaseFn release; static void release(struct lock * const lockP ATTR_UNUSED) { } static lockDestroyFn destroy; static void destroy(struct lock * const lockP ATTR_UNUSED) { free(lockP); } struct lock * xmlrpc_lock_create_none(void) { struct lock * lockP; MALLOCVAR(lockP); if (lockP) { lockP->implementationP = NULL; lockP->acquire = &acquire; lockP->release = &release; lockP->destroy = &destroy; } return lockP; } xmlrpc-c-1.33.14/lib/libutil/lock_platform.c000066400000000000000000000027241236133176700206400ustar00rootroot00000000000000/*============================================================================= lock_platform =============================================================================== This module provides locking services appropriate for the platform for which Xmlrpc-c is being built. I.e. services chosen by the build configuration. ============================================================================*/ #include "xmlrpc_config.h" #include "xmlrpc-c/lock_platform.h" #if HAVE_PTHREAD #include "xmlrpc-c/lock_pthread.h" #endif #if HAVE_WINDOWS_THREAD #include "xmlrpc-c/lock_windows.h" #endif struct lock * xmlrpc_lock_create(void) { #if HAVE_PTHREAD return xmlrpc_lock_create_pthread(); #elif HAVE_WINDOWS_THREAD return xmlrpc_lock_create_windows(); #else #error "You don't have any thread facility. (According to " #error "HAVE_PTHREAD and HAVE_WINDOWS_THREAD macros defined in " #error "xmlrpc_config.h)" /* One might consider using xmlrpc_lock_create_none() here, but that would be dangerous. If the system really does have threads that share memory, and there's just some configuration error here (which is the most likely case), we would silently build a broken library, which breakage would be difficult for the user to detect and then diagnose. If we encounter some actual need for lock_none in the future, we'll revisit the issue of when the build system should select it */ #endif } xmlrpc-c-1.33.14/lib/libutil/lock_pthread.c000066400000000000000000000023151236133176700204370ustar00rootroot00000000000000#include #include #include "mallocvar.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_pthread.h" static lockAcquireFn acquire; static void acquire(struct lock * const lockP) { pthread_mutex_t * const mutexP = lockP->implementationP; pthread_mutex_lock(mutexP); } static lockReleaseFn release; static void release(struct lock * const lockP) { pthread_mutex_t * const mutexP = lockP->implementationP; pthread_mutex_unlock(mutexP); } static lockDestroyFn destroy; static void destroy(struct lock * const lockP) { pthread_mutex_t * const mutexP = lockP->implementationP; pthread_mutex_destroy(mutexP); free(mutexP); free(lockP); } struct lock * xmlrpc_lock_create_pthread(void) { struct lock * lockP; MALLOCVAR(lockP); if (lockP) { pthread_mutex_t * mutexP; MALLOCVAR(mutexP); if (mutexP) { pthread_mutex_init(mutexP, NULL); lockP->implementationP = mutexP; lockP->acquire = &acquire; lockP->release = &release; lockP->destroy = &destroy; } else { free(lockP); lockP = NULL; } } return lockP; } xmlrpc-c-1.33.14/lib/libutil/lock_windows.c000066400000000000000000000031551236133176700205050ustar00rootroot00000000000000#include "xmlrpc_config.h" /* We define WIN32_WIN_LEAN_AND_MEAN to make contain less junk; nothing in Xmlrpc-c needs that stuff. One significant thing it cuts out is , which would conflict with the that our includer might use. */ #define WIN32_WIN_LEAN_AND_MEAN #include #include "mallocvar.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_windows.h" static lockAcquireFn acquire; static void acquire(struct lock * const lockP) { CRITICAL_SECTION * const criticalSectionP = lockP->implementationP; EnterCriticalSection(criticalSectionP); } static lockReleaseFn release; static void release(struct lock * const lockP) { CRITICAL_SECTION * const criticalSectionP = lockP->implementationP; LeaveCriticalSection(criticalSectionP); } static lockDestroyFn destroy; static void destroy(struct lock * const lockP) { CRITICAL_SECTION * const criticalSectionP = lockP->implementationP; DeleteCriticalSection(criticalSectionP); free(criticalSectionP); free(lockP); } struct lock * xmlrpc_lock_create_windows(void) { struct lock * lockP; MALLOCVAR(lockP); if (lockP) { CRITICAL_SECTION * criticalSectionP; MALLOCVAR(criticalSectionP); if (criticalSectionP) { InitializeCriticalSection(criticalSectionP); lockP->implementationP = criticalSectionP; lockP->acquire = &acquire; lockP->release = &release; lockP->destroy = &destroy; } else { free(lockP); lockP = NULL; } } return lockP; } xmlrpc-c-1.33.14/lib/libutil/make_printable.c000066400000000000000000000064111236133176700207560ustar00rootroot00000000000000#define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include #include #include "xmlrpc_config.h" #include "xmlrpc-c/string_int.h" const char * xmlrpc_makePrintable_lp(const char * const input, size_t const inputLength) { /*---------------------------------------------------------------------------- Convert an arbitrary string of characters in length-pointer form to printable ASCII. E.g. convert newlines to "\n". Return the result in newly malloc'ed storage. Return NULL if we can't get the storage. -----------------------------------------------------------------------------*/ char * output; output = malloc(inputLength*4+1); /* Worst case, we render a character like \x01 -- 4 characters */ if (output != NULL) { unsigned int inputCursor, outputCursor; for (inputCursor = 0, outputCursor = 0; inputCursor < inputLength; ++inputCursor) { if (0) { } else if (input[inputCursor] == '\\') { output[outputCursor++] = '\\'; output[outputCursor++] = '\\'; } else if (input[inputCursor] == '\n') { output[outputCursor++] = '\\'; output[outputCursor++] = 'n'; } else if (input[inputCursor] == '\t') { output[outputCursor++] = '\\'; output[outputCursor++] = 't'; } else if (input[inputCursor] == '\a') { output[outputCursor++] = '\\'; output[outputCursor++] = 'a'; } else if (input[inputCursor] == '\r') { output[outputCursor++] = '\\'; output[outputCursor++] = 'r'; } else if (isprint(input[inputCursor])) { output[outputCursor++] = input[inputCursor]; } else { snprintf(&output[outputCursor], 5, "\\x%02x", (unsigned char)input[inputCursor]); outputCursor += 4; } } output[outputCursor++] = '\0'; } return output; } const char * xmlrpc_makePrintable(const char * const input) { /*---------------------------------------------------------------------------- Convert an arbitrary string of characters (NUL-terminated, though) to printable ASCII. E.g. convert newlines to "\n". Return the result in newly malloc'ed storage. Return NULL if we can't get the storage. -----------------------------------------------------------------------------*/ return xmlrpc_makePrintable_lp(input, strlen(input)); } const char * xmlrpc_makePrintableChar(char const input) { /*---------------------------------------------------------------------------- Return an ASCIIZ string consisting of the character 'input', properly escaped so as to be printable. E.g., in C notation, '\n' turns into "\\n" -----------------------------------------------------------------------------*/ const char * retval; if (input == '\0') retval = strdup("\\0"); else { char buffer[2]; buffer[0] = input; buffer[1] = '\0'; retval = xmlrpc_makePrintable(buffer); } return retval; } xmlrpc-c-1.33.14/lib/libutil/memblock.c000066400000000000000000000135421236133176700175750ustar00rootroot00000000000000/* Copyright information is at end of file */ #include "xmlrpc_config.h" #include #include #include #include #include "mallocvar.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/util.h" #ifdef EFENCE /* when looking for corruption don't allocate extra slop */ #define BLOCK_ALLOC_MIN (1) #else #define BLOCK_ALLOC_MIN (16) #endif #define BLOCK_ALLOC_MAX (128 * 1024 * 1024) xmlrpc_mem_block * xmlrpc_mem_block_new(xmlrpc_env * const envP, size_t const size) { xmlrpc_mem_block * block; XMLRPC_ASSERT_ENV_OK(envP); MALLOCVAR(block); if (block == NULL) xmlrpc_faultf(envP, "Can't allocate memory block"); else { xmlrpc_mem_block_init(envP, block, size); if (envP->fault_occurred) { free(block); block = NULL; } } return block; } /* Destroy an existing xmlrpc_mem_block, and everything it contains. */ void xmlrpc_mem_block_free(xmlrpc_mem_block * const blockP) { XMLRPC_ASSERT(blockP != NULL); XMLRPC_ASSERT(blockP->_block != NULL); xmlrpc_mem_block_clean(blockP); free(blockP); } /* Initialize the contents of the provided xmlrpc_mem_block. */ void xmlrpc_mem_block_init(xmlrpc_env * const envP, xmlrpc_mem_block * const blockP, size_t const size) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(blockP != NULL); blockP->_size = size; if (size < BLOCK_ALLOC_MIN) blockP->_allocated = BLOCK_ALLOC_MIN; else blockP->_allocated = size; blockP->_block = (void*) malloc(blockP->_allocated); if (!blockP->_block) xmlrpc_faultf(envP, "Can't allocate %u-byte memory block", (unsigned)blockP->_allocated); } /* Deallocate the contents of the provided xmlrpc_mem_block, but not the block itself. */ void xmlrpc_mem_block_clean(xmlrpc_mem_block * const blockP) { XMLRPC_ASSERT(blockP != NULL); XMLRPC_ASSERT(blockP->_block != NULL); free(blockP->_block); blockP->_block = XMLRPC_BAD_POINTER; } /* Get the size of the xmlrpc_mem_block. */ size_t xmlrpc_mem_block_size(const xmlrpc_mem_block * const blockP) { XMLRPC_ASSERT(blockP != NULL); return blockP->_size; } /* Get the contents of the xmlrpc_mem_block. */ void * xmlrpc_mem_block_contents(const xmlrpc_mem_block * const blockP) { XMLRPC_ASSERT(blockP != NULL); return blockP->_block; } /* Resize an xmlrpc_mem_block, preserving as much of the contents as possible. */ void xmlrpc_mem_block_resize (xmlrpc_env * const envP, xmlrpc_mem_block * const blockP, size_t const size) { size_t proposed_alloc; void* new_block; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(blockP != NULL); /* Check to see if we already have enough space. Maybe we'll get lucky. */ if (size <= blockP->_allocated) { blockP->_size = size; return; } /* Calculate a new allocation size. */ #ifdef EFENCE proposed_alloc = size; #else proposed_alloc = blockP->_allocated; while (proposed_alloc < size && proposed_alloc <= BLOCK_ALLOC_MAX) proposed_alloc *= 2; #endif /* DEBUG_MEM_ERRORS */ if (proposed_alloc > BLOCK_ALLOC_MAX) XMLRPC_FAIL(envP, XMLRPC_INTERNAL_ERROR, "Memory block too large"); /* Allocate our new memory block. */ new_block = (void*) malloc(proposed_alloc); XMLRPC_FAIL_IF_NULL(new_block, envP, XMLRPC_INTERNAL_ERROR, "Can't resize memory block"); /* Copy over our data and update the xmlrpc_mem_block struct. */ memcpy(new_block, blockP->_block, blockP->_size); free(blockP->_block); blockP->_block = new_block; blockP->_size = size; blockP->_allocated = proposed_alloc; cleanup: return; } void xmlrpc_mem_block_append(xmlrpc_env * const envP, xmlrpc_mem_block * const blockP, const void * const data, size_t const len) { size_t const originalSize = blockP->_size; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(blockP != NULL); xmlrpc_mem_block_resize(envP, blockP, originalSize + len); if (!envP->fault_occurred) { memcpy(((unsigned char*) blockP->_block) + originalSize, data, len); } } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/lib/libutil/select.c000066400000000000000000000033121236133176700172550ustar00rootroot00000000000000#define _XOPEN_SOURCE 600 /* Get pselect() in */ #include "xmlrpc_config.h" #if MSVCRT #include #else /* In some systems (SUS), the select() interface comes from ; in others, from , and others from both. Including both in this order appears to work on all. */ #include #if HAVE_SYS_SELECT_H #include #include /* For struct timespec on some systems */ #endif #endif #include #include "xmlrpc-c/select_int.h" /* xmlrpc_pselect() is just for use with sockets. In a POSIX system, it technically works for any file descriptor, but in Windows, select() is part of the socket facility. */ int xmlrpc_pselect(int const n, fd_set * const readfdsP, fd_set * const writefdsP, fd_set * const exceptfdsP, const xmlrpc_timespec * const timeoutP, sigset_t * const sigmaskP) { int retval; #if HAVE_PSELECT #if !HAVE_TIMESPEC #error "Impossible configuration -- has pselect(), but not struct timespec" #else retval = pselect(n, readfdsP, writefdsP, exceptfdsP, timeoutP, sigmaskP); #endif #else /* HAVE_PSELECT */ struct timeval timeout; timeout.tv_sec = timeoutP->tv_sec; timeout.tv_usec = timeoutP->tv_nsec/1000; #if MSVCRT retval = select(n, readfdsP, writefdsP, exceptfdsP, &timeout); #else { sigset_t origmask; sigprocmask(SIG_SETMASK, sigmaskP, &origmask); retval = select(n, readfdsP, writefdsP, exceptfdsP, &timeout); sigprocmask(SIG_SETMASK, &origmask, NULL); } #endif #endif return retval; } xmlrpc-c-1.33.14/lib/libutil/sleep.c000066400000000000000000000005511236133176700171100ustar00rootroot00000000000000#include "xmlrpc_config.h" #include "bool.h" #include "xmlrpc-c/sleep_int.h" #if MSVCRT # define WIN32_LEAN_AND_MEAN # include # include #else # include #endif void xmlrpc_millisecond_sleep(unsigned int const milliseconds) { #if MSVCRT SleepEx(milliseconds, true); #else usleep(milliseconds * 1000); #endif } xmlrpc-c-1.33.14/lib/libutil/string_number.c000066400000000000000000000026421236133176700206610ustar00rootroot00000000000000/*============================================================================ string_number ============================================================================== This file contains utilities for dealing with text string representation of numbers. ============================================================================*/ #include #include #include #include #include #include #include "xmlrpc_config.h" #include "int.h" #include void xmlrpc_parse_int64(xmlrpc_env * const envP, const char * const str, xmlrpc_int64 * const i64P) { xmlrpc_int64 i64val; char * tail; errno = 0; i64val = XMLRPC_STRTOLL(str, &tail, 10); if (errno == ERANGE) xmlrpc_faultf(envP, "Number cannot be represented in 64 bits. " "Must be in the range " "[%" XMLRPC_PRId64 " - %" XMLRPC_PRId64 "]", XMLRPC_INT64_MIN, XMLRPC_INT64_MAX); else if (errno != 0) xmlrpc_faultf(envP, "unexpected error: " "strtoll() failed with errno %d (%s)", errno, strerror(errno)); else if (tail[0] != '\0') xmlrpc_faultf(envP, "contains non-numerical junk: '%s'", tail); else *i64P = i64val; } xmlrpc-c-1.33.14/lib/libutil/time.c000066400000000000000000000107021236133176700167350ustar00rootroot00000000000000#include "xmlrpc_config.h" #include #include #if HAVE_GETTIMEOFDAY # include #endif #if MSVCRT # define WIN32_LEAN_AND_MEAN # include #endif #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/time_int.h" /* A note about struct timeval and Windows: There is a 'struct timeval' type in Windows, but it is just an argument to select(), which is just part of the sockets interface. It's defined identically to the POSIX type of the same name, but not meant for general timekeeping as the POSIX type is. */ #if HAVE_GETTIMEOFDAY static void gettimeofdayPosix(xmlrpc_timespec * const todP) { struct timeval tv; gettimeofday(&tv, NULL); todP->tv_sec = tv.tv_sec; todP->tv_nsec = tv.tv_usec * 1000; } #endif #if MSVCRT static void gettimeofdayWindows(xmlrpc_timespec * const todP) { __int64 const epochOffset = 116444736000000000ll; /* Number of 100-nanosecond units between the beginning of the Windows epoch (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970). */ FILETIME ft; LARGE_INTEGER li; __int64 t; GetSystemTimeAsFileTime(&ft); li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; t = (li.QuadPart - epochOffset) * 100; /* nanoseconds */ todP->tv_sec = (long)(t / 1E9); todP->tv_nsec = (long)(t - (__int64)todP->tv_sec * 1E9); } #endif void xmlrpc_gettimeofday(xmlrpc_timespec * const todP) { assert(todP); #if HAVE_GETTIMEOFDAY gettimeofdayPosix(todP); #else #if MSVCRT gettimeofdayWindows(todP); #else #error "We don't know how to get the time of day on this system" #endif #endif /* HAVE_GETTIMEOFDAY */ } static bool isLeapYear(unsigned int const yearOfAd) { return (yearOfAd % 4) == 0 && ((yearOfAd % 100) != 0 || (yearOfAd % 400) == 0); } void xmlrpc_timegm(const struct tm * const tmP, time_t * const timeValueP, const char ** const errorP) { /*---------------------------------------------------------------------------- This does what GNU libc's timegm() does. -----------------------------------------------------------------------------*/ if (tmP->tm_year < 70 || tmP->tm_mon > 11 || tmP->tm_mon < 0 || tmP->tm_mday > 31 || tmP->tm_min > 60 || tmP->tm_sec > 60 || tmP->tm_hour > 24) { xmlrpc_asprintf(errorP, "Invalid time specification; a member " "of struct tm is out of range"); } else { static unsigned int const monthDaysNonLeap[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; unsigned int totalDays; unsigned int year; unsigned int month; totalDays = 0; /* initial value */ for (year = 70; year < (unsigned int)tmP->tm_year; ++year) totalDays += isLeapYear(1900 + year) ? 366 : 365; for (month = 0; month < (unsigned int)tmP->tm_mon; ++month) totalDays += monthDaysNonLeap[month]; if (tmP->tm_mon > 1 && isLeapYear(1900 + tmP->tm_year)) totalDays += 1; totalDays += tmP->tm_mday - 1; *errorP = NULL; *timeValueP = ((totalDays * 24 + tmP->tm_hour) * 60 + tmP->tm_min) * 60 + tmP->tm_sec; } } void xmlrpc_localtime(time_t const datetime, struct tm * const tmP) { /*---------------------------------------------------------------------------- Convert datetime from standard to broken-down format in the local time zone. For Windows, this is not thread-safe. If you run a version of Abyss with multiple threads, you can get arbitrary results here. -----------------------------------------------------------------------------*/ #if HAVE_LOCALTIME_R localtime_r(&datetime, tmP); #else *tmP = *localtime(&datetime); #endif } void xmlrpc_gmtime(time_t const datetime, struct tm * const resultP) { /*---------------------------------------------------------------------------- Convert datetime from standard to broken-down UTC format. For Windows, this is not thread-safe. If you run a version of Abyss with multiple threads, you can get arbitrary results here. -----------------------------------------------------------------------------*/ #if HAVE_GMTIME_R gmtime_r(&datetime, resultP); #else *resultP = *gmtime(&datetime); #endif } xmlrpc-c-1.33.14/lib/libutil/utf8.c000066400000000000000000000542741236133176700167010ustar00rootroot00000000000000/* Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ /*========================================================================= ** XML-RPC UTF-8 Utilities **========================================================================= ** Routines for validating, encoding and decoding UTF-8 data. We try to ** be very, very strict about invalid UTF-8 data. ** ** All of the code in this file assumes that your machine represents ** wchar_t as a 16-bit (or wider) character containing UCS-2 data. If this ** assumption is incorrect, you may need to replace this file. ** ** For lots of information on Unicode and UTF-8 decoding, see: ** http://www.cl.cam.ac.uk/~mgk25/unicode.html */ #include #include "int.h" #include "xmlrpc_config.h" #include "bool.h" #include "xmlrpc-c/base.h" /*========================================================================= ** Tables and Constants **========================================================================= ** We use a variety of tables and constants to help decode and validate ** UTF-8 data. */ static unsigned char utf8SeqLength[256] = { /* utf8SeqLength[B] is the number of bytes in a UTF-8 sequence that starts with byte B. Except zero indicates an illegal initial byte. Fredrik Lundh's UTF-8 decoder Python 2.0 uses a similar table. But since Python 2.0 has the icky CNRI license, I generated this table from scratch and wrote my own decoder. */ /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ /* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* D */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* E */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* F */ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 }; /* The minimum legal character value for a UTF-8 sequence of the given ** length. We have to check this to avoid accepting "overlong" UTF-8 ** sequences, which use more bytes than necessary to encode a given ** character. Such sequences are commonly used by evil people to bypass ** filters and security checks. This table is based on the UTF-8-test.txt ** file by Markus Kuhn . */ static uint32_t const utf8_min_char_for_length[] = { 0, /* Length 0: Not used (meaningless) */ 0x0000, /* Length 1: Not used (special-cased) */ 0x0080, /* Length 2 */ 0x0800, /* Length 3 */ 0x00010000, /* Length 4 */ 0x00200000, /* Length 5 */ 0x04000000 /* Length 6 */ }; /* This is the maximum legal 16-byte (UCS-2) character. Again, this ** information is based on UTF-8-test.txt. */ #define UCS2_MAX_LEGAL_CHARACTER (0xFFFD) /* First and last UTF-16 surrogate characters. These are *not* legal UCS-2 ** characters--they're used to code for UCS-4 characters when using ** UTF-16. They should never appear in decoded UTF-8 data! Again, these ** could hypothetically be used to bypass security measures on some machines. ** Based on UTF-8-test.txt. */ #define UTF16_FIRST_SURROGATE (0xD800) #define UTF16_LAST_SURROGATE (0xDFFF) /* Is the character 'c' a UTF-8 continuation character? */ #define IS_CONTINUATION(c) (((c) & 0xC0) == 0x80) #define MAX_ENCODED_BYTES (3) /* Maximum number of bytes needed to encode in UTF-8 a character in the Basic Multilingual Plane. */ #if HAVE_UNICODE_WCHAR static void validateContinuation(xmlrpc_env * const envP, char const c) { if (!IS_CONTINUATION(c)) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INVALID_UTF8_ERROR, "UTF-8 multibyte sequence contains character 0x%02x, " "which does not indicate continuation.", c); } static void validateUtf16(xmlrpc_env * const envP, wchar_t const wc) { /*---------------------------------------------------------------------------- Validate that the string is a legal UTF16 encoding of a Unicode character. Actually, we validate that it is UCS-2. The set of UCS-2 encodings is a subset of the set of UTF16 encodings. In particular, it is the set of UTF16 encodings that are 16 bits. UCS-2 is a fixed-length encoding, with 16 bits per character, whereas UTF16 is variable length, with 1 or more 16 bit units per character. The name of the subroutine reflects the fact that in concept, we _should_ accept any UTF16, but we haven't taken the time yet to figure out how to do that (in the big picture, not just this subroutine). The user will notice only if he uses those really arcane 3.1% of the Unicode characters that take more than 16 bits to represent in UTF16. -----------------------------------------------------------------------------*/ if (wc > UCS2_MAX_LEGAL_CHARACTER) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INVALID_UTF8_ERROR, "Xmlrpc-c is not capable of handling UTF16 character encodings " "longer than 16 bits, which means you can't have a code point " "> U+FFFD. " "This string contains 0x%04x", (unsigned)wc); else if (UTF16_FIRST_SURROGATE <= wc && wc <= UTF16_LAST_SURROGATE) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INVALID_UTF8_ERROR, "UTF-16 surrogates may not appear in UTF-8 data. " "String contains %04x", (unsigned)wc); } /* Microsoft Visual C in debug mode produces code that complains about returning an undefined value from xmlrpc_datetime_new_str(). It's a bogus complaint, because this function is defined to return nothing meaningful those cases. So we disable the check. */ #pragma runtime_checks("u", off) static void decodeMultibyte(xmlrpc_env * const envP, const char * const utf8_seq, size_t const length, wchar_t * const wcP) { /*---------------------------------------------------------------------------- Decode the multibyte UTF-8 sequence which is 'length' characters at 'utf8_data'. Return the character in UTF-16 format as *wcP. -----------------------------------------------------------------------------*/ wchar_t wc; assert(utf8_seq[0] & 0x80); /* High bit set: this is multibyte seq */ switch (length) { case 2: /* 110xxxxx 10xxxxxx */ validateContinuation(envP, utf8_seq[1]); if (!envP->fault_occurred) wc = ((((wchar_t) (utf8_seq[0] & 0x1F)) << 6) | (((wchar_t) (utf8_seq[1] & 0x3F)))); break; case 3: /* 1110xxxx 10xxxxxx 10xxxxxx */ validateContinuation(envP, utf8_seq[1]); if (!envP->fault_occurred) { validateContinuation(envP, utf8_seq[2]); if (!envP->fault_occurred) wc = ((((wchar_t) (utf8_seq[0] & 0x0F)) << 12) | (((wchar_t) (utf8_seq[1] & 0x3F)) << 6) | (((wchar_t) (utf8_seq[2] & 0x3F)))); } break; case 4: /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ case 5: /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ case 6: /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ /* This would require more than 16 bits in UTF-16, so it can't be represented in UCS-2, so it's beyond our capability. Characters in the BMP fit in 16 bits. */ xmlrpc_env_set_fault_formatted( envP, XMLRPC_INVALID_UTF8_ERROR, "UTF-8 string contains a character not in the " "Basic Multilingual Plane (first byte 0x%02x)", utf8_seq[0]); break; default: xmlrpc_faultf(envP, "Internal error: Impossible UTF-8 sequence length %u", (unsigned)length); } if (!envP->fault_occurred) validateUtf16(envP, wc); if (!envP->fault_occurred) if ((uint32_t)wc < utf8_min_char_for_length[length]) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INVALID_UTF8_ERROR, "Overlong UTF-8 sequence not allowed"); *wcP = wc; } #pragma runtime_checks("u", restore) static void decodeUtf8(xmlrpc_env * const envP, const char * const utf8_data, size_t const utf8_len, wchar_t * const ioBuff, size_t * const outBuffLenP) { /*---------------------------------------------------------------------------- Decode to UCS-2 (or validate as UTF-8 that can be decoded to UCS-2) a UTF-8 string. To validate, set ioBuff and outBuffLenP to NULL. To decode, allocate a sufficiently large buffer, pass it as ioBuff, and pass a pointer as as outBuffLenP. The data will be written to the buffer, and the length to outBuffLenP. We assume that wchar_t holds a single UCS-2 character in native-endian byte ordering. -----------------------------------------------------------------------------*/ size_t utf8Cursor; size_t outPos; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(utf8_data); XMLRPC_ASSERT((!ioBuff && !outBuffLenP) || (ioBuff && outBuffLenP)); for (utf8Cursor = 0, outPos = 0; utf8Cursor < utf8_len && !envP->fault_occurred; ) { char const init = utf8_data[utf8Cursor]; /* Initial byte of the UTF-8 sequence */ wchar_t wc; if ((init & 0x80) == 0x00) { /* Convert ASCII character to wide character. */ wc = init; ++utf8Cursor; } else { /* Look up the length of this UTF-8 sequence. */ size_t const length = utf8SeqLength[(unsigned char) init]; /* Special value 0 means no length could be determined because it is not a valid initial byte for a UTF-8 sequence. */ if (length == 0) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INVALID_UTF8_ERROR, "Unrecognized UTF-8 initial byte value 0x%02x", (unsigned char)init); else { /* Make sure we have enough bytes to convert. */ if (utf8Cursor + length > utf8_len) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_INVALID_UTF8_ERROR, "Invalid UTF-8 sequence indicates a %u-byte sequence " "when only %u bytes are left in the string", (unsigned)length, (unsigned)(utf8_len - utf8Cursor)); } else { decodeMultibyte(envP, &utf8_data[utf8Cursor], length, &wc); /* Advance to the end of the sequence. */ utf8Cursor += length; } } } if (!envP->fault_occurred) { /* If we have a buffer, write our character to it. */ if (ioBuff) ioBuff[outPos++] = wc; } } if (outBuffLenP) *outBuffLenP = envP->fault_occurred ? 0 : outPos; } xmlrpc_mem_block * xmlrpc_utf8_to_wcs(xmlrpc_env * const envP, const char * const utf8_data, size_t const utf8_len) { /*---------------------------------------------------------------------------- Decode UTF-8 string to a "wide character string". This function returns an xmlrpc_mem_block with an element type of wchar_t. Don't try to intepret the block in a bytewise fashion--it won't work in any useful or portable fashion. For backward compatibility, we return a meaningful value even when we fail. We return NULL when we fail. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * wcsP; size_t wcs_length; /* Allocate a memory block large enough to hold any possible output. We assume that each byte of the input may decode to a whcar_t. */ wcsP = XMLRPC_MEMBLOCK_NEW(wchar_t, envP, utf8_len); if (!envP->fault_occurred) { /* Decode the UTF-8 data. */ decodeUtf8(envP, utf8_data, utf8_len, XMLRPC_MEMBLOCK_CONTENTS(wchar_t, wcsP), &wcs_length); if (!envP->fault_occurred) { /* We can't have overrun our buffer. */ XMLRPC_ASSERT(wcs_length <= utf8_len); /* Correct the length of the memory block. */ XMLRPC_MEMBLOCK_RESIZE(wchar_t, envP, wcsP, wcs_length); } if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(wchar_t, wcsP); } if (envP->fault_occurred) return NULL; else return wcsP; } xmlrpc_mem_block * xmlrpc_wcs_to_utf8(xmlrpc_env * const envP, const wchar_t * const wcs_data, size_t const wcs_len) { /*---------------------------------------------------------------------------- Encode a "wide character string" as UTF-8. For backward compatibility, we return a meaningful value even when we fail. We return NULL when we fail. -----------------------------------------------------------------------------*/ size_t const estimate = wcs_len * MAX_ENCODED_BYTES; /* Our conservative estimate of how big the output will be; i.e. we know it won't be larger than this. For the estimate, we assume that every wchar might encode to the maximum length. */ xmlrpc_mem_block * utf8P; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(wcs_data); utf8P = XMLRPC_MEMBLOCK_NEW(char, envP, estimate); if (!envP->fault_occurred) { unsigned char * const buffer = XMLRPC_MEMBLOCK_CONTENTS(unsigned char, utf8P); size_t bytesUsed; size_t i; bytesUsed = 0; for (i = 0; i < wcs_len && !envP->fault_occurred; ++i) { wchar_t const wc = wcs_data[i]; if (wc <= 0x007F) buffer[bytesUsed++] = wc & 0x7F; else if (wc <= 0x07FF) { /* 110xxxxx 10xxxxxx */ buffer[bytesUsed++] = 0xC0 | (wc >> 6); buffer[bytesUsed++] = 0x80 | (wc & 0x3F); } else if (wc <= 0xFFFF) { /* 1110xxxx 10xxxxxx 10xxxxxx */ buffer[bytesUsed++] = 0xE0 | (wc >> 12); buffer[bytesUsed++] = 0x80 | ((wc >> 6) & 0x3F); buffer[bytesUsed++] = 0x80 | (wc & 0x3F); } else xmlrpc_faultf(envP, "Don't know how to encode UCS-4 characters yet"); } if (!envP->fault_occurred) { XMLRPC_ASSERT(bytesUsed <= estimate); XMLRPC_MEMBLOCK_RESIZE(char, envP, utf8P, bytesUsed); } if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, utf8P); } if (envP->fault_occurred) return NULL; else return utf8P; } #else /* HAVE_UNICODE_WCHAR */ xmlrpc_mem_block * xmlrpc_utf8_to_wcs(xmlrpc_env * const envP, const char * const utf8_data ATTR_UNUSED, size_t const utf8_len ATTR_UNUSED) { xmlrpc_faultf(envP, "INTERNAL ERROR: xmlrpc_utf8_to_wcs() called " "on a system that doesn't do Unicode!"); return NULL; } #endif /* HAVE_UNICODE_WCHAR */ void xmlrpc_force_to_utf8(char * const buffer) { /*---------------------------------------------------------------------------- Force the contents of 'buffer' to be valid UTF-8, any way possible. The buffer ends with a NUL character, and the mutation does not make it longer. The most common reason for a string that's supposed to be UTF-8 not to be UTF-8 is that it was supposed to be ASCII but instead includes garbage with the high bit on (ASCII characters always have the high bit off), or maybe a primitive 8-bit ASCII extension such as Latin1 (ISO 8859-1). Therefore, we force it to UTF-8 by replacing some bytes that have the high bit set with DEL (0x7F). That would leave the other characters meaningful. I've heard a standard way to do this is to substitute the Unicode character U+FFFD for the garbage. But that makes it harder to keep the length of the code the same, and in the case that the originator of these bits wasn't thinking UTF-8 at all, it does more violence to the string than our DEL method. -----------------------------------------------------------------------------*/ char * p; for (p = &buffer[0]; *p;) { unsigned int const length = utf8SeqLength[(unsigned char) *p]; bool forceDel; uint32_t decoded; forceDel = false; /* initial value */ switch (length) { case 1: /* One-byte UTF-8 characters are easy. */ decoded = *p; break; case 2: /* 110xxxxx 10xxxxxx */ if (!*(p+1) || !(*p+2)) forceDel = true; else if (!IS_CONTINUATION(*(p+1))) forceDel = true; else decoded = ((uint32_t)(*(p+0) & 0x1F) << 6) | ((uint32_t)(*(p+1) & 0x3F) << 0); break; case 3: /* 1110xxxx 10xxxxxx 10xxxxxx */ if (!*(p+1) || !(*p+2) || !(*p+3)) forceDel = true; else if (!IS_CONTINUATION(*(p+1)) || !IS_CONTINUATION(*(p+2))) forceDel = true; else decoded = ((uint32_t)(*(p+0) & 0x0F) << 12) | ((uint32_t)(*(p+1) & 0x3F) << 6) | ((uint32_t)(*(p+2) & 0x3F) << 0); break; default: forceDel = true; } if (!forceDel) { if (decoded > UCS2_MAX_LEGAL_CHARACTER) forceDel = true; else if (UTF16_FIRST_SURROGATE <= decoded && decoded <= UTF16_LAST_SURROGATE) forceDel = true; else if (decoded < utf8_min_char_for_length[length]) forceDel = true; } if (forceDel) { /* Not a valid UTF-8 character, so replace the first byte with a nice simple ASCII DEL. */ *p = 0x7F; p += 1; } else p += length; } } void xmlrpc_force_to_xml_chars(char * const buffer) { /*---------------------------------------------------------------------------- Modify 'buffer' so that it contains nothing but valid XML characters. The buffer ends with a NUL character, and the mutation does not make it longer. Note that the valid characters in an XML document are all Unicode codepoints except the ASCII control characters, plus CR, LF, and Tab. We change all non-XML characters to DEL (0x7F). Assume input is valid UTF-8. -----------------------------------------------------------------------------*/ char * p; for (p = &buffer[0]; *p;) { unsigned int const length = utf8SeqLength[(unsigned char) *p]; if (length == 1) { if (*p < 0x20 && *p != '\r' && *p != '\n' && *p != '\t') /* Not valid XML. Force to DEL */ *p = 0x7f; } else { /* We assume here that all other UTF-8 characters are valid XML, but it's apparently not actually true. */ } { unsigned int i; /* Advance to next UTF-8 character */ for (i = 0; i < length && *p; ++i) ++p; } } } void xmlrpc_validate_utf8(xmlrpc_env * const envP, const char * const utf8_data, size_t const utf8_len) { /*---------------------------------------------------------------------------- Validate that a string is valid UTF-8. -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_env_init(&env); #if HAVE_UNICODE_WCHAR decodeUtf8(&env, utf8_data, utf8_len, NULL, NULL); #else /* We don't have a convenient way to validate, so we just fake it and call it valid. */ #endif if (env.fault_occurred) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_INVALID_UTF8_ERROR, "%" XMLRPC_PRId64 "-byte " "supposed UTF-8 string is not valid UTF-8. %s", (XMLRPC_INT64)utf8_len, env.fault_string); } xmlrpc_env_clean(&env); } xmlrpc-c-1.33.14/lib/libwww_transport/000077500000000000000000000000001236133176700176165ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/libwww_transport/Makefile000066400000000000000000000022621236133176700212600ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') LIBDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/libwww_transport include $(BLDDIR)/config.mk default: all .PHONY: all all: xmlrpc_libwww_transport.o xmlrpc_libwww_transport.osh # Rules for the above dependencies are in common.mk, # courtesy of TARGET_MODS. TARGET_MODS = xmlrpc_libwww_transport OMIT_LIBWWW_TRANSPORT_RULE=Y include $(SRCDIR)/common.mk # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir LIBWWW_INCLUDES := $(shell libwww-config --cflags) INCLUDES = \ -I$(BLDDIR) \ -I$(BLDDIR)/include \ -Isrcdir/include \ -Isrcdir/lib/util/include \ $(LIBWWW_INCLUDES) .PHONY: clean clean: clean-common .PHONY: distclean distclean: clean distclean-common .PHONY: tags tags: TAGS .PHONY: distdir distdir: .PHONY: install install: .PHONY: dep dep: dep-common include depend.mk # Need this dependency for those who don't use depend.mk. # Without it, version.h doesn't get created. xmlrpc_libwww_transport.o xmlrpc_libwww_transport.osh: version.h xmlrpc-c-1.33.14/lib/libwww_transport/xmlrpc_libwww_transport.c000066400000000000000000001041511236133176700250000ustar00rootroot00000000000000/* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include "xmlrpc_config.h" #include #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/client_int.h" #include "xmlrpc-c/transport.h" /* The libwww interface */ /* These headers mistakenly define the macro PACKAGE. As xmlrpc_config.h already defines PACKAGE according to the package we're actually part of, this causes a conflict. So we undef here and then to avoid possible problems with an incorrect PACKAGE, we undef it again after. */ #undef PACKAGE #include "WWWLib.h" #include "WWWHTTP.h" #include "WWWInit.h" #undef PACKAGE /* Include our libwww SSL headers, if available. */ #if HAVE_LIBWWW_SSL #include "WWWSSL.h" #endif /* This value was discovered by Rick Blair. His efforts shaved two seconds ** off of every request processed. Many thanks. */ #define SMALLEST_LEGAL_LIBWWW_TIMEOUT (21) #define XMLRPC_CLIENT_USE_TIMEOUT (2) struct xmlrpc_client_transport { int saved_flags; HTList *xmlrpc_conversions; void * cookieJarP; /* This is a collection of all the cookies that servers have set via responses to prior requests. It's not implemented today. */ bool tracingOn; }; static struct xmlrpc_client_transport clientTransport; typedef struct { /*---------------------------------------------------------------------------- This object represents one RPC. -----------------------------------------------------------------------------*/ struct xmlrpc_client_transport * clientTransportP; /* These fields are used when performing synchronous calls. */ bool is_done; int http_status; /* Low-level information used by libwww. */ HTRequest * request; HTChunk * response_data; HTParentAnchor * source_anchor; HTAnchor * dest_anchor; xmlrpc_transport_asynch_complete complete; struct xmlrpc_call_info * callInfoP; } rpc; static void createCookieJar(xmlrpc_env * const envP ATTR_UNUSED, void ** const cookieJarP ATTR_UNUSED) { /* Cookies not implemented yet */ } static void destroyCookieJar(void * cookieJarP ATTR_UNUSED) { /* Cookies not implemented yet */ } static void initLibwww(const char * const appname, const char * const appversion) { /* We initialize the library using a robot profile, because we don't care about redirects or HTTP authentication, and we want to reduce our application footprint as much as possible. This takes the place of HTLibInit(). */ HTProfile_newRobot(appname, appversion); /* Ilya Goldberg provided the following code to access ** SSL-protected servers. */ #if HAVE_LIBWWW_SSL /* Set the SSL protocol method. By default, it is the highest ** available protocol. Setting it up to SSL_V23 allows the client ** to negotiate with the server and set up either TSLv1, SSLv3, ** or SSLv2 */ HTSSL_protMethod_set(HTSSL_V23); /* Set the certificate verification depth to 2 in order to be able to ** validate self-signed certificates */ HTSSL_verifyDepth_set(2); /* Register SSL stuff for handling ssl access. The parameter we pass ** is NO because we can't be pre-emptive with POST */ HTSSLhttps_init(NO); #endif /* HAVE_LIBWWW_SSL */ /* For interoperability with Frontier, we need to tell libwww *not* ** to send 'Expect: 100-continue' headers. But if we're not sending ** these, we shouldn't wait for them. So set our built-in delays to ** the smallest legal values. */ HTTP_setBodyWriteDelay (SMALLEST_LEGAL_LIBWWW_TIMEOUT, SMALLEST_LEGAL_LIBWWW_TIMEOUT); /* We attempt to disable all of libwww's chatty, interactive ** prompts. Let's hope this works. */ HTAlert_setInteractive(NO); /* Here are some alternate setup calls which will help greatly ** with debugging, should the need arise. ** ** HTProfile_newNoCacheClient(appname, appversion); ** HTAlert_setInteractive(YES); ** HTPrint_setCallback(printer); ** HTTrace_setCallback(tracer); */ } static void create(xmlrpc_env * const envP, int const flags, const char * const appname, const char * const appversion, const void * const transportParmsP ATTR_UNUSED, size_t const parm_size ATTR_UNUSED, struct xmlrpc_client_transport ** const handlePP) { /*---------------------------------------------------------------------------- This does the 'create' operation for a Libwww client transport. TODO: put 'appname' and 'appversion' in *transportParmsP and deprecate the create() arguments. Reason: these are particular to the Libwww transport. They're create() arguments because originally, Libwww was the only transport. -----------------------------------------------------------------------------*/ /* The Libwww transport is not re-entrant -- you can have only one per program instance. Even if we changed the Xmlrpc-c code not to use global variables, that wouldn't help because Libwww itself is not re-entrant. So we use a global variable ('clientTransport') for our transport state. */ struct xmlrpc_client_transport * const clientTransportP = &clientTransport; *handlePP = clientTransportP; clientTransportP->saved_flags = flags; createCookieJar(envP, &clientTransportP->cookieJarP); if (!envP->fault_occurred) { if (!(clientTransportP->saved_flags & XMLRPC_CLIENT_SKIP_LIBWWW_INIT)) initLibwww(appname, appversion); /* Set up our list of conversions for XML-RPC requests. This is a ** massively stripped-down version of the list in libwww's HTInit.c. ** XXX - This is hackish; 10.0 is an arbitrary, large quality factor ** designed to override the built-in converter for XML. */ clientTransportP->xmlrpc_conversions = HTList_new(); HTConversion_add(clientTransportP->xmlrpc_conversions, "text/xml", "*/*", HTThroughLine, 10.0, 0.0, 0.0); if (envP->fault_occurred) destroyCookieJar(clientTransportP->cookieJarP); } if (getenv("XMLRPC_LIBWWW_TRACE")) clientTransportP->tracingOn = TRUE; else clientTransportP->tracingOn = FALSE; } static void destroy(struct xmlrpc_client_transport * const clientTransportP) { /*---------------------------------------------------------------------------- This does the 'destroy' operation for a Libwww client transport. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT(clientTransportP != NULL); if (!(clientTransportP->saved_flags & XMLRPC_CLIENT_SKIP_LIBWWW_INIT)) { HTProfile_delete(); /* This takes the place of HTLibTerminate() */ } destroyCookieJar(clientTransportP->cookieJarP); HTConversion_deleteAll(clientTransportP->xmlrpc_conversions); HTProfile_delete(); } /*========================================================================= ** HTTP Error Reporting **=======================================================================*/ static void formatLibwwwError(HTRequest * const requestP, const char ** const msgP) { /*---------------------------------------------------------------------------- When something fails in a Libwww request, Libwww generates a stack of error information (precious little information, of course, in the Unix tradition) and attaches it to the request object. We make a message out of that information. We rely on Libwww's HTDialog_errorMessage() to do the bulk of the formatting; we might be able to coax more information out of the request if we interpreted the error stack directly. -----------------------------------------------------------------------------*/ HTList * const errStack = HTRequest_error(requestP); if (errStack == NULL) xmlrpc_asprintf(msgP, "Libwww supplied no error details"); else { /* Get an error message from libwww. The middle three parameters to HTDialog_errorMessage appear to be ignored. XXX - The documentation for this API is terrible, so we may be using it incorrectly. */ const char * const msg = HTDialog_errorMessage(requestP, HT_A_MESSAGE, HT_MSG_NULL, "An error occurred", errStack); if (msg == NULL) xmlrpc_asprintf(msgP, "Libwww supplied some error detail, " "but its HTDialog_errorMessage() subroutine " "mysteriously failed to interpret it for us."); else *msgP = msg; } } static void set_fault_from_http_request(xmlrpc_env * const envP, int const status, HTRequest * const requestP) { /*---------------------------------------------------------------------------- Assuming 'requestP' identifies a completed libwww HTTP request, set *envP according to its success/error status. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_PTR_OK(requestP); if (status == 200) { /* No error. Don't set one in *envP */ } else { const char * libwwwMsg; formatLibwwwError(requestP, &libwwwMsg); if (status == -1) xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "Unable to complete the HTTP request. %s", libwwwMsg); else { xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "HTTP request completed with HTTp error %d. %s", status, libwwwMsg); } xmlrpc_strfree(libwwwMsg); } } static BOOL setCookie(HTRequest * const request, HTCookie * const cookieP ATTR_UNUSED, void * const param ATTR_UNUSED) { /*---------------------------------------------------------------------------- This is the callback from libwww to tell us the server (according to its response) wants us to store a cookie (and include it in future requests). We assume that the cookies "domain" is the server's host name (there are options on the libwww connection to make libwww call this callback only when that's the case). -----------------------------------------------------------------------------*/ rpc * const rpcP = HTRequest_context(request); struct xmlrpc_client_transport * const clientTransportP = rpcP->clientTransportP; BOOL retval; /* Avoid unused variable warning */ if (clientTransportP->cookieJarP == clientTransportP->cookieJarP) {} /* Cookies are not implemented today */ retval = NO; return retval; } static HTAssocList * cookiesForHost(const char * const host ATTR_UNUSED, void * const cookieJarP ATTR_UNUSED) { /*---------------------------------------------------------------------------- Find and return all the cookies in jar 'cookieJarP' that are for the host 'host'. -----------------------------------------------------------------------------*/ HTAssocList * hisCookiesP; hisCookiesP = HTAssocList_new(); if (hisCookiesP) { /* Cookies are not implemented yet */ /* Library/Examples/cookie.c in the w3c-libwww source tree contains an example of constructing the cookie list we are supposed to return. But today, we return an empty list. */ } return hisCookiesP; } static HTAssocList * findCookie(HTRequest * const request, void * const param ATTR_UNUSED) { /*---------------------------------------------------------------------------- This is the callback from libwww to get the cookies to include in a request (presumably values the server set via a prior response). -----------------------------------------------------------------------------*/ rpc * const rpcP = HTRequest_context(request); struct xmlrpc_client_transport * const clientTransportP = rpcP->clientTransportP; const char * const addr = HTAnchor_address((HTAnchor *) HTRequest_anchor(request)); const char * const host = HTParse(addr, "", PARSE_HOST); return cookiesForHost(host, clientTransportP->cookieJarP); } static void deleteSourceAnchor(HTParentAnchor * const anchor) { /* We need to clear the document first, or else libwww won't ** really delete the anchor. */ HTAnchor_setDocument(anchor, NULL); /* XXX - Deleting this anchor causes HTLibTerminate to dump core. */ /* HTAnchor_delete(anchor); */ } static void createSourceAnchor(xmlrpc_env * const envP, HTParentAnchor ** const sourceAnchorPP, xmlrpc_mem_block * const xmlP) { HTParentAnchor * const sourceAnchorP = HTTmpAnchor(NULL); if (sourceAnchorP == NULL) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR, "Unable to build source anchor. HTTmpAnchor() failed."); else { HTAnchor_setDocument(sourceAnchorP, XMLRPC_MEMBLOCK_CONTENTS(char, xmlP)); HTAnchor_setFormat(sourceAnchorP, HTAtom_for("text/xml")); HTAnchor_setLength(sourceAnchorP, XMLRPC_MEMBLOCK_SIZE(char, xmlP)); *sourceAnchorPP = sourceAnchorP; } } static void createDestAnchor(xmlrpc_env * const envP, HTAnchor ** const destAnchorPP, const xmlrpc_server_info * const serverP) { *destAnchorPP = HTAnchor_findAddress(serverP->serverUrl); if (*destAnchorPP == NULL) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR, "Could not build destination anchor. HTAnchor_findAddress() " "failed."); } static void rpcCreate(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const xmlP, xmlrpc_transport_asynch_complete complete, struct xmlrpc_call_info * const callInfoP, rpc ** const rpcPP) { rpc *rpcP; HTRqHd request_headers; HTStream *target_stream; /* Allocate our structure. */ MALLOCVAR(rpcP); XMLRPC_FAIL_IF_NULL(rpcP, envP, XMLRPC_INTERNAL_ERROR, "Out of memory in rpcCreate()"); /* Set up our basic members. */ rpcP->clientTransportP = clientTransportP; rpcP->is_done = FALSE; rpcP->http_status = 0; rpcP->complete = complete; rpcP->callInfoP = callInfoP; /* Start cookie handler. */ HTCookie_init(); HTCookie_setCallbacks(setCookie, NULL, findCookie, NULL); HTCookie_setCookieMode(HT_COOKIE_ACCEPT | HT_COOKIE_SEND | HT_COOKIE_SAME_HOST); /* Cookies aren't implemented today; reset. */ HTCookie_setCookieMode(0); /* Create a HTRequest object. */ rpcP->request = HTRequest_new(); XMLRPC_FAIL_IF_NULL(rpcP, envP, XMLRPC_INTERNAL_ERROR, "HTRequest_new failed"); /* Install ourselves as the request context. */ HTRequest_setContext(rpcP->request, rpcP); /* XXX - Disable the 'Expect:' header so we can talk to Frontier. */ request_headers = HTRequest_rqHd(rpcP->request); request_headers = request_headers & ~HT_C_EXPECT; HTRequest_setRqHd(rpcP->request, request_headers); /* Send an authorization header if we need one. */ if (serverP->allowedAuth.basic) HTRequest_addCredentials(rpcP->request, "Authorization", (char *)serverP->basicAuthHdrValue); /* Make sure there is no XML conversion handler to steal our data. ** The 'override' parameter is currently ignored by libwww, so our ** list of conversions must be designed to co-exist with the built-in ** conversions. */ HTRequest_setConversion(rpcP->request, clientTransportP->xmlrpc_conversions, NO); /* Set up our response buffer. */ target_stream = HTStreamToChunk(rpcP->request, &rpcP->response_data, 0); XMLRPC_FAIL_IF_NULL(rpcP->response_data, envP, XMLRPC_INTERNAL_ERROR, "HTStreamToChunk failed"); XMLRPC_ASSERT(target_stream != NULL); HTRequest_setOutputStream(rpcP->request, target_stream); HTRequest_setOutputFormat(rpcP->request, WWW_SOURCE); createSourceAnchor(envP, &rpcP->source_anchor, xmlP); if (!envP->fault_occurred) { createDestAnchor(envP, &rpcP->dest_anchor, serverP); if (envP->fault_occurred) /* See below for comments about deleting the source and dest ** anchors. This is a bit of a black art. */ deleteSourceAnchor(rpcP->source_anchor); } cleanup: if (envP->fault_occurred) { if (rpcP) { if (rpcP->request) HTRequest_delete(rpcP->request); if (rpcP->response_data) HTChunk_delete(rpcP->response_data); free(rpcP); } } *rpcPP = rpcP; } static void rpcDestroy(rpc * const rpcP) { XMLRPC_ASSERT_PTR_OK(rpcP); XMLRPC_ASSERT(rpcP->request != NULL); XMLRPC_ASSERT(rpcP->response_data != NULL); /* Junji Kanemaru reports on 05.04.11 that with asynch calls, he get a segfault, and reversing the order of deleting the request and the response chunk buffer cured it. But we find no reason that should be so, so we're waiting for someone to arrive at an explanation before changing anything. HTRequest_delete() does destroy the output stream, and the output stream refers to the response chunk, but HTRequest_delete() explicitly refrains from destroying the response chunk. And the response chunk does not refer to the request. */ HTRequest_delete(rpcP->request); rpcP->request = NULL; HTChunk_delete(rpcP->response_data); rpcP->response_data = NULL; /* This anchor points to private data, so we're allowed to delete it. */ deleteSourceAnchor(rpcP->source_anchor); /* WARNING: We can't delete the destination anchor, because this points ** to something in the outside world, and lives in a libwww hash table. ** Under certain circumstances, this anchor may have been reissued to ** somebody else. So over time, the anchor cache will grow. If this ** is a problem for your application, read the documentation for ** HTAnchor_deleteAll. ** ** However, we CAN check to make sure that no documents have been ** attached to the anchor. This assertion may fail if you're using ** libwww for something else, so please feel free to comment it out. */ /* XMLRPC_ASSERT(HTAnchor_document(rpcP->dest_anchor) == NULL); */ HTCookie_deleteCallbacks(); HTCookie_terminate(); free(rpcP); } static void extract_response_chunk(xmlrpc_env * const envP, rpc * const rpcP, xmlrpc_mem_block ** const responseXmlPP) { /* Implementation warning: A Libwww chunk has nothing to do with an HTTP chunk. HTTP chunks (as in a chunked response) are not visible to us; Libwww delivers the entire unchunked body to us at once (we never see chunk headers and trailers). This subroutine is about a Libwww chunk, which is just a memory buffer. (Libwww is capable of delivering the response in a number of ways other than a chunk, e.g. it can write it to a file. */ /* Check to make sure that w3c-libwww actually sent us some data. ** XXX - This may happen if libwww is shut down prematurely, believe it ** or not--we'll get a 200 OK and no data. Gag me with a bogus design ** decision. This may also fail if some naughty libwww converter ** ate our data unexpectedly. */ if (!HTChunk_data(rpcP->response_data)) xmlrpc_env_set_fault(envP, XMLRPC_NETWORK_ERROR, "w3c-libwww returned no data"); else { *responseXmlPP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); if (!envP->fault_occurred) { if (rpcP->clientTransportP->tracingOn) { fprintf(stderr, "HTTP chunk received: %u bytes: '%.*s'", HTChunk_size(rpcP->response_data), HTChunk_size(rpcP->response_data), HTChunk_data(rpcP->response_data)); } XMLRPC_MEMBLOCK_APPEND(char, envP, *responseXmlPP, HTChunk_data(rpcP->response_data), HTChunk_size(rpcP->response_data)); if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, *responseXmlPP); } } } static int synch_terminate_handler(HTRequest * const request, HTResponse * const response ATTR_UNUSED, void * const param ATTR_UNUSED, int const status) { /*---------------------------------------------------------------------------- This is a libwww request completion handler. HTEventList_newLoop() calls this when it completes a request (with this registered as the completion handler). -----------------------------------------------------------------------------*/ rpc *rpcP; rpcP = HTRequest_context(request); rpcP->is_done = TRUE; rpcP->http_status = status; HTEventList_stopLoop(); return HT_OK; } static void call(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const xmlP, xmlrpc_mem_block ** const responsePP) { /*---------------------------------------------------------------------------- This does the 'call' operation for a Libwww client transport. -----------------------------------------------------------------------------*/ rpc * rpcP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(serverP); XMLRPC_ASSERT_PTR_OK(xmlP); XMLRPC_ASSERT_PTR_OK(responsePP); rpcCreate(envP, clientTransportP, serverP, xmlP, NULL, NULL, &rpcP); if (!envP->fault_occurred) { int ok; /* Install our request handler. */ HTRequest_addAfter(rpcP->request, &synch_terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST, NO); /* Start our request running. */ ok = HTPostAnchor(rpcP->source_anchor, rpcP->dest_anchor, rpcP->request); if (!ok) xmlrpc_env_set_fault( envP, XMLRPC_NETWORK_ERROR, "Libwww HTPostAnchor() failed to start POST request"); else { /* Run our event-processing loop. HTEventList_newLoop() is what calls synch_terminate_handler(), by virtue of it being registered as a handler. It may return for other reasons than the request being complete, though. so we call it in a loop until synch_terminate_handler() really has been called. */ while (!rpcP->is_done) HTEventList_newLoop(); /* Fail if we didn't get a "200 OK" response from the server */ if (rpcP->http_status != 200) set_fault_from_http_request( envP, rpcP->http_status, rpcP->request); else { /* XXX - Check to make sure response type is text/xml here. */ extract_response_chunk(envP, rpcP, responsePP); } } rpcDestroy(rpcP); } } /*========================================================================= ** Event Loop **========================================================================= ** We manage a fair bit of internal state about our event loop. This is ** needed to determine when (and if) we should exit the loop. */ static int outstanding_asynch_calls = 0; static int event_loop_flags = 0; static int timer_called = 0; static void register_asynch_call(void) { XMLRPC_ASSERT(outstanding_asynch_calls >= 0); ++outstanding_asynch_calls; } static void unregister_asynch_call(void) { XMLRPC_ASSERT(outstanding_asynch_calls > 0); --outstanding_asynch_calls; if (outstanding_asynch_calls == 0) HTEventList_stopLoop(); } static int timer_callback(HTTimer * const timer ATTR_UNUSED, void * const user_data ATTR_UNUSED, HTEventType const event ATTR_UNUSED) { /*---------------------------------------------------------------------------- A handy timer callback which cancels the running event loop. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT(event == HTEvent_TIMEOUT); timer_called = 1; HTEventList_stopLoop(); /* XXX - The meaning of this return value is undocumented, but close ** inspection of libwww's source suggests that we want to return HT_OK. */ return HT_OK; } static void eventLoopRun(int const flags, xmlrpc_timeout const milliseconds) { /*---------------------------------------------------------------------------- Process all responses from outstanding requests as they come in. Return when there are no more outstanding responses. Or, if 'flags' has the XMLRPC_CLIENT_USE_TIMEOUT flag set, return when 'milliseconds' milliseconds have elapsed, regardless of whether there are still outstanding responses. The processing we do consists of telling libwww to process the completion of the libwww request. That normally includes calling the xmlrpc_libwww_transport request termination handler, because the submitter of the libwww request would have registered that as a callback. -----------------------------------------------------------------------------*/ if (outstanding_asynch_calls > 0) { HTTimer *timer; event_loop_flags = flags; /* Run an appropriate event loop. The HTEeventList_newLoop() is what calls asynch_terminate_handler(), by virtue of it being registered as a handler. */ if (event_loop_flags & XMLRPC_CLIENT_USE_TIMEOUT) { /* Run our event loop with a timer. Note that we need to be very ** careful about race conditions--timers can be fired in either ** HTimer_new or HTEventList_newLoop. And if our callback were to ** get called before we entered the loop, we would never exit. ** So we use a private flag of our own--we can't even rely on ** HTTimer_hasTimerExpired, because that only checks the time, ** not whether our callback has been run. Yuck. */ timer_called = 0; timer = HTTimer_new(NULL, &timer_callback, NULL, milliseconds, YES, NO); XMLRPC_ASSERT(timer != NULL); if (!timer_called) HTEventList_newLoop(); HTTimer_delete(timer); } else { /* Run our event loop without a timer. */ HTEventList_newLoop(); } /* Reset our flags, so we don't interfere with direct calls to the ** libwww event loop functions. */ event_loop_flags = 0; } else { /* There are *no* calls to process. This may mean that none of the asynch calls were ever set up, and the client's callbacks have already been called with an error, or that all outstanding calls were completed during a previous synchronous call. */ } } static void finishAsynch( struct xmlrpc_client_transport * const clientTransportP ATTR_UNUSED, xmlrpc_timeoutType const timeoutType, xmlrpc_timeout const timeout) { /*---------------------------------------------------------------------------- This does the 'finish_asynch' operation for a Libwww client transport. -----------------------------------------------------------------------------*/ eventLoopRun(timeoutType == timeout_yes ? XMLRPC_CLIENT_USE_TIMEOUT : 0, timeout); } static int asynch_terminate_handler(HTRequest * const request, HTResponse * const response ATTR_UNUSED, void * const param ATTR_UNUSED, int const status) { /*---------------------------------------------------------------------------- Handle the completion of a libwww request. This is the bottom half of the xmlrpc_libwww_transport asynchronous call dispatcher. It's what the dispatcher registers with libwww as a "local after filter" so that libwww calls it when a request that xmlrpc_libwww_transport submitted to it is complete. We destroy the RPC, including the request which is our argument. Strange as that may seem, it is apparently legal for an after filter to destroy the request that was passed to it -- or not. -----------------------------------------------------------------------------*/ xmlrpc_env env; rpc * rpcP; xmlrpc_mem_block * responseXmlP; XMLRPC_ASSERT_PTR_OK(request); xmlrpc_env_init(&env); rpcP = HTRequest_context(request); /* Unregister this call from the event loop. Among other things, this ** may decide to stop the event loop. **/ unregister_asynch_call(); /* Give up if an error occurred. */ if (status != 200) set_fault_from_http_request(&env, status, request); else { /* XXX - Check to make sure response type is text/xml here. */ extract_response_chunk(&env, rpcP, &responseXmlP); } rpcP->complete(rpcP->callInfoP, responseXmlP, env); if (!env.fault_occurred) XMLRPC_MEMBLOCK_FREE(char, responseXmlP); rpcDestroy(rpcP); xmlrpc_env_clean(&env); return HT_OK; } static void sendRequest(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const xmlP, xmlrpc_transport_asynch_complete complete, xmlrpc_transport_progress progress ATTR_UNUSED, struct xmlrpc_call_info * const callInfoP) { /*---------------------------------------------------------------------------- Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to the server. Unless we return failure, we arrange to have complete() called when the rpc completes. This does the 'send_request' operation for a Libwww client transport. -----------------------------------------------------------------------------*/ rpc * rpcP; XMLRPC_ASSERT_PTR_OK(envP); XMLRPC_ASSERT_PTR_OK(serverP); XMLRPC_ASSERT_PTR_OK(xmlP); XMLRPC_ASSERT_PTR_OK(callInfoP); rpcCreate(envP, clientTransportP, serverP, xmlP, complete, callInfoP, &rpcP); if (!envP->fault_occurred) { int ok; /* Install our request handler. */ HTRequest_addAfter(rpcP->request, &asynch_terminate_handler, NULL, NULL, HT_ALL, HT_FILTER_LAST, NO); /* Register our asynchronous call with the event loop. This means the user's callback is guaranteed to be called eventually. */ register_asynch_call(); /* This makes the TCP connection and sends the XML to the server as an HTTP POST request. There was a comment here that said this might return failure (!ok) and still invoke our completion handler (asynch_terminate_handler(). The code attempted to deal with that. Well, it's impossible to deal with that, so if it really happens, we must fix Libwww. -Bryan 04.11.23. */ ok = HTPostAnchor(rpcP->source_anchor, rpcP->dest_anchor, rpcP->request); if (!ok) { unregister_asynch_call(); xmlrpc_env_set_fault(envP, XMLRPC_NETWORK_ERROR, "Libwww (HTPostAnchor()) failed to start the " "POST request."); } if (envP->fault_occurred) rpcDestroy(rpcP); } } struct xmlrpc_client_transport_ops xmlrpc_libwww_transport_ops = { NULL, NULL, &create, &destroy, &sendRequest, &call, &finishAsynch, NULL, }; xmlrpc-c-1.33.14/lib/util/000077500000000000000000000000001236133176700151445ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/util/Makefile000066400000000000000000000036771236133176700166210ustar00rootroot00000000000000############################################################################### # This directory builds object modules that provide utility functions that # programs can use. Not libraries, though -- just programs. The reason # we don't want any library to use object modules in here is that they'll # probably pollute the name space when users link those libraries to their # programs. In fact, if more than one Xmlrpc-c library included one of these # modules, the libraries would conflict with each other. # # So a utility function that is to be used by libraries (and, optionally, # programs) should go in libxmlrpc_util. libxmlrpc_util is a prerequisite # for many Xmlrpc-c libraries, gets included in a program link only once, # and uses external symbol names that have the "xmlrpc_" prefix to avoid # collision with users' code. # # If we knew a portable way to link multiple object modules into one and # restrict the symbols exported by the whole, we could avoid this mess and # just link utility object modules into each Xmlrpc-c library. ############################################################################## ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') LIBDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/util default: all include $(BLDDIR)/config.mk OMIT_UTILS_RULE = Y include $(SRCDIR)/common.mk # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir LIBOBJS = \ casprintf.o \ cmdline_parser.o \ cmdline_parser_cpp.o \ getoptx.o \ string_parser.o \ stripcaseeq.o \ .PHONY: all all: $(LIBOBJS) INCLUDES = -Isrcdir/$(SUBDIR)/include -I$(BLDDIR) %.o:%.c $(CC) -c $(CFLAGS_ALL) $< %.o:%.cpp $(CXX) -c $(CXXFLAGS_ALL) $< include depend.mk .PHONY: clean distclean clean: clean-common distclean: clean distclean-common .PHONY: dep dep: dep-common install:xmlrpc-c-1.33.14/lib/util/casprintf.c000066400000000000000000000072231236133176700173050ustar00rootroot00000000000000#define _GNU_SOURCE /* But only when HAVE_ASPRINTF */ #include #include #include #include #include "xmlrpc_config.h" /* For HAVE_ASPRINTF, __inline__ */ #include "bool.h" #include "casprintf.h" static __inline__ void newVsnprintf(char * const buffer, size_t const bufferSize, const char * const fmt, va_list varargs, size_t * const formattedSizeP) { /*---------------------------------------------------------------------------- This is vsnprintf() with the new behavior, where not fitting in the buffer is not a failure. Unfortunately, we can't practically return the size of the formatted string if the C library has old vsnprintf() and the formatted string doesn't fit in the buffer, so in that case we just return something larger than the buffer. -----------------------------------------------------------------------------*/ if (bufferSize > INT_MAX/2) { /* There's a danger we won't be able to coerce the return value of XMLRPC_VSNPRINTF to an integer (which we have to do because, while for POSIX its return value is ssize_t, on Windows it is int), or return double the buffer size. */ *formattedSizeP = 0; } else { int rc; rc = XMLRPC_VSNPRINTF(buffer, bufferSize, fmt, varargs); if (rc < 0) { /* We have old vsnprintf() (or Windows) and the formatted value doesn't fit in the buffer, but we don't know how big a buffer it needs. */ *formattedSizeP = bufferSize * 2; } else { /* Either the string fits in the buffer or we have new vsnprintf() which tells us how big the string is regardless. */ *formattedSizeP = rc; } } } static __inline__ void simpleVasprintf(char ** const retvalP, const char * const fmt, va_list varargs) { /*---------------------------------------------------------------------------- This is a poor man's implementation of vasprintf(), of GNU fame. -----------------------------------------------------------------------------*/ char * result; size_t bufferSize; bool outOfMemory; for (result = NULL, bufferSize = 4096, outOfMemory = false; !result && !outOfMemory; ) { result = malloc(bufferSize); if (!result) outOfMemory = true; else { size_t bytesNeeded; newVsnprintf(result, bufferSize, fmt, varargs, &bytesNeeded); if (bytesNeeded > bufferSize) { free(result); result = NULL; bufferSize = bytesNeeded; } } } *retvalP = result; } const char * const strsol = "[Insufficient memory to build string]"; void cvasprintf(const char ** const retvalP, const char * const fmt, va_list varargs) { char * string; #if HAVE_ASPRINTF vasprintf(&string, fmt, varargs); #else simpleVasprintf(&string, fmt, varargs); #endif if (string == NULL) *retvalP = strsol; else *retvalP = string; } void GNU_PRINTF_ATTR(2,3) casprintf(const char ** const retvalP, const char * const fmt, ...) { va_list varargs; /* mysterious structure used by variable arg facility */ va_start(varargs, fmt); /* start up the mysterious variable arg facility */ cvasprintf(retvalP, fmt, varargs); va_end(varargs); } void strfree(const char * const string) { if (string != strsol) free((void *)string); } xmlrpc-c-1.33.14/lib/util/cmdline_parser.c000066400000000000000000000366301236133176700203070ustar00rootroot00000000000000#define _XOPEN_SOURCE 600 /* Make sure has strdup() */ #include "xmlrpc_config.h" /* prereq for mallocvar.h -- defines __inline__ */ #include #include #include #include #include #include "bool.h" #include "int.h" #include "mallocvar.h" #include "casprintf.h" #include "getoptx.h" #include "string_parser.h" #include "cmdline_parser.h" #define MAXOPTS 100 struct optionDesc { const char * name; enum optiontype type; bool present; union { unsigned int u; int i; const char * s; uint64_t llu; double d; } value; }; struct cmdlineParserCtl { struct optionDesc * optionDescArray; unsigned int numOptions; const char ** argumentArray; unsigned int numArguments; }; static struct optionx * createLongOptsArray(struct optionDesc * const optionDescArray, unsigned int const numOptions) { struct optionx * longopts; MALLOCARRAY(longopts, numOptions+1); if (longopts != NULL) { unsigned int i; for (i = 0; i < numOptions; ++i) { longopts[i].name = optionDescArray[i].name; /* If the option takes a value, we say it is optional even though it never is. That's because if we say it is mandatory, getopt_long_only() pretends it doesn't even recognize the option if the user doesn't give a value. We prefer to generate a meaningful error message when the user omits a required option value. */ longopts[i].has_arg = optionDescArray[i].type == OPTTYPE_FLAG ? no_argument : optional_argument; longopts[i].flag = NULL; longopts[i].val = i; } longopts[numOptions].name = 0; longopts[numOptions].has_arg = 0; longopts[numOptions].flag = 0; longopts[numOptions].val = 0; } return longopts; } static void parseInt(enum optiontype const type, const char * const optarg, unsigned int * const valueUintP, int * const valueIntP, const char ** const errorP) { if (optarg == NULL) casprintf(errorP, "Option requires a value"); else if (strlen(optarg) == 0) casprintf(errorP, "Numeric option value is null string"); else { char * tailptr; long const longvalue = strtol(optarg, &tailptr, 10); if (*tailptr != '\0') casprintf(errorP, "Non-numeric value " "for numeric option value: '%s'", optarg); else if (errno == ERANGE || longvalue > INT_MAX) casprintf(errorP, "Numeric value out of range: %s", optarg); else { if (type == OPTTYPE_UINT) { if (longvalue < 0) casprintf(errorP, "Unsigned numeric value is " "negative: %ld", longvalue); else { *errorP = NULL; *valueUintP = (unsigned int) longvalue; } } else { *errorP = NULL; *valueIntP = (int) longvalue; } } } } static void parseBinUint(const char * const optarg, uint64_t * const valueP, const char ** const errorP) { if (optarg == NULL) casprintf(errorP, "Option requires a value"); else if (strlen(optarg) == 0) casprintf(errorP, "Numeric option value is null string"); else { const char * error; interpretBinUint(optarg, valueP, &error); if (error) { casprintf(errorP, "Invalid numeric option value '%s'. %s", optarg, error); strfree(error); } } } static void parseFloat(const char * const optarg, double * const valueP, const char ** const errorP) { if (optarg == NULL) casprintf(errorP, "Option requires a value"); else if (strlen(optarg) == 0) casprintf(errorP, "Numeric option value is null string"); else { char * tailptr; double const doublevalue = strtod(optarg, &tailptr); if (*tailptr != '\0') casprintf(errorP, "Non-numeric value " "for numeric option value: '%s'", optarg); else if (errno == ERANGE) casprintf(errorP, "Numeric value out of range: %s", optarg); else { *errorP = NULL; *valueP = doublevalue; } } } static void parseOptionValue(const char * const optarg, struct optionDesc * const optionP, const char ** const errorP) { switch (optionP->type) { case OPTTYPE_FLAG: *errorP = NULL; break; case OPTTYPE_INT: case OPTTYPE_UINT: parseInt(optionP->type, optarg, &optionP->value.u, &optionP->value.i, errorP); break; case OPTTYPE_STRING: if (optarg == NULL) casprintf(errorP, "Option requires a value"); else { *errorP = NULL; optionP->value.s = strdup(optarg); } break; case OPTTYPE_BINUINT: parseBinUint(optarg, &optionP->value.llu, errorP); break; case OPTTYPE_FLOAT: parseFloat(optarg, &optionP->value.d, errorP); break; } } static void processOption(struct optionDesc * const optionP, const char * const optarg, const char ** const errorP) { const char * error; parseOptionValue(optarg, optionP, &error); if (error) casprintf(errorP, "Error in '%s' option: %s", optionP->name, error); else optionP->present = true; } static void extractArguments(struct cmdlineParserCtl * const cpP, unsigned int const argc, const char ** const argv) { cpP->numArguments = argc - getopt_argstart(); MALLOCARRAY(cpP->argumentArray, cpP->numArguments); if (cpP->argumentArray == NULL) { fprintf(stderr, "Unable to allocate memory for argument array " "(%u arguments)\n", cpP->numArguments); abort(); } else { unsigned int i; for (i = 0; i < cpP->numArguments; ++i) { cpP->argumentArray[i] = strdup(argv[getopt_argstart() + i]); if (cpP->argumentArray[i] == NULL) { fprintf(stderr, "Unable to allocate memory for Argument %u\n", i); abort(); } } } } void cmd_processOptions(cmdlineParser const cpP, int const argc, const char ** const argv, const char ** const errorP) { struct optionx * longopts; longopts = createLongOptsArray(cpP->optionDescArray, cpP->numOptions); if (longopts == NULL) casprintf(errorP, "Unable to get memory for longopts array"); else { int endOfOptions; unsigned int i; *errorP = NULL; /* Set up initial assumption: No options present */ for (i = 0; i < cpP->numOptions; ++i) cpP->optionDescArray[i].present = false; endOfOptions = false; /* initial value */ while (!endOfOptions && !*errorP) { int const opterr0 = 0; /* Don't let getopt_long_only() print an error message */ unsigned int longoptsIndex; const char * unrecognizedOption; const char * optarg; getopt_long_onlyx(argc, (char**) argv, "", longopts, &longoptsIndex, opterr0, &endOfOptions, &optarg, &unrecognizedOption); if (unrecognizedOption) casprintf(errorP, "Unrecognized option: '%s'", unrecognizedOption); else { if (!endOfOptions) processOption(&cpP->optionDescArray[longoptsIndex], optarg, errorP); } } if (!*errorP) extractArguments(cpP, argc, argv); free(longopts); } } cmdlineParser cmd_createOptionParser(void) { struct cmdlineParserCtl * cpP; MALLOCVAR(cpP); if (cpP != NULL) { struct optionDesc * optionDescArray; cpP->numOptions = 0; MALLOCARRAY(optionDescArray, MAXOPTS); if (optionDescArray == NULL) { free(cpP); cpP = NULL; } else cpP->optionDescArray = optionDescArray; } return cpP; } void cmd_destroyOptionParser(cmdlineParser const cpP) { unsigned int i; for (i = 0; i < cpP->numOptions; ++i) { struct optionDesc const option = cpP->optionDescArray[i]; if (option.type == OPTTYPE_STRING && option.present) strfree(option.value.s); strfree(option.name); } for (i = 0; i < cpP->numArguments; ++i) strfree(cpP->argumentArray[i]); free(cpP->optionDescArray); free(cpP); } void cmd_defineOption(cmdlineParser const cpP, const char * const name, enum optiontype const type) { if (cpP->numOptions < MAXOPTS) { cpP->optionDescArray[cpP->numOptions].name = strdup(name); cpP->optionDescArray[cpP->numOptions].type = type; ++cpP->numOptions; } } static struct optionDesc * findOptionDesc(struct cmdlineParserCtl * const cpP, const char * const name) { struct optionDesc * retval; unsigned int i; retval = NULL; for (i = 0; i < cpP->numOptions && !retval; ++i) if (strcmp(cpP->optionDescArray[i].name, name) == 0) retval = &cpP->optionDescArray[i]; return retval; } int cmd_optionIsPresent(cmdlineParser const cpP, const char * const name) { struct optionDesc * const optionDescP = findOptionDesc(cpP, name); bool present; if (!optionDescP) { fprintf(stderr, "cmdlineParser called incorrectly. " "optionIsPresent() called for undefined option '%s'\n", name); abort(); } else present = optionDescP->present; return present; } unsigned int cmd_getOptionValueUint(cmdlineParser const cpP, const char * const name) { struct optionDesc * const optionDescP = findOptionDesc(cpP, name); unsigned int retval; if (!optionDescP) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueUint() called for undefined option '%s'\n", name); abort(); } else { if (optionDescP->type != OPTTYPE_UINT) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueUint() called for non-unsigned integer " "option '%s'\n", optionDescP->name); abort(); } else { if (optionDescP->present) retval = optionDescP->value.u; else retval = 0; } } return retval; } int cmd_getOptionValueInt(cmdlineParser const cpP, const char * const name) { struct optionDesc * const optionDescP = findOptionDesc(cpP, name); int retval; if (!optionDescP) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueInt() called for undefined option '%s'\n", name); abort(); } else { if (optionDescP->type != OPTTYPE_INT) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueInt() called for non-integer " "option '%s'\n", optionDescP->name); abort(); } else { if (optionDescP->present) retval = optionDescP->value.i; else retval = 0; } } return retval; } const char * cmd_getOptionValueString(cmdlineParser const cpP, const char * const name) { struct optionDesc * const optionDescP = findOptionDesc(cpP, name); const char * retval; if (!optionDescP) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueString() called for " "undefined option '%s'\n", name); abort(); } else { if (optionDescP->type != OPTTYPE_STRING) { fprintf(stderr, "cmdlineParser called incorrectly. " "getOptionValueString() called for non-string " "option '%s'\n", optionDescP->name); abort(); } else { if (optionDescP->present) { retval = strdup(optionDescP->value.s); if (retval == NULL) { fprintf(stderr, "out of memory in cmd_getOptionValueString()\n"); abort(); } } else retval = NULL; } } return retval; } uint64_t cmd_getOptionValueBinUint(cmdlineParser const cpP, const char * const name) { struct optionDesc * const optionDescP = findOptionDesc(cpP, name); uint64_t retval; if (!optionDescP) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueUint() called for undefined option '%s'\n", name); abort(); } else { if (optionDescP->type != OPTTYPE_BINUINT) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueBinUint() called for " "non-OPTTYPE_BINUINT " "option '%s'\n", optionDescP->name); abort(); } else { if (optionDescP->present) retval = optionDescP->value.llu; else retval = 0; } } return retval; } double cmd_getOptionValueFloat(cmdlineParser const cpP, const char * const name) { struct optionDesc * const optionDescP = findOptionDesc(cpP, name); double retval; if (!optionDescP) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueInt() called for undefined option '%s'\n", name); abort(); } else { if (optionDescP->type != OPTTYPE_FLOAT) { fprintf(stderr, "cmdlineParser called incorrectly. " "cmd_getOptionValueInt() called for non-float " "option '%s'\n", optionDescP->name); abort(); } else { if (optionDescP->present) retval = optionDescP->value.d; else retval = 0.0; } } return retval; } unsigned int cmd_argumentCount(cmdlineParser const cpP) { return cpP->numArguments; } const char * cmd_getArgument(cmdlineParser const cpP, unsigned int const argNumber) { const char * retval; if (argNumber >= cpP->numArguments) retval = NULL; else { retval = strdup(cpP->argumentArray[argNumber]); if (retval == NULL) { fprintf(stderr, "out of memory in cmd_getArgument()\n"); abort(); } } return retval; } xmlrpc-c-1.33.14/lib/util/cmdline_parser_cpp.cpp000066400000000000000000000055001236133176700215010ustar00rootroot00000000000000#include #include #include "girstring.h" #include "casprintf.h" #include "cmdline_parser.h" #include "cmdline_parser.hpp" using namespace std; static enum optiontype optTypeConvert( CmdlineParser::optType const arg) { enum optiontype retval; retval = OPTTYPE_FLAG; // defeat compiler warning switch (arg) { case CmdlineParser::FLAG: retval = OPTTYPE_FLAG; break; case CmdlineParser::INT: retval = OPTTYPE_INT; break; case CmdlineParser::UINT: retval = OPTTYPE_UINT; break; case CmdlineParser::STRING: retval = OPTTYPE_STRING; break; case CmdlineParser::BINUINT: retval = OPTTYPE_BINUINT; break; case CmdlineParser::FLOAT: retval = OPTTYPE_FLOAT; break; } return retval; } CmdlineParser::CmdlineParser() { this->cp = cmd_createOptionParser(); } CmdlineParser::~CmdlineParser() { cmd_destroyOptionParser(this->cp); } void CmdlineParser::defineOption( string const optionName, optType const optionType) { cmd_defineOption(this->cp, optionName.c_str(), optTypeConvert(optionType)); } void CmdlineParser::processOptions( int const argc, const char ** const argv) { const char * error; cmd_processOptions(this->cp, argc, argv, &error); if (error) { string const errorS(error); strfree(error); throw(runtime_error(errorS)); } } bool CmdlineParser::optionIsPresent( string const optionName) const { return (cmd_optionIsPresent(this->cp, optionName.c_str()) ? true : false); } int CmdlineParser::getOptionValueInt( string const optionName) const { return cmd_getOptionValueInt(this->cp, optionName.c_str()); } unsigned int CmdlineParser::getOptionValueUint( string const optionName) const { return cmd_getOptionValueUint(this->cp, optionName.c_str()); } unsigned long long CmdlineParser::getOptionValueBinUint( string const optionName) const { return cmd_getOptionValueBinUint(this->cp, optionName.c_str()); } double CmdlineParser::getOptionValueFloat( string const optionName) const { return cmd_getOptionValueFloat(this->cp, optionName.c_str()); } string CmdlineParser::getOptionValueString( string const optionName) const { const char * const value = cmd_getOptionValueString(this->cp, optionName.c_str()); string retval; if (value) { retval = string(value); strfree(value); } else retval = ""; return retval; } unsigned int CmdlineParser::argumentCount() const { return cmd_argumentCount(this->cp); } string CmdlineParser::getArgument( unsigned int const argNumber) const { const char * const value = cmd_getArgument(this->cp, argNumber); string const retval(value); strfree(value); return retval; } xmlrpc-c-1.33.14/lib/util/getoptx.c000066400000000000000000000370711236133176700170120ustar00rootroot00000000000000/* This version of `getopt' appears to the caller like standard Unix getopt() but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As getopt() works, it permutes the elements of `argv' so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable _POSIX_OPTION_ORDER disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include #include #include #include "getoptx.h" /* Note that on some systems, the header files above declare variables for use with their native getopt facilities, and those variables have the same names as we'd like to use. So we use things like optargx instead of optarg to avoid the collision. */ /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. */ static char *optargx = 0; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to getoptx(). On entry to getoptx(), zero means this is the first call; initialize. When getoptx() returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optindx' communicates from one call to the next how much of ARGV has been scanned so far. */ static int optindx = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ static int opterrx; /* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found. Only valid when a long-named option was found. */ static int option_index; struct optionx * _getopt_long_options; /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optindx), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ static void exchange(char ** const argv) { unsigned int const nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *); char **temp = (char **) malloc (nonopts_size); if (temp == NULL) abort(); /* Interchange the two blocks of data in argv. */ memcpy (temp, &argv[first_nonopt], nonopts_size); memcpy (&argv[first_nonopt], &argv[last_nonopt], (optindx - last_nonopt) * sizeof (char *)); memcpy (&argv[first_nonopt + optindx - last_nonopt], temp, nonopts_size); /* Update records for the slots the non-options now occupy. */ first_nonopt += (optindx - last_nonopt); last_nonopt = optindx; free(temp); } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If getoptx() is called repeatedly, it returns successively each of the option characters from each of the option elements. If getoptx() finds another option character, it returns that character, updating `optindx' and `nextchar' so that the next call to getoptx() can resume the scan with the following option character or ARGV-element. If there are no more option characters, getoptx() returns `EOF'. Then `optindx' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterrx' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optargx'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optargx', otherwise `optargx' is set to zero. If OPTSTRING starts with `-', it requests a different method of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER, above. Long-named options begin with `+' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. getoptx() returns 0 when it finds a long-named option. */ static int getoptx(int const argc, char ** const argv, const char * const optstring) { optargx = 0; /* Initialize the internal data when the first call is made. Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ if (optindx == 0) { first_nonopt = last_nonopt = optindx = 1; nextchar = 0; } if (nextchar == 0 || *nextchar == 0) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optindx) exchange (argv); else if (last_nonopt != optindx) first_nonopt = optindx; /* Now skip any additional non-options and extend the range of non-options previously skipped. */ while (optindx < argc && (argv[optindx][0] != '-'|| argv[optindx][1] == 0) && (argv[optindx][0] != '+'|| argv[optindx][1] == 0)) optindx++; last_nonopt = optindx; /* Special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optindx != argc && !strcmp (argv[optindx], "--")) { optindx++; if (first_nonopt != last_nonopt && last_nonopt != optindx) exchange (argv); else if (first_nonopt == last_nonopt) first_nonopt = optindx; last_nonopt = argc; optindx = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optindx == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optindx = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if ((argv[optindx][0] != '-' || argv[optindx][1] == 0) && (argv[optindx][0] != '+' || argv[optindx][1] == 0)) { optargx = argv[optindx++]; return 1; } /* We have found another option-ARGV-element. Start decoding its characters. */ nextchar = argv[optindx] + 1; } if ((argv[optindx][0] == '+' || (argv[optindx][0] == '-')) ) { struct optionx *p; char *s = nextchar; int exact = 0; int ambig = 0; struct optionx * pfound; int indfound; while (*s && *s != '=') s++; indfound = 0; /* quite compiler warning */ /* Test all options for either exact match or abbreviated matches. */ for (p = _getopt_long_options, option_index = 0, pfound = NULL; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, s - nextchar)) { if ((unsigned int)(s - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (!pfound) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second nonexact match found. */ ambig = 1; } if (ambig && !exact) { fprintf (stderr, "%s: option `%s' is ambiguous\n", argv[0], argv[optindx]); nextchar += strlen (nextchar); return '?'; } if (pfound) { option_index = indfound; optindx++; if (*s) { if (pfound->has_arg > 0) optargx = s + 1; else { fprintf (stderr, "%s: option `%c%s' doesn't allow an argument\n", argv[0], argv[optindx - 1][0], pfound->name); nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg) { if (optindx < argc) optargx = argv[optindx++]; else if (pfound->has_arg != 2) { fprintf (stderr, "%s: option `%s' requires an argument\n", argv[0], argv[optindx - 1]); nextchar += strlen (nextchar); return '?'; } } nextchar += strlen (nextchar); if (pfound->flag) *(pfound->flag) = pfound->val; return 0; } if (argv[optindx][0] == '+' || strchr (optstring, *nextchar) == 0) { if (opterrx != 0) fprintf (stderr, "%s: unrecognized option `%c%s'\n", argv[0], argv[optindx][0], nextchar); nextchar += strlen (nextchar); return '?'; } } /* Look at and handle the next option-character. */ { char c = *nextchar++; char *temp = strchr (optstring, c); /* Increment `optindx' when we start to process its last character. */ if (*nextchar == 0) optindx++; if (temp == 0 || c == ':') { if (opterrx != 0) { if (c < 040 || c >= 0177) fprintf (stderr, "%s: unrecognized option, " "character code 0%o\n", argv[0], c); else fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); } return '?'; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != 0) { optargx = nextchar; optindx++; } else optargx = 0; nextchar = 0; } else { /* This is an option that requires an argument. */ if (*nextchar != 0) { optargx = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optindx++; } else if (optindx == argc) { if (opterrx != 0) fprintf (stderr, "%s: option `-%c' requires an argument\n", argv[0], c); c = '?'; } else /* We already incremented `optindx' once; increment it again when taking next ARGV-elt as argument. */ optargx = argv[optindx++]; nextchar = 0; } } return c; } } void getopt_long_onlyx(int const argc, char ** const argv, const char * const options, struct optionx * const long_options, unsigned int * const opt_index, int const opterrArg, int * const end_of_options, const char ** const optarg_arg, const char ** const unrecognized_option) { int rc; opterrx = opterrArg; _getopt_long_options = long_options; rc = getoptx(argc, argv, options); if (rc == 0) *opt_index = option_index; if (rc == '?') *unrecognized_option = argv[optindx]; else *unrecognized_option = NULL; if (rc < 0) *end_of_options = 1; else *end_of_options = 0; *optarg_arg = optargx; } unsigned int getopt_argstart(void) { /*---------------------------------------------------------------------------- This is a replacement for what traditional getopt does with global variables. You call this after getopt_long_onlyx() has returned "end of options" -----------------------------------------------------------------------------*/ return optindx; } /* Getopt for GNU. Copyright (C) 1987, 1989 Free Software Foundation, Inc. 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ xmlrpc-c-1.33.14/lib/util/getoptx.h000066400000000000000000000034261236133176700170140ustar00rootroot00000000000000/* Interface to getopt_long_onlyx() */ enum argreq {no_argument, required_argument, optional_argument}; struct optionx { /* This describes an option. If the field `flag' is nonzero, it points to a variable that is to be set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. */ const char * name; enum argreq has_arg; int * flag; int val; }; /* long_options[] is a list terminated by an element that contains a NULL 'name' member. */ void getopt_long_onlyx(int const argc, char ** const argv, const char * const options, struct optionx * const long_options, unsigned int * const opt_index, int const opterrArg, int * const end_of_options, const char ** const optarg_arg, const char ** const unrecognized_option); unsigned int getopt_argstart(void); /* Copyright (C) 1989 Free Software Foundation, Inc. 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ xmlrpc-c-1.33.14/lib/util/include/000077500000000000000000000000001236133176700165675ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/util/include/assertx.hpp000066400000000000000000000013661236133176700207770ustar00rootroot00000000000000#ifndef ASSERTX_HPP_INCLUDED #define ASSERTX_HPP_INCLUDED #include /* The compiler often warns you if you give a function formal parameter a name, but don't use it. But because assert() disappears when doing an optimized build, the compiler doesn't recognize your reference to the parameter in the assert() argument. To avoid the bogus warning in this case, we have ASSERT_ONLY_ARG(), which declares a name for a formal parameter for purposes of assert() only. In cases where an assert() would disappear, ASSERT_ONLY_ARG() disappears too. E.g. void foo(int const ASSERT_ONLY_ARG(arg1)) { assert(arg1 > 0); } */ #ifdef NDEBUG #define ASSERT_ONLY_ARG(x) #else #define ASSERT_ONLY_ARG(x) x #endif #endif xmlrpc-c-1.33.14/lib/util/include/bool.h000066400000000000000000000006631236133176700177000ustar00rootroot00000000000000/* This takes the place of C99 stdbool.h, which at least some Windows compilers don't have. (October 2005). One must not also include , because it might cause a name collision. */ #ifndef __cplusplus /* At least the GNU compiler defines __bool_true_false_are_defined */ #ifndef __bool_true_false_are_defined #define __bool_true_false_are_defined typedef enum { false = 0, true = 1 } bool; #endif #endif xmlrpc-c-1.33.14/lib/util/include/c_util.h000066400000000000000000000010101236133176700202070ustar00rootroot00000000000000#ifndef C_UTIL_H_INCLUDED #define C_UTIL_H_INCLUDED /* C language stuff. Doesn't involve any libraries that aren't part of the compiler. */ #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /* GNU_PRINTF_ATTR lets the GNU compiler check printf-type calls to be sure the arguments match the format string, thus preventing runtime segmentation faults and incorrect messages. */ #ifdef __GNUC__ #define GNU_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) #else #define GNU_PRINTF_ATTR(a,b) #endif #endif xmlrpc-c-1.33.14/lib/util/include/casprintf.h000066400000000000000000000007311236133176700207320ustar00rootroot00000000000000#ifndef CASPRINTF_H_INCLUDED #define CASPRINTF_H_INCLUDED #include #include "c_util.h" #ifdef __cplusplus extern "C" { #endif extern const char * const strsol; void cvasprintf(const char ** const retvalP, const char * const fmt, va_list varargs); void GNU_PRINTF_ATTR(2,3) casprintf(const char ** const retvalP, const char * const fmt, ...); void strfree(const char * const string); #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/lib/util/include/cmdline_parser.h000066400000000000000000000034461236133176700217360ustar00rootroot00000000000000#ifndef CMDLINE_PARSER_H #define CMDLINE_PARSER_H #ifdef __cplusplus extern "C" { #endif #if 0 } /* to fake out automatic code indenters */ #endif #include "int.h" /* NOTE NOTE NOTE: cmd_getOptionValueString() and cmd_getArgument() return malloc'ed memory (and abort the program if out of memory). You must free it. */ enum optiontype { OPTTYPE_FLAG, OPTTYPE_INT, OPTTYPE_UINT, OPTTYPE_STRING, OPTTYPE_BINUINT, OPTTYPE_FLOAT }; struct cmdlineParserCtl; typedef struct cmdlineParserCtl * cmdlineParser; void cmd_processOptions(cmdlineParser const cpP, int const argc, const char ** const argv, const char ** const errorP); cmdlineParser cmd_createOptionParser(void); void cmd_destroyOptionParser(cmdlineParser const cpP); void cmd_defineOption(cmdlineParser const cpP, const char * const name, enum optiontype const type); int cmd_optionIsPresent(cmdlineParser const cpP, const char * const name); int cmd_getOptionValueInt(cmdlineParser const cpP, const char * const name); unsigned int cmd_getOptionValueUint(cmdlineParser const cpP, const char * const name); const char * cmd_getOptionValueString(cmdlineParser const cpP, const char * const name); uint64_t cmd_getOptionValueBinUint(cmdlineParser const cpP, const char * const name); double cmd_getOptionValueFloat(cmdlineParser const cpP, const char * const name); unsigned int cmd_argumentCount(cmdlineParser const cpP); const char * cmd_getArgument(cmdlineParser const cpP, unsigned int const argNumber); #ifdef __cplusplus } #endif #endif xmlrpc-c-1.33.14/lib/util/include/cmdline_parser.hpp000066400000000000000000000024631236133176700222740ustar00rootroot00000000000000#ifndef CMDLINE_PARSER_HPP_INCLUDED #define CMDLINE_PARSER_HPP_INCLUDED #include struct cmdlineParserCtl; class CmdlineParser { public: CmdlineParser(); ~CmdlineParser(); enum optType {FLAG, INT, UINT, STRING, BINUINT, FLOAT}; void defineOption(std::string const optionName, optType const optionType); void processOptions(int const argc, const char ** const argv); bool optionIsPresent(std::string const optionName) const; int getOptionValueInt(std::string const optionName) const; unsigned int getOptionValueUint(std::string const optionName) const; std::string getOptionValueString(std::string const optionName) const; unsigned long long getOptionValueBinUint(std::string const optionName) const; double getOptionValueFloat(std::string const optionName) const; unsigned int argumentCount() const; std::string getArgument(unsigned int const argNumber) const; private: struct cmdlineParserCtl * cp; // Make sure no one can copy this object, because if there are two // copies, there will be two attempts to destroy *cp. CmdlineParser(CmdlineParser const&) {}; CmdlineParser& operator=(CmdlineParser const&) {return *this;} }; #endif xmlrpc-c-1.33.14/lib/util/include/girmath.h000066400000000000000000000002041236133176700203670ustar00rootroot00000000000000#ifndef __GIRMATH_H #define __GIRMATH_H #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif xmlrpc-c-1.33.14/lib/util/include/girstring.h000066400000000000000000000023021236133176700207450ustar00rootroot00000000000000#ifndef GIRSTRING_H_INCLUDED #define GIRSTRING_H_INCLUDED #include #include "xmlrpc_config.h" #include "bool.h" bool stripcaseeq(const char * const comparand, const char * const comparator); static __inline__ bool streq(const char * const comparator, const char * const comparand) { return (strcmp(comparand, comparator) == 0); } static __inline__ bool memeq(const void * const comparator, const void * const comparand, size_t const size) { return (memcmp(comparator, comparand, size) == 0); } #define MEMEQ(a,b,c) (memcmp(a, b, c) == 0) #define MEMSSET(a,b) (memset(a, b, sizeof(*a))) #define MEMSCPY(a,b) (memcpy(a, b, sizeof(*a))) #define MEMSZERO(a) (MEMSSET(a, 0)) static __inline__ const char * sdup(const char * const input) { return (const char *) strdup(input); } /* Copy string pointed by B to array A with size checking. */ #define STRSCPY(A,B) \ (strncpy((A), (B), sizeof(A)), *((A)+sizeof(A)-1) = '\0') #define STRSCMP(A,B) \ (strncmp((A), (B), sizeof(A))) /* Concatenate string B onto string in array A with size checking */ #define STRSCAT(A,B) \ (strncat((A), (B), sizeof(A)-strlen(A)), *((A)+sizeof(A)-1) = '\0') #endif xmlrpc-c-1.33.14/lib/util/include/inline.h000066400000000000000000000005501236133176700202160ustar00rootroot00000000000000#ifndef XMLRPC_INLINE_H_INCLUDED #define XMLRPC_INLINE_H_INCLUDED /* Xmlrpc-c uses __inline__ to declare functions that should be compiled as inline code. Some compilers, e.g. GNU, recognize the __inline__ keyword. */ #ifndef __GNUC__ #ifndef __inline__ #ifdef __sgi #define __inline__ __inline #else #define __inline__ #endif #endif #endif #endif xmlrpc-c-1.33.14/lib/util/include/int.h000066400000000000000000000031061236133176700175320ustar00rootroot00000000000000/* This takes the place of C99 inttypes.h, which at least some Windows compilers don't have. (October 2007). */ /* PRId64 is the printf-style format specifier for a long long type, as in long long mynumber = 5; printf("My number is %" PRId64 ".\n", mynumber); The LL/ULL macro is for 64 bit integer literals, like this: long long mask= ULL(1) << 33; */ /* 'uint' is quite convenient, but there's no simple way have it everywhere. Some systems have it in the base system (e.g. GNU C library has it in , and others (e.g. Solaris - 08.12.02) don't. Since we can't define it unless we know it's not defined already, and we don't want to burden the reader with a special Xmlrpc-c name such as xuint, we just use standard "unsigned int" instead. */ #ifdef _MSC_VER # define PRId64 "I64d" # define PRIu64 "I64u" #ifndef int16_t typedef short int16_t; #endif #ifndef uint16_t typedef unsigned short uint16_t; #endif #ifndef int32_t typedef int int32_t; #endif #ifndef uint32_t typedef unsigned int uint32_t; #endif #ifndef int64_t typedef __int64 int64_t; #endif #ifndef uint64_t typedef unsigned __int64 uint64_t; #endif #ifndef uint8_t typedef unsigned char uint8_t; #endif /* Older Microsoft compilers don't know the standard ll/ull suffixes */ #define LL(x) x ## i64 #define ULL(x) x ## u64 #elif defined(__INTERIX) # include # define PRId64 "I64d" # define PRIu64 "I64u" #else /* Not Microsoft compiler */ #include #define LL(x) x ## ll #define ULL(x) x ## ull #endif xmlrpc-c-1.33.14/lib/util/include/linklist.h000066400000000000000000000113571236133176700206000ustar00rootroot00000000000000#ifndef LINKLIST_H_INCLUDED #define LINKLIST_H_INCLUDED #include "inline.h" struct list_head { /*---------------------------------------------------------------------------- This is a header for an element of a doubly linked list, or an anchor for such a list. itemP == NULL means it's an anchor; otherwise it's a header. Initialize a list header with list_init_header(). You don't have to do anything to terminate a list header. Initialize an anchor with list_make_emtpy(). You don't have to do anything to terminate a list header. -----------------------------------------------------------------------------*/ struct list_head * nextP; /* For a header, this is the address of the list header for the next element in the list. If there is no next element, it points to the anchor. If the header is not in a list at all, it is NULL. For an anchor, it is the address of the list header of the first element. If the list is empty, it points to the anchor itself. */ struct list_head * prevP; /* For a header, this is the address of the list header for the previous element in the list. If there is no previous element, it points to the anchor. If the header is not in a list at all, it is NULL. For an anchor, it is the address of the list header of the last element. If the list is empty, it points to the anchor itself. */ void * itemP; /* For a header, this is the address of the list element to which it belongs. For an anchor, this is NULL. */ }; static __inline__ void list_init_header(struct list_head * const headerP, void * const itemP) { headerP->prevP = NULL; headerP->nextP = NULL; headerP->itemP = itemP; } static __inline__ int list_is_linked(struct list_head * headerP) { return headerP->prevP != NULL; } static __inline__ int list_is_empty(struct list_head * const anchorP) { return anchorP->nextP == anchorP; } static __inline__ unsigned int list_count(struct list_head * const anchorP) { unsigned int count; struct list_head * p; for (p = anchorP->nextP, count = 0; p != anchorP; p = p->nextP, ++count); return count; } static __inline__ void list_make_empty(struct list_head * const anchorP) { anchorP->prevP = anchorP; anchorP->nextP = anchorP; anchorP->itemP = NULL; } static __inline__ void list_insert_after(struct list_head * const beforeHeaderP, struct list_head * const newHeaderP) { newHeaderP->prevP = beforeHeaderP; newHeaderP->nextP = beforeHeaderP->nextP; beforeHeaderP->nextP = newHeaderP; newHeaderP->nextP->prevP = newHeaderP; } static __inline__ void list_add_tail(struct list_head * const anchorP, struct list_head * const headerP) { list_insert_after(anchorP->prevP, headerP); } static __inline__ void list_add_head(struct list_head * const anchorP, struct list_head * const headerP) { list_insert_after(anchorP, headerP); } static __inline__ void list_remove(struct list_head * const headerP) { headerP->prevP->nextP = headerP->nextP; headerP->nextP->prevP = headerP->prevP; headerP->prevP = NULL; headerP->nextP = NULL; } static __inline__ struct list_head * list_remove_head(struct list_head * const anchorP) { struct list_head * retval; if (list_is_empty(anchorP)) retval = NULL; else { retval = anchorP->nextP; list_remove(retval); } return retval; } static __inline__ struct list_head * list_remove_tail(struct list_head * const anchorP) { struct list_head * retval; if (list_is_empty(anchorP)) retval = NULL; else { retval = anchorP->prevP; list_remove(retval); } return retval; } static __inline__ void * list_foreach(struct list_head * const anchorP, void * functionP(struct list_head *, void *), void * const context) { struct list_head * p; struct list_head * nextP; void * result; for (p = anchorP->nextP, nextP = p->nextP, result=NULL; p != anchorP && result == NULL; p = nextP, nextP = p->nextP) result = (*functionP)(p, context); return result; } static __inline__ void list_append(struct list_head * const newAnchorP, struct list_head * const baseAnchorP) { if (!list_is_empty(newAnchorP)) { baseAnchorP->prevP->nextP = newAnchorP->nextP; newAnchorP->nextP->prevP = baseAnchorP->prevP; newAnchorP->prevP->nextP = baseAnchorP; baseAnchorP->prevP = newAnchorP->prevP; } } #endif xmlrpc-c-1.33.14/lib/util/include/mallocvar.h000066400000000000000000000061251236133176700207240ustar00rootroot00000000000000/* These are some dynamic memory allocation facilities. They are essentially an extension to C, as they do allocations with a cognizance of C variables. You can use them to make C read more like a high level language. Before including this, you must define an __inline__ macro if your compiler doesn't recognize it as a keyword. */ #ifndef MALLOCVAR_INCLUDED #define MALLOCVAR_INCLUDED #include "xmlrpc_config.h" #include #include static __inline__ void mallocProduct(void ** const resultP, unsigned int const factor1, size_t const factor2) { /*---------------------------------------------------------------------------- malloc a space whose size in bytes is the product of 'factor1' and 'factor2'. But if that size cannot be represented as an unsigned int, return NULL without allocating anything. Also return NULL if the malloc fails. If either factor is zero, malloc a single byte. Note that malloc() actually takes a size_t size argument, so the proper test would be whether the size can be represented by size_t, not unsigned int. But there is no reliable indication available to us, like UINT_MAX, of what the limitations of size_t are. We assume size_t is at least as expressive as unsigned int and that nobody really needs to allocate more than 4GB of memory. -----------------------------------------------------------------------------*/ if (factor1 == 0 || factor2 == 0) *resultP = malloc(1); else { if (UINT_MAX / factor2 < factor1) *resultP = NULL; else *resultP = malloc(factor1 * factor2); } } static __inline__ void reallocProduct(void ** const blockP, unsigned int const factor1, unsigned int const factor2) { void * const oldBlockP = *blockP; void * newBlockP; if (UINT_MAX / factor2 < factor1) newBlockP = NULL; else newBlockP = realloc(oldBlockP, factor1 * factor2); if (newBlockP) *blockP = newBlockP; else { free(oldBlockP); *blockP = NULL; } } /* IMPLEMENTATION NOTE: There are huge strict aliasing pitfalls here if you cast pointers, e.g. (void **) */ #define MALLOCARRAY(arrayName, nElements) do { \ void * array; \ mallocProduct(&array, nElements, sizeof(arrayName[0])); \ arrayName = array; \ } while (0) #define REALLOCARRAY(arrayName, nElements) do { \ void * array = arrayName; \ reallocProduct(&array, nElements, sizeof(arrayName[0])); \ arrayName = array; \ } while (0) #define MALLOCARRAY_NOFAIL(arrayName, nElements) \ do { \ MALLOCARRAY(arrayName, nElements); \ if ((arrayName) == NULL) \ abort(); \ } while(0) #define REALLOCARRAY_NOFAIL(arrayName, nElements) \ do { \ REALLOCARRAY(arrayName, nElements); \ if ((arrayName) == NULL) \ abort(); \ } while(0) #define MALLOCVAR(varName) \ varName = malloc(sizeof(*varName)) #define MALLOCVAR_NOFAIL(varName) \ do {if ((varName = malloc(sizeof(*varName))) == NULL) abort();} while(0) #endif xmlrpc-c-1.33.14/lib/util/include/stdargx.h000066400000000000000000000037231236133176700204210ustar00rootroot00000000000000#ifndef STDARGX_H_INCLUDED #define STDARGX_H_INCLUDED #include "xmlrpc_config.h" #include #include /*---------------------------------------------------------------------------- We need a special version of va_list in order to pass around the variable argument heap by reference, thus allowing a subroutine to advance the heap's pointer. On some systems (e.g. Gcc for PPC or AMD64), va_list is an array. That invites the scourge of array-to-pointer degeneration if you try to take its address. Burying it inside a struct as we do with our va_listx type makes it immune. Example of what would happen if we used va_list instead of va_listx, on a system where va_list is an array: void sub2(va_list * argsP) [ ... } void sub1(va_list args) { sub2(&args); } This doesn't work. '&args' is the same thing as 'args', so is va_list, not va_list *. The compiler will even warn you about the pointer type mismatch. To use va_listx: void sub1_va(char * format, va_list args) { va_listx argsx; init_va_listx(&argsx, args); sub2(format, &argsx); } -----------------------------------------------------------------------------*/ typedef struct { /*---------------------------------------------------------------------------- Same thing as va_list, but in a form that works everywhere. See above. -----------------------------------------------------------------------------*/ va_list v; } va_listx; static __inline__ void init_va_listx(va_listx * const argsxP, va_list const args) { #if VA_LIST_IS_ARRAY /* 'args' is NOT a va_list. It is a pointer to the first element of a 'va_list', which is the same address as a pointer to the va_list itself. (That's what happens when you pass an array in C). */ memcpy(&argsxP->v, args, sizeof(argsxP->v)); #else argsxP->v = args; #endif } #endif xmlrpc-c-1.33.14/lib/util/include/string_parser.h000066400000000000000000000013561236133176700216270ustar00rootroot00000000000000#ifndef STRING_PARSER_H_INCLUDED #define STRING_PARSER_H_INCLUDED #include "int.h" void interpretUll(const char * const string, uint64_t * const ullP, const char ** const errorP); void interpretLl(const char * const string, int64_t * const llP, const char ** const errorP); void interpretUint(const char * const string, unsigned int * const uintP, const char ** const errorP); void interpretInt(const char * const string, int * const uintP, const char ** const errorP); void interpretBinUint(const char * const string, uint64_t * const valueP, const char ** const errorP); #endif xmlrpc-c-1.33.14/lib/util/include/unistdx.h000066400000000000000000000003561236133176700204420ustar00rootroot00000000000000#ifndef UNISTDX_H_INCLUDED #define UNISTDX_H_INCLUDED /* Xmlrpc-c code #includes "unistdx.h" instead of because does not exist on WIN32. */ #ifndef WIN32 # include #else #endif /* WIN32 */ #endif xmlrpc-c-1.33.14/lib/util/pthreadx_win32.c000066400000000000000000000065721236133176700201630ustar00rootroot00000000000000/* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include "xmlrpc_config.h" #include #include "mallocvar.h" #include "pthreadx.h" #undef PACKAGE #undef VERSION struct winStartArg { pthread_func * func; void * arg; }; static unsigned int __stdcall winThreadStart(void * const arg) { /*---------------------------------------------------------------------------- This is a thread start/root function for the Windows threading facility (i.e. this can be an argument to _beginthreadex()). All we do is call the real start/root function, which expects to be called in the pthread format. -----------------------------------------------------------------------------*/ struct winStartArg * const winStartArgP = arg; winStartArgP->func(winStartArgP->arg); free(winStartArgP); return 0; } int pthread_create(pthread_t * const newThreadIdP, const pthread_attr_t * const attr, pthread_func * func, void * const arg) { HANDLE hThread; DWORD dwThreadID; struct winStartArg * winStartArgP; MALLOCVAR_NOFAIL(winStartArgP); winStartArgP->func = func; winStartArgP->arg = arg; hThread = (HANDLE) _beginthreadex( NULL, 0, &winThreadStart, (LPVOID)winStartArgP, CREATE_SUSPENDED, &dwThreadID); SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL); ResumeThread(hThread); *newThreadIdP = hThread; return hThread ? 0 : -1; } /* Just kill it. */ int pthread_cancel(pthread_t const target_thread) { CloseHandle(target_thread); return 0; } /* Waits for the thread to exit before continuing. */ int pthread_join(pthread_t const target_thread, void ** const statusP) { DWORD dwResult = WaitForSingleObject(target_thread, INFINITE); *statusP = (void *)dwResult; return 0; } int pthread_detach(pthread_t const target_thread) { return 0; } xmlrpc-c-1.33.14/lib/util/string_parser.c000066400000000000000000000154071236133176700202010ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "int.h" #include "girstring.h" #include "casprintf.h" #include "string_parser.h" static const char * strippedSubstring(const char * const string) { const char * p; for (p = &string[0]; isspace(*p); ++p); return p; } void interpretUll(const char * const string, uint64_t * const ullP, const char ** const errorP) { /* strtoull() has the same disappointing weaknesses of strtoul(). See interpretUint(). */ const char * const strippedString = strippedSubstring(string); if (strippedString[0] == '\0') casprintf(errorP, "Null (or all whitespace) string."); else if (!isdigit(strippedString[0])) casprintf(errorP, "First non-blank character is '%c', not a digit.", strippedString[0]); else { /* strtoull() does a bizarre thing where if the number is out of range, it returns a clamped value but tells you about it by setting errno = ERANGE. If it is not out of range, strtoull() leaves errno alone. */ char * tail; errno = 0; /* So we can tell if strtoull() overflowed */ *ullP = XMLRPC_STRTOULL(strippedString, &tail, 10); if (tail[0] != '\0') casprintf(errorP, "Non-digit stuff in string: %s", tail); else if (errno == ERANGE) casprintf(errorP, "Number too large"); else *errorP = NULL; } } void interpretLl(const char * const string, int64_t * const llP, const char ** const errorP) { if (string[0] == '\0') casprintf(errorP, "Null string."); else { /* strtoll() does a bizarre thing where if the number is out of range, it returns a clamped value but tells you about it by setting errno = ERANGE. If it is not out of range, strtoll() leaves errno alone. */ char * tail; errno = 0; /* So we can tell if strtoll() overflowed */ *llP = XMLRPC_STRTOLL(string, &tail, 10); if (tail[0] != '\0') casprintf(errorP, "Non-digit stuff in string: %s", tail); else if (errno == ERANGE) casprintf(errorP, "Number too large"); else *errorP = NULL; } } void interpretUint(const char * const string, unsigned int * const uintP, const char ** const errorP) { /* strtoul() does a lousy job of dealing with invalid numbers. A null string is just zero; a negative number is a large positive one; a positive (cf unsigned) number is accepted. strtoul is inconsistent in its treatment of the tail; if there is no valid number at all, it returns the entire string as the tail, including leading white space and sign, which are not themselves invalid. */ const char * const strippedString = strippedSubstring(string); if (strippedString[0] == '\0') casprintf(errorP, "Null (or all whitespace) string."); else if (!isdigit(strippedString[0])) casprintf(errorP, "First non-blank character is '%c', not a digit.", strippedString[0]); else { /* strtoul() does a bizarre thing where if the number is out of range, it returns a clamped value but tells you about it by setting errno = ERANGE. If it is not out of range, strtoul() leaves errno alone. */ char * tail; unsigned long ulongValue; errno = 0; /* So we can tell if strtoul() overflowed */ ulongValue = strtoul(strippedString, &tail, 10); if (tail[0] != '\0') casprintf(errorP, "Non-digit stuff in string: %s", tail); else if (errno == ERANGE) casprintf(errorP, "Number too large"); else if (ulongValue > UINT_MAX) casprintf(errorP, "Number too large"); else { *uintP = ulongValue; *errorP = NULL; } } } void interpretInt(const char * const string, int * const intP, const char ** const errorP) { if (string[0] == '\0') casprintf(errorP, "Null string."); else { /* strtol() does a bizarre thing where if the number is out of range, it returns a clamped value but tells you about it by setting errno = ERANGE. If it is not out of range, strtol() leaves errno alone. */ char * tail; long longValue; errno = 0; /* So we can tell if strtol() overflowed */ longValue = strtol(string, &tail, 10); if (tail[0] != '\0') casprintf(errorP, "Non-digit stuff in string: %s", tail); else if (errno == ERANGE) casprintf(errorP, "Number too large"); else if (longValue > INT_MAX) casprintf(errorP, "Number too large"); else if (longValue < INT_MIN) casprintf(errorP, "Number too negative"); else { *intP = longValue; *errorP = NULL; } } } void interpretBinUint(const char * const string, uint64_t * const valueP, const char ** const errorP) { char * tailptr; long const mantissa_long = strtol(string, &tailptr, 10); if (errno == ERANGE) casprintf(errorP, "Numeric value out of range for computation: '%s'. " "Try a smaller number with a K, M, G, etc. suffix.", string); else { int64_t const mantissa = mantissa_long; int64_t argNumber; *errorP = NULL; /* initial assumption */ if (*tailptr == '\0') /* There's no suffix. A pure number */ argNumber = mantissa * 1; else if (stripcaseeq(tailptr, "K")) argNumber = mantissa * 1024; else if (stripcaseeq(tailptr, "M")) argNumber = mantissa * 1024 * 1024; else if (stripcaseeq(tailptr, "G")) argNumber = mantissa * 1024 * 1024 * 1024; else if (stripcaseeq(tailptr, "T")) argNumber = mantissa * 1024 * 1024 * 1024 * 1024; else if (stripcaseeq(tailptr, "P")) argNumber = mantissa * 1024 * 1024 * 1024 * 1024 * 1024; else { argNumber = 0; /* quiet compiler warning */ casprintf(errorP, "Garbage suffix '%s' on number", tailptr); } if (!*errorP) { if (argNumber < 0) casprintf(errorP, "Unsigned numeric value is " "negative: %" PRId64, argNumber); else *valueP = (uint64_t) argNumber; } } } xmlrpc-c-1.33.14/lib/util/stripcaseeq.c000066400000000000000000000030741236133176700176370ustar00rootroot00000000000000#include #include "bool.h" #include "girstring.h" bool stripcaseeq(const char * const comparand, const char * const comparator) { /*---------------------------------------------------------------------------- Compare two strings, ignoring leading and trailing blanks and case. Return true if the strings are identical, false otherwise. -----------------------------------------------------------------------------*/ const char *p, *q, *px, *qx; bool equal; /* Make p and q point to the first non-blank character in each string. If there are no non-blank characters, make them point to the terminating NULL. */ p = &comparand[0]; while (*p == ' ') ++p; q = &comparator[0]; while (*q == ' ') ++q; /* Make px and qx point to the last non-blank character in each string. If there are no nonblank characters (which implies the string is null), make them point to the terminating NULL. */ if (*p == '\0') px = p; else { px = p + strlen(p) - 1; while (*px == ' ') --px; } if (*q == '\0') qx = q; else { qx = q + strlen(q) - 1; while (*qx == ' ') --qx; } equal = true; /* initial assumption */ /* If the stripped strings aren't the same length, we know they aren't equal */ if (px - p != qx - q) equal = false; while (p <= px) { if (toupper(*p) != toupper(*q)) equal = false; ++p; ++q; } return equal; } xmlrpc-c-1.33.14/lib/wininet_transport/000077500000000000000000000000001236133176700177605ustar00rootroot00000000000000xmlrpc-c-1.33.14/lib/wininet_transport/Makefile000066400000000000000000000021601236133176700214170ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') LIBDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(LIBDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := lib/wininet_transport include $(BLDDIR)/config.mk default: all .PHONY: all all: xmlrpc_wininet_transport.o xmlrpc_wininet_transport.osh # Rules for the above dependencies are in common.mk, # courtesy of TARGET_MODS. TARGET_MODS = xmlrpc_wininet_transport OMIT_WININET_TRANSPORT_RULE=Y include $(SRCDIR)/common.mk # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir INCLUDES = \ -I$(BLDDIR) \ -I$(BLDDIR)/include \ -Isrcdir/include \ -Isrcdir/lib/util/include \ .PHONY: clean clean: clean-common .PHONY: distclean distclean: clean distclean-common .PHONY: tags tags: TAGS .PHONY: distdir distdir: .PHONY: install install: .PHONY: dep dep: dep-common include depend.mk # Need this dependency for those who don't use depend.mk. # Without it, version.h doesn't get created. xmlrpc_wininet_transport.o xmlrpc_wininet_transport.osh: version.h xmlrpc-c-1.33.14/lib/wininet_transport/xmlrpc_wininet_transport.c000066400000000000000000001020741236133176700253060ustar00rootroot00000000000000/*============================================================================= xmlrpc_wininet_transport =============================================================================== WinInet-based client transport for Xmlrpc-c. Copyright information at the bottom of this file. =============================================================================*/ #include "xmlrpc_config.h" #include #include #include #include #include #define WIN32_LEAN_AND_MEAN #include #include #include "bool.h" #include "mallocvar.h" #include "linklist.h" #include "casprintf.h" #include "pthreadx.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_platform.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/client_int.h" #include "xmlrpc-c/transport.h" #if defined(_DEBUG) # include # define new DEBUG_NEW # define malloc(size) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__) # undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif static HINTERNET hSyncInternetSession = NULL; /* Declare WinInet status callback. */ void CALLBACK statusCallback(HINTERNET const hInternet, unsigned long const dwContext, unsigned long const dwInternetStatus, void * const lpvStatusInformation, unsigned long const dwStatusInformationLength); struct xmlrpc_client_transport { lock * listLockP; struct list_head rpcList; /* List of all RPCs that exist for this transport. An RPC exists from the time the user requests it until the time the user acknowledges it is done. */ int allowInvalidSSLCerts; /* Flag to specify if we ignore invalid SSL Certificates. If this is set to zero, calling a XMLRPC server with an invalid SSL certificate will fail. This is the default behavior of the other transports, but invalid certificates were allowed in pre 1.2 wininet xmlrpc-c transports. */ }; typedef struct { unsigned long http_status; HINTERNET hHttpRequest; HINTERNET hURL; INTERNET_PORT nPort; char szHostName[255]; char szUrlPath[255]; BOOL bUseSSL; char * headerList; BYTE * pSendData; xmlrpc_mem_block * pResponseData; } winInetTransaction; typedef struct { struct list_head link; /* link in transport's list of RPCs */ winInetTransaction * winInetTransactionP; /* The object which does the HTTP transaction, with no knowledge of XML-RPC or Xmlrpc-c. */ xmlrpc_mem_block * responseXmlP; xmlrpc_bool threadExists; pthread_t thread; xmlrpc_transport_asynch_complete complete; /* Routine to call to complete the RPC after it is complete HTTP-wise. NULL if none. */ struct xmlrpc_call_info * callInfoP; /* User's identifier for this RPC */ struct xmlrpc_client_transport * clientTransportP; } rpc; static void createWinInetHeaderList(xmlrpc_env * const envP, const xmlrpc_server_info * const serverP, char ** const headerListP) { const char * const szContentType = "Content-Type: text/xml\r\n"; char * szHeaderList; /* Send an authorization header if we need one. */ if (serverP->allowedAuth.basic) { /* Make the header with content type and authorization */ /* NOTE: A newline is required between each added header */ szHeaderList = malloc(strlen(szContentType) + 17 + strlen(serverP->basicAuthHdrValue) + 1); if (szHeaderList == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for authorization header"); else { memcpy(szHeaderList, szContentType, strlen(szContentType)); memcpy(szHeaderList + strlen(szContentType),"\r\nAuthorization: ", 17); memcpy(szHeaderList + strlen(szContentType) + 17, serverP->basicAuthHdrValue, strlen(serverP->basicAuthHdrValue) + 1); } } else { /* Just the content type header is needed */ szHeaderList = malloc(strlen(szContentType) + 1); if (szHeaderList == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for standard header"); else memcpy(szHeaderList, szContentType, strlen(szContentType) + 1); } *headerListP = szHeaderList; } static void createWinInetTransaction(xmlrpc_env * const envP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block * const responseXmlP, winInetTransaction ** const winInetTranPP) { winInetTransaction * winInetTransactionP; MALLOCVAR(winInetTransactionP); if (winInetTransactionP == NULL) xmlrpc_faultf(envP, "No memory to create WinInet transaction."); else { char szExtraInfo[255]; char szScheme[100]; URL_COMPONENTS uc; BOOL succeeded; /* Init to defaults */ winInetTransactionP->http_status = 0; winInetTransactionP->hHttpRequest = NULL; winInetTransactionP->hURL = NULL; winInetTransactionP->headerList = NULL; winInetTransactionP->pSendData = NULL; winInetTransactionP->pResponseData = responseXmlP; /* Parse the URL and store results into the winInetTransaction */ memset(&uc, 0, sizeof(uc)); uc.dwStructSize = sizeof (uc); uc.lpszScheme = szScheme; uc.dwSchemeLength = 100; uc.lpszHostName = winInetTransactionP->szHostName; uc.dwHostNameLength = 255; uc.lpszUrlPath = winInetTransactionP->szUrlPath; uc.dwUrlPathLength = 255; uc.lpszExtraInfo = szExtraInfo; uc.dwExtraInfoLength = 255; succeeded = InternetCrackUrl(serverP->serverUrl, strlen(serverP->serverUrl), ICU_ESCAPE, &uc); if (!succeeded) xmlrpc_faultf(envP, "Unable to parse the server URL."); else { winInetTransactionP->nPort = uc.nPort ? uc.nPort : INTERNET_DEFAULT_HTTP_PORT; if (_strnicmp(uc.lpszScheme, "https", 5) == 0) winInetTransactionP->bUseSSL=TRUE; else winInetTransactionP->bUseSSL=FALSE; createWinInetHeaderList(envP, serverP, &winInetTransactionP->headerList); XMLRPC_MEMBLOCK_APPEND(char, envP, callXmlP, "\0", 1); if (!envP->fault_occurred) { winInetTransactionP->pSendData = XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP); } } if (envP->fault_occurred) free(winInetTransactionP); } *winInetTranPP = winInetTransactionP; } static void destroyWinInetTransaction(winInetTransaction * const winInetTransactionP) { XMLRPC_ASSERT_PTR_OK(winInetTransactionP); if (winInetTransactionP->hHttpRequest) InternetCloseHandle(winInetTransactionP->hHttpRequest); if (winInetTransactionP->hURL) InternetCloseHandle(winInetTransactionP->hURL); if (winInetTransactionP->headerList) free(winInetTransactionP->headerList); free(winInetTransactionP); } static void get_wininet_response(xmlrpc_env * const envP, winInetTransaction * const winInetTransactionP) { unsigned long dwLen; INTERNET_BUFFERS inetBuffer; unsigned long dwFlags; unsigned long dwErr; unsigned long nExpected; void * body; BOOL bOK; PVOID pMsgMem; pMsgMem = NULL; /* initial value */ dwErr = 0; /* initial value */ body = NULL; /* initial value */ dwLen = sizeof(unsigned long); /* initial value */ inetBuffer.dwStructSize = sizeof (INTERNET_BUFFERS); inetBuffer.Next = NULL; inetBuffer.lpcszHeader = NULL; inetBuffer.dwHeadersTotal = 0; inetBuffer.dwHeadersLength = 0; inetBuffer.dwOffsetHigh = 0; inetBuffer.dwOffsetLow = 0; inetBuffer.dwBufferLength = 0; /* Note that while Content-Length is optional in HTTP 1.1, it is required by XML-RPC. Following fails if server didn't send it. */ bOK = HttpQueryInfo(winInetTransactionP->hHttpRequest, HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, &inetBuffer.dwBufferTotal, &dwLen, NULL); if (!bOK) { LPTSTR pMsg; dwErr = GetLastError (); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pMsgMem, 1024,NULL); pMsg = pMsgMem ? (LPTSTR)pMsgMem : "Sync HttpQueryInfo failed."; XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, pMsg); } if (inetBuffer.dwBufferTotal == 0) XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, "WinInet returned no data"); inetBuffer.lpvBuffer = calloc(inetBuffer.dwBufferTotal, sizeof(TCHAR)); body = inetBuffer.lpvBuffer; dwFlags = IRF_SYNC; nExpected = inetBuffer.dwBufferTotal; inetBuffer.dwBufferLength = nExpected; InternetQueryDataAvailable(winInetTransactionP->hHttpRequest, &inetBuffer.dwBufferLength, 0, 0); /* Read Response from InternetFile */ do { if (inetBuffer.dwBufferLength != 0) bOK = InternetReadFileEx(winInetTransactionP->hHttpRequest, &inetBuffer, dwFlags, 1); if (!bOK) dwErr = GetLastError(); if (dwErr) { if (dwErr == WSAEWOULDBLOCK || dwErr == ERROR_IO_PENDING) { /* Non-block socket operation wait 10 msecs */ SleepEx(10, TRUE); /* Reset dwErr to zero for next pass */ dwErr = 0; } else { LPTSTR pMsg; FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pMsgMem, 1024,NULL); pMsg = pMsgMem ? (LPTSTR)pMsgMem : "ASync InternetReadFileEx failed."; XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, pMsg); } } if (inetBuffer.dwBufferLength) { TCHAR * const oldBufptr = inetBuffer.lpvBuffer; inetBuffer.lpvBuffer = oldBufptr + inetBuffer.dwBufferLength; nExpected -= inetBuffer.dwBufferLength; /* Adjust inetBuffer.dwBufferLength when it is greater than the */ /* expected end of file */ if (inetBuffer.dwBufferLength > nExpected) inetBuffer.dwBufferLength = nExpected; } else inetBuffer.dwBufferLength = nExpected; dwErr = 0; } while (nExpected != 0); /* Add to the response buffer. */ xmlrpc_mem_block_append(envP, winInetTransactionP->pResponseData, body, inetBuffer.dwBufferTotal); XMLRPC_FAIL_IF_FAULT(envP); cleanup: /* Since the XMLRPC_FAIL calls goto cleanup, we must handle */ /* the free'ing of the memory here. */ if (pMsgMem != NULL) LocalFree(pMsgMem); if (body) free(body); } static void performWinInetTransaction( xmlrpc_env * const envP, winInetTransaction * const winInetTransactionP, struct xmlrpc_client_transport * const clientTransportP) { const char * const acceptTypes[] = {"text/xml", NULL}; unsigned long queryLen; LPVOID pMsgMem; BOOL succeeded; unsigned long lastErr; unsigned long reqFlags; pMsgMem = NULL; /* initial value */ reqFlags = INTERNET_FLAG_NO_UI; /* initial value */ winInetTransactionP->hURL = InternetConnect(hSyncInternetSession, winInetTransactionP->szHostName, winInetTransactionP->nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); /* Start our request running. */ if (winInetTransactionP->bUseSSL == TRUE) reqFlags |= INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID; winInetTransactionP->hHttpRequest = HttpOpenRequest(winInetTransactionP->hURL, "POST", winInetTransactionP->szUrlPath, "HTTP/1.1", NULL, (const char **)&acceptTypes, reqFlags, 1); XMLRPC_FAIL_IF_NULL(winInetTransactionP->hHttpRequest, envP, XMLRPC_INTERNAL_ERROR, "Unable to open the requested URL."); succeeded = HttpAddRequestHeaders(winInetTransactionP->hHttpRequest, winInetTransactionP->headerList, strlen (winInetTransactionP->headerList), HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE); if (!succeeded) XMLRPC_FAIL(envP, XMLRPC_INTERNAL_ERROR, "Could not set Content-Type."); { /* By default, a request times out after 30 seconds. We don't want it to timeout at all, since we don't know what the user is doing. */ DWORD dwTimeOut = 0x7FFFFFFF; /* Approximation of infinity */ InternetSetOption(winInetTransactionP->hHttpRequest, INTERNET_OPTION_RECEIVE_TIMEOUT, &dwTimeOut, sizeof(dwTimeOut)); } Again: /* Send the requested XML remote procedure command */ succeeded = HttpSendRequest(winInetTransactionP->hHttpRequest, NULL, 0, winInetTransactionP->pSendData, strlen(winInetTransactionP->pSendData)); if (!succeeded) { LPTSTR pMsg; lastErr = GetLastError(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pMsgMem, 0, NULL); if (pMsgMem == NULL) { switch (lastErr) { case ERROR_INTERNET_CANNOT_CONNECT: pMsg = "Sync HttpSendRequest failed: Connection refused."; break; case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED: pMsg = "Sync HttpSendRequest failed: " "Client authorization certificate needed."; break; /* The following conditions are recommendations that microsoft */ /* provides in their knowledge base. */ /* HOWTO: Handle Invalid Certificate Authority Error with WinInet (Q182888) */ case ERROR_INTERNET_INVALID_CA: if (clientTransportP->allowInvalidSSLCerts){ OutputDebugString( "Sync HttpSendRequest failed: " "The function is unfamiliar with the certificate " "authority that generated the server's certificate. "); reqFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA; InternetSetOption(winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS, &reqFlags, sizeof(reqFlags)); goto Again; } else pMsg = "Invalid or unknown/untrusted " "SSL Certificate Authority."; break; /* HOWTO: Make SSL Requests Using WinInet (Q168151) */ case ERROR_INTERNET_SEC_CERT_CN_INVALID: if (clientTransportP->allowInvalidSSLCerts) { OutputDebugString( "Sync HttpSendRequest failed: " "The SSL certificate common name (host name field) " "is incorrect\r\n " "for example, if you entered www.server.com " "and the common name " "on the certificate says www.different.com. "); reqFlags = INTERNET_FLAG_IGNORE_CERT_CN_INVALID; InternetSetOption(winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS, &reqFlags, sizeof(reqFlags)); goto Again; } else pMsg = "The SSL certificate common name " "(host name field) is incorrect."; break; case ERROR_INTERNET_SEC_CERT_DATE_INVALID: if (clientTransportP->allowInvalidSSLCerts) { OutputDebugString( "Sync HttpSendRequest failed: " "The SSL certificate date that was received " "from the server is " "bad. The certificate is expired. "); reqFlags = INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; InternetSetOption(winInetTransactionP->hHttpRequest, INTERNET_OPTION_SECURITY_FLAGS, &reqFlags, sizeof(reqFlags)); goto Again; } else pMsg = "The SSL certificate date that was received " "from the server is invalid."; break; default: pMsg = (LPTSTR)pMsgMem = LocalAlloc(LPTR, MAX_PATH); sprintf(pMsg, "Sync HttpSendRequest failed: " "GetLastError (%d)", lastErr); break; } } else pMsg = (LPTSTR)pMsgMem; XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, pMsg); } queryLen = sizeof(unsigned long); /* initial value */ succeeded = HttpQueryInfo(winInetTransactionP->hHttpRequest, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE, &winInetTransactionP->http_status, &queryLen, NULL); if (!succeeded) { LPTSTR pMsg; lastErr = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, lastErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pMsgMem, 1024, NULL); pMsg = pMsgMem ? (LPTSTR)pMsgMem : "Sync HttpQueryInfo failed."; XMLRPC_FAIL(envP, XMLRPC_NETWORK_ERROR, pMsg); } /* Make sure we got a "200 OK" message from the remote server. */ if (winInetTransactionP->http_status != 200) { unsigned long msgLen; char errMsg[1024]; errMsg[0] = '\0'; msgLen = 1024; /* initial value */ HttpQueryInfo(winInetTransactionP->hHttpRequest, HTTP_QUERY_STATUS_TEXT, errMsg, &msgLen, NULL); xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "HTTP error #%d occurred\n %s", winInetTransactionP->http_status, errMsg); goto cleanup; } /* Read the response. */ get_wininet_response(envP, winInetTransactionP); XMLRPC_FAIL_IF_FAULT(envP); cleanup: /* Since the XMLRPC_FAIL calls goto cleanup, we must handle */ /* the free'ing of the memory here. */ if (pMsgMem) LocalFree(pMsgMem); } static void * doAsyncRpc(void * const arg) { rpc * const rpcP = arg; xmlrpc_env env; xmlrpc_env_init(&env); performWinInetTransaction(&env, rpcP->winInetTransactionP, rpcP->clientTransportP ); rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env); xmlrpc_env_clean(&env); return NULL; } static void createRpcThread(xmlrpc_env * const envP, rpc * const rpcP, pthread_t * const threadP) { int rc; rc = pthread_create(threadP, NULL, doAsyncRpc, rpcP); switch (rc) { case 0: break; case EAGAIN: xmlrpc_faultf(envP, "pthread_create() failed: " "System Resources exceeded."); break; case EINVAL: xmlrpc_faultf(envP, "pthread_create() failed: " "Param Error for attr."); break; case ENOMEM: xmlrpc_faultf(envP, "pthread_create() failed: " "No memory for new thread."); break; default: xmlrpc_faultf(envP, "pthread_create() failed: " "Unrecognized error code %d.", rc); break; } } static void rpcCreate(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block * const responseXmlP, xmlrpc_transport_asynch_complete complete, struct xmlrpc_call_info * const callInfoP, rpc ** const rpcPP) { rpc * rpcP; MALLOCVAR(rpcP); if (rpcP == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for rpc object"); else { rpcP->callInfoP = callInfoP; rpcP->complete = complete; rpcP->responseXmlP = responseXmlP; rpcP->threadExists = FALSE; createWinInetTransaction(envP, serverP, callXmlP, responseXmlP, &rpcP->winInetTransactionP); if (!envP->fault_occurred) { if (complete) { createRpcThread(envP, rpcP, &rpcP->thread); if (!envP->fault_occurred) rpcP->threadExists = TRUE; } if (!envP->fault_occurred) { list_init_header(&rpcP->link, rpcP); clientTransportP->listLockP->acquire( clientTransportP->listLockP); list_add_head(&clientTransportP->rpcList, &rpcP->link); clientTransportP->listLockP->release( clientTransportP->listLockP); } if (envP->fault_occurred) destroyWinInetTransaction(rpcP->winInetTransactionP); } if (envP->fault_occurred) free(rpcP); } *rpcPP = rpcP; } static void rpcDestroy(rpc * const rpcP) { XMLRPC_ASSERT_PTR_OK(rpcP); XMLRPC_ASSERT(!rpcP->threadExists); destroyWinInetTransaction(rpcP->winInetTransactionP); list_remove(&rpcP->link); free(rpcP); } static void * finishRpc(struct list_head * const headerP, void * const context ATTR_UNUSED) { rpc * const rpcP = headerP->itemP; if (rpcP->threadExists) { void * status; int result; result = pthread_join(rpcP->thread, &status); rpcP->threadExists = FALSE; } XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP); rpcDestroy(rpcP); return NULL; } /* Used for debugging purposes to track the status of your request. */ void CALLBACK statusCallback (HINTERNET const hInternet, unsigned long const dwContext, unsigned long const dwInternetStatus, void * const lpvStatusInformation, unsigned long const dwStatusInformationLength) { switch (dwInternetStatus) { case INTERNET_STATUS_RESOLVING_NAME: OutputDebugString("INTERNET_STATUS_RESOLVING_NAME\r\n"); break; case INTERNET_STATUS_NAME_RESOLVED: OutputDebugString("INTERNET_STATUS_NAME_RESOLVED\r\n"); break; case INTERNET_STATUS_HANDLE_CREATED: OutputDebugString("INTERNET_STATUS_HANDLE_CREATED\r\n"); break; case INTERNET_STATUS_CONNECTING_TO_SERVER: OutputDebugString("INTERNET_STATUS_CONNECTING_TO_SERVER\r\n"); break; case INTERNET_STATUS_REQUEST_SENT: OutputDebugString("INTERNET_STATUS_REQUEST_SENT\r\n"); break; case INTERNET_STATUS_SENDING_REQUEST: OutputDebugString("INTERNET_STATUS_SENDING_REQUEST\r\n"); break; case INTERNET_STATUS_CONNECTED_TO_SERVER: OutputDebugString("INTERNET_STATUS_CONNECTED_TO_SERVER\r\n"); break; case INTERNET_STATUS_RECEIVING_RESPONSE: OutputDebugString("INTERNET_STATUS_RECEIVING_RESPONSE\r\n"); break; case INTERNET_STATUS_RESPONSE_RECEIVED: OutputDebugString("INTERNET_STATUS_RESPONSE_RECEIVED\r\n"); break; case INTERNET_STATUS_CLOSING_CONNECTION: OutputDebugString("INTERNET_STATUS_CLOSING_CONNECTION\r\n"); break; case INTERNET_STATUS_CONNECTION_CLOSED: OutputDebugString("INTERNET_STATUS_CONNECTION_CLOSED\r\n"); break; case INTERNET_STATUS_HANDLE_CLOSING: OutputDebugString("INTERNET_STATUS_HANDLE_CLOSING\r\n"); break; case INTERNET_STATUS_CTL_RESPONSE_RECEIVED: OutputDebugString("INTERNET_STATUS_CTL_RESPONSE_RECEIVED\r\n"); break; case INTERNET_STATUS_REDIRECT: OutputDebugString("INTERNET_STATUS_REDIRECT\r\n"); break; case INTERNET_STATUS_REQUEST_COMPLETE: /* This indicates the data is ready. */ OutputDebugString("INTERNET_STATUS_REQUEST_COMPLETE\r\n"); break; default: OutputDebugString("statusCallback, default case!\r\n"); break; } } static void create(xmlrpc_env * const envP, int const flags ATTR_UNUSED, const char * const appname ATTR_UNUSED, const char * const appversion ATTR_UNUSED, const void * const transportparmsP, size_t const parm_size, struct xmlrpc_client_transport ** const handlePP) { /*---------------------------------------------------------------------------- This does the 'create' operation for a WinInet client transport. -----------------------------------------------------------------------------*/ const struct xmlrpc_wininet_xportparms * const wininetXportParmsP = transportparmsP; struct xmlrpc_client_transport * transportP; MALLOCVAR(transportP); if (transportP == NULL) xmlrpc_faultf(envP, "Unable to allocate transport descriptor."); else { transportP->listLockP = xmlrpc_lock_create(); list_make_empty(&transportP->rpcList); if (hSyncInternetSession == NULL) hSyncInternetSession = InternetOpen("xmlrpc-c wininet transport", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!wininetXportParmsP || parm_size < XMLRPC_WXPSIZE(allowInvalidSSLCerts)) transportP->allowInvalidSSLCerts = 0; else transportP->allowInvalidSSLCerts = wininetXportParmsP->allowInvalidSSLCerts; *handlePP = transportP; } } static void destroy(struct xmlrpc_client_transport * const clientTransportP) { /*---------------------------------------------------------------------------- This does the 'destroy' operation for a WinInet client transport. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT(clientTransportP != NULL); XMLRPC_ASSERT(list_is_empty(&clientTransportP->rpcList)); if (hSyncInternetSession) InternetCloseHandle(hSyncInternetSession); hSyncInternetSession = NULL; clientTransportP->listLockP->destroy(clientTransportP->listLockP); free(clientTransportP); } static void sendRequest(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_transport_asynch_complete complete, xmlrpc_transport_progress progress, struct xmlrpc_call_info * const callInfoP) { /*---------------------------------------------------------------------------- Initiate an XML-RPC rpc asynchronously. Don't wait for it to go to the server. Unless we return failure, we arrange to have complete() called when the rpc completes. This does the 'send_request' operation for a WinInet client transport. -----------------------------------------------------------------------------*/ rpc * rpcP; xmlrpc_mem_block * responseXmlP; responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); if (!envP->fault_occurred) { rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP, complete, callInfoP, &rpcP); if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, responseXmlP); } /* The user's eventual finish_asynch call will destroy this RPC and response buffer */ } static void finishAsynch(struct xmlrpc_client_transport * const clientTransportP, xmlrpc_timeoutType const timeoutType ATTR_UNUSED, xmlrpc_timeout const timeout ATTR_UNUSED) { /*---------------------------------------------------------------------------- Wait for the threads of all outstanding RPCs to exit and destroy those RPCs. This does the 'finish_asynch' operation for a WinInet client transport. -----------------------------------------------------------------------------*/ /* We ignore any timeout request. Some day, we should figure out how to set an alarm and interrupt running threads. */ clientTransportP->listLockP->acquire(clientTransportP->listLockP); list_foreach(&clientTransportP->rpcList, finishRpc, NULL); clientTransportP->listLockP->release(clientTransportP->listLockP); } static void call(xmlrpc_env * const envP, struct xmlrpc_client_transport * const clientTransportP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block ** const responsePP) { xmlrpc_mem_block * responseXmlP; rpc * rpcP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(serverP); XMLRPC_ASSERT_PTR_OK(callXmlP); XMLRPC_ASSERT_PTR_OK(responsePP); responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); if (!envP->fault_occurred) { rpcCreate(envP, clientTransportP, serverP, callXmlP, responseXmlP, NULL, NULL, &rpcP); if (!envP->fault_occurred) { performWinInetTransaction(envP, rpcP->winInetTransactionP, clientTransportP); *responsePP = responseXmlP; rpcDestroy(rpcP); } if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, responseXmlP); } } struct xmlrpc_client_transport_ops xmlrpc_wininet_transport_ops = { NULL, NULL, &create, &destroy, &sendRequest, &call, &finishAsynch, NULL, }; /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/missing000077500000000000000000000142131236133176700150210ustar00rootroot00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. # Copyright (C) 1996, 1997 Free Software Foundation, Inc. # Franc,ois Pinard , 1996. # 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, 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. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi case "$1" in -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch]" ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing - GNU libit 0.0" ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; aclocal) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acinclude.m4' or \`configure.in'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`configure.in'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`acconfig.h' or \`configure.in'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is missing on your system. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` fi touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and you do not seem to have it handy on your system. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequirements for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 xmlrpc-c-1.33.14/mkinstalldirs000077500000000000000000000013221236133176700162250ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $ errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here xmlrpc-c-1.33.14/src/000077500000000000000000000000001236133176700142105ustar00rootroot00000000000000xmlrpc-c-1.33.14/src/Makefile000066400000000000000000000243121236133176700156520ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') SRCDIR := $(call updir,$(CURDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := src include $(BLDDIR)/config.mk default: all SUBDIRS = ifeq ($(ENABLE_CPLUSPLUS),yes) SUBDIRS += cpp endif TARGET_LIBRARY_NAMES := libxmlrpc libxmlrpc_server # We cannot build libxmlrpc_server_abyss if we can't also build Abyss, # because we need libxmlrpc_abyss in order to build the proper runtime # dependencies into libxmlrpc_server_abyss. ifeq ($(ENABLE_ABYSS_SERVER),yes) TARGET_LIBRARY_NAMES += libxmlrpc_server_abyss endif ifeq ($(MUST_BUILD_CLIENT),yes) TARGET_LIBRARY_NAMES += libxmlrpc_client endif ifeq ($(ENABLE_CGI_SERVER),yes) TARGET_LIBRARY_NAMES += libxmlrpc_server_cgi endif STATIC_LIBRARIES_TO_INSTALL = $(TARGET_STATIC_LIBRARIES) SHARED_LIBS_TO_BUILD := $(TARGET_LIBRARY_NAMES) SHARED_LIBS_TO_INSTALL := $(TARGET_LIBRARY_NAMES) # TRANSPORT_MODS is the list of modules that have to go into the client # library to provide the client XML transport functions. # TRANSPORT_LIBDEP is linker -l options to declare what libraries contain # things to which the transport objects refer. (like LIBxxx_LIBDEP -- # see below) TRANSPORT_MODS = TRANSPORT_LIBDEP = TRANSPORT_INCLUDES = ifeq ($(MUST_BUILD_WININET_CLIENT),yes) TRANSPORT_MODS += $(BLDDIR)/lib/wininet_transport/xmlrpc_wininet_transport TRANSPORT_LIBDEP += $(shell wininet-config --libs) TRANSPORT_INCLUDES += -Isrcdir/lib/wininet_transport endif ifeq ($(MUST_BUILD_CURL_CLIENT),yes) TRANSPORT_MODS += $(BLDDIR)/lib/curl_transport/xmlrpc_curl_transport TRANSPORT_MODS += $(BLDDIR)/lib/curl_transport/curltransaction TRANSPORT_MODS += $(BLDDIR)/lib/curl_transport/curlmulti TRANSPORT_LIBDEP += $(shell curl-config --libs) TRANSPORT_INCLUDES += -Isrcdir/lib/curl_transport endif ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) TRANSPORT_MODS += $(BLDDIR)/lib/libwww_transport/xmlrpc_libwww_transport TRANSPORT_LIBDEP += $(shell libwww-config --libs) TRANSPORT_INCLUDES += -Isrcdir/lib/libwww_transport endif ifeq ($(ENABLE_LIBXML2_BACKEND),yes) XMLRPC_XML_PARSER = xmlrpc_libxml2 XML_PARSER_LIBDEP = $(shell xml2-config --libs) XML_PARSER_LIBDEP_DEP = else XMLRPC_XML_PARSER = xmlrpc_expat XML_PARSER_LIBDEP = \ -Lblddir/lib/expat/xmlparse -lxmlrpc_xmlparse \ -Lblddir/lib/expat/xmltok -lxmlrpc_xmltok XML_PARSER_LIBDEP_DEP = $(LIBXMLRPC_XMLPARSE) $(LIBXMLRPC_XMLTOK) endif # LIBxxx_OBJS is the list of object files that make up library libxxx. LIBXMLRPC_MODS = \ base_global \ double \ json \ parse_datetime \ parse_value \ resource \ trace \ version \ xmlrpc_data \ xmlrpc_datetime \ xmlrpc_string \ xmlrpc_array \ xmlrpc_struct \ xmlrpc_build \ xmlrpc_decompose \ $(XMLRPC_XML_PARSER) \ xmlrpc_parse \ xmlrpc_serialize \ xmlrpc_authcookie \ LIBXMLRPC_CLIENT_MODS = xmlrpc_client xmlrpc_client_global xmlrpc_server_info LIBXMLRPC_SERVER_MODS = registry method system_method LIBXMLRPC_SERVER_ABYSS_MODS = xmlrpc_server_abyss abyss_handler LIBXMLRPC_SERVER_CGI_MODS = xmlrpc_server_cgi TARGET_MODS = \ $(LIBXMLRPC_MODS) \ $(LIBXMLRPC_SERVER_MODS) \ $(LIBXMLRPC_SERVER_ABYSS_MODS) \ $(LIBXMLRPC_SERVER_CGI_MODS) \ $(LIBXMLRPC_CLIENT_MODS) \ OMIT_XMLRPC_LIB_RULE=Y MAJ=3 # Major number of shared libraries in this directory include $(SRCDIR)/common.mk # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir # TARGET_STATIC_LIBRARIES, etc. are set by common.mk, based on # TARGET_LIBRARY_NAMES. all: \ $(TARGET_STATIC_LIBRARIES) \ $(TARGET_SHARED_LIBRARIES) \ $(TARGET_SHARED_LE_LIBS) \ $(SUBDIRS:%=%/all) \ # Extra dependencies to make parallel make work in spite of all the submakes # (See top level make file for details) cpp/all: $(TARGET_SHARED_LE_LIBS) ifeq ($MUST_BUILD_CLIENT),yes) cpp/all: $(BLDDIR)/transport_config.h endif #----------------------------------------------------------------------------- # RULES TO LINK LIBRARIES #----------------------------------------------------------------------------- # Rules for these are in common.mk, courtesy of TARGET_LIBRARY_NAMES: # shlibfn generates e.g. libxmlrpc.so.3.1 # shliblefn generates e.g. libxmlrpc.so LIBXMLRPC = $(call shlibfn, libxmlrpc) $(LIBXMLRPC): $(LIBXMLRPC_MODS:%=%.osh) \ $(LIBXMLRPC_UTIL) \ $(XML_PARSER_LIBDEP_DEP) $(LIBXMLRPC): LIBOBJECTS = $(LIBXMLRPC_MODS:%=%.osh) $(LIBXMLRPC): LIBDEP = \ $(LIBXMLRPC_UTIL_LIBDEP) \ $(XML_PARSER_LIBDEP) LIBXMLRPC_SERVER = $(call shlibfn, libxmlrpc_server) $(LIBXMLRPC_SERVER): \ $(LIBXMLRPC_SERVER_MODS:%=%.osh) \ $(LIBXMLRPC_UTIL) \ $(call shliblefn, libxmlrpc) $(LIBXMLRPC_SERVER): LIBOBJECTS = $(LIBXMLRPC_SERVER_MODS:%=%.osh) $(LIBXMLRPC_SERVER): LIBDEP = \ -L. -lxmlrpc $(XML_PARSER_LIBDEP) $(LIBXMLRPC_UTIL_LIBDEP) LIBXMLRPC_SERVER_ABYSS = $(call shlibfn, libxmlrpc_server_abyss) $(LIBXMLRPC_SERVER_ABYSS): \ $(LIBXMLRPC_SERVER_ABYSS_MODS:%=%.osh) \ $(LIBXMLRPC_UTIL) \ $(LIBXMLRPC_ABYSS) \ $(call shliblefn, libxmlrpc_server) \ $(call shliblefn, libxmlrpc) $(LIBXMLRPC_SERVER_ABYSS): LIBOBJECTS = $(LIBXMLRPC_SERVER_ABYSS_MODS:%=%.osh) $(LIBXMLRPC_SERVER_ABYSS): LIBDEP = \ -L. -lxmlrpc_server \ -L$(LIBXMLRPC_ABYSS_DIR) -lxmlrpc_abyss \ -L. -lxmlrpc $(XML_PARSER_LIBDEP) $(LIBXMLRPC_UTIL_LIBDEP) ifeq ($(MSVCRT),yes) $(LIBXMLRPC_SERVER_ABYSS): LIBDEP += -lws2_32 -lwsock32 endif LIBXMLRPC_SERVER_CGI = $(call shlibfn, libxmlrpc_server_cgi) $(LIBXMLRPC_SERVER_CGI): \ $(LIBXMLRPC_SERVER_CGI_MODS:%=%.osh) \ $(LIBXMRPC_UTIL) \ $(call shliblefn, libxmlrpc_server) \ $(call shliblefn, libxmlrpc) $(LIBXMLRPC_SERVER_CGI): LIBOBJECTS = $(LIBXMLRPC_SERVER_CGI_MODS:%=%.osh) $(LIBXMLRPC_SERVER_CGI): LIBDEP = \ -L. -lxmlrpc_server \ -L. -lxmlrpc $(XML_PARSER_LIBDEP) $(LIBXMLRPC_UTIL_LIBDEP) LIBXMLRPC_CLIENT = $(call shlibfn, libxmlrpc_client) $(LIBXMLRPC_CLIENT): \ $(LIBXMLRPC_CLIENT_MODS:%=%.osh) \ $(TRANSPORT_MODS:%=%.osh) \ $(LIBXMLRPC_UTIL) \ $(call shliblefn, libxmlrpc) $(LIBXMLRPC_CLIENT): LIBOBJECTS = \ $(LIBXMLRPC_CLIENT_MODS:%=%.osh) \ $(TRANSPORT_MODS:%=%.osh) # We try to get Xmlrpc-c directories early in the link library search # path to avert problems with other versions of Xmlrpc-c being in more # general directories (such as /usr/local/lib) that are added to the # search path by curl-config, etc. That's why we separate the -L from # the corresponding -l. # # Note that in a properly configured system, curl-config, etc. do not # generate -L options for general directories. LIBXMLRPC_CLIENT_LIBDEP = \ -Lblddir/src -Lblddir/lib/libutil \ -lxmlrpc -lxmlrpc_util \ $(XML_PARSER_LIBDEP) \ $(TRANSPORT_LIBDEP) \ $(LIBXMLRPC_CLIENT): LIBDEP = $(LIBXMLRPC_CLIENT_LIBDEP) ifeq ($(MSVCRT),yes) $(LIBXMLRPC_CLIENT): LIBDEP += -lws2_32 -lwsock32 -lpthread endif libxmlrpc.a: $(LIBXMLRPC_MODS:%=%.o) libxmlrpc.a: LIBOBJECTS = $(LIBXMLRPC_MODS:%=%.o) libxmlrpc_server.a: $(LIBXMLRPC_SERVER_MODS:%=%.o) libxmlrpc_server.a: LIBOBJECTS = $(LIBXMLRPC_SERVER_MODS:%=%.o) libxmlrpc_server_abyss.a: $(LIBXMLRPC_SERVER_ABYSS_MODS:%=%.o) libxmlrpc_server_abyss.a: LIBOBJECTS=$(LIBXMLRPC_SERVER_ABYSS_MODS:%=%.o) libxmlrpc_server_cgi.a: $(LIBXMLRPC_SERVER_CGI_MODS:%=%.o) libxmlrpc_server_cgi.a: LIBOBJECTS=$(LIBXMLRPC_SERVER_CGI_MODS:%=%.o) libxmlrpc_client.a: $(LIBXMLRPC_CLIENT_MODS:%=%.o) $(TRANSPORT_MODS:%=%.o) libxmlrpc_client.a: LIBOBJECTS = \ $(LIBXMLRPC_CLIENT_MODS:%=%.o) \ $(TRANSPORT_MODS:%=%.o) #----------------------------------------------------------------------------- # RULES TO COMPILE OBJECT MODULES FOR LIBRARIES #----------------------------------------------------------------------------- # Rules for these are in common.mk, courtesy of TARGET_MODS: BASIC_INCLUDES = \ -Iblddir \ -Iblddir/include \ -Isrcdir/include \ -Isrcdir/lib/util/include \ ifeq ($(ENABLE_LIBXML2_BACKEND),yes) LIBXML_INCLUDES = $(shell xml2-config --cflags) else LIBXML_INCLUDES = -Isrcdir/lib/expat/xmlparse endif $(LIBXMLRPC_MODS:%=%.o) \ $(LIBXMLRPC_MODS:%=%.osh): \ INCLUDES = $(BASIC_INCLUDES) $(LIBXML_INCLUDES) $(LIBXMLRPC_CLIENT_MODS:%=%.o) \ $(LIBXMLRPC_CLIENT_MODS:%=%.osh): \ INCLUDES = $(BASIC_INCLUDES) $(TRANSPORT_INCLUDES) $(LIBXMLRPC_SERVER_MODS:%=%.o) \ $(LIBXMLRPC_SERVER_MODS:%=%.osh): \ INCLUDES = $(BASIC_INCLUDES) $(LIBXMLRPC_SERVER_ABYSS_MODS:%=%.o) \ $(LIBXMLRPC_SERVER_ABYSS_MODS:%=%.osh): \ INCLUDES = $(BASIC_INCLUDES) -Isrcdir/lib/abyss/src $(LIBXMLRPC_SERVER_CGI_MODS:%=%.o) \ $(LIBXMLRPC_SERVER_CGI_MODS:%=%.osh): \ INCLUDES = $(BASIC_INCLUDES) #----------------------------------------------------------------------------- # RULES TO MAKE CFLAGS/LDFLAGS FILES # # These are for builds in other directories of things that use libraries in # this directory. E.g. when you build libxmlrpc_client++, it depends upon # libxmlrpc_client from this directory. So the link of libxmlrpc_client++ # must specify a dependency upon libxmlrpc_client and any library upon which # libxmlrpc_client depends, so the link command for libxmlrpc_client++ # $(shell cat libxmlrpc_client.ldflags). # # Note that some systems don't need this because there is information in # libxmlrpc_client that tells libxmlrpc_client's dependencies, so you need # only find libxmlrpc_client to generate libxmlrpc_client++. #----------------------------------------------------------------------------- libxmlrpc_client.cflags: echo "$(TRANSPORT_INCLUDES)" >$@ libxmlrpc_client.ldflags: echo "-Lblddir/src -lxmlrpc_client $(LIBXMLRPC_CLIENT_LIBDEP)" >$@ #----------------------------------------------------------------------------- .PHONY: check check: .PHONY: install install: install-common $(SUBDIRS:%=%/install) .PHONY: clean clean-local distclean distclean-local clean: $(SUBDIRS:%=%/clean) clean-common clean-local clean-local: distclean: $(SUBDIRS:%=%/distclean) clean distclean-local distclean-common distclean-local: rm -f *.cflags *.ldflags .PHONY: dep dep: $(SUBDIRS:%=%/dep) $(BLDDIR)/transport_config.h dep-common dep-common: INCLUDES = $(BASIC_INCLUDES) $(TRANSPORT_INCLUDES) $(LIBXML_INCLUDES) xmlrpc_client.o xmlrpc_client.osh: $(BLDDIR)/transport_config.h xmlrpc_client.o xmlrpc_client.osh: $(BLDDIR)/version.h registry.o registry.osh: $(BLDDIR)/version.h version.o version.osh: $(BLDDIR)/version.h include depend.mk xmlrpc-c-1.33.14/src/abyss_handler.c000066400000000000000000000512731236133176700172020ustar00rootroot00000000000000#include "xmlrpc_config.h" #define _XOPEN_SOURCE 600 /* For strdup(), sigaction */ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/abyss.h */ #include #include #include #include #include #include #include #ifdef _WIN32 # include #else # include # include # include #endif #include "bool.h" #include "int.h" #include "mallocvar.h" #include "xmlrpc-c/abyss.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "abyss_handler.h" static const char * trace_abyss; void xmlrpc_abyss_handler_trace(const char * const trace) { trace_abyss = trace; } static void addAuthCookie(xmlrpc_env * const envP, TSession * const abyssSessionP, const char * const authCookie) { const char * cookieResponse; xmlrpc_asprintf(&cookieResponse, "auth=%s", authCookie); if (xmlrpc_strnomem(cookieResponse)) xmlrpc_faultf(envP, "Insufficient memory to generate cookie " "response header."); else { ResponseAddField(abyssSessionP, "Set-Cookie", cookieResponse); xmlrpc_strfree(cookieResponse); } } static void sendResponse(xmlrpc_env * const envP, TSession * const abyssSessionP, const char * const body, size_t const len, bool const chunked, ResponseAccessCtl const accessControl) { /*---------------------------------------------------------------------------- Generate an HTTP response containing body 'body' of length 'len' characters. This is meant to run in the context of an Abyss URI handler for Abyss session 'abyssSessionP'. -----------------------------------------------------------------------------*/ const char * http_cookie = NULL; /* This used to set http_cookie to getenv("HTTP_COOKIE"), but that doesn't make any sense -- environment variables are not appropriate for this. So for now, cookie code is disabled. - Bryan 2004.10.03. */ /* Various bugs before Xmlrpc-c 1.05 caused the response to be not chunked in the most basic case, but chunked if the client explicitly requested keepalive. I think it's better not to chunk, because it's simpler, so I removed this in 1.05. I don't know what the purpose of chunking would be, and an original comment suggests the author wasn't sure chunking was a good idea. In 1.06 we added the user option to chunk. */ if (chunked) ResponseChunked(abyssSessionP); ResponseStatus(abyssSessionP, 200); if (http_cookie) /* There's an auth cookie, so pass it back in the response. */ addAuthCookie(envP, abyssSessionP, http_cookie); if ((size_t)(uint32_t)len != len) xmlrpc_faultf(envP, "XML-RPC method generated a response too " "large for Abyss to send"); else { uint32_t const abyssLen = (uint32_t)len; /* See discussion below of quotes around "utf-8" */ ResponseContentType(abyssSessionP, "text/xml; charset=utf-8"); ResponseContentLength(abyssSessionP, abyssLen); ResponseAccessControl(abyssSessionP, accessControl); ResponseWriteStart(abyssSessionP); ResponseWriteBody(abyssSessionP, body, abyssLen); ResponseWriteEnd(abyssSessionP); } } /* From 0.9.10 (May 2001) through 1.17 (December 2008), the content-type header said charset="utf-8" (i.e. with the value of 'charset' an HTTP quoted string). Before 0.9.10, the header didn't have charset at all. We got a complaint in January 2009 that some client didn't understand that, saying apache2: XML-RPC: xmlrpcmsg::parseResponse: invalid charset encoding of received response: "UTF-8" And that removing the quotation marks fixes this. From what I can tell, the module is wrong to distinguish between the two, but I don't think it hurts anything to use a basic HTTP token instead of an HTTP quoted string here, so starting in 1.18, we do. */ static void sendError(TSession * const abyssSessionP, unsigned int const status, const char * const explanation) { /*---------------------------------------------------------------------------- Send an error response back to the client. -----------------------------------------------------------------------------*/ ResponseStatus(abyssSessionP, (uint16_t) status); ResponseError2(abyssSessionP, explanation); } static void traceChunkRead(TSession * const abyssSessionP) { fprintf(stderr, "XML-RPC handler got a chunk of %u bytes\n", (unsigned int)SessionReadDataAvail(abyssSessionP)); } static void refillBufferFromConnection(xmlrpc_env * const envP, TSession * const abyssSessionP, const char * const trace) { /*---------------------------------------------------------------------------- Get the next chunk of data from the connection into the buffer. -----------------------------------------------------------------------------*/ bool succeeded; succeeded = SessionRefillBuffer(abyssSessionP); if (!succeeded) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TIMEOUT_ERROR, "Timed out waiting for " "client to send its POST data"); else { if (trace) traceChunkRead(abyssSessionP); } } static void getBody(xmlrpc_env * const envP, TSession * const abyssSessionP, size_t const contentSize, const char * const trace, xmlrpc_mem_block ** const bodyP) { /*---------------------------------------------------------------------------- Get the entire body, which is of size 'contentSize' bytes, from the Abyss session and return it as the new memblock *bodyP. The first chunk of the body may already be in Abyss's buffer. We retrieve that before reading more. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * body; if (trace) fprintf(stderr, "XML-RPC handler processing body. " "Content Size = %u bytes\n", (unsigned)contentSize); body = xmlrpc_mem_block_new(envP, 0); if (!envP->fault_occurred) { size_t bytesRead; const char * chunkPtr; size_t chunkLen; bytesRead = 0; while (!envP->fault_occurred && bytesRead < contentSize) { SessionGetReadData(abyssSessionP, contentSize - bytesRead, &chunkPtr, &chunkLen); bytesRead += chunkLen; assert(bytesRead <= contentSize); XMLRPC_MEMBLOCK_APPEND(char, envP, body, chunkPtr, chunkLen); if (bytesRead < contentSize) refillBufferFromConnection(envP, abyssSessionP, trace); } if (envP->fault_occurred) xmlrpc_mem_block_free(body); } *bodyP = body; } static void storeCookies(TSession * const httpRequestP, const char ** const errorP) { /*---------------------------------------------------------------------------- Get the cookie settings from the HTTP headers and remember them for use in responses. -----------------------------------------------------------------------------*/ const char * const cookie = RequestHeaderValue(httpRequestP, "cookie"); if (cookie) { /* Setting the value in an environment variable doesn't make any sense. So for now, cookie code is disabled. -Bryan 04.10.03. setenv("HTTP_COOKIE", cookie, 1); */ } /* TODO: parse HTTP_COOKIE to find auth pair, if there is one */ *errorP = NULL; } static void processContentLength(TSession * const httpRequestP, size_t * const inputLenP, bool * const missingP, const char ** const errorP) { /*---------------------------------------------------------------------------- Make sure the content length is present and non-zero. This is technically required by XML-RPC, but we only enforce it because we don't want to figure out how to safely handle HTTP < 1.1 requests without it. -----------------------------------------------------------------------------*/ const char * const content_length = RequestHeaderValue(httpRequestP, "content-length"); if (content_length == NULL) { *missingP = TRUE; *errorP = NULL; } else { *missingP = FALSE; *inputLenP = 0; /* quiet compiler warning */ if (content_length[0] == '\0') xmlrpc_asprintf(errorP, "The value in your content-length " "HTTP header value is a null string"); else { unsigned long contentLengthValue; char * tail; contentLengthValue = strtoul(content_length, &tail, 10); if (*tail != '\0') xmlrpc_asprintf(errorP, "There's non-numeric crap in " "the value of your content-length " "HTTP header: '%s'", tail); else if (contentLengthValue < 1) xmlrpc_asprintf(errorP, "According to your content-length " "HTTP header, your request is empty (zero " "length)"); else if ((unsigned long)(size_t)contentLengthValue != contentLengthValue) xmlrpc_asprintf(errorP, "According to your content-length " "HTTP header, your request is too big to " "process; we can't even do arithmetic on its " "size: %s bytes", content_length); else { *errorP = NULL; *inputLenP = (size_t)contentLengthValue; } } } } static void traceHandlerCalled(TSession * const abyssSessionP) { const char * methodDesc; const TRequestInfo * requestInfoP; fprintf(stderr, "xmlrpc_server_abyss URI path handler called.\n"); SessionGetRequestInfo(abyssSessionP, &requestInfoP); fprintf(stderr, "URI = '%s'\n", requestInfoP->uri); switch (requestInfoP->method) { case m_unknown: methodDesc = "unknown"; break; case m_get: methodDesc = "get"; break; case m_put: methodDesc = "put"; break; case m_head: methodDesc = "head"; break; case m_post: methodDesc = "post"; break; case m_delete: methodDesc = "delete"; break; case m_trace: methodDesc = "trace"; break; case m_options: methodDesc = "m_options"; break; default: methodDesc = "?"; } fprintf(stderr, "HTTP method = '%s'\n", methodDesc); if (requestInfoP->query) fprintf(stderr, "query (component of URL)='%s'\n", requestInfoP->query); else fprintf(stderr, "URL has no query component\n"); } static void processCall(TSession * const abyssSessionP, size_t const contentSize, xmlrpc_call_processor xmlProcessor, void * const xmlProcessorArg, bool const wantChunk, ResponseAccessCtl const accessControl, const char * const trace) { /*---------------------------------------------------------------------------- Handle an RPC request. This is an HTTP request that has the proper form to be an XML-RPC call. The text of the call is available through the Abyss session 'abyssSessionP'. Its content length is 'contentSize' bytes. -----------------------------------------------------------------------------*/ xmlrpc_env env; if (trace) fprintf(stderr, "xmlrpc_server_abyss URI path handler processing RPC.\n"); xmlrpc_env_init(&env); if (contentSize > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) xmlrpc_env_set_fault_formatted( &env, XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large (%u bytes)", (unsigned)contentSize); else { xmlrpc_mem_block * body; /* Read XML data off the wire. */ getBody(&env, abyssSessionP, contentSize, trace, &body); if (!env.fault_occurred) { xmlrpc_mem_block * output; /* Process the RPC. */ xmlProcessor( &env, xmlProcessorArg, XMLRPC_MEMBLOCK_CONTENTS(char, body), XMLRPC_MEMBLOCK_SIZE(char, body), abyssSessionP, &output); if (!env.fault_occurred) { /* Send out the result. */ sendResponse(&env, abyssSessionP, XMLRPC_MEMBLOCK_CONTENTS(char, output), XMLRPC_MEMBLOCK_SIZE(char, output), wantChunk, accessControl); XMLRPC_MEMBLOCK_FREE(char, output); } XMLRPC_MEMBLOCK_FREE(char, body); } } if (env.fault_occurred) { uint16_t httpResponseStatus; if (env.fault_code == XMLRPC_TIMEOUT_ERROR) httpResponseStatus = 408; /* Request Timeout */ else httpResponseStatus = 500; /* Internal Server Error */ sendError(abyssSessionP, httpResponseStatus, env.fault_string); } xmlrpc_env_clean(&env); } void xmlrpc_initAccessCtl(ResponseAccessCtl * const accessCtlP, const char * const allowOrigin, bool const expires, unsigned int const maxAge) { /*---------------------------------------------------------------------------- Set up *accessCtlP to reflect the HTTP access control parameters 'allowOrigin', 'expires', and 'maxAge'. Note that 'maxAge' is irrelevant when 'expires' is false. -----------------------------------------------------------------------------*/ accessCtlP->allowOrigin = allowOrigin ? xmlrpc_strdupsol(allowOrigin) : NULL; accessCtlP->expires = expires; accessCtlP->maxAge = maxAge; } void xmlrpc_termAccessControl(ResponseAccessCtl * const accessCtlP) { xmlrpc_strfreenull(accessCtlP->allowOrigin); } void xmlrpc_termUriHandler(void * const arg) { struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = arg; xmlrpc_strfree(uriHandlerXmlrpcP->uriPath); xmlrpc_termAccessControl(&uriHandlerXmlrpcP->accessControl); free(uriHandlerXmlrpcP); } static void handleXmlRpcCallReq(TSession * const abyssSessionP, const TRequestInfo * const requestInfoP ATTR_UNUSED, xmlrpc_call_processor xmlProcessor, void * const xmlProcessorArg, bool const wantChunk, ResponseAccessCtl const accessControl) { /*---------------------------------------------------------------------------- Handle the HTTP request described by *requestInfoP, which arrived over Abyss HTTP session *abyssSessionP, which is an XML-RPC call (i.e. a POST request to /RPC2 or whatever other URI our server is supposed to handle). Handle it by feeding the XML which is its content to 'xmlProcessor' along with argument 'xmlProcessorArg'. -----------------------------------------------------------------------------*/ /* We used to reject the call if content-type was not present and text/xml, on some security theory (a firewall may block text/xml with the intent of blocking XML-RPC). Now, we believe that is silly, and we have seen an incorrectly implemented client that says text/plain. */ const char * error; assert(requestInfoP->method == m_post); storeCookies(abyssSessionP, &error); if (error) { sendError(abyssSessionP, 400, error); xmlrpc_strfree(error); } else { const char * error; bool missing; size_t contentSize; processContentLength(abyssSessionP, &contentSize, &missing, &error); if (error) { sendError(abyssSessionP, 400, error); xmlrpc_strfree(error); } else { if (missing) sendError(abyssSessionP, 411, "You must send a " "content-length HTTP header in an " "XML-RPC call."); else processCall(abyssSessionP, contentSize, xmlProcessor, xmlProcessorArg, wantChunk, accessControl, trace_abyss); } } } static void handleXmlRpcOptionsReq(TSession * const abyssSessionP, ResponseAccessCtl const accessControl) { ResponseAddField(abyssSessionP, "Allow", "POST"); ResponseAccessControl(abyssSessionP, accessControl); ResponseContentLength(abyssSessionP, 0); ResponseStatus(abyssSessionP, 200); ResponseWriteStart(abyssSessionP); ResponseWriteEnd(abyssSessionP); } void xmlrpc_handleIfXmlrpcReq(void * const handlerArg, TSession * const abyssSessionP, abyss_bool * const handledP) { /*---------------------------------------------------------------------------- Our job is to look at this HTTP request that the Abyss server is trying to process and see if we can handle it. If it's an XML-RPC call for this XML-RPC server, we handle it. If it's not, we refuse it and Abyss can try some other handler. Our return code is TRUE to mean we handled it; FALSE to mean we didn't. Note that failing the request counts as handling it, and not handling it does not mean we failed it. This is an Abyss HTTP Request handler -- type handleReqFn3. -----------------------------------------------------------------------------*/ struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = handlerArg; const TRequestInfo * requestInfoP; if (trace_abyss) traceHandlerCalled(abyssSessionP); SessionGetRequestInfo(abyssSessionP, &requestInfoP); /* Note that requestInfoP->uri is not the whole URI. It is just the "file name" part of it. */ if (!xmlrpc_streq(requestInfoP->uri, uriHandlerXmlrpcP->uriPath)) /* It's not for the path (e.g. "/RPC2") that we're supposed to handle. */ *handledP = FALSE; else { *handledP = TRUE; switch (requestInfoP->method) { case m_post: handleXmlRpcCallReq(abyssSessionP, requestInfoP, uriHandlerXmlrpcP->xmlProcessor, uriHandlerXmlrpcP->xmlProcessorArg, uriHandlerXmlrpcP->chunkResponse, uriHandlerXmlrpcP->accessControl); break; case m_options: handleXmlRpcOptionsReq(abyssSessionP, uriHandlerXmlrpcP->accessControl); break; default: sendError(abyssSessionP, 405, "POST is the only HTTP method this server understands"); /* 405 = Method Not Allowed */ } } if (trace_abyss) fprintf(stderr, "xmlrpc_server_abyss URI path handler returning.\n"); } unsigned int xmlrpc_abyss_handler_stacksize() { /*---------------------------------------------------------------------------- The maximum number of bytes an HTTP request handler in this file might place on the stack. This doesn't include what the user's method function requires. -----------------------------------------------------------------------------*/ return 1024; } abyss_bool xmlrpc_serverAbyssDefaultUriHandler(TSession * const sessionP) { /*---------------------------------------------------------------------------- This is an Abyss default handler. It return a 404 Not Found for all requests. -----------------------------------------------------------------------------*/ const TRequestInfo * requestInfoP; const char * explanation; if (trace_abyss) fprintf(stderr, "xmlrpc_server_abyss default handler called.\n"); SessionGetRequestInfo(sessionP, &requestInfoP); xmlrpc_asprintf( &explanation, "This XML-RPC For C/C++ Abyss XML-RPC server " "responds to only one URI path. " "I don't know what URI path that is, " "but it's not the one you requested: '%s'. (Typically, it's " "'/RPC2')", requestInfoP->uri); sendError(sessionP, 404, explanation); xmlrpc_strfree(explanation); return TRUE; } xmlrpc-c-1.33.14/src/abyss_handler.h000066400000000000000000000027651236133176700172110ustar00rootroot00000000000000#ifndef ABYSS_HANDER_H_INCLUDED #define ABYSS_HANDER_H_INCLUDED #include "xmlrpc-c/abyss.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/server_abyss.h" struct uriHandlerXmlrpc { /*---------------------------------------------------------------------------- This is the part of an Abyss HTTP request handler (aka URI handler) that is specific to the Xmlrpc-c handler. -----------------------------------------------------------------------------*/ xmlrpc_registry * registryP; const char * uriPath; /* malloc'ed */ bool chunkResponse; /* The handler should chunk its response whenever possible */ xmlrpc_call_processor * xmlProcessor; void * xmlProcessorArg; ResponseAccessCtl accessControl; }; void xmlrpc_termUriHandler(void * const arg); void xmlrpc_handleIfXmlrpcReq(void * const handlerArg, TSession * const abyssSessionP, abyss_bool * const handledP); abyss_bool xmlrpc_serverAbyssDefaultUriHandler(TSession * const sessionP); void xmlrpc_initAccessCtl(ResponseAccessCtl * const accessCtlP, const char * const allowOrigin, bool const expires, unsigned int const maxAge); void xmlrpc_termAccessControl(ResponseAccessCtl * const accessCtlP); void xmlrpc_abyss_handler_trace(const char * const trace); unsigned int xmlrpc_abyss_handler_stacksize(void); #endif xmlrpc-c-1.33.14/src/base_global.c000066400000000000000000000022721236133176700166110ustar00rootroot00000000000000#include "xmlrpc-c/base.h" #include "xmlrpc-c/xmlparser.h" static unsigned int globallyInitialized = 0; /* Initialization count */ /* It ought to be a requirement for any user of libxmlrpc to call xmlrpc_init(), but for ten years it wasn't, so we can't start requiring it now except for new services. One thing we know requires it (and always did, but didn't show up as a problem until 2012) is libxml2. Without a call to xmlrpc_init(), if libxmlrpc was built to use libxml2, the program leaks lots of memory. */ void xmlrpc_init(xmlrpc_env * const envP) { /* Note that this is specified as not thread safe; user calls it at the beginning of his program, when it is only one thread. */ XMLRPC_ASSERT_ENV_OK(envP); if (globallyInitialized == 0) { xml_init(envP); /* Initialize the XML parser library */ } ++globallyInitialized; } void xmlrpc_term(void) { /* Note that this is specified as not thread safe; user calls it at the end of his program, when it is only one thread. */ XMLRPC_ASSERT(globallyInitialized > 0); --globallyInitialized; if (globallyInitialized == 0) { xml_term(); } } xmlrpc-c-1.33.14/src/cpp/000077500000000000000000000000001236133176700147725ustar00rootroot00000000000000xmlrpc-c-1.33.14/src/cpp/Lock.cpp000066400000000000000000000017701236133176700163730ustar00rootroot00000000000000#include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "Lock.hpp" namespace xmlrpc_c { Lock::Holder::Holder(Lock * const lockP) /*----------------------------------------------------------------------------- Construct a holder of lock *lockP -- as long as this object exists, *lockP is locked. If *lockP is already locked, wait for it to be unlocked. -----------------------------------------------------------------------------*/ : lockP(lockP) { lockP->acquire(); } Lock::Holder::~Holder() { this->lockP->release(); } Lock::Lock() : c_lockP(xmlrpc_lock_create()){ if (this->c_lockP == NULL) throw(error("Failed to create lock. xmlrpc_lock_create() failed")); } Lock::~Lock() { this->c_lockP->destroy(this->c_lockP); } void Lock::acquire() { this->c_lockP->acquire(this->c_lockP); } void Lock::release() { this->c_lockP->release(this->c_lockP); } } // namespace xmlrpc-c-1.33.14/src/cpp/Lock.hpp000066400000000000000000000005071236133176700163750ustar00rootroot00000000000000struct lock; namespace xmlrpc_c { class Lock { public: class Holder { public: Holder(Lock * const lockP); ~Holder(); private: Lock * const lockP; }; Lock(); ~Lock(); void acquire(); void release(); private: lock * const c_lockP; }; } // namespace xmlrpc-c-1.33.14/src/cpp/Makefile000066400000000000000000000252421236133176700164370ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') srcDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(srcDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := src/cpp include $(BLDDIR)/config.mk default: all # libxmlrpc_cpp is the legacy C++ wrapper library. The others are the # more elaborate replacements. TARGET_LIB_NAMES_PP = \ libxmlrpc_cpp \ lib$(LIBXMLRPCPP_NAME) \ libxmlrpc_server++ \ libxmlrpc_server_cgi++ \ libxmlrpc_server_pstream++ \ libxmlrpc_packetsocket \ ifeq ($(ENABLE_ABYSS_SERVER),yes) TARGET_LIB_NAMES_PP += libxmlrpc_server_abyss++ endif ifeq ($(MUST_BUILD_CLIENT),yes) TARGET_LIB_NAMES_PP += libxmlrpc_client++ endif STATIC_LIBRARIES_TO_INSTALL = $(TARGET_STATIC_LIBRARIES) SHARED_LIBS_TO_BUILD = $(TARGET_LIB_NAMES_PP) SHARED_LIBS_TO_INSTALL = $(TARGET_LIB_NAMES_PP) # INCLUDES and DEP_SOURCES are used by dep-common target INCLUDES = $(BASIC_INCLUDES) $(CLIENT_INCLUDES) $(LIBXML_INCLUDES) \ $(SERVER_INCLUDES) $(SERVER_ABYSS_INCLUDES) \ $(shell cat blddir/src/libxmlrpc_client.cflags) DEP_SOURCES = *.cpp ifeq ($(ENABLE_LIBXML2_BACKEND),yes) LIBXML_INCLUDES = $(LIBXML2_CFLAGS) else LIBXML_INCLUDES = -Isrcdir/lib/expat/xmlparse endif ifeq ($(ENABLE_LIBXML2_BACKEND),yes) XML_PARSER_LIBDEP = $(shell xml2-config --libs) else XML_PARSER_LIBDEP = \ -L$(BLDDIR)/lib/expat/xmlparse -lxmlrpc_xmlparse \ -L$(BLDDIR)/lib/expat/xmltok -lxmlrpc_xmltok endif LIBXMLRPCPP_MODS = \ Lock base64 env_wrap fault girerr girmem global outcome param_list value xml LIBXMLRPC_SERVERPP_MODS = registry LIBXMLRPC_SERVER_ABYSSPP_MODS = server_abyss LIBXMLRPC_SERVER_CGIPP_MODS = server_cgi LIBXMLRPC_SERVER_PSTREAMPP_MODS = server_pstream_conn server_pstream LIBXMLRPC_CLIENTPP_MODS = client client_simple curl libwww wininet pstream LIBXMLRPC_PACKETSOCKET_MODS = packetsocket TARGET_MODS_PP = \ XmlRpcCpp \ $(LIBXMLRPCPP_MODS) \ $(LIBXMLRPC_SERVERPP_MODS) \ $(LIBXMLRPC_SERVER_ABYSSPP_MODS) \ $(LIBXMLRPC_SERVER_CGIPP_MODS) \ $(LIBXMLRPC_SERVER_PSTREAMPP_MODS) \ $(LIBXMLRPC_CLIENTPP_MODS) \ $(LIBXMLRPC_PACKETSOCKET_MODS) \ OMIT_CPP_LIB_RULES = Y MAJ = 8 # Major number of shared libraries in this directory include $(SRCDIR)/common.mk # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir BASIC_INCLUDES = \ -Iblddir/include \ -Isrcdir/include \ -Iblddir \ -Isrcdir/lib/util/include # TARGET_STATIC_LIBARIES, etc. are set by common.mk, based on # TARGET_LIB_NAMES_PP. all: \ $(TARGET_STATIC_LIBRARIES) \ $(TARGET_SHARED_LIBS_PP) \ $(TARGET_SHARED_LE_LIBS) #----------------------------------------------------------------------------- # RULES TO LINK LIBRARIES #----------------------------------------------------------------------------- # Rules for these are in common.mk, courtesy of TARGET_LIB_NAMES_PP: # shlibfn generates e.g. libxmlrpc.so.3.1 # shliblefn generates e.g. libxmlrpc.so LIBXMLRPC_CPP_SH = $(call shlibfn, libxmlrpc_cpp) $(LIBXMLRPC_CPP_SH): XmlRpcCpp.osh \ $(LIBXMLRPC_UTIL) \ $(LIBXMLRPC) \ $(LIBXMLRPC_SERVER) \ $(LIBXMLRPC_UTIL) $(LIBXMLRPC_CPP_SH): LIBOBJECTS = XmlRpcCpp.osh $(LIBXMLRPC_CPP_SH): LIBDEP = \ -Lblddir/src -lxmlrpc_server -lxmlrpc \ $(XML_PARSER_LIBDEP) \ $(LIBXMLRPC_UTIL_LIBDEP) \ LIBXMLRPCPP_SH = $(call shlibfn, lib$(LIBXMLRPCPP_NAME)) $(LIBXMLRPCPP_SH): $(LIBXMLRPCPP_MODS:%=%.osh) \ $(LIBXMLRPC) \ $(LIBXMLRPC_UTIL) $(LIBXMLRPCPP_SH): LIBOBJECTS = $(LIBXMLRPCPP_MODS:%=%.osh) $(LIBXMLRPCPP_SH): LIBDEP = \ -Lblddir/src -lxmlrpc \ $(XML_PARSER_LIBDEP) \ -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util ifeq ($(MSVCRT),yes) $(LIBXMLRPCPP_SH): LIBDEP += -lpthread endif LIBXMLRPC_SERVERPP_SH = $(call shlibfn, libxmlrpc_server++) $(LIBXMLRPC_SERVERPP_SH): $(LIBXMLRPC_SERVERPP_MODS:%=%.osh) \ $(LIBXMLRPC_SERVER) \ $(call shliblefn, lib$(LIBXMLRPCPP_NAME)) \ $(LIBXMLRPC_UTIL) \ $(LIBXMLRPC) $(LIBXMLRPC_SERVERPP_SH): LIBOBJECTS = $(LIBXMLRPC_SERVERPP_MODS:%=%.osh) $(LIBXMLRPC_SERVERPP_SH): LIBDEP = \ -L. -l$(LIBXMLRPCPP_NAME) \ -Lblddir/src -lxmlrpc_server -lxmlrpc \ $(XML_PARSER_LIBDEP) \ -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util ifeq ($(MSVCRT),yes) $(LIBXMLRPC_SERVERPP_SH): LIBDEP += -lpthread endif LIBXMLRPC_SERVER_ABYSSPP_SH = $(call shlibfn, libxmlrpc_server_abyss++) $(LIBXMLRPC_SERVER_ABYSSPP_SH): $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.osh) \ $(LIBXMLRPC_ABYSS) \ $(LIBXMLRPC_SERVER_ABYSS) \ $(call shliblefn, lib$(LIBXMLRPCPP_NAME)) \ $(call shlibfn, libxmlrpc_server++) \ $(LIBXMLRPC_UTIL) \ $(LIBXMLRPC) $(LIBXMLRPC_SERVER_ABYSSPP_SH): LIBOBJECTS = $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.osh) $(LIBXMLRPC_SERVER_ABYSSPP_SH): LIBDEP = \ -L. -lxmlrpc_server++ -l$(LIBXMLRPCPP_NAME) \ -Lblddir/src -lxmlrpc_server_abyss -lxmlrpc_server -lxmlrpc \ $(XML_PARSER_LIBDEP) \ -L$(LIBXMLRPC_ABYSS_DIR) -lxmlrpc_abyss \ -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util \ ifeq ($(MSVCRT),yes) $(LIBXMLRPC_SERVER_ABYSSPP_SH): LIBDEP += -lws2_32 -lwsock32 -lpthread endif LIBXMLRPC_SERVER_CGIPP_SH = $(call shlibfn, libxmlrpc_server_cgi++) $(LIBXMLRPC_SERVER_CGIPP_SH): $(LIBXMLRPC_SERVER_CGIPP_MODS:%=%.osh) \ $(call shliblefn, libxmlrpc_server++) \ $(call shliblefn, lib$(LIBXMLRPCPP_NAME)) \ $(LIBXMLRPC) $(LIBXMLRPC_SERVER_CGIPP_SH): LIBOBJECTS = $(LIBXMLRPC_SERVER_CGIPP_MODS:%=%.osh) $(LIBXMLRPC_SERVER_CGIPP_SH): LIBDEP = \ -L. -lxmlrpc_server++ -l$(LIBXMLRPCPP_NAME) \ -Lblddir/src -lxmlrpc_server -lxmlrpc \ $(XML_PARSER_LIBDEP) \ -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util ifeq ($(MSVCRT),yes) $(LIBXMLRPC_SERVER_CGIPP_SH): LIBDEP += -lpthread endif LIBXMLRPC_SERVER_PSTREAMPP_SH = $(call shlibfn, libxmlrpc_server_pstream++) $(LIBXMLRPC_SERVER_PSTREAMPP_SH): $(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.osh) \ $(LIBXMLRPC_SERVER) \ $(call shliblefn, lib$(LIBXMLRPCPP_NAME)) \ $(call shliblefn, libxmlrpc_packetsocket) \ $(call shliblefn, libxmlrpc_server++) $(LIBXMLRPC_SERVER_PSTREAMPP_SH): LIBOBJECTS = $(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.osh) $(LIBXMLRPC_SERVER_PSTREAMPP_SH): LIBDEP = \ -L. -lxmlrpc_server++ -l$(LIBXMLRPCPP_NAME) -lxmlrpc_packetsocket \ -Lblddir/src -lxmlrpc_server -lxmlrpc \ $(XML_PARSER_LIBDEP) \ -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util \ ifeq ($(MSVCRT),yes) $(LIBXMLRPC_SERVER_PSTREAMPP_SH): LIBDEP += -lws2_32 -lwsock32 -lpthread endif LIBXMLRPC_CLIENTPP_SH = $(call shlibfn, libxmlrpc_client++) $(LIBXMLRPC_CLIENTPP_SH): $(LIBXMLRPC_CLIENTPP_MODS:%=%.osh) \ $(LIBXMLRPC_UTIL) \ $(call shliblefn, libxmlrpc_packetsocket) \ $(LIBXMLRPC) \ $(call shliblefn, lib$(LIBXMLRPCPP_NAME)) \ $(LIBXMLRPC_CLIENT) \ $(BLDDIR)/src/libxmlrpc_client.ldflags $(LIBXMLRPC_CLIENTPP_SH): LIBOBJECTS = $(LIBXMLRPC_CLIENTPP_MODS:%=%.osh) $(LIBXMLRPC_CLIENTPP_SH): LIBDEP = \ -L. -l$(LIBXMLRPCPP_NAME) -lxmlrpc_packetsocket \ $(shell cat blddir/src/libxmlrpc_client.ldflags) \ -Lblddir/src -lxmlrpc_client -lxmlrpc \ $(XML_PARSER_LIBDEP) \ -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util ifeq ($(MSVCRT),yes) $(LIBXMLRPC_CLIENTPP_SH): LIBDEP += -lws2_32 -lwsock32 -lpthread endif LIBXMLRPC_PACKETSOCKET_SH = $(call shlibfn, libxmlrpc_packetsocket) $(LIBXMLRPC_PACKETSOCKET_SH): $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.osh) \ $(call shliblefn, lib$(LIBXMLRPCPP_NAME)) $(LIBXMLRPC_PACKETSOCKET_SH): LIBOBJECTS = $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.osh) $(LIBXMLRPC_PACKETSOCKET_SH): LIBDEP = \ -L. -l$(LIBXMLRPCPP_NAME) \ -Lblddir/src -lxmlrpc \ $(XML_PARSER_LIBDEP) \ -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util ifeq ($(MSVCRT),yes) $(LIBXMLRPC_PACKETSOCKET_SH): LIBDEP += -lws2_32 -lwsock32 -lpthread endif libxmlrpc_cpp.a: XmlRpcCpp.o libxmlrpc_cpp.a: LIBOBJECTS = XmlRpcCpp.o lib$(LIBXMLRPCPP_NAME).a: $(LIBXMLRPCPP_MODS:%=%.o) lib$(LIBXMLRPCPP_NAME).a: LIBOBJECTS = $(LIBXMLRPCPP_MODS:%=%.o) libxmlrpc_server++.a: $(LIBXMLRPC_SERVERPP_MODS:%=%.o) libxmlrpc_server++.a: LIBOBJECTS = $(LIBXMLRPC_SERVERPP_MODS:%=%.o) libxmlrpc_server_abyss++.a: $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.o) libxmlrpc_server_abyss++.a: LIBOBJECTS=$(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.o) libxmlrpc_server_cgi++.a: $(LIBXMLRPC_SERVER_CGIPP_MODS:%=%.o) libxmlrpc_server_cgi++.a: LIBOBJECTS=$(LIBXMLRPC_SERVER_CGIPP_MODS:%=%.o) libxmlrpc_server_pstream++.a: $(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.o) libxmlrpc_server_pstream++.a: LIBOBJECTS=$(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.o) libxmlrpc_client++.a: $(LIBXMLRPC_CLIENTPP_MODS:%=%.o) libxmlrpc_client++.a: LIBOBJECTS = $(LIBXMLRPC_CLIENTPP_MODS:%=%.o) libxmlrpc_packetsocket.a: $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.o) libxmlrpc_packetsocket.a: LIBOBJECTS = $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.o) #----------------------------------------------------------------------------- # RULES TO COMPILE OBJECT MODULES FOR LIBRARIES #----------------------------------------------------------------------------- # Rules for these are in common.mk, courtesy of TARGET_MODS_PP: XmlRpcCpp.o% XmlrpcCpp.osh: \ INCLUDES = $(BASIC_INCLUDES) $(LIBXMLRPCPP_MODS:%=%.o) \ $(LIBXMLRPCPP_MODS:%=%.osh): \ INCLUDES = $(BASIC_INCLUDES) SERVER_INCLUDES = $(BASIC_INCLUDES) $(LIBXML_INCLUDES) $(LIBXMLRPC_SERVERPP_MODS:%=%.o) \ $(LIBXMLRPC_SERVERPP_MODS:%=%.osh): \ INCLUDES = $(SERVER_INCLUDES) $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.o) \ $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.osh): \ INCLUDES = $(SERVER_INCLUDES) $(LIBXMLRPC_SERVER_CGIPP_MODS:%=%.o) \ $(LIBXMLRPC_SERVER_CGIPP_MODS:%=%.osh): \ INCLUDES = $(SERVER_INCLUDES) $(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.o) \ $(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.osh): \ INCLUDES = $(SERVER_INCLUDES) $(LIBXMLRPC_CLIENTPP_MODS:%=%.o) \ $(LIBXMLRPC_CLIENTPP_MODS:%=%.osh): $(BLDDIR)/src/libxmlrpc_client.cflags $(LIBXMLRPC_CLIENTPP_MODS:%=%.o) \ $(LIBXMLRPC_CLIENTPP_MODS:%=%.osh): \ INCLUDES = $(BASIC_INCLUDES) $(LIBXML_INCLUDES) \ $(shell cat blddir/src/libxmlrpc_client.cflags) $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.o) \ $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.osh): \ INCLUDES = $(BASIC_INCLUDES) # in Glibc 2.2 has some failed inlines, so we disable that warning: $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.o) \ $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.osh): \ CFLAGS_LOCAL = -Wno-inline TRANSPORT_CONFIG_USERS = client curl libwww wininet $(TRANSPORT_CONFIG_USERS:%=%.o) $(TRANSPORT_CONFIG_USERS:%=%.osh): \ $(BLDDIR)/transport_config.h #----------------------------------------------------------------------------- # MISCELLANEOUS RULES #----------------------------------------------------------------------------- .PHONY: install install: install-common .PHONY: clean clean-local distclean distclean-local clean: clean-common clean-local clean-local: distclean: clean distclean-local distclean-common distclean-local: .PHONY: dep dep: dep-common $(BLDDIR)/transport_config.h dep-common: $(BLDDIR)/src/libxmlrpc_client.cflags include depend.mk xmlrpc-c-1.33.14/src/cpp/XmlRpcCpp.cpp000066400000000000000000000306011236133176700173460ustar00rootroot00000000000000// Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. #include #include #include "xmlrpc-c/oldcppwrapper.hpp" using std::string; //========================================================================= // XmlRpcFault Methods //========================================================================= XmlRpcFault::XmlRpcFault (const XmlRpcFault &fault) { xmlrpc_env_init(&mFault); xmlrpc_env_set_fault(&mFault, fault.mFault.fault_code, fault.mFault.fault_string); } XmlRpcFault::XmlRpcFault (const int faultCode, const string faultString) { xmlrpc_env_init(&mFault); xmlrpc_env_set_fault(&mFault, faultCode, const_cast(faultString.c_str())); } XmlRpcFault::XmlRpcFault (const xmlrpc_env *env) { if (!env->fault_string) throw XmlRpcFault(XMLRPC_INTERNAL_ERROR, "Tried to create empty fault"); xmlrpc_env_init(&mFault); xmlrpc_env_set_fault(&mFault, env->fault_code, const_cast(env->fault_string)); } XmlRpcFault::~XmlRpcFault (void) { xmlrpc_env_clean(&mFault); } string XmlRpcFault::getFaultString (void) const { XMLRPC_ASSERT(mFault.fault_occurred); return string(mFault.fault_string); } //========================================================================= // XmlRpcEnv Methods //========================================================================= XmlRpcEnv::XmlRpcEnv (const XmlRpcEnv &env) { xmlrpc_env_init(&mEnv); if (env.hasFaultOccurred()) xmlrpc_env_set_fault(&mEnv, env.mEnv.fault_code, env.mEnv.fault_string); } XmlRpcFault XmlRpcEnv::getFault (void) const { return XmlRpcFault(&mEnv); } void XmlRpcEnv::throwMe (void) const { throw XmlRpcFault(&mEnv); } //========================================================================= // XmlRpcValue Methods //========================================================================= // If the user doesn't tell us what kind of value to create, use // a false boolean value as the default. XmlRpcValue::XmlRpcValue (void) { XmlRpcEnv env; mValue = xmlrpc_build_value(env, "b", (xmlrpc_bool) 0); env.throwIfFaultOccurred(); } XmlRpcValue XmlRpcValue::makeInt (const XmlRpcValue::int32 i) { XmlRpcEnv env; xmlrpc_value *value = xmlrpc_build_value(env, "i", i); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeBool (const bool b) { XmlRpcEnv env; xmlrpc_value *value = xmlrpc_build_value(env, "b", (xmlrpc_bool) b); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeDouble (const double d) { XmlRpcEnv env; xmlrpc_value *value = xmlrpc_build_value(env, "d", d); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeDateTime (const string& dateTime) { XmlRpcEnv env; xmlrpc_value *value; const char *data = dateTime.c_str(); // Make sure we're not using wchar_t. value = xmlrpc_build_value(env, "8", data); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeString (const string& str) { XmlRpcEnv env; const char *data = str.data(); // Make sure we're not using wchar_t. size_t size = str.size(); xmlrpc_value *value = xmlrpc_build_value(env, "s#", data, size); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeString (const char *const str) { XmlRpcEnv env; xmlrpc_value *value = xmlrpc_build_value(env, "s", str); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeString (const char *const str, size_t len) { XmlRpcEnv env; xmlrpc_value *value = xmlrpc_build_value(env, "s#", str, len); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeArray (void) { XmlRpcEnv env; xmlrpc_value *value = xmlrpc_build_value(env, "()"); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeStruct (void) { XmlRpcEnv env; xmlrpc_value *value = xmlrpc_struct_new(env); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue XmlRpcValue::makeBase64 (const unsigned char *const data, size_t len) { XmlRpcEnv env; xmlrpc_value *value = xmlrpc_build_value(env, "6", data, len); env.throwIfFaultOccurred(); return XmlRpcValue(value, CONSUME_REFERENCE); } XmlRpcValue::int32 XmlRpcValue::getInt (void) const { XmlRpcEnv env; XmlRpcValue::int32 result; xmlrpc_parse_value(env, mValue, "i", &result); env.throwIfFaultOccurred(); return result; } bool XmlRpcValue::getBool (void) const { XmlRpcEnv env; xmlrpc_bool result; xmlrpc_parse_value(env, mValue, "b", &result); env.throwIfFaultOccurred(); return (result != 0); } double XmlRpcValue::getDouble (void) const { XmlRpcEnv env; double result; xmlrpc_parse_value(env, mValue, "d", &result); env.throwIfFaultOccurred(); return result; } string XmlRpcValue::getRawDateTime (void) const { XmlRpcEnv env; char *result; xmlrpc_parse_value(env, mValue, "8", &result); env.throwIfFaultOccurred(); return string(result); } string XmlRpcValue::getString (void) const { XmlRpcEnv env; char *result; size_t result_len; xmlrpc_parse_value(env, mValue, "s#", &result, &result_len); env.throwIfFaultOccurred(); return string(result, result_len); } XmlRpcValue XmlRpcValue::getArray (void) const { XmlRpcEnv env; xmlrpc_value *result; xmlrpc_parse_value(env, mValue, "A", &result); env.throwIfFaultOccurred(); return XmlRpcValue(result); } XmlRpcValue XmlRpcValue::getStruct (void) const { XmlRpcEnv env; xmlrpc_value *result; xmlrpc_parse_value(env, mValue, "S", &result); env.throwIfFaultOccurred(); return XmlRpcValue(result); } void XmlRpcValue::getBase64 (const unsigned char *& out_data, size_t& out_len) const { XmlRpcEnv env; xmlrpc_parse_value(env, mValue, "6", &out_data, &out_len); env.throwIfFaultOccurred(); } size_t XmlRpcValue::arraySize (void) const { XmlRpcEnv env; size_t result = xmlrpc_array_size(env, mValue); env.throwIfFaultOccurred(); return result; } void XmlRpcValue::arrayAppendItem (const XmlRpcValue& value) { XmlRpcEnv env; xmlrpc_array_append_item(env, mValue, value.borrowReference()); env.throwIfFaultOccurred(); } XmlRpcValue XmlRpcValue::arrayGetItem (int index) const { XmlRpcEnv env; xmlrpc_value *result = xmlrpc_array_get_item(env, mValue, index); env.throwIfFaultOccurred(); return XmlRpcValue(result); } size_t XmlRpcValue::structSize (void) const { XmlRpcEnv env; size_t result = xmlrpc_struct_size(env, mValue); env.throwIfFaultOccurred(); return result; } bool XmlRpcValue::structHasKey (const string& key) const { XmlRpcEnv env; const char *keystr = key.data(); size_t keylen = key.size(); int result = xmlrpc_struct_has_key_n(env, mValue, const_cast(keystr), keylen); env.throwIfFaultOccurred(); return (result != 0); } XmlRpcValue XmlRpcValue::structGetValue (const string& key) const { XmlRpcEnv env; const char *keystr = key.data(); size_t keylen = key.size(); xmlrpc_value *result = xmlrpc_struct_get_value_n(env, mValue, const_cast(keystr), keylen); env.throwIfFaultOccurred(); return XmlRpcValue(result); } void XmlRpcValue::structSetValue (const string& key, const XmlRpcValue& value) { XmlRpcEnv env; const char *keystr = key.data(); size_t keylen = key.size(); xmlrpc_struct_set_value_n(env, mValue, (char*) keystr, keylen, value.borrowReference()); env.throwIfFaultOccurred(); } void XmlRpcValue::structGetKeyAndValue (const int index, string& out_key, XmlRpcValue& out_value) const { XmlRpcEnv env; xmlrpc_value *key, *value; xmlrpc_struct_get_key_and_value(env, mValue, index, &key, &value); env.throwIfFaultOccurred(); out_key = XmlRpcValue(key).getString(); out_value = XmlRpcValue(value); } XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name, xmlrpc_method method, void *data) { XmlRpcEnv env; xmlrpc_registry_add_method (env, mRegistry, NULL, name.c_str (), method, data); env.throwIfFaultOccurred (); return (*this); } XmlRpcGenSrv& XmlRpcGenSrv::addMethod (const string& name, xmlrpc_method method, void* data, const string& signature, const string& help) { XmlRpcEnv env; xmlrpc_registry_add_method_w_doc (env, mRegistry, NULL, name.c_str (), method, data, signature.c_str (), help.c_str ()); env.throwIfFaultOccurred (); return (*this); } xmlrpc_mem_block* XmlRpcGenSrv::alloc (XmlRpcEnv& env, const string& body) const { xmlrpc_mem_block* result = NULL; char* contents; result = xmlrpc_mem_block_new (env, body.length ()); env.throwIfFaultOccurred (); contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, result); memcpy (contents, body.c_str (), body.length ()); return result; } string XmlRpcGenSrv::handle (const string& body) const { XmlRpcEnv env; string result; xmlrpc_mem_block* input = NULL, * output = NULL; char* input_data, * output_data; size_t input_size, output_size; if (body.length () > xmlrpc_limit_get (XMLRPC_XML_SIZE_LIMIT_ID)) throw XmlRpcFault (XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large"); input = alloc (env, body); input_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, input); input_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, input); output = xmlrpc_registry_process_call (env, mRegistry, NULL, input_data, input_size); if (output) { output_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output); output_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); result.assign (output_data, output_size); xmlrpc_mem_block_free (output); } xmlrpc_mem_block_free (input); if (!result.length ()) throw XmlRpcFault (env); return result; } xmlrpc-c-1.33.14/src/cpp/base64.cpp000066400000000000000000000143461236133176700165720ustar00rootroot00000000000000#include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/base64.hpp" using namespace std; using namespace xmlrpc_c; namespace { char const table_a2b_base64[] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, /* Note PAD->0 */ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 }; char const base64Pad('='); size_t const base64MaxChunkSize(57); // Max binary chunk size (76 character line) #define BASE64_LINE_SZ 128 /* Buffer size for a single line. */ unsigned char const table_b2a_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; } // namespace class bitBuffer { public: bitBuffer() : bitsInBuffer(0) {}; void shiftIn8Bits(unsigned char const newBits) { // Shift in 8 bits to the right end of the buffer this->buffer = (this->buffer << 8) | newBits; this->bitsInBuffer += 8; assert(this->bitsInBuffer <= 12); } void shiftIn6Bits(unsigned char const newBits) { // Shift in 6 bits to the right end of the buffer this->buffer = (this->buffer << 6) | newBits; this->bitsInBuffer += 6; assert(this->bitsInBuffer <= 12); } void shiftOut6Bits(unsigned char * const outputP) { // Shift out 6 bits from the left end of the buffer assert(bitsInBuffer >= 6); *outputP = (this->buffer >> (this->bitsInBuffer - 6)) & 0x3f; this->bitsInBuffer -= 6; } void shiftOut8Bits(unsigned char * const outputP) { // Shift out 8 bits from the left end of the buffer assert(bitsInBuffer >= 8); *outputP = (this->buffer >> (this->bitsInBuffer - 8)) & 0xff; this->bitsInBuffer -= 8; } void shiftOutResidue(unsigned char * const outputP) { // Shift out the residual 2 or 4 bits, padded on the right with 0 // to 6 bits. while (this->bitsInBuffer < 6) { this->buffer <<= 2; this->bitsInBuffer += 2; } this->shiftOut6Bits(outputP); } void discardResidue() { assert(bitsInBuffer < 8); this->bitsInBuffer = 0; } unsigned int bitCount() { return bitsInBuffer; } private: unsigned int buffer; unsigned int bitsInBuffer; }; namespace xmlrpc_c { static void encodeChunk(vector const& bytes, size_t const lineStart, size_t const chunkSize, string * const outputP) { bitBuffer buffer; // A buffer in which we accumulate bits (up to 12 bits) // until we have enough (6) for a base64 character. // I suppose this would be more efficient with an iterator on // 'bytes' and/or *outputP. I'd have to find out how to use one. for (size_t linePos = 0; linePos < chunkSize; ++linePos) { // Shift the data into our buffer buffer.shiftIn8Bits(bytes[lineStart + linePos]); // Encode any complete 6 bit groups while (buffer.bitCount() >= 6) { unsigned char theseBits; buffer.shiftOut6Bits(&theseBits); outputP->append(1, table_b2a_base64[theseBits]); } } if (buffer.bitCount() > 0) { // Handle residual bits in the buffer unsigned char theseBits; buffer.shiftOutResidue(&theseBits); outputP->append(1, table_b2a_base64[theseBits]); // Pad to a multiple of 4 characters (24 bits) assert(outputP->length() % 4 > 0); outputP->append(4-outputP->length() % 4, base64Pad); } else { assert(outputP->length() % 4 == 0); } } string base64FromBytes(vector const& bytes, newlineCtl const newlineCtl) { string retval; if (bytes.size() == 0) { if (newlineCtl == NEWLINE_YES) retval = "\r\n"; else retval = ""; } else { // It would be good to preallocate retval. Need to look up // how to do that. for (size_t chunkStart = 0; chunkStart < bytes.size(); chunkStart += base64MaxChunkSize) { size_t const chunkSize( min(base64MaxChunkSize, bytes.size() - chunkStart)); encodeChunk(bytes, chunkStart, chunkSize, &retval); if (newlineCtl == NEWLINE_YES) // Append a courtesy crlf retval += "\r\n"; } } return retval; } vector bytesFromBase64(string const& base64) { vector retval; bitBuffer buffer; unsigned int npad; npad = 0; // No pad characters seen yet for (unsigned int cursor = 0; cursor < base64.length(); ++cursor) { char const thisChar(base64[cursor] & 0x7f); if (thisChar == '\r' || thisChar == '\n' || thisChar == ' ') { // ignore this punctuation } else { if (thisChar == base64Pad) { // This pad character is here to synchronize a chunk to // a multiple of 24 bits (4 base64 characters; 3 bytes). buffer.discardResidue(); } else { unsigned int const tableIndex(thisChar); if (table_a2b_base64[tableIndex] == -1) throwf("Contains non-base64 character " "with ASCII code 0x%02x", thisChar); buffer.shiftIn6Bits(table_a2b_base64[tableIndex]); if (buffer.bitCount() >= 8) { unsigned char thisByte; buffer.shiftOut8Bits(&thisByte); retval.push_back(thisByte); } } } } if (buffer.bitCount() > 0) throwf("Not a multiple of 4 characters"); return retval; } } //namespace xmlrpc-c-1.33.14/src/cpp/client.cpp000066400000000000000000000706671236133176700167740ustar00rootroot00000000000000/*============================================================================= client.cpp =============================================================================== This is the C++ XML-RPC client library for Xmlrpc-c. Note that unlike most of Xmlprc-c's C++ API, this is _not_ based on the C client library. This code is independent of the C client library, and is based directly on the client XML transport libraries (with a little help from internal C utility libraries). =============================================================================*/ #include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/girmem.hpp" using girmem::autoObjectPtr; using girmem::autoObject; #include "env_wrap.hpp" #include "xmlrpc-c/base.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/transport.h" #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/xml.hpp" #include "xmlrpc-c/timeout.hpp" #include "xmlrpc-c/client.hpp" #include "transport_config.h" using namespace std; using namespace xmlrpc_c; namespace { void throwIfError(env_wrap const& env) { if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } class memblockStringWrapper { public: memblockStringWrapper(string const value) { env_wrap env; this->memblockP = XMLRPC_MEMBLOCK_NEW(char, &env.env_c, 0); throwIfError(env); XMLRPC_MEMBLOCK_APPEND(char, &env.env_c, this->memblockP, value.c_str(), value.size()); throwIfError(env); } memblockStringWrapper(xmlrpc_mem_block * const memblockP) : memblockP(memblockP) {}; ~memblockStringWrapper() { XMLRPC_MEMBLOCK_FREE(char, this->memblockP); } xmlrpc_mem_block * memblockP; }; } // namespace namespace xmlrpc_c { struct client_xml_impl { /* We have both kinds of pointers to give the user flexibility -- we have constructors that take both. But the simple pointer 'transportP' is valid in both cases. */ clientXmlTransport * transportP; clientXmlTransportPtr transportPtr; xmlrpc_dialect dialect; client_xml_impl(clientXmlTransport * const transportP, xmlrpc_dialect const dialect = xmlrpc_dialect_i8) : transportP(transportP), dialect(dialect) {} client_xml_impl(clientXmlTransportPtr const transportPtr, clientXmlTransport * const transportP, xmlrpc_dialect const dialect = xmlrpc_dialect_i8) : transportP(transportP), transportPtr(transportPtr), dialect(dialect) {} }; carriageParm::carriageParm() {} carriageParm::~carriageParm() {} carriageParmPtr::carriageParmPtr() { // Base class constructor will construct pointer that points to nothing } carriageParmPtr::carriageParmPtr( carriageParm * const carriageParmP) : autoObjectPtr(carriageParmP) {} carriageParm * carriageParmPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } carriageParm * carriageParmPtr::get() const { return dynamic_cast(this->objectP); } carriageParm_http0::carriageParm_http0() : c_serverInfoP(NULL) {} carriageParm_http0::carriageParm_http0(string const serverUrl) { this->c_serverInfoP = NULL; this->instantiate(serverUrl); } carriageParm_http0::~carriageParm_http0() { if (this->c_serverInfoP) xmlrpc_server_info_free(this->c_serverInfoP); } void carriageParm_http0::instantiate(string const serverUrl) { if (c_serverInfoP) throw(error("object already instantiated")); env_wrap env; this->c_serverInfoP = xmlrpc_server_info_new(&env.env_c, serverUrl.c_str()); throwIfError(env); } void carriageParm_http0::setUser(string const userid, string const password) { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_set_user( &env.env_c, this->c_serverInfoP, userid.c_str(), password.c_str()); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::allowAuthBasic() { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_allow_auth_basic(&env.env_c, this->c_serverInfoP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::disallowAuthBasic() { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_disallow_auth_basic(&env.env_c, this->c_serverInfoP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::allowAuthDigest() { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_allow_auth_digest(&env.env_c, this->c_serverInfoP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::disallowAuthDigest() { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_disallow_auth_digest(&env.env_c, this->c_serverInfoP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::allowAuthNegotiate() { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_allow_auth_negotiate(&env.env_c, this->c_serverInfoP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::disallowAuthNegotiate() { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_disallow_auth_negotiate( &env.env_c, this->c_serverInfoP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::allowAuthNtlm() { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_allow_auth_ntlm(&env.env_c, this->c_serverInfoP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::disallowAuthNtlm() { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_disallow_auth_ntlm(&env.env_c, this->c_serverInfoP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void carriageParm_http0::setBasicAuth(string const username, string const password) { if (!this->c_serverInfoP) throw(error("object not instantiated")); env_wrap env; xmlrpc_server_info_set_basic_auth( &env.env_c, this->c_serverInfoP, username.c_str(), password.c_str()); throwIfError(env); } carriageParm_http0Ptr::carriageParm_http0Ptr() { // Base class constructor will construct pointer that points to nothing } carriageParm_http0Ptr::carriageParm_http0Ptr( carriageParm_http0 * const carriageParmP) : carriageParmPtr(carriageParmP) {} carriageParm_http0 * carriageParm_http0Ptr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } xmlTransaction::xmlTransaction() {} void xmlTransaction::finish(string const& responseXml) const { xml::trace("XML-RPC RESPONSE", responseXml); } void xmlTransaction::finishErr(error const&) const { } void xmlTransaction::progress(struct xmlrpc_progress_data const&) const { // This is just the base class method. A derived class may override // this with something substantial. } xmlTransactionPtr::xmlTransactionPtr() {} xmlTransactionPtr::xmlTransactionPtr(xmlTransaction * xmlTransP) : autoObjectPtr(xmlTransP) {} xmlTransaction * xmlTransactionPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } struct xmlTranCtl { /*---------------------------------------------------------------------------- This contains information needed to conduct a transaction. You construct it as you start the transaction and destroy it after the work is done. You need this only for an asynchronous one, because where the user starts and finishes the RPC in the same libxmlrpc_client call, you can just keep this information in various stack variables, and it's faster and easier to understand that way. The C transport is designed to take a xmlrpc_call_info argument for similar stuff needed by the the C client object. But it's really opaque to the transport, so we just let xmlTranCtl masquerade as xmlprc_call_info in our call to the C transport. -----------------------------------------------------------------------------*/ xmlTranCtl(xmlTransactionPtr const& xmlTranP, string const& callXml) : xmlTranP(xmlTranP) { env_wrap env; this->callXmlP = XMLRPC_MEMBLOCK_NEW(char, &env.env_c, 0); throwIfError(env); XMLRPC_MEMBLOCK_APPEND(char, &env.env_c, this->callXmlP, callXml.c_str(), callXml.size()); throwIfError(env); } ~xmlTranCtl() { XMLRPC_MEMBLOCK_FREE(char, this->callXmlP); } xmlTransactionPtr const xmlTranP; // The transaction we're controlling. Most notable use of this is // that this object we inform when the transaction is done. This // is where the response XML and other transaction results go. xmlrpc_mem_block * callXmlP; // The XML of the call. This is what the transport transports. }; clientXmlTransport::~clientXmlTransport() {} void clientXmlTransport::start(carriageParm * const carriageParmP, string const& callXml, xmlTransactionPtr const& xmlTranP) { // Note: derived class clientXmlTransport_http overrides this, // so it doesn't normally get used. string responseXml; this->call(carriageParmP, callXml, &responseXml); xmlTranP->finish(responseXml); } void clientXmlTransport::finishAsync(xmlrpc_c::timeout) { // Since our start() does the whole thing, there's nothing for // us to do. // A derived class that overrides start() with something properly // asynchronous had better also override finishAsync() with something // substantial. } void clientXmlTransport::asyncComplete( struct xmlrpc_call_info * const callInfoP, xmlrpc_mem_block * const responseXmlMP, xmlrpc_env const transportEnv) { xmlTranCtl * const xmlTranCtlP = reinterpret_cast(callInfoP); try { if (transportEnv.fault_occurred) { xmlTranCtlP->xmlTranP->finishErr(error(transportEnv.fault_string)); } else { string const responseXml( XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlMP), XMLRPC_MEMBLOCK_SIZE(char, responseXmlMP)); xmlTranCtlP->xmlTranP->finish(responseXml); } } catch(exception const&) { /* We can't throw an error back to C code, and the async_complete interface does not provide for failure, so we define ->finish() as not being capable of throwing an error. */ assert(false); } delete(xmlTranCtlP); /* Ordinarily, *xmlTranCtlP is the last reference to xmlTranCtlP->xmlTranP, so that will get destroyed too. But ->finish() could conceivably create a new reference to xmlTranCtlP->xmlTranP, and then it would keep living. */ } void clientXmlTransport::progress( struct xmlrpc_call_info * const callInfoP, struct xmlrpc_progress_data const progressData) { xmlTranCtl * const xmlTranCtlP = reinterpret_cast(callInfoP); xmlTranCtlP->xmlTranP->progress(progressData); } void clientXmlTransport::setInterrupt(int *) { throwf("The client XML transport is not interruptible"); } clientXmlTransportPtr::clientXmlTransportPtr() { // Base class constructor will construct pointer that points to nothing } clientXmlTransportPtr::clientXmlTransportPtr( clientXmlTransport * const transportP) : autoObjectPtr(transportP) {} clientXmlTransport * clientXmlTransportPtr::get() const { return dynamic_cast(objectP); } clientXmlTransport * clientXmlTransportPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } clientXmlTransport_http::~clientXmlTransport_http() {} void clientXmlTransport_http::call( carriageParm * const carriageParmP, string const& callXml, string * const responseXmlP) { carriageParm_http0 * const carriageParmHttpP = dynamic_cast(carriageParmP); if (carriageParmHttpP == NULL) throw(error("HTTP client XML transport called with carriage " "parameter object not of class carriageParm_http")); memblockStringWrapper callXmlM(callXml); xmlrpc_mem_block * responseXmlMP; env_wrap env; this->c_transportOpsP->call(&env.env_c, this->c_transportP, carriageParmHttpP->c_serverInfoP, callXmlM.memblockP, &responseXmlMP); throwIfError(env); memblockStringWrapper responseHolder(responseXmlMP); // Makes responseXmlMP get freed at end of scope *responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlMP), XMLRPC_MEMBLOCK_SIZE(char, responseXmlMP)); } void clientXmlTransport_http::start( carriageParm * const carriageParmP, string const& callXml, xmlTransactionPtr const& xmlTranP) { env_wrap env; carriageParm_http0 * const carriageParmHttpP = dynamic_cast(carriageParmP); if (carriageParmHttpP == NULL) throw(error("HTTP client XML transport called with carriage " "parameter object not of type carriageParm_http")); xmlTranCtl * const tranCtlP(new xmlTranCtl(xmlTranP, callXml)); try { this->c_transportOpsP->send_request( &env.env_c, this->c_transportP, carriageParmHttpP->c_serverInfoP, tranCtlP->callXmlP, &this->asyncComplete, &this->progress, reinterpret_cast(tranCtlP)); throwIfError(env); } catch (...) { delete tranCtlP; throw; } } void clientXmlTransport_http::finishAsync(xmlrpc_c::timeout const timeout) { xmlrpc_timeoutType const c_timeoutType( timeout.finite ? timeout_yes : timeout_no); xmlrpc_timeout const c_timeout(timeout.duration); this->c_transportOpsP->finish_asynch( this->c_transportP, c_timeoutType, c_timeout); } void clientXmlTransport_http::setInterrupt(int * const interruptP) { if (this->c_transportOpsP->set_interrupt) this->c_transportOpsP->set_interrupt(this->c_transportP, interruptP); } bool const haveCurl( #if MUST_BUILD_CURL_CLIENT true #else false #endif ); bool const haveLibwww( #if MUST_BUILD_LIBWWW_CLIENT true #else false #endif ); bool const haveWininet( #if MUST_BUILD_WININET_CLIENT true #else false #endif ); vector clientXmlTransport_http::availableTypes() { vector retval; if (haveCurl) retval.push_back("curl"); if (haveLibwww) retval.push_back("libwww"); if (haveWininet) retval.push_back("wininet"); return retval; } clientXmlTransportPtr clientXmlTransport_http::create() { /*---------------------------------------------------------------------------- Make an HTTP Client XML transport of any kind (Caller doesn't care). Caller can find out what kind he got by trying dynamic casts. Caller can use a carriageParm_http0 with the transport. -----------------------------------------------------------------------------*/ if (haveCurl) return clientXmlTransportPtr(new clientXmlTransport_curl()); else if (haveLibwww) return clientXmlTransportPtr(new clientXmlTransport_libwww()); else if (haveWininet) return clientXmlTransportPtr(new clientXmlTransport_wininet()); else throwf("This XML-RPC client library contains no HTTP XML transports"); } clientTransaction::clientTransaction() {} clientTransactionPtr::clientTransactionPtr() {} clientTransactionPtr::clientTransactionPtr( clientTransaction * const transP) : autoObjectPtr(transP) {} clientTransactionPtr::~clientTransactionPtr() {} clientTransaction * clientTransactionPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } client::~client() {} void client::start(carriageParm * const carriageParmP, string const& methodName, paramList const& paramList, clientTransactionPtr const& tranP) { /*---------------------------------------------------------------------------- Start an RPC, wait for it to complete, and finish it. Usually, a derived class overrides this with something that does not wait for the RPC to complete, but rather arranges for something to finish the RPC later when the RPC does complete. -----------------------------------------------------------------------------*/ rpcOutcome outcome; this->call(carriageParmP, methodName, paramList, &outcome); tranP->finish(outcome); } void client::finishAsync(xmlrpc_c::timeout) { // Since our start() does the whole thing, there's nothing for // us to do. // A derived class that overrides start() with something properly // asynchronous had better also override finishAsync() with something // substantial. } void client::setInterrupt(int *) { throwf("Clients of this type are not interruptible"); } clientPtr::clientPtr() { // Base class constructor will construct pointer that points to nothing } clientPtr::clientPtr( client * const clientP) : autoObjectPtr(clientP) {} client * clientPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } client * clientPtr::get() const { return dynamic_cast(objectP); } client_xml::client_xml(clientXmlTransport * const transportP) { this->implP = new client_xml_impl(transportP); } client_xml::client_xml(clientXmlTransportPtr const transportPtr) { this->implP = new client_xml_impl(transportPtr, transportPtr.get()); } client_xml::client_xml(clientXmlTransport * const transportP, xmlrpc_dialect const dialect) { this->implP = new client_xml_impl(transportP, dialect); } client_xml::client_xml(clientXmlTransportPtr const transportPtr, xmlrpc_dialect const dialect) { this->implP = new client_xml_impl(transportPtr, transportPtr.get(), dialect); } client_xml::~client_xml() { delete(this->implP); } void client_xml::call(carriageParm * const carriageParmP, string const& methodName, paramList const& paramList, rpcOutcome * const outcomeP) { string callXml; string responseXml; xml::generateCall(methodName, paramList, this->implP->dialect, &callXml); xml::trace("XML-RPC CALL", callXml); try { this->implP->transportP->call(carriageParmP, callXml, &responseXml); } catch (exception const& e) { throwf("Unable to transport XML to server and " "get XML response back. %s", e.what()); } xml::trace("XML-RPC RESPONSE", responseXml); try { xml::parseResponse(responseXml, outcomeP); } catch (exception const& e) { throwf("Response XML from server is not valid XML-RPC response. %s", e.what()); } } void client_xml::start(carriageParm * const carriageParmP, string const& methodName, paramList const& paramList, clientTransactionPtr const& tranP) { string callXml; xml::generateCall(methodName, paramList, this->implP->dialect, &callXml); xml::trace("XML-RPC CALL", callXml); xmlTransaction_clientPtr const xmlTranP(tranP); this->implP->transportP->start(carriageParmP, callXml, xmlTranP); } void client_xml::finishAsync(xmlrpc_c::timeout const timeout) { this->implP->transportP->finishAsync(timeout); } void client_xml::setInterrupt(int * const interruptP) { this->implP->transportP->setInterrupt(interruptP); } serverAccessor::serverAccessor(clientPtr const clientP, carriageParmPtr const carriageParmP) : clientP(clientP), carriageParmP(carriageParmP) {}; void serverAccessor::call(std::string const& methodName, xmlrpc_c::paramList const& paramList, xmlrpc_c::rpcOutcome * const outcomeP) const { this->clientP->call(this->carriageParmP.get(), methodName, paramList, outcomeP); } serverAccessorPtr::serverAccessorPtr() { // Base class constructor will construct pointer that points to nothing } serverAccessorPtr::serverAccessorPtr( serverAccessor * const serverAccessorParmP) : autoObjectPtr(serverAccessorParmP) {} serverAccessor * serverAccessorPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } serverAccessor * serverAccessorPtr::get() const { return dynamic_cast(objectP); } connection::connection(client * const clientP, carriageParm * const carriageParmP) : clientP(clientP), carriageParmP(carriageParmP) {} connection::~connection() {} struct rpc_impl { enum state { STATE_UNFINISHED, // RPC is running or not started yet STATE_ERROR, // We couldn't execute the RPC STATE_FAILED, // RPC executed successfully, but failed per XML-RPC STATE_SUCCEEDED // RPC is done, no exception }; enum state state; girerr::error * errorP; // Defined only in STATE_ERROR rpcOutcome outcome; // Defined only in STATE_FAILED and STATE_SUCCEEDED string methodName; xmlrpc_c::paramList paramList; rpc_impl(string const& methodName, xmlrpc_c::paramList const& paramList) : state(STATE_UNFINISHED), methodName(methodName), paramList(paramList) {} }; rpc::rpc(string const methodName, paramList const& paramList) { this->implP = new rpc_impl(methodName, paramList); } rpc::~rpc() { if (this->implP->state == rpc_impl::STATE_ERROR) delete(this->implP->errorP); delete(this->implP); } void rpc::call(client * const clientP, carriageParm * const carriageParmP) { if (this->implP->state != rpc_impl::STATE_UNFINISHED) throw(error("Attempt to execute an RPC that has already been " "executed")); clientP->call(carriageParmP, this->implP->methodName, this->implP->paramList, &this->implP->outcome); this->implP->state = this->implP->outcome.succeeded() ? rpc_impl::STATE_SUCCEEDED : rpc_impl::STATE_FAILED; } void rpc::call(connection const& connection) { this->call(connection.clientP, connection.carriageParmP); } void rpc::start(client * const clientP, carriageParm * const carriageParmP) { if (this->implP->state != rpc_impl::STATE_UNFINISHED) throw(error("Attempt to execute an RPC that has already been " "executed")); clientP->start(carriageParmP, this->implP->methodName, this->implP->paramList, rpcPtr(this)); } void rpc::start(xmlrpc_c::connection const& connection) { this->start(connection.clientP, connection.carriageParmP); } void rpc::finish(rpcOutcome const& outcome) { this->implP->state = outcome.succeeded() ? rpc_impl::STATE_SUCCEEDED : rpc_impl::STATE_FAILED; this->implP->outcome = outcome; this->notifyComplete(); } void rpc::finishErr(error const& error) { this->implP->state = rpc_impl::STATE_ERROR; this->implP->errorP = new girerr::error(error); this->notifyComplete(); } void rpc::notifyComplete() { /*---------------------------------------------------------------------------- Anyone who does RPCs asynchronously and doesn't use polling will want to make his own class derived from 'rpc' and override this with a notifyFinish() that does something. Typically, notifyFinish() will queue the RPC so some other thread will deal with the fact that the RPC is finished. In the absence of the aforementioned queueing, the RPC becomes unreferenced as soon as our Caller releases his reference, so the RPC gets destroyed when we return. -----------------------------------------------------------------------------*/ } void rpc::progress(struct xmlrpc_progress_data const&) const { /*---------------------------------------------------------------------------- If the user is interested in tracking the progress of the RPC, he will derive a class from xmlrpc_c::rpc and override this with a progress() that does something, such as display a progress bar. -----------------------------------------------------------------------------*/ } value rpc::getResult() const { switch (this->implP->state) { case rpc_impl::STATE_UNFINISHED: throw(error("Attempt to get result of RPC that is not finished.")); break; case rpc_impl::STATE_ERROR: throw(*this->implP->errorP); break; case rpc_impl::STATE_FAILED: throw(error("RPC response indicates failure. " + this->implP->outcome.getFault().getDescription())); break; case rpc_impl::STATE_SUCCEEDED: { // All normal } } return this->implP->outcome.getResult(); } fault rpc::getFault() const { switch (this->implP->state) { case rpc_impl::STATE_UNFINISHED: throw(error("Attempt to get fault from RPC that is not finished")); break; case rpc_impl::STATE_ERROR: throw(*this->implP->errorP); break; case rpc_impl::STATE_SUCCEEDED: throw(error("Attempt to get fault from an RPC that succeeded")); break; case rpc_impl::STATE_FAILED: { // All normal } } return this->implP->outcome.getFault(); } bool rpc::isFinished() const { return (this->implP->state != rpc_impl::STATE_UNFINISHED); } bool rpc::isSuccessful() const { return (this->implP->state == rpc_impl::STATE_SUCCEEDED); } rpcPtr::rpcPtr() {} rpcPtr::rpcPtr(rpc * const rpcP) : clientTransactionPtr(rpcP) {} rpcPtr::rpcPtr(string const methodName, xmlrpc_c::paramList const& paramList) : clientTransactionPtr(new rpc(methodName, paramList)) {} rpc * rpcPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } xmlTransaction_client::xmlTransaction_client( clientTransactionPtr const& tranP) : tranP(tranP) {} void xmlTransaction_client::finish(string const& responseXml) const { xml::trace("XML-RPC RESPONSE", responseXml); try { rpcOutcome outcome; xml::parseResponse(responseXml, &outcome); this->tranP->finish(outcome); } catch (error const& error) { this->tranP->finishErr(error); } } void xmlTransaction_client::finishErr(error const& error) const { this->tranP->finishErr(error); } void xmlTransaction_client::progress( struct xmlrpc_progress_data const& progressData) const { this->tranP->progress(progressData); } xmlTransaction_clientPtr::xmlTransaction_clientPtr() {} xmlTransaction_clientPtr::xmlTransaction_clientPtr( clientTransactionPtr const& tranP) : xmlTransactionPtr(new xmlTransaction_client(tranP)) {} xmlTransaction_client * xmlTransaction_clientPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } } // namespace xmlrpc-c-1.33.14/src/cpp/client_simple.cpp000066400000000000000000000105211236133176700203240ustar00rootroot00000000000000#include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "env_wrap.hpp" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/client.hpp" #include #include "xmlrpc-c/client_simple.hpp" using namespace std; using namespace xmlrpc_c; namespace xmlrpc_c { namespace { class cValueWrapper { /*---------------------------------------------------------------------------- Use an object of this class to set up to remove a reference to an xmlrpc_value object (a C object with manual reference management) at then end of a scope -- even if the scope ends with a throw. -----------------------------------------------------------------------------*/ xmlrpc_value * valueP; public: cValueWrapper(xmlrpc_value * valueP) : valueP(valueP) {} ~cValueWrapper() { xmlrpc_DECREF(valueP); } }; } // namespace clientSimple::clientSimple() { clientXmlTransportPtr const transportP(clientXmlTransport_http::create()); this->clientP = clientPtr(new client_xml(transportP)); } void clientSimple::call(string const serverUrl, string const methodName, value * const resultP) { carriageParm_http0 carriageParm(serverUrl); rpcPtr rpcPtr(methodName, paramList()); rpcPtr->call(this->clientP.get(), &carriageParm); *resultP = rpcPtr->getResult(); } namespace { void makeParamArray(string const format, xmlrpc_value ** const paramArrayPP, va_list args) { env_wrap env; /* The format is a sequence of parameter specifications, such as "iiii" for 4 integer parameters. We add parentheses to make it an array of those parameters: "(iiii)". */ string const arrayFormat("(" + string(format) + ")"); const char * tail; xmlrpc_build_value_va(&env.env_c, arrayFormat.c_str(), args, paramArrayPP, &tail); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); if (strlen(tail) != 0) { /* xmlrpc_build_value_va() parses off a single value specification from its format string, and 'tail' points to whatever is after it. Our format string should have been a single array value, meaning tail is end-of-string. If it's not, that means something closed our array early. */ xmlrpc_DECREF(*paramArrayPP); throw(error("format string is invalid. It apparently has a " "stray right parenthesis")); } } } // namespace void clientSimple::call(string const serverUrl, string const methodName, string const format, value * const resultP, ...) { carriageParm_http0 carriageParm(serverUrl); env_wrap env; xmlrpc_value * paramArrayP; va_list args; va_start(args, resultP); makeParamArray(format, ¶mArrayP, args); va_end(args); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); else { cValueWrapper paramArrayWrapper(paramArrayP); // ensure destruction unsigned int const paramCount( xmlrpc_array_size(&env.env_c, paramArrayP)); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); paramList paramList; for (unsigned int i = 0; i < paramCount; ++i) { xmlrpc_value * paramP; xmlrpc_array_read_item(&env.env_c, paramArrayP, i, ¶mP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); else { cValueWrapper paramWrapper(paramP); // ensure destruction paramList.add(value(paramP)); } } rpcPtr rpcPtr(methodName, paramList); rpcPtr->call(this->clientP.get(), &carriageParm); *resultP = rpcPtr->getResult(); } } void clientSimple::call(string const serverUrl, string const methodName, paramList const& paramList, value * const resultP) { carriageParm_http0 carriageParm(serverUrl); rpcPtr rpcPtr(methodName, paramList); rpcPtr->call(this->clientP.get(), &carriageParm); *resultP = rpcPtr->getResult(); } } // namespace xmlrpc-c-1.33.14/src/cpp/curl.cpp000066400000000000000000000277251236133176700164600ustar00rootroot00000000000000/*============================================================================= curl.cpp =============================================================================== This is the Curl XML transport of the C++ XML-RPC client library for Xmlrpc-c. Note that unlike most of Xmlprc-c's C++ API, this is _not_ based on the C client library. This code is independent of the C client library, and is based directly on the client XML transport libraries (with a little help from internal C utility libraries). =============================================================================*/ #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/girmem.hpp" using girmem::autoObjectPtr; using girmem::autoObject; #include "env_wrap.hpp" #include "xmlrpc-c/base.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/transport.h" #include "xmlrpc-c/base_int.h" /* transport_config.h defines MUST_BUILD_CURL_CLIENT */ #include "transport_config.h" #include "xmlrpc-c/client_transport.hpp" using namespace std; using namespace xmlrpc_c; namespace { class globalConstant { public: globalConstant(); ~globalConstant(); }; globalConstant::globalConstant() { // Not thread safe xmlrpc_transport_setup setupFn; #if MUST_BUILD_CURL_CLIENT setupFn = xmlrpc_curl_transport_ops.setup_global_const; #else setupFn = NULL; #endif if (setupFn) { env_wrap env; setupFn(&env.env_c); // Not thread safe if (env.env_c.fault_occurred) throwf("Failed to do global initialization " "of Curl transport code. %s", env.env_c.fault_string); } } globalConstant::~globalConstant() { // Not thread safe xmlrpc_transport_teardown teardownFn; #if MUST_BUILD_CURL_CLIENT teardownFn = xmlrpc_curl_transport_ops.teardown_global_const; #else teardownFn = NULL; #endif if (teardownFn) teardownFn(); // not thread safe } globalConstant globalConst; // This object is never accessed. Its whole purpose to to be born and // to die, which it does automatically as part of C++ program // program initialization and termination. } // namespace namespace xmlrpc_c { carriageParm_curl0::carriageParm_curl0( string const serverUrl ) { this->instantiate(serverUrl); } carriageParm_curl0Ptr::carriageParm_curl0Ptr() { // Base class constructor will construct pointer that points to nothing } carriageParm_curl0Ptr::carriageParm_curl0Ptr( carriageParm_curl0 * const carriageParmP) { this->point(carriageParmP); } carriageParm_curl0 * carriageParm_curl0Ptr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } struct clientXmlTransport_curl::constrOpt_impl { constrOpt_impl(); struct { std::string network_interface; bool dont_advertise; std::string user_agent; std::string referer; bool no_ssl_verifypeer; bool no_ssl_verifyhost; std::string ssl_cert; std::string sslcerttype; std::string sslcertpasswd; std::string sslkey; std::string sslkeytype; std::string sslkeypasswd; std::string sslengine; bool sslengine_default; xmlrpc_sslversion sslversion; std::string cainfo; std::string capath; std::string randomfile; std::string egdsocket; std::string ssl_cipher_list; unsigned int timeout; std::string proxy; unsigned int proxy_auth; unsigned int proxy_port; std::string proxy_userpwd; xmlrpc_httpproxytype proxy_type; bool gssapi_delegation; } value; struct { bool network_interface; bool dont_advertise; bool user_agent; bool referer; bool no_ssl_verifypeer; bool no_ssl_verifyhost; bool ssl_cert; bool sslcerttype; bool sslcertpasswd; bool sslkey; bool sslkeytype; bool sslkeypasswd; bool sslengine; bool sslengine_default; bool sslversion; bool cainfo; bool capath; bool randomfile; bool egdsocket; bool ssl_cipher_list; bool timeout; bool proxy; bool proxy_auth; bool proxy_port; bool proxy_userpwd; bool proxy_type; bool gssapi_delegation; } present; }; clientXmlTransport_curl::constrOpt_impl::constrOpt_impl() { present.network_interface = false; present.dont_advertise = false; present.user_agent = false; present.referer = false; present.no_ssl_verifypeer = false; present.no_ssl_verifyhost = false; present.ssl_cert = false; present.sslcerttype = false; present.sslcertpasswd = false; present.sslkey = false; present.sslkeytype = false; present.sslkeypasswd = false; present.sslengine = false; present.sslengine_default = false; present.sslversion = false; present.cainfo = false; present.capath = false; present.randomfile = false; present.egdsocket = false; present.ssl_cipher_list = false; present.timeout = false; present.proxy = false; present.proxy_port = false; present.proxy_auth = false; present.proxy_userpwd = false; present.proxy_type = false; present.gssapi_delegation = false; } #define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ clientXmlTransport_curl::constrOpt & \ clientXmlTransport_curl::constrOpt::OPTION_NAME(TYPE const& arg) { \ this->implP->value.OPTION_NAME = arg; \ this->implP->present.OPTION_NAME = true; \ return *this; \ } DEFINE_OPTION_SETTER(network_interface, string); DEFINE_OPTION_SETTER(dont_advertise, bool); DEFINE_OPTION_SETTER(referer, string); DEFINE_OPTION_SETTER(user_agent, string); DEFINE_OPTION_SETTER(no_ssl_verifypeer, bool); DEFINE_OPTION_SETTER(no_ssl_verifyhost, bool); DEFINE_OPTION_SETTER(ssl_cert, string); DEFINE_OPTION_SETTER(sslcerttype, string); DEFINE_OPTION_SETTER(sslcertpasswd, string); DEFINE_OPTION_SETTER(sslkey, string); DEFINE_OPTION_SETTER(sslkeytype, string); DEFINE_OPTION_SETTER(sslkeypasswd, string); DEFINE_OPTION_SETTER(sslengine, string); DEFINE_OPTION_SETTER(sslengine_default, bool); DEFINE_OPTION_SETTER(sslversion, xmlrpc_sslversion); DEFINE_OPTION_SETTER(cainfo, string); DEFINE_OPTION_SETTER(capath, string); DEFINE_OPTION_SETTER(randomfile, string); DEFINE_OPTION_SETTER(egdsocket, string); DEFINE_OPTION_SETTER(ssl_cipher_list, string); DEFINE_OPTION_SETTER(timeout, unsigned int); DEFINE_OPTION_SETTER(proxy, string); DEFINE_OPTION_SETTER(proxy_port, unsigned int); DEFINE_OPTION_SETTER(proxy_auth, unsigned int); DEFINE_OPTION_SETTER(proxy_userpwd, string); DEFINE_OPTION_SETTER(proxy_type, xmlrpc_httpproxytype); DEFINE_OPTION_SETTER(gssapi_delegation, bool); #undef DEFINE_OPTION_SETTER clientXmlTransport_curl::constrOpt::constrOpt() { this->implP = new clientXmlTransport_curl::constrOpt_impl(); } clientXmlTransport_curl::constrOpt::~constrOpt() { delete(this->implP); } clientXmlTransport_curl::constrOpt::constrOpt(constrOpt& arg) { this->implP = new constrOpt_impl(*arg.implP); } #if MUST_BUILD_CURL_CLIENT void clientXmlTransport_curl::initialize(constrOpt const& optExt) { constrOpt_impl const opt(*optExt.implP); struct xmlrpc_curl_xportparms transportParms; transportParms.network_interface = opt.present.network_interface ? opt.value.network_interface.c_str() : NULL; transportParms.referer = opt.present.referer ? opt.value.referer.c_str() : NULL; transportParms.dont_advertise = opt.present.dont_advertise ? opt.value.dont_advertise : false; transportParms.user_agent = opt.present.user_agent ? opt.value.user_agent.c_str() : NULL; transportParms.no_ssl_verifypeer = opt.present.no_ssl_verifypeer ? opt.value.no_ssl_verifypeer : false; transportParms.no_ssl_verifyhost = opt.present.no_ssl_verifyhost ? opt.value.no_ssl_verifyhost : false; transportParms.ssl_cert = opt.present.ssl_cert ? opt.value.ssl_cert.c_str() : NULL; transportParms.sslcerttype = opt.present.sslcerttype ? opt.value.sslcerttype.c_str() : NULL; transportParms.sslcertpasswd = opt.present.sslcertpasswd ? opt.value.sslcertpasswd.c_str() : NULL; transportParms.sslkey = opt.present.sslkey ? opt.value.sslkey.c_str() : NULL; transportParms.sslkeytype = opt.present.sslkeytype ? opt.value.sslkeytype.c_str() : NULL; transportParms.sslkeypasswd = opt.present.sslkeypasswd ? opt.value.sslkeypasswd.c_str() : NULL; transportParms.sslengine = opt.present.sslengine ? opt.value.sslengine.c_str() : NULL; transportParms.sslengine_default = opt.present.sslengine_default ? opt.value.sslengine_default : false; transportParms.sslversion = opt.present.sslversion ? opt.value.sslversion : XMLRPC_SSLVERSION_DEFAULT; transportParms.cainfo = opt.present.cainfo ? opt.value.cainfo.c_str() : NULL; transportParms.capath = opt.present.capath ? opt.value.capath.c_str() : NULL; transportParms.randomfile = opt.present.randomfile ? opt.value.randomfile.c_str() : NULL; transportParms.egdsocket = opt.present.egdsocket ? opt.value.egdsocket.c_str() : NULL; transportParms.ssl_cipher_list = opt.present.ssl_cipher_list ? opt.value.ssl_cipher_list.c_str() : NULL; transportParms.timeout = opt.present.timeout ? opt.value.timeout : 0; transportParms.proxy = opt.present.proxy ? opt.value.proxy.c_str() : NULL; transportParms.proxy_port = opt.present.proxy_port ? opt.value.proxy_port : 0; transportParms.proxy_auth = opt.present.proxy_auth ? opt.value.proxy_auth : XMLRPC_HTTPAUTH_NONE; transportParms.proxy_userpwd = opt.present.proxy_userpwd ? opt.value.proxy_userpwd.c_str() : NULL; transportParms.proxy_type = opt.present.proxy_type ? opt.value.proxy_type : XMLRPC_HTTPPROXY_HTTP; transportParms.gssapi_delegation = opt.present.gssapi_delegation ? opt.value.gssapi_delegation : false; this->c_transportOpsP = &xmlrpc_curl_transport_ops; env_wrap env; xmlrpc_curl_transport_ops.create( &env.env_c, 0, "", "", &transportParms, XMLRPC_CXPSIZE(gssapi_delegation), &this->c_transportP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } #else // MUST_BUILD_CURL_CLIENT void clientXmlTransport_curl::initialize(constrOpt const& opt) { throw(error("There is no Curl client XML transport in this XML-RPC client " "library")); } #endif clientXmlTransport_curl::clientXmlTransport_curl(constrOpt const& opt) { this->initialize(opt); } clientXmlTransport_curl::clientXmlTransport_curl( string const networkInterface, bool const noSslVerifyPeer, bool const noSslVerifyHost, string const userAgent) { clientXmlTransport_curl::constrOpt opt; if (networkInterface.size() > 0) opt.network_interface(networkInterface); opt.no_ssl_verifypeer(noSslVerifyPeer); opt.no_ssl_verifyhost(noSslVerifyHost); if (userAgent.size() > 0) opt.user_agent(userAgent); this->initialize(opt); } clientXmlTransport_curl::~clientXmlTransport_curl() { this->c_transportOpsP->destroy(this->c_transportP); } } // namespace xmlrpc-c-1.33.14/src/cpp/env_wrap.cpp000066400000000000000000000003311236133176700173140ustar00rootroot00000000000000#include "xmlrpc-c/util.h" #include "env_wrap.hpp" namespace xmlrpc_c { env_wrap::env_wrap() { xmlrpc_env_init(&this->env_c); } env_wrap::~env_wrap() { xmlrpc_env_clean(&this->env_c); } } // namespace xmlrpc-c-1.33.14/src/cpp/env_wrap.hpp000066400000000000000000000014141236133176700173240ustar00rootroot00000000000000#ifndef ENV_INT_HPP_INCLUDED #define ENV_INT_HPP_INCLUDED #include "xmlrpc-c/c_util.h" #include "xmlrpc-c/util.h" namespace xmlrpc_c { class XMLRPC_DLLEXPORT env_wrap { /*---------------------------------------------------------------------------- A wrapper to assist in using the Xmlrpc-c C libraries in Xmlrpc-c C++ code. To use the C libraries, you have to use type xmlrpc_env, but that type does not have an automatic destructor (because it's C), so it's hard to throw an error from a context in which a variable of that type exists. This wrapper provides that automatic destructor. -----------------------------------------------------------------------------*/ public: env_wrap(); ~env_wrap(); xmlrpc_env env_c; }; } // namespace #endif xmlrpc-c-1.33.14/src/cpp/fault.cpp000066400000000000000000000013311236133176700166070ustar00rootroot00000000000000#include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "xmlrpc-c/base.hpp" using namespace std; namespace xmlrpc_c { fault::fault() : valid(false) {}; fault::fault(string const _description, xmlrpc_c::fault::code_t const _code ) : valid(true), code(_code), description(_description) {} xmlrpc_c::fault::code_t fault::getCode() const { if (!valid) throw(error("Attempt to access placeholder xmlrpc_c::fault object")); return this->code; } string fault::getDescription() const { if (!valid) throw(error("Attempt to access placeholder xmlrpc_c::fault object")); return this->description; } } // namespace xmlrpc-c-1.33.14/src/cpp/girerr.cpp000066400000000000000000000006771236133176700170020ustar00rootroot00000000000000#include #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/girerr.hpp" using namespace std; namespace girerr { void throwf(const char * const format, ...) { va_list varargs; va_start(varargs, format); const char * value; xmlrpc_vasprintf(&value, format, varargs); string const valueString(value); xmlrpc_strfree(value); throw(girerr::error(valueString)); va_end(varargs); } } // namespace xmlrpc-c-1.33.14/src/cpp/girmem.cpp000066400000000000000000000072301236133176700167600ustar00rootroot00000000000000#include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "Lock.hpp" #include "xmlrpc-c/girmem.hpp" using namespace std; using namespace xmlrpc_c; namespace girmem { class autoObject::Impl { Lock refcountLock; unsigned int refcount; public: Impl(); ~Impl(); void incref(); void decref(bool * const unreferencedP); }; autoObject::Impl::Impl() { this->refcount = 0; } autoObject::Impl::~Impl() { if (this->refcount > 0) throw(error("Destroying referenced object")); } void autoObject::Impl::incref() { Lock::Holder(&this->refcountLock); ++this->refcount; } void autoObject::Impl::decref(bool * const unreferencedP) { if (this->refcount == 0) throw(error("Decrementing ref count of unreferenced object")); Lock::Holder(&this->refcountLock); --this->refcount; *unreferencedP = (this->refcount == 0); } autoObject::autoObject() : implP(auto_ptr(new Impl)) {} autoObject::autoObject(autoObject const&) { // This method is declared private, so we can be running now: assert(false); } autoObject::~autoObject() {} void autoObject::incref() { this->implP->incref(); } void autoObject::decref(bool * const unreferencedP) { this->implP->decref(unreferencedP); } autoObjectPtr::autoObjectPtr() : objectP(NULL) {} autoObjectPtr::autoObjectPtr(autoObject * const objectP) { // Note: When someone attempts to use this constructor with a null // argument, it's normally because a 'new' of the autoObject // failed, before calling the autoObject's constructor, thus // generating a null pointer. // E.g. the following code, where the system is out of memory: // // class client : public autoObject { ... } // class clientPtr : public autoObjectPtr { ... } // clientPtr clientP(new client); if (objectP == NULL) throw(error("Object creation failed; trying to create autoObjectPtr " "with a null autoObject pointer")); this->objectP = objectP; objectP->incref(); } autoObjectPtr::autoObjectPtr(autoObjectPtr const& autoObjectPtr) { // copy constructor this->objectP = autoObjectPtr.objectP; if (this->objectP) this->objectP->incref(); } autoObjectPtr::~autoObjectPtr() { this->unpoint(); } void autoObjectPtr::point(autoObject * const objectP) { if (this->objectP != NULL) throw(error("Already pointing")); this->objectP = objectP; objectP->incref(); } void autoObjectPtr::unpoint() { if (this->objectP) { bool dead; this->objectP->decref(&dead); if (dead) { delete(this->objectP); this->objectP = NULL; } } } autoObjectPtr autoObjectPtr::operator=(autoObjectPtr const& source) { // If we're overwriting a variable that already points to something, // we have to unpoint it from what it points to now before we can point // it to what 'source' points to. But if the source and destination // are the same object, we just want to leave the pointing alone. if (this == &source) { // Assignment of variable to itself; no-op } else { this->unpoint(); this->objectP = source.objectP; if (this->objectP) this->objectP->incref(); } return *this; } autoObject * autoObjectPtr::operator->() const { if (this->objectP == NULL) throw(error("attempt to dereference autoObjectPtr " "which does not point to anything")); return this->objectP; } autoObject * autoObjectPtr::get() const { return this->objectP; } } // namespace xmlrpc-c-1.33.14/src/cpp/global.cpp000066400000000000000000000011251236133176700167350ustar00rootroot00000000000000#include using namespace std; #include using girerr::throwf; #include class LibxmlrpcGlobalState { public: LibxmlrpcGlobalState() { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_init(&env); if (env.fault_occurred) { string const fault(env.fault_string); xmlrpc_env_clean(&env); throwf("Failed to initailize libxmlrpc. %s", fault.c_str()); } } ~LibxmlrpcGlobalState() { xmlrpc_term(); } }; static LibxmlrpcGlobalState libxmlrpcGlobalState; xmlrpc-c-1.33.14/src/cpp/libwww.cpp000066400000000000000000000066441236133176700170230ustar00rootroot00000000000000/*============================================================================= libwww.cpp =============================================================================== This is the Libwww XML transport of the C++ XML-RPC client library for Xmlrpc-c. =============================================================================*/ #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/girmem.hpp" using girmem::autoObjectPtr; using girmem::autoObject; #include "env_wrap.hpp" #include "xmlrpc-c/base.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/transport.h" #include "xmlrpc-c/base_int.h" /* transport_config.h defines MUST_BUILD_LIBWWW_CLIENT */ #include "transport_config.h" #include "xmlrpc-c/client_transport.hpp" using namespace std; using namespace xmlrpc_c; namespace { class globalConstant { public: globalConstant(); ~globalConstant(); }; globalConstant::globalConstant() { // Not thread safe xmlrpc_transport_setup setupFn; #if MUST_BUILD_LIBWWW_CLIENT setupFn = xmlrpc_libwww_transport_ops.setup_global_const; #else setupFn = NULL; #endif if (setupFn) { env_wrap env; setupFn(&env.env_c); // Not thread safe if (env.env_c.fault_occurred) throwf("Failed to do global initialization " "of Libwww transport code. %s", env.env_c.fault_string); } } globalConstant::~globalConstant() { // Not thread safe xmlrpc_transport_teardown teardownFn; #if MUST_BUILD_LIBWWW_CLIENT teardownFn = xmlrpc_libwww_transport_ops.teardown_global_const; #else teardownFn = NULL; #endif if (teardownFn) teardownFn(); // not thread safe } globalConstant globalConst; // This object is never accessed. Its whole purpose to to be born and // to die, which it does automatically as part of C++ program // program initialization and termination. } // namespace namespace xmlrpc_c { carriageParm_libwww0::carriageParm_libwww0( string const serverUrl ) { this->instantiate(serverUrl); } carriageParm_libwww0Ptr::carriageParm_libwww0Ptr() { // Base class constructor will construct pointer that points to nothing } carriageParm_libwww0Ptr::carriageParm_libwww0Ptr( carriageParm_libwww0 * const carriageParmP) { this->point(carriageParmP); } carriageParm_libwww0 * carriageParm_libwww0Ptr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } #if MUST_BUILD_LIBWWW_CLIENT clientXmlTransport_libwww::clientXmlTransport_libwww( string const appname, string const appversion) { this->c_transportOpsP = &xmlrpc_libwww_transport_ops; env_wrap env; xmlrpc_libwww_transport_ops.create( &env.env_c, 0, appname.c_str(), appversion.c_str(), NULL, 0, &this->c_transportP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } #else // MUST_BUILD_LIBWWW_CLIENT clientXmlTransport_libwww::clientXmlTransport_libwww(string const, string const) { throw(error("There is no Libwww client XML transport " "in this XML-RPC client library")); } #endif clientXmlTransport_libwww::~clientXmlTransport_libwww() { this->c_transportOpsP->destroy(this->c_transportP); } } // namespace xmlrpc-c-1.33.14/src/cpp/outcome.cpp000066400000000000000000000021511236133176700171500ustar00rootroot00000000000000#include "xmlrpc-c/girerr.hpp" using girerr::error; #include "xmlrpc-c/base.hpp" using namespace std; namespace xmlrpc_c { rpcOutcome::rpcOutcome() : valid(false) {} rpcOutcome::rpcOutcome(xmlrpc_c::value const result) : valid(true), _succeeded(true), result(result) {} rpcOutcome::rpcOutcome(xmlrpc_c::fault const fault) : valid(true), _succeeded(false), fault(fault) {} bool rpcOutcome::succeeded() const { if (!valid) throw(error("Attempt to access rpcOutcome object before setting it")); return _succeeded; } fault rpcOutcome::getFault() const { if (!valid) throw(error("Attempt to access rpcOutcome object before setting it")); if (_succeeded) throw(error("Attempt to get fault description from a non-failure " "RPC outcome")); return fault; } value rpcOutcome::getResult() const { if (!valid) throw(error("Attempt to access rpcOutcome object before setting it")); if (!_succeeded) throw(error("Attempt to get result from an unsuccessful RPC outcome")); return result; } } // namespace xmlrpc-c-1.33.14/src/cpp/packetsocket.cpp000066400000000000000000000615001236133176700201600ustar00rootroot00000000000000/*============================================================================ packetsocket ============================================================================== This is a facility for communicating socket-style, with defined packets like a datagram socket but with reliable delivery like a stream socket. It's like a POSIX "sequential packet" socket, except it is built on top of a stream socket, so it is usable on the many systems that have stream sockets but not sequential packet sockets. By Bryan Henderson 2007.05.12 Contributed to the public domain by its author. ============================================================================*/ /*============================================================================ The protocol for carrying packets on a character stream: The protocol consists of the actual bytes to be transported with a bare minimum of framing information added: An ASCII Escape ( == 0x1B) character marks the start of a 4-ASCII-character control word. These are defined: PKT : marks the beginning of a packet. END : marks the end of a packet. ESC : represents an character in the packet NOP : no meaning Any other bytes after is a protocol error. A stream is all the data transmitted during a single socket connection. End of stream in the middle of a packet is a protocol error. All bytes not part of a control word are literal bytes of a packet. You can create a packet socket from a POSIX stream socket or a Windows emulation of one. One use of the NOP control word is to validate that the connection is still working. You might send one periodically to detect, for example, an unplugged TCP/IP network cable. It's probably better to use the TCP keepalive facility for that. ============================================================================*/ #include "xmlrpc_config.h" #include #include #include #include #include #include // mingw32 doesn't have in 12.06. #include #include #include #if MSVCRT # include # include #else # include # include # include #endif #include #include "c_util.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/girerr.hpp" using girerr::throwf; #include "xmlrpc-c/packetsocket.hpp" using namespace std; #define ESC 0x1B // ASCII Escape character #define ESC_STR "\x1B" class XMLRPC_DLLEXPORT socketx { public: socketx(int const sockFd); ~socketx(); void waitForReadable() const; void waitForWritable() const; void read(unsigned char * const buffer, size_t const bufferSize, bool * const wouldblockP, size_t * const bytesReadP) const; void writeWait(const unsigned char * const data, size_t const size) const; private: int fd; bool fdIsBorrowed; }; /* Sockets are similar, but not identical between Unix and Windows. Some Unix socket functions appear to be available on Windows (a Unix compatibility feature), but work only for file descriptor numbers < 32, so we don't use those. */ socketx::socketx(int const sockFd) { #if MSVCRT // We don't have any way to duplicate; we'll just have to borrow. this->fdIsBorrowed = true; this->fd = sockFd; u_long iMode(1); // Nonblocking mode yes ioctlsocket(this->fd, FIONBIO, &iMode); // Make socket nonblocking #else this->fdIsBorrowed = false; int dupRc; dupRc = dup(sockFd); if (dupRc < 0) throwf("dup() failed. errno=%d (%s)", errno, strerror(errno)); else { this->fd = dupRc; fcntl(this->fd, F_SETFL, O_NONBLOCK); // Make socket nonblocking } #endif } socketx::~socketx() { if (!this->fdIsBorrowed) { #if MSVCRT ::closesocket(SOCKET(this->fd)); #else close(this->fd); #endif } } void socketx::waitForReadable() const { /* Return when there is something to read from the socket (an EOF indication counts as something to read). Also return if there is a signal (handled, of course). Rarely, it is OK to return when there isn't anything to read. */ #if MSVCRT // poll() is not available; settle for select(). // Starting in Windows Vista, there is WSApoll() fd_set rd_set; FD_ZERO(&rd_set); FD_SET(this->fd, &rd_set); select(this->fd + 1, &rd_set, 0, 0, 0); #else // poll() beats select() because higher file descriptor numbers // work. struct pollfd pollfds[1]; pollfds[0].fd = this->fd; pollfds[0].events = POLLIN; poll(pollfds, ARRAY_SIZE(pollfds), -1); #endif } void socketx::waitForWritable() const { /* Return when socket is able to be written to. */ #if MSVCRT fd_set wr_set; FD_ZERO(&wr_set); FD_SET(this->fd, &wr_set); select(this->fd + 1, 0, &wr_set, 0, 0); #else struct pollfd pollfds[1]; pollfds[0].fd = this->fd; pollfds[0].events = POLLOUT; poll(pollfds, ARRAY_SIZE(pollfds), -1); #endif } static bool wouldBlock() { /*---------------------------------------------------------------------------- The most recently executed system socket function, which we assume failed, failed because the situation was such that it wanted to block, but the socket had the nonblocking option. -----------------------------------------------------------------------------*/ #if MSVCRT return (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINPROGRESS); #else /* EWOULDBLOCK and EAGAIN are normally synonyms, but POSIX allows them to be separate and allows the OS to return whichever one it wants for the "would block" condition. */ return (errno == EWOULDBLOCK || errno == EAGAIN); #endif } static string lastErrorDesc() { /*---------------------------------------------------------------------------- A description suitable for an error message of why the most recent failed system socket function failed. -----------------------------------------------------------------------------*/ ostringstream msg; #if MSVCRT int const lastError = WSAGetLastError(); msg << "winsock error code " << lastError << " " << "(" << strerror(lastError) << ")"; #else msg << "errno = " << errno << ", (" << strerror(errno); #endif return msg.str(); } void socketx::read(unsigned char * const buffer, size_t const bufferSize, bool * const wouldblockP, size_t * const bytesReadP) const { int rc; // We've seen a Windows library whose recv() expects a char * buffer // (cf POSIX void *), so we cast. rc = recv(this->fd, (char *)buffer, bufferSize, 0); if (rc < 0) { if (wouldBlock()) { *wouldblockP = true; *bytesReadP = 0; } else throwf("read() of socket failed with %s", lastErrorDesc().c_str()); } else { *wouldblockP = false; *bytesReadP = rc; } } static void writeFd(int const fd, const unsigned char * const data, size_t const size, size_t * const bytesWrittenP) { size_t totalBytesWritten; bool full; // File image is "full" for now - won't take any more data full = false; totalBytesWritten = 0; while (totalBytesWritten < size && !full) { int rc; rc = send(fd, (char*)&data[totalBytesWritten], size - totalBytesWritten, 0); if (rc < 0) { if (wouldBlock()) full = true; else throwf("write() of socket failed with %s", lastErrorDesc().c_str()); } else if (rc == 0) throwf("Zero byte short write."); else { size_t const bytesWritten(rc); totalBytesWritten += bytesWritten; } } *bytesWrittenP = totalBytesWritten; } void socketx::writeWait(const unsigned char * const data, size_t const size) const { /*---------------------------------------------------------------------------- Write the 'size' bytes at 'data' to the socket. Wait as long as it takes for the file image to be able to take all the data. -----------------------------------------------------------------------------*/ size_t totalBytesWritten; // We do the first one blind because it will probably just work // and we don't want to waste the poll() call and buffer arithmetic. writeFd(this->fd, data, size, &totalBytesWritten); while (totalBytesWritten < size) { this->waitForWritable(); size_t bytesWritten; writeFd(this->fd, &data[totalBytesWritten], size - totalBytesWritten, &bytesWritten); totalBytesWritten += bytesWritten; } } namespace xmlrpc_c { packet::packet() : bytes(NULL), length(0), allocSize(0) {} void packet::initialize(const unsigned char * const data, size_t const dataLength) { this->bytes = reinterpret_cast(malloc(dataLength)); if (this->bytes == NULL) throwf("Can't get storage for a %u-byte packet", (unsigned)dataLength); this->allocSize = dataLength; memcpy(this->bytes, data, dataLength); this->length = dataLength; } packet::packet(const unsigned char * const data, size_t const dataLength) { this->initialize(data, dataLength); } packet::packet(const char * const data, size_t const dataLength) { this->initialize(reinterpret_cast(data), dataLength); } packet::~packet() { if (this->bytes) free(bytes); } void packet::addData(const unsigned char * const data, size_t const dataLength) { /*---------------------------------------------------------------------------- Add the 'length' bytes at 'data' to the packet. We allocate whatever additional memory is needed to fit the new data in. -----------------------------------------------------------------------------*/ size_t const neededSize(this->length + dataLength); if (this->allocSize < neededSize) this->bytes = reinterpret_cast( realloc(this->bytes, neededSize)); if (this->bytes == NULL) throwf("Can't get storage for a %u-byte packet", (unsigned)neededSize); memcpy(this->bytes + this->length, data, dataLength); this->length += dataLength; } packetPtr::packetPtr() { // Base class constructor will construct pointer that points to nothing } packetPtr::packetPtr(packet * const packetP) : autoObjectPtr(packetP) {} packet * packetPtr::operator->() const { girmem::autoObject * const p(this->objectP); return dynamic_cast(p); } class packetSocket_impl { public: packetSocket_impl(int const sockFd); void writeWait(packetPtr const& packetP) const; void read(bool * const eofP, bool * const gotPacketP, packetPtr * const packetPP); void readWait(volatile const int * const interruptP, bool * const eofP, bool * const gotPacketP, packetPtr * const packetPP); private: socketx sock; // The kernel stream socket we use. bool eof; // The packet socket is at end-of-file for reads. // 'readBuffer' is empty and there won't be any more data to fill // it because the underlying stream socket is closed. std::queue readBuffer; packetPtr packetAccumP; // The receive packet we're currently accumulating; it will join // 'readBuffer' when we've received the whole packet (and we've // seen the END escape sequence so we know we've received it all). // If we're not currently accumulating a packet (haven't seen a // PKT escape sequence), this points to nothing. bool inEscapeSeq; // In our trek through the data read from the underlying stream // socket, we are after an ESC character and before the end of the // escape sequence. 'escAccum' shows what of the escape sequence // we've seen so far. bool inPacket; // We're now receiving packet data from the underlying stream // socket. We've seen a complete PKT escape sequence, but have not // seen a complete END escape sequence since. struct { unsigned char bytes[3]; size_t len; } escAccum; void takeSomeEscapeSeq(const unsigned char * const buffer, size_t const length, size_t * const bytesTakenP); void takeSomePacket(const unsigned char * const buffer, size_t const length, size_t * const bytesTakenP); void verifyNothingAccumulated(); void processBytesRead(const unsigned char * const buffer, size_t const bytesRead); void readFromFile(); }; packetSocket_impl::packetSocket_impl(int const sockFd) : sock(sockFd) { this->inEscapeSeq = false; this->inPacket = false; this->escAccum.len = 0; this->eof = false; } /*---------------------------------------------------------------------------- To complete the job, we should provide writing services analogous to the reading services. That means a no-wait write method and the ability to interrupt with a signal without corrupting the write stream. We're a little to lazy to do that now, since we don't need it yet, but here's a design for that: The packetSocket has a send queue of packets called the write buffer. It stores packetPtr pointers to packets created by the user. packetSocket::write() adds a packet to the write buffer, then calls packetSocket::writeToFile(). If you give it a null packetPtr, it just calls writeToFile(). packetSocket::writeToFile() writes from the write buffer to the socket whatever the socket will take immediately. It writes the start sequence, writes the packet data, then writes the end sequence. The packetSocket keeps track of where it is in the process of writing the current send packet (including start end end sequences) it is. packetSocket::write() returns a "flushed" flag indicating that there is nothing left in the write buffer. packetSocket::writeWait() just calls packetSocket::write(), then packetSocket::flush() in a poll() loop. -----------------------------------------------------------------------------*/ void packetSocket_impl::writeWait(packetPtr const& packetP) const { const unsigned char * const packetStart( reinterpret_cast(ESC_STR "PKT")); const unsigned char * const packetEnd( reinterpret_cast(ESC_STR "END")); this->sock.writeWait(packetStart, 4); this->sock.writeWait(packetP->getBytes(), packetP->getLength()); this->sock.writeWait(packetEnd, 4); } void packetSocket_impl::takeSomeEscapeSeq(const unsigned char * const buffer, size_t const length, size_t * const bytesTakenP) { /*---------------------------------------------------------------------------- Take and process some bytes from the incoming stream 'buffer', which contains 'length' bytes, assuming they are within an escape sequence. -----------------------------------------------------------------------------*/ size_t bytesTaken; bytesTaken = 0; while (this->escAccum.len < 3 && bytesTaken < length) this->escAccum.bytes[this->escAccum.len++] = buffer[bytesTaken++]; assert(this->escAccum.len <= 3); if (this->escAccum.len == 3) { if (0) { } else if (xmlrpc_memeq(this->escAccum.bytes, "NOP", 3)) { // Nothing to do } else if (xmlrpc_memeq(this->escAccum.bytes, "PKT", 3)) { this->packetAccumP = packetPtr(new packet); this->inPacket = true; } else if (xmlrpc_memeq(this->escAccum.bytes, "END", 3)) { if (this->inPacket) { this->readBuffer.push(this->packetAccumP); this->inPacket = false; this->packetAccumP = packetPtr(); } else throwf("END control word received without preceding PKT"); } else if (xmlrpc_memeq(this->escAccum.bytes, "ESC", 3)) { if (this->inPacket) this->packetAccumP->addData((const unsigned char *)ESC_STR, 1); else throwf("ESC control work received outside of a packet"); } else throwf("Invalid escape sequence 0x%02x%02x%02x read from " "stream socket under packet socket", this->escAccum.bytes[0], this->escAccum.bytes[1], this->escAccum.bytes[2]); this->inEscapeSeq = false; this->escAccum.len = 0; } *bytesTakenP = bytesTaken; } void packetSocket_impl::takeSomePacket(const unsigned char * const buffer, size_t const length, size_t * const bytesTakenP) { assert(!this->inEscapeSeq); const unsigned char * const escPos( (const unsigned char *)memchr(buffer, ESC, length)); if (escPos) { size_t const escOffset(escPos - &buffer[0]); // move everything before the escape sequence into the // packet accumulator. this->packetAccumP->addData(buffer, escOffset); // Caller can pick up from here; we don't know nothin' 'bout // no escape sequences. *bytesTakenP = escOffset; } else { // No complete packet yet and no substitution to do; // just throw the whole thing into the accumulator. this->packetAccumP->addData(buffer, length); *bytesTakenP = length; } } void packetSocket_impl::verifyNothingAccumulated() { /*---------------------------------------------------------------------------- Throw an error if there is a partial packet accumulated. -----------------------------------------------------------------------------*/ if (this->inEscapeSeq) throwf("Streams socket closed in the middle of an " "escape sequence"); if (this->inPacket) throwf("Stream socket closed in the middle of a packet " "(%u bytes of packet received; no END marker to mark " "end of packet)", (unsigned)this->packetAccumP->getLength()); } void packetSocket_impl::processBytesRead(const unsigned char * const buffer, size_t const bytesRead) { unsigned int cursor; // Cursor into buffer[] cursor = 0; while (cursor < bytesRead) { size_t bytesTaken; if (this->inEscapeSeq) this->takeSomeEscapeSeq(&buffer[cursor], bytesRead - cursor, &bytesTaken); else if (buffer[cursor] == ESC) { this->inEscapeSeq = true; bytesTaken = 1; } else if (this->inPacket) this->takeSomePacket(&buffer[cursor], bytesRead - cursor, &bytesTaken); else throwf("Byte 0x%02x is not in a packet or escape sequence. " "Sender is probably not using packet socket protocol", buffer[cursor]); cursor += bytesTaken; } } void packetSocket_impl::readFromFile() { /*---------------------------------------------------------------------------- Read some data from the underlying stream socket. Read as much as is available right now, up to 4K. Update 'this' to reflect the data read. E.g. if we read an entire packet, we add it to the packet buffer (this->readBuffer). If we read the first part of a packet, we add it to the packet accumulator (*this->packetAccumP). If we read the end of a packet, we add the full packet to the packet buffer and empty the packet accumulator. Etc. -----------------------------------------------------------------------------*/ bool wouldblock; wouldblock = false; while (this->readBuffer.empty() && !this->eof && !wouldblock) { unsigned char buffer[4096]; size_t bytesRead; this->sock.read(buffer, sizeof(buffer), &wouldblock, &bytesRead); if (!wouldblock) { if (bytesRead == 0) { this->eof = true; this->verifyNothingAccumulated(); } else this->processBytesRead(buffer, bytesRead); } } } void packetSocket_impl::read(bool * const eofP, bool * const gotPacketP, packetPtr * const packetPP) { /*---------------------------------------------------------------------------- Read one packet from the socket, through the internal packet buffer. If there is a packet immediately available, return it as *packetPP and return *gotPacketP true. Otherwise, return *gotPacketP false. Iff the socket has no more data coming (it is shut down) and there is no complete packet in the packet buffer, return *eofP. This leaves one other possibility: there is no full packet immediately available, but there may be in the future because the socket is still alive. In that case, we return *eofP == false and *gotPacketP == false. Any packet we return belongs to caller; Caller must delete it. -----------------------------------------------------------------------------*/ // Move any packets now waiting to be read in the underlying stream // socket into our packet buffer (this->readBuffer). this->readFromFile(); if (this->readBuffer.empty()) { *gotPacketP = false; *eofP = this->eof; } else { *gotPacketP = true; *eofP = false; *packetPP = this->readBuffer.front(); readBuffer.pop(); } } void packetSocket_impl::readWait(volatile const int * const interruptP, bool * const eofP, bool * const gotPacketP, packetPtr * const packetPP) { /*---------------------------------------------------------------------------- Read a packet from the packet socket. It may be already in the buffer. If not, wait as long as it takes for one to arrive. But stop waiting and return without a packet when *interruptP is true (but if we're in a system call, which we usually are, Caller will have to ensure that call gets interrupted, e.g. by receiving a signal, so that we notice *interruptP has changed). Also return without a packet if we reach EOF on the packet socket (i.e. the other side disconnected). Return *gotPacketP true iff we return a packet. Return *eofP true iff we hit EOF. -----------------------------------------------------------------------------*/ bool gotPacket; bool eof; gotPacket = false; eof = false; while (!gotPacket && !eof && !*interruptP) { this->sock.waitForReadable(); this->read(&eof, &gotPacket, packetPP); } *gotPacketP = gotPacket; *eofP = eof; } packetSocket::packetSocket(int const sockFd) { this->implP = new packetSocket_impl(sockFd); } packetSocket::~packetSocket() { delete(this->implP); } void packetSocket::writeWait(packetPtr const& packetP) const { implP->writeWait(packetP); } void packetSocket::read(bool * const eofP, bool * const gotPacketP, packetPtr * const packetPP) { this->implP->read(eofP, gotPacketP, packetPP); } void packetSocket::readWait(volatile const int * const interruptP, bool * const eofP, bool * const gotPacketP, packetPtr * const packetPP) { this->implP->readWait(interruptP, eofP, gotPacketP, packetPP); } void packetSocket::readWait(volatile const int * const interruptP, bool * const eofP, packetPtr * const packetPP) { bool gotPacket; this->implP->readWait(interruptP, eofP, &gotPacket, packetPP); if (!gotPacket) throwf("Packet read was interrupted"); } void packetSocket::readWait(bool * const eofP, packetPtr * const packetPP) { int const interrupt(0); // Never interrupt this->readWait(&interrupt, eofP, packetPP); } } // namespace xmlrpc-c-1.33.14/src/cpp/param_list.cpp000066400000000000000000000205471236133176700176410ustar00rootroot00000000000000#include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "xmlrpc-c/base.h" #include "xmlrpc-c/base.hpp" using namespace std; using namespace xmlrpc_c; namespace xmlrpc_c { paramList::paramList(unsigned int const paramCount) { this->paramVector.reserve(paramCount); } paramList& paramList::add(xmlrpc_c::value const param) { // Note: Before Xmlrpc-c 1.10, the return value was void. Old programs // using this new add() won't notice the difference. New programs // using this new add() against an old library will, since the old // add() will not return anything. A new program that wants to get // a link error instead of a crash in this case can use addx() instead. this->paramVector.push_back(param); return *this; } paramList& paramList::addx(xmlrpc_c::value const param) { // See add() for an explanation of why this exists. return this->add(param); } unsigned int paramList::size() const { return this->paramVector.size(); } xmlrpc_c::value paramList::operator[](unsigned int const subscript) const { if (subscript >= this->paramVector.size()) throw(girerr::error( "Subscript of xmlrpc_c::paramList out of bounds")); return this->paramVector[subscript]; } int paramList::getInt(unsigned int const paramNumber, int const minimum, int const maximum) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); if (this->paramVector[paramNumber].type() != value::TYPE_INT) throw(fault("Parameter that is supposed to be integer is not", fault::CODE_TYPE)); int const intvalue(static_cast( value_int(this->paramVector[paramNumber]))); if (intvalue < minimum) throw(fault("Integer parameter too low", fault::CODE_TYPE)); if (intvalue > maximum) throw(fault("Integer parameter too high", fault::CODE_TYPE)); return intvalue; } bool paramList::getBoolean(unsigned int const paramNumber) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); if (this->paramVector[paramNumber].type() != value::TYPE_BOOLEAN) throw(fault("Parameter that is supposed to be boolean is not", fault::CODE_TYPE)); return static_cast(value_boolean(this->paramVector[paramNumber])); } double paramList::getDouble(unsigned int const paramNumber, double const minimum, double const maximum) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); if (this->paramVector[paramNumber].type() != value::TYPE_DOUBLE) throw(fault("Parameter that is supposed to be floating point number " "is not", fault::CODE_TYPE)); double const doublevalue(static_cast( value_double(this->paramVector[paramNumber]))); if (doublevalue < minimum) throw(fault("Floating point number parameter too low", fault::CODE_TYPE)); if (doublevalue > maximum) throw(fault("Floating point number parameter too high", fault::CODE_TYPE)); return doublevalue; } time_t paramList::getDatetime_sec( unsigned int const paramNumber, paramList::timeConstraint const constraint) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]); if (paramP->type() != value::TYPE_DATETIME) throw(fault("Parameter that is supposed to be a datetime is not", fault::CODE_TYPE)); time_t const timeValue(static_cast(value_datetime(*paramP))); time_t const now(time(NULL)); switch (constraint) { case TC_ANY: /* He'll take anything; no problem */ break; case TC_NO_FUTURE: if (timeValue > now) throw(fault("Datetime parameter that is not supposed to be in " "the future is.", fault::CODE_TYPE)); break; case TC_NO_PAST: if (timeValue < now) throw(fault("Datetime parameter that is not supposed to be in " "the past is.", fault::CODE_TYPE)); break; } return timeValue; } string paramList::getString(unsigned int const paramNumber) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); if (this->paramVector[paramNumber].type() != value::TYPE_STRING) throw(fault("Parameter that is supposed to be a string is not", fault::CODE_TYPE)); return static_cast(value_string(this->paramVector[paramNumber])); } std::vector paramList::getBytestring(unsigned int const paramNumber) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]); if (paramP->type() != value::TYPE_BYTESTRING) throw(fault("Parameter that is supposed to be a byte string is not", fault::CODE_TYPE)); return value_bytestring(*paramP).vectorUcharValue(); } std::vector paramList::getArray(unsigned int const paramNumber, unsigned int const minSize, unsigned int const maxSize) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]); if (paramP->type() != value::TYPE_ARRAY) throw(fault("Parameter that is supposed to be an array is not", fault::CODE_TYPE)); xmlrpc_c::value_array const arrayValue(*paramP); if (arrayValue.size() < minSize) throw(fault("Array parameter has too few elements", fault::CODE_TYPE)); if (arrayValue.size() > maxSize) throw(fault("Array parameter has too many elements", fault::CODE_TYPE)); return value_array(*paramP).vectorValueValue(); } std::map paramList::getStruct(unsigned int const paramNumber) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); const xmlrpc_c::value * const paramP(&this->paramVector[paramNumber]); if (paramP->type() != value::TYPE_STRUCT) throw(fault("Parameter that is supposed to be a structure is not", fault::CODE_TYPE)); return static_cast >( value_struct(*paramP)); } void paramList::getNil(unsigned int const paramNumber) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); if (this->paramVector[paramNumber].type() != value::TYPE_NIL) throw(fault("Parameter that is supposed to be nil is not", fault::CODE_TYPE)); } xmlrpc_int64 paramList::getI8(unsigned int const paramNumber, xmlrpc_int64 const minimum, xmlrpc_int64 const maximum) const { if (paramNumber >= this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); if (this->paramVector[paramNumber].type() != value::TYPE_I8) throw(fault("Parameter that is supposed to be 64-bit integer is not", fault::CODE_TYPE)); long long const longlongvalue(static_cast( value_i8(this->paramVector[paramNumber]))); if (longlongvalue < minimum) throw(fault("64-bit integer parameter too low", fault::CODE_TYPE)); if (longlongvalue > maximum) throw(fault("64-bit integer parameter too high", fault::CODE_TYPE)); return longlongvalue; } void paramList::verifyEnd(unsigned int const paramNumber) const { if (paramNumber < this->paramVector.size()) throw(fault("Too many parameters", fault::CODE_TYPE)); if (paramNumber > this->paramVector.size()) throw(fault("Not enough parameters", fault::CODE_TYPE)); } } // namespace xmlrpc-c-1.33.14/src/cpp/pstream.cpp000066400000000000000000000101261236133176700171510ustar00rootroot00000000000000/*============================================================================= pstream =============================================================================== Client XML transport for Xmlrpc-c based on a very simple byte stream. The protocol we use is the "packet socket" protocol, which is an Xmlrpc-c invention. It is an almost trivial representation of a sequence of packets on a byte stream. A transport object talks to exactly one server over its lifetime. You can create a pstream transport from any file descriptor from which you can read and write a bidirectional character stream. Typically, it's a TCP socket. This transport is synchronous only. It does not provide a working 'start' method. You have at most one outstanding RPC and wait for it to complete. By Bryan Henderson 07.05.12. Contributed to the public domain by its author. =============================================================================*/ #include #include "xmlrpc-c/girerr.hpp" using girerr::throwf; #include "xmlrpc-c/packetsocket.hpp" #include "xmlrpc-c/client_transport.hpp" using namespace std; namespace xmlrpc_c { struct clientXmlTransport_pstream::constrOpt_impl { constrOpt_impl(); struct { int fd; } value; struct { bool fd; } present; }; clientXmlTransport_pstream::constrOpt_impl::constrOpt_impl() { this->present.fd = false; } #define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ clientXmlTransport_pstream::constrOpt & \ clientXmlTransport_pstream::constrOpt::OPTION_NAME(TYPE const& arg) { \ this->implP->value.OPTION_NAME = arg; \ this->implP->present.OPTION_NAME = true; \ return *this; \ } DEFINE_OPTION_SETTER(fd, xmlrpc_socket); #undef DEFINE_OPTION_SETTER clientXmlTransport_pstream::constrOpt::constrOpt() { this->implP = new clientXmlTransport_pstream::constrOpt_impl(); } clientXmlTransport_pstream::constrOpt::~constrOpt() { delete(this->implP); } clientXmlTransport_pstream::constrOpt::constrOpt(constrOpt& arg) { this->implP = new clientXmlTransport_pstream::constrOpt_impl(*arg.implP); } clientXmlTransport_pstream::clientXmlTransport_pstream( constrOpt const& optExt) { constrOpt_impl const opt(*optExt.implP); if (!opt.present.fd) throwf("You must provide a 'fd' constructor option."); auto_ptr packetSocketAP; try { auto_ptr p(new packetSocket(opt.value.fd)); packetSocketAP = p; } catch (exception const& e) { throwf("Unable to create packet socket out of file descriptor %d. %s", opt.value.fd, e.what()); } this->packetSocketP = packetSocketAP.get(); packetSocketAP.release(); } clientXmlTransport_pstream::~clientXmlTransport_pstream() { delete(this->packetSocketP); } void clientXmlTransport_pstream::call( carriageParm * const carriageParmP, string const& callXml, string * const responseXmlP) { carriageParm_pstream * const carriageParmPstreamP( dynamic_cast(carriageParmP)); if (carriageParmPstreamP == NULL) throwf("Pstream client XML transport called with carriage " "parameter object not of class carriageParm_pstream"); packetPtr const callPacketP(new packet(callXml.c_str(), callXml.length())); try { this->packetSocketP->writeWait(callPacketP); } catch (exception const& e) { throwf("Failed to write the call to the packet socket. %s", e.what()); } packetPtr responsePacketP; try { bool eof; this->packetSocketP->readWait(&eof, &responsePacketP); if (eof) throwf("The other end closed the socket before sending " "the response."); } catch (exception const& e) { throwf("We sent the call, but couldn't get the response. %s", e.what()); } *responseXmlP = string(reinterpret_cast(responsePacketP->getBytes()), responsePacketP->getLength()); } } // namespace xmlrpc-c-1.33.14/src/cpp/registry.cpp000066400000000000000000000363721236133176700173610ustar00rootroot00000000000000#include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::throwf; #include "xmlrpc-c/girmem.hpp" using girmem::autoObject; using girmem::autoObjectPtr; #include "xmlrpc-c/base.h" #include "xmlrpc-c/base.hpp" #include "env_wrap.hpp" #include "xmlrpc-c/registry.hpp" using namespace std; using namespace xmlrpc_c; callInfo::callInfo() { // Even though this is the builtin default default constructor, we need // this because some compilers won't use the builtin default to construct // a constant (e.g. "callInfo const junk;"); I don't know why. } callInfo::~callInfo() {} namespace { void throwIfError(env_wrap const& env) { if (env.env_c.fault_occurred) throw(girerr::error(env.env_c.fault_string)); } } // namespace namespace xmlrpc_c { method::method() : _signature("?"), _help("No help is available for this method") {}; method::~method() {} methodPtr::methodPtr(method * const methodP) { this->point(methodP); } method * methodPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } method2::method2() {} method2::~method2() {} void method2::execute(xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const resultP) { callInfo const nullCallInfo; execute(paramList, &nullCallInfo, resultP); } defaultMethod::~defaultMethod() {} defaultMethodPtr::defaultMethodPtr() {} defaultMethodPtr::defaultMethodPtr(defaultMethod * const methodP) { this->point(methodP); } defaultMethod * defaultMethodPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } defaultMethod * defaultMethodPtr::get() const { autoObject * const p(this->objectP); return dynamic_cast(p); } struct registry_impl { xmlrpc_registry * c_registryP; // Pointer to the C registry object we use to implement this // object. std::list methodList; // This is a list of all the method objects (actually, pointers // to them). But since the real registry is the C registry object, // all this list is for is to maintain references to the objects // to which the C registry points so that they continue to exist. xmlrpc_c::defaultMethodPtr defaultMethodP; // The real identifier of the default method is the C registry // object; this member exists only to maintain a reference to the // object to which the C registry points so that it will continue // to exist. registry_impl(); ~registry_impl(); }; registry_impl::registry_impl() { env_wrap env; this->c_registryP = xmlrpc_registry_new(&env.env_c); throwIfError(env); } registry_impl::~registry_impl() { xmlrpc_registry_free(this->c_registryP); } registry::registry() { this->implP = new registry_impl(); } registry::~registry(void) { delete(this->implP); } registryPtr::registryPtr() {} registryPtr::registryPtr(registry * const registryP) { this->point(registryP); } registry * registryPtr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } registry * registryPtr::get() const { autoObject * const p(this->objectP); return dynamic_cast(p); } static xmlrpc_c::paramList pListFromXmlrpcArray(xmlrpc_value * const arrayP) { /*---------------------------------------------------------------------------- Convert an XML-RPC array in C (not C++) form to a parameter list object that can be passed to a method execute method. This is glue code to allow us to hook up C++ Xmlrpc-c code to C Xmlrpc-c code. -----------------------------------------------------------------------------*/ env_wrap env; XMLRPC_ASSERT_ARRAY_OK(arrayP); unsigned int const arraySize = xmlrpc_array_size(&env.env_c, arrayP); assert(!env.env_c.fault_occurred); xmlrpc_c::paramList paramList(arraySize); for (unsigned int i = 0; i < arraySize; ++i) { xmlrpc_value * arrayItemP; xmlrpc_array_read_item(&env.env_c, arrayP, i, &arrayItemP); assert(!env.env_c.fault_occurred); paramList.add(xmlrpc_c::value(arrayItemP)); xmlrpc_DECREF(arrayItemP); } return paramList; } static xmlrpc_value * c_executeMethod(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const methodPtr, void * const callInfoPtr) { /*---------------------------------------------------------------------------- This is a function designed to be called via a C registry to execute an XML-RPC method, but use a C++ method object to do the work. You register this function as the method function and a pointer to the C++ method object as the method data in the C registry. If we had a pure C++ registry, this would be unnecessary. Since we can't throw an error back to the C code, we catch anything the XML-RPC method's execute() method throws, and any error we encounter in processing the result it returns, and turn it into an XML-RPC method failure. This will cause a leak if the execute() method actually created a result, since it will not get destroyed. This function is of type 'xmlrpc_method2'. -----------------------------------------------------------------------------*/ method * const methodP(static_cast(methodPtr)); paramList const paramList(pListFromXmlrpcArray(paramArrayP)); callInfo * const callInfoP(static_cast(callInfoPtr)); xmlrpc_value * retval; retval = NULL; // silence used-before-set warning try { value result; try { method2 * const method2P(dynamic_cast(methodP)); if (method2P) method2P->execute(paramList, callInfoP, &result); else methodP->execute(paramList, &result); } catch (xmlrpc_c::fault const& fault) { xmlrpc_env_set_fault(envP, fault.getCode(), fault.getDescription().c_str()); } if (!envP->fault_occurred) { if (result.isInstantiated()) retval = result.cValue(); else throwf("Xmlrpc-c user's xmlrpc_c::method object's " "'execute method' failed to set the RPC result " "value."); } } catch (exception const& e) { xmlrpc_faultf(envP, "Unexpected error executing code for " "particular method, detected by Xmlrpc-c " "method registry code. Method did not " "fail; rather, it did not complete at all. %s", e.what()); } catch (...) { xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, "Unexpected error executing code for " "particular method, detected by Xmlrpc-c " "method registry code. Method did not " "fail; rather, it did not complete at all."); } return retval; } static xmlrpc_value * c_executeDefaultMethod(xmlrpc_env * const envP, const char * const , // host const char * const methodName, xmlrpc_value * const paramArrayP, void * const methodPtr) { /*---------------------------------------------------------------------------- This is a function designed to be called via a C registry to execute an XML-RPC method, but use a C++ method object to do the work. You register this function as the default method function and a pointer to the C++ default method object as the method data in the C registry. If we had a pure C++ registry, this would be unnecessary. Since we can't throw an error back to the C code, we catch anything the XML-RPC method's execute() method throws, and any error we encounter in processing the result it returns, and turn it into an XML-RPC method failure. This will cause a leak if the execute() method actually created a result, since it will not get destroyed. -----------------------------------------------------------------------------*/ defaultMethod * const methodP = static_cast(methodPtr); paramList const paramList(pListFromXmlrpcArray(paramArrayP)); xmlrpc_value * retval; retval = NULL; // silence used-before-set warning try { xmlrpc_c::value result; try { methodP->execute(methodName, paramList, &result); } catch (xmlrpc_c::fault const& fault) { xmlrpc_env_set_fault(envP, fault.getCode(), fault.getDescription().c_str()); } if (!envP->fault_occurred) { if (result.isInstantiated()) retval = result.cValue(); else throwf("Xmlrpc-c user's xmlrpc_c::defaultMethod object's " "'execute method' failed to set the RPC result " "value."); } } catch (exception const& e) { xmlrpc_faultf(envP, "Unexpected error executing default " "method code, detected by Xmlrpc-c " "method registry code. Method did not " "fail; rather, it did not complete at all. %s", e.what()); } catch (...) { xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, "Unexpected error executing default " "method code, detected by Xmlrpc-c " "method registry code. Method did not " "fail; rather, it did not complete at all."); } return retval; } void registry::addMethod(string const name, methodPtr const methodP) { this->implP->methodList.push_back(methodP); struct xmlrpc_method_info3 methodInfo; env_wrap env; methodInfo.methodName = name.c_str(); methodInfo.methodFunction = &c_executeMethod; methodInfo.serverInfo = methodP.get(); methodInfo.stackSize = 0; string const signatureString(methodP->signature()); methodInfo.signatureString = signatureString.c_str(); string const help(methodP->help()); methodInfo.help = help.c_str(); xmlrpc_registry_add_method3(&env.env_c, this->implP->c_registryP, &methodInfo); throwIfError(env); } void registry::setDefaultMethod(defaultMethodPtr const methodP) { this->implP->defaultMethodP = methodP; env_wrap env; xmlrpc_registry_set_default_method( &env.env_c, this->implP->c_registryP, &c_executeDefaultMethod, (void*) methodP.get()); throwIfError(env); } void registry::disableIntrospection() { xmlrpc_registry_disable_introspection(this->implP->c_registryP); } static xmlrpc_server_shutdown_fn shutdownServer; static void shutdownServer(xmlrpc_env * const envP, void * const context, const char * const comment, void * const callInfo) { registry::shutdown * const shutdownP( static_cast(context)); assert(shutdownP != NULL); try { shutdownP->doit(string(comment), callInfo); } catch (exception const& e) { xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, e.what()); } } void registry::setShutdown(const registry::shutdown * const shutdownP) { void * const context(const_cast(shutdownP)); xmlrpc_registry_set_shutdown(this->implP->c_registryP, &shutdownServer, context); } void registry::setDialect(xmlrpc_dialect const dialect) { env_wrap env; xmlrpc_registry_set_dialect(&env.env_c, this->implP->c_registryP, dialect); throwIfError(env); } void registry::processCall(string const& callXml, const callInfo * const callInfoP, string * const responseXmlP) const { /*---------------------------------------------------------------------------- Process an XML-RPC call whose XML is 'callXml'. Return the response XML as *responseXmlP. If we are unable to execute the call, we throw an error. But if the call executes and the method merely fails in an XML-RPC sense, we don't. In that case, *responseXmlP indicates the failure. -----------------------------------------------------------------------------*/ env_wrap env; xmlrpc_mem_block * response; // For the pure C++ version, this will have to parse 'callXml' // into a method name and parameters, look up the method name in // the registry, call the method's execute() method, then marshall // the result into XML and return it as *responseXmlP. It will // also have to execute system methods (e.g. introspection) // itself. This will be more or less like what // xmlrpc_registry_process_call() does. xmlrpc_registry_process_call2( &env.env_c, this->implP->c_registryP, callXml.c_str(), callXml.length(), const_cast(callInfoP), &response); throwIfError(env); *responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, response), XMLRPC_MEMBLOCK_SIZE(char, response)); xmlrpc_mem_block_free(response); } void registry::processCall(string const& callXml, string * const responseXmlP) const { /*---------------------------------------------------------------------------- Process an XML-RPC call whose XML is 'callXml'. Return the response XML as *responseXmlP. If we are unable to execute the call, we throw an error. But if the call executes and the method merely fails in an XML-RPC sense, we don't. In that case, *responseXmlP indicates the failure. -----------------------------------------------------------------------------*/ env_wrap env; xmlrpc_mem_block * output; // For the pure C++ version, this will have to parse 'callXml' // into a method name and parameters, look up the method name in // the registry, call the method's execute() method, then marshall // the result into XML and return it as *responseXmlP. It will // also have to execute system methods (e.g. introspection) // itself. This will be more or less like what // xmlrpc_registry_process_call() does. output = xmlrpc_registry_process_call( &env.env_c, this->implP->c_registryP, NULL, callXml.c_str(), callXml.length()); throwIfError(env); *responseXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, output), XMLRPC_MEMBLOCK_SIZE(char, output)); xmlrpc_mem_block_free(output); } #define PROCESS_CALL_STACK_SIZE 256 // This is our liberal estimate of how much stack space // registry::processCall() needs, not counting what // the call the to C registry uses. size_t registry::maxStackSize() const { return xmlrpc_registry_max_stackSize(this->implP->c_registryP) + PROCESS_CALL_STACK_SIZE; } } // namespace registry::shutdown::~shutdown() {} xmlrpc-c-1.33.14/src/cpp/server_abyss.cpp000066400000000000000000000675171236133176700202250ustar00rootroot00000000000000#include "xmlrpc_config.h" #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/abyss.h */ #include #include #include #include #include #include #if !MSVCRT # include #endif #include "assertx.hpp" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/base.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/abyss.h" #include "xmlrpc-c/server_abyss.h" #include "xmlrpc-c/registry.hpp" #include "env_wrap.hpp" #include "xmlrpc-c/server_abyss.hpp" using namespace std; using namespace xmlrpc_c; namespace xmlrpc_c { namespace { static void sigterm(int const signalClass) { cerr << "Signal of Class " << signalClass << " received. Exiting" << endl; exit(1); } static void sigchld(int const ASSERT_ONLY_ARG(signalClass)) { /*---------------------------------------------------------------------------- This is a signal handler for a SIGCHLD signal (which informs us that one of our child processes has terminated). The only child processes we have are those that belong to the Abyss server (and then only if the Abyss server was configured to use forking as a threading mechanism), so we respond by passing the signal on to the Abyss server. And reaping the dead child. -----------------------------------------------------------------------------*/ #ifndef _WIN32 // Reap zombie children / report to Abyss until there aren't any more. bool zombiesExist; bool error; assert(signalClass == SIGCHLD); zombiesExist = true; // initial assumption error = false; // no error yet while (zombiesExist && !error) { int status; pid_t const pid = waitpid((pid_t) -1, &status, WNOHANG); if (pid == 0) zombiesExist = false; else if (pid < 0) { /* because of ptrace */ if (errno == EINTR) { // This is OK - it's a ptrace notification } else error = true; } else ServerHandleSigchld(pid); } #endif /* _WIN32 */ } struct signalHandlers { #ifndef WIN32 struct sigaction term; struct sigaction int_; struct sigaction hup; struct sigaction usr1; struct sigaction pipe; struct sigaction chld; #else int dummy; #endif }; void setupSignalHandlers(struct signalHandlers * const oldHandlersP) { #ifndef _WIN32 struct sigaction mysigaction; sigemptyset(&mysigaction.sa_mask); mysigaction.sa_flags = 0; /* These signals abort the program, with tracing */ mysigaction.sa_handler = sigterm; sigaction(SIGTERM, &mysigaction, &oldHandlersP->term); sigaction(SIGINT, &mysigaction, &oldHandlersP->int_); sigaction(SIGHUP, &mysigaction, &oldHandlersP->hup); sigaction(SIGUSR1, &mysigaction, &oldHandlersP->usr1); /* This signal indicates connection closed in the middle */ mysigaction.sa_handler = SIG_IGN; sigaction(SIGPIPE, &mysigaction, &oldHandlersP->pipe); /* This signal indicates a child process (request handler) has died */ mysigaction.sa_handler = sigchld; sigaction(SIGCHLD, &mysigaction, &oldHandlersP->chld); #endif } void restoreSignalHandlers(struct signalHandlers const& oldHandlers) { #ifndef _WIN32 sigaction(SIGCHLD, &oldHandlers.chld, NULL); sigaction(SIGPIPE, &oldHandlers.pipe, NULL); sigaction(SIGUSR1, &oldHandlers.usr1, NULL); sigaction(SIGHUP, &oldHandlers.hup, NULL); sigaction(SIGINT, &oldHandlers.int_, NULL); sigaction(SIGTERM, &oldHandlers.term, NULL); #endif } // We need 'global' because methods of class serverAbyss call // functions in the Abyss C library. By virtue of global's static // storage class, the program loader will call its constructor and // destructor and thus initialize and terminate the Abyss C library. class abyssGlobalState { public: abyssGlobalState() { const char * error; AbyssInit(&error); if (error) { string const e(error); xmlrpc_strfree(error); throwf("AbyssInit() failed. %s", e.c_str()); } } ~abyssGlobalState() { AbyssTerm(); } } const global; } // namespace callInfo_serverAbyss::callInfo_serverAbyss( serverAbyss * const serverAbyssP, TSession * const abyssSessionP) : serverAbyssP(serverAbyssP), abyssSessionP(abyssSessionP) {} struct serverAbyss::constrOpt_impl { constrOpt_impl(); struct value { xmlrpc_c::registryPtr registryPtr; const xmlrpc_c::registry * registryP; XMLRPC_SOCKET socketFd; unsigned int portNumber; unsigned int maxConn; unsigned int maxConnBacklog; unsigned int keepaliveTimeout; unsigned int keepaliveMaxConn; unsigned int timeout; bool dontAdvertise; std::string uriPath; bool chunkResponse; std::string allowOrigin; unsigned int accessCtlMaxAge; const struct sockaddr * sockAddrP; socklen_t sockAddrLen; std::string logFileName; bool serverOwnsSignals; bool expectSigchld; } value; struct { bool registryPtr; bool registryP; bool socketFd; bool portNumber; bool maxConn; bool maxConnBacklog; bool keepaliveTimeout; bool keepaliveMaxConn; bool timeout; bool dontAdvertise; bool uriPath; bool chunkResponse; bool allowOrigin; bool accessCtlMaxAge; bool sockAddrP; bool sockAddrLen; bool logFileName; bool serverOwnsSignals; bool expectSigchld; } present; }; serverAbyss::constrOpt_impl::constrOpt_impl() { present.registryPtr = false; present.registryP = false; present.socketFd = false; present.portNumber = false; present.logFileName = false; present.maxConn = false; present.maxConnBacklog = false; present.keepaliveTimeout = false; present.keepaliveMaxConn = false; present.timeout = false; present.dontAdvertise = false; present.uriPath = false; present.chunkResponse = false; present.allowOrigin = false; present.accessCtlMaxAge = false; present.sockAddrP = false; present.sockAddrLen = false; present.serverOwnsSignals = false; present.expectSigchld = false; // Set default values value.dontAdvertise = false; value.uriPath = string("/RPC2"); value.chunkResponse = false; value.serverOwnsSignals = true; value.expectSigchld = false; } #define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ serverAbyss::constrOpt & \ serverAbyss::constrOpt::OPTION_NAME(TYPE const& arg) { \ this->implP->value.OPTION_NAME = arg; \ this->implP->present.OPTION_NAME = true; \ return *this; \ } DEFINE_OPTION_SETTER(registryPtr, xmlrpc_c::registryPtr); DEFINE_OPTION_SETTER(registryP, const registry *); DEFINE_OPTION_SETTER(socketFd, XMLRPC_SOCKET); DEFINE_OPTION_SETTER(portNumber, unsigned int); DEFINE_OPTION_SETTER(maxConn, unsigned int); DEFINE_OPTION_SETTER(maxConnBacklog, unsigned int); DEFINE_OPTION_SETTER(keepaliveTimeout, unsigned int); DEFINE_OPTION_SETTER(keepaliveMaxConn, unsigned int); DEFINE_OPTION_SETTER(timeout, unsigned int); DEFINE_OPTION_SETTER(dontAdvertise, bool); DEFINE_OPTION_SETTER(uriPath, string); DEFINE_OPTION_SETTER(chunkResponse, bool); DEFINE_OPTION_SETTER(allowOrigin, string); DEFINE_OPTION_SETTER(accessCtlMaxAge, unsigned int); DEFINE_OPTION_SETTER(sockAddrP, const struct sockaddr *); DEFINE_OPTION_SETTER(sockAddrLen, socklen_t); DEFINE_OPTION_SETTER(logFileName, string); DEFINE_OPTION_SETTER(serverOwnsSignals, bool); DEFINE_OPTION_SETTER(expectSigchld, bool); #undef DEFINE_OPTION_SETTER serverAbyss::constrOpt::constrOpt() { this->implP = new serverAbyss::constrOpt_impl(); } serverAbyss::constrOpt::~constrOpt() { delete(this->implP); } struct SockAddr { const struct sockaddr * const sockAddrP; socklen_t const sockAddrLen; SockAddr(const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen) : sockAddrP (sockAddrP), sockAddrLen (sockAddrLen) {} }; struct serverAbyss_impl { registryPtr regPtr; // This just holds a reference to the registry so that it may // get destroyed when the serverAbyss gets destroyed. If the // creator of the serverAbyss is managing lifetime himself, // this is a null pointer. 'registryP' is what you really use // to access the registry. const registry * registryP; TServer cServer; TChanSwitch * chanSwitchP; // Handle of the channel switch we created. Null if we didn't. // When user wants us to accept connections, we create a channel // switch and create a server based on it; otherwise, we don't. serverAbyss_impl(serverAbyss::constrOpt_impl const& opt, serverAbyss * const serverAbyssP); ~serverAbyss_impl(); void run(); void processCall(std::string const& call, TSession * const abyssSessionP, std::string * const responseP); serverAbyss * const serverAbyssP; // The server for which we are the implementation. bool expectSigchld; bool serverOwnsSignals; }; static void processXmlrpcCall(xmlrpc_env * const envP, void * const arg, const char * const callXml, size_t const callXmlLen, TSession * const abyssSessionP, xmlrpc_mem_block ** const responseXmlPP) { /*---------------------------------------------------------------------------- This is an XML-RPC XML call processor, as called by the HTTP request handler of the libxmlrpc_server_abyss C library. 'callXml'/'callXmlLen' is the XML text of a supposed XML-RPC call. We execute the RPC and return the XML text of the XML-RPC response as *responseXmlPP. 'arg' carries the information that tells us how to do that; e.g. what XML-RPC methods are defined. -----------------------------------------------------------------------------*/ serverAbyss_impl * const implP( static_cast(arg)); try { string const call(callXml, callXmlLen); string response; implP->processCall(call, abyssSessionP, &response); xmlrpc_mem_block * responseMbP; responseMbP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); if (!envP->fault_occurred) { XMLRPC_MEMBLOCK_APPEND(char, envP, responseMbP, response.c_str(), response.length()); *responseXmlPP = responseMbP; } } catch (exception const& e) { xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, e.what()); } } static void validateListenOptions(serverAbyss::constrOpt_impl const& opt) { if ((opt.present.portNumber ? 1 : 0) + (opt.present.socketFd ? 1 : 0) + (opt.present.sockAddrP ? 1 : 0) > 1) throwf("You can specify at most one of portNumber, socketFd, " "and sockAddrP options"); if (opt.present.sockAddrP && !opt.present.sockAddrLen) throwf("You must specify the sockAddrLen option when you " "specify sockAddrP"); if (!opt.present.sockAddrP && opt.present.sockAddrLen) throwf("The sockAddrLen option does not make sense without " "sockAddrP"); if (opt.present.portNumber) { if (opt.value.portNumber > 0xffff) throwf("Port number %u exceeds the maximum possible port number " "(65535)", opt.value.portNumber); } } static void createServerFromSwitch(TServer * const serverP, TChanSwitch * const chanSwitchP) { const char * error; ServerCreateSwitch(serverP, chanSwitchP, &error); if (error) { throwf("Abyss failed to create server. %s", error); xmlrpc_strfree(error); } } static TChanSwitch * newChanSwitchOsSocket(int const socketFd) { TChanSwitch * chanSwitchP; const char * error; #ifdef WIN32 ChanSwitchWinCreateWinsock(socketFd, &chanSwitchP, &error); #else ChanSwitchUnixCreateFd(socketFd, &chanSwitchP, &error); #endif if (error) { string const errorS(error); xmlrpc_strfree(error); throwf("Abyss failed to create a channel switch from the " "supplied listen socket. %s", errorS.c_str()); } return chanSwitchP; } static void chanSwitchCreateSockAddr(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP) { const char * error; #ifdef WIN32 ChanSwitchWinCreate2(protocolFamily, sockAddrP, sockAddrLen, chanSwitchPP, &error); #else ChanSwitchUnixCreate2(protocolFamily, sockAddrP, sockAddrLen, chanSwitchPP, &error); #endif if (error) { string const errorS(error); xmlrpc_strfree(error); throwf("Unable to create Abyss channel switch from socket address. " "%s", errorS.c_str()); } } static TChanSwitch * newChanSwitchSockAddr(SockAddr const& sockAddr) { int protocolFamily; switch (sockAddr.sockAddrP->sa_family) { case AF_INET: protocolFamily = PF_INET; break; case AF_INET6: protocolFamily = PF_INET6; break; default: throwf("Unknown socket address family %d. " "We know only AF_INET and AF_INET6.", sockAddr.sockAddrP->sa_family); } TChanSwitch * chanSwitchP; chanSwitchCreateSockAddr(protocolFamily, sockAddr.sockAddrP, sockAddr.sockAddrLen, &chanSwitchP); return chanSwitchP; } static TChanSwitch * newChanSwitchIpV4Port(unsigned int const portNumber) { struct sockaddr_in sockAddr; sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(portNumber); sockAddr.sin_addr.s_addr = INADDR_ANY; TChanSwitch * chanSwitchP; chanSwitchCreateSockAddr(PF_INET, (const struct sockaddr *)&sockAddr, sizeof(sockAddr), &chanSwitchP); return chanSwitchP; } static void createServerBare(bool const logFileNameGiven, string const& logFileName, bool const socketFdGiven, int const socketFd, bool const portNumberGiven, unsigned int const portNumber, bool const sockAddrPGiven, SockAddr const& sockAddr, TServer * const serverP, TChanSwitch ** const chanSwitchPP) { const char * const serverName("XmlRpcServer"); if (socketFdGiven || sockAddrPGiven || portNumberGiven) { TChanSwitch * const chanSwitchP( socketFdGiven ? newChanSwitchOsSocket(socketFd) : sockAddrPGiven ? newChanSwitchSockAddr(sockAddr) : portNumberGiven ? newChanSwitchIpV4Port(portNumber) : NULL); assert(chanSwitchP); try { createServerFromSwitch(serverP, chanSwitchP); try { ServerSetName(serverP, serverName); if (logFileNameGiven) ServerSetLogFileName(serverP, logFileName.c_str()); } catch (...) { ServerFree(serverP); throw; } } catch (...) { ChanSwitchDestroy(chanSwitchP); throw; } *chanSwitchPP = chanSwitchP; } else { const char * const logfileArg(logFileNameGiven ? logFileName.c_str() : NULL); ServerCreateNoAccept(serverP, serverName, DEFAULT_DOCS, logfileArg); *chanSwitchPP = NULL; } } static void setAdditionalServerParms(TServer * const serverP, serverAbyss::constrOpt_impl const& opt) { if (opt.present.maxConn) ServerSetMaxConn(serverP, opt.value.maxConn); if (opt.present.maxConnBacklog) ServerSetMaxConnBacklog(serverP, opt.value.maxConnBacklog); if (opt.present.keepaliveTimeout) ServerSetKeepaliveTimeout(serverP, opt.value.keepaliveTimeout); if (opt.present.keepaliveMaxConn) ServerSetKeepaliveMaxConn(serverP, opt.value.keepaliveMaxConn); if (opt.present.timeout) ServerSetTimeout(serverP, opt.value.timeout); ServerSetAdvertise(serverP, !opt.value.dontAdvertise); if (opt.value.expectSigchld) ServerUseSigchld(serverP); } static void setHttpReqHandlers(TServer * const serverP, void * const serverHandle, size_t const maxStackSize, string const& uriPath, bool const chunkResponse, bool const doHttpAccessControl, string const& allowOrigin, bool const accessCtlExpires, unsigned int const accessCtlMaxAge) { env_wrap env; xmlrpc_server_abyss_handler_parms parms; parms.xml_processor = &processXmlrpcCall; parms.xml_processor_arg = serverHandle; parms.xml_processor_max_stack = maxStackSize; parms.uri_path = uriPath.c_str(); parms.chunk_response = chunkResponse; parms.allow_origin = doHttpAccessControl ? allowOrigin.c_str() : NULL; parms.access_ctl_expires = accessCtlExpires; parms.access_ctl_max_age = accessCtlMaxAge; xmlrpc_server_abyss_set_handler3( &env.env_c, serverP, &parms, XMLRPC_AHPSIZE(access_ctl_max_age)); if (env.env_c.fault_occurred) throwf("Failed to register the HTTP handler for XML-RPC " "with the underlying Abyss HTTP server. " "xmlrpc_server_abyss_set_handler3() failed with: %s", env.env_c.fault_string); xmlrpc_server_abyss_set_default_handler(serverP); } static void createServer(serverAbyss::constrOpt_impl const& opt, void * const serverHandle, size_t const maxStackSize, TServer * const serverP, TChanSwitch ** const chanSwitchPP) { validateListenOptions(opt); createServerBare(opt.present.logFileName, opt.value.logFileName, opt.present.socketFd, opt.value.socketFd, opt.present.portNumber, opt.value.portNumber, opt.present.sockAddrP, SockAddr(opt.value.sockAddrP, opt.value.sockAddrLen), serverP, chanSwitchPP); try { setAdditionalServerParms(serverP, opt); setHttpReqHandlers(serverP, serverHandle, maxStackSize, opt.value.uriPath, opt.value.chunkResponse, opt.present.allowOrigin, opt.value.allowOrigin, opt.present.accessCtlMaxAge, opt.value.accessCtlMaxAge); if (opt.present.portNumber || opt.present.socketFd || opt.present.sockAddrP) ServerInit(serverP); } catch (...) { ServerFree(serverP); throw; } } serverAbyss_impl::serverAbyss_impl( serverAbyss::constrOpt_impl const& opt, serverAbyss * const serverAbyssP) : serverAbyssP(serverAbyssP) { if (!opt.present.registryP && !opt.present.registryPtr) throwf("You must specify the 'registryP' or 'registryPtr' option"); else if (opt.present.registryP && opt.present.registryPtr) throwf("You may not specify both the 'registryP' and " "the 'registryPtr' options"); else { if (opt.present.registryP) this->registryP = opt.value.registryP; else { this->regPtr = opt.value.registryPtr; this->registryP = this->regPtr.get(); } } this->serverOwnsSignals = opt.value.serverOwnsSignals; if (opt.value.serverOwnsSignals && opt.value.expectSigchld) throwf("You can't specify both expectSigchld " "and serverOwnsSignals options"); DateInit(); createServer(opt, this, this->registryP->maxStackSize(), &this->cServer, &this->chanSwitchP); } serverAbyss_impl::~serverAbyss_impl() { ServerFree(&this->cServer); if (this->chanSwitchP) ChanSwitchDestroy(this->chanSwitchP); } static void setupSignalsAndRunAbyss(TServer * const abyssServerP) { /* We do some pretty ugly stuff for an object method: we set signal handlers, which are process-global. One example of where this can be hairy is: Caller has a child process unrelated to the Abyss server. That child dies. We get his death of a child signal and Caller never knows. We really expect to be the only thing in the process, at least for the time we're running. If you want the Abyss Server to behave more like an object and own the signals yourself, use runOnce() in a loop instead of run(). */ signalHandlers oldHandlers; setupSignalHandlers(&oldHandlers); ServerUseSigchld(abyssServerP); ServerRun(abyssServerP); restoreSignalHandlers(oldHandlers); } void serverAbyss_impl::run() { if (this->serverOwnsSignals) setupSignalsAndRunAbyss(&this->cServer); else { if (this->expectSigchld) ServerUseSigchld(&this->cServer); ServerRun(&this->cServer); } } void serverAbyss_impl::processCall(string const& call, TSession * const abyssSessionP, string * const responseP) { callInfo_serverAbyss const callInfo(this->serverAbyssP, abyssSessionP); this->registryP->processCall(call, &callInfo, responseP); } serverAbyss::shutdown::shutdown(serverAbyss * const serverAbyssP) : serverAbyssP(serverAbyssP) {} serverAbyss::shutdown::~shutdown() {} void serverAbyss::shutdown::doit(string const&, void * const) const { this->serverAbyssP->terminate(); } void serverAbyss::initialize(constrOpt const& opt) { this->implP = new serverAbyss_impl(*opt.implP, this); } serverAbyss::serverAbyss(constrOpt const& opt) { initialize(opt); } serverAbyss::serverAbyss( xmlrpc_c::registry const& registry, unsigned int const portNumber, string const& logFileName, unsigned int const keepaliveTimeout, unsigned int const keepaliveMaxConn, unsigned int const timeout, bool const dontAdvertise, bool const socketBound, XMLRPC_SOCKET const socketFd) { /*---------------------------------------------------------------------------- This is a backward compatibility interface. This used to be the only constructor. -----------------------------------------------------------------------------*/ serverAbyss::constrOpt opt; opt.registryP(®istry); if (logFileName.length() > 0) opt.logFileName(logFileName); if (keepaliveTimeout > 0) opt.keepaliveTimeout(keepaliveTimeout); if (keepaliveMaxConn > 0) opt.keepaliveMaxConn(keepaliveMaxConn); if (timeout > 0) opt.timeout(timeout); opt.dontAdvertise(dontAdvertise); if (socketBound) opt.socketFd(socketFd); else opt.portNumber(portNumber); initialize(opt); } serverAbyss::~serverAbyss() { delete(this->implP); } void serverAbyss::run() { this->implP->run(); } void serverAbyss::runOnce() { ServerRunOnce(&this->implP->cServer); } void serverAbyss::runConn(int const socketFd) { ServerRunConn(&this->implP->cServer, socketFd); } #ifndef WIN32 void serverAbyss::sigchld(pid_t const pid) { // There's a hole in the design here, because the Abyss server uses // a process-global list of children (so there can't be more than one // Abyss object in the process), so while this is an object method, // it doesn't really refer to the object at all. // We might conceivably fix Abyss some day, then this method would do // what you expect -- affect only its own object. But forking Abyss is // obsolete anyway, so we just don't worry about it. ServerHandleSigchld(pid); } #endif void serverAbyss::terminate() { ServerTerminate(&this->implP->cServer); } callInfo_abyss::callInfo_abyss(TSession * const abyssSessionP) : abyssSessionP(abyssSessionP) {} void processXmlrpcCall2(xmlrpc_env * const envP, void * const arg, const char * const callXml, size_t const callXmlLen, TSession * const abyssSessionP, xmlrpc_mem_block ** const responseXmlPP) { /*---------------------------------------------------------------------------- This is an XML-RPC XML call processor, as called by the HTTP request handler of the libxmlrpc_server_abyss C library. 'callXml'/'callXmlLen' is the XML text of a supposed XML-RPC call. We execute the RPC and return the XML text of the XML-RPC response as *responseXmlPP. 'arg' carries the information that tells us how to do that; e.g. what XML-RPC methods are defined. -----------------------------------------------------------------------------*/ const registry * const registryP(static_cast(arg)); try { string const call(callXml, callXmlLen); callInfo_abyss const callInfo(abyssSessionP); string response; registryP->processCall(call, &callInfo, &response); xmlrpc_mem_block * responseMbP; responseMbP = XMLRPC_MEMBLOCK_NEW(char, envP, response.length()); if (!envP->fault_occurred) { XMLRPC_MEMBLOCK_APPEND(char, envP, responseMbP, response.c_str(), response.length()); *responseXmlPP = responseMbP; } } catch (exception const& e) { xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, e.what()); } } static void setHandlers(TServer * const serverP, string const& uriPath, registry const& registry) { xmlrpc_server_abyss_set_handler2( serverP, uriPath.c_str(), processXmlrpcCall2, const_cast(®istry), registry.maxStackSize(), false); xmlrpc_server_abyss_set_default_handler(serverP); } void server_abyss_set_handlers(TServer * const serverP, registry const& registry, string const& uriPath) { setHandlers(serverP, uriPath, registry); } void server_abyss_set_handlers(TServer * const serverP, const registry * const registryP, string const& uriPath) { setHandlers(serverP, uriPath, *registryP); } void server_abyss_set_handlers(TServer * const serverP, registryPtr const registryPtr, string const& uriPath) { setHandlers(serverP, uriPath, *registryPtr.get()); } } // namespace xmlrpc-c-1.33.14/src/cpp/server_cgi.cpp000066400000000000000000000216151236133176700176330ustar00rootroot00000000000000/*============================================================================= server_cgi =============================================================================== This is the definition of the xmlrpc_c::server_cgi class. An object of this class is the guts of a CGI-based XML-RPC server. It runs inside a CGI script and gets the XML-RPC call from and delivers the XML-RPC response to the CGI environment. By Bryan Henderson 08.09.17. Contributed to the public domain by its author. =============================================================================*/ #include "xmlrpc_config.h" #if MSVCRT #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #include #include #endif #include // for getenv #include #include #include "xmlrpc-c/girerr.hpp" using girerr::throwf; #include "xmlrpc-c/server_cgi.hpp" using namespace std; namespace { class httpInfo { public: string requestMethod; bool contentTypePresent; string contentType; unsigned int contentLength; bool contentLengthPresent; bool authCookiePresent; string authCookie; httpInfo() { const char * const requestMethodC = getenv("REQUEST_METHOD"); const char * const contentTypeC = getenv("CONTENT_TYPE"); const char * const contentLengthC = getenv("CONTENT_LENGTH"); const char * const authCookieC = getenv("HTTP_COOKIE_AUTH"); if (requestMethodC) this->requestMethod = string(requestMethodC); else throwf("Invalid CGI environment; environment variable " "REQUEST_METHOD is not set"); if (contentTypeC) { this->contentTypePresent = true; this->contentType = string(contentTypeC); } else this->contentTypePresent = false; if (contentLengthC) { this->contentLengthPresent = true; int const lengthAtoi(atoi(string(contentLengthC).c_str())); if (lengthAtoi < 0) throwf("Content-length HTTP header value is negative"); else if (lengthAtoi == 0) throwf("Content-length HTTP header value is zero"); else this->contentLength = lengthAtoi; } else this->contentLengthPresent = false; if (authCookieC) { this->authCookie = string(authCookieC); this->authCookiePresent = true; } else this->authCookiePresent = false; } }; class httpError { public: int const code; string const msg; httpError(int const code, string const& msg) : code(code), msg(msg) {} }; } // namespace namespace xmlrpc_c { struct serverCgi_impl { // 'registryP' is what we actually use; 'registryHolder' just holds a // reference to 'registryP' so the registry doesn't disappear while // this server exists. But note that if the creator doesn't supply // a registryPtr, 'registryHolder' is just a placeholder variable and // the creator is responsible for making sure the registry doesn't // go anywhere while the server exists. registryPtr registryHolder; const registry * registryP; serverCgi_impl(serverCgi::constrOpt const& opt); void establishRegistry(serverCgi::constrOpt const& opt); void tryToProcessCall(); }; void serverCgi_impl::establishRegistry(serverCgi::constrOpt const& opt) { if (!opt.present.registryP && !opt.present.registryPtr) throwf("You must specify the 'registryP' or 'registryPtr' option"); else if (opt.present.registryP && opt.present.registryPtr) throwf("You may not specify both the 'registryP' and " "the 'registryPtr' options"); else { if (opt.present.registryP) this->registryP = opt.value.registryP; else { this->registryHolder = opt.value.registryPtr; this->registryP = opt.value.registryPtr.get(); } } } serverCgi_impl::serverCgi_impl(serverCgi::constrOpt const& opt) { this->establishRegistry(opt); } serverCgi::constrOpt::constrOpt() { present.registryP = false; present.registryPtr = false; } #define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ serverCgi::constrOpt & \ serverCgi::constrOpt::OPTION_NAME(TYPE const& arg) { \ this->value.OPTION_NAME = arg; \ this->present.OPTION_NAME = true; \ return *this; \ } DEFINE_OPTION_SETTER(registryP, const registry *); DEFINE_OPTION_SETTER(registryPtr, xmlrpc_c::registryPtr); #undef DEFINE_OPTION_SETTER serverCgi::serverCgi(constrOpt const& opt) { this->implP = new serverCgi_impl(opt); } serverCgi::~serverCgi() { delete(this->implP); } #if MSVCRT #define FILEVAR fileP #else #define FILEVAR #endif static void setModeBinary(FILE * const FILEVAR) { #if MSVCRT /* Fix from Jeff Stewart: NT opens stdin and stdout in text mode by default, badly confusing our length calculations. So we need to set the file handle to binary. */ _setmode(_fileno(FILEVAR), _O_BINARY); #endif } static string getHttpBody(FILE * const fileP, size_t const length) { setModeBinary(fileP); char * const buffer(new char[length]); auto_ptr p(buffer); // To make it go away when we leave size_t count; count = fread(buffer, sizeof(buffer[0]), length, fileP); if (count < length) throwf("Expected %lu bytes, received %lu", (unsigned long) length, (unsigned long) count); return string(buffer, length); } static void writeNormalHttpResp(FILE * const fileP, bool const sendCookie, string const& authCookie, string const& httpBody) { setModeBinary(fileP); // HTTP headers fprintf(fileP, "Status: 200 OK\n"); if (sendCookie) fprintf(fileP, "Set-Cookie: auth=%s\n", authCookie.c_str()); fprintf(fileP, "Content-type: text/xml; charset=\"utf-8\"\n"); fprintf(fileP, "Content-length: %u\n", (unsigned)httpBody.size()); fprintf(fileP, "\n"); // HTTP body fwrite(httpBody.c_str(), sizeof(char), httpBody.size(), fileP); } void processCall2(const registry * const registryP, FILE * const callFileP, unsigned int const callSize, bool const sendCookie, string const& authCookie, FILE * const respFileP) { if (callSize > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) throw(xmlrpc_c::fault(string("XML-RPC call is too large"), fault::CODE_LIMIT_EXCEEDED)); else { string const callXml(getHttpBody(callFileP, callSize)); string responseXml; try { registryP->processCall(callXml, &responseXml); } catch (exception const& e) { throw(httpError(500, e.what())); } writeNormalHttpResp(respFileP, sendCookie, authCookie, responseXml); } } static void sendHttpErrorResp(FILE * const fileP, httpError const& e) { setModeBinary(fileP); // HTTP headers fprintf(fileP, "Status: %d %s\n", e.code, e.msg.c_str()); fprintf(fileP, "Content-type: text/html\n"); fprintf(fileP, "\n"); // HTTP body: HTML error message fprintf(fileP, "%d %s\n", e.code, e.msg.c_str()); fprintf(fileP, "

%d %s

\n", e.code, e.msg.c_str()); fprintf(fileP, "

The Xmlrpc-c CGI server was unable to process " "your request. It could not process it even enough to generate " "an XML-RPC fault response.

\n"); } void serverCgi_impl::tryToProcessCall() { httpInfo httpInfo; if (httpInfo.requestMethod != string("POST")) throw(httpError(405, "Method must be POST")); if (!httpInfo.contentTypePresent) throw(httpError(400, "Must have content-type header")); if (httpInfo.contentType != string("text/xml")) throw(httpError(400, string("ContentType must be 'text/xml', not '") + httpInfo.contentType + string("'"))); if (!httpInfo.contentLengthPresent) throw(httpError(411, "Content-length required")); processCall2(this->registryP, stdin, httpInfo.contentLength, httpInfo.authCookiePresent, httpInfo.authCookie, stdout); } void serverCgi::processCall() { /*---------------------------------------------------------------------------- Get the XML-RPC call from Standard Input and environment variables, parse it, find the right method, call it, prepare an XML-RPC response with the result, and write it to Standard Output. -----------------------------------------------------------------------------*/ try { this->implP->tryToProcessCall(); } catch (httpError const e) { sendHttpErrorResp(stdout, e); } } } // namespace xmlrpc-c-1.33.14/src/cpp/server_pstream.cpp000066400000000000000000000154661236133176700205530ustar00rootroot00000000000000/*============================================================================= server_pstream =============================================================================== RPC server based on a very simple byte stream and XML-RPC XML (But this is not an XML-RPC server because it doesn't use HTTP). The protocol we use is the "packet socket" protocol, which is an Xmlrpc-c invention. It is an almost trivial representation of a sequence of packets on a byte stream. By Bryan Henderson 09.03.22 Contributed to the public domain by its author. =============================================================================*/ #include "xmlrpc_config.h" #if MSVCRT #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #include typedef int socklen_t; #else #include #endif #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::throwf; #include "xmlrpc-c/server_pstream.hpp" using namespace std; namespace xmlrpc_c { struct serverPstream::constrOpt_impl { constrOpt_impl(); struct value { xmlrpc_c::registryPtr registryPtr; const xmlrpc_c::registry * registryP; XMLRPC_SOCKET socketFd; } value; struct { bool registryPtr; bool registryP; bool socketFd; } present; }; serverPstream::constrOpt_impl::constrOpt_impl() { this->present.socketFd = false; this->present.registryP = false; this->present.registryPtr = false; } serverPstream::constrOpt::constrOpt() { this->implP = new serverPstream::constrOpt_impl(); } serverPstream::constrOpt::~constrOpt() { delete(this->implP); } #define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ serverPstream::constrOpt & \ serverPstream::constrOpt::OPTION_NAME(TYPE const& arg) { \ this->implP->value.OPTION_NAME = arg; \ this->implP->present.OPTION_NAME = true; \ return *this; \ } DEFINE_OPTION_SETTER(socketFd, XMLRPC_SOCKET); DEFINE_OPTION_SETTER(registryP, const registry *); DEFINE_OPTION_SETTER(registryPtr, xmlrpc_c::registryPtr); #undef DEFINE_OPTION_SETTER struct serverPstream_impl { serverPstream_impl(serverPstream::constrOpt_impl const& opt); ~serverPstream_impl(); void establishRegistry(serverPstream::constrOpt_impl const& opt); // 'registryP' is what we actually use; 'registryHolder' just holds a // reference to 'registryP' so the registry doesn't disappear while // this server exists. But note that if the creator doesn't supply // a registryPtr, 'registryHolder' is just a placeholder variable and // the creator is responsible for making sure the registry doesn't // go anywhere while the server exists. registryPtr registryHolder; const registry * registryP; XMLRPC_SOCKET listenSocketFd; // The socket on which we accept connections from clients. This comes // to us from the creator, already bound and in listen mode. That // way, this object doesn't have to know anything about socket // addresses or listen parameters such as the maximum connection // backlog size. bool termRequested; // User has requested that the run method return ASAP; i.e. that // the server cease servicing RPCs. }; serverPstream_impl::serverPstream_impl( serverPstream::constrOpt_impl const& opt) { this->establishRegistry(opt); if (!opt.present.socketFd) throwf("You must provide a 'socketFd' constructor option."); this->listenSocketFd = opt.value.socketFd; this->termRequested = false; } serverPstream_impl::~serverPstream_impl() { } void serverPstream_impl::establishRegistry( serverPstream::constrOpt_impl const& opt) { if (!opt.present.registryP && !opt.present.registryPtr) throwf("You must specify the 'registryP' or 'registryPtr' option"); else if (opt.present.registryP && opt.present.registryPtr) throwf("You may not specify both the 'registryP' and " "the 'registryPtr' options"); else { if (opt.present.registryP) this->registryP = opt.value.registryP; else { this->registryHolder = opt.value.registryPtr; this->registryP = opt.value.registryPtr.get(); } } } /*----------------------------------------------------------------------------- serverPstream::shutdown is a derived class of registry::shutdown. You give it to the registry object to allow XML-RPC method 'system.shutdown' to -----------------------------------------------------------------------------*/ serverPstream::shutdown::shutdown(serverPstream * const serverPstreamP) : serverPstreamP(serverPstreamP) {} serverPstream::shutdown::~shutdown() {} void serverPstream::shutdown::doit(string const&, void * const) const { this->serverPstreamP->terminate(); } /*---------------------------------------------------------------------------*/ serverPstream::serverPstream(constrOpt const& opt) { this->implP = new serverPstream_impl(*opt.implP); } serverPstream::~serverPstream() { delete(this->implP); } void serverPstream::runSerial(volatile const int * const interruptP) { while (!this->implP->termRequested && !*interruptP) { struct sockaddr peerAddr; socklen_t size = sizeof(peerAddr); int rc; rc = accept(this->implP->listenSocketFd, &peerAddr, &size); if (!*interruptP) { if (rc < 0) if (errno == EINTR) { // system call was interrupted, but user doesn't want // to interrupt the server, so just keep trying } else throwf("Failed to accept a connection " "on the listening socket. accept() failed " "with errno %d (%s)", errno, strerror(errno)); else { int const acceptedFd = rc; serverPstreamConn connectionServer( xmlrpc_c::serverPstreamConn::constrOpt() .socketFd(acceptedFd) .registryP(this->implP->registryP)); callInfo_serverPstream callInfo(this, peerAddr, size); connectionServer.run(&callInfo, interruptP); } } } } void serverPstream::runSerial() { int const interrupt(0); // Never interrupt this->runSerial(&interrupt); } void serverPstream::terminate() { this->implP->termRequested = true; } callInfo_serverPstream::callInfo_serverPstream( serverPstream * const serverP, struct sockaddr const clientAddr, socklen_t const clientAddrSize) : serverP (serverP), clientAddr (clientAddr), clientAddrSize (clientAddrSize) {} } // namespace xmlrpc-c-1.33.14/src/cpp/server_pstream_conn.cpp000066400000000000000000000230571236133176700215630ustar00rootroot00000000000000/*============================================================================= server_pstream =============================================================================== RPC server based on a very simple byte stream and XML-RPC XML (But this is not an XML-RPC server because it doesn't use HTTP). The protocol we use is the "packet socket" protocol, which is an Xmlrpc-c invention. It is an almost trivial representation of a sequence of packets on a byte stream. You can create a pstream server from any file descriptor from which you can read and write a bidirectional character stream. Typically, it's a TCP socket. Such a server talks to one client its entire life. Some day, we'll also have a version that you create from a "listening" socket, which can talk to multiple clients serially (a client connects, does some RPCs, and disconnects). By Bryan Henderson 07.05.12. Contributed to the public domain by its author. =============================================================================*/ #include #include "xmlrpc-c/girerr.hpp" using girerr::throwf; #include "xmlrpc-c/packetsocket.hpp" #include "xmlrpc-c/server_pstream.hpp" using namespace std; namespace xmlrpc_c { struct serverPstreamConn::constrOpt_impl { constrOpt_impl(); struct value { xmlrpc_c::registryPtr registryPtr; const xmlrpc_c::registry * registryP; XMLRPC_SOCKET socketFd; } value; struct { bool registryPtr; bool registryP; bool socketFd; } present; }; serverPstreamConn::constrOpt_impl::constrOpt_impl() { this->present.socketFd = false; this->present.registryP = false; this->present.registryPtr = false; } serverPstreamConn::constrOpt::constrOpt() { this->implP = new constrOpt_impl(); } serverPstreamConn::constrOpt::~constrOpt() { delete(this->implP); } #define DEFINE_OPTION_SETTER(OPTION_NAME, TYPE) \ serverPstreamConn::constrOpt & \ serverPstreamConn::constrOpt::OPTION_NAME(TYPE const& arg) { \ this->implP->value.OPTION_NAME = arg; \ this->implP->present.OPTION_NAME = true; \ return *this; \ } DEFINE_OPTION_SETTER(socketFd, XMLRPC_SOCKET); DEFINE_OPTION_SETTER(registryP, const registry *); DEFINE_OPTION_SETTER(registryPtr, xmlrpc_c::registryPtr); #undef DEFINE_OPTION_SETTER struct serverPstreamConn_impl { serverPstreamConn_impl(serverPstreamConn::constrOpt_impl const& opt); ~serverPstreamConn_impl(); void establishRegistry(serverPstreamConn::constrOpt_impl const& opt); void establishPacketSocket(serverPstreamConn::constrOpt_impl const& opt); void processRecdPacket(packetPtr const callPacketP, callInfo * const callInfoP); // 'registryP' is what we actually use; 'registryHolder' just holds a // reference to 'registryP' so the registry doesn't disappear while // this server exists. But note that if the creator doesn't supply // a registryPtr, 'registryHolder' is just a placeholder variable and // the creator is responsible for making sure the registry doesn't // go anywhere while the server exists. registryPtr registryHolder; const registry * registryP; packetSocket * packetSocketP; // The packet socket over which we received RPCs. // This is permanently connected to our fixed client. }; serverPstreamConn_impl::serverPstreamConn_impl( serverPstreamConn::constrOpt_impl const& opt) { this->establishRegistry(opt); this->establishPacketSocket(opt); } serverPstreamConn_impl::~serverPstreamConn_impl() { delete(this->packetSocketP); } void serverPstreamConn_impl::establishRegistry( serverPstreamConn::constrOpt_impl const& opt) { if (!opt.present.registryP && !opt.present.registryPtr) throwf("You must specify the 'registryP' or 'registryPtr' option"); else if (opt.present.registryP && opt.present.registryPtr) throwf("You may not specify both the 'registryP' and " "the 'registryPtr' options"); else { if (opt.present.registryP) this->registryP = opt.value.registryP; else { this->registryHolder = opt.value.registryPtr; this->registryP = opt.value.registryPtr.get(); } } } void serverPstreamConn_impl::establishPacketSocket( serverPstreamConn::constrOpt_impl const& opt) { if (!opt.present.socketFd) throwf("You must provide a 'socketFd' constructor option."); auto_ptr packetSocketAP; try { auto_ptr p(new packetSocket(opt.value.socketFd)); packetSocketAP = p; } catch (exception const& e) { throwf("Unable to create packet socket out of file descriptor %d. %s", opt.value.socketFd, e.what()); } this->packetSocketP = packetSocketAP.get(); packetSocketAP.release(); } serverPstreamConn::serverPstreamConn(constrOpt const& opt) { this->implP = new serverPstreamConn_impl(*opt.implP); } serverPstreamConn::~serverPstreamConn() { delete(this->implP); } static void processCall(const registry * const registryP, packetPtr const& callPacketP, callInfo * const callInfoP, packetPtr * const responsePacketPP) { string const callXml(reinterpret_cast(callPacketP->getBytes()), callPacketP->getLength()); string responseXml; registryP->processCall(callXml, callInfoP, &responseXml); *responsePacketPP = packetPtr(new packet(responseXml.c_str(), responseXml.length())); } void serverPstreamConn_impl::processRecdPacket(packetPtr const callPacketP, callInfo * const callInfoP) { packetPtr responsePacketP; try { processCall(this->registryP, callPacketP, callInfoP, &responsePacketP); } catch (exception const& e) { throwf("Error executing received packet as an XML-RPC RPC. %s", e.what()); } try { this->packetSocketP->writeWait(responsePacketP); } catch (exception const& e) { throwf("Failed to write the response to the packet socket. %s", e.what()); } } void serverPstreamConn::runOnce(callInfo * const callInfoP, volatile const int * const interruptP, bool * const eofP) { /*---------------------------------------------------------------------------- Get and execute one RPC from the client. Unless *interruptP gets set nonzero first. -----------------------------------------------------------------------------*/ bool gotPacket; packetPtr callPacketP; try { this->implP->packetSocketP->readWait(interruptP, eofP, &gotPacket, &callPacketP); } catch (exception const& e) { throwf("Error reading a packet from the packet socket. %s", e.what()); } if (gotPacket) this->implP->processRecdPacket(callPacketP, callInfoP); } void serverPstreamConn::runOnce(volatile const int * const interruptP, bool * const eofP) { this->runOnce(NULL, interruptP, eofP); } void serverPstreamConn::runOnce(bool * const eofP) { /*---------------------------------------------------------------------------- Get and execute one RPC from the client. -----------------------------------------------------------------------------*/ int const interrupt(0); // Never interrupt this->runOnce(&interrupt, eofP); } void serverPstreamConn::runOnceNoWait(callInfo * const callInfoP, bool * const eofP, bool * const didOneP) { /*---------------------------------------------------------------------------- Get and execute one RPC from the client, unless none has been received yet. Return as *didOneP whether or not one has been received. Unless didOneP is NULL. -----------------------------------------------------------------------------*/ bool gotPacket; packetPtr callPacketP; try { this->implP->packetSocketP->read(eofP, &gotPacket, &callPacketP); } catch (exception const& e) { throwf("Error reading a packet from the packet socket. %s", e.what()); } if (gotPacket) this->implP->processRecdPacket(callPacketP, callInfoP); if (didOneP) *didOneP = gotPacket; } void serverPstreamConn::runOnceNoWait(bool * const eofP, bool * const didOneP) { this->runOnceNoWait(NULL, eofP, didOneP); } void serverPstreamConn::runOnceNoWait(bool * const eofP) { /*---------------------------------------------------------------------------- Get and execute one RPC from the client, unless none has been received yet. -----------------------------------------------------------------------------*/ this->runOnceNoWait(eofP, NULL); } void serverPstreamConn::run(callInfo * const callInfoP, volatile const int * const interruptP) { for (bool clientHasDisconnected = false; !clientHasDisconnected && !*interruptP;) this->runOnce(callInfoP, interruptP, &clientHasDisconnected); } void serverPstreamConn::run(volatile const int * const interruptP) { this->run(NULL, interruptP); } void serverPstreamConn::run() { int const interrupt(0); // Never interrupt this->run(&interrupt); } } // namespace xmlrpc-c-1.33.14/src/cpp/value.cpp000066400000000000000000000547661236133176700166340ustar00rootroot00000000000000/***************************************************************************** value.cpp ****************************************************************************** This module provides services for dealing with XML-RPC values. Each type of XML-RPC value is a C++ class. An object represents a particular XML-RPC value. Everything is based on the C services in libxmlrpc. We could make things more efficient by using the internal interfaces via xmlrpc_int.h. We could make them even more efficient by dumping libxmlrpc altogether for some or all of these services. An xmlrpc_c::value object is really just a handle for a C xmlrpc_value object. You're not supposed to make a pointer to an xmlrpc_c::value object, but rather copy the object around. Because the C xmlrpc_value object does reference counting, it disappears automatically when the last handle does. To go pure C++, we'd have to have a C++ object for the value itself and a separate handle object, like Boost's shared_ptr<>. The C++ is designed so that the user never sees the C interface at all. Unfortunately, the user can see it if he wants because some class members had to be declared public so that other components of the library could see them, but the user is not supposed to access those members. *****************************************************************************/ #include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "env_wrap.hpp" #include "xmlrpc-c/base.hpp" using namespace std; using namespace xmlrpc_c; namespace { void throwIfError(env_wrap const& env) { if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } class cDatetimeValueWrapper { public: xmlrpc_value * valueP; cDatetimeValueWrapper(xmlrpc_datetime const cppvalue) { env_wrap env; this->valueP = xmlrpc_datetime_new(&env.env_c, cppvalue); throwIfError(env); } cDatetimeValueWrapper(time_t const cppvalue) { env_wrap env; this->valueP = xmlrpc_datetime_new_sec(&env.env_c, cppvalue); throwIfError(env); } #if XMLRPC_HAVE_TIMEVAL cDatetimeValueWrapper(struct timeval const cppvalue) { env_wrap env; this->valueP = xmlrpc_datetime_new_timeval(&env.env_c, cppvalue); throwIfError(env); } #endif #if XMLRPC_HAVE_TIMESPEC cDatetimeValueWrapper(struct timespec const cppvalue) { env_wrap env; this->valueP = xmlrpc_datetime_new_timespec(&env.env_c, cppvalue); throwIfError(env); } #endif ~cDatetimeValueWrapper() { xmlrpc_DECREF(this->valueP); } }; class cStringWrapper { public: const char * str; size_t length; cStringWrapper(xmlrpc_value * valueP) { env_wrap env; xmlrpc_read_string_lp(&env.env_c, valueP, &length, &str); throwIfError(env); } ~cStringWrapper() { free((char*)str); } }; } // namespace namespace xmlrpc_c { value::value() { // default constructor this->cValueP = NULL; } value::value(xmlrpc_value * const valueP) { this->instantiate(valueP); } value::value(xmlrpc_c::value const& value) { // copy constructor this->cValueP = value.cValue(); } xmlrpc_c::value& value::operator=(xmlrpc_c::value const& value) { if (this->cValueP != NULL) throw(error("Assigning to already instantiated xmlrpc_c::value")); this->cValueP = value.cValue(); return *this; // The result of the (a = b) expression } value::~value() { if (this->cValueP) { xmlrpc_DECREF(this->cValueP); } } bool value::isInstantiated() const { /*---------------------------------------------------------------------------- Return whether the object is actually a value, as opposed to a placeholder variable waiting to be assigned a value. -----------------------------------------------------------------------------*/ return (this->cValueP != NULL); } void value::validateInstantiated() const { // private /*---------------------------------------------------------------------------- Throw an exception if the object is just a placeholder, rather than an actual XML-RPC value. -----------------------------------------------------------------------------*/ if (!this->cValueP) throw(error("Reference to xmlrpc_c::value that has not been " "instantiated. (xmlrpc_c::value::isInstantiated may be " "useful in diagnosing)")); } void value::instantiate(xmlrpc_value * const valueP) { xmlrpc_INCREF(valueP); this->cValueP = valueP; } xmlrpc_value * value::cValue() const { if (this->cValueP) { xmlrpc_INCREF(this->cValueP); // For Caller } return this->cValueP; } void value::appendToCArray(xmlrpc_value * const arrayP) const { /*---------------------------------------------------------------------------- Append this value to the C array 'arrayP'. ----------------------------------------------------------------------------*/ this->validateInstantiated(); env_wrap env; xmlrpc_array_append_item(&env.env_c, arrayP, this->cValueP); throwIfError(env); } void value::addToCStruct(xmlrpc_value * const structP, string const key) const { /*---------------------------------------------------------------------------- Add this value to the C array 'arrayP' with key 'key'. ----------------------------------------------------------------------------*/ this->validateInstantiated(); env_wrap env; xmlrpc_struct_set_value_n(&env.env_c, structP, key.c_str(), key.length(), this->cValueP); throwIfError(env); } value::type_t value::type() const { this->validateInstantiated(); /* You'd think we could just cast from xmlrpc_type to value::type_t, but Gcc warns if we do that. So we have to do this even messier union nonsense. */ union { xmlrpc_type x; value::type_t y; } u; u.x = xmlrpc_value_type(this->cValueP); return u.y; } ostream& operator<<(ostream& out, value::type_t const& type) { string typeName; return out << string(xmlrpc_type_name((xmlrpc_type)type)); } value_int::value_int(int const cppvalue) { class cWrapper { public: xmlrpc_value * valueP; cWrapper(int const cppvalue) { env_wrap env; this->valueP = xmlrpc_int_new(&env.env_c, cppvalue); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; cWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } value_int::value_int(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_INT) throw(error("Not integer type. See type() method")); else { this->instantiate(baseValue.cValueP); } } value_int::operator int() const { this->validateInstantiated(); int retval; env_wrap env; xmlrpc_read_int(&env.env_c, this->cValueP, &retval); throwIfError(env); return retval; } int value_int::cvalue() const { return static_cast(*this); } value_double::value_double(double const cppvalue) { class cWrapper { public: xmlrpc_value * valueP; cWrapper(double const cppvalue) { env_wrap env; this->valueP = xmlrpc_double_new(&env.env_c, cppvalue); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; this->instantiate(cWrapper(cppvalue).valueP); } value_double::value_double(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_DOUBLE) throw(error("Not double type. See type() method")); else { this->instantiate(baseValue.cValueP); } } value_double::operator double() const { this->validateInstantiated(); double retval; env_wrap env; xmlrpc_read_double(&env.env_c, this->cValueP, &retval); throwIfError(env); return retval; } double value_double::cvalue() const { return static_cast(*this); } value_boolean::value_boolean(bool const cppvalue) { class cWrapper { public: xmlrpc_value * valueP; cWrapper(xmlrpc_bool const cppvalue) { env_wrap env; this->valueP = xmlrpc_bool_new(&env.env_c, cppvalue); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; cWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } value_boolean::value_boolean(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_BOOLEAN) throw(error("Not boolean type. See type() method")); else { this->instantiate(baseValue.cValueP); } } value_boolean::operator bool() const { this->validateInstantiated(); xmlrpc_bool retval; env_wrap env; xmlrpc_read_bool(&env.env_c, this->cValueP, &retval); throwIfError(env); return (retval != false); } bool value_boolean::cvalue() const { return static_cast(*this); } value_datetime::value_datetime(string const cppvalue) { class cWrapper { public: xmlrpc_value * valueP; cWrapper(string const cppvalue) { env_wrap env; this->valueP = xmlrpc_datetime_new_str(&env.env_c, cppvalue.c_str()); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; cWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } value_datetime::value_datetime(xmlrpc_datetime const cppvalue) { cDatetimeValueWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } value_datetime::value_datetime(time_t const cppvalue) { cDatetimeValueWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } #if XMLRPC_HAVE_TIMEVAL value_datetime::value_datetime(struct timeval const& cppvalue) { cDatetimeValueWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } #endif #if XMLRPC_HAVE_TIMESPEC value_datetime::value_datetime(struct timespec const& cppvalue) { cDatetimeValueWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } #endif value_datetime::value_datetime(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_DATETIME) throw(error("Not datetime type. See type() method")); else { this->instantiate(baseValue.cValueP); } } value_datetime::operator xmlrpc_datetime() const { this->validateInstantiated(); xmlrpc_datetime retval; env_wrap env; xmlrpc_read_datetime(&env.env_c, this->cValueP, &retval); throwIfError(env); return retval; } value_datetime::operator time_t() const { this->validateInstantiated(); time_t retval; env_wrap env; xmlrpc_read_datetime_sec(&env.env_c, this->cValueP, &retval); throwIfError(env); return retval; } #if XMLRPC_HAVE_TIMEVAL value_datetime::operator timeval() const { this->validateInstantiated(); struct timeval retval; env_wrap env; xmlrpc_read_datetime_timeval(&env.env_c, this->cValueP, &retval); throwIfError(env); return retval; } #endif #if XMLRPC_HAVE_TIMESPEC value_datetime::operator timespec() const { this->validateInstantiated(); struct timespec retval; env_wrap env; xmlrpc_read_datetime_timespec(&env.env_c, this->cValueP, &retval); throwIfError(env); return retval; } #endif time_t value_datetime::cvalue() const { return static_cast(*this); } string value_datetime::iso8601Value() const { string retval; this->validateInstantiated(); const char * iso8601; env_wrap env; xmlrpc_read_datetime_8601(&env.env_c, this->cValueP, &iso8601); throwIfError(env); retval = iso8601; xmlrpc_strfree(iso8601); return retval; } class cNewStringWrapper { public: xmlrpc_value * valueP; cNewStringWrapper(string const cppvalue, value_string::nlCode const nlCode) { env_wrap env; switch (nlCode) { case value_string::nlCode_all: this->valueP = xmlrpc_string_new_lp(&env.env_c, cppvalue.length(), cppvalue.c_str()); break; case value_string::nlCode_lf: this->valueP = xmlrpc_string_new_lp_cr(&env.env_c, cppvalue.length(), cppvalue.c_str()); break; default: throw(error("Newline encoding argument to value_string " "constructor is not one of the defined " "enumerations of value_string::nlCode")); } throwIfError(env); } ~cNewStringWrapper() { xmlrpc_DECREF(this->valueP); } }; value_string::value_string(std::string const& cppvalue, value_string::nlCode const nlCode) { cNewStringWrapper wrapper(cppvalue, nlCode); this->instantiate(wrapper.valueP); } value_string::value_string(std::string const& cppvalue) { cNewStringWrapper wrapper(cppvalue, nlCode_all); this->instantiate(wrapper.valueP); } value_string::value_string(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_STRING) throw(error("Not string type. See type() method")); else { this->instantiate(baseValue.cValueP); } } std::string value_string::crlfValue() const { class cWrapper { public: const char * str; size_t length; cWrapper(xmlrpc_value * valueP) { env_wrap env; xmlrpc_read_string_lp_crlf(&env.env_c, valueP, &length, &str); throwIfError(env); } ~cWrapper() { free((char*)str); } }; this->validateInstantiated(); cWrapper wrapper(this->cValueP); return string(wrapper.str, wrapper.length); } value_string::operator string() const { this->validateInstantiated(); cStringWrapper adapter(this->cValueP); return string(adapter.str, adapter.length); } std::string value_string::cvalue() const { return static_cast(*this); } value_bytestring::value_bytestring( vector const& cppvalue) { class cWrapper { public: xmlrpc_value * valueP; cWrapper(vector const& cppvalue) { env_wrap env; this->valueP = xmlrpc_base64_new(&env.env_c, cppvalue.size(), &cppvalue[0]); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; cWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } value_bytestring::value_bytestring(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_BYTESTRING) throw(error("Not byte string type. See type() method")); else { this->instantiate(baseValue.cValueP); } } vector value_bytestring::vectorUcharValue() const { class cWrapper { public: const unsigned char * contents; size_t length; cWrapper(xmlrpc_value * const valueP) { env_wrap env; xmlrpc_read_base64(&env.env_c, valueP, &length, &contents); throwIfError(env); } ~cWrapper() { free((void*)contents); } }; this->validateInstantiated(); cWrapper wrapper(this->cValueP); return vector(&wrapper.contents[0], &wrapper.contents[wrapper.length]); } vector value_bytestring::cvalue() const { return this->vectorUcharValue(); } size_t value_bytestring::length() const { this->validateInstantiated(); env_wrap env; size_t length; xmlrpc_read_base64_size(&env.env_c, this->cValueP, &length); throwIfError(env); return length; } value_array::value_array(vector const& cppvalue) { class cWrapper { public: xmlrpc_value * valueP; cWrapper() { env_wrap env; this->valueP = xmlrpc_array_new(&env.env_c); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; cWrapper wrapper; vector::const_iterator i; for (i = cppvalue.begin(); i != cppvalue.end(); ++i) i->appendToCArray(wrapper.valueP); this->instantiate(wrapper.valueP); } value_array::value_array(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_ARRAY) throw(error("Not array type. See type() method")); else { this->instantiate(baseValue.cValueP); } } vector value_array::vectorValueValue() const { this->validateInstantiated(); env_wrap env; unsigned int arraySize; arraySize = xmlrpc_array_size(&env.env_c, this->cValueP); throwIfError(env); vector retval(arraySize); for (unsigned int i = 0; i < arraySize; ++i) { class cWrapper { public: xmlrpc_value * valueP; cWrapper(xmlrpc_value * const arrayP, unsigned int const index) { env_wrap env; xmlrpc_array_read_item(&env.env_c, arrayP, index, &valueP); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(valueP); } }; cWrapper wrapper(this->cValueP, i); retval[i].instantiate(wrapper.valueP); } return retval; } vector value_array::cvalue() const { return this->vectorValueValue(); } size_t value_array::size() const { this->validateInstantiated(); env_wrap env; unsigned int arraySize; arraySize = xmlrpc_array_size(&env.env_c, this->cValueP); throwIfError(env); return arraySize; } value_struct::value_struct( map const &cppvalue) { class cWrapper { public: xmlrpc_value * valueP; cWrapper() { env_wrap env; this->valueP = xmlrpc_struct_new(&env.env_c); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; cWrapper wrapper; map::const_iterator i; for (i = cppvalue.begin(); i != cppvalue.end(); ++i) { xmlrpc_c::value mapvalue(i->second); string mapkey(i->first); mapvalue.addToCStruct(wrapper.valueP, mapkey); } this->instantiate(wrapper.valueP); } value_struct::value_struct(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_STRUCT) throw(error("Not struct type. See type() method")); else { this->instantiate(baseValue.cValueP); } } value_struct::operator map() const { this->validateInstantiated(); env_wrap env; unsigned int structSize; structSize = xmlrpc_struct_size(&env.env_c, this->cValueP); throwIfError(env); map retval; for (unsigned int i = 0; i < structSize; ++i) { class cMemberWrapper { public: xmlrpc_value * keyP; xmlrpc_value * valueP; cMemberWrapper(xmlrpc_value * const structP, unsigned int const index) { env_wrap env; xmlrpc_struct_read_member(&env.env_c, structP, index, &keyP, &valueP); throwIfError(env); } ~cMemberWrapper() { xmlrpc_DECREF(keyP); xmlrpc_DECREF(valueP); } }; cMemberWrapper memberWrapper(this->cValueP, i); cStringWrapper keyWrapper(memberWrapper.keyP); string const key(keyWrapper.str, keyWrapper.length); retval[key] = xmlrpc_c::value(memberWrapper.valueP); } return retval; } map value_struct::cvalue() const { return static_cast >(*this); } value_nil::value_nil() { class cWrapper { public: xmlrpc_value * valueP; cWrapper() { env_wrap env; this->valueP = xmlrpc_nil_new(&env.env_c); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; cWrapper wrapper; this->instantiate(wrapper.valueP); } value_nil::value_nil(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_NIL) throw(error("Not nil type. See type() method")); else { this->instantiate(baseValue.cValueP); } } void * value_nil::cvalue() const { return NULL; } value_i8::value_i8(xmlrpc_int64 const cppvalue) { class cWrapper { public: xmlrpc_value * valueP; cWrapper(xmlrpc_int64 const cppvalue) { env_wrap env; this->valueP = xmlrpc_i8_new(&env.env_c, cppvalue); throwIfError(env); } ~cWrapper() { xmlrpc_DECREF(this->valueP); } }; cWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } value_i8::value_i8(xmlrpc_c::value const baseValue) { if (baseValue.type() != xmlrpc_c::value::TYPE_I8) throw(error("Not 64 bit integer type. See type() method")); else { this->instantiate(baseValue.cValueP); } } value_i8::operator xmlrpc_int64() const { this->validateInstantiated(); xmlrpc_int64 retval; env_wrap env; xmlrpc_read_i8(&env.env_c, this->cValueP, &retval); throwIfError(env); return retval; } xmlrpc_int64 value_i8::cvalue() const { return static_cast(*this); } } // namespace xmlrpc-c-1.33.14/src/cpp/wininet.cpp000066400000000000000000000070021236133176700171520ustar00rootroot00000000000000/*============================================================================= wininet.cpp =============================================================================== This is the Wininet XML transport of the C++ XML-RPC client library for Xmlrpc-c. =============================================================================*/ #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/girmem.hpp" using girmem::autoObjectPtr; using girmem::autoObject; #include "env_wrap.hpp" #include "xmlrpc-c/base.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/transport.h" #include "xmlrpc-c/base_int.h" /* transport_config.h defines MUST_BUILD_WININET_CLIENT */ #include "transport_config.h" #include "xmlrpc-c/client_transport.hpp" using namespace std; using namespace xmlrpc_c; namespace { class globalConstant { public: globalConstant(); ~globalConstant(); }; globalConstant::globalConstant() { // Not thread safe xmlrpc_transport_setup setupFn; #if MUST_BUILD_WININET_CLIENT setupFn = xmlrpc_wininet_transport_ops.setup_global_const; #else setupFn = NULL; #endif if (setupFn) { env_wrap env; setupFn(&env.env_c); // Not thread safe if (env.env_c.fault_occurred) throwf("Failed to do global initialization " "of Wininet transport code. %s", env.env_c.fault_string); } } globalConstant::~globalConstant() { // Not thread safe xmlrpc_transport_teardown teardownFn; #if MUST_BUILD_WININET_CLIENT teardownFn = xmlrpc_wininet_transport_ops.teardown_global_const; #else teardownFn = NULL; #endif if (teardownFn) teardownFn(); // not thread safe } globalConstant globalConst; // This object is never accessed. Its whole purpose to to be born and // to die, which it does automatically as part of C++ program // program initialization and termination. } // namespace namespace xmlrpc_c { carriageParm_wininet0::carriageParm_wininet0( string const serverUrl ) { this->instantiate(serverUrl); } carriageParm_wininet0Ptr::carriageParm_wininet0Ptr() { // Base class constructor will construct pointer that points to nothing } carriageParm_wininet0Ptr::carriageParm_wininet0Ptr( carriageParm_wininet0 * const carriageParmP) { this->point(carriageParmP); } carriageParm_wininet0 * carriageParm_wininet0Ptr::operator->() const { autoObject * const p(this->objectP); return dynamic_cast(p); } #if MUST_BUILD_WININET_CLIENT clientXmlTransport_wininet::clientXmlTransport_wininet( bool const allowInvalidSslCerts ) { struct xmlrpc_wininet_xportparms transportParms; transportParms.allowInvalidSSLCerts = allowInvalidSslCerts; this->c_transportOpsP = &xmlrpc_wininet_transport_ops; env_wrap env; xmlrpc_wininet_transport_ops.create( &env.env_c, 0, "", "", &transportParms, XMLRPC_WXPSIZE(allowInvalidSSLCerts), &this->c_transportP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } #else // MUST_BUILD_WININET_CLIENT clientXmlTransport_wininet::clientXmlTransport_wininet(bool const) { throw(error("There is no Wininet client XML transport " "in this XML-RPC client library")); } #endif clientXmlTransport_wininet::~clientXmlTransport_wininet() { this->c_transportOpsP->destroy(this->c_transportP); } } // namespace xmlrpc-c-1.33.14/src/cpp/xml.cpp000066400000000000000000000207041236133176700163010ustar00rootroot00000000000000#include #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/base.hpp" #include "env_wrap.hpp" #include "xmlrpc-c/xml.hpp" using namespace std; using namespace xmlrpc_c; namespace { class cValueWrapper { /*---------------------------------------------------------------------------- Use an object of this class to set up to remove a reference to an xmlrpc_value object (a C object with manual reference management) at the end of a scope -- even if the scope ends with a throw. -----------------------------------------------------------------------------*/ public: xmlrpc_value * const valueP; cValueWrapper(xmlrpc_value * valueP) : valueP(valueP) {} ~cValueWrapper() { xmlrpc_DECREF(valueP); } }; class cStringWrapper { public: const char * const cString; cStringWrapper(const char * const cString) : cString(cString) {} ~cStringWrapper() { xmlrpc_strfree(cString); } }; class memblockWrapper { xmlrpc_mem_block * const memblockP; public: memblockWrapper(xmlrpc_mem_block * const memblockP) : memblockP(memblockP) {} ~memblockWrapper() { XMLRPC_MEMBLOCK_FREE(char, memblockP); } }; xmlrpc_value * cArrayFromParamList(paramList const& paramList) { env_wrap env; xmlrpc_value * paramArrayP; paramArrayP = xmlrpc_array_new(&env.env_c); if (!env.env_c.fault_occurred) { for (unsigned int i = 0; i < paramList.size() && !env.env_c.fault_occurred; ++i) { cValueWrapper const param(paramList[i].cValue()); xmlrpc_array_append_item(&env.env_c, paramArrayP, param.valueP); } } if (env.env_c.fault_occurred) { xmlrpc_DECREF(paramArrayP); throw(error(env.env_c.fault_string)); } return paramArrayP; } paramList const paramListFromCArray(xmlrpc_value * const cArrayP) { paramList retval; env_wrap env; unsigned int const nParam(xmlrpc_array_size(&env.env_c, cArrayP)); if (!env.env_c.fault_occurred) { for (unsigned int i = 0; i < nParam && !env.env_c.fault_occurred; ++i) { xmlrpc_value * cParamP; xmlrpc_array_read_item(&env.env_c, cArrayP, i, &cParamP); if (!env.env_c.fault_occurred) { cValueWrapper const paramAuto(cParamP); // Causes xmlrpc_DECREF(cParamP) at end of scope retval.add(cParamP); } } } if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); return retval; } } // namespace namespace xmlrpc_c { namespace xml { void generateCall(string const& methodName, paramList const& paramList, xmlrpc_dialect const dialect, string * const callXmlP) { /*---------------------------------------------------------------------------- Generate the XML for an XML-RPC call, given a method name and parameter list. Use dialect 'dialect' of XML-RPC. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * callXmlMP; env_wrap env; callXmlMP = XMLRPC_MEMBLOCK_NEW(char, &env.env_c, 0); if (!env.env_c.fault_occurred) { memblockWrapper callXmlHolder(callXmlMP); // Makes callXmlMP get freed at end of scope xmlrpc_value * const paramArrayP(cArrayFromParamList(paramList)); xmlrpc_serialize_call2(&env.env_c, callXmlMP, methodName.c_str(), paramArrayP, dialect); *callXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, callXmlMP), XMLRPC_MEMBLOCK_SIZE(char, callXmlMP)); xmlrpc_DECREF(paramArrayP); } if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void generateCall(string const& methodName, paramList const& paramList, string * const callXmlP) { generateCall(methodName, paramList, xmlrpc_dialect_i8, callXmlP); } void parseCall(string const& callXml, string * const methodNameP, paramList * const paramListP) { env_wrap env; const char * c_methodName; xmlrpc_value * c_paramArrayP; xmlrpc_parse_call(&env.env_c, callXml.c_str(), callXml.size(), &c_methodName, &c_paramArrayP); if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); else { cValueWrapper const paramListAuto(c_paramArrayP); // Causes XMLRPC_decref(c_paramArrayP) at end of scope cStringWrapper const methodNameAuto(c_methodName); // Causes xmlrpc_strfree(c_methodName) at end of scope *paramListP = paramListFromCArray(c_paramArrayP); *methodNameP = string(c_methodName); } } void generateResponse(rpcOutcome const& outcome, xmlrpc_dialect const dialect, string * const respXmlP) { /*---------------------------------------------------------------------------- Generate the XML for an XML-RPC resp, given the RPC outcome. Use dialect 'dialect' of XML-RPC. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * respXmlMP; env_wrap env; respXmlMP = XMLRPC_MEMBLOCK_NEW(char, &env.env_c, 0); if (!env.env_c.fault_occurred) { memblockWrapper respXmlAuto(respXmlMP); // Makes respXmlMP get freed at end of scope if (outcome.succeeded()) { cValueWrapper cResult(outcome.getResult().cValue()); xmlrpc_serialize_response2(&env.env_c, respXmlMP, cResult.valueP, dialect); *respXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, respXmlMP), XMLRPC_MEMBLOCK_SIZE(char, respXmlMP)); } else { env_wrap cFault; xmlrpc_env_set_fault(&cFault.env_c, outcome.getFault().getCode(), outcome.getFault().getDescription().c_str()); xmlrpc_serialize_fault(&env.env_c, respXmlMP, &cFault.env_c); *respXmlP = string(XMLRPC_MEMBLOCK_CONTENTS(char, respXmlMP), XMLRPC_MEMBLOCK_SIZE(char, respXmlMP)); } } if (env.env_c.fault_occurred) throw(error(env.env_c.fault_string)); } void generateResponse(rpcOutcome const& outcome, string * const respXmlP) { generateResponse(outcome, xmlrpc_dialect_i8, respXmlP); } void parseResponse(string const& responseXml, rpcOutcome * const outcomeP) { /*---------------------------------------------------------------------------- Parse the XML for an XML-RPC response into an XML-RPC result value. -----------------------------------------------------------------------------*/ env_wrap env; xmlrpc_value * c_resultP; int faultCode; const char * faultString; xmlrpc_parse_response2(&env.env_c, responseXml.c_str(), responseXml.size(), &c_resultP, &faultCode, &faultString); if (env.env_c.fault_occurred) throwf("Unable to find XML-RPC response in what server sent back. %s", env.env_c.fault_string); else { if (faultString) { *outcomeP = rpcOutcome(fault(faultString, static_cast(faultCode))); xmlrpc_strfree(faultString); } else { XMLRPC_ASSERT_VALUE_OK(c_resultP); *outcomeP = rpcOutcome(value(c_resultP)); xmlrpc_DECREF(c_resultP); } } } void parseSuccessfulResponse(string const& responseXml, value * const resultP) { /*---------------------------------------------------------------------------- Same as parseResponse(), but expects the response to indicate success; throws an error if it doesn't. -----------------------------------------------------------------------------*/ rpcOutcome outcome; parseResponse(responseXml, &outcome); if (!outcome.succeeded()) throwf("RPC response indicates it failed. %s", outcome.getFault().getDescription().c_str()); *resultP = outcome.getResult(); } void trace(string const& label, string const& xml) { xmlrpc_traceXml(label.c_str(), xml.c_str(), xml.size()); } }} // namespace xmlrpc-c-1.33.14/src/double.c000066400000000000000000000155261236133176700156370ustar00rootroot00000000000000#include #include #include #include "xmlrpc-c/util.h" #include "xmlrpc-c/util_int.h" #include "double.h" typedef struct { char * bytes; /* NULL means there has been a memory allocation failure. bufferConcat() still works in this case, because we dont' want callers to have to deal with the out-of-memory possibility; it's just a no-op. */ char * next; char * end; } buffer; static void bufferInit(buffer * const bufferP) { unsigned int const initialSize = 64; bufferP->bytes = malloc(initialSize); if (bufferP->bytes) { bufferP->next = bufferP->bytes; bufferP->end = bufferP->bytes + initialSize; } } static void bufferConcat(buffer * const bufferP, char const newChar) { if (bufferP->bytes) { if (bufferP->next >= bufferP->end) { size_t const oldSize = bufferP->end - bufferP->bytes; size_t const newSize = oldSize + 64; bufferP->bytes = realloc(bufferP->bytes, newSize); bufferP->next = bufferP->bytes + oldSize; bufferP->end = bufferP->bytes + newSize; } if (bufferP->bytes) *(bufferP->next++) = newChar; } } static char digitChar(unsigned int const digitValue) { assert(digitValue < 10); return '0' + digitValue; } static unsigned int leadDigit(double const arg, double const precision) { /*---------------------------------------------------------------------------- Assuming 'arg' has one digit before the decimal point (which may be zero), return that digit. We assume the precision of 'arg' is plus or minus 'precision', and bias our estimation of the first digit up. We do that bias in order to bias toward shorter decimal ciphers: It's cleaner to consider 2.9999999 to be 3 than to consider 3 to be 2.999999. -----------------------------------------------------------------------------*/ return MIN(9, (unsigned int)(arg + precision)); } static void floatWhole(double const value, buffer * const formattedP, double * const formattedAmountP, double * const precisionP) { /*---------------------------------------------------------------------------- Format into *formattedP the whole part of 'value', i.e. the part before the decimal point. Return as *formattedAmountP the whole amount; e.g. if 'value' is 35.2, we return *formattedAmountP = 35. As there is imprecision involved in our calculations, return as *precisionP the maximum difference there may be be between 'double' and what we formatted. -----------------------------------------------------------------------------*/ if (value < 1.0) { /* No digits to add to the whole part */ *formattedAmountP = 0; *precisionP = DBL_EPSILON; } else { double nonLeastAmount; double nonLeastPrecision; unsigned int leastValue; /* Add all digits but the least significant to *formattedP */ floatWhole(value/10.0, formattedP, &nonLeastAmount, &nonLeastPrecision); /* Add the least significant digit to *formattedP */ if (nonLeastPrecision > 0.1) { /* We're down in the noise now; no point in showing any more significant digits (and we couldn't if we wanted to, because nonLeastPrecision * 10 might be more than 10 less than 'value'). */ leastValue = 0; } else leastValue = leadDigit(value - nonLeastAmount * 10, nonLeastPrecision * 10); bufferConcat(formattedP, digitChar(leastValue)); *formattedAmountP = nonLeastAmount * 10 + leastValue; *precisionP = nonLeastPrecision * 10; } } static void floatFractionPart(double const value, double const wholePrecision, buffer * const formattedP) { /*---------------------------------------------------------------------------- Serialize the part that comes after the decimal point, assuming there is something (nonzero) before the decimal point that uses up all but 'wholePrecision' of the available precision. -----------------------------------------------------------------------------*/ double precision; double d; assert(value < 1.0); for (d = value, precision = wholePrecision; d > precision; precision *= 10) { unsigned int digitValue; d *= 10; digitValue = leadDigit(d, precision); d -= digitValue; assert(d < 1.0); bufferConcat(formattedP, digitChar(digitValue)); } } static void floatFraction(double const value, buffer * const formattedP) { /*---------------------------------------------------------------------------- Serialize the part that comes after the decimal point, assuming there is nothing before the decimal point. -----------------------------------------------------------------------------*/ double precision; double d; assert(0.0 < value && value < 1.0); /* Do the leading zeroes, which eat no precision */ for (d = value * 10; d < 1.0; d *= 10) bufferConcat(formattedP, '0'); /* Now the significant digits */ precision = DBL_EPSILON; while (d > precision) { unsigned int const digitValue = leadDigit(d, precision); bufferConcat(formattedP, digitChar(digitValue)); d -= digitValue; assert(d < 1.0); d *= 10; precision *= 10; } } void xmlrpc_formatFloat(xmlrpc_env * const envP, double const value, const char ** const formattedP) { double absvalue; buffer formatted; bufferInit(&formatted); if (value < 0.0) { bufferConcat(&formatted, '-'); absvalue = - value; } else absvalue = value; if (absvalue >= 1.0) { double wholePart; double wholePrecision; floatWhole(absvalue, &formatted, &wholePart, &wholePrecision); if (wholePrecision >= 1.0) { /* We ran out of precision before we got to the decimal point */ } else { double const fractionPart = absvalue - wholePart; if (fractionPart > wholePrecision) { bufferConcat(&formatted, '.'); floatFractionPart(fractionPart, wholePrecision, &formatted); } } } else { bufferConcat(&formatted, '0'); if (absvalue > 0.0) { bufferConcat(&formatted, '.'); floatFraction(absvalue, &formatted); } } bufferConcat(&formatted, '\0'); if (formatted.bytes == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory to format %g", value); else *formattedP = formatted.bytes; } xmlrpc-c-1.33.14/src/double.h000066400000000000000000000003551236133176700156360ustar00rootroot00000000000000#ifndef DOUBLE_H_INCLUDED #define DOUBLE_H_INCLUDED #include "xmlrpc-c/util.h" void xmlrpc_formatFloat(xmlrpc_env * const envP, double const value, const char ** const formattedP); #endif xmlrpc-c-1.33.14/src/json.c000066400000000000000000001157351236133176700153410ustar00rootroot00000000000000/*============================================================================= json.c =============================================================================== Bo Lorentsen (bl@lue.dk) had the idea to do XML-RPC values in JSON and wrote the original version of this code in February and March 2010. Bryan Henderson restructured the code and improved diagnostic information (made it tell you where the JSON is screwed up) before its first release in XML-RPC for C and C++ in Release 1.22. JSON: RFC-4627 =============================================================================*/ #include "xmlrpc_config.h" #include #include #include #include #include #include #include #include "xmlrpc-c/json.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/string_number.h" /*============================================================================= Tokenizer for the json parser =============================================================================*/ enum ttype { typeNone, typeOpenBrace, typeCloseBrace, typeOpenBracket, typeCloseBracket, typeColon, typeComma, typeString, typeInteger, typeFloat, typeNull, typeUndefined, typeTrue, typeFalse, typeEof, } ; static const char * tokTypeName(enum ttype const type) { switch (type) { case typeNone: return "None"; case typeOpenBrace: return "Open brace"; case typeCloseBrace: return "Close brace"; case typeOpenBracket: return "Open bracket"; case typeCloseBracket: return "Close bracket"; case typeColon: return "Colon"; case typeComma: return "Comma"; case typeString: return "String"; case typeInteger: return "Integer"; case typeFloat: return "Float"; case typeNull: return "Null"; case typeUndefined: return "Undefined"; case typeTrue: return "True"; case typeFalse: return "False"; case typeEof: return "Eof"; default: return "???"; } } typedef struct { const char * original; size_t size; const char * begin; const char * end; enum ttype type; } Tokenizer; static void initializeTokenizer(Tokenizer * const tokP, const char * const str) { tokP->original = str; tokP->end = str; /* end of the "previous" token */ tokP->type = typeNone; } static void terminateTokenizer(Tokenizer * const tokP ATTR_UNUSED ) { } struct docPosition { /* A position in the document, as meaningful to the user */ unsigned int lineNum; /* First line is 1 */ unsigned int colNum; /* First column is 1 */ }; static struct docPosition currentDocumentPosition(Tokenizer * const tokP) { /*---------------------------------------------------------------------------- Return the document position (line & column) of the start of the current token -----------------------------------------------------------------------------*/ struct docPosition retval; unsigned int curLine; unsigned int curCol; const char * cursor; curLine = 0; curCol = 0; for (cursor = tokP->original; cursor < tokP->begin; ++cursor) { ++curCol; if (*cursor == '\n') { ++curLine; curCol = 0; } } retval.lineNum = curLine + 1; retval.colNum = curCol + 1; return retval; } static void setParseErr(xmlrpc_env * const envP, Tokenizer * const tokP, const char * const format, ...) { struct docPosition const pos = currentDocumentPosition(tokP); va_list args; const char * msg; XMLRPC_ASSERT(envP != NULL); XMLRPC_ASSERT(format != NULL); va_start(args, format); xmlrpc_vasprintf(&msg, format, args); xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "JSON parse error at Line %u, Column %u: %s", pos.lineNum, pos.colNum, msg); xmlrpc_strfree(msg); va_end(args); } static void finishStringToken(xmlrpc_env * const envP, Tokenizer * const tokP) { ++tokP->end; while (*tokP->end != '"' && *tokP->end != '\0' && !envP->fault_occurred) { if (*tokP->end == '\\') { ++tokP->end; switch (*tokP->end) { case '"': case '\\': case '/': case 'b': case 'f': case 'n': case 'r': case 't': ++tokP->end; break; case 'u': { const char * cur; ++tokP->end; cur = tokP->end; while (isxdigit(*cur) && cur - tokP->end < 4) ++cur; if (cur - tokP->end < 4) setParseErr(envP, tokP, "hex unicode must contain 4 digits. " "There are only %u here", cur - tokP->end); else tokP->end = cur; } break; default: setParseErr(envP, tokP, "unknown escape character " "after backslash: '%c'", *tokP->end); } } else ++tokP->end; } if (!envP->fault_occurred) { if (*tokP->end == '\0') setParseErr(envP, tokP, "JSON document ends in the middle " "of a backslash escape sequence"); else { ++tokP->end; tokP->size = (tokP->end - tokP->begin) - 1; } } } static bool isInteger(const char * const token, unsigned int const tokSize) { if (tokSize < 1) return false; else { unsigned int i; i = 0; if (token[0] == '-') ++i; while (i < tokSize) { if (!isdigit(token[i])) return false; ++i; } return true; } } static bool isFloat(const char * const token, unsigned int const tokSize) { /*---------------------------------------------------------------------------- The token 'token', of size 'tokSize' is a syntactically valid floating point number. N.B. This is true of any integer. We don't accept plus signs. Examples of valid floating point: 0, 32, 32.5, , 32.500, 32.5E4 -5, 32.5E-4, 005. -----------------------------------------------------------------------------*/ unsigned int i; bool seenPeriod; bool seenDigit; seenPeriod = false; seenDigit = false; i = 0; if (tokSize >= 1 && token[0] == '-') ++i; while (i < tokSize) { char const c = token[i]; if (c == 'e') return isInteger(&token[i], tokSize - i); else if (c == '.') { if (seenPeriod) { /* It's a second period */ return false; } else { seenPeriod = true; } } else if (isdigit(c)) seenDigit = true; else return false; ++i; } if (seenDigit) return true; else return false; } static bool isWordChar(char const candidate) { /*---------------------------------------------------------------------------- Return true iff 'candidate' is a character that can be in a "word" token. A word token is a multi-character token that is either a JSON keyword or a number. -----------------------------------------------------------------------------*/ return (isalnum(candidate) || candidate == '.' || candidate == '-'); } static void finishAlphanumericWordToken(Tokenizer * const tokP) { ++tokP->end; while (isWordChar(*tokP->end)) ++tokP->end; tokP->size = tokP->end - tokP->begin; } static void finishDelimiterToken(Tokenizer * const tokP) { ++tokP->end; tokP->size = tokP->end - tokP->begin; } static bool atComment(Tokenizer * const tokP) { return (*tokP->begin == '/' && *(tokP->begin + 1) == '/'); } static void advancePastWhiteSpace(Tokenizer * const tokP) { while (isspace(*tokP->begin)) ++tokP->begin; } static void advancePastComments(Tokenizer * const tokP) { /*---------------------------------------------------------------------------- Advance the pointer over any comments. -----------------------------------------------------------------------------*/ while (atComment(tokP)) { /* A comment ends at a newline or end of document */ while (*tokP->begin != '\n' && *tokP->begin != '\0') ++tokP->begin; } } static void advanceToNextToken(Tokenizer * const tokP) { /*---------------------------------------------------------------------------- Advance the pointer over any white space and comments to the next token, or end of document, whichever comes first. -----------------------------------------------------------------------------*/ while (*tokP->begin != '\0' && (isspace(*tokP->begin) || atComment(tokP))) { advancePastWhiteSpace(tokP); advancePastComments(tokP); } } static void getToken(xmlrpc_env * const envP, Tokenizer * const tokP) { /* The token starts where the last one left off */ tokP->begin = tokP->end; advanceToNextToken(tokP); if (*tokP->begin == '\0') { /* End of document */ tokP->end = tokP->begin; tokP->type = typeEof; tokP->size = tokP->end - tokP->begin; } else { tokP->end = tokP->begin; /* initial value */ if (*tokP->begin == '{') { finishDelimiterToken(tokP); tokP->type = typeOpenBrace; } else if (*tokP->begin == '}') { finishDelimiterToken(tokP); tokP->type = typeCloseBrace; } else if (*tokP->begin == '[') { finishDelimiterToken(tokP); tokP->type = typeOpenBracket; } else if (*tokP->begin == ']') { finishDelimiterToken(tokP); tokP->type = typeCloseBracket; } else if (*tokP->begin == ':') { finishDelimiterToken(tokP); tokP->type = typeColon; } else if (*tokP->begin == ',') { finishDelimiterToken(tokP); tokP->type = typeComma; } else if (*tokP->begin == '"') { finishStringToken(envP, tokP); if (!envP->fault_occurred) tokP->type = typeString; } else { if (isWordChar(*tokP->begin)) { finishAlphanumericWordToken(tokP); if (isInteger(tokP->begin, tokP->size)) tokP->type = typeInteger; else if (isFloat(tokP->begin, tokP->size)) tokP->type = typeFloat; else if (xmlrpc_strneq(tokP->begin, "null", tokP->size)) tokP->type = typeNull; else if (xmlrpc_strneq(tokP->begin, "undefined", tokP->size)) tokP->type = typeUndefined; else if(xmlrpc_strneq(tokP->begin, "false", tokP->size)) tokP->type = typeFalse; else if(xmlrpc_strneq(tokP->begin, "true", tokP->size)) tokP->type = typeTrue; else setParseErr(envP, tokP, "Invalid word token -- " "Not a valid integer, floating point " "number, 'null', 'true', or 'false'"); } else { setParseErr(envP, tokP, "Not a valid token -- starts with '%c'; " "a valid token starts with " "one of []{}:,\"-. or digit or letter", *tokP->begin); } } } } /*===========================================================================*/ static int utf8Decode(uint32_t const c, char * const out) { /*--------------------------------------------------------------------------- convert a unicode char to a utf8 char ---------------------------------------------------------------------------*/ if (c <= 0x7F) { /* 0XXX XXXX one byte */ out[0] = (char) c; return 1; } else if (c <= 0x7FF) { /* 110X XXXX two bytes */ out[0] = (char)( 0xC0 | (c >> 6) ); out[1] = (char)( 0x80 | (c & 0x3F) ); return 2; } else if (c <= 0xFFFF) { /* 1110 XXXX three bytes */ out[0] = (char) (0xE0 | (c >> 12)); out[1] = (char) (0x80 | ((c >> 6) & 0x3F)); out[2] = (char) (0x80 | (c & 0x3F)); return 3; } else if (c <= 0x1FFFFF) { /* 1111 0XXX four bytes */ out[0] = (char) (0xF0 | (c >> 18)); out[1] = (char) (0x80 | ((c >> 12) & 0x3F)); out[2] = (char) (0x80 | ((c >> 6) & 0x3F)); out[3] = (char) (0x80 | (c & 0x3F)); return 4; } else return 0; } static void getBackslashSequence(xmlrpc_env * const envP, const char * const cur, xmlrpc_mem_block * const memBlockP, unsigned int * const nBytesConsumedP) { char buffer[5]; unsigned int tsize; switch (*cur) { case '"': buffer[0] = '"'; tsize = 1; *nBytesConsumedP = 1; break; case '/': buffer[0] = '/'; tsize = 1; *nBytesConsumedP = 1; break; case '\\': buffer[0] = '\\'; tsize = 1; *nBytesConsumedP = 1; break; case 'b': buffer[0] = '\b'; tsize = 1; *nBytesConsumedP = 1; break; case 'f': buffer[0] = '\f'; tsize = 1; *nBytesConsumedP = 1; break; case 'n': buffer[0] = '\n'; tsize = 1; *nBytesConsumedP = 1; break; case 'r': buffer[0] = '\r'; tsize = 1; *nBytesConsumedP = 1; break; case 't': buffer[0] = '\t'; tsize = 1; *nBytesConsumedP = 1; break; case 'u': { long digit; strncpy(buffer, cur + 1, 4); digit = strtol(buffer, NULL, 16); tsize = utf8Decode(digit, buffer); *nBytesConsumedP = 5; /* uXXXX */ break; } default: xmlrpc_faultf(envP, "Invalid character after backslash " "escape: '%c'", *cur); *nBytesConsumedP = 0; /* quiet compiler warning */ tsize = 0; /* quiet compiler warning */ } if (!envP->fault_occurred) XMLRPC_MEMBLOCK_APPEND(char, envP, memBlockP, buffer, tsize ); } static void unescapeString(xmlrpc_env * const envP, const char * const begin, const char * const end, xmlrpc_mem_block * const memBlockP) { XMLRPC_MEMBLOCK_INIT(char, envP, memBlockP, 0); if (!envP->fault_occurred) { const char * cur; const char * last; cur = begin; last = cur; while (cur != end && !envP->fault_occurred) { if (*cur == '\\') { if (cur != last) { XMLRPC_MEMBLOCK_APPEND( char, envP, memBlockP, last, cur - last ); if (!envP->fault_occurred) last = cur; } if (!envP->fault_occurred) { unsigned int nBytesConsumed; cur += 1; /* consume slash */ getBackslashSequence(envP, cur, memBlockP, &nBytesConsumed); if (!envP->fault_occurred) { cur += nBytesConsumed; last = cur; } } } else ++cur; } if (!envP->fault_occurred) { if (cur != last) { XMLRPC_MEMBLOCK_APPEND(char, envP, memBlockP, last, cur - last ); } } if (!envP->fault_occurred) { /* Append terminating NUL */ XMLRPC_MEMBLOCK_APPEND(char, envP, memBlockP, "", 1); } if (envP->fault_occurred) XMLRPC_MEMBLOCK_CLEAN(char, memBlockP); } } static xmlrpc_value * makeUtf8String(xmlrpc_env * const envP, const char * const begin, const char * const end) { /*---------------------------------------------------------------------------- Copy a json string directly into a string value, and convert any json escaping (\uXXXX) to something acceptable to the internal string handling. Try to do this in as few chunks as possible ! -----------------------------------------------------------------------------*/ xmlrpc_value * valP; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_STRING; valP->_wcs_block = NULL; if (!envP->fault_occurred) unescapeString(envP, begin, end, &valP->_block); if (envP->fault_occurred) xmlrpc_DECREF(valP); } return valP; } static xmlrpc_value * stringTokenValue(xmlrpc_env * const envP, Tokenizer * const tokP) { xmlrpc_env env; xmlrpc_value * valP; xmlrpc_env_init(&env); assert(tokP->end >= tokP->begin + 2); assert(*tokP->begin == '"'); assert(*(tokP->end-1) == '"'); valP = makeUtf8String(&env, tokP->begin + 1, tokP->end - 1); if (env.fault_occurred) { setParseErr(envP, tokP, "Error in string token: %s", env.fault_string); } xmlrpc_env_clean(&env); return valP; } static xmlrpc_value * integerTokenValue(xmlrpc_env * const envP, Tokenizer * const tokP) { xmlrpc_env env; char valueString[tokP->size + 1]; xmlrpc_int64 value; xmlrpc_value * valP; xmlrpc_env_init(&env); memcpy(valueString, tokP->begin, tokP->size); valueString[tokP->size] = '\0'; xmlrpc_parse_int64(&env, valueString, &value); if (env.fault_occurred) setParseErr(envP, tokP, "Error in integer token value '%s': %s", tokP->begin, env.fault_string); else valP = xmlrpc_i8_new(envP, value); xmlrpc_env_clean(&env); return valP; } /* Forward declarations for recursion: */ static xmlrpc_value * parseValue(xmlrpc_env * const envP, Tokenizer * const tokP); static xmlrpc_value * parseList(xmlrpc_env * const envP, Tokenizer * const tokP); static xmlrpc_value * parseObject(xmlrpc_env * const envP, Tokenizer * const tokP); static void parseListElement(xmlrpc_env * const envP, Tokenizer * const tokP, xmlrpc_value * const listArrayP, bool * const endOfListP) { xmlrpc_value * itemP; itemP = parseValue(envP, tokP); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, listArrayP, itemP); if (!envP->fault_occurred) { getToken(envP, tokP); if (!envP->fault_occurred) { if (tokP->type == typeComma) { *endOfListP = false; } else if (tokP->type == typeCloseBracket) *endOfListP = true; else setParseErr(envP, tokP, "Need comma or close bracket " "after array item. Instead we have %s", tokTypeName(tokP->type)); } } xmlrpc_DECREF(itemP); } } static xmlrpc_value * parseList(xmlrpc_env * const envP, Tokenizer * const tokP) { xmlrpc_value * retval; XMLRPC_ASSERT_ENV_OK(envP); retval = xmlrpc_array_new(envP); if (!envP->fault_occurred) { bool endOfList; for (endOfList = false; !endOfList && !envP->fault_occurred; ) { getToken(envP,tokP); if (!envP->fault_occurred) { if (tokP->type == typeEof) endOfList = true; else if (tokP->type == typeCloseBracket) endOfList = true; else parseListElement(envP, tokP, retval, &endOfList); } } if (envP->fault_occurred) xmlrpc_DECREF(retval); } return retval; } static void parseObjectMemberValue(xmlrpc_env * const envP, Tokenizer * const tokP, xmlrpc_value * const keyP, xmlrpc_value * const objectP) { xmlrpc_value * valP; getToken(envP,tokP); if (!envP->fault_occurred) { valP = parseValue(envP, tokP); if (!envP->fault_occurred) { xmlrpc_struct_set_value_v(envP, objectP, keyP, valP); xmlrpc_DECREF(valP); } } } static void parseObjectMember(xmlrpc_env * const envP, Tokenizer * const tokP, xmlrpc_value * const objectP) { xmlrpc_env env; xmlrpc_value * keyP; xmlrpc_env_init(&env); /* The current token is the string which is the member name: */ assert(tokP->type = typeString); assert(tokP->end >= tokP->begin + 2); assert(*tokP->begin == '"'); assert(*(tokP->end-1) == '"'); keyP = makeUtf8String(&env, tokP->begin + 1, tokP->end - 1); if (env.fault_occurred) setParseErr(envP, tokP, "Error in what is supposed to be " "the key of a member of an object: %s", env.fault_string); else { getToken(envP, tokP); if (!envP->fault_occurred) { if (tokP->type == typeColon) parseObjectMemberValue(envP, tokP, keyP, objectP); else setParseErr(envP, tokP, "Need a colon after member key " "in object. Instead we have %s", tokTypeName(tokP->type)); } xmlrpc_DECREF(keyP); } xmlrpc_env_clean(&env); } static xmlrpc_value * parseObject(xmlrpc_env * const envP, Tokenizer * const tokP) { xmlrpc_value * retval; XMLRPC_ASSERT_ENV_OK(envP); retval = xmlrpc_struct_new(envP); if (!envP->fault_occurred) { bool objectDone; objectDone = false; while (!objectDone && !envP->fault_occurred) { getToken(envP, tokP); if (!envP->fault_occurred) { if (tokP->type == typeCloseBrace) { objectDone = true; } else if (tokP->type == typeString) { parseObjectMember(envP, tokP, retval); if (!envP->fault_occurred) { getToken(envP, tokP); if (!envP->fault_occurred) { if (tokP->type == typeComma) { /* member separator; keep going */ } else if (tokP->type == typeCloseBrace) { /* No more members in this object */ objectDone = true; } else setParseErr( envP, tokP, "Need a comma or close brace after object " "member. Instead we have %s", tokTypeName(tokP->type)); } } } else { setParseErr(envP, tokP, "Need a string (i.e. starting with " "a quotation mark) as member key " "in object, or closing brace to end the " "object. Instead we have %s", tokTypeName(tokP->type)); } } } if (envP->fault_occurred) xmlrpc_DECREF(retval); } return retval; } static xmlrpc_value * parseValue(xmlrpc_env * const envP, Tokenizer * const tokP) { xmlrpc_value * retval; XMLRPC_ASSERT_ENV_OK(envP); switch (tokP->type) { case typeOpenBracket: retval = parseList(envP, tokP); break; case typeOpenBrace: retval = parseObject(envP, tokP); break; case typeNull: retval = xmlrpc_nil_new(envP); break; case typeUndefined: retval = xmlrpc_nil_new(envP); break; case typeFalse: retval = xmlrpc_bool_new(envP, (xmlrpc_bool)false); break; case typeTrue: retval = xmlrpc_bool_new(envP, (xmlrpc_bool)true); break; case typeInteger: retval = integerTokenValue(envP, tokP); break; case typeFloat: retval = xmlrpc_double_new(envP, strtod(tokP->begin, NULL)); break; case typeString: retval = stringTokenValue(envP, tokP); break; default: retval = NULL; setParseErr(envP, tokP, "Invalid token " "where a value is supposed to begin: %s. " "Should be an open bracket, open brace, " "'null', 'false', 'true', a number, or a string", tokTypeName(tokP->type)); } return retval; } xmlrpc_value * xmlrpc_parse_json(xmlrpc_env * const envP, const char * const str) { xmlrpc_value * retval = retval; Tokenizer tok; XMLRPC_ASSERT_ENV_OK(envP); initializeTokenizer(&tok, str); getToken(envP, &tok); if (!envP->fault_occurred) { retval = parseValue(envP, &tok); if (!envP->fault_occurred) { getToken(envP, &tok); if (!envP->fault_occurred) { if (tok.type != typeEof) setParseErr(envP, &tok, "There is junk after the end of " "the JSON value, to wit a %s token", tokTypeName(tok.type)); } if (envP->fault_occurred) xmlrpc_DECREF(retval); } } terminateTokenizer(&tok); return retval; } /*============================================================================ Serialize value to JSON ============================================================================*/ /* Borrowed from xmlrpc_serialize */ static void formatOut(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const char * const formatString, ... ) { va_list args; char buffer[1024]; int rc; XMLRPC_ASSERT_ENV_OK(envP); va_start(args, formatString); rc = XMLRPC_VSNPRINTF(buffer, sizeof(buffer), formatString, args); /* Old vsnprintf() (and Windows) fails with return value -1 if the full string doesn't fit in the buffer. New vsnprintf() puts whatever will fit in the buffer, and returns the length of the full string regardless. For us, this truncation is a failure. */ if (rc < 0) xmlrpc_faultf(envP, "formatOut() overflowed internal buffer"); else { unsigned int const formattedLen = rc; if (formattedLen + 1 >= (sizeof(buffer))) xmlrpc_faultf(envP, "formatOut() overflowed internal buffer"); else XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, buffer, formattedLen); } va_end(args); } static void indent(xmlrpc_env * const envP, unsigned int const level, xmlrpc_mem_block * const outP) { unsigned int i; for (i = 0; i < level * 2 && !envP->fault_occurred; ++i) XMLRPC_MEMBLOCK_APPEND(char, envP, outP, " ", 1); } /* Forward declaration for recursion */ static void serializeValue(xmlrpc_env * const envP, xmlrpc_value * const valP, unsigned int const level, xmlrpc_mem_block * const outP); static void appendEscapeSeq(xmlrpc_env * const envP, xmlrpc_mem_block * const outP, unsigned char const c) { /*---------------------------------------------------------------------------- Append to *outP the escaped representation of 'c'. This is e.g. "\t" for tab, or "\u001C" for something exotic. -----------------------------------------------------------------------------*/ unsigned int size; char buffer[6]; char slashChar; /* Character that goes after the backslash, including 'u' for \uHHHH */ switch (c) { case '"' : slashChar = '"'; break; /* U+0022 */ case '\\': slashChar = '\\'; break; /* U+005C */ case '\b': slashChar = 'b'; break; /* U+0008 */ case '\f': slashChar = 'f'; break; /* U+000C */ case '\n': slashChar = 'n'; break; /* U+000A */ case '\r': slashChar = 'r'; break; /* U+000D */ case '\t': slashChar = 't'; break; /* U+0009 */ default: slashChar = 'u'; }; buffer[0] = '\\'; buffer[1] = slashChar; if (slashChar == 'u') { sprintf(&buffer[2], "%04x", c); size = 6; /* \u1234 */ } else size = 2; XMLRPC_MEMBLOCK_APPEND(char, envP, outP, buffer, size); } static void makeJsonString(xmlrpc_env * const envP, const char * const value, size_t const length, xmlrpc_mem_block * const outP) { /*---------------------------------------------------------------------------- Create a JSON representation of a string, appended to *outP. -----------------------------------------------------------------------------*/ const char * const begin = &value[0]; const char * const end = begin + length; const char * cur; const char * last; last = cur = begin; while (cur != end && !envP->fault_occurred) { unsigned char const c = *cur; if (c < 0x1F || c == '"' || c == '\\') { /* This characters needs to be escaped. Put a backslash escape sequence in the output for this character, after copying all the characters before it to the output. */ XMLRPC_MEMBLOCK_APPEND(char, envP, outP, last, cur - last); if (!envP->fault_occurred) { appendEscapeSeq(envP, outP, c); ++cur; last = cur; } } else ++cur; } /* Copy all characters since the last escaped character to the output */ if (cur != last) XMLRPC_MEMBLOCK_APPEND(char, envP, outP, last, cur - last); if (envP->fault_occurred) XMLRPC_MEMBLOCK_CLEAN(char, outP); } static void makeJsonStringFromXmlRpc(xmlrpc_env * const envP, const xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { /*---------------------------------------------------------------------------- Convert a string XML-RPC value to JSON, appended to *outP. -----------------------------------------------------------------------------*/ const char * value; size_t length; xmlrpc_read_string_lp(envP, valP, &length, &value); if (!envP->fault_occurred) { makeJsonString(envP, value, length, outP); xmlrpc_strfree(value); } } static void serializeInt(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { xmlrpc_int value; xmlrpc_read_int(envP, valP, &value); formatOut(envP, outP, "%d", value); } static void serializeI8(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { xmlrpc_int64 value; xmlrpc_read_i8(envP, valP, &value); formatOut(envP, outP, "%" XMLRPC_PRId64, value); } static void serializeBool(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { xmlrpc_bool value; xmlrpc_read_bool(envP, valP, &value); formatOut(envP, outP, "%s", value ? "true" : "false"); } static void serializeDouble(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { xmlrpc_double value; xmlrpc_read_double(envP, valP, &value); formatOut(envP, outP, "%e", value); } static void serializeDatetime(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { /* ISO 8601 time string as JSON does not have a datetime type */ formatOut(envP, outP, "\"%u%02u%02uT%02u:%02u:%02u\"", valP->_value.dt.Y, valP->_value.dt.M, valP->_value.dt.D, valP->_value.dt.h, valP->_value.dt.m, valP->_value.dt.s); } static void serializeString(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { formatOut(envP, outP, "\""); makeJsonStringFromXmlRpc(envP, valP, outP); formatOut(envP, outP, "\""); } static void serializeBitstring(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { /*---------------------------------------------------------------------------- Append to *outP a JSON string whose value is the bit string *valP in base64 ASCII. -----------------------------------------------------------------------------*/ const unsigned char * bytes; size_t size; xmlrpc_read_base64(envP, valP, &size, &bytes); if (!envP->fault_occurred) { xmlrpc_mem_block * const base64P = xmlrpc_base64_encode(envP, bytes, size); if (!envP->fault_occurred) { formatOut(envP, outP, "\""); XMLRPC_MEMBLOCK_APPEND( char, envP, outP, XMLRPC_MEMBLOCK_CONTENTS(char, base64P), XMLRPC_MEMBLOCK_SIZE(char, base64P)); if (!envP->fault_occurred) formatOut(envP, outP, "\""); XMLRPC_MEMBLOCK_FREE(char, base64P); } free((unsigned char*)bytes); } } static void serializeArray(xmlrpc_env * const envP, xmlrpc_value * const valP, unsigned int const level, xmlrpc_mem_block * const outP) { unsigned int const size = xmlrpc_array_size(envP, valP); if (!envP->fault_occurred) { unsigned int i; formatOut(envP, outP, "[\n"); for (i = 0; i < size && !envP->fault_occurred; ++i) { xmlrpc_value * const itemP = xmlrpc_array_get_item(envP, valP, i); if (!envP->fault_occurred) { if (!envP->fault_occurred) { serializeValue(envP, itemP, level + 1, outP); if (i < size - 1) XMLRPC_MEMBLOCK_APPEND(char, envP, outP, ",\n", 2); } } } if (!envP->fault_occurred) { XMLRPC_MEMBLOCK_APPEND(char, envP, outP, "\n", 1); indent(envP, level, outP); if (!envP->fault_occurred) { XMLRPC_MEMBLOCK_APPEND(char, envP, outP, "]", 1); } } } } static void serializeStructMember(xmlrpc_env * const envP, xmlrpc_value * const memberKeyP, xmlrpc_value * const memberValueP, unsigned int const level, xmlrpc_mem_block * const outP) { serializeValue(envP, memberKeyP, level, outP); if (!envP->fault_occurred) { formatOut(envP, outP, ":"); if (!envP->fault_occurred) serializeValue(envP, memberValueP, level, outP); } } static void serializeStruct(xmlrpc_env * const envP, xmlrpc_value * const valP, unsigned int const level, xmlrpc_mem_block * const outP) { if (!envP->fault_occurred) { formatOut(envP, outP, "{\n"); if (!envP->fault_occurred) { unsigned int const size = xmlrpc_struct_size(envP, valP); if (!envP->fault_occurred) { unsigned int i; for (i = 0; i < size && !envP->fault_occurred; ++i) { xmlrpc_value * memberKeyP; xmlrpc_value * memberValueP; xmlrpc_struct_get_key_and_value(envP, valP, i, &memberKeyP, &memberValueP); if (!envP->fault_occurred) { serializeStructMember(envP, memberKeyP, memberValueP, level + 1, outP); if (!envP->fault_occurred && i < size - 1) XMLRPC_MEMBLOCK_APPEND(char, envP, outP, ",\n", 2); } } if (!envP->fault_occurred) { XMLRPC_MEMBLOCK_APPEND(char, envP, outP, "\n", 1); indent(envP, level, outP); XMLRPC_MEMBLOCK_APPEND(char, envP, outP, "}", 1); } } } } } static void serializeValue(xmlrpc_env * const envP, xmlrpc_value * const valP, unsigned int const level, xmlrpc_mem_block * const outP) { XMLRPC_ASSERT_ENV_OK(envP); indent(envP, level, outP); switch (xmlrpc_value_type(valP)) { case XMLRPC_TYPE_INT: serializeInt(envP, valP, outP); break; case XMLRPC_TYPE_I8: serializeI8(envP, valP, outP); break; case XMLRPC_TYPE_BOOL: serializeBool(envP, valP, outP); break; case XMLRPC_TYPE_DOUBLE: serializeDouble(envP, valP, outP); break; case XMLRPC_TYPE_DATETIME: serializeDatetime(envP, valP, outP); break; case XMLRPC_TYPE_STRING: serializeString(envP, valP, outP); break; case XMLRPC_TYPE_BASE64: serializeBitstring(envP, valP, outP); break; case XMLRPC_TYPE_ARRAY: serializeArray(envP, valP, level, outP); break; case XMLRPC_TYPE_STRUCT: serializeStruct(envP, valP, level, outP); break; case XMLRPC_TYPE_C_PTR: xmlrpc_faultf(envP, "Tried to serialize a C pointer value."); break; case XMLRPC_TYPE_NIL: formatOut(envP, outP, "null"); break; case XMLRPC_TYPE_DEAD: xmlrpc_faultf(envP, "Tried to serialize a dead value."); break; default: xmlrpc_faultf(envP, "Invalid xmlrpc_value type: 0x%x", xmlrpc_value_type(valP)); } } void xmlrpc_serialize_json(xmlrpc_env * const envP, xmlrpc_value * const valP, xmlrpc_mem_block * const outP) { serializeValue(envP, valP, 0, outP); } xmlrpc-c-1.33.14/src/method.c000066400000000000000000000311711236133176700156370ustar00rootroot00000000000000/*========================================================================= XML-RPC server method registry Method services =========================================================================== These are the functions that implement the method objects that the XML-RPC method registry uses. By Bryan Henderson, December 2006. Contributed to the public domain by its author. =========================================================================*/ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include "xmlrpc_config.h" #include #include #include #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/base.h" #include "registry.h" #include "method.h" static void signatureDestroy(struct xmlrpc_signature * const signatureP) { if (signatureP->argList) free((void*)signatureP->argList); free(signatureP); } static void translateTypeSpecifierToName(xmlrpc_env * const envP, char const typeSpecifier, const char ** const typeNameP) { switch (typeSpecifier) { case 'i': *typeNameP = "int"; break; case 'b': *typeNameP = "boolean"; break; case 'd': *typeNameP = "double"; break; case 's': *typeNameP = "string"; break; case '8': *typeNameP = "dateTime.iso8601"; break; case '6': *typeNameP = "base64"; break; case 'S': *typeNameP = "struct"; break; case 'A': *typeNameP = "array"; break; case 'n': *typeNameP = "nil"; break; case 'I': *typeNameP = "i8"; break; default: xmlrpc_faultf(envP, "Method registry contains invalid signature " "data. It contains the type specifier '%c'", typeSpecifier); *typeNameP = NULL; /* quiet compiler warning */ } } #if defined(_MSC_VER) /* MSVC 8 complains that const char ** is incompatible with void * in the REALLOCARRAY. It's not. */ #pragma warning(push) #pragma warning(disable:4090) #endif static void makeRoomInArgList(xmlrpc_env * const envP, struct xmlrpc_signature * const signatureP, unsigned int const minArgCount) { if (signatureP->argListSpace < minArgCount) { REALLOCARRAY(signatureP->argList, minArgCount); if (signatureP->argList == NULL) { xmlrpc_faultf(envP, "Couldn't get memory for a argument list for " "a method signature with %u arguments", minArgCount); signatureP->argListSpace = 0; } } } #if defined(_MSC_VER) #pragma warning(pop) #endif static void parseArgumentTypeSpecifiers(xmlrpc_env * const envP, const char * const startP, struct xmlrpc_signature * const signatureP, const char ** const nextPP) { const char * cursorP; cursorP = startP; /* start at the beginning */ while (!envP->fault_occurred && *cursorP != ',' && *cursorP != '\0') { const char * typeName; translateTypeSpecifierToName(envP, *cursorP, &typeName); if (!envP->fault_occurred) { ++cursorP; makeRoomInArgList(envP, signatureP, signatureP->argCount + 1); signatureP->argList[signatureP->argCount++] = typeName; } } if (!envP->fault_occurred) { if (*cursorP) { XMLRPC_ASSERT(*cursorP == ','); ++cursorP; /* Move past the signature and comma */ } } if (envP->fault_occurred) free((void*)signatureP->argList); *nextPP = cursorP; } static void parseOneSignature(xmlrpc_env * const envP, const char * const startP, struct xmlrpc_signature ** const signaturePP, const char ** const nextPP) { /*---------------------------------------------------------------------------- Parse one signature from the signature string that starts at 'startP'. Return that signature as a signature object *signaturePP. Return as *nextP the location in the signature string of the next signature (i.e. right after the next comma). If there is no next signature (the string ends before any comma), make it point to the terminating NUL. -----------------------------------------------------------------------------*/ struct xmlrpc_signature * signatureP; MALLOCVAR(signatureP); if (signatureP == NULL) xmlrpc_faultf(envP, "Couldn't get memory for signature"); else { const char * cursorP; signatureP->argListSpace = 0; /* Start with no argument space */ signatureP->argList = NULL; /* Nothing allocated yet */ signatureP->argCount = 0; /* Start with no arguments */ cursorP = startP; /* start at the beginning */ if (*cursorP == ',' || *cursorP == '\0') xmlrpc_faultf(envP, "empty signature (a signature " "must have at least return value type)"); else { translateTypeSpecifierToName(envP, *cursorP, &signatureP->retType); ++cursorP; if (*cursorP != ':') xmlrpc_faultf(envP, "No colon (':') after " "the result type specifier"); else { ++cursorP; parseArgumentTypeSpecifiers(envP, cursorP, signatureP, nextPP); } } if (envP->fault_occurred) free(signatureP); } *signaturePP = signatureP; } static void destroySignatures(struct xmlrpc_signature * const firstSignatureP) { struct xmlrpc_signature * p; struct xmlrpc_signature * nextP; for (p = firstSignatureP; p; p = nextP) { nextP = p->nextP; signatureDestroy(p); } } static void listSignatures(xmlrpc_env * const envP, const char * const sigListString, struct xmlrpc_signature ** const firstSignaturePP) { struct xmlrpc_signature ** p; const char * cursorP; *firstSignaturePP = NULL; /* Start with empty list */ p = firstSignaturePP; cursorP = &sigListString[0]; while (!envP->fault_occurred && *cursorP != '\0') { struct xmlrpc_signature * signatureP; parseOneSignature(envP, cursorP, &signatureP, &cursorP); /* cursorP now points at next signature in the list or the terminating NUL. */ if (!envP->fault_occurred) { signatureP->nextP = NULL; *p = signatureP; p = &signatureP->nextP; } } if (envP->fault_occurred) destroySignatures(*firstSignaturePP); } static void signatureListCreate(xmlrpc_env * const envP, const char * const sigListString, xmlrpc_signatureList ** const signatureListPP) { xmlrpc_signatureList * signatureListP; XMLRPC_ASSERT_ENV_OK(envP); MALLOCVAR(signatureListP); if (signatureListP == NULL) xmlrpc_faultf(envP, "Could not allocate memory for signature list"); else { signatureListP->firstSignatureP = NULL; if (sigListString == NULL || xmlrpc_streq(sigListString, "?")) { /* No signatures -- leave the list empty */ } else { listSignatures(envP, sigListString, &signatureListP->firstSignatureP); if (!envP->fault_occurred) { if (!signatureListP->firstSignatureP) xmlrpc_faultf(envP, "Signature string is empty."); if (envP->fault_occurred) destroySignatures(signatureListP->firstSignatureP); } } if (envP->fault_occurred) free(signatureListP); *signatureListPP = signatureListP; } } static void signatureListDestroy(xmlrpc_signatureList * const signatureListP) { destroySignatures(signatureListP->firstSignatureP); free(signatureListP); } static void makeSignatureList(xmlrpc_env * const envP, const char * const signatureString, xmlrpc_signatureList ** const signatureListPP) { xmlrpc_env env; xmlrpc_env_init(&env); signatureListCreate(&env, signatureString, signatureListPP); if (env.fault_occurred) xmlrpc_faultf(envP, "Can't interpret signature string '%s'. %s", signatureString, env.fault_string); xmlrpc_env_clean(&env); } void xmlrpc_methodCreate(xmlrpc_env * const envP, xmlrpc_method1 methodFnType1, xmlrpc_method2 methodFnType2, void * const userData, const char * const signatureString, const char * const helpText, size_t const stackSize, xmlrpc_methodInfo ** const methodPP) { xmlrpc_methodInfo * methodP; XMLRPC_ASSERT_ENV_OK(envP); MALLOCVAR(methodP); if (methodP == NULL) xmlrpc_faultf(envP, "Unable to allocate storage for a method " "descriptor"); else { methodP->methodFnType1 = methodFnType1; methodP->methodFnType2 = methodFnType2; methodP->userData = userData; methodP->helpText = xmlrpc_strdupsol(helpText); methodP->stackSize = stackSize; makeSignatureList(envP, signatureString, &methodP->signatureListP); if (envP->fault_occurred) { xmlrpc_strfree(methodP->helpText); free(methodP); } *methodPP = methodP; } } void xmlrpc_methodDestroy(xmlrpc_methodInfo * const methodP) { signatureListDestroy(methodP->signatureListP); xmlrpc_strfree(methodP->helpText); free(methodP); } void xmlrpc_methodListCreate(xmlrpc_env * const envP, xmlrpc_methodList ** const methodListPP) { xmlrpc_methodList * methodListP; XMLRPC_ASSERT_ENV_OK(envP); MALLOCVAR(methodListP); if (methodListP == NULL) xmlrpc_faultf(envP, "Couldn't allocate method list descriptor"); else { methodListP->firstMethodP = NULL; methodListP->lastMethodP = NULL; *methodListPP = methodListP; } } void xmlrpc_methodListDestroy(xmlrpc_methodList * methodListP) { xmlrpc_methodNode * p; xmlrpc_methodNode * nextP; for (p = methodListP->firstMethodP; p; p = nextP) { nextP = p->nextP; xmlrpc_methodDestroy(p->methodP); xmlrpc_strfree(p->methodName); free(p); } free(methodListP); } void xmlrpc_methodListLookupByName(xmlrpc_methodList * const methodListP, const char * const methodName, xmlrpc_methodInfo ** const methodPP) { /* We do a simple linear lookup along a linked list. If speed is important, we can make this a binary tree instead. */ xmlrpc_methodNode * p; xmlrpc_methodInfo * methodP; for (p = methodListP->firstMethodP, methodP = NULL; p && !methodP; p = p->nextP) { if (xmlrpc_streq(p->methodName, methodName)) methodP = p->methodP; } *methodPP = methodP; } void xmlrpc_methodListAdd(xmlrpc_env * const envP, xmlrpc_methodList * const methodListP, const char * const methodName, xmlrpc_methodInfo * const methodP) { xmlrpc_methodInfo * existingMethodP; XMLRPC_ASSERT_ENV_OK(envP); xmlrpc_methodListLookupByName(methodListP, methodName, &existingMethodP); if (existingMethodP) xmlrpc_faultf(envP, "Method named '%s' already registered", methodName); else { xmlrpc_methodNode * methodNodeP; MALLOCVAR(methodNodeP); if (methodNodeP == NULL) xmlrpc_faultf(envP, "Couldn't allocate method node"); else { methodNodeP->methodName = strdup(methodName); methodNodeP->methodP = methodP; methodNodeP->nextP = NULL; if (!methodListP->firstMethodP) methodListP->firstMethodP = methodNodeP; if (methodListP->lastMethodP) methodListP->lastMethodP->nextP = methodNodeP; methodListP->lastMethodP = methodNodeP; } } } xmlrpc-c-1.33.14/src/method.h000066400000000000000000000107071236133176700156460ustar00rootroot00000000000000#ifndef METHOD_H_INCLUDED #define METHOD_H_INCLUDED #include "xmlrpc-c/base.h" struct xmlrpc_signature { struct xmlrpc_signature * nextP; const char * retType; /* Name of the XML-RPC element that represents the return value type, e.g. "int" or "dateTime.iso8601" */ unsigned int argCount; /* Number of arguments method takes */ unsigned int argListSpace; /* Number of slots that exist in the argList[] (i.e. memory is allocated) */ const char ** argList; /* Array of size 'argCount'. argList[i] is the name of the type of argument i. Like 'retType', e.g. "string". The strings are constants, not malloc'ed. */ }; typedef struct xmlrpc_signatureList { /* A list of signatures for a method. Each signature describes one alternative form of invoking the method (a single method might have multiple forms, e.g. one takes two integer arguments; another takes a single string). */ struct xmlrpc_signature * firstSignatureP; } xmlrpc_signatureList; struct xmlrpc_registry { bool introspectionEnabled; struct xmlrpc_methodList * methodListP; xmlrpc_default_method defaultMethodFunction; void * defaultMethodUserData; xmlrpc_preinvoke_method preinvokeFunction; void * preinvokeUserData; xmlrpc_server_shutdown_fn * shutdownServerFn; /* Function that can be called to shut down the server that is using this registry. NULL if none. */ void * shutdownContext; /* Context for _shutdown_server_fn -- understood only by that function, passed to it as argument. */ xmlrpc_dialect dialect; }; typedef struct { /*---------------------------------------------------------------------------- Everything a registry knows about one XML-RPC method -----------------------------------------------------------------------------*/ /* One of the methodTypeX fields is NULL and the other isn't. (The reason there are two is backward compatibility. Old programs set up the registry with Type 1; modern ones set it up with Type 2. */ xmlrpc_method1 methodFnType1; /* The method function, if it's type 1. Null if it's not */ xmlrpc_method2 methodFnType2; /* The method function, if it's type 2. Null if it's not */ void * userData; /* Passed to method function */ size_t stackSize; /* Amount of stack space 'methodFnType1' or 'methodFnType2' uses. Zero means unspecified. */ struct xmlrpc_signatureList * signatureListP; /* Stuff returned by system method system.methodSignature. Empty list doesn't mean there are no valid forms of calling the method -- just that the registry declines to state. */ const char * helpText; /* Stuff returned by system method system.methodHelp */ } xmlrpc_methodInfo; typedef struct xmlrpc_methodNode { struct xmlrpc_methodNode * nextP; const char * methodName; xmlrpc_methodInfo * methodP; } xmlrpc_methodNode; typedef struct xmlrpc_methodList { xmlrpc_methodNode * firstMethodP; xmlrpc_methodNode * lastMethodP; } xmlrpc_methodList; void xmlrpc_methodCreate(xmlrpc_env * const envP, xmlrpc_method1 methodFnType1, xmlrpc_method2 methodFnType2, void * const userData, const char * const signatureString, const char * const helpText, size_t const stackSize, xmlrpc_methodInfo ** const methodPP); void xmlrpc_methodDestroy(xmlrpc_methodInfo * const methodP); void xmlrpc_methodListCreate(xmlrpc_env * const envP, xmlrpc_methodList ** const methodListPP); void xmlrpc_methodListDestroy(xmlrpc_methodList * methodListP); void xmlrpc_methodListLookupByName(xmlrpc_methodList * const methodListP, const char * const methodName, xmlrpc_methodInfo ** const methodPP); void xmlrpc_methodListAdd(xmlrpc_env * const envP, xmlrpc_methodList * const methodListP, const char * const methodName, xmlrpc_methodInfo * const methodP); #endif xmlrpc-c-1.33.14/src/parse_datetime.c000066400000000000000000000341331236133176700173460ustar00rootroot00000000000000#include "xmlrpc_config.h" #include #include #include #include #if HAVE_REGEX #include /* Missing from regex.h in GNU libc */ #include #endif #include "bool.h" #include "c_util.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "parse_datetime.h" #if HAVE_REGEX static unsigned int digitStringValue(const char * const string, regmatch_t const match) { /*---------------------------------------------------------------------------- Return the numerical value of the decimal whole number substring of 'string' identified by 'match'. E.g. if 'string' is 'abc34d' and 'match' says start at 3 and end at 5, we return 34. -----------------------------------------------------------------------------*/ unsigned int i; unsigned int accum; assert(match.rm_so >= 0); assert(match.rm_eo >= 0); for (i = match.rm_so, accum = 0; i < (unsigned)match.rm_eo; ++i) { accum *= 10; assert(isdigit(string[i])); accum += string[i] - '0'; } return accum; } #endif /* HAVE_REGEX */ #if HAVE_REGEX static unsigned int digitStringMillionths(const char * const string, regmatch_t const match) { /*---------------------------------------------------------------------------- Return the number of millionths represented by the digits after the decimal point in a decimal string, where thse digits are the substring of 'string' identified by 'match'. E.g. if the substring is 34, we return 340,000. -----------------------------------------------------------------------------*/ unsigned int i; unsigned int accum; assert(match.rm_so >= 0); assert(match.rm_eo >= 0); for (i = match.rm_so, accum = 0; i < (unsigned)match.rm_so+6; ++i) { accum *= 10; if (i < (unsigned)match.rm_eo) { assert(isdigit(string[i])); accum += string[i] - '0'; } } return accum; } #endif /* HAVE_REGEX */ #if HAVE_REGEX static void subParseDtRegex_standard(regmatch_t * const matches, const char * const datetimeString, xmlrpc_datetime * const dtP) { dtP->Y = digitStringValue(datetimeString, matches[1]); dtP->M = digitStringValue(datetimeString, matches[2]); dtP->D = digitStringValue(datetimeString, matches[3]); dtP->h = digitStringValue(datetimeString, matches[4]); dtP->m = digitStringValue(datetimeString, matches[5]); dtP->s = digitStringValue(datetimeString, matches[6]); if (matches[7].rm_so == -1) dtP->u = 0; else dtP->u = digitStringMillionths(datetimeString, matches[7]); } static void subParseDtRegex_standardtzd(regmatch_t * const matches, const char * const datetimeString, xmlrpc_datetime * const dtP) { dtP->Y = digitStringValue(datetimeString, matches[1]); dtP->M = digitStringValue(datetimeString, matches[2]); dtP->D = digitStringValue(datetimeString, matches[3]); dtP->h = digitStringValue(datetimeString, matches[4]); dtP->m = digitStringValue(datetimeString, matches[5]); dtP->s = digitStringValue(datetimeString, matches[6]); dtP->u = 0; } #endif /* HAVE_REGEX */ #if HAVE_REGEX typedef void (*regparsefunc_t)(regmatch_t * const matches, const char * const datetimeString, xmlrpc_datetime * const dtP); struct regexParser { const char * const regex; regparsefunc_t func; }; static const struct regexParser iso8601Regex[] /* Each entry of this table is instructions for recognizing and parsing some form of a "dateTime.iso8601" XML element. (Note that we recognize far more than just the XML-RPC standard dateTime.iso8601). */ = { { /* Examples: YYYYMMDD[T]HHMMSS YYYY-MM-DD[T]HH:MM:SS YYYY-MM-DD[T]HH:MM:SS.ssss */ "^([0-9]{4})\\-?([0-9]{2})\\-?([0-9]{2})T" "([0-9]{2}):?([0-9]{2}):?([0-9]{2})\\.?([0-9]+)?$", subParseDtRegex_standard }, { /* Examples: YYYYMMDD[T]HHMMSS[Z] YYYYMMDD[T]HHMMSS[+-]hh YYYYMMDD[T]HHMMSS[+-]hhmm */ "^([0-9]{4})\\-?([0-9]{2})\\-?([0-9]{2})T" "([0-9]{2}):?([0-9]{2}):?([0-9]{2})[Z\\+\\-]([0-9]{2,4})?$", subParseDtRegex_standardtzd }, { NULL, NULL } }; #endif /* HAVE_REGEX */ #if HAVE_REGEX static void parseDtRegex(xmlrpc_env * const envP, const char * const datetimeString, xmlrpc_datetime * const dtP) { unsigned int i; const struct regexParser * parserP; /* The parser that matches 'datetimeString'. Null if no match yet found. */ regmatch_t matches[1024]; for (i = 0, parserP = NULL; iso8601Regex[i].regex && !parserP; ++i) { const struct regexParser * const thisParserP = &iso8601Regex[i]; regex_t re; int status; status = regcomp(&re, thisParserP->regex, REG_ICASE | REG_EXTENDED); /* Our regex is valid, so it must have compiled: */ assert(status == 0); { int status; status = regexec(&re, datetimeString, ARRAY_SIZE(matches), matches, 0); if (status == 0) { assert(matches[0].rm_so != -1); /* Match of whole regex */ parserP = thisParserP; } regfree(&re); } } if (parserP) { parserP->func(matches, datetimeString, dtP); } else { xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "value '%s' is not of any form we recognize " "for a element", datetimeString); } } #endif /* HAVE_REGEX */ static __inline__ void parseDtNoRegex(xmlrpc_env * const envP, const char * const datetimeString, xmlrpc_datetime * const dtP) { unsigned int const dtStrlen = strlen(datetimeString); char year[4+1]; char month[2+1]; char day[2+1]; char hour[2+1]; char minute[2+1]; char second[2+1]; if (dtStrlen < 17 || dtStrlen == 18 || dtStrlen > 24) xmlrpc_faultf(envP, "could not parse date, size incompatible: '%d'", dtStrlen); else { year[0] = datetimeString[ 0]; year[1] = datetimeString[ 1]; year[2] = datetimeString[ 2]; year[3] = datetimeString[ 3]; year[4] = '\0'; month[0] = datetimeString[ 4]; month[1] = datetimeString[ 5]; month[2] = '\0'; day[0] = datetimeString[ 6]; day[1] = datetimeString[ 7]; day[2] = '\0'; assert(datetimeString[ 8] == 'T'); hour[0] = datetimeString[ 9]; hour[1] = datetimeString[10]; hour[2] = '\0'; assert(datetimeString[11] == ':'); minute[0] = datetimeString[12]; minute[1] = datetimeString[13]; minute[2] = '\0'; assert(datetimeString[14] == ':'); second[0] = datetimeString[15]; second[1] = datetimeString[16]; second[2] = '\0'; if (dtStrlen > 17) { unsigned int const pad = 24 - dtStrlen; unsigned int i; dtP->u = atoi(&datetimeString[18]); for (i = 0; i < pad; ++i) dtP->u *= 10; } else dtP->u = 0; dtP->Y = atoi(year); dtP->M = atoi(month); dtP->D = atoi(day); dtP->h = atoi(hour); dtP->m = atoi(minute); dtP->s = atoi(second); } } static void validateFirst17(xmlrpc_env * const envP, const char * const dt) { /*---------------------------------------------------------------------------- Assuming 'dt' is at least 17 characters long, validate that the first 17 characters are a valid XML-RPC datetime, e.g. "20080628T16:35:02" -----------------------------------------------------------------------------*/ unsigned int i; for (i = 0; i < 8 && !envP->fault_occurred; ++i) if (!isdigit(dt[i])) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a digit: '%c'", dt[i]); if (dt[8] != 'T') xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "9th character is '%c', not 'T'", dt[8]); if (!isdigit(dt[9])) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a digit: '%c'", dt[9]); if (!isdigit(dt[10])) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a digit: '%c'", dt[10]); if (dt[11] != ':') xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a colon: '%c'", dt[11]); if (!isdigit(dt[12])) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a digit: '%c'", dt[12]); if (!isdigit(dt[13])) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a digit: '%c'", dt[13]); if (dt[14] != ':') xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a colon: '%c'", dt[14]); if (!isdigit(dt[15])) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a digit: '%c'", dt[15]); if (!isdigit(dt[16])) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Not a digit: '%c'", dt[16]); } static void validateFractionalSeconds(xmlrpc_env * const envP, const char * const dt) { /*---------------------------------------------------------------------------- Validate the fractional seconds part of the XML-RPC datetime string 'dt', if any. That's the decimal point and everything following it. -----------------------------------------------------------------------------*/ if (strlen(dt) > 17) { if (dt[17] != '.') { xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "'%c' where only a period is valid", dt[17]); } else { if (dt[18] == '\0') xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Nothing after decimal point"); else { unsigned int i; for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) { if (!isdigit(dt[i])) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Non-digit in fractional seconds: '%c'", dt[i]); } } } } } static __inline__ void validateFormatNoRegex(xmlrpc_env * const envP, const char * const dt) { if (strlen(dt) < 17) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Invalid length of %u of datetime. " "Must be at least 17 characters", (unsigned)strlen(dt)); else { validateFirst17(envP, dt); validateFractionalSeconds(envP, dt); } } static void validateXmlrpcDatetimeSome(xmlrpc_env * const envP, xmlrpc_datetime const dt) { /*---------------------------------------------------------------------------- Type xmlrpc_datetime is defined such that it can represent a nonexistent datetime such as February 30. Validate that 'dt' doesn't have glaring invalidities such as Hour 25. We leave the possibility of more subtle invalidity such as February 30. -----------------------------------------------------------------------------*/ if (dt.M < 1 || dt.M > 12) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Month of year value %u is not in the range 1-12", dt.M); else if (dt.D < 1 || dt.D > 31) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Day of month value %u is not in the range 1-31", dt.D); else if (dt.h > 23) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Hour of day value %u is not in the range 0-23", dt.h); else if (dt.m > 59) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Minute of hour value %u is not in the range 0-59", dt.m); else if (dt.s > 59) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Second of minute value %u is not in the range 0-59", dt.s); else if (dt.u > 999999) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Microsecond of second value %u is not in the range 0-1M", dt.u); } void xmlrpc_parseDatetime(xmlrpc_env * const envP, const char * const datetimeString, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Parse the content of a XML-RPC XML element, e.g. "20000301T00:00:00". 'str' is that content. Example of the format we parse: "19980717T14:08:55" Note that this is not quite ISO 8601. It's a bizarre combination of two ISO 8601 formats. Note that Xmlrpc-c recognizes various extensions of the XML-RPC element type. 'str' may not be valid XML-RPC (with extensions). In that case we fail with fault code XMLRPC_PARSE_ERROR. -----------------------------------------------------------------------------*/ xmlrpc_datetime dt; #if HAVE_REGEX parseDtRegex(envP, datetimeString, &dt); #else /* Note: validation is not as strong without regex */ validateFormatNoRegex(envP, datetimeString); if (!envP->fault_occurred) parseDtNoRegex(envP, datetimeString, &dt); #endif if (!envP->fault_occurred) { validateXmlrpcDatetimeSome(envP, dt); if (!envP->fault_occurred) *valuePP = xmlrpc_datetime_new(envP, dt); } } xmlrpc-c-1.33.14/src/parse_datetime.h000066400000000000000000000004371236133176700173530ustar00rootroot00000000000000#ifndef PARSE_DATETIME_H_INCLUDED #define PARSE_DATETIME_H_INCLUDED #include "xmlrpc-c/util.h" #include "xmlrpc-c/base.h" void xmlrpc_parseDatetime(xmlrpc_env * const envP, const char * const str, xmlrpc_value ** const valuePP); #endif xmlrpc-c-1.33.14/src/parse_value.c000066400000000000000000000571331236133176700166730ustar00rootroot00000000000000#include "xmlrpc_config.h" #include #include #include #include #include #include #include #include "bool.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/string_number.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/xmlparser.h" #include "parse_datetime.h" #include "parse_value.h" static void setParseFault(xmlrpc_env * const envP, const char * const format, ...) { va_list args; va_start(args, format); xmlrpc_set_fault_formatted_v(envP, XMLRPC_PARSE_ERROR, format, args); va_end(args); } static void parseArrayDataChild(xmlrpc_env * const envP, xml_element * const childP, unsigned int const maxRecursion, xmlrpc_value * const arrayP) { const char * const elemName = xml_element_name(childP); if (!xmlrpc_streq(elemName, "value")) setParseFault(envP, " element has <%s> child. " "Only makes sense.", elemName); else { xmlrpc_value * itemP; xmlrpc_parseValue(envP, maxRecursion-1, childP, &itemP); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, arrayP, itemP); xmlrpc_DECREF(itemP); } } } static void parseArray(xmlrpc_env * const envP, unsigned int const maxRecursion, xml_element * const arrayElemP, xmlrpc_value ** const arrayPP) { xmlrpc_value * arrayP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(arrayElemP != NULL); arrayP = xmlrpc_array_new(envP); if (!envP->fault_occurred) { size_t const childCount = xml_element_children_size(arrayElemP); if (childCount != 1) setParseFault(envP, " element has %u children. Only one " "makes sense.", (unsigned int)childCount); else { xml_element * const dataElemP = xml_element_children(arrayElemP)[0]; const char * const elemName = xml_element_name(dataElemP); if (!xmlrpc_streq(elemName, "data")) setParseFault(envP, " element has <%s> child. Only " "makes sense.", elemName); else { xml_element ** const values = xml_element_children(dataElemP); unsigned int const size = xml_element_children_size(dataElemP); unsigned int i; for (i = 0; i < size && !envP->fault_occurred; ++i) parseArrayDataChild(envP, values[i], maxRecursion, arrayP); } } if (envP->fault_occurred) xmlrpc_DECREF(arrayP); else *arrayPP = arrayP; } } static void parseName(xmlrpc_env * const envP, xml_element * const nameElemP, xmlrpc_value ** const valuePP) { size_t const childCount = xml_element_children_size(nameElemP); if (childCount > 0) setParseFault(envP, " element has %u children. " "Should have none.", (unsigned int)childCount); else { const char * const cdata = xml_element_cdata(nameElemP); size_t const cdataSize = xml_element_cdata_size(nameElemP); *valuePP = xmlrpc_string_new_lp(envP, cdataSize, cdata); } } static void getNameChild(xmlrpc_env * const envP, xml_element * const parentP, xml_element * * const childPP) { xml_element ** const children = xml_element_children(parentP); size_t const childCount = xml_element_children_size(parentP); xml_element * childP; unsigned int i; for (i = 0, childP = NULL; i < childCount && !childP; ++i) { if (xmlrpc_streq(xml_element_name(children[i]), "name")) childP = children[i]; } if (!childP) xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, " has no child"); else *childPP = childP; } static void getValueChild(xmlrpc_env * const envP, xml_element * const parentP, xml_element * * const childPP) { xml_element ** const children = xml_element_children(parentP); size_t const childCount = xml_element_children_size(parentP); xml_element * childP; unsigned int i; for (i = 0, childP = NULL; i < childCount && !childP; ++i) { if (xmlrpc_streq(xml_element_name(children[i]), "value")) childP = children[i]; } if (!childP) xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, " has no child"); else *childPP = childP; } static void parseMember(xmlrpc_env * const envP, xml_element * const memberP, unsigned int const maxRecursion, xmlrpc_value ** const keyPP, xmlrpc_value ** const valuePP) { size_t const childCount = xml_element_children_size(memberP); if (childCount != 2) setParseFault(envP, " element has %u children. Only one and " "one make sense.", (unsigned int)childCount); else { xml_element * nameElemP; getNameChild(envP, memberP, &nameElemP); if (!envP->fault_occurred) { parseName(envP, nameElemP, keyPP); if (!envP->fault_occurred) { xml_element * valueElemP; getValueChild(envP, memberP, &valueElemP); if (!envP->fault_occurred) xmlrpc_parseValue(envP, maxRecursion-1, valueElemP, valuePP); if (envP->fault_occurred) xmlrpc_DECREF(*keyPP); } } } } static void parseStruct(xmlrpc_env * const envP, unsigned int const maxRecursion, xml_element * const elemP, xmlrpc_value ** const structPP) { /*---------------------------------------------------------------------------- Parse the element 'elemP'. -----------------------------------------------------------------------------*/ xmlrpc_value * structP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(elemP != NULL); structP = xmlrpc_struct_new(envP); if (!envP->fault_occurred) { /* Iterate over our children, extracting key/value pairs. */ xml_element ** const members = xml_element_children(elemP); unsigned int const size = xml_element_children_size(elemP); unsigned int i; for (i = 0; i < size && !envP->fault_occurred; ++i) { const char * const elemName = xml_element_name(members[i]); if (!xmlrpc_streq(elemName, "member")) setParseFault(envP, "<%s> element found where only " "makes sense", elemName); else { xmlrpc_value * keyP; xmlrpc_value * valueP; parseMember(envP, members[i], maxRecursion, &keyP, &valueP); if (!envP->fault_occurred) { xmlrpc_struct_set_value_v(envP, structP, keyP, valueP); xmlrpc_DECREF(keyP); xmlrpc_DECREF(valueP); } } } if (envP->fault_occurred) xmlrpc_DECREF(structP); else *structPP = structP; } } static void parseInt(xmlrpc_env * const envP, const char * const str, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Parse the content of a XML-RPC XML element, e.g. "34". 'str' is that content. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(str); if (str[0] == '\0') setParseFault(envP, " XML element content is empty"); else if (isspace(str[0])) setParseFault(envP, " content '%s' starts with white space", str); else { long i; char * tail; errno = 0; i = strtol(str, &tail, 10); /* Look for ERANGE. */ if (errno == ERANGE) setParseFault(envP, " XML element value '%s' represents a " "number beyond the range that " "XML-RPC allows (%d - %d)", str, XMLRPC_INT32_MIN, XMLRPC_INT32_MAX); else if (errno != 0) setParseFault(envP, "unexpected error parsing XML element " "value '%s'. strtol() failed with errno %d (%s)", str, errno, strerror(errno)); else { /* Look for out-of-range errors which didn't produce ERANGE. */ if (i < XMLRPC_INT32_MIN) setParseFault(envP, " value %ld is below the range allowed " "by XML-RPC (minimum is %d)", i, XMLRPC_INT32_MIN); else if (i > XMLRPC_INT32_MAX) setParseFault(envP, " value %ld is above the range allowed " "by XML-RPC (maximum is %d)", i, XMLRPC_INT32_MAX); else { if (tail[0] != '\0') setParseFault(envP, " value '%s' contains non-numerical " "junk: '%s'", str, tail); else *valuePP = xmlrpc_int_new(envP, i); } } } } static void parseBoolean(xmlrpc_env * const envP, const char * const str, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Parse the content of a XML-RPC XML element, e.g. "1". 'str' is that content. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(str); if (xmlrpc_streq(str, "0") || xmlrpc_streq(str, "1")) *valuePP = xmlrpc_bool_new(envP, xmlrpc_streq(str, "1") ? 1 : 0); else setParseFault(envP, " XML element content must be either " "'0' or '1' according to XML-RPC. This one has '%s'", str); } static void scanAndValidateDoubleString(xmlrpc_env * const envP, const char * const string, const char ** const mantissaP, const char ** const mantissaEndP, const char ** const fractionP, const char ** const fractionEndP) { const char * mantissa; const char * dp; const char * p; if (string[0] == '-' || string[0] == '+') mantissa = &string[1]; else mantissa = &string[0]; for (p = mantissa, dp = NULL; *p; ++p) { char const c = *p; if (c == '.') { if (dp) { setParseFault(envP, "Two decimal points"); return; } else dp = p; } else if (c < '0' || c > '9') { setParseFault(envP, "Garbage (not sign, digit, or period) " "starting at '%s'", p); return; } } *mantissaP = mantissa; if (dp) { *mantissaEndP = dp; *fractionP = dp+1; *fractionEndP = p; } else { *mantissaEndP = p; *fractionP = p; *fractionEndP = p; } } static bool isInfinite(double const value) { return value > DBL_MAX; } static void parseDoubleString(xmlrpc_env * const envP, const char * const string, double * const valueP) { /*---------------------------------------------------------------------------- Turn e.g. "4.3" into 4.3 . -----------------------------------------------------------------------------*/ /* strtod() is no good for this because it is designed for human interfaces; it parses according to locale. As a practical matter that sometimes means that it does not recognize "." as a decimal point. In XML-RPC, "." is a decimal point. Design note: in my experiments, using strtod() was 10 times slower than using this function. */ const char * mantissa; const char * mantissaEnd; const char * fraction; const char * fractionEnd; scanAndValidateDoubleString(envP, string, &mantissa, &mantissaEnd, &fraction, &fractionEnd); if (!envP->fault_occurred) { double accum; accum = 0.0; if (mantissa == mantissaEnd && fraction == fractionEnd) { setParseFault(envP, "No digits"); return; } { /* Add in the whole part */ const char * p; for (p = mantissa; p < mantissaEnd; ++p) { accum *= 10; accum += (*p - '0'); } } { /* Add in the fractional part */ double significance; const char * p; for (significance = 0.1, p = fraction; p < fractionEnd; ++p, significance *= 0.1) { accum += (*p - '0') * significance; } } if (isInfinite(accum)) setParseFault(envP, "Value exceeds the size allowed by XML-RPC"); else *valueP = string[0] == '-' ? (- accum) : accum; } } static void parseDoubleStringStrtod(const char * const str, bool * const failedP, double * const valueP) { if (strlen(str) == 0) { /* strtod() happily interprets empty string as 0.0. We don't think the user will appreciate that XML-RPC extension. */ *failedP = true; } else { char * tail; errno = 0; *valueP = strtod(str, &tail); if (errno != 0) *failedP = true; else { if (tail[0] != '\0') *failedP = true; else *failedP = false; } } } static void parseDouble(xmlrpc_env * const envP, const char * const str, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Parse the content of a XML-RPC XML element, e.g. "34.5". 'str' is that content. -----------------------------------------------------------------------------*/ xmlrpc_env parseEnv; double valueDouble; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(str); xmlrpc_env_init(&parseEnv); parseDoubleString(&parseEnv, str, &valueDouble); if (parseEnv.fault_occurred) { /* As an alternative, try a strtod() parsing. strtod() accepts other forms, e.g. "3.4E6"; "3,4"; " 3.4". These are not permitted by XML-RPC, but an almost-XML-RPC partner might use one. In fact, for many years, Xmlrpc-c generated such alternatives (by mistake). */ bool failed; parseDoubleStringStrtod(str, &failed, &valueDouble); if (failed) setParseFault(envP, " element value '%s' is not a valid " "floating point number. %s", str, parseEnv.fault_string); } if (!envP->fault_occurred) *valuePP = xmlrpc_double_new(envP, valueDouble); xmlrpc_env_clean(&parseEnv); } static void parseBase64(xmlrpc_env * const envP, const char * const str, size_t const strLength, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Parse the content of a XML-RPC XML element, e.g. "FD32YY". 'str' is that content. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * decoded; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(str); decoded = xmlrpc_base64_decode(envP, str, strLength); if (!envP->fault_occurred) { unsigned char * const bytes = XMLRPC_MEMBLOCK_CONTENTS(unsigned char, decoded); size_t const byteCount = XMLRPC_MEMBLOCK_SIZE(unsigned char, decoded); *valuePP = xmlrpc_base64_new(envP, byteCount, bytes); XMLRPC_MEMBLOCK_FREE(unsigned char, decoded); } } static void parseI8(xmlrpc_env * const envP, const char * const str, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Parse the content of a XML-RPC XML element, e.g. "34". 'str' is that content. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(str); if (str[0] == '\0') setParseFault(envP, " XML element content is empty"); else if (isspace(str[0])) setParseFault(envP, " content '%s' starts with white space", str); else { xmlrpc_int64 i; xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_parse_int64(&env, str, &i); if (env.fault_occurred) setParseFault(envP, " XML element value '%s' is invalid " "because it does not represent " "a 64 bit integer. %s", env.fault_string); else *valuePP = xmlrpc_i8_new(envP, i); xmlrpc_env_clean(&env); } } static void parseSimpleValueCdata(xmlrpc_env * const envP, const char * const elementName, const char * const cdata, size_t const cdataLength, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Parse an XML element that is supposedly a data type element such as . Its name is 'elementName', and it has no children, but contains cdata 'cdata', which is 'dataLength' characters long. -----------------------------------------------------------------------------*/ /* We need to straighten out the whole character set / encoding thing some day. What is 'cdata', and what should it be? Does it have embedded NUL? Some of the code here assumes it doesn't. Is it text? The parser assumes it's UTF 8 with embedded NULs. But the parser will get terribly confused if there are any UTF-8 multibyte sequences or NUL characters. So will most of the others. The "ex:XXX" element names are what the Apache XML-RPC facility uses: http://ws.apache.org/xmlrpc/types.html. (Technically, it isn't "ex" but an arbitrary prefix that identifies a namespace declared earlier in the XML document -- this is an XML thing. But we aren't nearly sophisticated enough to use real XML namespaces, so we exploit the fact that XML-RPC actually uses "ex"). "i1" and "i2" are just from my imagination. */ if (xmlrpc_streq(elementName, "int") || xmlrpc_streq(elementName, "i4") || xmlrpc_streq(elementName, "i1") || xmlrpc_streq(elementName, "i2") || xmlrpc_streq(elementName, "ex:i1") || xmlrpc_streq(elementName, "ex:i2")) parseInt(envP, cdata, valuePP); else if (xmlrpc_streq(elementName, "boolean")) parseBoolean(envP, cdata, valuePP); else if (xmlrpc_streq(elementName, "double")) parseDouble(envP, cdata, valuePP); else if (xmlrpc_streq(elementName, "dateTime.iso8601")) xmlrpc_parseDatetime(envP, cdata, valuePP); else if (xmlrpc_streq(elementName, "string")) *valuePP = xmlrpc_string_new_lp(envP, cdataLength, cdata); else if (xmlrpc_streq(elementName, "base64")) parseBase64(envP, cdata, cdataLength, valuePP); else if (xmlrpc_streq(elementName, "nil") || xmlrpc_streq(elementName, "ex:nil")) *valuePP = xmlrpc_nil_new(envP); else if (xmlrpc_streq(elementName, "i8") || xmlrpc_streq(elementName, "ex:i8")) parseI8(envP, cdata, valuePP); else setParseFault(envP, "Unknown value type -- XML element is named " "<%s>", elementName); } static void parseSimpleValue(xmlrpc_env * const envP, xml_element * const elemP, xmlrpc_value ** const valuePP) { size_t const childCount = xml_element_children_size(elemP); if (childCount > 0) setParseFault(envP, "The child of a element " "is neither nor , " "but has %u child elements of its own.", (unsigned int)childCount); else { const char * const elemName = xml_element_name(elemP); const char * const cdata = xml_element_cdata(elemP); size_t const cdataSize = xml_element_cdata_size(elemP); parseSimpleValueCdata(envP, elemName, cdata, cdataSize, valuePP); } } void xmlrpc_parseValue(xmlrpc_env * const envP, unsigned int const maxRecursion, xml_element * const elemP, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Compute the xmlrpc_value represented by the XML element 'elem'. Return that xmlrpc_value. We call convert_array() and convert_struct(), which may ultimately call us recursively. Don't recurse any more than 'maxRecursion' times. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(elemP != NULL); /* Assume we'll need to recurse, make sure we're allowed */ if (maxRecursion < 1) xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, "Nested data structure too deep."); else { if (!xmlrpc_streq(xml_element_name(elemP), "value")) setParseFault(envP, "<%s> element where expected", xml_element_name(elemP)); else { size_t const childCount = xml_element_children_size(elemP); if (childCount == 0) { /* We have no type element, so treat the value as a string. */ char * const cdata = xml_element_cdata(elemP); size_t const cdata_size = xml_element_cdata_size(elemP); *valuePP = xmlrpc_string_new_lp(envP, cdata_size, cdata); } else if (childCount > 1) setParseFault(envP, " has %u child elements. " "Only zero or one make sense.", (unsigned int)childCount); else { /* We should have a type tag inside our value tag. */ xml_element * const childP = xml_element_children(elemP)[0]; const char * const childName = xml_element_name(childP); if (xmlrpc_streq(childName, "struct")) parseStruct(envP, maxRecursion, childP, valuePP); else if (xmlrpc_streq(childName, "array")) parseArray(envP, maxRecursion, childP, valuePP); else parseSimpleValue(envP, childP, valuePP); } } } } xmlrpc-c-1.33.14/src/parse_value.h000066400000000000000000000005151236133176700166700ustar00rootroot00000000000000#ifndef PARSE_VALUE_H_INCLUDED #define PARSE_VALUE_H_INCLUDED #include "xmlrpc-c/base.h" #include "xmlrpc-c/xmlparser.h" void xmlrpc_parseValue(xmlrpc_env * const envP, unsigned int const maxRecursion, xml_element * const elemP, xmlrpc_value ** const valuePP); #endif xmlrpc-c-1.33.14/src/registry.c000066400000000000000000000367671236133176700162470ustar00rootroot00000000000000/*========================================================================= XML-RPC Server Method Registry =========================================================================== These are the functions that implement the XML-RPC method registry. A method registry is a list of XML-RPC methods for a server to implement, along with the details of how to implement each -- most notably a function pointer for a function that executes the method. To build an XML-RPC server, just add a communication facility. Copyright information is at end of file =========================================================================*/ #include #include #include #include "xmlrpc_config.h" #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "method.h" #include "system_method.h" #include "version.h" #include "registry.h" unsigned int const xmlrpc_server_version_major = XMLRPC_VERSION_MAJOR; unsigned int const xmlrpc_server_version_minor = XMLRPC_VERSION_MINOR; unsigned int const xmlrpc_server_version_point = XMLRPC_VERSION_POINT; void xmlrpc_server_version(unsigned int * const majorP, unsigned int * const minorP, unsigned int * const pointP) { *majorP = XMLRPC_VERSION_MAJOR; *minorP = XMLRPC_VERSION_MINOR; *pointP = XMLRPC_VERSION_POINT; } xmlrpc_registry * xmlrpc_registry_new(xmlrpc_env * const envP) { xmlrpc_registry * registryP; XMLRPC_ASSERT_ENV_OK(envP); MALLOCVAR(registryP); if (registryP == NULL) xmlrpc_faultf(envP, "Could not allocate memory for registry"); else { registryP->introspectionEnabled = true; registryP->defaultMethodFunction = NULL; registryP->preinvokeFunction = NULL; registryP->shutdownServerFn = NULL; registryP->dialect = xmlrpc_dialect_i8; xmlrpc_methodListCreate(envP, ®istryP->methodListP); if (!envP->fault_occurred) xmlrpc_installSystemMethods(envP, registryP); if (envP->fault_occurred) free(registryP); } return registryP; } void xmlrpc_registry_free(xmlrpc_registry * const registryP) { XMLRPC_ASSERT_PTR_OK(registryP); xmlrpc_methodListDestroy(registryP->methodListP); free(registryP); } static void registryAddMethod(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const methodName, xmlrpc_method1 method1, xmlrpc_method2 method2, const char * const signatureString, const char * const help, void * const userData, size_t const stackSize) { const char * const helpString = help ? help : "No help is available for this method."; xmlrpc_methodInfo * methodP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(registryP); XMLRPC_ASSERT_PTR_OK(methodName); XMLRPC_ASSERT(method1 != NULL || method2 != NULL); xmlrpc_methodCreate(envP, method1, method2, userData, signatureString, helpString, stackSize, &methodP); if (!envP->fault_occurred) { xmlrpc_methodListAdd(envP, registryP->methodListP, methodName, methodP); if (envP->fault_occurred) xmlrpc_methodDestroy(methodP); } } void xmlrpc_registry_add_method_w_doc( xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const host ATTR_UNUSED, const char * const methodName, xmlrpc_method1 const method, void * const serverInfo, const char * const signatureString, const char * const help) { XMLRPC_ASSERT(host == NULL); registryAddMethod(envP, registryP, methodName, method, NULL, signatureString, help, serverInfo, 0); } void xmlrpc_registry_add_method(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const host, const char * const methodName, xmlrpc_method1 const method, void * const serverInfoP) { xmlrpc_registry_add_method_w_doc( envP, registryP, host, methodName, method, serverInfoP, "?", "No help is available for this method."); } void xmlrpc_registry_add_method2(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const methodName, xmlrpc_method2 method, const char * const signatureString, const char * const help, void * const serverInfo) { registryAddMethod(envP, registryP, methodName, NULL, method, signatureString, help, serverInfo, 0); } void xmlrpc_registry_add_method3( xmlrpc_env * const envP, xmlrpc_registry * const registryP, const struct xmlrpc_method_info3 * const infoP) { registryAddMethod(envP, registryP, infoP->methodName, NULL, infoP->methodFunction, infoP->signatureString, infoP->help, infoP->serverInfo, infoP->stackSize); } void xmlrpc_registry_set_default_method( xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_registry * const registryP ATTR_UNUSED, xmlrpc_default_method const function, void * const userData) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(registryP); XMLRPC_ASSERT_PTR_OK(function); /* Note: this may be the first default method, or it may be a replacement of the current one. */ registryP->defaultMethodFunction = function; registryP->defaultMethodUserData = userData; } /* This is our guess at what a method function requires when the user doesn't say. */ #define METHOD_FUNCTION_STACK 128*1024 static size_t methodStackSize(const xmlrpc_methodInfo * const methodP) { return methodP->stackSize == 0 ? METHOD_FUNCTION_STACK : methodP->stackSize; } size_t xmlrpc_registry_max_stackSize(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Return the maximum amount of stack required by the methods in registry *registryP. If there are no methods, return 0. -----------------------------------------------------------------------------*/ xmlrpc_methodNode * p; size_t stackSize; for (p = registryP->methodListP->firstMethodP, stackSize = 0; p; p = p->nextP) { stackSize = MAX(stackSize, methodStackSize(p->methodP)); } return stackSize; } void xmlrpc_registry_set_preinvoke_method( xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_registry * const registryP ATTR_UNUSED, xmlrpc_preinvoke_method const function, void * const userData) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(registryP); XMLRPC_ASSERT_PTR_OK(function); registryP->preinvokeFunction = function; registryP->preinvokeUserData = userData; } void xmlrpc_registry_set_shutdown(xmlrpc_registry * const registryP, xmlrpc_server_shutdown_fn * const shutdownFn, void * const context) { XMLRPC_ASSERT_PTR_OK(registryP); XMLRPC_ASSERT_PTR_OK(shutdownFn); registryP->shutdownServerFn = shutdownFn; registryP->shutdownContext = context; } void xmlrpc_registry_set_dialect(xmlrpc_env * const envP, xmlrpc_registry * const registryP, xmlrpc_dialect const dialect) { if (dialect != xmlrpc_dialect_i8 && dialect != xmlrpc_dialect_apache) xmlrpc_faultf(envP, "Invalid dialect argument -- not of type " "xmlrpc_dialect. Numerical value is %u", dialect); else registryP->dialect = dialect; } static void callNamedMethod(xmlrpc_env * const envP, xmlrpc_methodInfo * const methodP, xmlrpc_value * const paramArrayP, void * const callInfoP, xmlrpc_value ** const resultPP) { if (methodP->methodFnType2) *resultPP = methodP->methodFnType2(envP, paramArrayP, methodP->userData, callInfoP); else { assert(methodP->methodFnType1); *resultPP = methodP->methodFnType1(envP, paramArrayP, methodP->userData); } } void xmlrpc_dispatchCall(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const methodName, xmlrpc_value * const paramArrayP, void * const callInfoP, xmlrpc_value ** const resultPP) { if (registryP->preinvokeFunction) registryP->preinvokeFunction(envP, methodName, paramArrayP, registryP->preinvokeUserData); if (!envP->fault_occurred) { xmlrpc_methodInfo * methodP; xmlrpc_methodListLookupByName(registryP->methodListP, methodName, &methodP); if (methodP) callNamedMethod(envP, methodP, paramArrayP, callInfoP, resultPP); else { if (registryP->defaultMethodFunction) *resultPP = registryP->defaultMethodFunction( envP, callInfoP, methodName, paramArrayP, registryP->defaultMethodUserData); else { /* No matching method, and no default. */ xmlrpc_env_set_fault_formatted( envP, XMLRPC_NO_SUCH_METHOD_ERROR, "Method '%s' not defined", methodName); } } } /* For backward compatibility, for sloppy users: */ if (envP->fault_occurred) *resultPP = NULL; } /*========================================================================= ** xmlrpc_registry_process_call **========================================================================= ** */ static void serializeFault(xmlrpc_env * const envP, xmlrpc_env const fault, xmlrpc_mem_block * const responseXmlP) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_serialize_fault(&env, responseXmlP, &fault); if (env.fault_occurred) xmlrpc_faultf(envP, "Executed XML-RPC method completely and it " "generated a fault response, but we failed " "to encode that fault response as XML-RPC " "so we could send it to the client. %s", env.fault_string); xmlrpc_env_clean(&env); } void xmlrpc_registry_process_call2(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const callXml, size_t const callXmlLen, void * const callInfo, xmlrpc_mem_block ** const responseXmlPP) { xmlrpc_mem_block * responseXmlP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(callXml); xmlrpc_traceXml("XML-RPC CALL", callXml, callXmlLen); /* Allocate our output buffer. ** If this fails, we need to die in a special fashion. */ responseXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); if (!envP->fault_occurred) { const char * methodName; xmlrpc_value * paramArrayP; xmlrpc_env fault; xmlrpc_env parseEnv; xmlrpc_env_init(&fault); xmlrpc_env_init(&parseEnv); xmlrpc_parse_call(&parseEnv, callXml, callXmlLen, &methodName, ¶mArrayP); if (parseEnv.fault_occurred) xmlrpc_env_set_fault_formatted( &fault, XMLRPC_PARSE_ERROR, "Call XML not a proper XML-RPC call. %s", parseEnv.fault_string); else { xmlrpc_value * resultP; xmlrpc_dispatchCall(&fault, registryP, methodName, paramArrayP, callInfo, &resultP); if (!fault.fault_occurred) { xmlrpc_serialize_response2(envP, responseXmlP, resultP, registryP->dialect); xmlrpc_DECREF(resultP); } xmlrpc_strfree(methodName); xmlrpc_DECREF(paramArrayP); } if (!envP->fault_occurred && fault.fault_occurred) serializeFault(envP, fault, responseXmlP); xmlrpc_env_clean(&parseEnv); xmlrpc_env_clean(&fault); if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, responseXmlP); else { *responseXmlPP = responseXmlP; xmlrpc_traceXml("XML-RPC RESPONSE", XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlP), XMLRPC_MEMBLOCK_SIZE(char, responseXmlP)); } } } xmlrpc_mem_block * xmlrpc_registry_process_call(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const host ATTR_UNUSED, const char * const callXml, size_t const callXmlLen) { xmlrpc_mem_block * responseXmlP; xmlrpc_registry_process_call2(envP, registryP, callXml, callXmlLen, NULL, &responseXmlP); return responseXmlP; } /* Copyright (C) 2001 by First Peer, Inc. All rights reserved. ** Copyright (C) 2001 by Eric Kidd. All rights reserved. ** Copyright (C) 2001 by Luke Howard. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/registry.h000066400000000000000000000007631236133176700162370ustar00rootroot00000000000000#ifndef REGISTRY_H_INCLUDED #define REGISTRY_H_INCLUDED #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" void xmlrpc_dispatchCall(struct _xmlrpc_env * const envP, struct xmlrpc_registry * const registryP, const char * const methodName, struct _xmlrpc_value * const paramArrayP, void * const callInfoP, struct _xmlrpc_value ** const resultPP); #endif xmlrpc-c-1.33.14/src/resource.c000066400000000000000000000012711236133176700162040ustar00rootroot00000000000000#include "xmlrpc_config.h" #include "xmlrpc-c/base.h" /*========================================================================= ** Resource Limits **========================================================================= */ static size_t limits[XMLRPC_LAST_LIMIT_ID + 1] = { XMLRPC_NESTING_LIMIT_DEFAULT, XMLRPC_XML_SIZE_LIMIT_DEFAULT }; void xmlrpc_limit_set (int const limit_id, size_t const value) { XMLRPC_ASSERT(0 <= limit_id && limit_id <= XMLRPC_LAST_LIMIT_ID); limits[limit_id] = value; } size_t xmlrpc_limit_get(int const limit_id) { XMLRPC_ASSERT(0 <= limit_id && limit_id <= XMLRPC_LAST_LIMIT_ID); return limits[limit_id]; } xmlrpc-c-1.33.14/src/system_method.c000066400000000000000000000661551236133176700172550ustar00rootroot00000000000000/* Copyright information is at end of file */ #include "xmlrpc_config.h" #include #include #include #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "version.h" #include "registry.h" #include "method.h" #include "system_method.h" struct systemMethodReg { /*---------------------------------------------------------------------------- Information needed to register a system method -----------------------------------------------------------------------------*/ const char * const methodName; xmlrpc_method2 const methodFunction; const char * const signatureString; const char * const helpText; }; void xmlrpc_registry_disable_introspection(xmlrpc_registry * const registryP) { XMLRPC_ASSERT_PTR_OK(registryP); registryP->introspectionEnabled = false; } /*========================================================================= system.multicall =========================================================================*/ static void callOneMethod(xmlrpc_env * const envP, xmlrpc_registry * const registryP, xmlrpc_value * const rpcDescP, void * const callInfo, xmlrpc_value ** const resultPP) { const char * methodName; xmlrpc_value * paramArrayP; XMLRPC_ASSERT_ENV_OK(envP); if (xmlrpc_value_type(rpcDescP) != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "An element of the multicall array is type %u, but should " "be a struct (with members 'methodName' and 'params')", xmlrpc_value_type(rpcDescP)); else { xmlrpc_decompose_value(envP, rpcDescP, "{s:s,s:A,*}", "methodName", &methodName, "params", ¶mArrayP); if (!envP->fault_occurred) { /* Watch out for a deep recursion attack. */ if (xmlrpc_streq(methodName, "system.multicall")) xmlrpc_env_set_fault_formatted( envP, XMLRPC_REQUEST_REFUSED_ERROR, "Recursive system.multicall forbidden"); else { xmlrpc_env env; xmlrpc_value * resultValP; xmlrpc_env_init(&env); xmlrpc_dispatchCall(&env, registryP, methodName, paramArrayP, callInfo, &resultValP); if (env.fault_occurred) { /* Method failed, so result is a fault structure */ *resultPP = xmlrpc_build_value( envP, "{s:i,s:s}", "faultCode", (xmlrpc_int32) env.fault_code, "faultString", env.fault_string); } else { *resultPP = xmlrpc_build_value(envP, "(V)", resultValP); xmlrpc_DECREF(resultValP); } xmlrpc_env_clean(&env); } xmlrpc_DECREF(paramArrayP); xmlrpc_strfree(methodName); } } } static void getMethListFromMulticallPlist(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, xmlrpc_value ** const methlistPP) { if (xmlrpc_array_size(envP, paramArrayP) != 1) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "system.multicall takes one parameter, which is an " "array, each element describing one RPC. You " "supplied %u arguments", xmlrpc_array_size(envP, paramArrayP)); else { xmlrpc_value * methlistP; xmlrpc_array_read_item(envP, paramArrayP, 0, &methlistP); XMLRPC_ASSERT_ENV_OK(envP); if (xmlrpc_value_type(methlistP) != XMLRPC_TYPE_ARRAY) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "system.multicall's parameter should be an array, " "each element describing one RPC. But it is type " "%u instead.", xmlrpc_value_type(methlistP)); else *methlistPP = methlistP; if (envP->fault_occurred) xmlrpc_DECREF(methlistP); } } static xmlrpc_value * system_multicall(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo) { xmlrpc_registry * registryP; xmlrpc_value * resultsP; xmlrpc_value * methlistP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_ARRAY_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(serverInfo); resultsP = NULL; /* defeat compiler warning */ /* Turn our arguments into something more useful. */ registryP = (xmlrpc_registry*) serverInfo; getMethListFromMulticallPlist(envP, paramArrayP, &methlistP); if (!envP->fault_occurred) { /* Create an initially empty result list. */ resultsP = xmlrpc_array_new(envP); if (!envP->fault_occurred) { /* Loop over our input list, calling each method in turn. */ unsigned int const methodCount = xmlrpc_array_size(envP, methlistP); unsigned int i; for (i = 0; i < methodCount && !envP->fault_occurred; ++i) { xmlrpc_value * const methinfoP = xmlrpc_array_get_item(envP, methlistP, i); xmlrpc_value * resultP; XMLRPC_ASSERT_ENV_OK(envP); callOneMethod(envP, registryP, methinfoP, callInfo, &resultP); if (!envP->fault_occurred) { /* Append this method result to our master array. */ xmlrpc_array_append_item(envP, resultsP, resultP); xmlrpc_DECREF(resultP); } } if (envP->fault_occurred) xmlrpc_DECREF(resultsP); xmlrpc_DECREF(methlistP); } } return resultsP; } static struct systemMethodReg const methodMulticall = { "system.multicall", &system_multicall, "A:A", "Process an array of calls, and return an array of results. Calls should " "be structs of the form {'methodName': string, 'params': array}. Each " "result will either be a single-item array containg the result value, or " "a struct of the form {'faultCode': int, 'faultString': string}. This " "is useful when you need to make lots of small calls without lots of " "round trips.", }; /*========================================================================= system.listMethods =========================================================================*/ static void createMethodListArray(xmlrpc_env * const envP, xmlrpc_registry * const registryP, xmlrpc_value ** const methodListPP) { /*---------------------------------------------------------------------------- Create as an XML-RPC array value a list of names of methods registered in registry 'registryP'. This is the type of value that the system.listMethods method is supposed to return. -----------------------------------------------------------------------------*/ xmlrpc_value * methodListP; methodListP = xmlrpc_array_new(envP); if (!envP->fault_occurred) { xmlrpc_methodNode * methodNodeP; for (methodNodeP = registryP->methodListP->firstMethodP; methodNodeP && !envP->fault_occurred; methodNodeP = methodNodeP->nextP) { xmlrpc_value * methodNameVP; methodNameVP = xmlrpc_string_new(envP, methodNodeP->methodName); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, methodListP, methodNameVP); xmlrpc_DECREF(methodNameVP); } } if (envP->fault_occurred) xmlrpc_DECREF(methodListP); } *methodListPP = methodListP; } static xmlrpc_value * system_listMethods(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo ATTR_UNUSED) { xmlrpc_registry * const registryP = serverInfo; xmlrpc_value * retvalP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(serverInfo); xmlrpc_decompose_value(envP, paramArrayP, "()"); if (!envP->fault_occurred) { if (!registryP->introspectionEnabled) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTROSPECTION_DISABLED_ERROR, "Introspection is disabled in this server " "for security reasons"); else createMethodListArray(envP, registryP, &retvalP); } return retvalP; } static struct systemMethodReg const methodListMethods = { "system.listMethods", &system_listMethods, "A:", "Return an array of all available XML-RPC methods on this server.", }; /*========================================================================= system.methodExist ==========================================================================*/ static void determineMethodExistence(xmlrpc_env * const envP, const char * const methodName, xmlrpc_registry * const registryP, xmlrpc_value ** const existsPP) { xmlrpc_methodInfo * methodP; xmlrpc_methodListLookupByName(registryP->methodListP, methodName, &methodP); *existsPP = xmlrpc_bool_new(envP, !!methodP); } static xmlrpc_value * system_methodExist(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo ATTR_UNUSED) { xmlrpc_registry * const registryP = serverInfo; xmlrpc_value * retvalP; const char * methodName; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(serverInfo); xmlrpc_decompose_value(envP, paramArrayP, "(s)", &methodName); if (!envP->fault_occurred) { determineMethodExistence(envP, methodName, registryP, &retvalP); xmlrpc_strfree(methodName); } return retvalP; } static struct systemMethodReg const methodMethodExist = { "system.methodExist", &system_methodExist, "s:b", "Tell whether a method by a specified name exists on this server", }; /*========================================================================= system.methodHelp =========================================================================*/ static void getHelpString(xmlrpc_env * const envP, const char * const methodName, xmlrpc_registry * const registryP, xmlrpc_value ** const helpStringPP) { xmlrpc_methodInfo * methodP; xmlrpc_methodListLookupByName(registryP->methodListP, methodName, &methodP); if (!methodP) xmlrpc_env_set_fault_formatted( envP, XMLRPC_NO_SUCH_METHOD_ERROR, "Method '%s' does not exist", methodName); else *helpStringPP = xmlrpc_string_new(envP, methodP->helpText); } static xmlrpc_value * system_methodHelp(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo ATTR_UNUSED) { xmlrpc_registry * const registryP = serverInfo; xmlrpc_value * retvalP; const char * methodName; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(serverInfo); xmlrpc_decompose_value(envP, paramArrayP, "(s)", &methodName); if (!envP->fault_occurred) { if (!registryP->introspectionEnabled) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTROSPECTION_DISABLED_ERROR, "Introspection is disabled in this server " "for security reasons"); else getHelpString(envP, methodName, registryP, &retvalP); xmlrpc_strfree(methodName); } return retvalP; } static struct systemMethodReg const methodMethodHelp = { "system.methodHelp", &system_methodHelp, "s:s", "Given the name of a method, return a help string.", }; /*========================================================================= system.methodSignature ==========================================================================*/ static void buildNoSigSuppliedResult(xmlrpc_env * const envP, xmlrpc_value ** const resultPP) { xmlrpc_env env; xmlrpc_env_init(&env); *resultPP = xmlrpc_string_new(&env, "undef"); if (env.fault_occurred) xmlrpc_faultf(envP, "Unable to construct 'undef'. %s", env.fault_string); xmlrpc_env_clean(&env); } static void buildSignatureValue(xmlrpc_env * const envP, struct xmlrpc_signature * const signatureP, xmlrpc_value ** const sigValuePP) { xmlrpc_value * sigValueP; unsigned int i; sigValueP = xmlrpc_array_new(envP); { xmlrpc_value * retTypeVP; retTypeVP = xmlrpc_string_new(envP, signatureP->retType); xmlrpc_array_append_item(envP, sigValueP, retTypeVP); xmlrpc_DECREF(retTypeVP); } for (i = 0; i < signatureP->argCount && !envP->fault_occurred; ++i) { xmlrpc_value * argTypeVP; argTypeVP = xmlrpc_string_new(envP, signatureP->argList[i]); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, sigValueP, argTypeVP); xmlrpc_DECREF(argTypeVP); } } if (envP->fault_occurred) xmlrpc_DECREF(sigValueP); *sigValuePP = sigValueP; } static void getSignatureList(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const methodName, xmlrpc_value ** const signatureListPP) { /*---------------------------------------------------------------------------- Get the signature list array for method named 'methodName' from registry 'registryP'. If there is no signature information for the method in the registry, return *signatureListPP == NULL. Nonexistent method is considered a failure. -----------------------------------------------------------------------------*/ xmlrpc_methodInfo * methodP; xmlrpc_methodListLookupByName(registryP->methodListP, methodName, &methodP); if (!methodP) xmlrpc_env_set_fault_formatted( envP, XMLRPC_NO_SUCH_METHOD_ERROR, "Method '%s' does not exist", methodName); else { if (!methodP->signatureListP->firstSignatureP) *signatureListPP = NULL; else { xmlrpc_value * signatureListP; signatureListP = xmlrpc_array_new(envP); if (!envP->fault_occurred) { struct xmlrpc_signature * signatureP; for (signatureP = methodP->signatureListP->firstSignatureP; signatureP && !envP->fault_occurred; signatureP = signatureP->nextP) { xmlrpc_value * signatureVP; buildSignatureValue(envP, signatureP, &signatureVP); xmlrpc_array_append_item(envP, signatureListP, signatureVP); xmlrpc_DECREF(signatureVP); } if (envP->fault_occurred) xmlrpc_DECREF(signatureListP); } *signatureListPP = signatureListP; } } } /* Microsoft Visual C in debug mode produces code that complains about returning an undefined value from system_methodSignature(). It's a bogus complaint, because this function is defined to return nothing meaningful those cases. So we disable the check. */ #pragma runtime_checks("u", off) static xmlrpc_value * system_methodSignature(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo ATTR_UNUSED) { xmlrpc_registry * const registryP = (xmlrpc_registry *) serverInfo; xmlrpc_value * retvalP; const char * methodName; xmlrpc_env env; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(serverInfo); xmlrpc_env_init(&env); /* Turn our arguments into something more useful. */ xmlrpc_decompose_value(&env, paramArrayP, "(s)", &methodName); if (env.fault_occurred) xmlrpc_env_set_fault_formatted( envP, env.fault_code, "Invalid parameter list. %s", env.fault_string); else { if (!registryP->introspectionEnabled) xmlrpc_env_set_fault(envP, XMLRPC_INTROSPECTION_DISABLED_ERROR, "Introspection disabled on this server"); else { xmlrpc_value * signatureListP; getSignatureList(envP, registryP, methodName, &signatureListP); if (!envP->fault_occurred) { if (signatureListP) retvalP = signatureListP; else buildNoSigSuppliedResult(envP, &retvalP); } } xmlrpc_strfree(methodName); } xmlrpc_env_clean(&env); return retvalP; } #pragma runtime_checks("u", restore) static struct systemMethodReg const methodMethodSignature = { "system.methodSignature", &system_methodSignature, "A:s", "Given the name of a method, return an array of legal signatures. " "Each signature is an array of strings. The first item of each signature " "is the return type, and any others items are parameter types.", }; /*========================================================================= system.shutdown ==========================================================================*/ static xmlrpc_value * system_shutdown(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo) { xmlrpc_registry * const registryP = (xmlrpc_registry *) serverInfo; xmlrpc_value * retvalP; const char * comment; xmlrpc_env env; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(serverInfo); xmlrpc_env_init(&env); /* Turn our arguments into something more useful. */ xmlrpc_decompose_value(&env, paramArrayP, "(s)", &comment); if (env.fault_occurred) xmlrpc_env_set_fault_formatted( envP, env.fault_code, "Invalid parameter list. %s", env.fault_string); else { if (!registryP->shutdownServerFn) xmlrpc_env_set_fault( envP, 0, "This server program is not capable of " "shutting down"); else { registryP->shutdownServerFn( &env, registryP->shutdownContext, comment, callInfo); if (env.fault_occurred) xmlrpc_env_set_fault(envP, env.fault_code, env.fault_string); else { retvalP = xmlrpc_int_new(&env, 0); if (env.fault_occurred) xmlrpc_faultf(envP, "Failed to construct return value. %s", env.fault_string); } } xmlrpc_strfree(comment); } xmlrpc_env_clean(&env); return retvalP; } static struct systemMethodReg const methodShutdown = { "system.shutdown", &system_shutdown, "i:s", "Shut down the server. Return code is always zero.", }; /*========================================================================= system.capabilities =========================================================================*/ static void constructCapabilities(xmlrpc_env * const envP, xmlrpc_registry * const registryP ATTR_UNUSED, xmlrpc_value ** const capabilitiesPP) { *capabilitiesPP = xmlrpc_build_value( envP, "{s:s,s:i,s:i,s:i,s:i}", "facility", "xmlrpc-c", "version_major", XMLRPC_VERSION_MAJOR, "version_minor", XMLRPC_VERSION_MINOR, "version_point", XMLRPC_VERSION_POINT, "protocol_version", 2 ); } static xmlrpc_value * system_capabilities(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo ATTR_UNUSED) { xmlrpc_registry * const registryP = serverInfo; xmlrpc_value * retvalP; unsigned int paramCount; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(serverInfo); paramCount = xmlrpc_array_size(envP, paramArrayP); if (paramCount > 0) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "There are no parameters. You supplied %u", paramCount); else constructCapabilities(envP, registryP, &retvalP); return retvalP; } static struct systemMethodReg const methodCapabilities = { "system.capabilities", &system_capabilities, "S:", "Return the capabilities of XML-RPC server. This includes the " "version number of the XML-RPC For C/C++ software" }; /*========================================================================= system.getCapabilities =========================================================================*/ /* This implements a standard. See http://tech.groups.yahoo.com/group/xml-rpc/message/2897 . */ static void listCapabilities(xmlrpc_env * const envP, xmlrpc_registry * const registryP ATTR_UNUSED, xmlrpc_value ** const capabilitiesPP) { *capabilitiesPP = xmlrpc_build_value( envP, "{s:{s:s,s:i}}", "introspect", "specUrl", "http://xmlrpc-c.sourceforge.net/xmlrpc-c/introspection.html", "specVersion", 1 ); } static xmlrpc_value * system_getCapabilities(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo ATTR_UNUSED) { xmlrpc_registry * const registryP = serverInfo; xmlrpc_value * retvalP; unsigned int paramCount; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(serverInfo); paramCount = xmlrpc_array_size(envP, paramArrayP); if (paramCount > 0) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "There are no parameters. You supplied %u", paramCount); else listCapabilities(envP, registryP, &retvalP); return retvalP; } static struct systemMethodReg const methodGetCapabilities = { "system.getCapabilities", &system_getCapabilities, "S:", "Return the list of standard capabilities of XML-RPC server. " "See http://tech.groups.yahoo.com/group/xml-rpc/message/2897" }; /*============================================================================ Installer of system methods ============================================================================*/ static void registerSystemMethod(xmlrpc_env * const envP, xmlrpc_registry * const registryP, struct systemMethodReg const methodReg) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_registry_add_method2( &env, registryP, methodReg.methodName, methodReg.methodFunction, methodReg.signatureString, methodReg.helpText, registryP); if (env.fault_occurred) xmlrpc_faultf(envP, "Failed to register '%s' system method. %s", methodReg.methodName, env.fault_string); xmlrpc_env_clean(&env); } void xmlrpc_installSystemMethods(xmlrpc_env * const envP, xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Install the built-in methods (system.*) into registry 'registryP'. -----------------------------------------------------------------------------*/ if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodListMethods); if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodMethodExist); if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodMethodHelp); if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodMethodSignature); if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodMulticall); if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodShutdown); if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodCapabilities); if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodGetCapabilities); } /* Copyright (C) 2001 by First Peer, Inc. All rights reserved. ** Copyright (C) 2001 by Eric Kidd. All rights reserved. ** Copyright (C) 2001 by Luke Howard. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/system_method.h000066400000000000000000000006221236133176700172450ustar00rootroot00000000000000#ifndef SYSTEM_METHOD_H_INCLUDED #define SYSTEM_METHOD_H_INCLUDED void xmlrpc_installSystemMethods(struct _xmlrpc_env * const envP, struct xmlrpc_registry * const registryP); void xmlrpc_buildSignatureArray(xmlrpc_env * const envP, const char * const sigListString, xmlrpc_value ** const resultPP); #endif xmlrpc-c-1.33.14/src/trace.c000066400000000000000000000032761236133176700154620ustar00rootroot00000000000000#include #include #include #include #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" static size_t nextLineSize(const char * const string, size_t const startPos, size_t const stringSize) { /*---------------------------------------------------------------------------- Return the length of the line that starts at offset 'startPos' in the string 'string', which is 'stringSize' characters long. 'string' in not NUL-terminated. A line begins at beginning of string or after a newline character and runs through the next newline character or end of string. The line includes the newline character at the end, if any. -----------------------------------------------------------------------------*/ size_t i; for (i = startPos; i < stringSize && string[i] != '\n'; ++i); if (i < stringSize) ++i; /* Include the newline */ return i - startPos; } void xmlrpc_traceXml(const char * const label, const char * const xml, size_t const xmlLength) { if (getenv("XMLRPC_TRACE_XML")) { size_t cursor; /* Index into xml[] */ fprintf(stderr, "%s:\n\n", label); for (cursor = 0; cursor < xmlLength; ) { /* Print one line of XML */ size_t const lineSize = nextLineSize(xml, cursor, xmlLength); const char * const xmlPrintableLine = xmlrpc_makePrintable_lp(&xml[cursor], lineSize); fprintf(stderr, "%s\n", xmlPrintableLine); cursor += lineSize; xmlrpc_strfree(xmlPrintableLine); } fprintf(stderr, "\n"); } } xmlrpc-c-1.33.14/src/version.c000066400000000000000000000007561236133176700160510ustar00rootroot00000000000000#include "version.h" #include "xmlrpc-c/base.h" unsigned int const xmlrpc_version_major = XMLRPC_VERSION_MAJOR; unsigned int const xmlrpc_version_minor = XMLRPC_VERSION_MINOR; unsigned int const xmlrpc_version_point = XMLRPC_VERSION_POINT; void xmlrpc_version(unsigned int * const majorP, unsigned int * const minorP, unsigned int * const pointP) { *majorP = XMLRPC_VERSION_MAJOR; *minorP = XMLRPC_VERSION_MINOR; *pointP = XMLRPC_VERSION_POINT; } xmlrpc-c-1.33.14/src/xmlrpc_array.c000066400000000000000000000161671236133176700170720ustar00rootroot00000000000000/* Copyright information is at the end of the file */ /*========================================================================= ** XML-RPC Array Functions **========================================================================= */ #include "xmlrpc_config.h" #include #include #include #include "xmlrpc-c/util.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" void xmlrpc_abort_if_array_bad(xmlrpc_value * const arrayP) { if (arrayP == NULL) abort(); else if (arrayP->_type != XMLRPC_TYPE_ARRAY) abort(); else { size_t const arraySize = XMLRPC_MEMBLOCK_SIZE(xmlrpc_value*, &arrayP->_block); xmlrpc_value ** const contents = XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value*, &arrayP->_block); if (contents == NULL) abort(); else { size_t index; for (index = 0; index < arraySize; ++index) { xmlrpc_value * const itemP = contents[index]; if (itemP == NULL) abort(); else if (itemP->refcount < 1) abort(); } } } } void xmlrpc_destroyArrayContents(xmlrpc_value * const arrayP) { /*---------------------------------------------------------------------------- Dispose of the contents of an array (but not the array value itself). The value is not valid after this. -----------------------------------------------------------------------------*/ size_t const arraySize = XMLRPC_MEMBLOCK_SIZE(xmlrpc_value*, &arrayP->_block); xmlrpc_value ** const contents = XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value*, &arrayP->_block); size_t index; XMLRPC_ASSERT_ARRAY_OK(arrayP); /* Release our reference to each item in the array */ for (index = 0; index < arraySize; ++index) { xmlrpc_value * const itemP = contents[index]; xmlrpc_DECREF(itemP); } XMLRPC_MEMBLOCK_CLEAN(xmlrpc_value *, &arrayP->_block); } int xmlrpc_array_size(xmlrpc_env * const envP, const xmlrpc_value * const arrayP) { int retval; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(arrayP); if (arrayP->_type != XMLRPC_TYPE_ARRAY) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value is not an array"); retval = -1; } else { size_t const size = XMLRPC_MEMBLOCK_SIZE(xmlrpc_value *, &arrayP->_block); assert((size_t)(int)(size) == size); retval = (int)size; } return retval; } void xmlrpc_array_append_item(xmlrpc_env * const envP, xmlrpc_value * const arrayP, xmlrpc_value * const valueP) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(arrayP); if (xmlrpc_value_type(arrayP) != XMLRPC_TYPE_ARRAY) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value is not an array"); else { size_t const size = XMLRPC_MEMBLOCK_SIZE(xmlrpc_value *, &arrayP->_block); XMLRPC_MEMBLOCK_RESIZE(xmlrpc_value *, envP, &arrayP->_block, size+1); if (!envP->fault_occurred) { xmlrpc_value ** const contents = XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value*, &arrayP->_block); xmlrpc_INCREF(valueP); contents[size] = valueP; } } } void xmlrpc_array_read_item(xmlrpc_env * const envP, const xmlrpc_value * const arrayP, unsigned int const index, xmlrpc_value ** const valuePP) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(arrayP); XMLRPC_ASSERT_PTR_OK(valuePP); if (arrayP->_type != XMLRPC_TYPE_ARRAY) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Attempt to read array item from " "a value that is not an array"); else { xmlrpc_value ** const contents = XMLRPC_MEMBLOCK_CONTENTS(xmlrpc_value *, &arrayP->_block); size_t const size = XMLRPC_MEMBLOCK_SIZE(xmlrpc_value *, &arrayP->_block); if (index >= size) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "Array index %u is beyond end " "of %u-item array", index, (unsigned int)size); else { *valuePP = contents[index]; xmlrpc_INCREF(*valuePP); } } } xmlrpc_value * xmlrpc_array_get_item(xmlrpc_env * const envP, const xmlrpc_value * const arrayP, int const index) { xmlrpc_value * valueP; if (index < 0) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "Index %d is negative.", index); else { xmlrpc_array_read_item(envP, arrayP, index, &valueP); if (!envP->fault_occurred) xmlrpc_DECREF(valueP); } if (envP->fault_occurred) valueP = NULL; return valueP; } xmlrpc_value * xmlrpc_array_new(xmlrpc_env * const envP) { /*---------------------------------------------------------------------------- Create an empty array xmlrpc_value. -----------------------------------------------------------------------------*/ xmlrpc_value * arrayP; xmlrpc_createXmlrpcValue(envP, &arrayP); if (!envP->fault_occurred) { arrayP->_type = XMLRPC_TYPE_ARRAY; XMLRPC_MEMBLOCK_INIT(xmlrpc_value*, envP, &arrayP->_block, 0); if (envP->fault_occurred) free(arrayP); } return arrayP; } /* Copyright (C) 2001 by First Peer, Inc. All rights reserved. ** Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/xmlrpc_authcookie.c000066400000000000000000000062201236133176700200740ustar00rootroot00000000000000/* Copyright (C) 2002 by jeff@ourexchange.net. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include "xmlrpc_config.h" #include #include #include #include "mallocvar.h" #include "xmlrpc-c/base.h" /***************************************************************************** I don't see how these were expected to be used. And I probably broke it somehow at some point by removing code from somewhere else. But I doubt that, whatever it's supposed to do, environment variables are the right tool. Note that on a platform that doesn't have SETENV, xmlrpc_authcookie_set() is just a no-op. -Bryan 2005.06.10 ****************************************************************************/ void xmlrpc_authcookie_set(xmlrpc_env * const envP, const char * const username, const char * const password) { char * unencoded; xmlrpc_mem_block * token; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(username); XMLRPC_ASSERT_PTR_OK(password); /* Create unencoded string/hash. */ MALLOCARRAY(unencoded,(strlen(username) + strlen(password) + 1 + 1)); sprintf(unencoded, "%s:%s", username, password); /* Create encoded string. */ token = xmlrpc_base64_encode_without_newlines( envP, (unsigned char *)unencoded, strlen(unencoded)); if (!envP->fault_occurred) { /* Set HTTP_COOKIE_AUTH to the character representation of the encoded string. */ #if HAVE_SETENV setenv("HTTP_COOKIE_AUTH", XMLRPC_MEMBLOCK_CONTENTS(char, token), 1); #endif xmlrpc_mem_block_free(token); } free(unencoded); } char *xmlrpc_authcookie ( void ) { return getenv("HTTP_COOKIE_AUTH"); } xmlrpc-c-1.33.14/src/xmlrpc_build.c000066400000000000000000000303671236133176700170510ustar00rootroot00000000000000/* Copyright information is at end of file */ #include "xmlrpc_config.h" #include #include #include #include #include "bool.h" #include "c_util.h" #include "mallocvar.h" #include "stdargx.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" static void getString(xmlrpc_env * const envP, const char ** const formatP, va_listx * const argsP, xmlrpc_value ** const valPP) { const char * str; size_t len; str = (const char*) va_arg(argsP->v, char*); if (*(*formatP) == '#') { ++(*formatP); len = (size_t) va_arg(argsP->v, size_t); } else len = strlen(str); *valPP = xmlrpc_string_new_lp(envP, len, str); } static void getWideString(xmlrpc_env * const envP ATTR_UNUSED, const char ** const formatP ATTR_UNUSED, va_listx * const argsP ATTR_UNUSED, xmlrpc_value ** const valPP ATTR_UNUSED) { #if HAVE_UNICODE_WCHAR wchar_t *wcs; size_t len; wcs = (wchar_t*) va_arg(argsP->v, wchar_t*); if (**formatP == '#') { (*formatP)++; len = (size_t) va_arg(argsP->v, size_t); } else len = wcslen(wcs); *valPP = xmlrpc_string_w_new_lp(envP, len, wcs); #endif /* HAVE_UNICODE_WCHAR */ } static void getBase64(xmlrpc_env * const envP, va_listx * const argsP, xmlrpc_value ** const valPP) { unsigned char * value; size_t length; value = (unsigned char*) va_arg(argsP->v, unsigned char*); length = (size_t) va_arg(argsP->v, size_t); *valPP = xmlrpc_base64_new(envP, length, value); } static void getValue(xmlrpc_env * const envP, const char** const format, va_listx * const argsP, xmlrpc_value ** const valPP); static void getArray(xmlrpc_env * const envP, const char ** const formatP, char const delimiter, va_listx * const argsP, xmlrpc_value ** const arrayPP) { xmlrpc_value * arrayP; arrayP = xmlrpc_array_new(envP); /* Add items to the array until we hit our delimiter. */ while (**formatP != delimiter && !envP->fault_occurred) { xmlrpc_value * itemP; if (**formatP == '\0') xmlrpc_env_set_fault( envP, XMLRPC_INTERNAL_ERROR, "format string ended before closing ')'."); else { getValue(envP, formatP, argsP, &itemP); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, arrayP, itemP); xmlrpc_DECREF(itemP); } } } if (envP->fault_occurred) xmlrpc_DECREF(arrayP); *arrayPP = arrayP; } static void getStructMember(xmlrpc_env * const envP, const char ** const formatP, va_listx * const argsP, xmlrpc_value ** const keyPP, xmlrpc_value ** const valuePP) { /* Get the key */ getValue(envP, formatP, argsP, keyPP); if (!envP->fault_occurred) { if (**formatP != ':') xmlrpc_env_set_fault( envP, XMLRPC_INTERNAL_ERROR, "format string does not have ':' after a " "structure member key."); else { /* Skip over colon that separates key from value */ (*formatP)++; /* Get the value */ getValue(envP, formatP, argsP, valuePP); } if (envP->fault_occurred) xmlrpc_DECREF(*keyPP); } } static void getStruct(xmlrpc_env * const envP, const char ** const formatP, char const delimiter, va_listx * const argsP, xmlrpc_value ** const structPP) { xmlrpc_value * structP; structP = xmlrpc_struct_new(envP); if (!envP->fault_occurred) { while (**formatP != delimiter && !envP->fault_occurred) { xmlrpc_value * keyP; xmlrpc_value * valueP; getStructMember(envP, formatP, argsP, &keyP, &valueP); if (!envP->fault_occurred) { if (**formatP == ',') (*formatP)++; /* Skip over the comma */ else if (**formatP == delimiter) { /* End of the line */ } else xmlrpc_env_set_fault( envP, XMLRPC_INTERNAL_ERROR, "format string does not have ',' or ')' after " "a structure member"); if (!envP->fault_occurred) /* Add the new member to the struct. */ xmlrpc_struct_set_value_v(envP, structP, keyP, valueP); xmlrpc_DECREF(valueP); xmlrpc_DECREF(keyP); } } if (envP->fault_occurred) xmlrpc_DECREF(structP); } *structPP = structP; } static void mkArrayFromVal(xmlrpc_env * const envP, xmlrpc_value * const value, xmlrpc_value ** const valPP) { if (xmlrpc_value_type(value) != XMLRPC_TYPE_ARRAY) xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, "Array format ('A'), non-array xmlrpc_value"); else xmlrpc_INCREF(value); *valPP = value; } static void mkStructFromVal(xmlrpc_env * const envP, xmlrpc_value * const value, xmlrpc_value ** const valPP) { if (xmlrpc_value_type(value) != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, "Struct format ('S'), non-struct xmlrpc_value"); else xmlrpc_INCREF(value); *valPP = value; } static void getValue(xmlrpc_env * const envP, const char** const formatP, va_listx * const argsP, xmlrpc_value ** const valPP) { /*---------------------------------------------------------------------------- Get the next value from the list. *formatP points to the specifier for the next value in the format string (i.e. to the type code character) and we move *formatP past the whole specifier for the next value. We read the required arguments from 'argsP'. We return the value as *valPP with a reference to it. For example, if *formatP points to the "i" in the string "sis", we read one argument from 'argsP' and return as *valP an integer whose value is the argument we read. We advance *formatP to point to the last 's' and advance 'argsP' to point to the argument that belongs to that 's'. -----------------------------------------------------------------------------*/ char const formatChar = *(*formatP)++; switch (formatChar) { case 'i': *valPP = xmlrpc_int_new(envP, (xmlrpc_int32) va_arg(argsP->v, xmlrpc_int32)); break; case 'b': *valPP = xmlrpc_bool_new(envP, (xmlrpc_bool) va_arg(argsP->v, xmlrpc_bool)); break; case 'd': *valPP = xmlrpc_double_new(envP, (double) va_arg(argsP->v, double)); break; case 's': getString(envP, formatP, argsP, valPP); break; case 'w': getWideString(envP, formatP, argsP, valPP); break; case 't': *valPP = xmlrpc_datetime_new_sec(envP, va_arg(argsP->v, time_t)); break; case '8': *valPP = xmlrpc_datetime_new_str(envP, va_arg(argsP->v, char*)); break; case '6': getBase64(envP, argsP, valPP); break; case 'n': *valPP = xmlrpc_nil_new(envP); break; case 'I': *valPP = xmlrpc_i8_new(envP, (xmlrpc_int64) va_arg(argsP->v, xmlrpc_int64)); break; case 'p': *valPP = xmlrpc_cptr_new(envP, (void*) va_arg(argsP->v, void*)); break; case 'A': mkArrayFromVal(envP, (xmlrpc_value*) va_arg(argsP->v, xmlrpc_value*), valPP); break; case 'S': mkStructFromVal(envP, (xmlrpc_value*) va_arg(argsP->v, xmlrpc_value*), valPP); break; case 'V': *valPP = (xmlrpc_value*) va_arg(argsP->v, xmlrpc_value*); xmlrpc_INCREF(*valPP); break; case '(': getArray(envP, formatP, ')', argsP, valPP); if (!envP->fault_occurred) { XMLRPC_ASSERT(**formatP == ')'); (*formatP)++; /* Skip over closing parenthesis */ } break; case '{': getStruct(envP, formatP, '}', argsP, valPP); if (!envP->fault_occurred) { XMLRPC_ASSERT(**formatP == '}'); (*formatP)++; /* Skip over closing brace */ } break; default: { const char * const badCharacter = xmlrpc_makePrintableChar(formatChar); xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR, "Unexpected character '%s' in format string", badCharacter); xmlrpc_strfree(badCharacter); } } } void xmlrpc_build_value_va(xmlrpc_env * const envP, const char * const format, va_list const args, xmlrpc_value ** const valPP, const char ** const tailP) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(format != NULL); if (strlen(format) == 0) xmlrpc_faultf(envP, "Format string is empty."); else { va_listx currentArgs; const char * formatCursor; init_va_listx(¤tArgs, args); formatCursor = &format[0]; getValue(envP, &formatCursor, ¤tArgs, valPP); if (!envP->fault_occurred) XMLRPC_ASSERT_VALUE_OK(*valPP); *tailP = formatCursor; } } xmlrpc_value * xmlrpc_build_value(xmlrpc_env * const envP, const char * const format, ...) { va_list args; xmlrpc_value * retval; const char * suffix; va_start(args, format); xmlrpc_build_value_va(envP, format, args, &retval, &suffix); va_end(args); if (!envP->fault_occurred) { if (*suffix != '\0') xmlrpc_faultf(envP, "Junk after the format specifier: '%s'. " "The format string must describe exactly " "one XML-RPC value " "(but it might be a compound value " "such as an array)", suffix); if (envP->fault_occurred) xmlrpc_DECREF(retval); } return retval; } /* Copyright (C) 2001 by First Peer, Inc. All rights reserved. ** Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/xmlrpc_client.c000066400000000000000000001154451236133176700172310ustar00rootroot00000000000000/* Copyright information is at end of file */ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include "xmlrpc_config.h" #undef PACKAGE #undef VERSION #include #include #include #include #include #include #include #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/client_int.h" /* transport_config.h defines XMLRPC_DEFAULT_TRANSPORT, MUST_BUILD_WININET_CLIENT, MUST_BUILD_CURL_CLIENT, MUST_BUILD_LIBWWW_CLIENT */ #include "transport_config.h" #include "version.h" struct xmlrpc_client { /*---------------------------------------------------------------------------- This represents a client object. -----------------------------------------------------------------------------*/ bool myTransport; /* The transport described below was created by this object; No one else knows it exists and this object is responsible for destroying it. */ struct xmlrpc_client_transport * transportP; struct xmlrpc_client_transport_ops transportOps; xmlrpc_dialect dialect; xmlrpc_progress_fn * progressFn; }; struct xmlrpc_call_info { /* This is all the information needed to finish executing a started RPC. You don't need this for an RPC the user executes synchronously, because then you can just use the storage in which the user passed his arguments. But for asynchronous, the user will take back his storage, and we need to keep this info in our own. */ void * userHandle; /* This is a handle for this call that is meaningful to our user. */ xmlrpc_progress_fn * progressFn; struct { /* These are arguments to pass to the completion function. It doesn't make sense to use them for anything else. In fact, it really doesn't make sense for them to be arguments to the completion function, but they are historically. */ const char * serverUrl; const char * methodName; xmlrpc_value * paramArrayP; } completionArgs; xmlrpc_response_handler * completionFn; /* The serialized XML data passed to this call. We keep this around ** for use by our source_anchor field. */ xmlrpc_mem_block *serialized_xml; }; /*========================================================================= Global Constant Setup/Teardown =========================================================================*/ static void callTransportSetup(xmlrpc_env * const envP, xmlrpc_transport_setup setupFn) { if (setupFn) setupFn(envP); } int xmlrpc_trace_transport; static void setupTransportGlobalConst(xmlrpc_env * const envP) { xmlrpc_trace_transport = getenv("XMLRPC_TRACE_TRANSPORT") ? 1 : 0; #if MUST_BUILD_WININET_CLIENT if (!envP->fault_occurred) callTransportSetup(envP, xmlrpc_wininet_transport_ops.setup_global_const); #endif #if MUST_BUILD_CURL_CLIENT if (!envP->fault_occurred) callTransportSetup(envP, xmlrpc_curl_transport_ops.setup_global_const); #endif #if MUST_BUILD_LIBWWW_CLIENT if (!envP->fault_occurred) callTransportSetup(envP, xmlrpc_libwww_transport_ops.setup_global_const); #endif } static void callTransportTeardown(xmlrpc_transport_teardown teardownFn) { if (teardownFn) teardownFn(); } static void teardownTransportGlobalConst(void) { #if MUST_BUILD_WININET_CLIENT callTransportTeardown( xmlrpc_wininet_transport_ops.teardown_global_const); #endif #if MUST_BUILD_CURL_CLIENT callTransportTeardown( xmlrpc_curl_transport_ops.teardown_global_const); #endif #if MUST_BUILD_LIBWWW_CLIENT callTransportTeardown( xmlrpc_libwww_transport_ops.teardown_global_const); #endif } /*========================================================================= Global stuff (except the global client) =========================================================================*/ static unsigned int constSetupCount = 0; void xmlrpc_client_setup_global_const(xmlrpc_env * const envP) { /*---------------------------------------------------------------------------- Set up pseudo-constant global variables (they'd be constant, except that the library loader doesn't set them. An explicit call from the loaded program does). This function is not thread-safe. The user is supposed to call it (perhaps cascaded down from a multitude of higher level libraries) as part of early program setup, when the program is only one thread. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); if (constSetupCount == 0) setupTransportGlobalConst(envP); ++constSetupCount; } void xmlrpc_client_teardown_global_const(void) { /*---------------------------------------------------------------------------- Complement to xmlrpc_client_setup_global_const(). This function is not thread-safe. The user is supposed to call it (perhaps cascaded down from a multitude of higher level libraries) as part of final program cleanup, when the program is only one thread. -----------------------------------------------------------------------------*/ assert(constSetupCount > 0); --constSetupCount; if (constSetupCount == 0) teardownTransportGlobalConst(); } unsigned int const xmlrpc_client_version_major = XMLRPC_VERSION_MAJOR; unsigned int const xmlrpc_client_version_minor = XMLRPC_VERSION_MINOR; unsigned int const xmlrpc_client_version_point = XMLRPC_VERSION_POINT; void xmlrpc_client_version(unsigned int * const majorP, unsigned int * const minorP, unsigned int * const pointP) { *majorP = XMLRPC_VERSION_MAJOR; *minorP = XMLRPC_VERSION_MINOR; *pointP = XMLRPC_VERSION_POINT; } /*========================================================================= Client Create/Destroy =========================================================================*/ static void getTransportOps( xmlrpc_env * const envP, const char * const transportName, const struct xmlrpc_client_transport_ops ** const opsPP) { if (false) { } #if MUST_BUILD_WININET_CLIENT else if (xmlrpc_streq(transportName, "wininet")) *opsPP = &xmlrpc_wininet_transport_ops; #endif #if MUST_BUILD_CURL_CLIENT else if (xmlrpc_streq(transportName, "curl")) *opsPP = &xmlrpc_curl_transport_ops; #endif #if MUST_BUILD_LIBWWW_CLIENT else if (xmlrpc_streq(transportName, "libwww")) *opsPP = &xmlrpc_libwww_transport_ops; #endif else xmlrpc_faultf(envP, "Unrecognized XML transport name '%s'", transportName); } struct xportParms { const void * parmsP; size_t size; }; static void getTransportParmsFromClientParms( xmlrpc_env * const envP, const struct xmlrpc_clientparms * const clientparmsP, unsigned int const parmSize, struct xportParms * const xportParmsP) { if (parmSize < XMLRPC_CPSIZE(transportparmsP) || clientparmsP->transportparmsP == NULL) { xportParmsP->parmsP = NULL; xportParmsP->size = 0; } else { xportParmsP->parmsP = clientparmsP->transportparmsP; if (parmSize < XMLRPC_CPSIZE(transportparm_size)) xmlrpc_faultf(envP, "Your 'clientparms' argument contains the " "transportparmsP member, " "but no transportparms_size member"); else xportParmsP->size = clientparmsP->transportparm_size; } } static void getTransportInfo( xmlrpc_env * const envP, const struct xmlrpc_clientparms * const clientparmsP, unsigned int const parmSize, const char ** const transportNameP, struct xportParms * const transportParmsP, const struct xmlrpc_client_transport_ops ** const transportOpsPP, xmlrpc_client_transport ** const transportPP) { const char * transportNameParm; xmlrpc_client_transport * transportP; const struct xmlrpc_client_transport_ops * transportOpsP; if (parmSize < XMLRPC_CPSIZE(transport)) transportNameParm = NULL; else transportNameParm = clientparmsP->transport; if (parmSize < XMLRPC_CPSIZE(transportP)) transportP = NULL; else transportP = clientparmsP->transportP; if (parmSize < XMLRPC_CPSIZE(transportOpsP)) transportOpsP = NULL; else transportOpsP = clientparmsP->transportOpsP; if ((transportOpsP && !transportP) || (transportP && ! transportOpsP)) xmlrpc_faultf(envP, "'transportOpsP' and 'transportP' go together. " "You must specify both or neither"); else if (transportNameParm && transportP) xmlrpc_faultf(envP, "You cannot specify both 'transport' and " "'transportP' transport parameters."); else if (transportP) *transportNameP = NULL; else if (transportNameParm) *transportNameP = transportNameParm; else *transportNameP = xmlrpc_client_get_default_transport(envP); *transportOpsPP = transportOpsP; *transportPP = transportP; if (!envP->fault_occurred) { getTransportParmsFromClientParms( envP, clientparmsP, parmSize, transportParmsP); if (!envP->fault_occurred) { if (transportParmsP->parmsP && !transportNameParm) xmlrpc_faultf( envP, "You specified transport parameters, but did not " "specify a transport type. Parameters are specific " "to a particular type."); } } } static void getDialectFromClientParms( const struct xmlrpc_clientparms * const clientparmsP, unsigned int const parmSize, xmlrpc_dialect * const dialectP) { if (parmSize < XMLRPC_CPSIZE(dialect)) *dialectP = xmlrpc_dialect_i8; else *dialectP = clientparmsP->dialect; } static void clientCreate( xmlrpc_env * const envP, bool const myTransport, const struct xmlrpc_client_transport_ops * const transportOpsP, struct xmlrpc_client_transport * const transportP, xmlrpc_dialect const dialect, xmlrpc_progress_fn * const progressFn, xmlrpc_client ** const clientPP) { XMLRPC_ASSERT_PTR_OK(transportOpsP); XMLRPC_ASSERT_PTR_OK(transportP); XMLRPC_ASSERT_PTR_OK(clientPP); if (constSetupCount == 0) { xmlrpc_faultf(envP, "You have not called " "xmlrpc_client_setup_global_const()."); /* Impl note: We can't just call it now because it isn't thread-safe. */ } else { xmlrpc_client * clientP; MALLOCVAR(clientP); if (clientP == NULL) xmlrpc_faultf(envP, "Unable to allocate memory for " "client descriptor."); else { clientP->myTransport = myTransport; clientP->transportOps = *transportOpsP; clientP->transportP = transportP; clientP->dialect = dialect; clientP->progressFn = progressFn; *clientPP = clientP; } } } static void createTransportAndClient( xmlrpc_env * const envP, const char * const transportName, const void * const transportparmsP, size_t const transportparmSize, int const flags, const char * const appname, const char * const appversion, xmlrpc_dialect const dialect, xmlrpc_progress_fn * const progressFn, xmlrpc_client ** const clientPP) { const struct xmlrpc_client_transport_ops * transportOpsP; getTransportOps(envP, transportName, &transportOpsP); if (!envP->fault_occurred) { xmlrpc_client_transport * transportP; /* The following call is not thread-safe */ transportOpsP->create( envP, flags, appname, appversion, transportparmsP, transportparmSize, &transportP); if (!envP->fault_occurred) { bool const myTransportTrue = true; clientCreate(envP, myTransportTrue, transportOpsP, transportP, dialect, progressFn, clientPP); if (envP->fault_occurred) transportOpsP->destroy(transportP); } } } void xmlrpc_client_create(xmlrpc_env * const envP, int const flags, const char * const appname, const char * const appversion, const struct xmlrpc_clientparms * const clientparmsP, unsigned int const parmSize, xmlrpc_client ** const clientPP) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(clientPP); if (constSetupCount == 0) { xmlrpc_faultf(envP, "You have not called " "xmlrpc_client_setup_global_const()."); /* Impl note: We can't just call it now because it isn't thread-safe. */ } else { const char * transportName; struct xportParms transportparms; const struct xmlrpc_client_transport_ops * transportOpsP; xmlrpc_client_transport * transportP; xmlrpc_dialect dialect; xmlrpc_progress_fn * progressFn; getTransportInfo(envP, clientparmsP, parmSize, &transportName, &transportparms, &transportOpsP, &transportP); getDialectFromClientParms(clientparmsP, parmSize, &dialect); progressFn = parmSize >= XMLRPC_CPSIZE(progressFn) ? clientparmsP->progressFn : NULL; if (!envP->fault_occurred) { if (transportName) createTransportAndClient(envP, transportName, transportparms.parmsP, transportparms.size, flags, appname, appversion, dialect, progressFn, clientPP); else { bool myTransportFalse = false; clientCreate(envP, myTransportFalse, transportOpsP, transportP, dialect, progressFn, clientPP); } } } } void xmlrpc_client_destroy(xmlrpc_client * const clientP) { XMLRPC_ASSERT_PTR_OK(clientP); if (clientP->myTransport) clientP->transportOps.destroy(clientP->transportP); free(clientP); } /*========================================================================= Call/Response Utilities =========================================================================*/ static void makeCallXml(xmlrpc_env * const envP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_dialect const dialect, xmlrpc_mem_block ** const callXmlPP) { XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(callXmlPP); if (methodName == NULL) xmlrpc_faultf(envP, "method name argument is NULL pointer"); else { xmlrpc_mem_block * callXmlP; callXmlP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); if (!envP->fault_occurred) { xmlrpc_serialize_call2(envP, callXmlP, methodName, paramArrayP, dialect); *callXmlPP = callXmlP; if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, callXmlP); } } } /*========================================================================= Synchronous Call =========================================================================*/ void xmlrpc_client_transport_call2( xmlrpc_env * const envP, xmlrpc_client * const clientP, const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block ** const respXmlPP) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(clientP); XMLRPC_ASSERT_PTR_OK(serverP); XMLRPC_ASSERT_PTR_OK(callXmlP); XMLRPC_ASSERT_PTR_OK(respXmlPP); clientP->transportOps.call( envP, clientP->transportP, serverP, callXmlP, respXmlPP); } static void parseResponse(xmlrpc_env * const envP, xmlrpc_mem_block * const respXmlP, xmlrpc_value ** const resultPP, int * const faultCodeP, const char ** const faultStringP) { xmlrpc_env respEnv; XMLRPC_ASSERT_ENV_OK(envP); xmlrpc_env_init(&respEnv); xmlrpc_parse_response2( &respEnv, XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP), XMLRPC_MEMBLOCK_SIZE(char, respXmlP), resultPP, faultCodeP, faultStringP); if (respEnv.fault_occurred) xmlrpc_env_set_fault_formatted( envP, respEnv.fault_code, "Unable to make sense of XML-RPC response from server. " "%s. Use XMLRPC_TRACE_XML to see for yourself", respEnv.fault_string); xmlrpc_env_clean(&respEnv); } void xmlrpc_client_call2(xmlrpc_env * const envP, struct xmlrpc_client * const clientP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_value ** const resultPP) { xmlrpc_mem_block * callXmlP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(clientP); XMLRPC_ASSERT_PTR_OK(serverInfoP); XMLRPC_ASSERT_PTR_OK(paramArrayP); makeCallXml(envP, methodName, paramArrayP, clientP->dialect, &callXmlP); if (!envP->fault_occurred) { xmlrpc_mem_block * respXmlP; xmlrpc_traceXml("XML-RPC CALL", XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP), XMLRPC_MEMBLOCK_SIZE(char, callXmlP)); clientP->transportOps.call( envP, clientP->transportP, serverInfoP, callXmlP, &respXmlP); if (!envP->fault_occurred) { int faultCode; const char * faultString; xmlrpc_traceXml("XML-RPC RESPONSE", XMLRPC_MEMBLOCK_CONTENTS(char, respXmlP), XMLRPC_MEMBLOCK_SIZE(char, respXmlP)); parseResponse(envP, respXmlP, resultPP, &faultCode, &faultString); if (!envP->fault_occurred) { if (faultString) { xmlrpc_env_set_fault_formatted( envP, faultCode, "RPC failed at server. %s", faultString); xmlrpc_strfree(faultString); } else XMLRPC_ASSERT_VALUE_OK(*resultPP); } XMLRPC_MEMBLOCK_FREE(char, respXmlP); } XMLRPC_MEMBLOCK_FREE(char, callXmlP); } } static void computeParamArray(xmlrpc_env * const envP, const char * const format, va_list args, xmlrpc_value ** const paramArrayPP) { /*---------------------------------------------------------------------------- 'format' and 'args' specify the parameter list of an RPC, in the form of an XML-RPC array value, with one element per RPC parameter. 'format' is an XML-RPC value format string, e.g. "(ii{s:i,s:i})". 'args' is the list of substitution values for that string (6 values in this example, 4 integers and 2 strings). We return the XML-RPC value 'format' and 'args' represent, but throw an error if they don't validly specify a single array. Note that it is a common user error to specify the format string as a single or string of argument types, instead of as an array of argument types. E.g. "i" or "ii" instead of "(i)" and "(ii)". So we try especially hard to give an informative message for that case. -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * paramArrayP; const char * suffix; /* Stuff left over in format string after parameter array specification. */ xmlrpc_env_init(&env); xmlrpc_build_value_va(&env, format, args, ¶mArrayP, &suffix); if (env.fault_occurred) xmlrpc_env_set_fault_formatted( envP, env.fault_code, "Invalid RPC arguments. " "The format argument must indicate a single array (each element " "of which is one argument to the XML-RPC call), and the " "following arguments must correspond to that format argument. " "The failure is: %s", env.fault_string); else { XMLRPC_ASSERT_VALUE_OK(paramArrayP); if (*suffix != '\0') xmlrpc_faultf(envP, "Junk after the parameter array specifier: '%s'. " "The format string must specify exactly one value: " "an array of RPC parameters", suffix); else { if (xmlrpc_value_type(paramArrayP) != XMLRPC_TYPE_ARRAY) xmlrpc_faultf( envP, "You must specify the parameter list as an " "XML-RPC array value, " "each element of which is a parameter of the RPC. " "But your format string specifies an XML-RPC %s, not " "an array", xmlrpc_type_name(xmlrpc_value_type(paramArrayP))); } if (env.fault_occurred) xmlrpc_DECREF(paramArrayP); else *paramArrayPP = paramArrayP; } xmlrpc_env_clean(&env); } void xmlrpc_client_call_server2_va(xmlrpc_env * const envP, struct xmlrpc_client * const clientP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, const char * const format, va_list args, xmlrpc_value ** const resultPP) { /* This function exists only for use by the global client function xmlrpc_client_call_server(). */ xmlrpc_value * paramArrayP; /* The XML-RPC parameter list array */ XMLRPC_ASSERT_ENV_OK(envP); computeParamArray(envP, format, args, ¶mArrayP); if (!envP->fault_occurred) { xmlrpc_client_call2(envP, clientP, serverInfoP, methodName, paramArrayP, resultPP); xmlrpc_DECREF(paramArrayP); } } void xmlrpc_client_call2f_va(xmlrpc_env * const envP, xmlrpc_client * const clientP, const char * const serverUrl, const char * const methodName, const char * const format, xmlrpc_value ** const resultPP, va_list args) { xmlrpc_value * paramArrayP; /* The XML-RPC parameter list array */ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(clientP); XMLRPC_ASSERT_PTR_OK(serverUrl); XMLRPC_ASSERT_PTR_OK(methodName); XMLRPC_ASSERT_PTR_OK(format); XMLRPC_ASSERT_PTR_OK(resultPP); computeParamArray(envP, format, args, ¶mArrayP); if (!envP->fault_occurred) { xmlrpc_server_info * serverInfoP; serverInfoP = xmlrpc_server_info_new(envP, serverUrl); if (!envP->fault_occurred) { /* Perform the actual XML-RPC call. */ xmlrpc_client_call2(envP, clientP, serverInfoP, methodName, paramArrayP, resultPP); if (!envP->fault_occurred) XMLRPC_ASSERT_VALUE_OK(*resultPP); xmlrpc_server_info_free(serverInfoP); } xmlrpc_DECREF(paramArrayP); } } void xmlrpc_client_call2f(xmlrpc_env * const envP, xmlrpc_client * const clientP, const char * const serverUrl, const char * const methodName, xmlrpc_value ** const resultPP, const char * const format, ...) { va_list args; XMLRPC_ASSERT_PTR_OK(format); va_start(args, format); xmlrpc_client_call2f_va(envP, clientP, serverUrl, methodName, format, resultPP, args); va_end(args); } /*========================================================================= Asynchronous Call =========================================================================*/ static void callInfoSetCompletion(xmlrpc_env * const envP, struct xmlrpc_call_info * const callInfoP, const char * const serverUrl, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_response_handler completionFn, xmlrpc_progress_fn progressFn, void * const userHandle) { /*---------------------------------------------------------------------------- Set the members of callinfo structure *callInfoP that are used for the completion and progress calls from the transport to us. -----------------------------------------------------------------------------*/ callInfoP->completionFn = completionFn; callInfoP->progressFn = progressFn; callInfoP->userHandle = userHandle; callInfoP->completionArgs.serverUrl = strdup(serverUrl); if (callInfoP->completionArgs.serverUrl == NULL) xmlrpc_faultf(envP, "Couldn't get memory to store server URL"); else { callInfoP->completionArgs.methodName = strdup(methodName); if (callInfoP->completionArgs.methodName == NULL) xmlrpc_faultf(envP, "Couldn't get memory to store method name"); else { callInfoP->completionArgs.paramArrayP = paramArrayP; xmlrpc_INCREF(paramArrayP); } if (envP->fault_occurred) xmlrpc_strfree(callInfoP->completionArgs.serverUrl); } } static void callInfoCreate(xmlrpc_env * const envP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_dialect const dialect, const char * const serverUrl, xmlrpc_response_handler completionFn, xmlrpc_progress_fn progressFn, void * const userHandle, struct xmlrpc_call_info ** const callInfoPP) { /*---------------------------------------------------------------------------- Create a call_info object. A call_info object represents an XML-RPC call. -----------------------------------------------------------------------------*/ struct xmlrpc_call_info * callInfoP; XMLRPC_ASSERT_PTR_OK(serverUrl); XMLRPC_ASSERT_PTR_OK(methodName); XMLRPC_ASSERT_VALUE_OK(paramArrayP); XMLRPC_ASSERT_PTR_OK(callInfoPP); MALLOCVAR(callInfoP); if (callInfoP == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for xmlrpc_call_info"); else { xmlrpc_mem_block * callXmlP; makeCallXml(envP, methodName, paramArrayP, dialect, &callXmlP); if (!envP->fault_occurred) { callInfoP->serialized_xml = callXmlP; callInfoSetCompletion(envP, callInfoP, serverUrl, methodName, paramArrayP, completionFn, progressFn, userHandle); if (envP->fault_occurred) free(callInfoP); } } *callInfoPP = callInfoP; } static void callInfoDestroy(struct xmlrpc_call_info * const callInfoP) { XMLRPC_ASSERT_PTR_OK(callInfoP); if (callInfoP->completionFn) { xmlrpc_DECREF(callInfoP->completionArgs.paramArrayP); xmlrpc_strfree(callInfoP->completionArgs.methodName); xmlrpc_strfree(callInfoP->completionArgs.serverUrl); } if (callInfoP->serialized_xml) xmlrpc_mem_block_free(callInfoP->serialized_xml); free(callInfoP); } void xmlrpc_client_event_loop_finish(xmlrpc_client * const clientP) { XMLRPC_ASSERT_PTR_OK(clientP); clientP->transportOps.finish_asynch( clientP->transportP, timeout_no, 0); } void xmlrpc_client_event_loop_finish_timeout(xmlrpc_client * const clientP, xmlrpc_timeout const timeout) { XMLRPC_ASSERT_PTR_OK(clientP); clientP->transportOps.finish_asynch( clientP->transportP, timeout_yes, timeout); } /* Microsoft Visual C in debug mode produces code that complains about passing an undefined value of 'resultP' to xmlrpc_parse_response2(). It's a bogus complaint, because this function knows in those cases that the value of 'resultP' is meaningless. So we disable the check. */ #pragma runtime_checks("u", off) static void asynchComplete(struct xmlrpc_call_info * const callInfoP, xmlrpc_mem_block * const responseXmlP, xmlrpc_env const transportEnv) { /*---------------------------------------------------------------------------- Complete an asynchronous XML-RPC call request. This includes calling the user's RPC completion routine. 'transportEnv' describes an error that the transport encountered in processing the call. If the transport successfully sent the call to the server and processed the response but the server failed the call, 'transportEnv' indicates no error, and the response in *responseXmlP might very well indicate that the server failed the request. -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_env_init(&env); if (transportEnv.fault_occurred) xmlrpc_env_set_fault_formatted( &env, transportEnv.fault_code, "Client transport failed to execute the RPC. %s", transportEnv.fault_string); if (!env.fault_occurred) { int faultCode; const char * faultString; xmlrpc_parse_response2(&env, XMLRPC_MEMBLOCK_CONTENTS(char, responseXmlP), XMLRPC_MEMBLOCK_SIZE(char, responseXmlP), &resultP, &faultCode, &faultString); if (!env.fault_occurred) { if (faultString) { xmlrpc_env_set_fault_formatted( &env, faultCode, "RPC failed at server. %s", faultString); xmlrpc_strfree(faultString); } } } /* Call the user's completion function with the RPC result */ (*callInfoP->completionFn)(callInfoP->completionArgs.serverUrl, callInfoP->completionArgs.methodName, callInfoP->completionArgs.paramArrayP, callInfoP->userHandle, &env, resultP); if (!env.fault_occurred) xmlrpc_DECREF(resultP); callInfoDestroy(callInfoP); xmlrpc_env_clean(&env); } #pragma runtime_checks("u", restore) static void progress(struct xmlrpc_call_info * const callInfoP, struct xmlrpc_progress_data const progressData) { /* We wouldn't have asked the transport to call our progress function if we didn't have a user progress function to call: */ assert(callInfoP->progressFn); callInfoP->progressFn(callInfoP->userHandle, progressData); } void xmlrpc_client_start_rpc(xmlrpc_env * const envP, struct xmlrpc_client * const clientP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_response_handler completionFn, void * const userHandle) { struct xmlrpc_call_info * callInfoP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(clientP); XMLRPC_ASSERT_PTR_OK(serverInfoP); XMLRPC_ASSERT_PTR_OK(methodName); XMLRPC_ASSERT_VALUE_OK(paramArrayP); callInfoCreate(envP, methodName, paramArrayP, clientP->dialect, serverInfoP->serverUrl, completionFn, clientP->progressFn, userHandle, &callInfoP); if (!envP->fault_occurred) { xmlrpc_traceXml( "XML-RPC CALL", XMLRPC_MEMBLOCK_CONTENTS(char, callInfoP->serialized_xml), XMLRPC_MEMBLOCK_SIZE(char, callInfoP->serialized_xml)); clientP->transportOps.send_request( envP, clientP->transportP, serverInfoP, callInfoP->serialized_xml, &asynchComplete, clientP->progressFn ? &progress : NULL, callInfoP); } if (envP->fault_occurred) callInfoDestroy(callInfoP); else { /* asynchComplete() will destroy *callInfoP */ } } void xmlrpc_client_start_rpcf_server_va( xmlrpc_env * const envP, xmlrpc_client * const clientP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userHandle, const char * const format, va_list args) { xmlrpc_value * paramArrayP; /* The XML-RPC parameter list array */ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(clientP); XMLRPC_ASSERT_PTR_OK(serverInfoP); XMLRPC_ASSERT_PTR_OK(methodName); XMLRPC_ASSERT_PTR_OK(format); computeParamArray(envP, format, args, ¶mArrayP); if (!envP->fault_occurred) { xmlrpc_client_start_rpc(envP, clientP, serverInfoP, methodName, paramArrayP, responseHandler, userHandle); xmlrpc_DECREF(paramArrayP); } } void xmlrpc_client_start_rpcf_va(xmlrpc_env * const envP, xmlrpc_client * const clientP, const char * const serverUrl, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userHandle, const char * const format, va_list args) { xmlrpc_server_info * serverInfoP; XMLRPC_ASSERT_ENV_OK(envP); serverInfoP = xmlrpc_server_info_new(envP, serverUrl); if (!envP->fault_occurred) { xmlrpc_client_start_rpcf_server_va( envP, clientP, serverInfoP, methodName, responseHandler, userHandle, format, args); xmlrpc_server_info_free(serverInfoP); } } void xmlrpc_client_start_rpcf(xmlrpc_env * const envP, xmlrpc_client * const clientP, const char * const serverUrl, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userHandle, const char * const format, ...) { va_list args; XMLRPC_ASSERT_PTR_OK(format); va_start(args, format); xmlrpc_client_start_rpcf_va(envP, clientP, serverUrl, methodName, responseHandler, userHandle, format, args); va_end(args); } /*========================================================================= Miscellaneous =========================================================================*/ const char * xmlrpc_client_get_default_transport(xmlrpc_env * const envP ATTR_UNUSED) { return XMLRPC_DEFAULT_TRANSPORT; } void xmlrpc_client_set_interrupt(xmlrpc_client * const clientP, int * const interruptP) { if (clientP->transportOps.set_interrupt) clientP->transportOps.set_interrupt(clientP->transportP, interruptP); } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/xmlrpc_client_global.c000066400000000000000000000246531236133176700205510ustar00rootroot00000000000000#include #include "xmlrpc_config.h" #include "bool.h" #include #include #include #include /*========================================================================= Global Client =========================================================================*/ static struct xmlrpc_client * globalClientP; static bool globalClientExists = false; void xmlrpc_client_init2(xmlrpc_env * const envP, int const flags, const char * const appname, const char * const appversion, const struct xmlrpc_clientparms * const clientparmsP, unsigned int const parmSize) { /*---------------------------------------------------------------------------- This function is not thread-safe. -----------------------------------------------------------------------------*/ if (globalClientExists) xmlrpc_faultf( envP, "Xmlrpc-c global client instance has already been created " "(need to call xmlrpc_client_cleanup() before you can " "reinitialize)."); else { /* The following call is not thread-safe */ xmlrpc_client_setup_global_const(envP); if (!envP->fault_occurred) { xmlrpc_client_create(envP, flags, appname, appversion, clientparmsP, parmSize, &globalClientP); if (!envP->fault_occurred) globalClientExists = true; if (envP->fault_occurred) xmlrpc_client_teardown_global_const(); } } } void xmlrpc_client_init(int const flags, const char * const appname, const char * const appversion) { /*---------------------------------------------------------------------------- This function is not thread-safe. -----------------------------------------------------------------------------*/ struct xmlrpc_clientparms clientparms; /* As our interface does not allow for failure, we just fail silently ! */ xmlrpc_env env; xmlrpc_env_init(&env); clientparms.transport = NULL; /* The following call is not thread-safe */ xmlrpc_client_init2(&env, flags, appname, appversion, &clientparms, XMLRPC_CPSIZE(transport)); xmlrpc_env_clean(&env); } void xmlrpc_client_cleanup() { /*---------------------------------------------------------------------------- This function is not thread-safe -----------------------------------------------------------------------------*/ XMLRPC_ASSERT(globalClientExists); xmlrpc_client_destroy(globalClientP); globalClientExists = false; /* The following call is not thread-safe */ xmlrpc_client_teardown_global_const(); } static void validateGlobalClientExists(xmlrpc_env * const envP) { if (!globalClientExists) xmlrpc_faultf(envP, "Xmlrpc-c global client instance " "has not been created " "(need to call xmlrpc_client_init2())."); } void xmlrpc_client_transport_call( xmlrpc_env * const envP, void * const reserved ATTR_UNUSED, /* for client handle */ const xmlrpc_server_info * const serverP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block ** const respXmlPP) { validateGlobalClientExists(envP); if (!envP->fault_occurred) xmlrpc_client_transport_call2(envP, globalClientP, serverP, callXmlP, respXmlPP); } xmlrpc_value * xmlrpc_client_call(xmlrpc_env * const envP, const char * const serverUrl, const char * const methodName, const char * const format, ...) { xmlrpc_value * resultP; validateGlobalClientExists(envP); if (!envP->fault_occurred) { va_list args; va_start(args, format); xmlrpc_client_call2f_va(envP, globalClientP, serverUrl, methodName, format, &resultP, args); va_end(args); } return resultP; } xmlrpc_value * xmlrpc_client_call_server(xmlrpc_env * const envP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, const char * const format, ...) { xmlrpc_value * resultP; validateGlobalClientExists(envP); if (!envP->fault_occurred) { va_list args; va_start(args, format); xmlrpc_client_call_server2_va(envP, globalClientP, serverInfoP, methodName, format, args, &resultP); va_end(args); } return resultP; } xmlrpc_value * xmlrpc_client_call_server_params( xmlrpc_env * const envP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_value * const paramArrayP) { xmlrpc_value * resultP; validateGlobalClientExists(envP); if (!envP->fault_occurred) xmlrpc_client_call2(envP, globalClientP, serverInfoP, methodName, paramArrayP, &resultP); return resultP; } xmlrpc_value * xmlrpc_client_call_params(xmlrpc_env * const envP, const char * const serverUrl, const char * const methodName, xmlrpc_value * const paramArrayP) { xmlrpc_value * resultP; validateGlobalClientExists(envP); if (!envP->fault_occurred) { xmlrpc_server_info * serverInfoP; serverInfoP = xmlrpc_server_info_new(envP, serverUrl); if (!envP->fault_occurred) { xmlrpc_client_call2(envP, globalClientP, serverInfoP, methodName, paramArrayP, &resultP); xmlrpc_server_info_free(serverInfoP); } } return resultP; } void xmlrpc_client_call_server_asynch_params( xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userData, xmlrpc_value * const paramArrayP) { xmlrpc_env env; xmlrpc_env_init(&env); validateGlobalClientExists(&env); if (!env.fault_occurred) xmlrpc_client_start_rpc(&env, globalClientP, serverInfoP, methodName, paramArrayP, responseHandler, userData); if (env.fault_occurred) { /* Unfortunately, we have no way to return an error and the regular callback for a failed RPC is designed to have the parameter array passed to it. This was probably an oversight of the original asynch design, but now we have to be as backward compatible as possible, so we do this: */ (*responseHandler)(serverInfoP->serverUrl, methodName, paramArrayP, userData, &env, NULL); } xmlrpc_env_clean(&env); } void xmlrpc_client_call_asynch(const char * const serverUrl, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userData, const char * const format, ...) { xmlrpc_env env; xmlrpc_env_init(&env); validateGlobalClientExists(&env); if (!env.fault_occurred) { va_list args; va_start(args, format); xmlrpc_client_start_rpcf_va(&env, globalClientP, serverUrl, methodName, responseHandler, userData, format, args); va_end(args); } if (env.fault_occurred) (*responseHandler)(serverUrl, methodName, NULL, userData, &env, NULL); xmlrpc_env_clean(&env); } void xmlrpc_client_call_asynch_params(const char * const serverUrl, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userData, xmlrpc_value * const paramArrayP) { xmlrpc_env env; xmlrpc_server_info * serverInfoP; xmlrpc_env_init(&env); serverInfoP = xmlrpc_server_info_new(&env, serverUrl); if (!env.fault_occurred) { xmlrpc_client_call_server_asynch_params( serverInfoP, methodName, responseHandler, userData, paramArrayP); xmlrpc_server_info_free(serverInfoP); } if (env.fault_occurred) (*responseHandler)(serverUrl, methodName, paramArrayP, userData, &env, NULL); xmlrpc_env_clean(&env); } void xmlrpc_client_call_server_asynch(xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_response_handler responseHandler, void * const userData, const char * const format, ...) { xmlrpc_env env; validateGlobalClientExists(&env); if (!env.fault_occurred) { va_list args; xmlrpc_env_init(&env); va_start(args, format); xmlrpc_client_start_rpcf_server_va( &env, globalClientP, serverInfoP, methodName, responseHandler, userData, format, args); va_end(args); } if (env.fault_occurred) (*responseHandler)(serverInfoP->serverUrl, methodName, NULL, userData, &env, NULL); xmlrpc_env_clean(&env); } void xmlrpc_client_event_loop_finish_asynch(void) { XMLRPC_ASSERT(globalClientExists); xmlrpc_client_event_loop_finish(globalClientP); } void xmlrpc_client_event_loop_finish_asynch_timeout( unsigned long const milliseconds) { XMLRPC_ASSERT(globalClientExists); xmlrpc_client_event_loop_finish_timeout(globalClientP, milliseconds); } xmlrpc-c-1.33.14/src/xmlrpc_data.c000066400000000000000000000351561236133176700166640ustar00rootroot00000000000000/* Copyright information is at end of file */ #include "xmlrpc_config.h" #include #include #include #include #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/lock.h" #include "xmlrpc-c/lock_platform.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" /*============================================================================= xmlrpc_value is designed to enable cheap copies by sharing pointers and maintaining reference counts. Multiple threads can use an xmlrpc_value simultaneously because there is locking around the reference count manipulation (but only since Xmlrpc-c 1.33). But there is no copy on write, so the scheme depends upon the user not modifying an xmlrpc_value after building it, and not copying it while building it. Another reason to observe this sequence is that there is no locking around modifications, so a reader could see a half-updated xmlrpc_value. We could enforce a prohibition against modifying an xmlrpc_value that has references other than the one by the party doing the modifying, but we don't because we allowed it for a long time before we noticed the problem adn we're afraid of breaking an existing program that does these updates in such a way that it actually works. =============================================================================*/ static void destroyCptr(xmlrpc_value * const valueP) { if (valueP->_value.cptr.dtor) valueP->_value.cptr.dtor(valueP->_value.cptr.dtorContext, valueP->_value.cptr.objectP); } static void destroyValue(xmlrpc_value * const valueP) { /* First, we need to destroy this value's contents, if any. */ switch (valueP->_type) { case XMLRPC_TYPE_INT: break; case XMLRPC_TYPE_BOOL: break; case XMLRPC_TYPE_DOUBLE: break; case XMLRPC_TYPE_DATETIME: xmlrpc_destroyDatetime(valueP); break; case XMLRPC_TYPE_STRING: xmlrpc_destroyString(valueP); break; case XMLRPC_TYPE_BASE64: xmlrpc_mem_block_clean(&valueP->_block); break; case XMLRPC_TYPE_ARRAY: xmlrpc_destroyArrayContents(valueP); break; case XMLRPC_TYPE_STRUCT: xmlrpc_destroyStruct(valueP); break; case XMLRPC_TYPE_C_PTR: destroyCptr(valueP); break; case XMLRPC_TYPE_NIL: break; case XMLRPC_TYPE_I8: break; case XMLRPC_TYPE_DEAD: XMLRPC_ASSERT(false); /* Can't happen, per entry conditions */ default: XMLRPC_ASSERT(false); /* There are no other possible values */ } valueP->lockP->destroy(valueP->lockP); /* Next, we mark this value as invalid, to help catch refcount errors. */ valueP->_type = XMLRPC_TYPE_DEAD; /* Finally, we destroy the value itself. */ free(valueP); } /*=========================================================================== Reference Counting ============================================================================= Some simple reference-counting code. The xmlrpc_DECREF routine is in charge of destroying values when their reference count reaches zero. ============================================================================*/ void xmlrpc_INCREF (xmlrpc_value * const valueP) { XMLRPC_ASSERT_VALUE_OK(valueP); valueP->lockP->acquire(valueP->lockP); XMLRPC_ASSERT(valueP->refcount > 0); ++valueP->refcount; valueP->lockP->release(valueP->lockP); } void xmlrpc_DECREF (xmlrpc_value * const valueP) { bool died; XMLRPC_ASSERT_VALUE_OK(valueP); valueP->lockP->acquire(valueP->lockP); XMLRPC_ASSERT(valueP->refcount > 0); XMLRPC_ASSERT(valueP->_type != XMLRPC_TYPE_DEAD); --valueP->refcount; died = (valueP->refcount == 0); valueP->lockP->release(valueP->lockP); if (died) destroyValue(valueP); } /*========================================================================= Utiltiies =========================================================================*/ const char * xmlrpc_type_name(xmlrpc_type const type) { switch (type) { case XMLRPC_TYPE_INT: return "INT"; case XMLRPC_TYPE_BOOL: return "BOOL"; case XMLRPC_TYPE_DOUBLE: return "DOUBLE"; case XMLRPC_TYPE_DATETIME: return "DATETIME"; case XMLRPC_TYPE_STRING: return "STRING"; case XMLRPC_TYPE_BASE64: return "BASE64"; case XMLRPC_TYPE_ARRAY: return "ARRAY"; case XMLRPC_TYPE_STRUCT: return "STRUCT"; case XMLRPC_TYPE_C_PTR: return "C_PTR"; case XMLRPC_TYPE_NIL: return "NIL"; case XMLRPC_TYPE_I8: return "I8"; case XMLRPC_TYPE_DEAD: return "DEAD"; default: return "???"; } } static void validateType(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_type const expectedType) { if (valueP->_type != expectedType) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value of type %s supplied where " "type %s was expected.", xmlrpc_type_name(valueP->_type), xmlrpc_type_name(expectedType)); } } /*========================================================================= Extracting XML-RPC value =========================================================================== These routines extract XML-RPC values into ordinary C data types. For array and struct values, see the separates files xmlrpc_array.c and xmlrpc_struct.c. =========================================================================*/ void xmlrpc_read_int(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_int32 * const intValueP) { validateType(envP, valueP, XMLRPC_TYPE_INT); if (!envP->fault_occurred) *intValueP = valueP->_value.i; } void xmlrpc_read_bool(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_bool * const boolValueP) { validateType(envP, valueP, XMLRPC_TYPE_BOOL); if (!envP->fault_occurred) *boolValueP = valueP->_value.b; } void xmlrpc_read_double(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_double * const doubleValueP) { validateType(envP, valueP, XMLRPC_TYPE_DOUBLE); if (!envP->fault_occurred) *doubleValueP = valueP->_value.d; } /* datetime stuff is in xmlrpc_datetime.c */ /* string stuff is in xmlrpc_string.c */ void xmlrpc_read_base64(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const unsigned char ** const byteStringValueP) { validateType(envP, valueP, XMLRPC_TYPE_BASE64); if (!envP->fault_occurred) { size_t const size = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); const char * const contents = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); char * byteStringValue; byteStringValue = malloc(size); if (byteStringValue == NULL) xmlrpc_faultf(envP, "Unable to allocate %u bytes for byte string.", (unsigned)size); else { memcpy(byteStringValue, contents, size); *byteStringValueP = (const unsigned char *)byteStringValue; *lengthP = size; } } } void xmlrpc_read_base64_old(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const unsigned char ** const byteStringValueP) { validateType(envP, valueP, XMLRPC_TYPE_BASE64); if (!envP->fault_occurred) { *lengthP = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); *byteStringValueP = (const unsigned char *) XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); } } void xmlrpc_read_base64_size(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP) { validateType(envP, valueP, XMLRPC_TYPE_BASE64); if (!envP->fault_occurred) *lengthP = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); } void xmlrpc_read_cptr(xmlrpc_env * const envP, const xmlrpc_value * const valueP, void ** const ptrValueP) { validateType(envP, valueP, XMLRPC_TYPE_C_PTR); if (!envP->fault_occurred) *ptrValueP = valueP->_value.cptr.objectP; } void xmlrpc_read_nil(xmlrpc_env * const envP, xmlrpc_value * const valueP) { /*---------------------------------------------------------------------------- Read out the value of a nil value. It doesn't have one, of course, so this is essentially a no-op. But it does validate the type and is necessary to match all the other types. -----------------------------------------------------------------------------*/ validateType(envP, valueP, XMLRPC_TYPE_NIL); } void xmlrpc_read_i8(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_int64 * const intValueP) { validateType(envP, valueP, XMLRPC_TYPE_I8); if (!envP->fault_occurred) *intValueP = valueP->_value.i8; } xmlrpc_type xmlrpc_value_type (xmlrpc_value* const value) { XMLRPC_ASSERT_VALUE_OK(value); return value->_type; } void xmlrpc_createXmlrpcValue(xmlrpc_env * const envP, xmlrpc_value ** const valPP) { /*---------------------------------------------------------------------------- Create a blank xmlrpc_value to be filled in. Set the reference count to 1. -----------------------------------------------------------------------------*/ xmlrpc_value * valP; MALLOCVAR(valP); if (!valP) xmlrpc_faultf(envP, "Could not allocate memory for xmlrpc_value"); else { valP->lockP = xmlrpc_lock_create(); if (!valP->lockP) xmlrpc_faultf(envP, "Could not allocate memory for lock for " "xmlrpc_value"); else valP->refcount = 1; } *valPP = valP; } xmlrpc_value * xmlrpc_int_new(xmlrpc_env * const envP, xmlrpc_int32 const value) { xmlrpc_value * valP; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_INT; valP->_value.i = value; } return valP; } xmlrpc_value * xmlrpc_i8_new(xmlrpc_env * const envP, xmlrpc_int64 const value) { xmlrpc_value * valP; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_I8; valP->_value.i8 = value; } return valP; } xmlrpc_value * xmlrpc_bool_new(xmlrpc_env * const envP, xmlrpc_bool const value) { xmlrpc_value * valP; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_BOOL; valP->_value.b = value; } return valP; } xmlrpc_value * xmlrpc_double_new(xmlrpc_env * const envP, double const value) { xmlrpc_value * valP; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_DOUBLE; valP->_value.d = value; } return valP; } xmlrpc_value * xmlrpc_base64_new(xmlrpc_env * const envP, size_t const length, const unsigned char * const value) { xmlrpc_value * valP; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_BASE64; xmlrpc_mem_block_init(envP, &valP->_block, length); if (!envP->fault_occurred) { char * const contents = xmlrpc_mem_block_contents(&valP->_block); memcpy(contents, value, length); } if (envP->fault_occurred) free(valP); } return valP; } /* array stuff is in xmlrpc_array.c */ xmlrpc_value * xmlrpc_cptr_new(xmlrpc_env * const envP, void * const value) { return xmlrpc_cptr_new_dtor(envP, value, NULL, NULL); } xmlrpc_value * xmlrpc_cptr_new_dtor(xmlrpc_env * const envP, void * const value, xmlrpc_cptr_dtor_fn const dtor, void * const dtorContext) { xmlrpc_value * valP; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_C_PTR; valP->_value.cptr.objectP = value; valP->_value.cptr.dtor = dtor; valP->_value.cptr.dtorContext = dtorContext; } return valP; } xmlrpc_value * xmlrpc_nil_new(xmlrpc_env * const envP) { xmlrpc_value * valP; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) valP->_type = XMLRPC_TYPE_NIL; return valP; } /* Copyright (C) 2001 by First Peer, Inc. All rights reserved. ** Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/xmlrpc_datetime.c000066400000000000000000000444121236133176700175420ustar00rootroot00000000000000#include "xmlrpc_config.h" #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include #include #include #if MSVCRT # define WIN32_LEAN_AND_MEAN # include #endif #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/c_util.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/time_int.h" #if HAVE_REGEX #include #endif #if MSVCRT static const __int64 SECS_BETWEEN_EPOCHS = 11644473600; static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */ void UnixTimeToFileTime(time_t const t, LPFILETIME const pft) { int64_t const ll = Int32x32To64(t, SECS_TO_100NS) + SECS_BETWEEN_EPOCHS * SECS_TO_100NS; pft->dwLowDateTime = (DWORD)ll; pft->dwHighDateTime = (DWORD)(ll >> 32); } void UnixTimeToSystemTime(time_t const t, LPSYSTEMTIME const pst) { FILETIME ft; UnixTimeToFileTime(t, &ft); FileTimeToSystemTime(&ft, pst); } static void UnixTimeFromFileTime(xmlrpc_env * const envP, LPFILETIME const pft, time_t * const timeValueP) { int64_t const WinEpoch100Ns = ((int64_t)pft->dwHighDateTime << 32) + pft->dwLowDateTime; int64_t const unixEpoch100Ns = WinEpoch100Ns - (SECS_BETWEEN_EPOCHS * SECS_TO_100NS); int64_t const unixEpochSeconds = unixEpoch100Ns / SECS_TO_100NS; if ((time_t)unixEpochSeconds != unixEpochSeconds) { /* Value is too big for a time_t; fail. */ xmlrpc_faultf(envP, "Does not indicate a valid date"); *timeValueP = (time_t)(-1); } else *timeValueP = (time_t)unixEpochSeconds; } static void UnixTimeFromSystemTime(xmlrpc_env * const envP, LPSYSTEMTIME const pst, time_t * const timeValueP) { FILETIME filetime; SystemTimeToFileTime(pst, &filetime); UnixTimeFromFileTime(envP, &filetime, timeValueP); } #endif /* MSVCRT */ static void validateDatetimeType(xmlrpc_env * const envP, const xmlrpc_value * const valueP) { if (valueP->_type != XMLRPC_TYPE_DATETIME) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value of type %s supplied where " "type %s was expected.", xmlrpc_type_name(valueP->_type), xmlrpc_type_name(XMLRPC_TYPE_DATETIME)); } } void xmlrpc_read_datetime(xmlrpc_env * const envP, const xmlrpc_value * const valueP, xmlrpc_datetime * const dtP) { validateDatetimeType(envP, valueP); if (!envP->fault_occurred) { *dtP = valueP->_value.dt; } } void xmlrpc_read_datetime_str(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP) { /*---------------------------------------------------------------------------- This exists for backward compatibility. No normal modern program would want to see a datetime value in this format. Note that the format isn't even ISO 8601 -- it's a bizarre hybrid of two ISO 8601 formats. Do not extend this. This exists because Xmlrpc-c was at one time lazy and this was the only way to extract the value. An xmlrpc_value in those days represented a datetime with the actual XML-RPC wire format of a datetime, and this function simply returned a copy of it. -----------------------------------------------------------------------------*/ validateDatetimeType(envP, valueP); if (!envP->fault_occurred) { time_t secs; unsigned int usecs; xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); if (!envP->fault_occurred) { struct tm brokenTime; char dtString[64]; xmlrpc_gmtime(secs, &brokenTime); /* Note that this format is NOT ISO 8601 -- it's a bizarre hybrid of two ISO 8601 formats. */ strftime(dtString, sizeof(dtString), "%Y%m%dT%H:%M:%S", &brokenTime); if (usecs != 0) { char usecString[64]; assert(usecs < 1000000); snprintf(usecString, sizeof(usecString), ".%06u", usecs); STRSCAT(dtString, usecString); } *stringValueP = strdup(dtString); if (*stringValueP == NULL) xmlrpc_faultf(envP, "Unable to allocate memory for datetime string"); } } } void xmlrpc_read_datetime_str_old(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP) { assert(valueP->_cache); validateDatetimeType(envP, valueP); if (!envP->fault_occurred) { const char ** const readBufferP = valueP->_cache; if (!*readBufferP) /* Nobody's asked for the internal buffer before. Set it up. */ xmlrpc_read_datetime_str(envP, valueP, readBufferP); *stringValueP = *readBufferP; } } void xmlrpc_read_datetime_usec(xmlrpc_env * const envP, const xmlrpc_value * const valueP, time_t * const secsP, unsigned int * const usecsP) { validateDatetimeType(envP, valueP); if (!envP->fault_occurred) { if (valueP->_value.dt.Y < 1970) xmlrpc_faultf(envP, "Year (%u) is too early to represent as " "a standard Unix time", valueP->_value.dt.Y); else { struct tm brokenTime; const char * error; brokenTime.tm_sec = valueP->_value.dt.s; brokenTime.tm_min = valueP->_value.dt.m; brokenTime.tm_hour = valueP->_value.dt.h; brokenTime.tm_mday = valueP->_value.dt.D; brokenTime.tm_mon = valueP->_value.dt.M - 1; brokenTime.tm_year = valueP->_value.dt.Y - 1900; xmlrpc_timegm(&brokenTime, secsP, &error); if (error) { /* Ideally, this wouldn't be possible - it wouldn't be possible to create an xmlrpc_value that doesn't actually represent a real datetime. But today, we're lazy and don't fully validate incoming XML-RPC elements, and we also have the legacy xmlrpc_datetime_new_str() constructor to which the user may feed garbage. We should tighten that up and then simply assert here that xmlrpc_timegm() succeeded. */ xmlrpc_env_set_fault_formatted(envP, XMLRPC_PARSE_ERROR, "A datetime received in an XML-RPC message " "or generated with legacy Xmlrpc-c facilities " "does not validly describe a datetime. %s", error); xmlrpc_strfree(error); } else *usecsP = valueP->_value.dt.u; } } } void xmlrpc_read_datetime_sec(xmlrpc_env * const envP, const xmlrpc_value * const valueP, time_t * const timeValueP) { unsigned int usecs; xmlrpc_read_datetime_usec(envP, valueP, timeValueP, &usecs); } #if XMLRPC_HAVE_TIMEVAL void xmlrpc_read_datetime_timeval(xmlrpc_env * const envP, const xmlrpc_value * const valueP, struct timeval * const timeValueP) { time_t secs; unsigned int usecs; xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); timeValueP->tv_sec = secs; timeValueP->tv_usec = usecs; } #endif #if XMLRPC_HAVE_TIMESPEC void xmlrpc_read_datetime_timespec(xmlrpc_env * const envP, const xmlrpc_value * const valueP, struct timespec * const timeValueP) { time_t secs; unsigned int usecs; xmlrpc_read_datetime_usec(envP, valueP, &secs, &usecs); timeValueP->tv_sec = secs; timeValueP->tv_nsec = usecs * 1000; } #endif void xmlrpc_read_datetime_8601(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const iso8601ValueP) { /*---------------------------------------------------------------------------- Get the datetime in ISO 8601 format. ISO 8601 allows a variety of representations for each datetime. The particular one we return is as in the following example. 19930214T131030,250000Z (13:10:30.25 on February 14, 1993) There are always 4 digits for the year. There are always 6 digits after the comma (microseconds). Midnight is hour 0, not 24. -----------------------------------------------------------------------------*/ validateDatetimeType(envP, valueP); if (!envP->fault_occurred) { xmlrpc_datetime dt; xmlrpc_read_datetime(envP, valueP, &dt); if (!envP->fault_occurred) { if (dt.Y > 9999) xmlrpc_faultf(envP, "Too far in future (year %u). " "ISO 8601 cannot " "represent years after AD 9999", dt.Y); else { xmlrpc_asprintf(iso8601ValueP, "%04u%02u%02uT%02u%02u%02u,%06uZ", dt.Y, dt.M, dt.D, dt.h, dt.m, dt.s, dt.u); if (xmlrpc_strnomem(*iso8601ValueP)) xmlrpc_faultf(envP, "Unable to allocate memory " "for datetime string"); if (envP->fault_occurred) xmlrpc_strfree(*iso8601ValueP); } } } } xmlrpc_value * xmlrpc_datetime_new(xmlrpc_env * const envP, xmlrpc_datetime const dt) { xmlrpc_value * valP; const char ** readBufferP; MALLOCVAR(readBufferP); if (!readBufferP) xmlrpc_faultf(envP, "Couldn't get memory for the cache part of the " "XML-RPC datetime value object"); else { *readBufferP = NULL; xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_DATETIME; valP->_value.dt = dt; valP->_cache = readBufferP; } if (envP->fault_occurred) free(readBufferP); } return valP; } static void parseDatetimeString(const char * const datetimeString, xmlrpc_datetime * const dtP) { size_t const dtStrlen = strlen(datetimeString); char year[4+1]; char month[2+1]; char day[2+1]; char hour[2+1]; char minute[2+1]; char second[2+1]; /* Because we require input to be valid: */ assert(dtStrlen >= 17 && dtStrlen != 18 && dtStrlen <= 24); year[0] = datetimeString[ 0]; year[1] = datetimeString[ 1]; year[2] = datetimeString[ 2]; year[3] = datetimeString[ 3]; year[4] = '\0'; month[0] = datetimeString[ 4]; month[1] = datetimeString[ 5]; month[2] = '\0'; day[0] = datetimeString[ 6]; day[1] = datetimeString[ 7]; day[2] = '\0'; assert(datetimeString[ 8] == 'T'); hour[0] = datetimeString[ 9]; hour[1] = datetimeString[10]; hour[2] = '\0'; assert(datetimeString[11] == ':'); minute[0] = datetimeString[12]; minute[1] = datetimeString[13]; minute[2] = '\0'; assert(datetimeString[14] == ':'); second[0] = datetimeString[15]; second[1] = datetimeString[16]; second[2] = '\0'; if (dtStrlen > 17) { size_t const pad = 24 - dtStrlen; size_t i; dtP->u = atoi(&datetimeString[18]); for (i = 0; i < pad; ++i) dtP->u *= 10; } else dtP->u = 0; dtP->Y = atoi(year); dtP->M = atoi(month); dtP->D = atoi(day); dtP->h = atoi(hour); dtP->m = atoi(minute); dtP->s = atoi(second); } static void validateFirst17(xmlrpc_env * const envP, const char * const dt) { /*---------------------------------------------------------------------------- Assuming 'dt' is at least 17 characters long, validate that the first 17 characters are a valid XML-RPC datetime, e.g. "20080628T16:35:02" -----------------------------------------------------------------------------*/ unsigned int i; for (i = 0; i < 8 && !envP->fault_occurred; ++i) if (!isdigit(dt[i])) xmlrpc_faultf(envP, "Not a digit: '%c'", dt[i]); if (dt[8] != 'T') xmlrpc_faultf(envP, "9th character is '%c', not 'T'", dt[8]); if (!isdigit(dt[9])) xmlrpc_faultf(envP, "Not a digit: '%c'", dt[9]); if (!isdigit(dt[10])) xmlrpc_faultf(envP, "Not a digit: '%c'", dt[10]); if (dt[11] != ':') xmlrpc_faultf(envP, "Not a colon: '%c'", dt[11]); if (!isdigit(dt[12])) xmlrpc_faultf(envP, "Not a digit: '%c'", dt[12]); if (!isdigit(dt[13])) xmlrpc_faultf(envP, "Not a digit: '%c'", dt[13]); if (dt[14] != ':') xmlrpc_faultf(envP, "Not a colon: '%c'", dt[14]); if (!isdigit(dt[15])) xmlrpc_faultf(envP, "Not a digit: '%c'", dt[15]); if (!isdigit(dt[16])) xmlrpc_faultf(envP, "Not a digit: '%c'", dt[16]); } static void validateFractionalSeconds(xmlrpc_env * const envP, const char * const dt) { /*---------------------------------------------------------------------------- Validate the fractional seconds part of the XML-RPC datetime string 'dt', if any. That's the decimal point and everything following it. -----------------------------------------------------------------------------*/ if (strlen(dt) > 17) { if (dt[17] != '.') { xmlrpc_faultf(envP, "'%c' where only a period is valid", dt[17]); } else { if (dt[18] == '\0') xmlrpc_faultf(envP, "Nothing after decimal point"); else { unsigned int i; for (i = 18; dt[i] != '\0' && !envP->fault_occurred; ++i) { if (!isdigit(dt[i])) xmlrpc_faultf(envP, "Non-digit in fractional seconds: '%c'", dt[i]); } } } } } static void validateFormat(xmlrpc_env * const envP, const char * const dt) { if (strlen(dt) < 17) xmlrpc_faultf(envP, "Invalid length of %u of datetime string. " "Must be at least 17 characters", (unsigned)strlen(dt)); else { validateFirst17(envP, dt); if (!envP->fault_occurred) validateFractionalSeconds(envP, dt); } } /* Microsoft Visual C in debug mode produces code that complains about returning an undefined value from xmlrpc_datetime_new_str(). It's a bogus complaint, because this function is defined to return nothing meaningful those cases. So we disable the check. */ #pragma runtime_checks("u", off) xmlrpc_value * xmlrpc_datetime_new_str(xmlrpc_env * const envP, const char * const datetimeString) { /*---------------------------------------------------------------------------- This exists only for backward compatibility. Originally, this was the only way to create a datetime XML-RPC value, because we had a really lazy implementation of XML-RPC serialization and parsing (basically, the user did it!). Do not extend this. The user should use more normal C representations of datetimes. -----------------------------------------------------------------------------*/ xmlrpc_value * retval; validateFormat(envP, datetimeString); if (!envP->fault_occurred) { xmlrpc_datetime dt; parseDatetimeString(datetimeString, &dt); /* Note that parseDatetimeString() can generate an invalid datetime value, e.g. Hour 25 or February 30. Ideally, we would catch that here, but due to laziness, we simply accept the possibility of invalid xmlrpc_datetime in xmlrpc_value and whoever uses the the xmlrpc_value has to deal with it. */ retval = xmlrpc_datetime_new(envP, dt); } return retval; } #pragma runtime_checks("u", restore) xmlrpc_value * xmlrpc_datetime_new_usec(xmlrpc_env * const envP, time_t const secs, unsigned int const usecs) { xmlrpc_value * valueP; if (usecs >= 1000000) xmlrpc_faultf(envP, "Number of fractional microseconds must be less " "than one million. You specified %u", usecs); else { struct tm brokenTime; xmlrpc_datetime dt; xmlrpc_gmtime(secs, &brokenTime); dt.s = brokenTime.tm_sec; dt.m = brokenTime.tm_min; dt.h = brokenTime.tm_hour; dt.D = brokenTime.tm_mday; dt.M = brokenTime.tm_mon + 1; dt.Y = 1900 + brokenTime.tm_year; dt.u = usecs; valueP = xmlrpc_datetime_new(envP, dt); } return valueP; } xmlrpc_value * xmlrpc_datetime_new_sec(xmlrpc_env * const envP, time_t const value) { return xmlrpc_datetime_new_usec(envP, value, 0); } #if XMLRPC_HAVE_TIMEVAL xmlrpc_value * xmlrpc_datetime_new_timeval(xmlrpc_env * const envP, struct timeval const value) { return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_usec); } #endif #if XMLRPC_HAVE_TIMESPEC xmlrpc_value * xmlrpc_datetime_new_timespec(xmlrpc_env * const envP, struct timespec const value) { return xmlrpc_datetime_new_usec(envP, value.tv_sec, value.tv_nsec/1000); } #endif void xmlrpc_destroyDatetime(xmlrpc_value * const datetimeP) { const char ** const readBufferP = datetimeP->_cache; if (*readBufferP) xmlrpc_strfree(*readBufferP); free(datetimeP->_cache); } xmlrpc-c-1.33.14/src/xmlrpc_decompose.c000066400000000000000000001060431236133176700177230ustar00rootroot00000000000000/* By Bryan Henderson July 2006. Contributed to the public domain. */ #include "xmlrpc_config.h" #include #include #include #include #include "bool.h" #include "c_util.h" #include "mallocvar.h" #include "stdargx.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" /* THE DECOMPOSITION TREE We execute xmlrpc_decompose_value() in two steps: 1) Create a "decomposition tree" that tells how Caller wants the XML-RPC value decomposed. 2) Using that tree, decompose the value. I.e. store stuff in the variables in which Caller wants it stored. The decomposition tree is composed of information from the format string and the variable arguments that the format string describes. Nothing in the tree is derived from the actual XML-RPC value being decomposed, and the tree may in fact be invalid for the particular XML-RPC value it's meant for. If the XML-RPC value is a simple value such as an integer, the decomposition tree is trivial -- it's a single node that says "store the value of an integer via pointer P". Where it gets interesting is where the XML-RPC value to be decomposed is a complex value (array or struct). Then, the root node of the tree says, e.g., "decompose a 5-item array according to the following 5 decomposition trees" and it points to 5 additional nodes. Each of those nodes is the root of another decomposition tree (which can also be called a branch in this context). Each of those branches tells how to decompose one of the items of the array. Roots, interior nodes, and leaves are all essentially the same data type. */ struct integerDecomp { xmlrpc_int32 * valueP; }; struct boolDecomp { xmlrpc_bool * valueP; }; struct doubleDecomp { double * valueP; }; struct datetimeTDecomp { time_t * valueP; }; struct datetime8Decomp { const char ** valueP; }; struct stringDecomp { const char ** valueP; size_t * sizeP; /* NULL means don't store a size */ }; struct wideStringDecomp { #if HAVE_UNICODE_WCHAR const wchar_t ** valueP; #endif size_t * sizeP; /* NULL means don't store a size */ }; struct bitStringDecomp { const unsigned char ** valueP; size_t * sizeP; }; struct cptrDecomp { void ** valueP; }; struct i8Decomp { xmlrpc_int64 * valueP; }; struct valueDecomp { xmlrpc_value ** valueP; }; struct arrayValDecomp { xmlrpc_value ** valueP; }; struct structValDecomp { xmlrpc_value ** valueP; }; struct arrayDecomp { unsigned int itemCnt; bool ignoreExcess; /* If there are more that 'itemCnt' items in the array, just extract the first 'itemCnt' and ignore the rest, rather than fail the decomposition. */ struct decompTreeNode * itemArray[16]; /* Only first 'itemCnt' elements of this array are defined */ }; struct mbrDecomp { const char * key; /* The key for the member whose value client wants to extract */ struct decompTreeNode * decompTreeP; /* Instructions on how to decompose (extract) member's value */ }; struct structDecomp { unsigned int mbrCnt; struct mbrDecomp mbrArray[16]; }; struct decompTreeNode { char formatSpecChar; /* e.g. 'i', 'b', '8', 'A'. '(' means array; '{' means struct */ union { /*------------------------------------------------------------------------ 'formatSpecChar' selects among these members. -------------------------------------------------------------------------*/ struct integerDecomp Tinteger; struct boolDecomp Tbool; struct doubleDecomp Tdouble; struct datetimeTDecomp TdatetimeT; struct datetime8Decomp Tdatetime8; struct stringDecomp Tstring; struct wideStringDecomp TwideString; struct bitStringDecomp TbitString; struct cptrDecomp Tcptr; struct i8Decomp Ti8; struct valueDecomp Tvalue; struct arrayValDecomp TarrayVal; struct structValDecomp TstructVal; struct arrayDecomp Tarray; struct structDecomp Tstruct; } store; }; /* prototype for recursive calls */ static void releaseDecomposition(const struct decompTreeNode * const decompRootP); static void releaseDecompArray(struct arrayDecomp const arrayDecomp) { unsigned int i; for (i = 0; i < arrayDecomp.itemCnt; ++i) { releaseDecomposition(arrayDecomp.itemArray[i]); } } static void releaseDecompStruct(struct structDecomp const structDecomp) { unsigned int i; for (i = 0; i < structDecomp.mbrCnt; ++i) { releaseDecomposition(structDecomp.mbrArray[i].decompTreeP); } } static void releaseDecomposition(const struct decompTreeNode * const decompRootP) { /*---------------------------------------------------------------------------- Assuming that Caller has decomposed something according to 'decompRootP', release whatever resources the decomposed information occupies. E.g. if it's an XML-RPC string, Caller would have allocated memory for the C string that represents the decomposed value of XML-RPC string, and we release that memory. -----------------------------------------------------------------------------*/ switch (decompRootP->formatSpecChar) { case 'i': case 'b': case 'd': case 'n': case 'I': case 't': case 'p': /* Nothing was allocated; nothing to release */ break; case '8': xmlrpc_strfree(*decompRootP->store.Tdatetime8.valueP); break; case 's': xmlrpc_strfree(*decompRootP->store.Tstring.valueP); break; case 'w': free((void*)*decompRootP->store.TwideString.valueP); break; case '6': free((void*)*decompRootP->store.TbitString.valueP); break; case 'V': xmlrpc_DECREF(*decompRootP->store.Tvalue.valueP); break; case 'A': xmlrpc_DECREF(*decompRootP->store.TarrayVal.valueP); break; case 'S': xmlrpc_DECREF(*decompRootP->store.TstructVal.valueP); break; case '(': releaseDecompArray(decompRootP->store.Tarray); break; case '{': releaseDecompStruct(decompRootP->store.Tstruct); break; } } /* Prototype for recursive invocation: */ static void decomposeValueWithTree(xmlrpc_env * const envP, xmlrpc_value * const valueP, bool const oldstyleMemMgmt, const struct decompTreeNode * const decompRootP); static void validateArraySize(xmlrpc_env * const envP, const xmlrpc_value * const arrayP, struct arrayDecomp const arrayDecomp) { unsigned int size; size = xmlrpc_array_size(envP, arrayP); if (!envP->fault_occurred) { if (arrayDecomp.itemCnt > size) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "Format string requests %u items from array, but array " "has only %u items.", arrayDecomp.itemCnt, size); else if (arrayDecomp.itemCnt < size && !arrayDecomp.ignoreExcess) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "Format string requests exactly %u items from array, " "but array has %u items. (A '*' at the end would avoid " "this failure)", arrayDecomp.itemCnt, size); } } static void parsearray(xmlrpc_env * const envP, const xmlrpc_value * const arrayP, struct arrayDecomp const arrayDecomp, bool const oldstyleMemMgmt) { validateArraySize(envP, arrayP, arrayDecomp); if (!envP->fault_occurred) { unsigned int doneCnt; doneCnt = 0; while(doneCnt < arrayDecomp.itemCnt && !envP->fault_occurred) { xmlrpc_value * itemP; xmlrpc_array_read_item(envP, arrayP, doneCnt, &itemP); if (!envP->fault_occurred) { XMLRPC_ASSERT(doneCnt < ARRAY_SIZE(arrayDecomp.itemArray)); decomposeValueWithTree(envP, itemP, oldstyleMemMgmt, arrayDecomp.itemArray[doneCnt]); if (!envP->fault_occurred) ++doneCnt; xmlrpc_DECREF(itemP); } } if (envP->fault_occurred) { if (!oldstyleMemMgmt) { /* Release the items we completed before we failed. */ unsigned int i; for (i = 0; i < doneCnt; ++i) releaseDecomposition(arrayDecomp.itemArray[i]); } } } } static void parsestruct(xmlrpc_env * const envP, xmlrpc_value * const structP, struct structDecomp const structDecomp, bool const oldstyleMemMgmt) { unsigned int doneCount; doneCount = 0; /* No members done yet */ while (doneCount < structDecomp.mbrCnt && !envP->fault_occurred) { const char * const key = structDecomp.mbrArray[doneCount].key; xmlrpc_value * valueP; xmlrpc_struct_read_value(envP, structP, key, &valueP); if (!envP->fault_occurred) { decomposeValueWithTree( envP, valueP, oldstyleMemMgmt, structDecomp.mbrArray[doneCount].decompTreeP); if (!envP->fault_occurred) ++doneCount; xmlrpc_DECREF(valueP); } } if (envP->fault_occurred) { if (!oldstyleMemMgmt) { /* Release the items we completed before we failed. */ unsigned int i; for (i = 0; i < doneCount; ++i) releaseDecomposition(structDecomp.mbrArray[i].decompTreeP); } } } static void readString(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP, bool const oldstyleMemMgmt) { if (oldstyleMemMgmt) { xmlrpc_read_string_old(envP, valueP, stringValueP); } else xmlrpc_read_string(envP, valueP, stringValueP); } static void readStringLp(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const char ** const stringValueP, bool const oldstyleMemMgmt) { if (oldstyleMemMgmt) { xmlrpc_read_string_lp_old(envP, valueP, lengthP, stringValueP); } else xmlrpc_read_string_lp(envP, valueP, lengthP, stringValueP); } #if HAVE_UNICODE_WCHAR static void readStringW(xmlrpc_env * const envP, xmlrpc_value * const valueP, const wchar_t ** const stringValueP, bool const oldstyleMemMgmt) { if (oldstyleMemMgmt) { xmlrpc_read_string_w_old(envP, valueP, stringValueP); } else xmlrpc_read_string_w(envP, valueP, stringValueP); } static void readStringWLp(xmlrpc_env * const envP, xmlrpc_value * const valueP, size_t * const lengthP, const wchar_t ** const stringValueP, bool const oldstyleMemMgmt) { if (oldstyleMemMgmt) { xmlrpc_read_string_w_lp_old(envP, valueP, lengthP, stringValueP); } else xmlrpc_read_string_w_lp(envP, valueP, lengthP, stringValueP); } #endif static void readDatetime8Str(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP, bool const oldstyleMemMgmt) { if (oldstyleMemMgmt) xmlrpc_read_datetime_str_old(envP, valueP, stringValueP); else xmlrpc_read_datetime_str(envP, valueP, stringValueP); } static void readBase64(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const unsigned char ** const byteStringValueP, bool const oldstyleMemMgmt) { if (oldstyleMemMgmt) xmlrpc_read_base64_old(envP, valueP, lengthP, byteStringValueP); else xmlrpc_read_base64(envP, valueP, lengthP, byteStringValueP); } static void decomposeValueWithTree(xmlrpc_env * const envP, xmlrpc_value * const valueP, bool const oldstyleMemMgmt, const struct decompTreeNode * const decompRootP) { /*---------------------------------------------------------------------------- Decompose XML-RPC value *valueP, given the decomposition tree *decompRootP. The decomposition tree tells what structure *valueP is expected to have and where to put the various components of it (e.g. it says "it's an array of 3 integers. Put their values at locations x, y, and z") -----------------------------------------------------------------------------*/ switch (decompRootP->formatSpecChar) { case '-': /* There's nothing to validate or return */ break; case 'i': xmlrpc_read_int(envP, valueP, decompRootP->store.Tinteger.valueP); break; case 'b': xmlrpc_read_bool(envP, valueP, decompRootP->store.Tbool.valueP); break; case 'd': xmlrpc_read_double(envP, valueP, decompRootP->store.Tdouble.valueP); break; case 't': xmlrpc_read_datetime_sec(envP, valueP, decompRootP->store.TdatetimeT.valueP); break; case '8': readDatetime8Str(envP, valueP, decompRootP->store.Tdatetime8.valueP, oldstyleMemMgmt); break; case 's': if (decompRootP->store.Tstring.sizeP) readStringLp(envP, valueP, decompRootP->store.Tstring.sizeP, decompRootP->store.Tstring.valueP, oldstyleMemMgmt); else readString(envP, valueP, decompRootP->store.Tstring.valueP, oldstyleMemMgmt); break; case 'w': #if HAVE_UNICODE_WCHAR if (decompRootP->store.Tstring.sizeP) readStringWLp(envP, valueP, decompRootP->store.TwideString.sizeP, decompRootP->store.TwideString.valueP, oldstyleMemMgmt); else readStringW(envP, valueP, decompRootP->store.TwideString.valueP, oldstyleMemMgmt); #else XMLRPC_ASSERT(false); #endif /* HAVE_UNICODE_WCHAR */ break; case '6': readBase64(envP, valueP, decompRootP->store.TbitString.sizeP, decompRootP->store.TbitString.valueP, oldstyleMemMgmt); break; case 'n': xmlrpc_read_nil(envP, valueP); break; case 'I': xmlrpc_read_i8(envP, valueP, decompRootP->store.Ti8.valueP); break; case 'p': xmlrpc_read_cptr(envP, valueP, decompRootP->store.Tcptr.valueP); break; case 'V': *decompRootP->store.Tvalue.valueP = valueP; if (!oldstyleMemMgmt) xmlrpc_INCREF(valueP); break; case 'A': if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value to be decomposed is of type " "%s, but the 'A' specifier requires type ARRAY", xmlrpc_type_name(xmlrpc_value_type(valueP))); else { *decompRootP->store.TarrayVal.valueP = valueP; if (!oldstyleMemMgmt) xmlrpc_INCREF(valueP); } break; case 'S': if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value to be decomposed is of type " "%s, but the 'S' specifier requires type STRUCT.", xmlrpc_type_name(xmlrpc_value_type(valueP))); else { *decompRootP->store.TstructVal.valueP = valueP; if (!oldstyleMemMgmt) xmlrpc_INCREF(valueP); } break; case '(': if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_ARRAY) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value to be decomposed is of type " "%s, but the '(...)' specifier requires type ARRAY", xmlrpc_type_name(xmlrpc_value_type(valueP))); else parsearray(envP, valueP, decompRootP->store.Tarray, oldstyleMemMgmt); break; case '{': if (xmlrpc_value_type(valueP) != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value to be decomposed is of type " "%s, but the '{...}' specifier requires type STRUCT", xmlrpc_type_name(xmlrpc_value_type(valueP))); else parsestruct(envP, valueP, decompRootP->store.Tstruct, oldstyleMemMgmt); break; default: /* Every format character that is allowed in a decomposition tree node is handled above. */ XMLRPC_ASSERT(false); } } /* Forward declaration for recursive calls */ static void createDecompTreeNext(xmlrpc_env * const envP, const char ** const formatP, va_listx * const argsP, struct decompTreeNode ** const decompNodePP); static void buildWideStringNode(xmlrpc_env * const envP ATTR_UNUSED, const char ** const formatP, va_listx * const argsP, struct decompTreeNode * const decompNodeP) { #if HAVE_UNICODE_WCHAR decompNodeP->store.TwideString.valueP = (const wchar_t**) va_arg(argsP->v, wchar_t**); if (**formatP == '#') { decompNodeP->store.TwideString.sizeP = (size_t*) va_arg(argsP->v, size_t**); (*formatP)++; } else decompNodeP->store.TwideString.sizeP = NULL; #else xmlrpc_faultf(envP, "This XML-RPC For C/C++ library was built without Unicode " "wide character capability. 'w' isn't available."); #endif /* HAVE_UNICODE_WCHAR */ } static void destroyDecompTree(struct decompTreeNode * const decompRootP) { switch (decompRootP->formatSpecChar) { case '(': { unsigned int i; for (i = 0; i < decompRootP->store.Tarray.itemCnt; ++i) destroyDecompTree(decompRootP->store.Tarray.itemArray[i]); } break; case '{': { unsigned int i; for (i = 0; i < decompRootP->store.Tstruct.mbrCnt; ++i) destroyDecompTree( decompRootP->store.Tstruct.mbrArray[i].decompTreeP); } break; } free(decompRootP); } static void processArraySpecTail(xmlrpc_env * const envP, const char ** const formatP, bool * const hasTrailingAsteriskP, char const delim) { if (**formatP == '*') { *hasTrailingAsteriskP = true; ++*formatP; if (!**formatP) xmlrpc_faultf(envP, "missing closing delimiter ('%c')", delim); else if (**formatP != delim) xmlrpc_faultf(envP, "character following '*' in array " "specification should be the closing delimiter " "'%c', but is '%c'", delim, **formatP); } else { *hasTrailingAsteriskP = false; if (!**formatP) xmlrpc_faultf(envP, "missing closing delimiter ('%c')", delim); } if (!envP->fault_occurred) XMLRPC_ASSERT(**formatP == delim); } static void buildArrayDecompBranch(xmlrpc_env * const envP, const char ** const formatP, char const delim, va_listx * const argsP, struct decompTreeNode * const decompNodeP) { /*---------------------------------------------------------------------------- Fill in the decomposition tree node *decompNodeP to cover an array whose items are described by *formatP. To wit, they are the values described by successive format specifiers in *formatP up to but not including the next 'delim' character. Plus, the last character before the delimiter might be a '*', which means "ignore any additional items in the array." We create a node (and whole branch if required) to describe each array item. The pointers to where those items are to be stored are given by 'argsP'. We advance *formatP to the delimiter character, and advance 'argsP' past whatever arguments we use. -----------------------------------------------------------------------------*/ unsigned int itemCnt; /* Number of array items in the branch so far */ itemCnt = 0; /* Branch is empty so far */ while (**formatP && **formatP != delim && **formatP != '*' && !envP->fault_occurred) { if (itemCnt >= ARRAY_SIZE(decompNodeP->store.Tarray.itemArray)) xmlrpc_faultf(envP, "Too many array items in format string. " "The most items you can have for an array in " "a format string is %u.", (unsigned) ARRAY_SIZE(decompNodeP->store.Tarray.itemArray)); else { struct decompTreeNode * itemNodeP; createDecompTreeNext(envP, formatP, argsP, &itemNodeP); if (!envP->fault_occurred) decompNodeP->store.Tarray.itemArray[itemCnt++] = itemNodeP; } } if (!envP->fault_occurred) { decompNodeP->store.Tarray.itemCnt = itemCnt; processArraySpecTail(envP, formatP, &decompNodeP->store.Tarray.ignoreExcess, delim); } if (envP->fault_occurred) { unsigned int i; for (i = 0; i < itemCnt; ++i) destroyDecompTree(decompNodeP->store.Tarray.itemArray[i]); } } static void doStructValue(xmlrpc_env * const envP, const char ** const formatP, va_listx * const argsP, struct mbrDecomp * const mbrP) { struct decompTreeNode * valueNodeP; mbrP->key = (const char*) va_arg(argsP->v, char*); createDecompTreeNext(envP, formatP, argsP, &valueNodeP); if (!envP->fault_occurred) mbrP->decompTreeP = valueNodeP; } static void skipAsterisk(xmlrpc_env * const envP, const char ** const formatP, char const delim) { if (**formatP == '*') { ++*formatP; if (!**formatP) xmlrpc_faultf(envP, "missing closing delimiter ('%c')", delim); else if (**formatP != delim) xmlrpc_faultf(envP, "junk after '*' in the specifier of an " "array. First character='%c'", **formatP); } else /* Conceptually, one can make it an error to leave some struct members behind, but we have never had code that knows how to recognize that case. */ xmlrpc_faultf(envP, "You must put a trailing '*' in the specifiers for " "struct members to signify it's OK if there are " "additional members you didn't get."); } static void skipColon(xmlrpc_env * const envP, const char ** const formatP, char const delim) { if (**formatP == '\0') xmlrpc_faultf(envP, "format string ends in the middle of a struct " "member specifier"); else if (**formatP == delim) xmlrpc_faultf(envP, "member list ends in the middle of a member"); else if (**formatP != ':') xmlrpc_faultf(envP, "In a struct specifier, '%c' found " "where a colon (':') separating key and " "value was expected.", **formatP); } static void skipComma(xmlrpc_env * const envP, const char ** const formatP, char const delim) { if (**formatP && **formatP != delim) { if (**formatP == ',') ++*formatP; /* skip over comma */ else xmlrpc_faultf(envP, "'%c' where we expected a ',' " "to separate struct members", **formatP); } } static void buildStructDecompBranch(xmlrpc_env * const envP, const char ** const formatP, char const delim, va_listx * const argsP, struct decompTreeNode * const decompNodeP) { /*---------------------------------------------------------------------------- Fill in the decomposition tree node *decompNodeP to cover a struct whose members are described by *formatP. To wit, they are the values described by successive format specifiers in *formatP up to but not including the next 'delim' character. We create a node (and whole branch if required) to describe each struct member value. The pointers to where those values are to be stored are given by 'argsP'. The names of the members to be extracted are also given by 'argsP'. We advance *formatP to the delimiter character, and advance 'argsP' past whatever arguments we use. -----------------------------------------------------------------------------*/ unsigned int memberCnt; /* Number of struct members in the branch so far */ memberCnt = 0; /* Branch is empty so far */ while (**formatP && **formatP != delim && **formatP != '*' && !envP->fault_occurred) { if (memberCnt >= ARRAY_SIZE(decompNodeP->store.Tstruct.mbrArray)) xmlrpc_faultf(envP, "Too many structure members in format string. " "The most members you can specify in " "a format string is %u.", (unsigned) ARRAY_SIZE(decompNodeP->store.Tstruct.mbrArray)); else { struct mbrDecomp * const mbrP = &decompNodeP->store.Tstruct.mbrArray[memberCnt]; if (**formatP != 's') xmlrpc_faultf(envP, "In a struct specifier, the specifier " "for the key is '%c', but it must be 's'.", **formatP); else { ++*formatP; skipColon(envP, formatP, delim); if (!envP->fault_occurred) { ++*formatP; doStructValue(envP, formatP, argsP, mbrP); if (!envP->fault_occurred) ++memberCnt; skipComma(envP, formatP, delim); } } } } decompNodeP->store.Tstruct.mbrCnt = memberCnt; if (!envP->fault_occurred) { skipAsterisk(envP, formatP, delim); if (!envP->fault_occurred) XMLRPC_ASSERT(**formatP == delim); } if (envP->fault_occurred) { unsigned int i; for (i = 0; i < memberCnt; ++i) destroyDecompTree( decompNodeP->store.Tstruct.mbrArray[i].decompTreeP); } } static void createDecompTreeNext(xmlrpc_env * const envP, const char ** const formatP, va_listx * const argsP, struct decompTreeNode ** const decompNodePP) { /*---------------------------------------------------------------------------- Create a branch of a decomposition tree that applies to the first value described by '*formatP', and advance *formatP past the description of that first value. E.g.: - If *formatP is "isb", we create a branch consisting of one node -- for an integer. We advance *formatP by one character, so it points to the "s". - If *formatP is "(isb)s", we create a branch that represents the array (isb) and advance *formatP past the closing parenthesis to point to the final "s". We return as *decompNodePP a pointer to a node for the array, and that array in turn points to nodes for each of the 3 array items: one for an integer, one for a string, and one for a boolean. The locations at which the components of that value are to be stored (which is the main contents of the branch we create) are given by 'argsP'. Return as *decompNodeP a pointer to the root node of the branch we generate. -----------------------------------------------------------------------------*/ struct decompTreeNode * decompNodeP; MALLOCVAR(decompNodeP); if (decompNodeP == NULL) xmlrpc_faultf(envP, "Could not allocate space for a decomposition " "tree node"); else { decompNodeP->formatSpecChar = *(*formatP)++; switch (decompNodeP->formatSpecChar) { case '-': /* There's nothing to store */ break; case 'i': decompNodeP->store.Tinteger.valueP = (xmlrpc_int32*) va_arg(argsP->v, xmlrpc_int32*); break; case 'b': decompNodeP->store.Tbool.valueP = (xmlrpc_bool*) va_arg(argsP->v, xmlrpc_bool*); break; case 'd': decompNodeP->store.Tdouble.valueP = (double*) va_arg(argsP->v, double*); break; case 't': decompNodeP->store.TdatetimeT.valueP = va_arg(argsP->v, time_t*); break; case '8': decompNodeP->store.Tdatetime8.valueP = (const char**) va_arg(argsP->v, char**); break; case 's': decompNodeP->store.Tstring.valueP = (const char**) va_arg(argsP->v, char**); if (**formatP == '#') { decompNodeP->store.Tstring.sizeP = (size_t*) va_arg(argsP->v, size_t**); ++*formatP; } else decompNodeP->store.Tstring.sizeP = NULL; break; case 'w': buildWideStringNode(envP, formatP, argsP, decompNodeP); break; case '6': decompNodeP->store.TbitString.valueP = (const unsigned char**) va_arg(argsP->v, unsigned char**); decompNodeP->store.TbitString.sizeP = (size_t*) va_arg(argsP->v, size_t**); break; case 'n': /* There's no value to store */ break; case 'I': decompNodeP->store.Ti8.valueP = (xmlrpc_int64 *) va_arg(argsP->v, xmlrpc_int64 *); break; case 'p': decompNodeP->store.Tcptr.valueP = (void**) va_arg(argsP->v, void**); break; case 'V': decompNodeP->store.Tvalue.valueP = (xmlrpc_value**) va_arg(argsP->v, xmlrpc_value**); break; case 'A': decompNodeP->store.TarrayVal.valueP = (xmlrpc_value**) va_arg(argsP->v, xmlrpc_value**); break; case 'S': decompNodeP->store.TstructVal.valueP = (xmlrpc_value**) va_arg(argsP->v, xmlrpc_value**); break; case '(': buildArrayDecompBranch(envP, formatP, ')', argsP, decompNodeP); ++(*formatP); /* skip past closing ')' */ break; case '{': buildStructDecompBranch(envP, formatP, '}', argsP, decompNodeP); ++(*formatP); /* skip past closing '}' */ break; default: xmlrpc_faultf(envP, "Invalid format character '%c'", decompNodeP->formatSpecChar); } if (envP->fault_occurred) free(decompNodeP); else *decompNodePP = decompNodeP; } } static void createDecompTree(xmlrpc_env * const envP, const char * const format, va_listx const args, struct decompTreeNode ** const decompRootPP) { const char * formatCursor; struct decompTreeNode * decompRootP; va_listx currentArgs; currentArgs = args; formatCursor = &format[0]; createDecompTreeNext(envP, &formatCursor, ¤tArgs, &decompRootP); if (!envP->fault_occurred) { if (*formatCursor != '\0') xmlrpc_faultf(envP, "format string '%s' has garbage at the end: " "'%s'. It should be a specifier of a single value " "(but that might be a complex value, such as an " "array)", format, formatCursor); if (envP->fault_occurred) destroyDecompTree(decompRootP); } *decompRootPP = decompRootP; } static void decomposeValue(xmlrpc_env * const envP, xmlrpc_value * const valueP, bool const oldstyleMemMgmt, const char * const format, va_listx const args) { struct decompTreeNode * decompRootP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(valueP); XMLRPC_ASSERT(format != NULL); createDecompTree(envP, format, args, &decompRootP); if (!envP->fault_occurred) { decomposeValueWithTree(envP, valueP, oldstyleMemMgmt, decompRootP); destroyDecompTree(decompRootP); } } void xmlrpc_decompose_value_va(xmlrpc_env * const envP, xmlrpc_value * const valueP, const char * const format, va_list const args) { bool const oldstyleMemMgtFalse = false; va_listx argsx; init_va_listx(&argsx, args); decomposeValue(envP, valueP, oldstyleMemMgtFalse, format, argsx); } void xmlrpc_decompose_value(xmlrpc_env * const envP, xmlrpc_value * const value, const char * const format, ...) { va_list args; va_start(args, format); xmlrpc_decompose_value_va(envP, value, format, args); va_end(args); } void xmlrpc_parse_value_va(xmlrpc_env * const envP, xmlrpc_value * const valueP, const char * const format, va_list const args) { bool const oldstyleMemMgmtTrue = true; va_listx argsx; init_va_listx(&argsx, args); decomposeValue(envP, valueP, oldstyleMemMgmtTrue, format, argsx); } void xmlrpc_parse_value(xmlrpc_env * const envP, xmlrpc_value * const value, const char * const format, ...) { va_list args; va_start(args, format); xmlrpc_parse_value_va(envP, value, format, args); va_end(args); } xmlrpc-c-1.33.14/src/xmlrpc_expat.c000066400000000000000000000373651236133176700171000ustar00rootroot00000000000000/* Copyright information is at end of file */ #include "xmlrpc_config.h" #include #include #include #include /* Expat */ #include "bool.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/xmlparser.h" /* Define the contents of our internal structure. */ struct _xml_element { struct _xml_element *_parent; char *_name; xmlrpc_mem_block _cdata; /* char */ xmlrpc_mem_block _children; /* xml_element* */ }; /* Check that we're using expat in UTF-8 mode, not wchar_t mode. ** If you need to use expat in wchar_t mode, write a subroutine to ** copy a wchar_t string to a char string & return an error for ** any non-ASCII characters. Then call this subroutine on all ** XML_Char strings passed to our event handlers before using the ** data. */ /* #if sizeof(char) != sizeof(XML_Char) ** #error expat must define XML_Char to be a regular char. ** #endif */ #define XMLRPC_ASSERT_ELEM_OK(elem) \ XMLRPC_ASSERT((elem) != NULL && (elem)->_name != XMLRPC_BAD_POINTER) void xml_init(xmlrpc_env * const envP) { XMLRPC_ASSERT_ENV_OK(envP); } void xml_term(void) { } /*========================================================================= ** xml_element_new **========================================================================= ** Create a new xml_element. This routine isn't exported, because the ** arguments are implementation-dependent. */ static xml_element * xml_element_new (xmlrpc_env * const env, const char * const name) { xml_element *retval; int name_valid, cdata_valid, children_valid; XMLRPC_ASSERT_ENV_OK(env); XMLRPC_ASSERT(name != NULL); /* Set up our error-handling preconditions. */ retval = NULL; name_valid = cdata_valid = children_valid = 0; /* Allocate our xml_element structure. */ retval = (xml_element*) malloc(sizeof(xml_element)); XMLRPC_FAIL_IF_NULL(retval, env, XMLRPC_INTERNAL_ERROR, "Couldn't allocate memory for XML element"); /* Set our parent field to NULL. */ retval->_parent = NULL; /* Copy over the element name. */ retval->_name = (char*) malloc(strlen(name) + 1); XMLRPC_FAIL_IF_NULL(retval->_name, env, XMLRPC_INTERNAL_ERROR, "Couldn't allocate memory for XML element"); name_valid = 1; strcpy(retval->_name, name); /* Initialize a block to hold our CDATA. */ XMLRPC_TYPED_MEM_BLOCK_INIT(char, env, &retval->_cdata, 0); XMLRPC_FAIL_IF_FAULT(env); cdata_valid = 1; /* Initialize a block to hold our child elements. */ XMLRPC_TYPED_MEM_BLOCK_INIT(xml_element*, env, &retval->_children, 0); XMLRPC_FAIL_IF_FAULT(env); children_valid = 1; cleanup: if (env->fault_occurred) { if (retval) { if (name_valid) free(retval->_name); if (cdata_valid) xmlrpc_mem_block_clean(&retval->_cdata); if (children_valid) xmlrpc_mem_block_clean(&retval->_children); free(retval); } return NULL; } else { return retval; } } /*========================================================================= ** xml_element_free **========================================================================= ** Blow away an existing element & all of its child elements. */ void xml_element_free(xml_element * const elemP) { xmlrpc_mem_block * childrenP; size_t size, i; xml_element ** contents; XMLRPC_ASSERT_ELEM_OK(elemP); free(elemP->_name); elemP->_name = XMLRPC_BAD_POINTER; XMLRPC_MEMBLOCK_CLEAN(xml_element *, &elemP->_cdata); /* Deallocate all of our children recursively. */ childrenP = &elemP->_children; contents = XMLRPC_MEMBLOCK_CONTENTS(xml_element *, childrenP); size = XMLRPC_MEMBLOCK_SIZE(xml_element *, childrenP); for (i = 0; i < size; ++i) xml_element_free(contents[i]); XMLRPC_MEMBLOCK_CLEAN(xml_element *, &elemP->_children); free(elemP); } /*========================================================================= ** Miscellaneous Accessors **========================================================================= ** Return the fields of the xml_element. See the header for more ** documentation on each function works. */ const char * xml_element_name(const xml_element * const elemP) { XMLRPC_ASSERT_ELEM_OK(elemP); return elemP->_name; } /* The result of this function is NOT VALID until the end_element handler ** has been called! */ size_t xml_element_cdata_size (xml_element *elem) { XMLRPC_ASSERT_ELEM_OK(elem); return XMLRPC_TYPED_MEM_BLOCK_SIZE(char, &elem->_cdata) - 1; } char *xml_element_cdata (xml_element *elem) { XMLRPC_ASSERT_ELEM_OK(elem); return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &elem->_cdata); } size_t xml_element_children_size(const xml_element * const elemP) { XMLRPC_ASSERT_ELEM_OK(elemP); return XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element *, &elemP->_children); } xml_element ** xml_element_children(const xml_element * const elemP) { XMLRPC_ASSERT_ELEM_OK(elemP); return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element *, &elemP->_children); } /*========================================================================= ** Internal xml_element Utility Functions **========================================================================= */ static void xml_element_append_cdata (xmlrpc_env *env, xml_element *elem, char *cdata, size_t size) { XMLRPC_ASSERT_ENV_OK(env); XMLRPC_ASSERT_ELEM_OK(elem); XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, &elem->_cdata, cdata, size); } /* Whether or not this function succeeds, it takes ownership of the 'child' ** argument. ** WARNING - This is the exact opposite of the usual memory ownership ** rules for xmlrpc_value! So please pay attention. */ static void xml_element_append_child (xmlrpc_env *env, xml_element *elem, xml_element *child) { XMLRPC_ASSERT_ENV_OK(env); XMLRPC_ASSERT_ELEM_OK(elem); XMLRPC_ASSERT_ELEM_OK(child); XMLRPC_ASSERT(child->_parent == NULL); XMLRPC_TYPED_MEM_BLOCK_APPEND(xml_element*, env, &elem->_children, &child, 1); if (!env->fault_occurred) child->_parent = elem; else xml_element_free(child); } /*========================================================================= ** Our parse context. We pass this around as expat user data. **========================================================================= */ typedef struct { xmlrpc_env env; xml_element * rootP; xml_element * currentP; } parseContext; /*========================================================================= ** Expat Event Handler Functions **========================================================================= */ static void startElement(void * const userData, XML_Char * const name, XML_Char ** const atts ATTR_UNUSED) { parseContext * const contextP = userData; XMLRPC_ASSERT(contextP != NULL); XMLRPC_ASSERT(name != NULL); if (!contextP->env.fault_occurred) { xml_element * elemP; elemP = xml_element_new(&contextP->env, name); if (!contextP->env.fault_occurred) { XMLRPC_ASSERT(elemP != NULL); /* Insert the new element in the appropriate place. */ if (!contextP->rootP) { /* No root yet, so this element must be the root. */ contextP->rootP = elemP; contextP->currentP = elemP; } else { XMLRPC_ASSERT(contextP->currentP != NULL); /* (We need to watch our error handling invariants very carefully here. Read the docs for xml_element_append_child. */ xml_element_append_child(&contextP->env, contextP->currentP, elemP); if (!contextP->env.fault_occurred) contextP->currentP = elemP; } if (contextP->env.fault_occurred) xml_element_free(elemP); } if (contextP->env.fault_occurred) { /* Having changed *contextP to reflect failure, we are responsible for undoing everything that has been done so far in this context. */ if (contextP->rootP) xml_element_free(contextP->rootP); } } } static void endElement(void * const userData, XML_Char * const name ATTR_UNUSED) { parseContext * const contextP = userData; XMLRPC_ASSERT(contextP != NULL); XMLRPC_ASSERT(name != NULL); if (!contextP->env.fault_occurred) { /* I think Expat enforces these facts: */ XMLRPC_ASSERT(xmlrpc_streq(name, contextP->currentP->_name)); XMLRPC_ASSERT(contextP->currentP->_parent != NULL || contextP->currentP == contextP->rootP); /* Add a trailing NUL to our cdata. */ xml_element_append_cdata(&contextP->env, contextP->currentP, "\0", 1); if (!contextP->env.fault_occurred) /* Pop our "stack" of elements. */ contextP->currentP = contextP->currentP->_parent; if (contextP->env.fault_occurred) { /* Having changed *contextP to reflect failure, we are responsible for undoing everything that has been done so far in this context. */ if (contextP->rootP) xml_element_free(contextP->rootP); } } } static void characterData(void * const userData, XML_Char * const s, int const len) { /*---------------------------------------------------------------------------- This is an Expat character data (cdata) handler. When an Expat parser comes across cdata, he calls one of these with the cdata as argument. He can call it multiple times for consecutive cdata. We simply append the cdata to the cdata buffer for whatever XML element the parser is presently parsing. -----------------------------------------------------------------------------*/ parseContext * const contextP = userData; XMLRPC_ASSERT(contextP != NULL); XMLRPC_ASSERT(s != NULL); XMLRPC_ASSERT(len >= 0); if (!contextP->env.fault_occurred) { XMLRPC_ASSERT(contextP->currentP != NULL); xml_element_append_cdata(&contextP->env, contextP->currentP, s, len); } } static void createParser(xmlrpc_env * const envP, parseContext * const contextP, XML_Parser * const parserP) { /*---------------------------------------------------------------------------- Create an Expat parser to parse our XML. -----------------------------------------------------------------------------*/ XML_Parser parser; parser = xmlrpc_XML_ParserCreate(NULL); if (parser == NULL) xmlrpc_faultf(envP, "Could not create expat parser"); else { /* Initialize our parse context. */ xmlrpc_env_init(&contextP->env); contextP->rootP = NULL; contextP->currentP = NULL; xmlrpc_XML_SetUserData(parser, contextP); xmlrpc_XML_SetElementHandler( parser, (XML_StartElementHandler) startElement, (XML_EndElementHandler) endElement); xmlrpc_XML_SetCharacterDataHandler( parser, (XML_CharacterDataHandler) characterData); } *parserP = parser; } static void destroyParser(XML_Parser const parser, parseContext * const contextP) { xmlrpc_env_clean(&contextP->env); xmlrpc_XML_ParserFree(parser); } void xml_parse(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xml_element ** const resultPP) { /*---------------------------------------------------------------------------- Parse the XML text 'xmlData', of length 'xmlDataLen'. Return the description of the element that the XML text contains as *resultPP. -----------------------------------------------------------------------------*/ /* This is an Expat driver. We set up event-based parser handlers for Expat and set Expat loose on the XML. Expat walks through the XML, calling our handlers along the way. Our handlers build up the element description in our 'context' variable, so that when Expat is finished, our results are in 'context' and we just have to pluck them out. We should allow the user to specify the encoding in 'xmlData', but we don't. */ XML_Parser parser; parseContext context; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(xmlData != NULL); createParser(envP, &context, &parser); if (!envP->fault_occurred) { bool ok; ok = xmlrpc_XML_Parse(parser, xmlData, xmlDataLen, 1); /* sets 'context', *envP */ if (!ok) { /* Expat failed on its own to parse it -- this is not an error that our handlers detected. */ xmlrpc_env_set_fault( envP, XMLRPC_PARSE_ERROR, xmlrpc_XML_GetErrorString(parser)); if (!context.env.fault_occurred) { /* Have to clean up what our handlers built before Expat barfed. */ if (context.rootP) xml_element_free(context.rootP); } } else { /* Expat got through the XML OK, but when it called our handlers, they might have detected a problem. They would have noted such a problem in *contextP. */ if (context.env.fault_occurred) xmlrpc_env_set_fault_formatted( envP, context.env.fault_code, "XML doesn't parse. %s", context.env.fault_string); else { XMLRPC_ASSERT(context.rootP != NULL); XMLRPC_ASSERT(context.currentP == NULL); *resultPP = context.rootP; } } destroyParser(parser, &context); } } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/xmlrpc_libxml2.c000066400000000000000000000351101236133176700173120ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2001 by First Peer, Inc. All rights reserved. ** Copyright (C) 2002 Ximian, Inc. ** ** 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 not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include "xmlrpc_config.h" #include #include #include #include /* There was code here from 2006-2013 that included instead of when compiling for Windows. It was probably compiled rarely if ever (this file is an optional part of the build). In Feburary 2013, a Mingw user found was necessary, and that makes more sense, so we changed it. */ #include #include "mallocvar.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/xmlparser.h" struct _xml_element { xml_element * parentP; const char * name; xmlrpc_mem_block cdata; /* char */ xmlrpc_mem_block children; /* xml_element* */ }; #define XMLRPC_ASSERT_ELEM_OK(elem) \ XMLRPC_ASSERT((elem) != NULL && (elem)->name != XMLRPC_BAD_POINTER) void xml_init(xmlrpc_env * const envP) { XMLRPC_ASSERT_ENV_OK(envP); /* N.B. xmlInitParser() does not stack. Calling it twice is the same as calling it once. Consequently, the same is true of xml_init(). N.B. xmlInitParser() is necessary for form only, because every libxml2 subroutine that needs it to be called just calls it itself. */ xmlInitParser(); } void xml_term(void) { /* N.B xmlCleanupParser() doesn't know how many times you called xmlInitParser(). Calling it twice is the same as calling it once. This means you must not call xml_term() while anything else in the process is still using libxml2. */ xmlCleanupParser(); } static xml_element * xmlElementNew(xmlrpc_env * const envP, const char * const name) { /*---------------------------------------------------------------------------- Create a new xml_element. This routine isn't exported, because the arguments are implementation-dependent. -----------------------------------------------------------------------------*/ xml_element * retval; bool nameIsValid; bool cdataIsValid; bool childrenAreValid; XMLRPC_ASSERT_ENV_OK(envP); assert(name != NULL); /* Set up our error-handling preconditions. */ retval = NULL; nameIsValid = cdataIsValid = childrenAreValid = false; MALLOCVAR(retval); XMLRPC_FAIL_IF_NULL(retval, envP, XMLRPC_INTERNAL_ERROR, "Couldn't allocate memory for XML element"); retval->parentP = NULL; /* Copy over the element name. */ retval->name = strdup(name); XMLRPC_FAIL_IF_NULL(retval->name, envP, XMLRPC_INTERNAL_ERROR, "Couldn't allocate memory for XML element"); nameIsValid = true; /* Initialize a block to hold our CDATA. */ XMLRPC_TYPED_MEM_BLOCK_INIT(char, envP, &retval->cdata, 0); XMLRPC_FAIL_IF_FAULT(envP); cdataIsValid = true; /* Initialize a block to hold our child elements. */ XMLRPC_TYPED_MEM_BLOCK_INIT(xml_element *, envP, &retval->children, 0); XMLRPC_FAIL_IF_FAULT(envP); childrenAreValid = true; cleanup: if (envP->fault_occurred) { if (retval) { if (nameIsValid) xmlrpc_strfree(retval->name); if (cdataIsValid) xmlrpc_mem_block_clean(&retval->cdata); if (childrenAreValid) xmlrpc_mem_block_clean(&retval->children); free(retval); } retval = NULL; } return retval; } void xml_element_free(xml_element * const elemP) { /*---------------------------------------------------------------------------- Blow away an existing element & all of its child elements. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * children; unsigned int size; unsigned int i; xml_element ** contents; XMLRPC_ASSERT_ELEM_OK(elemP); xmlrpc_strfree(elemP->name); elemP->name = XMLRPC_BAD_POINTER; xmlrpc_mem_block_clean(&elemP->cdata); /* Deallocate all of our children recursively. */ children = &elemP->children; contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element *, children); size = XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element *, children); for (i = 0; i < size; ++i) xml_element_free(contents[i]); xmlrpc_mem_block_clean(&elemP->children); free(elemP); } /*========================================================================= ** Miscellaneous Accessors **========================================================================= ** Return the fields of the xml_element. See the header for more ** documentation on each function works. */ const char * xml_element_name(const xml_element * const elemP) { XMLRPC_ASSERT_ELEM_OK(elemP); return elemP->name; } size_t xml_element_cdata_size(xml_element * const elemP) { /* The result of this function is NOT VALID until the end_element handler has been called! */ XMLRPC_ASSERT_ELEM_OK(elemP); return XMLRPC_TYPED_MEM_BLOCK_SIZE(char, &elemP->cdata) - 1; } char * xml_element_cdata(xml_element * const elemP) { XMLRPC_ASSERT_ELEM_OK(elemP); return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &elemP->cdata); } size_t xml_element_children_size(const xml_element * const elemP) { XMLRPC_ASSERT_ELEM_OK(elemP); return XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element *, &elemP->children); } xml_element ** xml_element_children(const xml_element * const elemP) { XMLRPC_ASSERT_ELEM_OK(elemP); return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element *, &elemP->children); } /*========================================================================= ** Internal xml_element Utility Functions **========================================================================= */ static void xmlElementAppendCdata(xmlrpc_env * const envP, xml_element * const elemP, const char * const cdata, size_t const size) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_ELEM_OK(elemP); XMLRPC_TYPED_MEM_BLOCK_APPEND(char, envP, &elemP->cdata, cdata, size); } static void xmlElementAppendChild(xmlrpc_env * const envP, xml_element * const elemP, xml_element * const childP) { /* Whether or not this function succeeds, it takes ownership of the 'child' argument. WARNING - This is the exact opposite of the usual memory ownership rules for xmlrpc_value! So please pay attention. */ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_ELEM_OK(elemP); XMLRPC_ASSERT_ELEM_OK(childP); assert(childP->parentP == NULL); XMLRPC_TYPED_MEM_BLOCK_APPEND(xml_element *, envP, &elemP->children, &childP, 1); if (!envP->fault_occurred) childP->parentP = elemP; else xml_element_free(childP); } typedef struct { /*---------------------------------------------------------------------------- Our parse context. We pass this around as libxml user data. -----------------------------------------------------------------------------*/ xmlrpc_env env; xml_element * rootP; xml_element * currentP; } ParseContext; /*========================================================================= ** LibXML Event Handler Functions **========================================================================= */ static void startElement_(void * const userData, const xmlChar * const name, const xmlChar ** const attrs ATTR_UNUSED) { ParseContext * contextP; xml_element * elemP; xml_element * newCurrentP; assert(userData != NULL && name != NULL); /* Get our context and see if an error has already occured. */ contextP = (ParseContext*) userData; if (!contextP->env.fault_occurred) { /* Build a new element. */ elemP = xmlElementNew(&contextP->env, (char *) name); XMLRPC_FAIL_IF_FAULT(&contextP->env); /* Insert it in the appropriate place. */ if (!contextP->rootP) { contextP->rootP = elemP; contextP->currentP = elemP; elemP = NULL; } else { assert(contextP->currentP != NULL); /* (We need to watch our error handling invariants very carefully ** here. Read the docs for xml_elementAppendChild. */ newCurrentP = elemP; xmlElementAppendChild(&contextP->env, contextP->currentP, elemP); elemP = NULL; XMLRPC_FAIL_IF_FAULT(&contextP->env); contextP->currentP = newCurrentP; } cleanup: if (elemP) xml_element_free(elemP); } } static void endElement_(void * const userData, const xmlChar * const name ATTR_UNUSED) { ParseContext * contextP; assert(userData != NULL && name != NULL); /* Get our context and see if an error has already occured. */ contextP = (ParseContext*) userData; if (!contextP->env.fault_occurred) { assert(xmlrpc_streq((const char *)name, contextP->currentP->name)); assert(contextP->currentP->parentP != NULL || contextP->currentP == contextP->rootP); /* Add a trailing '\0' to our cdata. */ xmlElementAppendCdata(&contextP->env, contextP->currentP, "\0", 1); if (!contextP->env.fault_occurred) { /* Pop our "stack" of elements. */ contextP->currentP = contextP->currentP->parentP; } } } static void characterData(void * const userData, const xmlChar * const s, int const len) { ParseContext * contextP; assert(userData != NULL && s != NULL); /* Get our context and see if an error has already occured. */ contextP = (ParseContext*)userData; if (!contextP->env.fault_occurred) { assert(contextP->currentP != NULL); xmlElementAppendCdata(&contextP->env, contextP->currentP, (char *)s, len); } } /*========================================================================= ** LibXML Driver **========================================================================= ** XXX - We should allow the user to specify the encoding of our xml_data. */ static xmlSAXHandler const saxHandler = { NULL, /* internalSubset */ NULL, /* isStandalone */ NULL, /* hasInternalSubset */ NULL, /* hasExternalSubset */ NULL, /* resolveEntity */ NULL, /* getEntity */ NULL, /* entityDecl */ NULL, /* notationDecl */ NULL, /* attributeDecl */ NULL, /* elementDecl */ NULL, /* unparsedEntityDecl */ NULL, /* setDocumentLocator */ NULL, /* startDocument */ NULL, /* endDocument */ startElement_, /* startElement */ endElement_, /* endElement */ NULL, /* reference */ characterData, /* characters */ NULL, /* ignorableWhitespace */ NULL, /* processingInstruction */ NULL, /* comment */ NULL, /* warning */ NULL, /* error */ NULL, /* fatalError */ NULL, /* getParameterEntity */ NULL, /* cdataBlock */ NULL, /* externalSubset */ 1 /* initialized */ /* Following are SAX2 fields. Any ifdef here? */ ,NULL, /* _private */ NULL, /* startElementNs */ NULL, /* endElementNs */ NULL /* serror */ }; void xml_parse(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xml_element ** const resultPP) { ParseContext context; xmlParserCtxt * parserP; XMLRPC_ASSERT_ENV_OK(envP); assert(xmlData != NULL); xmlrpc_env_init(&context.env); context.rootP = NULL; context.currentP = NULL; parserP = xmlCreatePushParserCtxt((xmlSAXHandler *)&saxHandler, &context, NULL, 0, NULL); if (!parserP) xmlrpc_faultf(envP, "Failed to create libxml2 parser."); else { int rc; rc = xmlParseChunk(parserP, xmlData, xmlDataLen, 1); if (rc != 0) xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, "XML parsing failed"); else { if (context.env.fault_occurred) { xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, context.env.fault_string); /* This should be done by the parser, but I'm not sure which callbacks need to do it. */ if (context.rootP) xml_element_free(context.rootP); } else { assert(context.rootP != NULL); assert(context.currentP == NULL); *resultPP = context.rootP; } } /* xmlParseChunk() creates a document. You find it with parserP->myDoc. */ if (parserP->myDoc) xmlFreeDoc(parserP->myDoc); xmlFreeParserCtxt(parserP); } xmlrpc_env_clean(&context.env); } xmlrpc-c-1.33.14/src/xmlrpc_parse.c000066400000000000000000000603501236133176700170570ustar00rootroot00000000000000/* Copyright information is at end of file. */ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include "xmlrpc_config.h" #include #include #include #include #include #include #include "bool.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/xmlparser.h" #include "parse_value.h" /* Notes about XML-RPC XML documents: Contain CDATA: methodName, i4, int, boolean, string, double, dateTime.iso8601, base64, name We attempt to validate the structure of the XML document carefully. We also try *very* hard to handle malicious data gracefully, and without leaking memory. The CHECK_NAME and CHECK_CHILD_COUNT macros examine an XML element, and invoke XMLRPC_FAIL if something looks wrong. */ static void setParseFault(xmlrpc_env * const envP, const char * const format, ...) { va_list args; va_start(args, format); xmlrpc_set_fault_formatted_v(envP, XMLRPC_PARSE_ERROR, format, args); va_end(args); } static void validateName(xmlrpc_env * const envP, const xml_element * const elemP, const char * const name) { if (!xmlrpc_streq(name, xml_element_name(elemP))) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Expected element of type <%s>, found <%s>", name, xml_element_name(elemP)); } static void validateChildCount(xmlrpc_env * const envP, const xml_element * const elemP, unsigned int const requiredCount) { if (xml_element_children_size(elemP) != requiredCount) xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Expected <%s> to have %u children, found %u", xml_element_name(elemP), requiredCount, (unsigned)xml_element_children_size(elemP)); } static xml_element * getChildByName (xmlrpc_env * const envP, xml_element * const parentP, const char * const name) { size_t const childCount = xml_element_children_size(parentP); xml_element ** const childrenP = xml_element_children(parentP); unsigned int i; for (i = 0; i < childCount; ++i) { if (xmlrpc_streq(xml_element_name(childrenP[i]), name)) return childrenP[i]; } setParseFault(envP, "Expected <%s> to have child <%s>", xml_element_name(parentP), name); return NULL; } static xmlrpc_value * convertParams(xmlrpc_env * const envP, const xml_element * const elemP) { /*---------------------------------------------------------------------------- Convert an XML element representing a list of parameters (i.e. a element) to an xmlrpc_value of type array. Note that an xmlrpc_value is normally represented in XML by a element, not a element. We use type xmlrpc_value to represent the parameter list just for convenience. -----------------------------------------------------------------------------*/ xmlrpc_value * arrayP; xmlrpc_value * itemP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(elemP != NULL); /* Allocate an array to hold our parameters. */ arrayP = xmlrpc_array_new(envP); if (!envP->fault_occurred) { /* We're responsible for checking our own element name. */ validateName(envP, elemP, "params"); if (!envP->fault_occurred) { /* Iterate over our children. */ unsigned int const size = xml_element_children_size(elemP); xml_element ** const paramPList = xml_element_children(elemP); unsigned int i; for (i = 0; i < size; ++i) { xml_element * const paramP = paramPList[i]; unsigned int const maxNest = (unsigned int) xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID); validateName(envP, paramP, "param"); if (!envP->fault_occurred) { validateChildCount(envP, paramP, 1); if (!envP->fault_occurred) { xml_element * const valueEltP = xml_element_children(paramP)[0]; validateName(envP, valueEltP, "value"); if (!envP->fault_occurred) { xmlrpc_parseValue(envP, maxNest, valueEltP, &itemP); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, arrayP, itemP); xmlrpc_DECREF(itemP); } } } } } } if (envP->fault_occurred) xmlrpc_DECREF(arrayP); } return arrayP; } static void parseCallXml(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xml_element ** const callElemPP) { /*---------------------------------------------------------------------------- Parse the XML of an XML-RPC call. -----------------------------------------------------------------------------*/ xml_element * callElemP; xmlrpc_env env; xmlrpc_env_init(&env); xml_parse(&env, xmlData, xmlDataLen, &callElemP); if (env.fault_occurred) xmlrpc_env_set_fault_formatted( envP, env.fault_code, "Call is not valid XML. %s", env.fault_string); else { if (!xmlrpc_streq(xml_element_name(callElemP), "methodCall")) setParseFault(envP, "XML-RPC call should be a element. " "Instead, we have a <%s> element.", xml_element_name(callElemP)); if (envP->fault_occurred) xml_element_free(callElemP); } *callElemPP = callElemP; xmlrpc_env_clean(&env); } static void parseMethodNameElement(xmlrpc_env * const envP, xml_element * const nameElemP, const char ** const methodNameP) { XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(nameElemP), "methodName")); if (xml_element_children_size(nameElemP) > 0) setParseFault(envP, "A element should not have " "children. This one has %u of them.", xml_element_children_size(nameElemP)); else { const char * const cdata = xml_element_cdata(nameElemP); xmlrpc_validate_utf8(envP, cdata, strlen(cdata)); if (!envP->fault_occurred) { *methodNameP = strdup(cdata); if (*methodNameP == NULL) xmlrpc_faultf(envP, "Could not allocate memory for method name"); } } } static void parseCallChildren(xmlrpc_env * const envP, xml_element * const callElemP, const char ** const methodNameP, xmlrpc_value ** const paramArrayPP ) { /*---------------------------------------------------------------------------- Parse the children of a XML element *callElemP. They should be and . -----------------------------------------------------------------------------*/ size_t const callChildCount = xml_element_children_size(callElemP); xml_element * nameElemP; XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(callElemP), "methodCall")); nameElemP = getChildByName(envP, callElemP, "methodName"); if (!envP->fault_occurred) { parseMethodNameElement(envP, nameElemP, methodNameP); if (!envP->fault_occurred) { /* Convert our parameters. */ if (callChildCount > 1) { xml_element * paramsElemP; paramsElemP = getChildByName(envP, callElemP, "params"); if (!envP->fault_occurred) *paramArrayPP = convertParams(envP, paramsElemP); } else { /* Workaround for Ruby XML-RPC and old versions of xmlrpc-epi. Future improvement: Instead of looking at child count, we should just check for existence of . */ *paramArrayPP = xmlrpc_array_new(envP); } if (!envP->fault_occurred) { if (callChildCount > 2) setParseFault(envP, " has extraneous " "children, other than and " ". Total child count = %u", callChildCount); if (envP->fault_occurred) xmlrpc_DECREF(*paramArrayPP); } if (envP->fault_occurred) xmlrpc_strfree(*methodNameP); } } } void xmlrpc_parse_call(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, const char ** const methodNameP, xmlrpc_value ** const paramArrayPP) { /*---------------------------------------------------------------------------- Given some XML text, attempt to parse it as an XML-RPC call. Return as *methodNameP the name of the method identified in the call and as *paramArrayPP the parameter list as an XML-RPC array. Caller must free() and xmlrpc_DECREF() these, respectively). -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(xmlData != NULL); XMLRPC_ASSERT(methodNameP != NULL && paramArrayPP != NULL); /* SECURITY: Last-ditch attempt to make sure our content length is legal. XXX - This check occurs too late to prevent an attacker from creating an enormous memory block, so you should try to enforce it *before* reading any data off the network. */ if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) xmlrpc_env_set_fault_formatted( envP, XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large. Max allowed is %u bytes", (unsigned)xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)); else { xml_element * callElemP; parseCallXml(envP, xmlData, xmlDataLen, &callElemP); if (!envP->fault_occurred) { parseCallChildren(envP, callElemP, methodNameP, paramArrayPP); xml_element_free(callElemP); } } if (envP->fault_occurred) { /* Should not be necessary, but for backward compatibility: */ *methodNameP = NULL; *paramArrayPP = NULL; } } static void interpretFaultCode(xmlrpc_env * const envP, xmlrpc_value * const faultCodeVP, int * const faultCodeP) { xmlrpc_env fcEnv; xmlrpc_env_init(&fcEnv); xmlrpc_read_int(&fcEnv, faultCodeVP, faultCodeP); if (fcEnv.fault_occurred) xmlrpc_faultf(envP, "Invalid value for 'faultCode' member. %s", fcEnv.fault_string); xmlrpc_env_clean(&fcEnv); } static void interpretFaultString(xmlrpc_env * const envP, xmlrpc_value * const faultStringVP, const char ** const faultStringP) { xmlrpc_env fsEnv; xmlrpc_env_init(&fsEnv); xmlrpc_read_string(&fsEnv, faultStringVP, faultStringP); if (fsEnv.fault_occurred) xmlrpc_faultf(envP, "Invalid value for 'faultString' member. %s", fsEnv.fault_string); xmlrpc_env_clean(&fsEnv); } static void interpretFaultValue(xmlrpc_env * const envP, xmlrpc_value * const faultVP, int * const faultCodeP, const char ** const faultStringP) { if (faultVP->_type != XMLRPC_TYPE_STRUCT) setParseFault(envP, " element of response is not " "of structure type"); else { xmlrpc_value * faultCodeVP; xmlrpc_env fvEnv; xmlrpc_env_init(&fvEnv); xmlrpc_struct_read_value(&fvEnv, faultVP, "faultCode", &faultCodeVP); if (!fvEnv.fault_occurred) { interpretFaultCode(&fvEnv, faultCodeVP, faultCodeP); if (!fvEnv.fault_occurred) { xmlrpc_value * faultStringVP; xmlrpc_struct_read_value(&fvEnv, faultVP, "faultString", &faultStringVP); if (!fvEnv.fault_occurred) { interpretFaultString(&fvEnv, faultStringVP, faultStringP); xmlrpc_DECREF(faultStringVP); } } xmlrpc_DECREF(faultCodeVP); } if (fvEnv.fault_occurred) setParseFault(envP, "Invalid struct for value. %s", fvEnv.fault_string); xmlrpc_env_clean(&fvEnv); } } static void parseFaultElement(xmlrpc_env * const envP, const xml_element * const faultElement, int * const faultCodeP, const char ** const faultStringP) { unsigned int const maxRecursion = (unsigned int) xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID); XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(faultElement), "fault")); if (xml_element_children_size(faultElement) != 1) setParseFault(envP, " element should have 1 child, " "but it has %u.", xml_element_children_size(faultElement)); else { xml_element * const faultValueP = xml_element_children(faultElement)[0]; const char * const elemName = xml_element_name(faultValueP); if (!xmlrpc_streq(elemName, "value")) setParseFault(envP, " contains a <%s> element. " "Only makes sense.", elemName); else { xmlrpc_value * faultVP; xmlrpc_parseValue(envP, maxRecursion, faultValueP, &faultVP); if (!envP->fault_occurred) { interpretFaultValue(envP, faultVP, faultCodeP, faultStringP); xmlrpc_DECREF(faultVP); } } } } static void parseParamsElement(xmlrpc_env * const envP, const xml_element * const paramsElementP, xmlrpc_value ** const resultPP) { xmlrpc_value * paramsVP; xmlrpc_env env; xmlrpc_env_init(&env); XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(paramsElementP), "params")); paramsVP = convertParams(envP, paramsElementP); if (!envP->fault_occurred) { int arraySize; xmlrpc_env sizeEnv; XMLRPC_ASSERT_ARRAY_OK(paramsVP); xmlrpc_env_init(&sizeEnv); arraySize = xmlrpc_array_size(&sizeEnv, paramsVP); /* Since it's a valid array, as asserted above, can't fail */ XMLRPC_ASSERT(!sizeEnv.fault_occurred); if (arraySize != 1) setParseFault(envP, "Contains %d items. It should have 1.", arraySize); else { xmlrpc_array_read_item(envP, paramsVP, 0, resultPP); } xmlrpc_DECREF(paramsVP); xmlrpc_env_clean(&sizeEnv); } if (env.fault_occurred) xmlrpc_env_set_fault_formatted( envP, env.fault_code, "Invalid element. %s", env.fault_string); xmlrpc_env_clean(&env); } static void parseMethodResponseElt(xmlrpc_env * const envP, const xml_element * const methodResponseEltP, xmlrpc_value ** const resultPP, int * const faultCodeP, const char ** const faultStringP) { XMLRPC_ASSERT(xmlrpc_streq(xml_element_name(methodResponseEltP), "methodResponse")); if (xml_element_children_size(methodResponseEltP) == 1) { xml_element * const child = xml_element_children(methodResponseEltP)[0]; if (xmlrpc_streq(xml_element_name(child), "params")) { /* It's a successful response */ parseParamsElement(envP, child, resultPP); *faultStringP = NULL; } else if (xmlrpc_streq(xml_element_name(child), "fault")) { /* It's a failure response */ parseFaultElement(envP, child, faultCodeP, faultStringP); } else setParseFault(envP, " must contain or , " "but contains <%s>.", xml_element_name(child)); } else setParseFault(envP, " has %u children, should have 1.", xml_element_children_size(methodResponseEltP)); } void xmlrpc_parse_response2(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xmlrpc_value ** const resultPP, int * const faultCodeP, const char ** const faultStringP) { /*---------------------------------------------------------------------------- Given some XML text, attempt to parse it as an XML-RPC response. If the response is a regular, valid response, return a new reference to the appropriate value as *resultP and return NULL as *faultStringP and nothing as *faultCodeP. If the response is valid, but indicates a failure of the RPC, return the fault string in newly malloc'ed space as *faultStringP and the fault code as *faultCodeP and nothing as *resultP. If the XML text is not a valid response or something prevents us from parsing it, return a description of the error as *envP and nothing else. -----------------------------------------------------------------------------*/ xml_element * responseEltP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(xmlData != NULL); /* SECURITY: Last-ditch attempt to make sure our content length is legal. ** XXX - This check occurs too late to prevent an attacker from creating ** an enormous memory block, so you should try to enforce it ** *before* reading any data off the network. */ if (xmlDataLen > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) xmlrpc_env_set_fault_formatted( envP, XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC response too large. Our limit is %u characters. " "We got %u characters", (unsigned)xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID), (unsigned)xmlDataLen); else { xmlrpc_env env; xmlrpc_env_init(&env); xml_parse(&env, xmlData, xmlDataLen, &responseEltP); if (env.fault_occurred) setParseFault(envP, "Not valid XML. %s", env.fault_string); else { /* Pick apart and verify our structure. */ if (xmlrpc_streq(xml_element_name(responseEltP), "methodResponse")) { parseMethodResponseElt(envP, responseEltP, resultPP, faultCodeP, faultStringP); } else setParseFault(envP, "XML-RPC response must consist of a " " element. " "This has a <%s> instead.", xml_element_name(responseEltP)); xml_element_free(responseEltP); } xmlrpc_env_clean(&env); } } xmlrpc_value * xmlrpc_parse_response(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen) { /*---------------------------------------------------------------------------- This exists for backward compatibility. It is like xmlrpc_parse_response2(), except that it merges the concepts of a failed RPC and an error in executing the RPC. -----------------------------------------------------------------------------*/ xmlrpc_value * retval; xmlrpc_value * result; const char * faultString; int faultCode; xmlrpc_parse_response2(envP, xmlData, xmlDataLen, &result, &faultCode, &faultString); if (envP->fault_occurred) retval = NULL; else { if (faultString) { xmlrpc_env_set_fault(envP, faultCode, faultString); xmlrpc_strfree(faultString); retval = NULL; } else retval = result; /* transfer reference */ } return retval; } void xmlrpc_parse_value_xml(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlDataLen, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Compute the xmlrpc_value represented by the XML document 'xmlData' (of length 'xmlDataLen' characters), which must consist of a single element. Return that xmlrpc_value. We call convert_array() and convert_struct(), which may ultimately call us recursively. Don't recurse any more than 'maxRecursion' times. This isn't generally useful in XML-RPC programs, because such programs parse a whole XML-RPC call or response document, and never see the XML text of just a element. But a program may do some weird form of XML-RPC processing or just borrow Xmlrpc-c's value serialization facilities for something unrelated to XML-RPC. In any case, it makes sense to have an inverse of xmlrpc_serialize_value2(), which generates XML text from an xmlrpc_value. -----------------------------------------------------------------------------*/ xmlrpc_env env; xml_element * valueEltP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(xmlData != NULL); xmlrpc_env_init(&env); xml_parse(&env, xmlData, xmlDataLen, &valueEltP); if (env.fault_occurred) { setParseFault(envP, "Not valid XML. %s", env.fault_string); } else { if (xmlrpc_streq(xml_element_name(valueEltP), "value")) { unsigned int const maxRecursion = (unsigned int) xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID); xmlrpc_parseValue(envP, maxRecursion, valueEltP, valuePP); } else setParseFault(envP, "XML-RPC value XML document must consist of " "a element. This has a <%s> instead.", xml_element_name(valueEltP)); xml_element_free(valueEltP); } xmlrpc_env_clean(&env); } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/xmlrpc_serialize.c000066400000000000000000000652041236133176700177370ustar00rootroot00000000000000/* Copyright information is at end of file */ /* Implementation note: The printf format specifiers we use appear to be entirely standard, except for the "long long" one, which is %I64 on Windows and %lld everywhere else. We could use the C99 standard macro PRId64 for that, but on at least one 64-bit-long GNU compiler, PRId64 is "ld", which is considered to be incompatible with long long. So we have XMLRPC_PRId64. */ #include "xmlrpc_config.h" #include #include #include #include #include #include #include #include "int.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "double.h" #define CRLF "\015\012" #define XML_PROLOGUE ""CRLF #define APACHE_URL "http://ws.apache.org/xmlrpc/namespaces/extensions" #define XMLNS_APACHE "xmlns:ex=\"" APACHE_URL "\"" static void addString(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const char * const string) { XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, string, strlen(string)); } static void formatOut(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const char * const formatString, ...) { /*---------------------------------------------------------------------------- A lightweight print routine for use with various serialization functions. Use this routine only for printing small objects -- it uses a fixed-size internal buffer and returns an error on overflow. In particular, do NOT use this routine to print XML-RPC string values! -----------------------------------------------------------------------------*/ va_list args; char buffer[128]; int rc; XMLRPC_ASSERT_ENV_OK(envP); va_start(args, formatString); rc = XMLRPC_VSNPRINTF(buffer, sizeof(buffer), formatString, args); /* Old vsnprintf() (and Windows) fails with return value -1 if the full string doesn't fit in the buffer. New vsnprintf() puts whatever will fit in the buffer, and returns the length of the full string regardless. For us, this truncation is a failure. */ if (rc < 0) xmlrpc_faultf(envP, "formatOut() overflowed internal buffer"); else { unsigned int const formattedLen = rc; if (formattedLen + 1 >= (sizeof(buffer))) xmlrpc_faultf(envP, "formatOut() overflowed internal buffer"); else XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, buffer, formattedLen); } va_end(args); } static void assertValidUtf8(const char * const str ATTR_UNUSED, size_t const len ATTR_UNUSED) { /*---------------------------------------------------------------------------- Assert that the string 'str' of length 'len' is valid UTF-8. -----------------------------------------------------------------------------*/ #if !defined NDEBUG /* Check the assertion; if it's false, issue a message to Standard Error, but otherwise ignore it. */ xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_validate_utf8(&env, str, len); if (env.fault_occurred) fprintf(stderr, "*** xmlrpc-c WARNING ***: %s (%s)\n", "Xmlrpc-c sending corrupted UTF-8 data to network", env.fault_string); xmlrpc_env_clean(&env); #endif } static size_t escapedSize(const char * const chars, size_t const len) { size_t size; size_t i; size = 0; for (i = 0; i < len; ++i) { if (chars[i] == '<') size += 4; /* < */ else if (chars[i] == '>') size += 4; /* > */ else if (chars[i] == '&') size += 5; /* & */ else if (chars[i] == '\r') size += 6; /* */ else size += 1; } return size; } static void escapeForXml(xmlrpc_env * const envP, const char * const chars, size_t const len, xmlrpc_mem_block ** const outputPP) { /*---------------------------------------------------------------------------- Escape & and < in a UTF-8 string so as to make it suitable for the content of an XML element. I.e. turn them into entity references & and <. Also change > to >, even though not required for XML, for symmetry. < etc. are known in XML as "entity references." Also Escape CR as . While raw CR _is_ allowed in the content of an XML element, it has a special meaning -- it means line ending. Our input uses LF for for line endings. Since it also means line ending in XML, we just pass it through to our output like it were a regular character. is known in XML as a "character reference." We assume chars[] is is ASCII. That isn't right -- we should handle all valid UTF-8. Someday, we must do something more complex and copy over multibyte characters verbatim. (The code here could erroneously find that e.g. the 2nd byte of a UTF-8 character is a CR). -----------------------------------------------------------------------------*/ xmlrpc_mem_block * outputP; size_t outputSize; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(chars != NULL); assertValidUtf8(chars, len); /* Note that in UTF-8, any byte that has high bit of zero is a character all by itself (every byte of a multi-byte UTF-8 character has the high bit set). Also, the Unicode code points < 128 are identical to the ASCII ones. */ outputSize = escapedSize(chars, len); outputP = XMLRPC_MEMBLOCK_NEW(char, envP, outputSize); if (!envP->fault_occurred) { char * p; size_t i; p = XMLRPC_MEMBLOCK_CONTENTS(char, outputP); /* Start at beginning */ for (i = 0; i < len; i++) { if (chars[i] == '<') { memcpy(p, "<", 4); p += 4; } else if (chars[i] == '>') { memcpy(p, ">", 4); p += 4; } else if (chars[i] == '&') { memcpy(p, "&", 5); p += 5; } else if (chars[i] == '\r') { memcpy(p, " ", 6); p += 6; } else { /* Either a plain character or a LF line delimiter */ *p = chars[i]; p += 1; } } *outputPP = outputP; assert(p == XMLRPC_MEMBLOCK_CONTENTS(char, outputP) + outputSize); if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, outputP); } } static void serializeUtf8MemBlock(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_mem_block * const inputP) { /*---------------------------------------------------------------------------- Append the characters in *inputP to the XML stream in *outputP. *inputP contains Unicode characters in UTF-8. We assume *inputP ends with a NUL character that marks end of string, and we ignore that. (There might also be NUL characters inside the string, though). -----------------------------------------------------------------------------*/ xmlrpc_mem_block * escapedP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(outputP != NULL); XMLRPC_ASSERT(inputP != NULL); escapeForXml(envP, XMLRPC_MEMBLOCK_CONTENTS(const char, inputP), XMLRPC_MEMBLOCK_SIZE(const char, inputP) - 1, /* -1 is for the terminating NUL */ &escapedP); if (!envP->fault_occurred) { const char * const contents = XMLRPC_MEMBLOCK_CONTENTS(const char, escapedP); size_t const size = XMLRPC_MEMBLOCK_SIZE(char, escapedP); XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, contents, size); XMLRPC_MEMBLOCK_FREE(const char, escapedP); } } static void xmlrpc_serialize_base64_data(xmlrpc_env * const envP, xmlrpc_mem_block * const output, unsigned char * const data, size_t const len) { /*---------------------------------------------------------------------------- Encode the 'len' bytes at 'data' in base64 ASCII and append the result to 'output'. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * encoded; encoded = xmlrpc_base64_encode(envP, data, len); if (!envP->fault_occurred) { unsigned char * const contents = XMLRPC_MEMBLOCK_CONTENTS(unsigned char, encoded); size_t const size = XMLRPC_MEMBLOCK_SIZE(unsigned char, encoded); XMLRPC_MEMBLOCK_APPEND(char, envP, output, contents, size); XMLRPC_MEMBLOCK_FREE(char, encoded); } } static void serializeDatetime(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP) { /*---------------------------------------------------------------------------- Add to *outputP the content of a element to represent the datetime value *valueP. I.e. " ... ". -----------------------------------------------------------------------------*/ addString(envP, outputP, ""); if (!envP->fault_occurred) { char dtString[64]; snprintf(dtString, sizeof(dtString), "%u%02u%02uT%02u:%02u:%02u", valueP->_value.dt.Y, valueP->_value.dt.M, valueP->_value.dt.D, valueP->_value.dt.h, valueP->_value.dt.m, valueP->_value.dt.s); if (valueP->_value.dt.u != 0) { char usecString[64]; assert(valueP->_value.dt.u < 1000000); snprintf(usecString, sizeof(usecString), ".%06u", valueP->_value.dt.u); STRSCAT(dtString, usecString); } addString(envP, outputP, dtString); if (!envP->fault_occurred) { addString(envP, outputP, ""); } } } static void serializeStructMember(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const memberKeyP, xmlrpc_value * const memberValueP, xmlrpc_dialect const dialect) { addString(envP, outputP, ""); if (!envP->fault_occurred) { serializeUtf8MemBlock(envP, outputP, &memberKeyP->_block); if (!envP->fault_occurred) { addString(envP, outputP, ""CRLF); if (!envP->fault_occurred) { xmlrpc_serialize_value2(envP, outputP, memberValueP, dialect); if (!envP->fault_occurred) { addString(envP, outputP, ""CRLF); } } } } } static void serializeStruct(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const structP, xmlrpc_dialect const dialect) { /*---------------------------------------------------------------------------- Add to *outputP the content of a element to represent the structure value *valueP. I.e. " ... ". -----------------------------------------------------------------------------*/ addString(envP, outputP, ""CRLF); if (!envP->fault_occurred) { unsigned int const size = xmlrpc_struct_size(envP, structP); if (!envP->fault_occurred) { unsigned int i; for (i = 0; i < size && !envP->fault_occurred; ++i) { xmlrpc_value * memberKeyP; xmlrpc_value * memberValueP; xmlrpc_struct_get_key_and_value(envP, structP, i, &memberKeyP, &memberValueP); if (!envP->fault_occurred) { serializeStructMember(envP, outputP, memberKeyP, memberValueP, dialect); } } if (!envP->fault_occurred) addString(envP, outputP, ""); } } } static void serializeArray(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP, xmlrpc_dialect const dialect) { /*---------------------------------------------------------------------------- Add to *outputP the content of a element to represent the array value *valueP. I.e. " ... ". -----------------------------------------------------------------------------*/ int const size = xmlrpc_array_size(envP, valueP); if (!envP->fault_occurred) { addString(envP, outputP, ""CRLF); if (!envP->fault_occurred) { int i; /* Serialize each item. */ for (i = 0; i < size && !envP->fault_occurred; ++i) { xmlrpc_value * const itemP = xmlrpc_array_get_item(envP, valueP, i); if (!envP->fault_occurred) { xmlrpc_serialize_value2(envP, outputP, itemP, dialect); if (!envP->fault_occurred) addString(envP, outputP, CRLF); } } } } if (!envP->fault_occurred) addString(envP, outputP, ""); } static void formatValueContent(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP, xmlrpc_dialect const dialect) { /*---------------------------------------------------------------------------- Add to *outputP the content of a element to represent value *valueP. E.g. "42" -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); switch (valueP->_type) { case XMLRPC_TYPE_INT: formatOut(envP, outputP, "%d", valueP->_value.i); break; case XMLRPC_TYPE_I8: { const char * const elemName = dialect == xmlrpc_dialect_apache ? "ex:i8" : "i8"; formatOut(envP, outputP, "<%s>%" PRId64 "", elemName, valueP->_value.i8, elemName); } break; case XMLRPC_TYPE_BOOL: formatOut(envP, outputP, "%s", valueP->_value.b ? "1" : "0"); break; case XMLRPC_TYPE_DOUBLE: { const char * serializedValue; xmlrpc_formatFloat(envP, valueP->_value.d, &serializedValue); if (!envP->fault_occurred) { addString(envP, outputP, ""); if (!envP->fault_occurred) { addString(envP, outputP, serializedValue); if (!envP->fault_occurred) addString(envP, outputP, ""); } xmlrpc_strfree(serializedValue); } } break; case XMLRPC_TYPE_DATETIME: serializeDatetime(envP, outputP, valueP); break; case XMLRPC_TYPE_STRING: addString(envP, outputP, ""); if (!envP->fault_occurred) { serializeUtf8MemBlock(envP, outputP, &valueP->_block); if (!envP->fault_occurred) addString(envP, outputP, ""); } break; case XMLRPC_TYPE_BASE64: { unsigned char * const contents = XMLRPC_MEMBLOCK_CONTENTS(unsigned char, &valueP->_block); size_t const size = XMLRPC_MEMBLOCK_SIZE(unsigned char, &valueP->_block); addString(envP, outputP, ""CRLF); if (!envP->fault_occurred) { xmlrpc_serialize_base64_data(envP, outputP, contents, size); if (!envP->fault_occurred) addString(envP, outputP, ""); } } break; case XMLRPC_TYPE_ARRAY: serializeArray(envP, outputP, valueP, dialect); break; case XMLRPC_TYPE_STRUCT: serializeStruct(envP, outputP, valueP, dialect); break; case XMLRPC_TYPE_C_PTR: xmlrpc_faultf(envP, "Tried to serialize a C pointer value."); break; case XMLRPC_TYPE_NIL: { const char * const elemName = dialect == xmlrpc_dialect_apache ? "ex:nil" : "nil"; formatOut(envP, outputP, "<%s/>", elemName); } break; case XMLRPC_TYPE_DEAD: xmlrpc_faultf(envP, "Tried to serialize a dead value."); break; default: xmlrpc_faultf(envP, "Invalid xmlrpc_value type: %d", valueP->_type); } } void xmlrpc_serialize_value2(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP, xmlrpc_dialect const dialect) { /*---------------------------------------------------------------------------- Generate the XML to represent XML-RPC value 'valueP' in XML-RPC. Add it to *outputP. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(outputP != NULL); XMLRPC_ASSERT_VALUE_OK(valueP); addString(envP, outputP, ""); if (!envP->fault_occurred) { formatValueContent(envP, outputP, valueP, dialect); if (!envP->fault_occurred) addString(envP, outputP, ""); } } void xmlrpc_serialize_value(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP) { xmlrpc_serialize_value2(envP, outputP, valueP, xmlrpc_dialect_i8); } void xmlrpc_serialize_params2(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const paramArrayP, xmlrpc_dialect const dialect) { /*---------------------------------------------------------------------------- Serialize the parameter list of an XML-RPC call. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(outputP != NULL); XMLRPC_ASSERT_VALUE_OK(paramArrayP); addString(envP, outputP, ""CRLF); if (!envP->fault_occurred) { /* Serialize each parameter. */ int const paramCount = xmlrpc_array_size(envP, paramArrayP); if (!envP->fault_occurred) { int paramSeq; for (paramSeq = 0; paramSeq < paramCount && !envP->fault_occurred; ++paramSeq) { addString(envP, outputP, ""); if (!envP->fault_occurred) { xmlrpc_value * const itemP = xmlrpc_array_get_item(envP, paramArrayP, paramSeq); if (!envP->fault_occurred) { xmlrpc_serialize_value2(envP, outputP, itemP, dialect); if (!envP->fault_occurred) addString(envP, outputP, ""CRLF); } } } } } if (!envP->fault_occurred) addString(envP, outputP, ""CRLF); } void xmlrpc_serialize_params(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const paramArrayP) { /*---------------------------------------------------------------------------- Serialize the parameter list of an XML-RPC call in the original "i8" dialect. -----------------------------------------------------------------------------*/ xmlrpc_serialize_params2(envP, outputP, paramArrayP, xmlrpc_dialect_i8); } /*========================================================================= ** xmlrpc_serialize_call **========================================================================= ** Serialize an XML-RPC call. */ void xmlrpc_serialize_call2(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_dialect const dialect) { /*---------------------------------------------------------------------------- Serialize an XML-RPC call of method named 'methodName' with parameter list *paramArrayP. Use XML-RPC dialect 'dialect'. Append the call XML ot *outputP. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(outputP != NULL); XMLRPC_ASSERT(methodName != NULL); XMLRPC_ASSERT_VALUE_OK(paramArrayP); addString(envP, outputP, XML_PROLOGUE); if (!envP->fault_occurred) { const char * const xmlns = dialect == xmlrpc_dialect_apache ? " " XMLNS_APACHE : ""; formatOut(envP, outputP, ""CRLF"", xmlns); if (!envP->fault_occurred) { xmlrpc_mem_block * encodedP; escapeForXml(envP, methodName, strlen(methodName), &encodedP); if (!envP->fault_occurred) { const char * const contents = XMLRPC_MEMBLOCK_CONTENTS(char, encodedP); size_t const size = XMLRPC_MEMBLOCK_SIZE(char, encodedP); XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, contents, size); if (!envP->fault_occurred) { addString(envP, outputP, ""CRLF); if (!envP->fault_occurred) { xmlrpc_serialize_params2(envP, outputP, paramArrayP, dialect); if (!envP->fault_occurred) addString(envP, outputP, ""CRLF); } } XMLRPC_MEMBLOCK_FREE(char, encodedP); } } } } void xmlrpc_serialize_call(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const char * const methodName, xmlrpc_value * const paramArrayP) { xmlrpc_serialize_call2(envP, outputP, methodName, paramArrayP, xmlrpc_dialect_i8); } void xmlrpc_serialize_response2(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP, xmlrpc_dialect const dialect) { /*---------------------------------------------------------------------------- Serialize a result response to an XML-RPC call. The result is 'valueP'. Add the response XML to *outputP. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(outputP != NULL); XMLRPC_ASSERT_VALUE_OK(valueP); addString(envP, outputP, XML_PROLOGUE); if (!envP->fault_occurred) { const char * const xmlns = dialect == xmlrpc_dialect_apache ? " " XMLNS_APACHE : ""; formatOut(envP, outputP, ""CRLF""CRLF"", xmlns); if (!envP->fault_occurred) { xmlrpc_serialize_value2(envP, outputP, valueP, dialect); if (!envP->fault_occurred) { addString(envP, outputP, ""CRLF""CRLF ""CRLF); } } } } void xmlrpc_serialize_response(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, xmlrpc_value * const valueP) { xmlrpc_serialize_response2(envP, outputP, valueP, xmlrpc_dialect_i8); } void xmlrpc_serialize_fault(xmlrpc_env * const envP, xmlrpc_mem_block * const outputP, const xmlrpc_env * const faultP) { /*---------------------------------------------------------------------------- Serialize a fault response to an XML-RPC call. 'faultP' is the fault. Add the response XML to *outputP. -----------------------------------------------------------------------------*/ xmlrpc_value * faultStructP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(outputP != NULL); XMLRPC_ASSERT(faultP != NULL); XMLRPC_ASSERT(faultP->fault_occurred); faultStructP = xmlrpc_build_value(envP, "{s:i,s:s}", "faultCode", (xmlrpc_int32) faultP->fault_code, "faultString", faultP->fault_string); if (!envP->fault_occurred) { addString(envP, outputP, XML_PROLOGUE); if (!envP->fault_occurred) { addString(envP, outputP, ""CRLF""CRLF); if (!envP->fault_occurred) { xmlrpc_serialize_value(envP, outputP, faultStructP); if (!envP->fault_occurred) { addString(envP, outputP, CRLF""CRLF""CRLF); } } } xmlrpc_DECREF(faultStructP); } } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/xmlrpc_server_abyss.c000066400000000000000000001207501236133176700204550ustar00rootroot00000000000000/* Copyright information is at the end of the file */ #include "xmlrpc_config.h" #define _XOPEN_SOURCE 600 /* For strdup(), sigaction */ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/abyss.h */ #include #include #include #include #include #include #include #ifdef _WIN32 # include # pragma comment(lib, "Ws2_32.lib") #else # include # include # include # include # include #endif #include "bool.h" #include "int.h" #include "mallocvar.h" #include "xmlrpc-c/abyss.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/server_abyss.h" #include "abyss_handler.h" struct xmlrpc_server_abyss { TServer abyssServer; TChanSwitch * chanSwitchP; bool shutdownEnabled; /* User wants system.shutdown to succeed */ }; static void dieIfFaultOccurred(xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "Unexpected XML-RPC fault: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } static void initAbyss(xmlrpc_env * const envP) { const char * error; AbyssInit(&error); if (error) { xmlrpc_faultf(envP, "Failed to initialize the Abyss library. %s", error); xmlrpc_strfree(error); } } static void termAbyss(void) { AbyssTerm(); } static unsigned int globallyInitialized = 0; /* Initialization count */ void xmlrpc_server_abyss_global_init(xmlrpc_env * const envP) { /* Note that this is specified as not thread safe; user calls it at the beginning of his program, when it is only one thread. */ XMLRPC_ASSERT_ENV_OK(envP); if (globallyInitialized == 0) initAbyss(envP); ++globallyInitialized; } void xmlrpc_server_abyss_global_term(void) { /* Note that this is specified as not thread safe; user calls it at the end of his program, when it is only one thread. */ XMLRPC_ASSERT(globallyInitialized > 0); --globallyInitialized; if (globallyInitialized == 0) termAbyss(); } static void validateGlobalInit(xmlrpc_env * const envP) { if (!globallyInitialized) xmlrpc_faultf(envP, "libxmlrpc_server_abyss has not been globally " "initialized. See xmlrpc_server_abyss_init()"); } static void processXmlrpcCall(xmlrpc_env * const envP, void * const arg, const char * const callXml, size_t const callXmlLen, TSession * const abyssSessionP, xmlrpc_mem_block ** const responseXmlPP) { xmlrpc_registry * const registryP = arg; xmlrpc_registry_process_call2(envP, registryP, callXml, callXmlLen, abyssSessionP, responseXmlPP); } static void setHandler(xmlrpc_env * const envP, TServer * const srvP, struct uriHandlerXmlrpc * const uriHandlerXmlrpcP, size_t const xmlProcessorMaxStackSize) { abyss_bool success; xmlrpc_abyss_handler_trace( getenv("XMLRPC_TRACE_ABYSS")); { size_t const stackSize = xmlrpc_abyss_handler_stacksize() + xmlProcessorMaxStackSize; struct ServerReqHandler3 const handlerDesc = { /* .term = */ &xmlrpc_termUriHandler, /* .handleReq = */ &xmlrpc_handleIfXmlrpcReq, /* .userdata = */ uriHandlerXmlrpcP, /* .handleReqStackSize = */ stackSize }; ServerAddHandler3(srvP, &handlerDesc, &success); } if (!success) xmlrpc_faultf(envP, "Abyss failed to register the Xmlrpc-c request " "handler. ServerAddHandler3() failed."); } static void interpretHttpAccessControl( const xmlrpc_server_abyss_handler_parms * const parmsP, unsigned int const parmSize, ResponseAccessCtl * const accessCtlP) { const char * allowOrigin; bool expires; unsigned int maxAge; if (parmSize >= XMLRPC_AHPSIZE(allow_origin) && parmsP->allow_origin) allowOrigin = parmsP->allow_origin; else allowOrigin = NULL; if (parmSize >= XMLRPC_AHPSIZE(access_ctl_expires) && parmsP->access_ctl_expires) { expires = true; if (parmSize >= XMLRPC_AHPSIZE(access_ctl_max_age)) maxAge = parmsP->access_ctl_max_age; else maxAge = 0; } else { expires = false; maxAge = 0; /* Meaningless; just to quiet runtime memory checks */ } xmlrpc_initAccessCtl(accessCtlP, allowOrigin, expires, maxAge); } void xmlrpc_server_abyss_set_handler3( xmlrpc_env * const envP, TServer * const srvP, const xmlrpc_server_abyss_handler_parms * const parmsP, unsigned int const parmSize) { struct uriHandlerXmlrpc * uriHandlerXmlrpcP; size_t xmlProcessorMaxStackSize; MALLOCVAR_NOFAIL(uriHandlerXmlrpcP); if (!envP->fault_occurred) { if (parmSize >= XMLRPC_AHPSIZE(xml_processor)) uriHandlerXmlrpcP->xmlProcessor = parmsP->xml_processor; else xmlrpc_faultf(envP, "Parameter too short to contain the required " "'xml_processor' member"); } if (!envP->fault_occurred) { if (parmSize >= XMLRPC_AHPSIZE(xml_processor_arg)) uriHandlerXmlrpcP->xmlProcessorArg = parmsP->xml_processor_arg; else xmlrpc_faultf(envP, "Parameter too short to contain the required " "'xml_processor_arg' member"); } if (!envP->fault_occurred) { if (parmSize >= XMLRPC_AHPSIZE(xml_processor_max_stack)) xmlProcessorMaxStackSize = parmsP->xml_processor_max_stack; else xmlrpc_faultf(envP, "Parameter too short to contain the required " "'xml_processor_max_stack' member"); } if (!envP->fault_occurred) { if (parmSize >= XMLRPC_AHPSIZE(uri_path) && parmsP->uri_path) uriHandlerXmlrpcP->uriPath = xmlrpc_strdupsol(parmsP->uri_path); else uriHandlerXmlrpcP->uriPath = xmlrpc_strdupsol("/RPC2"); if (parmSize >= XMLRPC_AHPSIZE(chunk_response) && parmsP->chunk_response) uriHandlerXmlrpcP->chunkResponse = parmsP->chunk_response; else uriHandlerXmlrpcP->chunkResponse = false; interpretHttpAccessControl(parmsP, parmSize, &uriHandlerXmlrpcP->accessControl); if (envP->fault_occurred) xmlrpc_termAccessControl(&uriHandlerXmlrpcP->accessControl); } if (!envP->fault_occurred) setHandler(envP, srvP, uriHandlerXmlrpcP, xmlProcessorMaxStackSize); if (envP->fault_occurred) free(uriHandlerXmlrpcP); } void xmlrpc_server_abyss_set_handler2( TServer * const srvP, const char * const uriPath, xmlrpc_call_processor xmlProcessor, void * const xmlProcessorArg, size_t const xmlProcessorMaxStackSize, xmlrpc_bool const chunkResponse) { xmlrpc_env env; xmlrpc_server_abyss_handler_parms parms; xmlrpc_env_init(&env); parms.xml_processor = xmlProcessor; parms.xml_processor_arg = xmlProcessorArg; parms.xml_processor_max_stack = xmlProcessorMaxStackSize; parms.uri_path = uriPath; parms.chunk_response = chunkResponse; xmlrpc_server_abyss_set_handler3(&env, srvP, &parms, XMLRPC_AHPSIZE(chunk_response)); if (env.fault_occurred) abort(); xmlrpc_env_clean(&env); } void xmlrpc_server_abyss_set_handler(xmlrpc_env * const envP, TServer * const srvP, const char * const uriPath, xmlrpc_registry * const registryP) { xmlrpc_server_abyss_handler_parms parms; parms.xml_processor = &processXmlrpcCall; parms.xml_processor_arg = registryP; parms.xml_processor_max_stack = xmlrpc_registry_max_stackSize(registryP); parms.uri_path = uriPath; xmlrpc_server_abyss_set_handler3(envP, srvP, &parms, XMLRPC_AHPSIZE(uri_path)); } void xmlrpc_server_abyss_set_default_handler(TServer * const srvP) { ServerDefaultHandler(srvP, xmlrpc_serverAbyssDefaultUriHandler); } static void setHandlersRegistry(TServer * const srvP, const char * const uriPath, xmlrpc_registry * const registryP, bool const chunkResponse, const char * const allowOrigin, bool const expires, unsigned int const maxAge) { xmlrpc_env env; xmlrpc_server_abyss_handler_parms parms; xmlrpc_env_init(&env); parms.xml_processor = &processXmlrpcCall; parms.xml_processor_arg = registryP; parms.xml_processor_max_stack = xmlrpc_registry_max_stackSize(registryP), parms.uri_path = uriPath; parms.chunk_response = chunkResponse; parms.allow_origin = allowOrigin; parms.access_ctl_expires = expires; parms.access_ctl_max_age = maxAge; xmlrpc_server_abyss_set_handler3( &env, srvP, &parms, XMLRPC_AHPSIZE(access_ctl_max_age)); if (env.fault_occurred) abort(); xmlrpc_env_clean(&env); xmlrpc_server_abyss_set_default_handler(srvP); } void xmlrpc_server_abyss_set_handlers2(TServer * const srvP, const char * const uriPath, xmlrpc_registry * const registryP) { setHandlersRegistry(srvP, uriPath, registryP, false, NULL, false, 0); } void xmlrpc_server_abyss_set_handlers(TServer * const srvP, xmlrpc_registry * const registryP) { setHandlersRegistry(srvP, "/RPC2", registryP, false, NULL, false, 0); } /*============================================================================ createServer() ============================================================================*/ static void setAdditionalServerParms(const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize, TServer * const serverP) { if (parmSize >= XMLRPC_APSIZE(keepalive_timeout) && parmsP->keepalive_timeout > 0) ServerSetKeepaliveTimeout(serverP, parmsP->keepalive_timeout); if (parmSize >= XMLRPC_APSIZE(keepalive_max_conn) && parmsP->keepalive_max_conn > 0) ServerSetKeepaliveMaxConn(serverP, parmsP->keepalive_max_conn); if (parmSize >= XMLRPC_APSIZE(timeout) && parmsP->timeout > 0) ServerSetTimeout(serverP, parmsP->timeout); if (parmSize >= XMLRPC_APSIZE(dont_advertise)) ServerSetAdvertise(serverP, !parmsP->dont_advertise); if (parmSize >= XMLRPC_APSIZE(max_conn)) { if (parmsP->max_conn != 0) ServerSetMaxConn(serverP, parmsP->max_conn); } if (parmSize >= XMLRPC_APSIZE(max_conn_backlog)) { if (parmsP->max_conn_backlog != 0) ServerSetMaxConnBacklog(serverP, parmsP->max_conn_backlog); } } static void extractSockAddrParms(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize, const struct sockaddr ** const sockAddrPP, socklen_t * const sockAddrLenP, unsigned int * const portNumberP) { /*---------------------------------------------------------------------------- Return the server parameters that affect the address on which the server socket shall listen. There are two ways the arguments can specify this: 1) user supplies a complete socket address, which specifies both a TCP port number and an IP address (which determines on which interface, ergo which network, if any, the server listens); and 2) just a TCP port number, which means he wants to listen on all IPv4 interfaces and networks. (2) is legacy. If the user specifies the 'sockaddrP' and 'sockaddrlen' arguments, he gets (1) and we ignore his 'port' argument. We return his 'sockaddrP' and 'sockaddrlen' values as *sockAddrPP and *sockAddrLenP and nothing as *portNumberP. If the user doesn't specify 'sockaddrP', he gets (2). We return NULL as *sockAddrP and his 'port_number' argument as *portNumberP. If he doesn't specify 'port' either, we default it to 8080. Specifying 'sockaddrP' and not 'sockaddrlen' is an error. Note that the user's socket address may indicate "any IP address." -----------------------------------------------------------------------------*/ if (parmSize >= XMLRPC_APSIZE(sockaddr_p)) { if (parmSize < XMLRPC_APSIZE(sockaddrlen)) xmlrpc_faultf(envP, "You must specify 'sockaddrlen' when you " "specify 'sockaddrP'"); else { *sockAddrPP = parmsP->sockaddr_p; *sockAddrLenP = parmsP->sockaddrlen; } } else *sockAddrPP = NULL; if (*sockAddrPP == NULL) { unsigned int portNumber; if (parmSize >= XMLRPC_APSIZE(port_number)) portNumber = parmsP->port_number; else portNumber = 8080; if (portNumber > 0xffff) xmlrpc_faultf(envP, "TCP port number %u exceeds the maximum possible " "TCP port number (65535)", portNumber); *portNumberP = portNumber; } } static void extractServerCreateParms( xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize, bool * const socketBoundP, const struct sockaddr ** const sockAddrPP, socklen_t * const sockAddrLenP, unsigned int * const portNumberP, TOsSocket * const socketFdP, const char ** const logFileNameP) { if (parmSize >= XMLRPC_APSIZE(socket_bound)) *socketBoundP = parmsP->socket_bound; else *socketBoundP = FALSE; if (*socketBoundP) { if (parmSize < XMLRPC_APSIZE(socket_handle)) xmlrpc_faultf(envP, "socket_bound is true, but server parameter " "structure does not contain socket_handle (it's too " "short)"); else *socketFdP = parmsP->socket_handle; } else { extractSockAddrParms(envP, parmsP, parmSize, sockAddrPP, sockAddrLenP, portNumberP); } if (!envP->fault_occurred) { if (parmSize >= XMLRPC_APSIZE(log_file_name) && parmsP->log_file_name) *logFileNameP = strdup(parmsP->log_file_name); else *logFileNameP = NULL; } } static void chanSwitchCreateOsSocket(TOsSocket const socketFd, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { #ifdef _WIN32 ChanSwitchWinCreateWinsock(socketFd, chanSwitchPP, errorP); #else ChanSwitchUnixCreateFd(socketFd, chanSwitchPP, errorP); #endif } static void createChanSwitchOsSocket(xmlrpc_env * const envP, TOsSocket const socketFd, TChanSwitch ** const chanSwitchPP) { const char * error; chanSwitchCreateOsSocket(socketFd, chanSwitchPP, &error); if (error) { xmlrpc_faultf(envP, "Unable to create Abyss channel switch out of " "file descriptor %d. %s", socketFd, error); xmlrpc_strfree(error); } } static void chanSwitchCreateSockAddr(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { #ifdef _WIN32 ChanSwitchWinCreate2(protocolFamily, sockAddrP, sockAddrLen, chanSwitchPP, errorP); #else ChanSwitchUnixCreate2(protocolFamily, sockAddrP, sockAddrLen, chanSwitchPP, errorP); #endif } static void createChanSwitchSockAddr(xmlrpc_env * const envP, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP) { int protocolFamily; assert(sockAddrP); switch (sockAddrP->sa_family) { case AF_INET: protocolFamily = PF_INET; break; case AF_INET6: protocolFamily = PF_INET6; break; default: xmlrpc_faultf(envP, "Unknown socket address family %d. " "We know only AF_INET and AF_INET6.", sockAddrP->sa_family); } if (!envP->fault_occurred) { const char * error; chanSwitchCreateSockAddr(protocolFamily, sockAddrP, sockAddrLen, chanSwitchPP, &error); if (error) { xmlrpc_faultf(envP, "Unable to create Abyss channel switch " "given the socket address. %s", error); xmlrpc_strfree(error); } } } static void createChanSwitchIpv4Port(xmlrpc_env * const envP, unsigned int const portNumber, TChanSwitch ** const chanSwitchPP) { struct sockaddr_in sockAddr; const char * error; sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(portNumber); sockAddr.sin_addr.s_addr = INADDR_ANY; chanSwitchCreateSockAddr(PF_INET, (const struct sockaddr *)&sockAddr, sizeof(sockAddr), chanSwitchPP, &error); if (error) { xmlrpc_faultf(envP, "Unable to create Abyss channel switch " "to listen on Port %u at any IPv4 address. %s", portNumber, error); xmlrpc_strfree(error); } } static void createServerBare(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize, TServer * const serverP, TChanSwitch ** const chanSwitchPP) { /*---------------------------------------------------------------------------- Create a bare server. It will need further setup before it is ready to use. -----------------------------------------------------------------------------*/ bool socketBound; const struct sockaddr * sockAddrP; socklen_t sockAddrLen; unsigned int portNumber; TOsSocket socketFd; const char * logFileName; extractServerCreateParms(envP, parmsP, parmSize, &socketBound, &sockAddrP, &sockAddrLen, &portNumber, &socketFd, &logFileName); if (!envP->fault_occurred) { TChanSwitch * chanSwitchP; if (socketBound) createChanSwitchOsSocket(envP, socketFd, &chanSwitchP); else { if (sockAddrP) createChanSwitchSockAddr(envP, sockAddrP, sockAddrLen, &chanSwitchP); else createChanSwitchIpv4Port(envP, portNumber, &chanSwitchP); } if (!envP->fault_occurred) { const char * error; ServerCreateSwitch(serverP, chanSwitchP, &error); if (error) { xmlrpc_faultf(envP, "Abyss failed to create server. %s", error); xmlrpc_strfree(error); } else { *chanSwitchPP = chanSwitchP; ServerSetName(serverP, "XmlRpcServer"); if (logFileName) ServerSetLogFileName(serverP, logFileName); } if (envP->fault_occurred) ChanSwitchDestroy(chanSwitchP); } if (logFileName) xmlrpc_strfree(logFileName); } } static const char * uriPathParm(const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { const char * uriPath; if (parmSize >= XMLRPC_APSIZE(uri_path) && parmsP->uri_path) uriPath = parmsP->uri_path; else uriPath = "/RPC2"; return uriPath; } static bool chunkResponseParm(const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { return parmSize >= XMLRPC_APSIZE(chunk_response) && parmsP->chunk_response; } static const char * allowOriginParm(const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { return parmSize >= XMLRPC_APSIZE(allow_origin) ? parmsP->allow_origin : NULL; } static bool expiresParm(const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { return parmSize >= XMLRPC_APSIZE(access_ctl_expires) ? parmsP->access_ctl_expires : false; } static unsigned int maxAgeParm(const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { return parmSize >= XMLRPC_APSIZE(access_ctl_max_age) ? parmsP->access_ctl_max_age : 0; } static void createServer(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize, TServer * const abyssServerP, TChanSwitch ** const chanSwitchPP) { createServerBare(envP, parmsP, parmSize, abyssServerP, chanSwitchPP); if (!envP->fault_occurred) { const char * error; setAdditionalServerParms(parmsP, parmSize, abyssServerP); setHandlersRegistry(abyssServerP, uriPathParm(parmsP, parmSize), parmsP->registryP, chunkResponseParm(parmsP, parmSize), allowOriginParm(parmsP, parmSize), expiresParm(parmsP, parmSize), maxAgeParm(parmsP, parmSize)); ServerInit2(abyssServerP, &error); if (error) { xmlrpc_faultf(envP, error); xmlrpc_strfree(error); } } } static bool enableShutdownParm(const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { return parmSize >= XMLRPC_APSIZE(enable_shutdown) && parmsP->enable_shutdown; } static xmlrpc_server_shutdown_fn shutdownAbyss; static void shutdownAbyss(xmlrpc_env * const faultP, void * const context, const char * const comment ATTR_UNUSED, void * const callInfo ATTR_UNUSED) { /*---------------------------------------------------------------------------- Tell Abyss to wrap up whatever it's doing and shut down. This is a server shutdown function to be registered in the method registry, for use by the 'system.shutdown' system method. After we return, Abyss will finish up the system.shutdown and any other connections that are in progress, then the call to ServerRun() etc. will return. *faultP is the result of the shutdown request, not whether we succeeded or failed. We are not allowed to fail. -----------------------------------------------------------------------------*/ xmlrpc_server_abyss_t * const serverP = context; xmlrpc_env_init(faultP); if (!serverP->shutdownEnabled) xmlrpc_env_set_fault_formatted( faultP, XMLRPC_REQUEST_REFUSED_ERROR, "Shutdown by client is disabled on this server."); else ServerTerminate(&serverP->abyssServer); } /*============================================================================= xmlrpc_server_abyss object methods =============================================================================*/ void xmlrpc_server_abyss_create(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize, xmlrpc_server_abyss_t ** const serverPP) { xmlrpc_server_abyss_t * serverP; XMLRPC_ASSERT_ENV_OK(envP); validateGlobalInit(envP); if (!envP->fault_occurred) { if (parmSize < XMLRPC_APSIZE(registryP)) xmlrpc_faultf(envP, "You must specify members at least up through " "'registryP' in the server parameters argument. " "That would mean the parameter size would be >= %u " "but you specified a size of %u", (unsigned)XMLRPC_APSIZE(registryP), parmSize); else { MALLOCVAR(serverP); if (serverP == NULL) xmlrpc_faultf(envP, "Unable to allocate memory for " "server descriptor."); else { createServer(envP, parmsP, parmSize, &serverP->abyssServer, &serverP->chanSwitchP); if (!envP->fault_occurred) { serverP->shutdownEnabled = enableShutdownParm(parmsP, parmSize); xmlrpc_registry_set_shutdown( parmsP->registryP, &shutdownAbyss, serverP); if (envP->fault_occurred) free(serverP); else *serverPP = serverP; } } } } } void xmlrpc_server_abyss_destroy(xmlrpc_server_abyss_t * const serverP) { XMLRPC_ASSERT(globallyInitialized); ServerFree(&serverP->abyssServer); if (serverP->chanSwitchP) ChanSwitchDestroy(serverP->chanSwitchP); free(serverP); } void xmlrpc_server_abyss_use_sigchld(xmlrpc_server_abyss_t * const serverP) { ServerUseSigchld(&serverP->abyssServer); } void xmlrpc_server_abyss_run_server(xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_server_abyss_t * const serverP) { ServerRun(&serverP->abyssServer); } void xmlrpc_server_abyss_terminate( xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_server_abyss_t * const serverP) { ServerTerminate(&serverP->abyssServer); } void xmlrpc_server_abyss_reset_terminate( xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_server_abyss_t * const serverP) { ServerResetTerminate(&serverP->abyssServer); } static void sigchld(int const signalClass ATTR_UNUSED) { /*---------------------------------------------------------------------------- This is a signal handler for a SIGCHLD signal (which informs us that one of our child processes has terminated). The only child processes we have are those that belong to the Abyss server (and then only if the Abyss server was configured to use forking as a threading mechanism), so we respond by passing the signal on to the Abyss server. And reaping the dead child. -----------------------------------------------------------------------------*/ #ifndef _WIN32 /* Reap zombie children / report to Abyss until there aren't any more. */ bool childrenLeft; bool error; assert(signalClass == SIGCHLD); error = false; childrenLeft = true; /* initial assumption */ /* Reap defunct children until there aren't any more. */ while (childrenLeft && !error) { int status; pid_t pid; pid = waitpid((pid_t) -1, &status, WNOHANG); if (pid == 0) childrenLeft = false; else if (pid < 0) { /* because of ptrace */ if (errno != EINTR) error = true; } else ServerHandleSigchld(pid); } #endif /* _WIN32 */ } struct xmlrpc_server_abyss_sig { /* A description of the state of the process' signal handlers before functions in this library messed with them; useful for restoring them later. */ #ifndef _WIN32 struct sigaction pipe; struct sigaction chld; #else int dummy; #endif }; static void setupSignalHandlers(xmlrpc_server_abyss_sig * const oldHandlersP) { #ifndef _WIN32 struct sigaction mysigaction; sigemptyset(&mysigaction.sa_mask); mysigaction.sa_flags = 0; /* This signal indicates connection closed in the middle */ mysigaction.sa_handler = SIG_IGN; sigaction(SIGPIPE, &mysigaction, &oldHandlersP->pipe); /* This signal indicates a child process (request handler) has died */ mysigaction.sa_handler = sigchld; sigaction(SIGCHLD, &mysigaction, &oldHandlersP->chld); #endif } static void restoreSignalHandlers(const xmlrpc_server_abyss_sig * const oldHandlersP) { #ifndef _WIN32 sigaction(SIGPIPE, &oldHandlersP->pipe, NULL); sigaction(SIGCHLD, &oldHandlersP->chld, NULL); #endif } void xmlrpc_server_abyss_setup_sig( xmlrpc_env * const envP, xmlrpc_server_abyss_t * const serverP, xmlrpc_server_abyss_sig ** const oldHandlersPP) { xmlrpc_server_abyss_sig * oldHandlersP; XMLRPC_ASSERT_ENV_OK(envP); validateGlobalInit(envP); if (!envP->fault_occurred) { MALLOCVAR(oldHandlersP); if (oldHandlersP == NULL) xmlrpc_faultf(envP, "Unable to allocate memory to save signal " "handling state."); else { setupSignalHandlers(oldHandlersP); xmlrpc_server_abyss_use_sigchld(serverP); } if (oldHandlersPP) *oldHandlersPP = oldHandlersP; else free(oldHandlersP); } } void xmlrpc_server_abyss_restore_sig( const xmlrpc_server_abyss_sig * const oldHandlersP) { restoreSignalHandlers(oldHandlersP); } static void runServerDaemon(TServer * const serverP, runfirstFn const runfirst, void * const runfirstArg) { xmlrpc_server_abyss_sig oldHandlers; setupSignalHandlers(&oldHandlers); ServerUseSigchld(serverP); ServerDaemonize(serverP); /* We run the user supplied runfirst after forking, but before accepting connections (helpful when running with threads) */ if (runfirst) runfirst(runfirstArg); ServerRun(serverP); restoreSignalHandlers(&oldHandlers); } static void oldHighLevelAbyssRun(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { /*---------------------------------------------------------------------------- This is the old deprecated interface, where the caller of the xmlrpc_server_abyss API supplies an Abyss configuration file and we use it to daemonize (fork into the background, chdir, set uid, etc.) and run the Abyss server. The new preferred interface, implemented by normalLevelAbyssRun(), instead lets Caller set up the process environment himself and pass Abyss parameters in memory. That's a more conventional and flexible API. -----------------------------------------------------------------------------*/ TServer server; abyss_bool success; success = ServerCreate(&server, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); if (!success) xmlrpc_faultf(envP, "Failed to create Abyss server object"); else { runfirstFn runfirst; void * runfirstArg; assert(parmSize >= XMLRPC_APSIZE(config_file_name)); ConfReadServerFile(parmsP->config_file_name, &server); assert(parmSize >= XMLRPC_APSIZE(registryP)); setHandlersRegistry(&server, "/RPC2", parmsP->registryP, false, NULL, false, 0); ServerInit(&server); if (parmSize >= XMLRPC_APSIZE(runfirst_arg)) { runfirst = parmsP->runfirst; runfirstArg = parmsP->runfirst_arg; } else { runfirst = NULL; runfirstArg = NULL; } runServerDaemon(&server, runfirst, runfirstArg); ServerFree(&server); } } static void normalLevelAbyssRun(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { xmlrpc_server_abyss_t * serverP; xmlrpc_server_abyss_create(envP, parmsP, parmSize, &serverP); if (!envP->fault_occurred) { xmlrpc_server_abyss_sig * oldHandlersP; xmlrpc_server_abyss_setup_sig(envP, serverP, &oldHandlersP); if (!envP->fault_occurred) { xmlrpc_server_abyss_run_server(envP, serverP); xmlrpc_server_abyss_restore_sig(oldHandlersP); free(oldHandlersP); } xmlrpc_server_abyss_destroy(serverP); } } void xmlrpc_server_abyss(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { /*---------------------------------------------------------------------------- Note that this is not re-entrant and not thread-safe, due to the global library initialization. If you want to run a server inside a thread of a multi-threaded program, use xmlrpc_server_abyss_create() instead. As required by that subroutine, your program will contain a call to xmlrpc_server_abyss_global_init() early in your program, when it is only one thread. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); xmlrpc_server_abyss_global_init(envP); if (!envP->fault_occurred) { if (parmSize < XMLRPC_APSIZE(registryP)) xmlrpc_faultf(envP, "You must specify members at least up through " "'registryP' in the server parameters argument. " "That would mean the parameter size would be >= %u " "but you specified a size of %u", (unsigned)XMLRPC_APSIZE(registryP), parmSize); else { if (parmsP->config_file_name) oldHighLevelAbyssRun(envP, parmsP, parmSize); else normalLevelAbyssRun(envP, parmsP, parmSize); } xmlrpc_server_abyss_global_term(); } } /*========================================================================= XML-RPC Server Method Registry This is an old deprecated form of the server facilities that uses global variables. =========================================================================*/ /* These global variables must be treated as read-only after the server has started. */ static TServer globalSrv; /* When you use the old interface (xmlrpc_server_abyss_init(), etc.), this is the Abyss server to which they refer. Obviously, there can be only one Abyss server per program using this interface. */ static xmlrpc_registry * builtin_registryP; void xmlrpc_server_abyss_init_registry(void) { /* This used to just create the registry and Caller would be responsible for adding the handlers that use it. But that isn't very modular -- the handlers and registry go together; there's no sense in using the built-in registry and not the built-in handlers because if you're custom building something, you can just make your own regular registry. So now we tie them together, and we don't export our handlers. */ xmlrpc_env env; xmlrpc_env_init(&env); builtin_registryP = xmlrpc_registry_new(&env); dieIfFaultOccurred(&env); xmlrpc_env_clean(&env); setHandlersRegistry(&globalSrv, "/RPC2", builtin_registryP, false, NULL, false, 0); } xmlrpc_registry * xmlrpc_server_abyss_registry(void) { /* This is highly deprecated. If you want to mess with a registry, make your own with xmlrpc_registry_new() -- don't mess with the internal one. */ return builtin_registryP; } /* A quick & easy shorthand for adding a method. */ void xmlrpc_server_abyss_add_method(char * const method_name, xmlrpc_method const method, void * const user_data) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_registry_add_method(&env, builtin_registryP, NULL, method_name, method, user_data); dieIfFaultOccurred(&env); xmlrpc_env_clean(&env); } void xmlrpc_server_abyss_add_method_w_doc(char * const method_name, xmlrpc_method const method, void * const user_data, char * const signature, char * const help) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_registry_add_method_w_doc( &env, builtin_registryP, NULL, method_name, method, user_data, signature, help); dieIfFaultOccurred(&env); xmlrpc_env_clean(&env); } void xmlrpc_server_abyss_init(int const flags ATTR_UNUSED, const char * const config_file) { abyss_bool success; success = ServerCreate(&globalSrv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); if (!success) abort(); else { ConfReadServerFile(config_file, &globalSrv); xmlrpc_server_abyss_init_registry(); /* Installs /RPC2 handler and default handler that use the built-in registry. */ ServerInit(&globalSrv); } } void xmlrpc_server_abyss_run_first(runfirstFn const runfirst, void * const runfirstArg) { runServerDaemon(&globalSrv, runfirst, runfirstArg); } void xmlrpc_server_abyss_run(void) { runServerDaemon(&globalSrv, NULL, NULL); } /* ** Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. ** ** There is more copyright information in the bottom half of this file. ** Please see it for more details. */ xmlrpc-c-1.33.14/src/xmlrpc_server_cgi.c000066400000000000000000000247201236133176700200760ustar00rootroot00000000000000/* Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ #include "xmlrpc_config.h" #include #include #include /* Windows NT stdout binary mode fix. */ #ifdef _WIN32 #include #include #endif #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/server_cgi.h" /*========================================================================= ** Output Routines **========================================================================= ** These routines send various kinds of responses to the server. */ static void send_xml(const char * const xml_data, size_t const xml_len) { #ifdef _WIN32 _setmode(_fileno(stdout), _O_BINARY); #endif /* Send our CGI headers back to the server. ** XXX - Coercing 'size_t' to 'unsigned long' might be unsafe under ** really weird circumstances. */ fprintf(stdout, "Status: 200 OK\n"); /* Handle authentication cookie being sent back. */ if (getenv("HTTP_COOKIE_AUTH") != NULL) fprintf(stdout, "Set-Cookie: auth=%s\n", getenv("HTTP_COOKIE_AUTH")); fprintf(stdout, "Content-type: text/xml; charset=\"utf-8\"\n"); fprintf(stdout, "Content-length: %ld\n\n", (unsigned long) xml_len); /* Blast out our data. */ fwrite(xml_data, sizeof(char), xml_len, stdout); } static void send_error(int const code, const char * const message, xmlrpc_env * const env) { #ifdef _WIN32 _setmode(_fileno(stdout), _O_BINARY); #endif /* Send an error header. */ fprintf(stdout, "Status: %d %s\n", code, message); fprintf(stdout, "Content-type: text/html\n\n"); /* Send an error message. */ fprintf(stdout, "%d %s\n", code, message); fprintf(stdout, "

%d %s

\n", code, message); fprintf(stdout, "

An error occurred processing your request.

\n"); /* Print out the XML-RPC fault, if present. */ if (env && env->fault_occurred) fprintf(stdout, "

XML-RPC Fault #%d: %s

\n", env->fault_code, env->fault_string); } /*========================================================================= ** die_if_fault_occurred **========================================================================= ** Certain kinds of errors aren't worth the trouble of generating ** an XML-RPC fault. For these, we just send status 500 to our web server ** and log the fault to our server log. */ static void die_if_fault_occurred(xmlrpc_env * const env) { if (env->fault_occurred) { fprintf(stderr, "Unexpected XML-RPC fault: %s (%d)\n", env->fault_string, env->fault_code); send_error(500, "Internal Server Error", env); exit(1); } } /*========================================================================= ** Initialization, Cleanup & Method Registry **========================================================================= ** These are all related, so we group them together. */ static xmlrpc_registry * globalRegistryP; /*========================================================================= ** get_body **========================================================================= ** Slurp the body of the request into an xmlrpc_mem_block. */ static xmlrpc_mem_block * get_body(xmlrpc_env * const env, size_t const length) { xmlrpc_mem_block *result; char *contents; size_t count; XMLRPC_ASSERT_ENV_OK(env); /* Error-handling preconditions. */ result = NULL; #ifdef _WIN32 /* Fix from Jeff Stewart: NT opens stdin and stdout in text mode by default, badly confusing our length calculations. So we need to set the file handle to binary. */ _setmode(_fileno(stdin), _O_BINARY); #endif /* XXX - Puke if length is too big. */ /* Allocate our memory block. */ result = xmlrpc_mem_block_new(env, length); XMLRPC_FAIL_IF_FAULT(env); contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, result); /* Get our data off the network. ** XXX - Coercing 'size_t' to 'unsigned long' might be unsafe under ** really weird circumstances. */ count = fread(contents, sizeof(char), length, stdin); if (count < length) XMLRPC_FAIL2(env, XMLRPC_INTERNAL_ERROR, "Expected %ld bytes, received %ld", (unsigned long) length, (unsigned long) count); cleanup: if (env->fault_occurred) { if (result) xmlrpc_mem_block_free(result); return NULL; } return result; } void xmlrpc_server_cgi_process_call(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Get the XML-RPC call from Standard Input and environment variables, parse it, find the right method, call it, prepare an XML-RPC response with the result, and write it to Standard Output. -----------------------------------------------------------------------------*/ xmlrpc_env env; char *method, *type, *length_str; int length; xmlrpc_mem_block *input, *output; char *input_data, *output_data; size_t input_size, output_size; int code; char *message; /* Error-handling preconditions. */ xmlrpc_env_init(&env); input = output = NULL; /* Set up a default error message. */ code = 500; message = "Internal Server Error"; /* Get our HTTP information from the environment. */ method = getenv("REQUEST_METHOD"); type = getenv("CONTENT_TYPE"); length_str = getenv("CONTENT_LENGTH"); /* Perform some sanity checks. */ if (!method || !xmlrpc_streq(method, "POST")) { code = 405; message = "Method Not Allowed"; XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Expected HTTP method POST"); } if (!type || !xmlrpc_strneq(type, "text/xml", strlen("text/xml"))) { char *template = "Expected content type: \"text/xml\", received: \"%s\""; size_t err_len = strlen(template) + strlen(type) + 1; char *err = malloc(err_len); (void)snprintf(err, err_len, template, type); code = 400; message = "Bad Request"; XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, err); free(err); } if (!length_str) { code = 411; message = "Length Required"; XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Content-length required"); } /* Get our content length. */ length = atoi(length_str); if (length <= 0) { code = 400; message = "Bad Request"; XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Content-length must be > 0"); } /* SECURITY: Make sure our content length is legal. ** XXX - We can cast 'input_len' because we know it's >= 0, yes? */ if ((size_t) length > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) { code = 400; message = "Bad Request"; XMLRPC_FAIL(&env, XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large"); } /* Get our body. */ input = get_body(&env, length); XMLRPC_FAIL_IF_FAULT(&env); input_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, input); input_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, input); /* Process our call. */ xmlrpc_registry_process_call2(&env, registryP, input_data, input_size, NULL, &output); XMLRPC_FAIL_IF_FAULT(&env); output_data = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output); output_size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); /* Send our data. */ send_xml(output_data, output_size); cleanup: if (input) xmlrpc_mem_block_free(input); if (output) xmlrpc_mem_block_free(output); if (env.fault_occurred) send_error(code, message, &env); xmlrpc_env_clean(&env); } void xmlrpc_cgi_init(int const flags ATTR_UNUSED) { xmlrpc_env env; xmlrpc_env_init(&env); globalRegistryP = xmlrpc_registry_new(&env); die_if_fault_occurred(&env); xmlrpc_env_clean(&env); } void xmlrpc_cgi_cleanup(void) { xmlrpc_registry_free(globalRegistryP); } xmlrpc_registry * xmlrpc_cgi_registry(void) { return globalRegistryP; } void xmlrpc_cgi_add_method(const char * const method_name, xmlrpc_method const method, void * const user_data) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_registry_add_method(&env, globalRegistryP, NULL, method_name, method, user_data); die_if_fault_occurred(&env); xmlrpc_env_clean(&env); } void xmlrpc_cgi_add_method_w_doc(const char * const method_name, xmlrpc_method const method, void * const user_data, const char * const signature, const char * const help) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_registry_add_method_w_doc(&env, globalRegistryP, NULL, method_name, method, user_data, signature, help); die_if_fault_occurred(&env); xmlrpc_env_clean(&env); } void xmlrpc_cgi_process_call(void) { xmlrpc_server_cgi_process_call(globalRegistryP); } xmlrpc-c-1.33.14/src/xmlrpc_server_info.c000066400000000000000000000235051236133176700202670ustar00rootroot00000000000000/*============================================================================= xmlrpc_server_info =============================================================================== The xmlrpc_server_info class. By Bryan Henderson, San Jose CA 2007.10.17. Contributed to the public domain by its author The xmlrpc_server_info class was originally just supposed to be information about an HTTP server, hence the name. But we think of it now as a generic carriage parameter, as in the C++ library. In the future, it should be a union or maybe contain an opaque pointer to the carriage parameter for a particular kind of transport. That way, the client XML transports can be more than just HTTP XML transports. =============================================================================*/ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/client_int.h" xmlrpc_server_info * xmlrpc_server_info_new(xmlrpc_env * const envP, const char * const serverUrl) { xmlrpc_server_info * serverInfoP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(serverUrl); MALLOCVAR(serverInfoP); if (serverInfoP == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for xmlrpc_server_info"); else { serverInfoP->serverUrl = strdup(serverUrl); if (serverInfoP->serverUrl == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for server URL"); else { serverInfoP->allowedAuth.basic = false; serverInfoP->allowedAuth.digest = false; serverInfoP->allowedAuth.gssnegotiate = false; serverInfoP->allowedAuth.ntlm = false; serverInfoP->userNamePw = NULL; serverInfoP->basicAuthHdrValue = NULL; if (envP->fault_occurred) xmlrpc_strfree(serverInfoP->serverUrl); } if (envP->fault_occurred) free(serverInfoP); } return serverInfoP; } static void copyUserNamePw(xmlrpc_env * const envP, const char * const src, const char ** const dstP) { if (src == NULL) *dstP = NULL; else { *dstP = strdup(src); if (*dstP == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for user name/pw"); } } static void freeIfNonNull(const char * const arg) { if (arg) xmlrpc_strfree(arg); } static void copyBasicAuthHdrValue(xmlrpc_env * const envP, const char * const src, const char ** const dstP) { if (src == NULL) *dstP = NULL; else { *dstP = strdup(src); if (*dstP == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory " "for authentication header value"); } } static void copyServerInfoContent(xmlrpc_env * const envP, xmlrpc_server_info * const dstP, const xmlrpc_server_info * const srcP) { dstP->serverUrl = strdup(srcP->serverUrl); if (dstP->serverUrl == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for server URL"); else { copyUserNamePw(envP, srcP->userNamePw, &dstP->userNamePw); if (!envP->fault_occurred) { copyBasicAuthHdrValue(envP, srcP->basicAuthHdrValue, &dstP->basicAuthHdrValue); if (!envP->fault_occurred) { dstP->allowedAuth.basic = srcP->allowedAuth.basic; dstP->allowedAuth.digest = srcP->allowedAuth.digest; dstP->allowedAuth.gssnegotiate = srcP->allowedAuth.gssnegotiate; dstP->allowedAuth.ntlm = srcP->allowedAuth.ntlm; if (envP->fault_occurred) freeIfNonNull(dstP->basicAuthHdrValue); } if (envP->fault_occurred) freeIfNonNull(dstP->userNamePw); } if (envP->fault_occurred) xmlrpc_strfree(dstP->serverUrl); } } xmlrpc_server_info * xmlrpc_server_info_copy(xmlrpc_env * const envP, xmlrpc_server_info * const srcP) { xmlrpc_server_info * serverInfoP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(srcP); MALLOCVAR(serverInfoP); if (serverInfoP == NULL) xmlrpc_faultf(envP, "Couldn't allocate memory for xmlrpc_server_info"); else { copyServerInfoContent(envP, serverInfoP, srcP); if (envP->fault_occurred) free(serverInfoP); } return serverInfoP; } void xmlrpc_server_info_free(xmlrpc_server_info * const serverInfoP) { XMLRPC_ASSERT_PTR_OK(serverInfoP); XMLRPC_ASSERT(serverInfoP->serverUrl != XMLRPC_BAD_POINTER); if (serverInfoP->userNamePw) xmlrpc_strfree(serverInfoP->userNamePw); serverInfoP->userNamePw = XMLRPC_BAD_POINTER; if (serverInfoP->basicAuthHdrValue) xmlrpc_strfree(serverInfoP->basicAuthHdrValue); serverInfoP->basicAuthHdrValue = XMLRPC_BAD_POINTER; xmlrpc_strfree(serverInfoP->serverUrl); serverInfoP->serverUrl = XMLRPC_BAD_POINTER; free(serverInfoP); } void xmlrpc_server_info_set_user(xmlrpc_env * const envP, xmlrpc_server_info * const serverInfoP, const char * const username, const char * const password) { const char * userNamePw; xmlrpc_mem_block * userNamePw64; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(serverInfoP); XMLRPC_ASSERT_PTR_OK(username); XMLRPC_ASSERT_PTR_OK(password); xmlrpc_asprintf(&userNamePw, "%s:%s", username, password); userNamePw64 = xmlrpc_base64_encode_without_newlines(envP, (unsigned char*) userNamePw, strlen(userNamePw)); if (!envP->fault_occurred) { const char * const data = XMLRPC_MEMBLOCK_CONTENTS(char, userNamePw64); size_t const len = XMLRPC_MEMBLOCK_SIZE(char, userNamePw64); const char * const authType = "Basic "; char * hdrValue; hdrValue = malloc(strlen(authType) + len + 1); if (hdrValue == NULL) xmlrpc_faultf(envP, "Could not allocate memory to store " "authorization header value."); else { strcpy(hdrValue, authType); strncat(hdrValue, data, len); if (serverInfoP->basicAuthHdrValue) xmlrpc_strfree(serverInfoP->basicAuthHdrValue); serverInfoP->basicAuthHdrValue = hdrValue; } XMLRPC_MEMBLOCK_FREE(char, userNamePw64); } if (serverInfoP->userNamePw) xmlrpc_strfree(serverInfoP->userNamePw); serverInfoP->userNamePw = userNamePw; } void xmlrpc_server_info_set_basic_auth(xmlrpc_env * const envP, xmlrpc_server_info * const serverInfoP, const char * const username, const char * const password) { xmlrpc_server_info_set_user(envP, serverInfoP, username, password); if (!envP->fault_occurred) { serverInfoP->allowedAuth.basic = true; serverInfoP->allowedAuth.digest = false; serverInfoP->allowedAuth.gssnegotiate = false; serverInfoP->allowedAuth.ntlm = false; } } void xmlrpc_server_info_allow_auth_basic(xmlrpc_env * const envP, xmlrpc_server_info * const sP) { if (sP->userNamePw == NULL) xmlrpc_faultf(envP, "You must set username/password with " "xmlrpc_server_info_set_user()"); else sP->allowedAuth.basic = true; } void xmlrpc_server_info_disallow_auth_basic( xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_server_info * const sP) { sP->allowedAuth.basic = false; } void xmlrpc_server_info_allow_auth_digest(xmlrpc_env * const envP, xmlrpc_server_info * const sP) { if (sP->userNamePw == NULL) xmlrpc_faultf(envP, "You must set username/password with " "xmlrpc_server_info_set_user()"); else sP->allowedAuth.digest = true; } void xmlrpc_server_info_disallow_auth_digest( xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_server_info * const sP) { sP->allowedAuth.digest = false; } void xmlrpc_server_info_allow_auth_negotiate(xmlrpc_env * const envP, xmlrpc_server_info * const sP) { if (sP->userNamePw == NULL) xmlrpc_faultf(envP, "You must set username/password with " "xmlrpc_server_info_set_user()"); else sP->allowedAuth.gssnegotiate = true; } void xmlrpc_server_info_disallow_auth_negotiate( xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_server_info * const sP) { sP->allowedAuth.gssnegotiate = false; } void xmlrpc_server_info_allow_auth_ntlm(xmlrpc_env * const envP, xmlrpc_server_info * const sP) { if (sP->userNamePw == NULL) xmlrpc_faultf(envP, "You must set username/password with " "xmlrpc_server_info_set_user()"); else sP->allowedAuth.ntlm = true; } void xmlrpc_server_info_disallow_auth_ntlm( xmlrpc_env * const envP ATTR_UNUSED, xmlrpc_server_info * const sP) { sP->allowedAuth.ntlm = true; } xmlrpc-c-1.33.14/src/xmlrpc_server_w32httpsys.c000066400000000000000000001112031236133176700213770ustar00rootroot00000000000000/* Copyright information is at end of file. */ /* COMPILATION NOTE: Note that the Platform SDK headers and link libraries for Windows XP SP2 or newer are required to compile Xmlrpc-c for this module. If you are not using this XML-RPC server program, it is safe to exclude the xmlrpc_server_w32httpsys.c file from the xmlrpc project and you will not have this dependency. You can get the latest platform SDK at http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ Be sure after installation to choose the program to "register the PSDK directories with Visual Studio" so the newer headers are found. */ #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif /* Declare that we require the Windows XP SP2 or better version of the interface to Windows. Microsoft recommends (http://msdn.microsoft.com/en-us/library/aa383745(VS.85).aspx) defining NTDDI_VERSION instead of _WIN32_WINNT for this purpose, but as it was invented recently, it's pretty useless. Windows header files from old Windows SDKs won't know what to do with it. */ #define _WIN32_WINNT 0x0502 /* See compilation note above if the compiler doesn't find this header file */ #include #include #include "xmlrpc_config.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/server_w32httpsys.h" #include "version.h" #pragma comment( lib, "httpapi" ) #pragma message( "Compiling HTTPS server ..." ) /* XXX - This variable is *not* currently threadsafe. Once the server has ** been started, it must be treated as read-only. */ static xmlrpc_registry *global_registryP; //set TRUE if you want a log static BOOL g_bDebug; //set log filename static char g_fLogFile[MAX_PATH]; //do you want OutputDebugString() to be called? static BOOL g_bDebugString; // // Macros. // #define INITIALIZE_HTTP_RESPONSE( resp, status, reason ) \ do \ { \ RtlZeroMemory( (resp), sizeof(*(resp)) ); \ (resp)->StatusCode = (status); \ (resp)->pReason = (reason); \ (resp)->ReasonLength = (USHORT) strlen(reason); \ } while (FALSE) #define ADD_KNOWN_HEADER(Response, HeaderId, RawValue) \ do \ { \ (Response).Headers.KnownHeaders[(HeaderId)].pRawValue = (RawValue); \ (Response).Headers.KnownHeaders[(HeaderId)].RawValueLength = \ (USHORT) strlen(RawValue); \ } while(FALSE) #define ALLOC_MEM(cb) HeapAlloc(GetProcessHeap(), 0, (cb)) #define FREE_MEM(ptr) HeapFree(GetProcessHeap(), 0, (ptr)) // // Prototypes for Internal Functions. // DWORD DoReceiveRequests( HANDLE hReqQueue, const xmlrpc_server_httpsys_parms * const parmsP ); DWORD SendHttpResponse( IN HANDLE hReqQueue, IN PHTTP_REQUEST pRequest, IN USHORT StatusCode, IN PSTR pReason, IN PSTR pEntity ); DWORD SendHttpResponseAuthRequired( IN HANDLE hReqQueue, IN PHTTP_REQUEST pRequest ); void processRPCCall( xmlrpc_env * const envP, IN HANDLE hReqQueue, IN PHTTP_REQUEST pRequest ); __inline void TraceA(const char *format, ...); __inline void TraceW(const wchar_t *format, ...); // // External Function Implementation. // void xmlrpc_server_httpsys( xmlrpc_env * const envP, const xmlrpc_server_httpsys_parms * const parmsP, unsigned int const parm_size ) { ULONG retCode; HANDLE hReqQueue = NULL; HTTPAPI_VERSION HttpApiVersion = HTTPAPI_VERSION_1; WCHAR wszURL[35]; XMLRPC_ASSERT_ENV_OK(envP); if (parm_size < XMLRPC_HSSIZE(authfn)) { xmlrpc_faultf(envP, "You must specify members at least up through " "'authfn' in the server parameters argument. " "That would mean the parameter size would be >= %u " "but you specified a size of %u", XMLRPC_HSSIZE(authfn), parm_size); return; } //Set logging options if (parmsP->logLevel>0) g_bDebug=TRUE; else g_bDebug=FALSE; if (parmsP->logLevel>1) g_bDebugString=TRUE; else g_bDebugString=FALSE; if (!parmsP->logFile) g_bDebug=FALSE; else StringCchPrintfA(g_fLogFile,MAX_PATH,parmsP->logFile); //construct the URL we are listening on if (parmsP->useSSL!=0) StringCchPrintf(wszURL,35,L"https://+:%u/RPC2",parmsP->portNum); else StringCchPrintf(wszURL,35,L"http://+:%u/RPC2",parmsP->portNum); global_registryP = parmsP->registryP; // Initialize HTTP APIs. retCode = HttpInitialize(HttpApiVersion, HTTP_INITIALIZE_SERVER, // Flags NULL // Reserved ); if (retCode != NO_ERROR) { xmlrpc_faultf(envP, "HttpInitialize failed with %lu", retCode); return; } // Create a Request Queue Handle retCode = HttpCreateHttpHandle(&hReqQueue, // Req Queue 0 // Reserved ); if (retCode != NO_ERROR) { xmlrpc_faultf(envP, "HttpCreateHttpHandle failed with %lu", retCode); goto CleanUp; } retCode = HttpAddUrl(hReqQueue, // Req Queue wszURL, // Fully qualified URL NULL // Reserved ); if (retCode != NO_ERROR) { xmlrpc_faultf(envP, "HttpAddUrl failed with %lu", retCode); goto CleanUp; } TraceW(L"we are listening for requests on the following url: %ws", wszURL); // Loop while receiving requests for(;;) { TraceW(L"Calling DoReceiveRequests()"); retCode = DoReceiveRequests(hReqQueue, parmsP); if(NO_ERROR == retCode) { TraceW(L"DoReceiveRequests() returned NO_ERROR, breaking"); break; } } CleanUp: TraceW(L"Tearing down the server.", wszURL); // Call HttpRemoveUrl for the URL that we added. HttpRemoveUrl( hReqQueue, wszURL ); // Close the Request Queue handle. if(hReqQueue) CloseHandle(hReqQueue); // Call HttpTerminate. HttpTerminate(HTTP_INITIALIZE_SERVER, NULL); return; } // // Internal Function Implementations. // __inline void TraceA(const char *format, ...) { if(g_bDebug) { if (format) { va_list arglist; char str[4096]; va_start(arglist, format); StringCchVPrintfA(str, sizeof(str), format, arglist); StringCbCatA(str, sizeof(str), "\n"); if (g_fLogFile) { FILE *fout = fopen(g_fLogFile, "a+t"); if (fout) { fprintf(fout, str); fclose(fout); } } printf(str); if (g_bDebugString) { OutputDebugStringA(str); } va_end(arglist); } } } __inline void TraceW(const wchar_t *format, ...) { if(g_bDebug) { if (format) { va_list arglist; wchar_t str[4096]; va_start(arglist, format); StringCchVPrintfW(str, 4096, format, arglist); StringCbCatW(str, sizeof(str), L"\n"); if (g_fLogFile) { FILE *fout = fopen(g_fLogFile, "a+t"); if (fout) { fwprintf(fout, str); fclose(fout); } } wprintf(str); if (g_bDebugString) { OutputDebugStringW(str); } va_end(arglist); } } } /* * This is a blocking function that merely sits on the request queue * for our URI and processes them one at a time. Once a request comes * in, we check it for content-type, content-length, and verb. As long * as the initial validations are done, we pass the request to the * processRPCCall() function, which collects the body of the request * and processes it. If we get an error back other than network type, * we are responsible for notifing the client. */ DWORD DoReceiveRequests( IN HANDLE hReqQueue, const xmlrpc_server_httpsys_parms * const parmsP ) { ULONG result; HTTP_REQUEST_ID requestId; DWORD bytesRead; PHTTP_REQUEST pRequest; PCHAR pRequestBuffer; ULONG RequestBufferLength; xmlrpc_env env; char szHeaderBuf[255]; long lContentLength; // Allocate a 2K buffer. Should be good for most requests, we'll grow // this if required. We also need space for a HTTP_REQUEST structure. RequestBufferLength = sizeof(HTTP_REQUEST) + 2048; pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength ); if (pRequestBuffer == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } pRequest = (PHTTP_REQUEST)pRequestBuffer; // Wait for a new request -- This is indicated by a NULL request ID. HTTP_SET_NULL_ID( &requestId ); for(;;) { RtlZeroMemory(pRequest, RequestBufferLength); result = HttpReceiveHttpRequest( hReqQueue, // Req Queue requestId, // Req ID 0, // Flags pRequest, // HTTP request buffer RequestBufferLength,// req buffer length &bytesRead, // bytes received NULL // LPOVERLAPPED ); if(NO_ERROR == result) { // Got a request with a filled buffer. switch(pRequest->Verb) { case HttpVerbPOST: TraceW(L"Got a POST request for %ws", pRequest->CookedUrl.pFullUrl); //Check if we need use authorization. if(parmsP->authfn) { xmlrpc_env_init(&env); if(pRequest->Headers.KnownHeaders[ HttpHeaderAuthorization].RawValueLength < 6) { xmlrpc_env_set_fault( &env, XMLRPC_REQUEST_REFUSED_ERROR, "Authorization header too short."); } else { //unencode the headers if(_strnicmp( "basic", pRequest->Headers.KnownHeaders[ HttpHeaderAuthorization].pRawValue,5) !=0) { #ifndef NDEBUG PCHAR pTmp = (PCHAR) ALLOC_MEM(pRequest->Headers.KnownHeaders[ HttpHeaderAuthorization ].RawValueLength + 1 ); if( pTmp ) { strncpy(pTmp, pRequest->Headers.KnownHeaders[ HttpHeaderAuthorization ].pRawValue, pRequest->Headers.KnownHeaders[ HttpHeaderAuthorization ].RawValueLength ); pTmp[pRequest->Headers.KnownHeaders[ HttpHeaderAuthorization ].RawValueLength] = 0; TraceA("Got HEADER [%s]",pTmp); FREE_MEM(pTmp); } #endif /* #ifndef NDEBUG */ xmlrpc_env_set_fault( &env, XMLRPC_REQUEST_REFUSED_ERROR, "Authorization header does not start " "with type 'basic'!"); } else { xmlrpc_mem_block * decoded; decoded = xmlrpc_base64_decode( &env, pRequest->Headers.KnownHeaders[ HttpHeaderAuthorization ].pRawValue+6, pRequest->Headers.KnownHeaders[ HttpHeaderAuthorization ].RawValueLength-6); if(!env.fault_occurred) { char *pDecodedStr; char *pUser; char *pPass; char *pColon; pDecodedStr = (char*) malloc(decoded->_size+1); memcpy(pDecodedStr, decoded->_block, decoded->_size); pDecodedStr[decoded->_size]='\0'; pUser = pPass = pDecodedStr; pColon=strchr(pDecodedStr,':'); if(pColon) { *pColon='\0'; pPass=pColon+1; //The authfn should set env to //fail if auth is denied. parmsP->authfn(&env,pUser,pPass); } else { xmlrpc_env_set_fault( &env, XMLRPC_REQUEST_REFUSED_ERROR, "Decoded auth not of the correct " "format."); } free(pDecodedStr); } if(decoded) XMLRPC_MEMBLOCK_FREE(char, decoded); } } if(env.fault_occurred) { //request basic authorization, as the user //did not provide it. xmlrpc_env_clean(&env); TraceW(L"POST request did not provide valid " L"authorization header."); result = SendHttpResponseAuthRequired( hReqQueue, pRequest); break; } xmlrpc_env_clean(&env); } //Check content type to make sure it is text/xml. memcpy(szHeaderBuf, pRequest->Headers.KnownHeaders[ HttpHeaderContentType ].pRawValue, pRequest->Headers.KnownHeaders[ HttpHeaderContentType ].RawValueLength); szHeaderBuf[pRequest->Headers.KnownHeaders[ HttpHeaderContentType ].RawValueLength] = '\0'; if (_stricmp(szHeaderBuf,"text/xml")!=0) { //We handle only text/xml data. Anything else //is not valid. TraceW(L"POST request had an unrecognized " L"content-type: %s", szHeaderBuf); result = SendHttpResponse( hReqQueue, pRequest, 400, "Bad Request", NULL ); break; } //Check content length to make sure it exists and //is not too big. memcpy(szHeaderBuf, pRequest->Headers.KnownHeaders[ HttpHeaderContentLength ].pRawValue, pRequest->Headers.KnownHeaders[ HttpHeaderContentLength ].RawValueLength); szHeaderBuf[pRequest->Headers.KnownHeaders[ HttpHeaderContentLength ].RawValueLength]='\0'; lContentLength = atol(szHeaderBuf); if (lContentLength<=0) { //Make sure a content length was supplied. TraceW(L"POST request did not include a " L"content-length", szHeaderBuf); result = SendHttpResponse( hReqQueue, pRequest, 411, "Length Required", NULL ); break; } if((size_t) lContentLength > xmlrpc_limit_get(XMLRPC_XML_SIZE_LIMIT_ID)) { //Content-length is too big for us to handle TraceW(L"POST request content-length is too big " L"for us to handle: %d bytes", lContentLength); result = SendHttpResponse( hReqQueue, pRequest, 500, "content-length too large", NULL ); break; } //our initial validations of POST, content-type, //and content-length all check out. Collect and //pass the complete buffer to the XMLRPC-C library xmlrpc_env_init(&env); processRPCCall(&env,hReqQueue, pRequest); if (env.fault_occurred) { //if we fail and it is anything other than a //network error, we should return a failure //response to the client. if (env.fault_code != XMLRPC_NETWORK_ERROR) { if (env.fault_string) result = SendHttpResponse( hReqQueue, pRequest, 500, env.fault_string, NULL ); else result = SendHttpResponse( hReqQueue, pRequest, 500, "Unknown Error", NULL ); } } xmlrpc_env_clean(&env); break; default: //We handle only POST data. Anything else is not valid. TraceW(L"Got an unrecognized Verb request for URI %ws", pRequest->CookedUrl.pFullUrl); result = SendHttpResponse( hReqQueue, pRequest, 405, "Method Not Allowed", NULL ); break; } if(result != NO_ERROR) { break; } // Reset the Request ID so that we pick up the next request. HTTP_SET_NULL_ID( &requestId ); } else if(result == ERROR_MORE_DATA) { // The input buffer was too small to hold the request headers // We have to allocate more buffer & call the API again. // // When we call the API again, we want to pick up the request // that just failed. This is done by passing a RequestID. // This RequestID is picked from the old buffer. requestId = pRequest->RequestId; // Free the old buffer and allocate a new one. RequestBufferLength = bytesRead; FREE_MEM( pRequestBuffer ); pRequestBuffer = (PCHAR) ALLOC_MEM( RequestBufferLength ); if (pRequestBuffer == NULL) { result = ERROR_NOT_ENOUGH_MEMORY; break; } pRequest = (PHTTP_REQUEST)pRequestBuffer; } else if(ERROR_CONNECTION_INVALID == result && !HTTP_IS_NULL_ID(&requestId)) { // The TCP connection got torn down by the peer when we were // trying to pick up a request with more buffer. We'll just move // onto the next request. HTTP_SET_NULL_ID( &requestId ); } else { break; } } // for(;;) if(pRequestBuffer) { FREE_MEM( pRequestBuffer ); } return result; } /* * SendHttpResponse sends a text/html content type back with * the user specified status code and reason. Used for returning * errors to clients. */ DWORD SendHttpResponse( IN HANDLE hReqQueue, IN PHTTP_REQUEST pRequest, IN USHORT StatusCode, IN PSTR pReason, IN PSTR pEntityString ) { HTTP_RESPONSE response; HTTP_DATA_CHUNK dataChunk; DWORD result; DWORD bytesSent; CHAR szServerHeader[20]; // Initialize the HTTP response structure. INITIALIZE_HTTP_RESPONSE(&response, StatusCode, pReason); ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/html"); StringCchPrintfA(szServerHeader, sizeof(szServerHeader), "Xmlrpc-c/%s", XMLRPC_C_VERSION); ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader); if(pEntityString) { // Add an entity chunk dataChunk.DataChunkType = HttpDataChunkFromMemory; dataChunk.FromMemory.pBuffer = pEntityString; dataChunk.FromMemory.BufferLength = (ULONG) strlen(pEntityString); response.EntityChunkCount = 1; response.pEntityChunks = &dataChunk; } // Since we are sending all the entity body in one call, we don't have // to specify the Content-Length. result = HttpSendHttpResponse( hReqQueue, // ReqQueueHandle pRequest->RequestId, // Request ID 0, // Flags &response, // HTTP response NULL, // pReserved1 &bytesSent, // bytes sent (OPTIONAL) NULL, // pReserved2 (must be NULL) 0, // Reserved3 (must be 0) NULL, // LPOVERLAPPED (OPTIONAL) NULL // pReserved4 (must be NULL) ); if(result != NO_ERROR) { TraceW(L"HttpSendHttpResponse failed with %lu", result); } return result; } /* SendHttpResponseAuthRequired sends a 401 status code requesting * authorization */ DWORD SendHttpResponseAuthRequired( IN HANDLE hReqQueue, IN PHTTP_REQUEST pRequest ) { HTTP_RESPONSE response; DWORD result; DWORD bytesSent; CHAR szServerHeader[20]; // Initialize the HTTP response structure. INITIALIZE_HTTP_RESPONSE(&response, 401, "Authentication Required"); // Add the WWW_Authenticate header. ADD_KNOWN_HEADER(response, HttpHeaderWwwAuthenticate, "Basic realm=\"xmlrpc\""); StringCchPrintfA(szServerHeader, sizeof(szServerHeader), "Xmlrpc-c/%s", XMLRPC_C_VERSION); ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader); // Since we are sending all the entity body in one call, we don't have // to specify the Content-Length. result = HttpSendHttpResponse( hReqQueue, // ReqQueueHandle pRequest->RequestId, // Request ID 0, // Flags &response, // HTTP response NULL, // pReserved1 &bytesSent, // bytes sent (OPTIONAL) NULL, // pReserved2 (must be NULL) 0, // Reserved3 (must be 0) NULL, // LPOVERLAPPED (OPTIONAL) NULL // pReserved4 (must be NULL) ); if(result != NO_ERROR) { TraceW(L"SendHttpResponseAuthRequired failed with %lu", result); } return result; } /* * processRPCCall() is called after some validations. The assumption is that * the request is an HTTP post of content-type text/xml with a content-length * that is less than the maximum the library can handle. * * The caller should check the error status, and if the error was other than * a network type, respond back to the client to let them know the call failed. */ void processRPCCall( xmlrpc_env * const envP, IN HANDLE hReqQueue, IN PHTTP_REQUEST pRequest ) { HTTP_RESPONSE response; DWORD result; DWORD bytesSent; PUCHAR pEntityBuffer; ULONG EntityBufferLength; ULONG BytesRead; #define MAX_ULONG_STR ((ULONG) sizeof("4294967295")) CHAR szContentLength[MAX_ULONG_STR]; CHAR szServerHeader[20]; HTTP_DATA_CHUNK dataChunk; ULONG TotalBytesRead = 0; xmlrpc_mem_block * body; xmlrpc_mem_block * output; BytesRead = 0; body = NULL; output = NULL; // Allocate some space for an entity buffer. EntityBufferLength = 2048; pEntityBuffer = (PUCHAR) ALLOC_MEM( EntityBufferLength ); if (pEntityBuffer == NULL) { xmlrpc_faultf(envP, "Out of Memory"); goto Done; } // NOTE: If we had passed the HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY // flag with HttpReceiveHttpRequest(), the entity would have // been a part of HTTP_REQUEST (using the pEntityChunks field). // Since we have not passed that flag, we can be assured that // there are no entity bodies in HTTP_REQUEST. if(pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS) { //Allocate some space for an XMLRPC memory block. body = xmlrpc_mem_block_new(envP, 0); if (envP->fault_occurred) goto Done; // The entity body can be sent over multiple calls. Let's collect all // of these in a buffer and send the buffer to the xmlrpc-c library do { // Read the entity chunk from the request. BytesRead = 0; result = HttpReceiveRequestEntityBody( hReqQueue, pRequest->RequestId, 0, pEntityBuffer, EntityBufferLength, &BytesRead, NULL ); switch(result) { case NO_ERROR: if(BytesRead != 0) { XMLRPC_MEMBLOCK_APPEND(char, envP, body, pEntityBuffer, BytesRead); if(envP->fault_occurred) goto Done; } break; case ERROR_HANDLE_EOF: // We have read the last request entity body. We can now // process the suppossed XMLRPC data. if(BytesRead != 0) { XMLRPC_MEMBLOCK_APPEND(char, envP, body, pEntityBuffer, BytesRead); if(envP->fault_occurred) goto Done; } // We will send the response over multiple calls. // This is achieved by passing the // HTTP_SEND_RESPONSE_FLAG_MORE_DATA flag. // NOTE: Since we are accumulating the TotalBytesRead in // a ULONG, this will not work for entity bodies that // are larger than 4 GB. To work with large entity // bodies, we would have to use a ULONGLONG. TraceA("xmlrpc_server RPC2 handler processing " "RPC request."); // Process the RPC. xmlrpc_registry_process_call2( envP, global_registryP, XMLRPC_MEMBLOCK_CONTENTS(char, body), XMLRPC_MEMBLOCK_SIZE(char, body), NULL, &output); if (envP->fault_occurred) goto Done; // Initialize the HTTP response structure. INITIALIZE_HTTP_RESPONSE(&response, 200, "OK"); //Add the content-length StringCchPrintfA(szContentLength,MAX_ULONG_STR, "%lu", XMLRPC_MEMBLOCK_SIZE(char, output)); ADD_KNOWN_HEADER( response, HttpHeaderContentLength, szContentLength ); //Add the content-type ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/xml"); StringCchPrintfA(szServerHeader, sizeof(szServerHeader), "Xmlrpc-c/%s", XMLRPC_C_VERSION); ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader); //send the response result = HttpSendHttpResponse( hReqQueue, // ReqQueueHandle pRequest->RequestId, // Request ID HTTP_SEND_RESPONSE_FLAG_MORE_DATA, &response, // HTTP response NULL, // pReserved1 &bytesSent, // bytes sent (optional) NULL, // pReserved2 0, // Reserved3 NULL, // LPOVERLAPPED NULL // pReserved4 ); if(result != NO_ERROR) { TraceW(L"HttpSendHttpResponse failed with %lu", result); xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "HttpSendHttpResponse failed with %lu", result); goto Done; } // Send entity body from a memory chunk. dataChunk.DataChunkType = HttpDataChunkFromMemory; dataChunk.FromMemory.BufferLength = (ULONG)XMLRPC_MEMBLOCK_SIZE(char, output); dataChunk.FromMemory.pBuffer = XMLRPC_MEMBLOCK_CONTENTS(char, output); result = HttpSendResponseEntityBody( hReqQueue, pRequest->RequestId, 0, // This is the last send. 1, // Entity Chunk Count. &dataChunk, NULL, NULL, 0, NULL, NULL ); if(result != NO_ERROR) { TraceW(L"HttpSendResponseEntityBody failed " L"with %lu", result); xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "HttpSendResponseEntityBody failed with %lu", result); goto Done; } goto Done; break; default: TraceW(L"HttpReceiveRequestEntityBody failed with %lu", result); xmlrpc_env_set_fault_formatted( envP, XMLRPC_NETWORK_ERROR, "HttpReceiveRequestEntityBody failed " "with %lu", result); goto Done; } } while(TRUE); } else { // This request does not have an entity body. TraceA("Received a bad request (no body in HTTP post)."); xmlrpc_env_set_fault_formatted( envP, XMLRPC_PARSE_ERROR, "Bad POST request (no body)"); goto Done; } Done: if(pEntityBuffer) FREE_MEM(pEntityBuffer); if(output) XMLRPC_MEMBLOCK_FREE(char, output); if(body) XMLRPC_MEMBLOCK_FREE(char, body); return; } /* Copyright (C) 2005 by Steven A. Bone, sbone@pobox.com. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/src/xmlrpc_string.c000066400000000000000000000631631236133176700172600ustar00rootroot00000000000000/*============================================================================= xmlrpc_string =============================================================================== Routines for the "string" type of xmlrpc_value. By Bryan Henderson. Contributed to the public domain by its author. =============================================================================*/ #include "xmlrpc_config.h" #include #include #include #include #include "bool.h" #include "mallocvar.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" void xmlrpc_destroyString(xmlrpc_value * const valueP) { if (valueP->_wcs_block) xmlrpc_mem_block_free(valueP->_wcs_block); xmlrpc_mem_block_clean(&valueP->_block); } static void verifyNoNulls(xmlrpc_env * const envP, const char * const contents, unsigned int const len) { /*---------------------------------------------------------------------------- Verify that the character array 'contents', which is 'len' bytes long, does not contain any NUL characters, which means it can be made into a passable ASCIIZ string just by adding a terminating NUL. Fail if the array contains a NUL. -----------------------------------------------------------------------------*/ unsigned int i; for (i = 0; i < len && !envP->fault_occurred; ++i) if (contents[i] == '\0') xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "String must not contain NUL characters"); } #if HAVE_UNICODE_WCHAR static void verifyNoNullsW(xmlrpc_env * const envP, const wchar_t * const contents, unsigned int const len) { /*---------------------------------------------------------------------------- Same as verifyNoNulls(), but for wide characters. -----------------------------------------------------------------------------*/ unsigned int i; for (i = 0; i < len && !envP->fault_occurred; i++) if (contents[i] == '\0') xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "String must not contain NUL characters"); } #endif static void validateStringType(xmlrpc_env * const envP, const xmlrpc_value * const valueP) { if (valueP->_type != XMLRPC_TYPE_STRING) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value of type %s supplied where " "string type was expected.", xmlrpc_type_name(valueP->_type)); } } static void accessStringValue(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const char ** const contentsP) { validateStringType(envP, valueP); if (!envP->fault_occurred) { size_t const size = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); const char * const contents = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); size_t const len = size - 1; /* The memblock has a null character added to the end */ verifyNoNulls(envP, contents, len); *lengthP = len; *contentsP = contents; } } void xmlrpc_read_string(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP) { /*---------------------------------------------------------------------------- Read the value of an XML-RPC string as an ASCIIZ string, with LF for line delimiters. Return the string in newly malloc'ed storage that Caller must free. Fail if the string contains null characters (which means it wasn't really a string, but XML-RPC doesn't seem to understand what a string is, and such values are possible). -----------------------------------------------------------------------------*/ size_t length; const char * contents; accessStringValue(envP, valueP, &length, &contents); if (!envP->fault_occurred) { char * stringValue; MALLOCARRAY(stringValue, length + 1); if (stringValue == NULL) xmlrpc_faultf(envP, "Unable to allocate space " "for %u-character string", (unsigned)length); else { memcpy(stringValue, contents, length); stringValue[length] = '\0'; *stringValueP = stringValue; } } } static unsigned int lineDelimCount(const char * const start, const char * const end) { unsigned int count; const char * p; for (p = start, count = 0; p < end; ) { const char * const nlPos = memchr(p, '\n', end-p); if (nlPos) { ++count; p = nlPos + 1; } else p = end; } return count; } static void copyAndConvertLfToCrlf(xmlrpc_env * const envP, size_t const srcLen, const char * const src, size_t * const dstLenP, const char ** const dstP) { const char * const srcEnd = src + srcLen; unsigned int const nLineDelim = lineDelimCount(src, srcEnd); size_t const dstLen = srcLen + nLineDelim; char * dst; MALLOCARRAY(dst, dstLen + 1); if (dst == NULL) xmlrpc_faultf(envP, "Unable to allocate space " "for %u-character string", (unsigned)dstLen + 1); else { const char * p; /* source pointer */ char * q; /* destination pointer */ for (p = &src[0], q = &dst[0]; p < srcEnd; ++p) { if (*p == '\n') *q++ = '\r'; *q++ = *p; } XMLRPC_ASSERT(q == dst + dstLen); *q = '\0'; *dstP = dst; *dstLenP = dstLen; } } void xmlrpc_read_string_crlf(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP) { /*---------------------------------------------------------------------------- Same as xmlrpc_read_string(), but return CRLF instead of LF for line delimiters. -----------------------------------------------------------------------------*/ size_t length; const char * contents; accessStringValue(envP, valueP, &length, &contents); if (!envP->fault_occurred) { size_t stringLen; copyAndConvertLfToCrlf(envP, length, contents, &stringLen, stringValueP); } } void xmlrpc_read_string_old(xmlrpc_env * const envP, const xmlrpc_value * const valueP, const char ** const stringValueP) { /*---------------------------------------------------------------------------- Like xmlrpc_read_string(), except it returns as *stringValueP a pointer into memory owned by *valueP, rather than new memory to be owned by Caller. This is for internal use; it's necessary to implement the deprecated xmlrpc_parse_value(), which also returns pointers to someone else's storage. -----------------------------------------------------------------------------*/ size_t length; accessStringValue(envP, valueP, &length, stringValueP); } void xmlrpc_read_string_lp(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const char ** const stringValueP) { validateStringType(envP, valueP); if (!envP->fault_occurred) { size_t const size = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); const char * const contents = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); char * stringValue; stringValue = malloc(size); if (stringValue == NULL) xmlrpc_faultf(envP, "Unable to allocate %u bytes for string.", (unsigned int)size); else { memcpy(stringValue, contents, size); *stringValueP = stringValue; *lengthP = size - 1; /* Size includes terminating NUL */ } } } void xmlrpc_read_string_lp_crlf(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const char ** const stringValueP) { validateStringType(envP, valueP); if (!envP->fault_occurred) { size_t const size = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block); /* Includes NUL */ const char * const contents = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); copyAndConvertLfToCrlf(envP, size-1, contents, lengthP, stringValueP); } } void xmlrpc_read_string_lp_old(xmlrpc_env * const envP, const xmlrpc_value * const valueP, size_t * const lengthP, const char ** const stringValueP) { /*---------------------------------------------------------------------------- This is to xmlrpc_read_string_lp() as xmlrpc_read_string_old() is to xmlrpc_read_string(). -----------------------------------------------------------------------------*/ validateStringType(envP, valueP); if (!envP->fault_occurred) { *lengthP = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1; *stringValueP = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); } } static __inline__ void setupWcsBlock(xmlrpc_env * const envP, xmlrpc_value * const valueP) { /*---------------------------------------------------------------------------- Add a wcs block (wchar_t string) to the indicated xmlrpc_value if it doesn't have one already. -----------------------------------------------------------------------------*/ if (!valueP->_wcs_block) { char * const contents = XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block); size_t const len = XMLRPC_MEMBLOCK_SIZE(char, &valueP->_block) - 1; valueP->_wcs_block = xmlrpc_utf8_to_wcs(envP, contents, len + 1); } } #if HAVE_UNICODE_WCHAR static void accessStringValueW(xmlrpc_env * const envP, xmlrpc_value * const valueP, size_t * const lengthP, const wchar_t ** const stringValueP) { validateStringType(envP, valueP); if (!envP->fault_occurred) { setupWcsBlock(envP, valueP); if (!envP->fault_occurred) { wchar_t * const wcontents = XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block); size_t const len = XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block) - 1; verifyNoNullsW(envP, wcontents, len); *lengthP = len; *stringValueP = wcontents; } } } void xmlrpc_read_string_w(xmlrpc_env * const envP, xmlrpc_value * const valueP, const wchar_t ** const stringValueP) { size_t length; const wchar_t * wcontents; accessStringValueW(envP, valueP, &length, &wcontents); if (!envP->fault_occurred) { wchar_t * stringValue; MALLOCARRAY(stringValue, length + 1); if (stringValue == NULL) xmlrpc_faultf(envP, "Unable to allocate space for %u-byte string", (unsigned)length); else { memcpy(stringValue, wcontents, length * sizeof(wchar_t)); stringValue[length] = '\0'; *stringValueP = stringValue; } } } static unsigned int lineDelimCountW(const wchar_t * const start, const wchar_t * const end) { unsigned int count; const wchar_t * p; count = 0; p = start; while (p && p < end) { /* We used to use memchr(), but Windows doesn't have it */ p = wcsstr(p, L"\n"); if (p && p < end) { ++count; /* count the newline */ ++p; /* skip the newline */ } } return count; } static void wCopyAndConvertLfToCrlf(xmlrpc_env * const envP, size_t const srcLen, const wchar_t * const src, size_t * const dstLenP, const wchar_t ** const dstP) { const wchar_t * const srcEnd = src + srcLen; unsigned int const nLineDelim = lineDelimCountW(src, srcEnd); size_t const dstLen = srcLen + nLineDelim; wchar_t * dst; MALLOCARRAY(dst, dstLen + 1); if (dst == NULL) xmlrpc_faultf(envP, "Unable to allocate space " "for %u-character string", (unsigned)dstLen + 1); else { const wchar_t * p; /* source pointer */ wchar_t * q; /* destination pointer */ for (p = &src[0], q = &dst[0]; p < srcEnd; ++p) { if (*p == '\n') *q++ = '\r'; *q++ = *p; } XMLRPC_ASSERT(q == dst + dstLen); *q = '\0'; *dstP = dst; *dstLenP = dstLen; } } void xmlrpc_read_string_w_crlf(xmlrpc_env * const envP, xmlrpc_value * const valueP, const wchar_t ** const stringValueP) { size_t size; const wchar_t * contents; accessStringValueW(envP, valueP, &size, &contents); if (!envP->fault_occurred) { size_t stringLen; wCopyAndConvertLfToCrlf(envP, size, contents, &stringLen, stringValueP); } } void xmlrpc_read_string_w_old(xmlrpc_env * const envP, xmlrpc_value * const valueP, const wchar_t ** const stringValueP) { /*---------------------------------------------------------------------------- This is to xmlrpc_read_string_w() as xmlrpc_read_string_old() is to xmlrpc_read_string(). -----------------------------------------------------------------------------*/ size_t length; accessStringValueW(envP, valueP, &length, stringValueP); } void xmlrpc_read_string_w_lp(xmlrpc_env * const envP, xmlrpc_value * const valueP, size_t * const lengthP, const wchar_t ** const stringValueP) { validateStringType(envP, valueP); if (!envP->fault_occurred) { setupWcsBlock(envP, valueP); if (!envP->fault_occurred) { wchar_t * const wcontents = XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block); size_t const size = XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block); wchar_t * stringValue; MALLOCARRAY(stringValue, size); if (stringValue == NULL) xmlrpc_faultf(envP, "Unable to allocate space for %u-byte string", (unsigned int)size); else { memcpy(stringValue, wcontents, size * sizeof(wchar_t)); *lengthP = size - 1; /* size includes terminating NUL */ *stringValueP = stringValue; } } } } void xmlrpc_read_string_w_lp_crlf(xmlrpc_env * const envP, xmlrpc_value * const valueP, size_t * const lengthP, const wchar_t ** const stringValueP) { validateStringType(envP, valueP); if (!envP->fault_occurred) { setupWcsBlock(envP, valueP); if (!envP->fault_occurred) { size_t const size = XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block); wchar_t * const wcontents = XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block); wCopyAndConvertLfToCrlf(envP, size-1, wcontents, lengthP, stringValueP); } } } void xmlrpc_read_string_w_lp_old(xmlrpc_env * const envP, xmlrpc_value * const valueP, size_t * const lengthP, const wchar_t ** const stringValueP) { /*---------------------------------------------------------------------------- This is to xmlrpc_read_string_w_lp() as xmlrpc_read_string_old() is to xmlrpc_read_string(). -----------------------------------------------------------------------------*/ validateStringType(envP, valueP); if (!envP->fault_occurred) { setupWcsBlock(envP, valueP); if (!envP->fault_occurred) { wchar_t * const wcontents = XMLRPC_MEMBLOCK_CONTENTS(wchar_t, valueP->_wcs_block); size_t const size = XMLRPC_MEMBLOCK_SIZE(wchar_t, valueP->_wcs_block); *lengthP = size - 1; /* size includes terminating NUL */ *stringValueP = wcontents; } } } #endif /* HAVE_UNICODE_WCHAR */ static void copyLines(xmlrpc_env * const envP, const char * const src, size_t const srcLen, xmlrpc_mem_block * const dstP) { /*---------------------------------------------------------------------------- Copy the string 'src', 'srcLen' characters long, into 'dst', where 'dst' is the internal representation of string xmlrpc_value contents, and 'src' has lines separated by LF, CR, and/or CRLF. Note that the source format differs from the destination format in that in the destination format, lines are separated only by newline (LF). It is tempting to believe that if we just put the user's line delimiters in the xmlrpc_value here (i.e. where user has CRLF, the xmlrpc_value also has CRLF), the user's line delimiters would go all the way across to the XML-RPC partner. But that won't work, because the XML processor on the other side will, following Section 2.11 of the XML spec, normalize all line endings to LF anyhow. So then you might ask, why do we bother to do all the work to convert them here? Because: besides just being logically cleaner, this way xmlrpc_read_string() gets the proper value -- the same one the XML-RPC partner would see. -----------------------------------------------------------------------------*/ /* Destination format is sometimes smaller than source (because CRLF turns into LF), but never smaller. So we allocate destination space equal to source size (plus one for terminating NUL), but don't necessarily use it all. */ /* To convert LF, CR, and CRLF to LF, all we have to do is copy everything up to a CR verbatim, then insert an LF and skip the CR and any following LF, and repeat. */ XMLRPC_MEMBLOCK_INIT(char, envP, dstP, srcLen + 1); if (!envP->fault_occurred) { const char * const srcEnd = &src[srcLen]; char * const contents = XMLRPC_MEMBLOCK_CONTENTS(char, dstP); const char * srcCursor; char * dstCursor; for (srcCursor = &src[0], dstCursor = &contents[0]; srcCursor < srcEnd;) { char * const crPos = memchr(srcCursor, '\r', srcEnd - srcCursor); if (crPos) { size_t const copyLen = crPos - srcCursor; memcpy(dstCursor, srcCursor, copyLen); srcCursor += copyLen; dstCursor += copyLen; *(dstCursor++) = '\n'; XMLRPC_ASSERT(*srcCursor == '\r'); ++srcCursor; /* Move past CR */ if (*srcCursor == '\n') ++srcCursor; /* Move past LF */ } else { size_t const remainingLen = srcEnd - srcCursor; memcpy(dstCursor, srcCursor, remainingLen); srcCursor += remainingLen; dstCursor += remainingLen; } } *dstCursor++ = '\0'; XMLRPC_ASSERT((unsigned)(dstCursor - &contents[0]) <= srcLen + 1); XMLRPC_MEMBLOCK_RESIZE(char, envP, dstP, dstCursor - &contents[0]); } } static void copySimple(xmlrpc_env * const envP, const char * const src, size_t const srcLen, xmlrpc_mem_block * const dstP) { /*---------------------------------------------------------------------------- Copy the string 'src', 'srcLen' characters long, into 'dst', where 'dst' is the internal representation of string xmlrpc_value contents, and 'src', conveniently enough, is in the exact same format. To wit, 'src' has lines separated by LFs only -- no CR or CRLF. -----------------------------------------------------------------------------*/ XMLRPC_MEMBLOCK_INIT(char, envP, dstP, srcLen + 1); if (!envP->fault_occurred) { char * const contents = XMLRPC_MEMBLOCK_CONTENTS(char, dstP); memcpy(contents, src, srcLen); contents[srcLen] = '\0'; } } enum crTreatment { CR_IS_LINEDELIM, CR_IS_CHAR }; static void stringNew(xmlrpc_env * const envP, size_t const length, const char * const value, enum crTreatment const crTreatment, xmlrpc_value ** const valPP) { xmlrpc_value * valP; xmlrpc_validate_utf8(envP, value, length); if (!envP->fault_occurred) { xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_STRING; valP->_wcs_block = NULL; /* Note that copyLines() works for strings with no CRs, but it's slower. */ if (memchr(value, '\r', length) && crTreatment == CR_IS_LINEDELIM) copyLines(envP, value, length, &valP->_block); else copySimple(envP, value, length, &valP->_block); if (envP->fault_occurred) free(valP); else *valPP = valP; } } } xmlrpc_value * xmlrpc_string_new_lp(xmlrpc_env * const envP, size_t const length, const char * const value) { xmlrpc_value * retval; stringNew(envP, length, value, CR_IS_LINEDELIM, &retval); return retval; } xmlrpc_value * xmlrpc_string_new_lp_cr(xmlrpc_env * const envP, size_t const length, const char * const value) { xmlrpc_value * retval; stringNew(envP, length, value, CR_IS_CHAR, &retval); return retval; } xmlrpc_value * xmlrpc_string_new(xmlrpc_env * const envP, const char * const value) { xmlrpc_value * retval; stringNew(envP, strlen(value), value, CR_IS_LINEDELIM, &retval); return retval; } xmlrpc_value * xmlrpc_string_new_cr(xmlrpc_env * const envP, const char * const value) { xmlrpc_value * retval; stringNew(envP, strlen(value), value, CR_IS_CHAR, &retval); return retval; } xmlrpc_value * xmlrpc_string_new_va(xmlrpc_env * const envP, const char * const format, va_list args) { const char * formattedString; xmlrpc_value * retvalP; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(format != NULL); xmlrpc_vasprintf(&formattedString, format, args); if (xmlrpc_strnomem(formattedString)) { xmlrpc_faultf(envP, "Out of memory building formatted string"); retvalP = NULL; /* defeat compiler warning */ } else retvalP = xmlrpc_string_new(envP, formattedString); xmlrpc_strfree(formattedString); return retvalP; } xmlrpc_value * xmlrpc_string_new_f(xmlrpc_env * const envP, const char * const format, ...) { va_list args; xmlrpc_value * retval; va_start(args, format); retval = xmlrpc_string_new_va(envP, format, args); va_end(args); return retval; } #if HAVE_UNICODE_WCHAR static void stringWNew(xmlrpc_env * const envP, size_t const length, const wchar_t * const value, enum crTreatment const crTreatment, xmlrpc_value ** const valPP) { xmlrpc_mem_block * utf8P; utf8P = xmlrpc_wcs_to_utf8(envP, value, length); if (!envP->fault_occurred) { char * const utf8_value = XMLRPC_MEMBLOCK_CONTENTS(char, utf8P); size_t const utf8_len = XMLRPC_MEMBLOCK_SIZE(char, utf8P); if (!envP->fault_occurred) { stringNew(envP, utf8_len, utf8_value, crTreatment, valPP); XMLRPC_MEMBLOCK_FREE(char, utf8P); } } } xmlrpc_value * xmlrpc_string_w_new_lp(xmlrpc_env * const envP, size_t const length, const wchar_t * const value) { xmlrpc_value * valP; stringWNew(envP, length, value, CR_IS_LINEDELIM, &valP); return valP; } xmlrpc_value * xmlrpc_string_w_new_lp_cr(xmlrpc_env * const envP, size_t const length, const wchar_t * const value) { xmlrpc_value * valP; stringWNew(envP, length, value, CR_IS_CHAR, &valP); return valP; } xmlrpc_value * xmlrpc_string_w_new(xmlrpc_env * const envP, const wchar_t * const value) { xmlrpc_value * valP; stringWNew(envP, wcslen(value), value, CR_IS_LINEDELIM, &valP); return valP; } xmlrpc_value * xmlrpc_string_w_new_cr(xmlrpc_env * const envP, const wchar_t * const value) { xmlrpc_value * valP; stringWNew(envP, wcslen(value), value, CR_IS_CHAR, &valP); return valP; } #endif /* HAVE_UNICODE_WCHAR */ xmlrpc-c-1.33.14/src/xmlrpc_struct.c000066400000000000000000000506661236133176700173020ustar00rootroot00000000000000#include "xmlrpc_config.h" #include #include #include #include #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "int.h" #define KEY_ERROR_BUFFER_SZ (32) void xmlrpc_destroyStruct(xmlrpc_value * const structP) { _struct_member * const members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); size_t const size = XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block); unsigned int i; for (i = 0; i < size; ++i) { xmlrpc_DECREF(members[i].key); xmlrpc_DECREF(members[i].value); } XMLRPC_MEMBLOCK_CLEAN(_struct_member, &structP->_block); } /*========================================================================= ** xmlrpc_struct_new **========================================================================= ** Create a new value. The corresponding destructor code ** currently lives in xmlrpc_DECREF. ** ** We store the individual members in an array of _struct_member. This ** contains a key, a hash code, and a value. We look up keys by doing ** a linear search of the hash codes. */ xmlrpc_value * xmlrpc_struct_new(xmlrpc_env * const envP) { xmlrpc_value * valP; XMLRPC_ASSERT_ENV_OK(envP); xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { valP->_type = XMLRPC_TYPE_STRUCT; XMLRPC_MEMBLOCK_INIT(_struct_member, envP, &valP->_block, 0); if (envP->fault_occurred) free(valP); } return valP; } /*========================================================================= ** xmlrpc_struct_size **========================================================================= ** Return the number of key-value pairs contained in the struct. If the ** value is not a struct, return -1 and set a fault. */ int xmlrpc_struct_size(xmlrpc_env * const envP, xmlrpc_value * const structP) { int retval; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(structP); if (structP->_type != XMLRPC_TYPE_STRUCT) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d", structP->_type); retval = -1; } else { size_t const size = XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block); assert((size_t)(int)size == size); /* Because structs are defined to have few enough members */ retval = (int)size; } return retval; } static uint32_t hashStructKey(const char * const key, size_t const keyLen) { uint32_t hash; size_t i; XMLRPC_ASSERT(key != NULL); /* This is the Bernstein hash, optimized for lower case ASCII keys. Note that the bytes of such a key differ only in their lower 5 bits. */ for (hash = 0, i = 0; i < keyLen; ++i) hash = hash + key[i] + (hash << 5); return hash; } static void findMember(xmlrpc_value * const structP, const char * const key, size_t const keyLen, bool * const foundP, unsigned int * const indexP) { size_t size, i; uint32_t searchHash; _struct_member * contents; /* array */ bool found; size_t foundIndex; /* Meaningful only when 'found' is true */ XMLRPC_ASSERT_VALUE_OK(structP); XMLRPC_ASSERT(key != NULL); foundIndex = 0; /* defeat used-before-set compiler warning */ /* Look for our key. */ searchHash = hashStructKey(key, keyLen); size = XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block); contents = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); for (i = 0, found = false; i < size && !found; ++i) { if (contents[i].keyHash == searchHash) { xmlrpc_value * const keyvalP = contents[i].key; const char * const keystr = XMLRPC_MEMBLOCK_CONTENTS(char, &keyvalP->_block); size_t const keystrSize = XMLRPC_MEMBLOCK_SIZE(char, &keyvalP->_block)-1; if (keystrSize == keyLen && memcmp(key, keystr, keyLen) == 0) { found = true; foundIndex = i; } } } if (found) { assert((size_t)(int)foundIndex == foundIndex); /* Definition of structure says it has few enough members */ if (indexP) *indexP = foundIndex; } *foundP = found; } /*========================================================================= ** xmlrpc_struct_has_key **========================================================================= */ int xmlrpc_struct_has_key(xmlrpc_env * const envP, xmlrpc_value * const strctP, const char * const key) { XMLRPC_ASSERT(key != NULL); return xmlrpc_struct_has_key_n(envP, strctP, key, strlen(key)); } int xmlrpc_struct_has_key_n(xmlrpc_env * const envP, xmlrpc_value * const structP, const char * const key, size_t const keyLen) { int retval; /* Suppress a compiler warning about uninitialized variables. */ retval = 0; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(structP); XMLRPC_ASSERT(key != NULL); if (structP->_type != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault(envP, XMLRPC_TYPE_ERROR, "Value is not a struct"); else { bool found; findMember(structP, key, keyLen, &found, NULL); retval = found ? 1 : 0; } return retval; } /*========================================================================= ** xmlrpc_struct_find_value... **========================================================================= ** These functions look up a specified key value in a specified struct. ** If it exists, they return the value of the struct member. If not, ** they return a NULL to indicate such. */ /* It would be a nice extension to be able to look up a key that is not a text string. */ void xmlrpc_struct_find_value(xmlrpc_env * const envP, xmlrpc_value * const structP, const char * const key, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Given a key, retrieve a value from the struct. If the key is not present, return NULL as *valuePP. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(structP); XMLRPC_ASSERT_PTR_OK(key); if (structP->_type != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d", structP->_type); else { bool found; unsigned int index; /* Get our member index. */ findMember(structP, key, strlen(key), &found, &index); if (!found) *valuePP = NULL; else { _struct_member * const members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); *valuePP = members[index].value; XMLRPC_ASSERT_VALUE_OK(*valuePP); xmlrpc_INCREF(*valuePP); } } } void xmlrpc_struct_find_value_v(xmlrpc_env * const envP, xmlrpc_value * const structP, xmlrpc_value * const keyP, xmlrpc_value ** const valuePP) { /*---------------------------------------------------------------------------- Given a key, retrieve a value from the struct. If the key is not present, return NULL as *valuePP. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(structP); XMLRPC_ASSERT_VALUE_OK(keyP); if (structP->_type != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Value is not a struct. It is type #%d", structP->_type); else { if (keyP->_type != XMLRPC_TYPE_STRING) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Key value is not a string. " "It is type #%d", keyP->_type); else { bool found; unsigned int index; /* Get our member index. */ findMember(structP, XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block), XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block)-1, &found, &index); if (!found) *valuePP = NULL; else { _struct_member * const members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); *valuePP = members[index].value; XMLRPC_ASSERT_VALUE_OK(*valuePP); xmlrpc_INCREF(*valuePP); } } } } /*========================================================================= ** xmlrpc_struct_read_value... **========================================================================= ** These fail if no member with the specified key exists. ** Otherwise, they are the same as xmlrpc_struct_find_value... */ void xmlrpc_struct_read_value_v(xmlrpc_env * const envP, xmlrpc_value * const structP, xmlrpc_value * const keyP, xmlrpc_value ** const valuePP) { xmlrpc_struct_find_value_v(envP, structP, keyP, valuePP); if (!envP->fault_occurred) { if (*valuePP == NULL) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%.*s'", (int)XMLRPC_MEMBLOCK_SIZE(char, &keyP->_block), XMLRPC_MEMBLOCK_CONTENTS(char, &keyP->_block)); } } } void xmlrpc_struct_read_value(xmlrpc_env * const envP, xmlrpc_value * const structP, const char * const key, xmlrpc_value ** const valuePP) { xmlrpc_struct_find_value(envP, structP, key, valuePP); if (!envP->fault_occurred) { if (*valuePP == NULL) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%s'", key); /* We should fix the error message to format the key for display */ } } } /*========================================================================= ** xmlrpc_struct_get_value... **========================================================================= ** These are for backward compatibility. They used to be the only ones. ** They're deprecated because they don't acquire a reference to the ** value they return. */ xmlrpc_value * xmlrpc_struct_get_value_n(xmlrpc_env * const envP, xmlrpc_value * const structP, const char * const key, size_t const keyLen) { xmlrpc_value * retval; xmlrpc_value * keyP; /* 'key' as an XML-RPC string */ keyP = xmlrpc_string_new_lp(envP, keyLen, key); if (!envP->fault_occurred) { xmlrpc_struct_find_value_v(envP, structP, keyP, &retval); if (!envP->fault_occurred) { if (retval == NULL) { xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "No member of struct has key '%.*s'", (int)keyLen, key); /* We should fix the error message to format the key for display */ } else /* For backward compatibility. */ xmlrpc_DECREF(retval); } xmlrpc_DECREF(keyP); } return retval; } xmlrpc_value * xmlrpc_struct_get_value(xmlrpc_env * const envP, xmlrpc_value * const strctP, const char * const key) { XMLRPC_ASSERT(key != NULL); return xmlrpc_struct_get_value_n(envP, strctP, key, strlen(key)); } /*========================================================================= ** xmlrpc_struct_set_value **========================================================================= */ void xmlrpc_struct_set_value(xmlrpc_env * const envP, xmlrpc_value * const strctP, const char * const key, xmlrpc_value * const valueP) { XMLRPC_ASSERT(key != NULL); xmlrpc_struct_set_value_n(envP, strctP, key, strlen(key), valueP); } void xmlrpc_struct_set_value_n(xmlrpc_env * const envP, xmlrpc_value * const strctP, const char * const key, size_t const keyLen, xmlrpc_value * const valueP) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT(key != NULL); if (xmlrpc_value_type(strctP) != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Trying to set value in something not a struct. " "Type is %d; struct is %d", xmlrpc_value_type(strctP), XMLRPC_TYPE_STRUCT); else { xmlrpc_value * keyvalP; /* 'key' as an XML-RPC string */ keyvalP = xmlrpc_string_new_lp(envP, keyLen, key); if (!envP->fault_occurred) xmlrpc_struct_set_value_v(envP, strctP, keyvalP, valueP); xmlrpc_DECREF(keyvalP); } } static void changeMemberValue(xmlrpc_value * const structP, unsigned int const mbrIndex, xmlrpc_value * const newValueP) { /*---------------------------------------------------------------------------- Change the value of an existing member. (But be careful--the original and new values might be the same object, so watch the order of INCREF and DECREF calls!) -----------------------------------------------------------------------------*/ _struct_member * const members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); _struct_member * const memberP = &members[mbrIndex]; xmlrpc_value * const oldValueP = memberP->value; /* Juggle our references. */ memberP->value = newValueP; xmlrpc_INCREF(memberP->value); xmlrpc_DECREF(oldValueP); } static void addNewMember(xmlrpc_env * const envP, xmlrpc_value * const structP, xmlrpc_value * const keyvalP, xmlrpc_value * const valueP) { /*---------------------------------------------------------------------------- Add a new member. Assume no member already exists with this key. -----------------------------------------------------------------------------*/ const char * const key = XMLRPC_MEMBLOCK_CONTENTS(char, &keyvalP->_block); size_t const keyLen = XMLRPC_MEMBLOCK_SIZE(char, &keyvalP->_block) - 1; _struct_member newMember; newMember.keyHash = hashStructKey(key, keyLen); newMember.key = keyvalP; newMember.value = valueP; XMLRPC_MEMBLOCK_APPEND(_struct_member, envP, &structP->_block, &newMember, 1); if (!envP->fault_occurred) { xmlrpc_INCREF(keyvalP); xmlrpc_INCREF(valueP); } } void xmlrpc_struct_set_value_v(xmlrpc_env * const envP, xmlrpc_value * const structP, xmlrpc_value * const keyvalP, xmlrpc_value * const valueP) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(structP); XMLRPC_ASSERT_VALUE_OK(keyvalP); XMLRPC_ASSERT_VALUE_OK(valueP); if (structP->_type != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault(envP, XMLRPC_TYPE_ERROR, "Value is not a struct"); else if (keyvalP->_type != XMLRPC_TYPE_STRING) xmlrpc_env_set_fault(envP, XMLRPC_TYPE_ERROR, "Key value is not a string"); else { const char * const key = XMLRPC_MEMBLOCK_CONTENTS(char, &keyvalP->_block); size_t const keyLen = XMLRPC_MEMBLOCK_SIZE(char, &keyvalP->_block) - 1; bool found; unsigned int index; findMember(structP, key, keyLen, &found, &index); if (found) changeMemberValue(structP, index, valueP); else addNewMember(envP, structP, keyvalP, valueP); } } /* Note that the order of keys and values is undefined, and may change when you modify the struct. */ void xmlrpc_struct_read_member(xmlrpc_env * const envP, xmlrpc_value * const structP, unsigned int const index, xmlrpc_value ** const keyvalP, xmlrpc_value ** const valueP) { XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(structP); XMLRPC_ASSERT_PTR_OK(keyvalP); XMLRPC_ASSERT_PTR_OK(valueP); if (structP->_type != XMLRPC_TYPE_STRUCT) xmlrpc_env_set_fault_formatted( envP, XMLRPC_TYPE_ERROR, "Attempt to read a struct member " "of something that is not a struct"); else { _struct_member * const members = XMLRPC_MEMBLOCK_CONTENTS(_struct_member, &structP->_block); size_t const size = XMLRPC_MEMBLOCK_SIZE(_struct_member, &structP->_block); if (index >= size) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "Index %u is beyond the end of " "the %u-member structure", index, (unsigned int)size); else { _struct_member * const memberP = &members[index]; *keyvalP = memberP->key; xmlrpc_INCREF(memberP->key); *valueP = memberP->value; xmlrpc_INCREF(memberP->value); } } } void xmlrpc_struct_get_key_and_value(xmlrpc_env * const envP, xmlrpc_value * const structP, int const index, xmlrpc_value ** const keyvalP, xmlrpc_value ** const valueP) { /*---------------------------------------------------------------------------- Same as xmlrpc_struct_read_member(), except doesn't take a reference to the returned value. This is obsolete. -----------------------------------------------------------------------------*/ XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_VALUE_OK(structP); XMLRPC_ASSERT_PTR_OK(keyvalP); XMLRPC_ASSERT_PTR_OK(valueP); if (index < 0) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INDEX_ERROR, "Index %d is negative.", index); else { xmlrpc_struct_read_member(envP, structP, index, keyvalP, valueP); if (!envP->fault_occurred) { xmlrpc_DECREF(*keyvalP); xmlrpc_DECREF(*valueP); } } if (envP->fault_occurred) { *keyvalP = NULL; *valueP = NULL; } } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/srcdir.mk.in000066400000000000000000000000241236133176700156410ustar00rootroot00000000000000SRCDIR=@abs_srcdir@ xmlrpc-c-1.33.14/stamp-h.in000066400000000000000000000000121236133176700153130ustar00rootroot00000000000000timestamp xmlrpc-c-1.33.14/test/000077500000000000000000000000001236133176700144005ustar00rootroot00000000000000xmlrpc-c-1.33.14/test/Makefile000066400000000000000000000047011236133176700160420ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') SRCDIR := $(call updir,$(CURDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := test include $(BLDDIR)/config.mk SUBDIRS = cpp XMLRPC_C_CONFIG = $(BLDDIR)/xmlrpc-c-config.test LDADD_ABYSS_SERVER = \ $(shell $(XMLRPC_C_CONFIG) abyss-server --ldadd) LDADD_CGI_SERVER = \ $(shell $(XMLRPC_C_CONFIG) cgi-server --ldadd) default: all INCLUDES = -I$(BLDDIR) -Isrcdir/include -Isrcdir/lib/util/include \ PROGS = test cgitest1 all: $(PROGS) $(SUBDIRS:%=%/all) TEST_OBJS = \ testtool.o \ test.o \ abyss.o \ cgi.o \ method_registry.o \ parse_xml.o \ serialize.o \ serialize_value.o \ server_abyss.o \ value.o \ value_datetime.o \ xml_data.o \ ifeq ($(MUST_BUILD_CLIENT),yes) TEST_OBJS += client.o LIBXMLRPC_CLIENT_DEP = $(LIBXMLRPC_CLIENT_A) LDADD_CLIENT = $(shell $(XMLRPC_C_CONFIG) client --ldadd) else TEST_OBJS += client_dummy.o LIBXMLRPC_CLIENT_DEP = LDADD_CLIENT = endif include $(SRCDIR)/common.mk # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir test: \ $(XMLRPC_C_CONFIG) \ $(TEST_OBJS) $(LIBXMLRPC_A) $(LIBXMLRPC_UTIL_A) \ $(LIBXMLRPC_SERVER_A) $(LIBXMLRPC_SERVER_ABYSS_A) $(LIBXMLRPC_XML) \ $(LIBXMLRPC_CLIENT_DEP) $(LIBXMLRPC_ABYSS_A) \ $(LIBXMLRPC_XMLPARSE_A) $(LIBXMLRPC_XMLTOK_A) \ $(CASPRINTF) $(CCLD) -o $@ $(LDFLAGS_ALL) \ $(TEST_OBJS) $(LDADD_CLIENT) $(LDADD_ABYSS_SERVER) $(CASPRINTF) CGITEST1_OBJS = cgitest1.o testtool.o cgitest1: $(CGITEST1_OBJS) $(LIBXMLRPC_SERVER_A) $(LIBXMLRPC_SERVER_CGI_A) \ $(LIBXMLRPC_A) $(LIBXMLRPC_UTIL_A) $(LIBXMLRPC_XML) $(CCLD) -o $@ $(CGITEST1_OBJS) $(LDFLAGS_ALL) $(LDADD_CGI_SERVER) OBJS = $(TEST_OBJS) cgitest1.o $(OBJS):%.o:%.c $(CC) -c $(INCLUDES) $(CFLAGS_ALL) $< # Note the difference between 'check' and 'runtests'. 'check' means to check # our own correctness. 'runtests' means to run the tests that check our # parent's correctness .PHONY: check check: .PHONY: runtests_local runtests_local: test cgitest1 ./test .PHONY: runtests runtests: runtests_local cpp/runtests cpp/runtests: FORCE $(MAKE) -C $(dir $@) $(notdir $@) .PHONY: install install: .PHONY: clean clean-local distclean clean: clean-common clean-local clean-local: $(SUBDIRS:%=%/clean) rm -f $(PROGS) distclean: clean $(SUBDIRS:%=%/distclean) distclean-common .PHONY: dep dep: dep-common $(SUBDIRS:%=%/dep) include depend.mk xmlrpc-c-1.33.14/test/abyss.c000066400000000000000000000201061236133176700156640ustar00rootroot00000000000000/* None of the tests in here rely on a client existing, or even a network connection. We should figure out how to create a test client and do such tests. */ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/abyss.h */ #include "unistdx.h" #include #ifndef _WIN32 #include #include #endif #include #include #include "xmlrpc_config.h" #include "int.h" #include "casprintf.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/abyss.h" #include "testtool.h" #include "abyss.h" static void bindSocketToPort(int const fd, uint16_t const portNumber) { struct sockaddr_in name; int rc; name.sin_family = AF_INET; name.sin_port = htons(portNumber); name.sin_addr.s_addr = INADDR_ANY; rc = bind(fd, (struct sockaddr *)&name, sizeof(name)); if (rc != 0) fprintf(stderr, "bind() of %d failed, errno=%d (%s)", fd, errno, strerror(errno)); TEST(rc == 0); } static void chanSwitchCreateFd(int const fd, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { #ifdef _WIN32 ChanSwitchWinCreateWinsock(fd, chanSwitchPP, errorP); #else ChanSwitchUnixCreateFd(fd, chanSwitchPP, errorP); #endif } static void closesock(int const fd) { #ifdef _WIN32 closesocket(fd); #else close(fd); #endif } static void chanSwitchCreate(uint16_t const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { #ifdef _WIN32 ChanSwitchWinCreate(portNumber, chanSwitchPP, errorP); #else ChanSwitchUnixCreate(portNumber, chanSwitchPP, errorP); #endif } static void chanSwitchCreate2(int const protocolFamily, const struct sockaddr * const sockAddrP, socklen_t const sockAddrLen, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { #ifdef _WIN32 ChanSwitchWinCreate2(protocolFamily, sockAddrP, sockAddrLen, chanSwitchPP, errorP); #else ChanSwitchUnixCreate2(protocolFamily, sockAddrP, sockAddrLen, chanSwitchPP, errorP); #endif } static void chanSwitchCreateIpV6(uint16_t const portNumber, TChanSwitch ** const chanSwitchPP, const char ** const errorP) { #ifndef _WIN32 ChanSwitchUnixCreateIpV6Port(portNumber, chanSwitchPP, errorP); #endif } static void channelCreateFd(int const fd, TChannel ** const channelPP, const char ** const errorP) { #ifdef _WIN32 struct abyss_win_chaninfo * channelInfoP; ChannelWinCreateWinsock(fd, channelPP, &channelInfoP, errorP); #else struct abyss_unix_chaninfo * channelInfoP; ChannelUnixCreateFd(fd, channelPP, &channelInfoP, errorP); #endif } static void testChanSwitchOsSocket(void) { XMLRPC_SOCKET rc; rc = socket(AF_INET, SOCK_STREAM, 0); if (rc < 0) { fprintf(stderr, "socket() failed with errno %d (%s)", errno, strerror(errno)); abort(); } else { int const fd = rc; TChanSwitch * chanSwitchP; TServer server; const char * error; bindSocketToPort(fd, 8080); chanSwitchCreateFd(fd, &chanSwitchP, &error); TEST_NULL_STRING(error); ServerCreateSwitch(&server, chanSwitchP, &error); TEST_NULL_STRING(error); ServerFree(&server); ChanSwitchDestroy(chanSwitchP); closesock(fd); } } static void testChanSwitchSockAddr(void) { TServer server; TChanSwitch * chanSwitchP; const char * error; struct sockaddr_in sockAddr; sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(8080); sockAddr.sin_addr = test_ipAddrFromDecimal(127, 0, 0, 1); chanSwitchCreate2(PF_INET, (const struct sockaddr *) &sockAddr, sizeof(sockAddr), &chanSwitchP, &error); TEST_NULL_STRING(error); ServerCreateSwitch(&server, chanSwitchP, &error); TEST_NULL_STRING(error); ServerFree(&server); ChanSwitchDestroy(chanSwitchP); } static void testChanSwitch(void) { TServer server; TChanSwitch * chanSwitchP; const char * error; chanSwitchCreate(8080, &chanSwitchP, &error); TEST_NULL_STRING(error); ServerCreateSwitch(&server, chanSwitchP, &error); TEST_NULL_STRING(error); ServerFree(&server); ChanSwitchDestroy(chanSwitchP); #ifndef _WIN32 chanSwitchCreateIpV6(8080, &chanSwitchP, &error); TEST_NULL_STRING(error); ChanSwitchDestroy(chanSwitchP); testChanSwitchSockAddr(); testChanSwitchOsSocket(); #endif } static void testChannel(void) { XMLRPC_SOCKET rc; rc = socket(AF_INET, SOCK_STREAM, 0); if (rc < 0) { fprintf(stderr, "socket() failed with errno %d (%s)", errno, strerror(errno)); abort(); } else { int const fd = rc; TChannel * channelP; const char * error; channelCreateFd(fd, &channelP, &error); TEST(error); TEST(strstr(error, "not in connected")); strfree(error); } } static void testOsSocket(void) { XMLRPC_SOCKET rc; rc = socket(AF_INET, SOCK_STREAM, 0); if (rc < 0) { fprintf(stderr, "socket() failed with errno %d (%s)", errno, strerror(errno)); abort(); } else { int const fd = rc; TServer server; abyss_bool success; bindSocketToPort(fd, 8080); success = ServerCreateSocket(&server, NULL, fd, NULL, NULL); TEST(success); ServerFree(&server); closesock(fd); } } static void testSocket(void) { #ifndef _WIN32 int rc; rc = socket(AF_INET, SOCK_STREAM, 0); if (rc < 0) { fprintf(stderr, "socket() failed with errno %d (%s)", errno, strerror(errno)); abort(); } else { int const fd = rc; TSocket * socketP; TServer server; const char * error; SocketUnixCreateFd(fd, &socketP); TEST(socketP != NULL); ServerCreateSocket2(&server, socketP, &error); TEST(!error); ServerFree(&server); SocketDestroy(socketP); close(fd); } #endif } static void testServerCreate(void) { TServer server; abyss_bool success; success = ServerCreate(&server, NULL, 8080, NULL, NULL); TEST(success); ServerInit(&server); ServerFree(&server); success = ServerCreate(&server, "myserver", 8080, "/tmp/docroot", "/tmp/logfile"); TEST(success); ServerInit(&server); ServerFree(&server); success = ServerCreateNoAccept(&server, NULL, NULL, NULL); TEST(success); ServerFree(&server); { TChanSwitch * chanSwitchP; const char * error; chanSwitchCreate(8080, &chanSwitchP, &error); TEST_NULL_STRING(error); ServerCreateSwitch(&server, chanSwitchP, &error); TEST_NULL_STRING(error); ServerSetName(&server, "/tmp/docroot"); ServerSetLogFileName(&server, "/tmp/logfile"); ServerSetKeepaliveTimeout(&server, 50); ServerSetKeepaliveMaxConn(&server, 5); ServerSetTimeout(&server, 75); ServerSetAdvertise(&server, 1); ServerSetAdvertise(&server, 0); ServerInit(&server); ServerFree(&server); ChanSwitchDestroy(chanSwitchP); } } void test_abyss(void) { const char * error; printf("Running Abyss server tests...\n"); AbyssInit(&error); TEST_NULL_STRING(error); ChanSwitchInit(&error); TEST_NULL_STRING(error); ChannelInit(&error); TEST_NULL_STRING(error); testChanSwitch(); testChannel(); testOsSocket(); testSocket(); testServerCreate(); ChannelTerm(); ChanSwitchTerm(); AbyssTerm(); printf("\n"); printf("Abyss server tests done.\n"); } xmlrpc-c-1.33.14/test/abyss.h000066400000000000000000000000271236133176700156710ustar00rootroot00000000000000void test_abyss(void); xmlrpc-c-1.33.14/test/cgi.c000066400000000000000000000031421236133176700153060ustar00rootroot00000000000000#include #include #include #include #include "xmlrpc_config.h" #include "testtool.h" #include "cgi.h" static const char cgiResponse1[] = "....Status: 200 OK\n" "Content-type: text/xml; charset=\"utf-8\"\n" "Content-length: 141\n" "\n" "\r\n" "\r\n" "\r\n" "12\r\n" "\r\n" "\r\n"; #define TESTDATA_DIR "data" #define DIRSEP DIRECTORY_SEPARATOR void test_server_cgi(void) { /*---------------------------------------------------------------------------- Here, we pretend to be a web server when someone has requested a POST to the CGI script "cgitest1". -----------------------------------------------------------------------------*/ FILE * cgiOutputP; printf("Running CGI tests...\n"); cgiOutputP = popen("REQUEST_METHOD=POST " "CONTENT_TYPE=text/xml " "CONTENT_LENGTH=211 " "./cgitest1 " "<" TESTDATA_DIR DIRSEP "sample_add_call.xml", "r"); if (cgiOutputP == NULL) TEST_ERROR("Unable to run 'cgitest' program."); else { unsigned char cgiResponse[4096]; size_t bytesRead; bytesRead = fread(cgiResponse, 1, sizeof(cgiResponse), cgiOutputP); TEST(bytesRead == strlen(cgiResponse1)); TEST(memcmp(cgiResponse, cgiResponse1, bytesRead) == 0); } fclose(cgiOutputP); printf("\n"); printf("CGI tests done.\n"); } xmlrpc-c-1.33.14/test/cgi.h000066400000000000000000000000341236133176700153100ustar00rootroot00000000000000void test_server_cgi(void); xmlrpc-c-1.33.14/test/cgitest1.c000066400000000000000000000035131236133176700162710ustar00rootroot00000000000000/*============================================================================ Act like a CGI script -- read POST data from Standard Input, interpret it as an XML-RPC call, and write an XML-RPC response to Standard Output. This is for use by a test program. ============================================================================*/ #include #include #include #include #include "xmlrpc_config.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/server_cgi.h" #include "testtool.h" int total_tests; int total_failures; static xmlrpc_value * sample_add(xmlrpc_env * const env, xmlrpc_value * const param_array, void * const user_data ATTR_UNUSED) { xmlrpc_int32 x, y, z; /* Parse our argument array. */ xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y); if (env->fault_occurred) return NULL; /* Add our two numbers. */ z = x + y; /* Return our result. */ return xmlrpc_build_value(env, "i", z); } int main(int argc ATTR_UNUSED, char ** argv ATTR_UNUSED) { xmlrpc_env env; xmlrpc_registry * registryP; xmlrpc_value * argArrayP; xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); TEST(registryP != NULL); TEST_NO_FAULT(&env); xmlrpc_registry_add_method(&env, registryP, NULL, "sample.add", sample_add, NULL); TEST_NO_FAULT(&env); argArrayP = xmlrpc_build_value(&env, "(ii)", (xmlrpc_int32) 25, (xmlrpc_int32) 17); TEST_NO_FAULT(&env); /* The following reads from Standard Input and writes to Standard Output */ xmlrpc_server_cgi_process_call(registryP); xmlrpc_DECREF(argArrayP); xmlrpc_registry_free(registryP); return 0; } xmlrpc-c-1.33.14/test/client.c000066400000000000000000000347551236133176700160400ustar00rootroot00000000000000#include #include #include #include #include "xmlrpc_config.h" #include "transport_config.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/transport.h" #include "bool.h" #include "testtool.h" #include "client.h" static void testVersion(void) { unsigned int major, minor, point; xmlrpc_client_version(&major, &minor, &point); #ifndef _WIN32 /* xmlrpc_client_version_major, etc. are not exported from a Windows DLL */ TEST(major == xmlrpc_client_version_major); TEST(minor == xmlrpc_client_version_minor); TEST(point == xmlrpc_client_version_point); #endif } static void testGlobalConst(void) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_client_setup_global_const(&env); TEST_NO_FAULT(&env); xmlrpc_client_teardown_global_const(); xmlrpc_client_setup_global_const(&env); TEST_NO_FAULT(&env); xmlrpc_client_setup_global_const(&env); TEST_NO_FAULT(&env); xmlrpc_client_teardown_global_const(); xmlrpc_client_teardown_global_const(); xmlrpc_env_clean(&env); } static xmlrpc_progress_fn myProgress; static void myProgress(void * const userHandle, struct xmlrpc_progress_data const data) { printf("Progress of %p: %f, %f, %f, %f\n", userHandle, data.call.total, data.call.now, data.response.total, data.response.now); } static void testCreateCurlParms(void) { #if MUST_BUILD_CURL_CLIENT xmlrpc_env env; xmlrpc_client * clientP; struct xmlrpc_clientparms clientParms1; struct xmlrpc_curl_xportparms curlTransportParms1; xmlrpc_env_init(&env); clientParms1.transport = "curl"; clientParms1.transportparmsP = &curlTransportParms1; curlTransportParms1.network_interface = "eth0"; clientParms1.transportparm_size = XMLRPC_CXPSIZE(network_interface); xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); curlTransportParms1.no_ssl_verifypeer = 1; curlTransportParms1.no_ssl_verifyhost = 1; clientParms1.transportparm_size = XMLRPC_CXPSIZE(no_ssl_verifyhost); xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); curlTransportParms1.user_agent = "testprog/1.0"; clientParms1.transportparm_size = XMLRPC_CXPSIZE(user_agent); xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); curlTransportParms1.ssl_cert = NULL; curlTransportParms1.sslcerttype = NULL; curlTransportParms1.sslcertpasswd = NULL; curlTransportParms1.sslkey = NULL; curlTransportParms1.sslkeytype = NULL; curlTransportParms1.sslkeypasswd = NULL; curlTransportParms1.sslengine = NULL; curlTransportParms1.sslengine_default = false; curlTransportParms1.sslversion = XMLRPC_SSLVERSION_DEFAULT; curlTransportParms1.cainfo = NULL; curlTransportParms1.capath = NULL; curlTransportParms1.randomfile = NULL; curlTransportParms1.egdsocket = NULL; curlTransportParms1.ssl_cipher_list = NULL; curlTransportParms1.timeout = 0; curlTransportParms1.dont_advertise = 1; curlTransportParms1.proxy = NULL; curlTransportParms1.proxy_port = 0; curlTransportParms1.proxy_type = XMLRPC_HTTPPROXY_HTTP; curlTransportParms1.proxy_auth = XMLRPC_HTTPAUTH_NONE; curlTransportParms1.proxy_userpwd = "mypassword"; curlTransportParms1.gssapi_delegation = 1; curlTransportParms1.referer = "myreferer"; clientParms1.transportparm_size = XMLRPC_CXPSIZE(referer); xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); xmlrpc_env_clean(&env); #endif /* MUST_BUILD_CURL_CLIENT */ } static void testCreateSeparateXport(void) { #if MUST_BUILD_CURL_CLIENT xmlrpc_env env; xmlrpc_client * clientP; struct xmlrpc_clientparms clientParms1; struct xmlrpc_curl_xportparms curlTransportParms1; struct xmlrpc_client_transport * transportP; xmlrpc_env_init(&env); xmlrpc_curl_transport_ops.create( &env, 0, "", "", &curlTransportParms1, 0, &transportP); TEST_NO_FAULT(&env); clientParms1.transport = NULL; clientParms1.transportparmsP = NULL; clientParms1.transportparm_size = 0; clientParms1.transportOpsP = NULL; clientParms1.transportP = NULL; xmlrpc_client_create(&env, 0, "", "", &clientParms1, XMLRPC_CPSIZE(transportP), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); clientParms1.transport = "curl"; clientParms1.transportparmsP = &curlTransportParms1; clientParms1.transportparm_size = 0; clientParms1.transportOpsP = NULL; clientParms1.transportP = NULL; xmlrpc_client_create(&env, 0, "", "", &clientParms1, XMLRPC_CPSIZE(transportP), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); clientParms1.transportP = transportP; xmlrpc_client_create(&env, 0, "", "", &clientParms1, XMLRPC_CPSIZE(transportP), &clientP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Both transportP and transport specified */ clientParms1.transport = NULL; clientParms1.transportparmsP = NULL; clientParms1.transportparm_size = 0; clientParms1.transportOpsP = &xmlrpc_curl_transport_ops; clientParms1.transportP = transportP; xmlrpc_client_create(&env, 0, "", "", &clientParms1, XMLRPC_CPSIZE(transportOpsP), &clientP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* transportOpsP but no transportP */ xmlrpc_client_create(&env, 0, "", "", &clientParms1, XMLRPC_CPSIZE(transportP), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); xmlrpc_curl_transport_ops.destroy(transportP); xmlrpc_env_clean(&env); #endif /* MUST_BUILD_CURL_CLIENT */ } static void testCreateDestroy(void) { xmlrpc_env env; xmlrpc_client * clientP; struct xmlrpc_clientparms clientParms1; struct xmlrpc_curl_xportparms curlTransportParms1; int interrupt; xmlrpc_env_init(&env); xmlrpc_client_create(&env, 0, "testprog", "1.0", NULL, 0, &clientP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Didn't set up global const */ xmlrpc_client_setup_global_const(&env); TEST_NO_FAULT(&env); xmlrpc_client_create(&env, 0, "testprog", "1.0", NULL, 0, &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, 0, &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); clientParms1.transport = "curl"; xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transport), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); clientParms1.transportparmsP = NULL; xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparmsP), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); clientParms1.transportOpsP = NULL; clientParms1.transportP = NULL; clientParms1.dialect = xmlrpc_dialect_apache; clientParms1.progressFn = &myProgress; xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(progressFn), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_destroy(clientP); clientParms1.transportparmsP = &curlTransportParms1; xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparmsP), &clientP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); clientParms1.transportparm_size = 0; xmlrpc_client_create(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size), &clientP); TEST_NO_FAULT(&env); xmlrpc_client_set_interrupt(clientP, &interrupt); xmlrpc_client_set_interrupt(clientP, NULL); xmlrpc_client_destroy(clientP); testCreateCurlParms(); testCreateSeparateXport(); xmlrpc_client_teardown_global_const(); xmlrpc_env_clean(&env); } static void testSynchCall(void) { xmlrpc_env env; xmlrpc_client * clientP; xmlrpc_value * resultP; xmlrpc_value * emptyArrayP; xmlrpc_server_info * noSuchServerInfoP; xmlrpc_env_init(&env); emptyArrayP = xmlrpc_array_new(&env); TEST_NO_FAULT(&env); xmlrpc_client_setup_global_const(&env); TEST_NO_FAULT(&env); xmlrpc_client_create(&env, 0, "testprog", "1.0", NULL, 0, &clientP); TEST_NO_FAULT(&env); noSuchServerInfoP = xmlrpc_server_info_new(&env, "nosuchserver"); TEST_NO_FAULT(&env); xmlrpc_client_call2(&env, clientP, noSuchServerInfoP, "nosuchmethod", emptyArrayP, &resultP); TEST_FAULT(&env, XMLRPC_NETWORK_ERROR); /* No such server */ xmlrpc_client_call2f(&env, clientP, "nosuchserver", "nosuchmethod", &resultP, "(i)", 7); TEST_FAULT(&env, XMLRPC_NETWORK_ERROR); /* No such server */ xmlrpc_server_info_free(noSuchServerInfoP); xmlrpc_client_destroy(clientP); xmlrpc_DECREF(emptyArrayP); xmlrpc_client_teardown_global_const(); xmlrpc_env_clean(&env); } static void testInitCleanup(void) { xmlrpc_env env; struct xmlrpc_clientparms clientParms1; struct xmlrpc_curl_xportparms curlTransportParms1; xmlrpc_env_init(&env); xmlrpc_client_init2(&env, 0, "testprog", "1.0", NULL, 0); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, 0); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); clientParms1.transport = "curl"; xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transport)); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); clientParms1.transportparmsP = NULL; xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparmsP)); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); clientParms1.transportparmsP = &curlTransportParms1; /* Fails because we didn't include transportparm_size: */ xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparmsP)); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); clientParms1.transportparm_size = 0; xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size)); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); curlTransportParms1.network_interface = "eth0"; clientParms1.transportparm_size = XMLRPC_CXPSIZE(network_interface); xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size)); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); curlTransportParms1.no_ssl_verifypeer = 1; curlTransportParms1.no_ssl_verifyhost = 1; clientParms1.transportparm_size = XMLRPC_CXPSIZE(no_ssl_verifyhost); xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size)); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); curlTransportParms1.user_agent = "testprog/1.0"; clientParms1.transportparm_size = XMLRPC_CXPSIZE(user_agent); xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, XMLRPC_CPSIZE(transportparm_size)); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); xmlrpc_client_init(0, "testprog", "1.0"); TEST_NO_FAULT(&env); xmlrpc_client_cleanup(); xmlrpc_env_clean(&env); } static void testServerInfo(void) { xmlrpc_env env; xmlrpc_server_info * serverInfoP; xmlrpc_server_info * serverInfo2P; printf(" Running serverInfo tests...\n"); xmlrpc_env_init(&env); serverInfoP = xmlrpc_server_info_new(&env, "testurl"); TEST_NO_FAULT(&env); serverInfo2P = xmlrpc_server_info_copy(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_free(serverInfo2P); /* Fails because we haven't set user/password yet: */ xmlrpc_server_info_allow_auth_basic(&env, serverInfoP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_server_info_set_basic_auth(&env, serverInfoP, "username", "password"); TEST_NO_FAULT(&env); xmlrpc_server_info_set_user(&env, serverInfoP, "username", "password"); TEST_NO_FAULT(&env); xmlrpc_server_info_allow_auth_basic(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_disallow_auth_basic(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_allow_auth_digest(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_disallow_auth_digest(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_allow_auth_negotiate(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_disallow_auth_negotiate(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_allow_auth_ntlm(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_disallow_auth_ntlm(&env, serverInfoP); TEST_NO_FAULT(&env); xmlrpc_server_info_free(serverInfoP); xmlrpc_env_clean(&env); } void test_client(void) { printf("Running client tests."); testVersion(); testGlobalConst(); testCreateDestroy(); testInitCleanup(); printf("\n"); testServerInfo(); testSynchCall(); printf("\n"); printf("Client tests done.\n"); } xmlrpc-c-1.33.14/test/client.h000066400000000000000000000000311236133176700160210ustar00rootroot00000000000000void test_client(void); xmlrpc-c-1.33.14/test/client_dummy.c000066400000000000000000000002511236133176700172330ustar00rootroot00000000000000#include #include "client.h" void test_client(void) { printf("Running dummy client test."); printf("\n"); printf("Client tests done.\n"); } xmlrpc-c-1.33.14/test/cpp/000077500000000000000000000000001236133176700151625ustar00rootroot00000000000000xmlrpc-c-1.33.14/test/cpp/Makefile000066400000000000000000000044131236133176700166240ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') testDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(testDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := test/cpp include $(BLDDIR)/config.mk PROGS = test default: all all: $(PROGS) XMLRPC_C_CONFIG = $(BLDDIR)/xmlrpc-c-config.test LIBS := LIBS += -lpthread INCLUDES = -Isrcdir/include -I$(BLDDIR) -Isrcdir -Isrcdir/lib/util/include # This 'common.mk' dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/common.mk: srcdir blddir include $(SRCDIR)/common.mk TEST_OBJS = \ test.o \ base64.o \ registry.o \ server_abyss.o \ server_pstream.o \ tools.o \ value.o \ xml.o \ ifeq ($(MUST_BUILD_CLIENT),yes) TEST_OBJS += testclient.o CLIENT_LIBS = $(LIBXMLRPC_CLIENTPP_A) $(LIBXMLRPC_CLIENT_A) LIBS += $(shell $(XMLRPC_C_CONFIG) client --ldadd) else TEST_OBJS += testclient_dummy.o CLIENT_LIBS = endif TEST_LIBS = \ $(LIBXMLRPC_SERVER_ABYSSPP_A) \ $(LIBXMLRPC_SERVER_PSTREAMPP_A) \ $(LIBXMLRPC_SERVERPP_A) \ $(CLIENT_LIBS) $(LIBXMLRPCPP_A) \ $(LIBXMLRPC_CPP_A) \ $(LIBXMLRPC_SERVER_ABYSS_A) \ $(LIBXMLRPC_SERVER_A) \ $(LIBXMLRPC_A) \ $(LIBXMLRPC_ABYSS_A) \ $(LIBXMLRPC_PACKETSOCKET_A) \ $(LIBXMLRPC_UTIL_A) \ ifeq ($(MSVCRT),yes) TEST_LIBS += socketpair.o endif ifneq ($(ENABLE_LIBXML2_BACKEND),yes) # We're using the internal Expat XML parser TEST_LIBS += $(LIBXMLRPC_XMLPARSE_A) $(LIBXMLRPC_XMLTOK_A) LIB_XML = registry.o: D_INTERNAL_EXPAT=-DINTERNAL_EXPAT else LIB_XML = $(shell xml2-config --libs) endif test: $(TEST_OBJS) $(TEST_LIBS) $(CXXLD) -o $@ $(LDFLAGS_ALL) $^ $(LIB_XML) $(LIBS) %.o:%.cpp $(CXX) -c $(INCLUDES) $(CXXFLAGS_ALL) $(D_INTERNAL_EXPAT) $< socketpair.o: $(SRCDIR)/Windows/socketpair.cpp $(CXX) -c $(INCLUDES) $(CXXFLAGS_ALL) $(D_INTERNAL_EXPAT) $< # Note the difference between 'check' and 'runtests'. 'check' means to check # our own correctness. 'runtests' means to run the tests that check our # parent's correctness .PHONY: check check: .PHONY: runtests runtests: test ./test .PHONY: install install: .PHONY: clean clean-local distclean clean: clean-common clean-local clean-local: rm -f $(PROGS) distclean: clean distclean-common .PHONY: dep dep: dep-common include depend.mk xmlrpc-c-1.33.14/test/cpp/base64.cpp000066400000000000000000000021351236133176700167530ustar00rootroot00000000000000#include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "xmlrpc-c/base64.hpp" #include "tools.hpp" #include "base64.hpp" using namespace xmlrpc_c; using namespace std; string base64TestSuite::suiteName() { return "base64TestSuite"; } void base64TestSuite::runtests(unsigned int const) { unsigned char const bytes0Data[] = "This is a test"; vector bytes0(&bytes0Data[0], &bytes0Data[sizeof(bytes0Data)]); string const base64_0("VGhpcyBpcyBhIHRlc3QA"); string const expectedBase64_0(base64_0 + "\r\n"); TEST(base64FromBytes(bytes0) == expectedBase64_0); TEST(bytesFromBase64(base64_0) == bytes0); unsigned char const bytes1Data[] = {0x80, 0xff}; vector bytes1(&bytes1Data[0], &bytes1Data[sizeof(bytes1Data)]); string const base64_1("gP8="); string const expectedBase64_1(base64_1 + "\r\n"); TEST(base64FromBytes(bytes1) == expectedBase64_1); TEST(bytesFromBase64(base64_1) == bytes1); } xmlrpc-c-1.33.14/test/cpp/base64.hpp000066400000000000000000000002561236133176700167620ustar00rootroot00000000000000#include "tools.hpp" class base64TestSuite : public testSuite { public: virtual std::string suiteName(); virtual void runtests(unsigned int const indentation); }; xmlrpc-c-1.33.14/test/cpp/registry.cpp000066400000000000000000000325501236133176700175430ustar00rootroot00000000000000/*============================================================================= registry =============================================================================== Test the method registry (server) C++ facilities of XML-RPC for C/C++. =============================================================================*/ #include #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/registry.hpp" #include "tools.hpp" #include "registry.hpp" using namespace xmlrpc_c; using namespace std; namespace { static string const xmlPrologue("\r\n"); static string const apacheUrl("http://ws.apache.org/xmlrpc/namespaces/extensions"); static string const xmlnsApache("xmlns:ex=\"" + apacheUrl + "\""); string const noElementFoundXml( xmlPrologue + "\r\n" "\r\n" "\r\n" "faultCode\r\n" "-503\r\n" "faultString\r\n" "Call XML not a proper XML-RPC call. " "Call is not valid XML. no element found" "\r\n" "\r\n" "\r\n" "\r\n" ); string const invalidXMLCall( xmlPrologue + "\r\n" "\r\n" "\r\n" "faultCode\r\n" "-503\r\n" "faultString\r\n" "Call XML not a proper XML-RPC call. " "Call is not valid XML. XML parsing failed" "\r\n" "\r\n" "\r\n" "\r\n" ); string const sampleAddGoodCallXml( xmlPrologue + "\r\n" "sample.add\r\n" "\r\n" "5\r\n" "7\r\n" "\r\n" "\r\n" ); string const sampleAddGoodResponseXml( xmlPrologue + "\r\n" "\r\n" "12\r\n" "\r\n" "\r\n" ); string const sampleAddBadCallXml( xmlPrologue + "\r\n" "sample.add\r\n" "\r\n" "5\r\n" "\r\n" "\r\n" ); string const sampleAddBadResponseXml( xmlPrologue + "\r\n" "\r\n" "\r\n" "faultCode\r\n" "-501\r\n" "faultString\r\n" "Not enough parameters\r\n" "\r\n" "\r\n" "\r\n" ); string const testCallInfoCallXml( xmlPrologue + "\r\n" "test.callinfo\r\n" "\r\n" "\r\n" "\r\n" ); string const testCallInfoResponseXml( xmlPrologue + "\r\n" "\r\n" "this is a test callInfo" "\r\n" "\r\n" "\r\n" ); string const nonexistentMethodCallXml( xmlPrologue + "\r\n" "nosuchmethod\r\n" "\r\n" "5\r\n" "7\r\n" "\r\n" "\r\n" ); string const nonexistentMethodYesDefResponseXml( xmlPrologue + "\r\n" "\r\n" "no such method: nosuchmethod" "\r\n" "\r\n" "\r\n" ); string const nonexistentMethodNoDefResponseXml( xmlPrologue + "\r\n" "\r\n" "\r\n" "faultCode\r\n" "-506\r\n" "faultString\r\n" "Method 'nosuchmethod' not defined" "\r\n" "\r\n" "\r\n" "\r\n" ); string const echoI8ApacheCall( xmlPrologue + "\r\n" "echo\r\n" "\r\n" "5\r\n" "\r\n" "\r\n" ); string const echoI8ApacheResponse( xmlPrologue + "\r\n" "\r\n" "5\r\n" "\r\n" "\r\n" ); string const echoNilApacheCall( xmlPrologue + "\r\n" "echo\r\n" "\r\n" "\r\n" "\r\n" "\r\n" ); string const echoNilApacheResponse( xmlPrologue + "\r\n" "\r\n" "\r\n" "\r\n" "\r\n" ); class callInfo_test : public callInfo { public: callInfo_test() : data("this is a test callInfo") {} callInfo_test(string const& data) : data(data) {}; string data; }; class sampleAddMethod : public method { public: sampleAddMethod() { this->_signature = "i:ii"; this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = value_int(addend + adder); } }; class sampleAddMethod2 : public method2 { public: sampleAddMethod2() { this->_signature = "i:ii"; this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, const callInfo * const, value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = value_int(addend + adder); } }; class testCallInfoMethod : public method2 { public: testCallInfoMethod() { this->_signature = "s:"; } void execute(xmlrpc_c::paramList const& paramList, const callInfo * const callInfoPtr, value * const retvalP) { const callInfo_test * const callInfoP( dynamic_cast(callInfoPtr)); TEST(callInfoP != NULL); paramList.verifyEnd(0); *retvalP = value_string(callInfoP->data); } }; class nameMethod : public defaultMethod { void execute(string const& methodName, xmlrpc_c::paramList const& , // paramList value * const retvalP) { *retvalP = value_string(string("no such method: ") + methodName); } }; class echoMethod : public method { public: void execute(xmlrpc_c::paramList const& paramList, value * const retvalP) { paramList.verifyEnd(1); *retvalP = paramList[0]; } }; static void testEmptyXmlDocCall(xmlrpc_c::registry const& myRegistry) { string response; myRegistry.processCall("", &response); #ifdef INTERNAL_EXPAT TEST(response == noElementFoundXml); #else // This is what we get with libxml2 TEST(response == invalidXMLCall); #endif } class registryRegMethodTestSuite : public testSuite { public: virtual string suiteName() { return "registryRegMethodTestSuite"; } virtual void runtests(unsigned int const) { xmlrpc_c::registry myRegistry; myRegistry.addMethod("sample.add", xmlrpc_c::methodPtr(new sampleAddMethod)); myRegistry.disableIntrospection(); testEmptyXmlDocCall(myRegistry); { string response; myRegistry.processCall(sampleAddGoodCallXml, &response); TEST(response == sampleAddGoodResponseXml); } { string response; myRegistry.processCall(sampleAddBadCallXml, &response); TEST(response == sampleAddBadResponseXml); } { string response; callInfo const callInfo; myRegistry.processCall(sampleAddBadCallXml, &callInfo, &response); TEST(response == sampleAddBadResponseXml); } } }; class registryDefaultMethodTestSuite : public testSuite { public: virtual string suiteName() { return "registryDefaultMethodTestSuite"; } virtual void runtests(unsigned int const) { xmlrpc_c::registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); { string response; myRegistry.processCall(sampleAddGoodCallXml, &response); TEST(response == sampleAddGoodResponseXml); } { string response; myRegistry.processCall(nonexistentMethodCallXml, &response); TEST(response == nonexistentMethodNoDefResponseXml); } // We're actually violating the spirit of setDefaultMethod by // doing this to a registry that's already been used, but as long // as it works, it's a convenient way to implement this test. myRegistry.setDefaultMethod(defaultMethodPtr(new nameMethod)); { string response; myRegistry.processCall(nonexistentMethodCallXml, &response); TEST(response == nonexistentMethodYesDefResponseXml); } } }; class method2TestSuite : public testSuite { public: virtual string suiteName() { return "method2TestSuite"; } virtual void runtests(unsigned int const) { xmlrpc_c::registry myRegistry; myRegistry.addMethod("sample.add", xmlrpc_c::methodPtr(new sampleAddMethod2)); myRegistry.addMethod("test.callinfo", xmlrpc_c::methodPtr(new testCallInfoMethod)); { string response; myRegistry.processCall(sampleAddGoodCallXml, &response); TEST(response == sampleAddGoodResponseXml); } { string response; myRegistry.processCall(sampleAddBadCallXml, &response); TEST(response == sampleAddBadResponseXml); } { string response; callInfo_test const callInfo; myRegistry.processCall(testCallInfoCallXml, &callInfo, &response); TEST(response == testCallInfoResponseXml); } } }; class dialectTestSuite : public testSuite { public: virtual string suiteName() { return "dialectTestSuite"; } virtual void runtests(unsigned int const) { registry myRegistry; string response; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); myRegistry.addMethod("echo", methodPtr(new echoMethod)); myRegistry.setDialect(xmlrpc_dialect_i8); myRegistry.setDialect(xmlrpc_dialect_apache); myRegistry.processCall(echoI8ApacheCall, &response); TEST(response == echoI8ApacheResponse); myRegistry.processCall(echoNilApacheCall, &response); TEST(response == echoNilApacheResponse); EXPECT_ERROR( // invalid dialect myRegistry.setDialect(static_cast(300)); ); } }; class testShutdown : public xmlrpc_c::registry::shutdown { /*---------------------------------------------------------------------------- This class is logically local to registryShutdownTestSuite::runtests(), but if we declare it that way, gcc 2.95.3 fails with some bogus messages about undefined references from random functions when we do that. -----------------------------------------------------------------------------*/ public: void doit(string const&, void * const) const { } }; class registryShutdownTestSuite : public testSuite { public: virtual string suiteName() { return "registryShutdownTestSuite"; } virtual void runtests(unsigned int const) { xmlrpc_c::registry myRegistry; testShutdown shutdown; myRegistry.setShutdown(&shutdown); } }; } // unnamed namespace string registryTestSuite::suiteName() { return "registryTestSuite"; } void registryTestSuite::runtests(unsigned int const indentation) { { registryPtr myRegistryP(new registry); myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod)); } registryRegMethodTestSuite().run(indentation+1); registryDefaultMethodTestSuite().run(indentation+1); method2TestSuite().run(indentation+1); registry myRegistry; myRegistry.disableIntrospection(); dialectTestSuite().run(indentation+1); registryShutdownTestSuite().run(indentation+1); TEST(myRegistry.maxStackSize() >= 256); } xmlrpc-c-1.33.14/test/cpp/registry.hpp000066400000000000000000000002601236133176700175410ustar00rootroot00000000000000#include "tools.hpp" class registryTestSuite : public testSuite { public: virtual std::string suiteName(); virtual void runtests(unsigned int const indentation); }; xmlrpc-c-1.33.14/test/cpp/server_abyss.cpp000066400000000000000000000263211236133176700204010ustar00rootroot00000000000000/*============================================================================= server_abyss =============================================================================== Test the Abyss server C++ facilities of XML-RPC for C/C++. =============================================================================*/ #define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/abyss.h */ #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #include #include #include #endif #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/registry.hpp" #include "xmlrpc-c/server_abyss.hpp" #include "xmlrpc-c/abyss.h" #include "tools.hpp" #include "server_abyss.hpp" using namespace xmlrpc_c; using namespace std; namespace { static void closesock(int const fd) { #ifdef WIN32 closesocket(fd); #else close(fd); #endif } static sockaddr_in localhostSockAddr(short const portNumber) { struct sockaddr_in retval; retval.sin_family = AF_INET; retval.sin_port = htons(portNumber); retval.sin_addr = test_ipAddrFromDecimal(127, 0, 0, 1); return retval; } class boundSocket { public: boundSocket(short const portNumber) { this->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (this->fd < 0) throwf("socket() failed. errno=%d (%s)", errno, strerror(errno)); struct sockaddr_in sockAddr; int rc; sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(portNumber); sockAddr.sin_addr.s_addr = 0; rc = bind(this->fd, (struct sockaddr *)&sockAddr, sizeof(sockAddr)); if (rc != 0) { closesock(this->fd); throwf("Couldn't bind. bind() failed with errno=%d (%s)", errno, strerror(errno)); } } ~boundSocket() { closesock(this->fd); } XMLRPC_SOCKET fd; }; class sampleAddMethod : public method { public: sampleAddMethod() { this->_signature = "i:ii"; this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = value_int(addend + adder); } }; // We need 'global' because methods of class addHandlerTestSuite call // functions in the Abyss C library. By virtue of global's static // storage class, the program loader will call its constructor and // destructor and thus initialize and terminate the Abyss C library. static class abyssGlobalState { public: abyssGlobalState() { const char * error; AbyssInit(&error); if (error) { string const e(error); free(const_cast(error)); throwf("AbyssInit() failed. %s", e.c_str()); } } ~abyssGlobalState() { AbyssTerm(); } } const global; class addHandlerTestSuite : public testSuite { public: virtual string suiteName() { return "addHandlerTestSuite"; } virtual void runtests(unsigned int const) { TServer abyssServer; ServerCreate(&abyssServer, "testserver", 8080, NULL, NULL); registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); registryPtr myRegistryP(new registry); myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod)); server_abyss_set_handlers(&abyssServer, myRegistry); server_abyss_set_handlers(&abyssServer, &myRegistry); server_abyss_set_handlers(&abyssServer, myRegistryP); server_abyss_set_handlers(&abyssServer, myRegistry, "/RPC3"); server_abyss_set_handlers(&abyssServer, &myRegistry, "/RPC3"); server_abyss_set_handlers(&abyssServer, myRegistryP, "/RPC3"); ServerFree(&abyssServer); } }; class setShutdownTestSuite : public testSuite { public: virtual string suiteName() { return "setShutdownTestSuite"; } virtual void runtests(unsigned int const) { registry myRegistry; serverAbyss myServer(serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(12345) ); serverAbyss::shutdown shutdown(&myServer); myRegistry.setShutdown(&shutdown); } }; class createTestSuite : public testSuite { public: virtual string suiteName() { return "createTestSuite"; } virtual void runtests(unsigned int const) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); registryPtr myRegistryP(new registry); myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod)); struct sockaddr_in const sockAddr(localhostSockAddr(8080)); const struct sockaddr * const sockAddrP( (const struct sockaddr *)&sockAddr); EXPECT_ERROR( // No registry serverAbyss::constrOpt opt; serverAbyss abyssServer(opt); ); EXPECT_ERROR( // Both registryP and registryPtr serverAbyss abyssServer(serverAbyss::constrOpt() .registryPtr(myRegistryP) .registryP(&myRegistry) .portNumber(12345) ); ); EXPECT_ERROR( // Both portNumber and socketFd serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(8080) .socketFd(3)); ); EXPECT_ERROR( // Both portNumber and sockAddrP serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(8080) .sockAddrP(sockAddrP) .sockAddrLen(sizeof(sockAddr))); ); EXPECT_ERROR( // Both socketFd and sockAddrP serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) .socketFd(3) .sockAddrP(sockAddrP) .sockAddrLen(sizeof(sockAddr))); ); EXPECT_ERROR( // sockAddrP but no sockAddrLen serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) .sockAddrP(sockAddrP)); ); EXPECT_ERROR( // port number too big serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(65536)); ); // Due to the vagaries of Abyss, construction of the following // objects may exit the program if it detects an error, such as // port number already in use. We need to fix Abyss some day. { serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(12345) ); } { serverAbyss abyssServer(serverAbyss::constrOpt() .registryPtr(myRegistryP) .portNumber(12345) ); } { boundSocket socket(12345); serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) .socketFd(socket.fd) ); } { serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) ); } { serverAbyss abyssServer(serverAbyss::constrOpt() .registryPtr(myRegistryP) .sockAddrP(sockAddrP) .sockAddrLen(sizeof(sockAddr)) ); } { // Test all the options serverAbyss abyssServer(serverAbyss::constrOpt() .registryPtr(myRegistryP) .portNumber(12345) .maxConn(10) .maxConnBacklog(10) .keepaliveTimeout(5) .keepaliveMaxConn(4) .timeout(20) .dontAdvertise(true) .uriPath("/xmlrpc") .chunkResponse(true) .allowOrigin("*") .accessCtlMaxAge(42) .logFileName("/tmp/logfile") .serverOwnsSignals(false) .expectSigchld(true) ); } { serverAbyss abyssServer( myRegistry, 12345, // TCP port on which to listen "/tmp/xmlrpc_log" // Log file ); } } }; class testCallInfoMethod : public method2 { public: void execute(paramList const& paramList, const callInfo * const callInfoPtr, value * const retvalP) { const callInfo_serverAbyss * const callInfoP( dynamic_cast(callInfoPtr)); TEST(callInfoP != NULL); paramList.verifyEnd(0); TEST(callInfoP->serverAbyssP != NULL); TEST(callInfoP->abyssSessionP != NULL); *retvalP = value_nil(); } }; class callInfoTestSuite : public testSuite { public: virtual string suiteName() { return "callInfoTestSuite"; } virtual void runtests(unsigned int const) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new testCallInfoMethod)); serverAbyss abyssServer(serverAbyss::constrOpt() .registryP(&myRegistry) .portNumber(12345) ); } }; } // unnamed namespace string serverAbyssTestSuite::suiteName() { return "serverAbyssTestSuite"; } void serverAbyssTestSuite::runtests(unsigned int const indentation) { addHandlerTestSuite().run(indentation+1); setShutdownTestSuite().run(indentation+1); createTestSuite().run(indentation+1); callInfoTestSuite().run(indentation+1); } xmlrpc-c-1.33.14/test/cpp/server_abyss.hpp000066400000000000000000000002461236133176700204040ustar00rootroot00000000000000#include "tools.hpp" class serverAbyssTestSuite : public testSuite { public: virtual std::string suiteName(); virtual void runtests(unsigned int const); }; xmlrpc-c-1.33.14/test/cpp/server_pstream.cpp000066400000000000000000000464411236133176700207400ustar00rootroot00000000000000/*============================================================================= server_pstream =============================================================================== Test the pstream server C++ facilities of XML-RPC for C/C++. =============================================================================*/ #include "xmlrpc_config.h" #if MSVCRT #include #include #else #include #include #include #include #endif #include #include #include #include #include "xmlrpc-c/config.h" #if MSVCRT int xmlrpc_win32_socketpair(int const domain, int const type, int const protocol, SOCKET socks[2]); #endif #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/sleep_int.h" #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/registry.hpp" #include "xmlrpc-c/server_pstream.hpp" #include "tools.hpp" #include "server_pstream.hpp" using namespace xmlrpc_c; using namespace std; namespace { static void setNonBlocking(XMLRPC_SOCKET const socket) { #if MSVCRT u_long iMode = 1; ioctlsocket(socket, FIONBIO, &iMode); #else fcntl(socket, F_SETFL, O_NONBLOCK); #endif } #define ESC_STR "\x1B" static string const xmlPrologue("\r\n"); static string const packetStart(ESC_STR "PKT"); static string const packetEnd(ESC_STR "END"); class callInfo_test : public callInfo { public: callInfo_test() : info("this is a test") {} string const info; }; class sampleAddMethod : public method { public: sampleAddMethod() { this->_signature = "i:ii"; this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = value_int(addend + adder); } }; string const sampleAddCallXml( xmlPrologue + "\r\n" "sample.add\r\n" "\r\n" "5\r\n" "7\r\n" "\r\n" "\r\n" ); string const sampleAddResponseXml( xmlPrologue + "\r\n" "\r\n" "12\r\n" "\r\n" "\r\n" ); class testCallInfoMethod : public method2 { public: virtual void execute(paramList const& paramList, const callInfo * const callInfoPtr, value * const retvalP) { const callInfo_test * const callInfoP( dynamic_cast(callInfoPtr)); TEST(callInfoP != NULL); paramList.verifyEnd(0); TEST(callInfoP->info == string("this is a test")); *retvalP = value_nil(); } }; string const testCallInfoCallXml( xmlPrologue + "\r\n" "test.callinfo\r\n" "\r\n" "\r\n" "\r\n" ); string const testCallInfoResponseXml( xmlPrologue + "\r\n" "\r\n" "" "\r\n" "\r\n" "\r\n" ); static void waitForNetworkTransport() { /*---------------------------------------------------------------------------- Wait for a message to travel through the network. This is part of our hack to allow us to test client/server communication without the bother of a separate thread for each. One party writes to a socket, causing the OS to buffer the message, then the other party reads from the socket, getting the buffered message. We never wait to send or receive, because with only one thread to do both, we would deadlock. Instead, we just count on the buffer being big enough. But on some systems, the message doesn't immediately travel like this. It takes action by an independent thread (provided by the OS) to move the message. In particular, we've seen this behavior on Windows (2010.10). So we just sleep for a small amount of time to let the message move. -----------------------------------------------------------------------------*/ // xmlrpc_millisecond_sleep() is allowed to return early, and on Windows // it does that in preference to returning late insofar as the clock // resolution doesn't allow returning at the exact time. It is rumored // that Windows clock period may be as long as 40 milliseconds. xmlrpc_millisecond_sleep(50); } class client { /*---------------------------------------------------------------------------- This is an object you can use as a client to test a packet stream server. You attach the 'serverFd' member to your packet stream server, then call the 'sendCall' method to send a call to your server, then call the 'recvResp' method to get the response. Destroying the object closes the connection. We rely on typical, though unguaranteed socket function: we need to be able to write 'contents' to the socket in a single write() system call before the other side reads anything -- i.e. the socket has to have a buffer that big. We do this because we're lazy; doing it right would require forking a writer process. -----------------------------------------------------------------------------*/ public: client(); ~client(); void sendCall(string const& callBytes) const; void hangup(); void recvResp(string * const respBytesP) const; int serverFd; private: int clientFd; }; client::client() { enum { SERVER = 0, CLIENT = 1, }; XMLRPC_SOCKET sockets[2]; int rc; rc = XMLRPC_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sockets); if (rc < 0) throwf("Failed to create UNIX domain stream socket pair " "as test tool. errno=%d (%s)", errno, strerror(errno)); else { setNonBlocking(sockets[CLIENT]); this->serverFd = sockets[SERVER]; this->clientFd = sockets[CLIENT]; } } client::~client() { XMLRPC_CLOSESOCKET(this->clientFd); XMLRPC_CLOSESOCKET(this->serverFd); } void client::sendCall(string const& packetBytes) const { int rc; rc = send(this->clientFd, packetBytes.c_str(), packetBytes.length(), 0); waitForNetworkTransport(); if (rc < 0) throwf("send() of test data to socket failed, errno=%d (%s)", errno, strerror(errno)); else { unsigned int bytesWritten(rc); if (bytesWritten != packetBytes.length()) throwf("Short write to socket"); } } void client::hangup() { // Closing the socket (close()) would be a better simulation of the // real world, and easier, but we shut down just the client->server // half of the socket and remain open to receive an RPC response. // That's because this test program is lazy and does the client and // server in the same thread, depending on socket buffering on the // receive side to provide parallelism. We need to be able to do the // following sequence: // // - Client sends call // - Client hangs up // - Server gets call // - Server sends response // - Client gets response // - Server notices hangup shutdown(this->clientFd, 1); // Shutdown for transmission only } void client::recvResp(string * const packetBytesP) const { char buffer[4096]; int rc; waitForNetworkTransport(); rc = recv(this->clientFd, buffer, sizeof(buffer), 0); if (rc < 0) throwf("recv() from socket failed, errno=%d (%s)", errno, strerror(errno)); else { unsigned int bytesReceived(rc); *packetBytesP = string(buffer, bytesReceived); } } static void testEmptyStream(registry const& myRegistry) { /*---------------------------------------------------------------------------- Here we send the pstream server an empty stream; i.e. we close the socket from the client end without sending anything. This should cause the server to recognize EOF. -----------------------------------------------------------------------------*/ client client; serverPstreamConn server(serverPstreamConn::constrOpt() .registryP(&myRegistry) .socketFd(client.serverFd)); client.hangup(); bool eof; server.runOnce(&eof); TEST(eof); } static void testBrokenPacket(registry const& myRegistry) { /*---------------------------------------------------------------------------- Here we send a stream that is not a legal packetsocket stream: it doesn't have any control word. -----------------------------------------------------------------------------*/ client client; serverPstreamConn server(serverPstreamConn::constrOpt() .registryP(&myRegistry) .socketFd(client.serverFd)); client.sendCall("junk"); client.hangup(); bool eof; EXPECT_ERROR( server.runOnce(&eof); ); } static void testEmptyPacket(registry const& myRegistry) { /*---------------------------------------------------------------------------- Here we send the pstream server one empty packet. It should respond with one packet, being an XML-RPC fault response complaining that the call is not valid XML. -----------------------------------------------------------------------------*/ client client; serverPstreamConn server(serverPstreamConn::constrOpt() .registryP(&myRegistry) .socketFd(client.serverFd)); client.sendCall(packetStart + packetEnd); bool eof; server.runOnce(&eof); TEST(!eof); string response; client.recvResp(&response); // We ought to validate that the response is a complaint about // the empty call client.hangup(); server.runOnce(&eof); TEST(eof); } static void testCallInfo(client * const clientP, serverPstreamConn * const serverP) { string const testCallInfoCallStream( packetStart + testCallInfoCallXml + packetEnd ); string const testCallInfoResponseStream( packetStart + testCallInfoResponseXml + packetEnd ); clientP->sendCall(testCallInfoCallStream); callInfo_test callInfo; int nointerrupt(0); bool eof; serverP->runOnce(&callInfo, &nointerrupt, &eof); TEST(!eof); string response; clientP->recvResp(&response); TEST(response == testCallInfoResponseStream); } static void testNormalCall(registry const& myRegistry) { string const sampleAddGoodCallStream( packetStart + sampleAddCallXml + packetEnd ); string const sampleAddGoodResponseStream( packetStart + sampleAddResponseXml + packetEnd ); client client; serverPstreamConn server(serverPstreamConn::constrOpt() .registryP(&myRegistry) .socketFd(client.serverFd)); client.sendCall(sampleAddGoodCallStream); bool eof; int interrupt(1); server.runOnce(&interrupt, &eof); // returns without reading socket TEST(!eof); server.runOnce(&eof); TEST(!eof); string response; client.recvResp(&response); TEST(response == sampleAddGoodResponseStream); testCallInfo(&client, &server); client.hangup(); server.runOnce(&eof); TEST(eof); } static void testNoWaitCall(registry const& myRegistry) { string const sampleAddGoodCallStream( packetStart + xmlPrologue + "\r\n" "sample.add\r\n" "\r\n" "5\r\n" "7\r\n" "\r\n" "\r\n" + packetEnd ); string const sampleAddGoodResponseStream( packetStart + xmlPrologue + "\r\n" "\r\n" "12\r\n" "\r\n" "\r\n" + packetEnd ); client client; serverPstreamConn server(serverPstreamConn::constrOpt() .registryP(&myRegistry) .socketFd(client.serverFd)); bool eof; bool gotOne; string response; server.runOnceNoWait(&eof, &gotOne); TEST(!eof); TEST(!gotOne); server.runOnceNoWait(&eof); TEST(!eof); client.sendCall(sampleAddGoodCallStream); server.runOnceNoWait(&eof, &gotOne); TEST(!eof); TEST(gotOne); client.recvResp(&response); TEST(response == sampleAddGoodResponseStream); client.sendCall(sampleAddGoodCallStream); server.runOnce(&eof); TEST(!eof); client.recvResp(&response); TEST(response == sampleAddGoodResponseStream); client.hangup(); server.runOnce(&eof); TEST(eof); } static void testMultiRpcRunNoRpc(registry const& myRegistry) { client client; serverPstreamConn server(serverPstreamConn::constrOpt() .registryP(&myRegistry) .socketFd(client.serverFd)); client.hangup(); server.run(); } static void testMultiRpcRunOneRpc(registry const& myRegistry) { string const sampleAddGoodCallStream( packetStart + xmlPrologue + "\r\n" "sample.add\r\n" "\r\n" "5\r\n" "7\r\n" "\r\n" "\r\n" + packetEnd ); string const sampleAddGoodResponseStream( packetStart + xmlPrologue + "\r\n" "\r\n" "12\r\n" "\r\n" "\r\n" + packetEnd ); client client; serverPstreamConn server(serverPstreamConn::constrOpt() .registryP(&myRegistry) .socketFd(client.serverFd)); client.sendCall(sampleAddGoodCallStream); client.hangup(); int interrupt; interrupt = 1; server.run(&interrupt); // Returns without reading socket interrupt = 0; server.run(&interrupt); // Does the buffered RPC string response; client.recvResp(&response); TEST(response == sampleAddGoodResponseStream); } class serverPstreamConnTestSuite : public testSuite { public: virtual string suiteName() { return "serverPstreamConnTestSuite"; } virtual void runtests(unsigned int const) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); myRegistry.addMethod("test.callinfo", methodPtr(new testCallInfoMethod)); registryPtr myRegistryP(new registry); myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod)); EXPECT_ERROR( // Empty options serverPstreamConn::constrOpt opt; serverPstreamConn server(opt); ); EXPECT_ERROR( // No registry serverPstreamConn server(serverPstreamConn::constrOpt() .socketFd(3)); ); EXPECT_ERROR( // No socket fd serverPstreamConn server(serverPstreamConn::constrOpt() .registryP(&myRegistry)); ); testEmptyStream(myRegistry); testBrokenPacket(myRegistry); testEmptyPacket(myRegistry); testNormalCall(myRegistry); testNoWaitCall(myRegistry); testMultiRpcRunNoRpc(myRegistry); testMultiRpcRunOneRpc(myRegistry); } }; static void testMultiConnInterrupt(registry const& myRegistry) { // We use a nonexistent file descriptor, but the server won't // ever access it, so it won't know. serverPstream server(serverPstream::constrOpt() .registryP(&myRegistry) .socketFd(37)); int interrupt(1); // interrupt immediately server.runSerial(&interrupt); } class derivedServer : public xmlrpc_c::serverPstream { public: derivedServer(serverPstream::constrOpt const& constrOpt) : serverPstream(constrOpt), info("this is my derived server") {} string const info; }; class multiTestCallInfoMethod : public method2 { // The test isn't sophisticated enough actually to do an RPC, so this // code never runs. We just want to see if it compiles. public: virtual void execute(paramList const& paramList, const callInfo * const callInfoPtr, value * const retvalP) { const callInfo_serverPstream * const callInfoP( dynamic_cast(callInfoPtr)); TEST(callInfoP != NULL); paramList.verifyEnd(0); derivedServer * const derivedServerP( dynamic_cast(callInfoP->serverP)); TEST(derivedServerP->info == string("this is my derived server")); TEST(callInfoP->clientAddr.sa_family == AF_INET); TEST(callInfoP->clientAddrSize >= sizeof(struct sockaddr_in)); *retvalP = value_nil(); } }; static void testMultiConnCallInfo() { registry myRegistry; myRegistry.addMethod("testCallInfo", methodPtr(new multiTestCallInfoMethod)); derivedServer server(serverPstream::constrOpt() .registryP(&myRegistry) .socketFd(37)); } class multiConnServerTestSuite : public testSuite { public: virtual string suiteName() { return "multiConnServerTestSuite"; } virtual void runtests(unsigned int const) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); registryPtr myRegistryP(new registry); myRegistryP->addMethod("sample.add", methodPtr(new sampleAddMethod)); EXPECT_ERROR( // Empty options serverPstream::constrOpt opt; serverPstream server(opt); ); EXPECT_ERROR( // No registry serverPstream server(serverPstream::constrOpt() .socketFd(3)); ); EXPECT_ERROR( // No socket fd serverPstream server(serverPstream::constrOpt() .registryP(&myRegistry)); ); testMultiConnInterrupt(myRegistry); testMultiConnCallInfo(); } }; } // unnamed namespace string serverPstreamTestSuite::suiteName() { return "serverPstreamTestSuite"; } void serverPstreamTestSuite::runtests(unsigned int const indentation) { serverPstreamConnTestSuite().run(indentation + 1); multiConnServerTestSuite().run(indentation + 1); } xmlrpc-c-1.33.14/test/cpp/server_pstream.hpp000066400000000000000000000002501236133176700207310ustar00rootroot00000000000000#include "tools.hpp" class serverPstreamTestSuite : public testSuite { public: virtual std::string suiteName(); virtual void runtests(unsigned int const); }; xmlrpc-c-1.33.14/test/cpp/test.cpp000066400000000000000000000304561236133176700166550ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/oldcppwrapper.hpp" #include "xmlrpc-c/registry.hpp" #include "base64.hpp" #include "xml.hpp" #include "value.hpp" #include "testclient.hpp" #include "registry.hpp" #include "server_abyss.hpp" #include "server_pstream.hpp" #include "tools.hpp" using namespace xmlrpc_c; using namespace std; //========================================================================= // Test Harness //========================================================================= // // There are two styles of test in here. The older ones are vaguely // inspired by Kent Beck's book on eXtreme Programming (XP) and use // the TEST...() macros. // // But this style is not really appropriate for C++. It's based on // code that explicitly tests for errors, as one would do in C. In C++, // it is cumbersome to catch exceptions on every call, so we don't in // the new style. // And there's not much point in trying to count test successes and // failures. Any failure is a problem, so in the new style, we just // quit after we recognize one (again, more in line with regular exception // throwing). With exception throwing, you can't count what _didn't_ // cause an exception, so there's no meaningful count of test successes. // // To run the tests, type './cpptest'. // To check for memory leaks, install RedHat's 'memprof' utility, and // type 'memprof cpptest'. // // If you add new tests to this file, please deallocate any data // structures you use in the appropriate fashion. This allows us to test // various destructor code for memory leaks. //========================================================================= // Test Suites //========================================================================= void test_fault (void) { // Create a new fault and perform basic operations. XmlRpcFault fault1 = XmlRpcFault(6, "Sample fault"); TEST(fault1.getFaultCode() == 6); TEST(fault1.getFaultString() == "Sample fault"); // Extract and examine the underlying xmlrpc_env struct. xmlrpc_env *env1 = fault1.getFaultEnv(); TEST(env1 != NULL); TEST(env1->fault_occurred); TEST(env1->fault_code == 6); TEST(strcmp(env1->fault_string, "Sample fault") == 0); // Test our copy constructor. XmlRpcFault fault2 = fault1; TEST(fault2.getFaultCode() == 6); TEST(fault2.getFaultString() == "Sample fault"); // Construct a fault from a pre-existing xmlrpc_env structure. xmlrpc_env env3; xmlrpc_env_init(&env3); xmlrpc_env_set_fault(&env3, 7, "Another fault"); XmlRpcFault fault3 = XmlRpcFault(&env3); xmlrpc_env_clean(&env3); TEST(fault3.getFaultCode() == 7); TEST(fault3.getFaultString() == "Another fault"); // Attempt to construct a fault from a fault-free xmlrpc_env. xmlrpc_env env4; xmlrpc_env_init(&env4); try { XmlRpcFault fault4 = XmlRpcFault(&env4); TEST_FAILED("Constructed invalid XmlRpcFault"); } catch (XmlRpcFault const& fault) { TEST_PASSED(); TEST(fault.getFaultCode() == XMLRPC_INTERNAL_ERROR); } xmlrpc_env_clean(&env4); } void test_env (void) { // Declare these here to prevent silly compiler warnings about // potentially uninitialized variables. XmlRpcEnv env1; XmlRpcEnv env2; // Perform simple environment tests. TEST(!env1.hasFaultOccurred()); xmlrpc_env_set_fault(env1, 8, "Fault 8"); TEST(env1.hasFaultOccurred()); XmlRpcFault fault1 = env1.getFault(); TEST(fault1.getFaultCode() == 8); TEST(fault1.getFaultString() == "Fault 8"); // Test throwIfFaultOccurred. try { env2.throwIfFaultOccurred(); TEST_PASSED(); } catch (XmlRpcFault const&) { TEST_FAILED("We threw a fault when one hadn't occurred"); } xmlrpc_env_set_fault(env2, 9, "Fault 9"); try { env2.throwIfFaultOccurred(); TEST_FAILED("A fault occurred, and we didn't throw it"); } catch (XmlRpcFault const& fault) { TEST_PASSED(); TEST(fault.getFaultCode() == 9); TEST(fault.getFaultString() == "Fault 9"); } // Make sure we can't get a fault if one hasn't occurred. XmlRpcEnv env3; try { XmlRpcFault fault3 = env3.getFault(); TEST_FAILED("We retrieved a non-existant fault"); } catch (XmlRpcFault const& fault) { TEST_PASSED(); TEST(fault.getFaultCode() == XMLRPC_INTERNAL_ERROR); } } void test_value (void) { XmlRpcEnv env; // Test basic reference counting behavior. xmlrpc_value *v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 1); env.throwIfFaultOccurred(); XmlRpcValue val1 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE); v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 2); env.throwIfFaultOccurred(); XmlRpcValue val2 = v; xmlrpc_DECREF(v); // Borrow a reference. v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 3); env.throwIfFaultOccurred(); XmlRpcValue val3 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE); xmlrpc_value *borrowed = val3.borrowReference(); TEST(borrowed == v); // Make a reference. v = xmlrpc_build_value(env, "i", (xmlrpc_int32) 4); env.throwIfFaultOccurred(); XmlRpcValue val4 = XmlRpcValue(v, XmlRpcValue::CONSUME_REFERENCE); xmlrpc_value *made = val4.makeReference(); TEST(made == v); xmlrpc_DECREF(made); // Test our default constructor. XmlRpcValue val5; TEST(val5.getBool() == false); // Test our type introspection. TEST(XmlRpcValue::makeInt(0).getType() == XMLRPC_TYPE_INT); // Test our basic data types. TEST(XmlRpcValue::makeInt(30).getInt() == 30); TEST(XmlRpcValue::makeInt(-30).getInt() == -30); TEST(XmlRpcValue::makeBool(true).getBool() == true); TEST(XmlRpcValue::makeBool(false).getBool() == false); TEST(XmlRpcValue::makeDateTime("19980717T14:08:55").getRawDateTime() == "19980717T14:08:55"); TEST(XmlRpcValue::makeString("foo").getString() == "foo"); TEST(XmlRpcValue::makeString("bar", 3).getString() == "bar"); TEST(XmlRpcValue::makeString("bar", 3).getString() == "bar"); TEST(XmlRpcValue::makeString("a\0b").getString() == string("a\0b")); XmlRpcValue::makeArray().getArray(); XmlRpcValue::makeStruct().getStruct(); // Test byte string values. const unsigned char *b64_data; size_t b64_len; XmlRpcValue val6 = XmlRpcValue::makeBase64((unsigned char*) "a\0\0b", 4); val6.getBase64(b64_data, b64_len); TEST(b64_len == 4); TEST(memcmp(b64_data, "a\0\0b", 4) == 0); // Test arrays. XmlRpcValue array = XmlRpcValue::makeArray(); TEST(array.arraySize() == 0); array.arrayAppendItem(XmlRpcValue::makeString("foo")); TEST(array.arraySize() == 1); array.arrayAppendItem(XmlRpcValue::makeString("bar")); TEST(array.arraySize() == 2); TEST(array.arrayGetItem(0).getString() == "foo"); TEST(array.arrayGetItem(1).getString() == "bar"); // Test structs. XmlRpcValue strct = XmlRpcValue::makeStruct(); TEST(strct.structSize() == 0); strct.structSetValue("foo", XmlRpcValue::makeString("fooval")); TEST(strct.structSize() == 1); strct.structSetValue("bar", XmlRpcValue::makeString("barval")); TEST(strct.structSize() == 2); TEST(strct.structHasKey("bar")); TEST(!strct.structHasKey("nosuch")); for (int i = 0; i < (int)strct.structSize(); ++i) { string key; XmlRpcValue value; strct.structGetKeyAndValue(i, key, value); TEST(key + "val" == value.getString()); } } static void testXmlRpcCpp() { /*---------------------------------------------------------------------------- Test the legacy XmlRpcCpp.cpp library -----------------------------------------------------------------------------*/ cout << "Testing XmlRpcCpp library..." << endl; test_fault(); test_env(); test_value(); } static void buildParamListWithAdd(paramList * const paramListP, time_t const timeFuture) { paramListP->add(value_int(7)); paramListP->add(value_boolean(true)).add(value_double(3.14)); time_t const timeZero(0); paramListP->add(value_datetime(timeZero)); paramListP->add(value_datetime(timeFuture)); paramListP->add(value_string("hello world")); unsigned char bytestringArray[] = {0x10, 0x11, 0x12, 0x13, 0x14}; vector bytestringData(&bytestringArray[0], &bytestringArray[4]); paramListP->add(value_bytestring(bytestringData)); vector arrayData; arrayData.push_back(value_int(7)); arrayData.push_back(value_double(2.78)); arrayData.push_back(value_string("hello world")); paramListP->add(value_array(arrayData)); map structData; pair member("the_integer", value_int(9)); structData.insert(member); paramListP->add(value_struct(structData)); paramListP->add(value_nil()); paramListP->add(value_i8((xmlrpc_int64)UINT_MAX + 1)); } static void verifyParamList(paramList const& paramList, time_t const timeFuture) { TEST(paramList.size() == 11); TEST(paramList.getInt(0) == 7); TEST(paramList.getInt(0, 7) == 7); TEST(paramList.getInt(0, -5, 7) == 7); TEST(paramList.getBoolean(1) == true); TEST(paramList.getDouble(2) == 3.14); TEST(paramList.getDouble(2, 1) == 3.14); TEST(paramList.getDouble(2, 1, 4) == 3.14); time_t const timeZero(0); TEST(paramList.getDatetime_sec(3) == timeZero); TEST(paramList.getDatetime_sec(3, paramList::TC_ANY) == timeZero); TEST(paramList.getDatetime_sec(3, paramList::TC_NO_FUTURE) == timeZero); TEST(paramList.getDatetime_sec(4, paramList::TC_NO_PAST) == timeFuture); TEST(paramList.getString(5) == "hello world"); TEST(paramList.getBytestring(6)[0] == 0x10); TEST(paramList.getArray(7).size() == 3); TEST(paramList.getArray(7, 3).size() == 3); TEST(paramList.getArray(7, 1, 3).size() == 3); paramList.getStruct(8)["the_integer"]; paramList.getNil(9); TEST(paramList.getI8(10) == (xmlrpc_int64)UINT_MAX + 1); paramList.verifyEnd(11); } class paramListTestSuite : public testSuite { public: virtual string suiteName() { return "paramListTestSuite"; } virtual void runtests(unsigned int const) { time_t const timeFuture(time(NULL)+100); paramList paramList1; TEST(paramList1.size() == 0); buildParamListWithAdd(¶mList1, timeFuture); verifyParamList(paramList1, timeFuture); paramList paramList2(5); TEST(paramList2.size() == 0); paramList2.addc(7); paramList2.addc(true).addc(3.14); TEST(paramList2.size() == 3); TEST(paramList2.getInt(0) == 7); TEST(paramList2.getBoolean(1) == true); TEST(paramList2.getDouble(2) == 3.14); } }; //========================================================================= // Test Driver //========================================================================= int main(int argc, char**) { int retval; if (argc-1 > 0) { cout << "Program takes no arguments" << endl; exit(1); } bool testsPassed; try { // Add your test suites here. base64TestSuite().run(0); xmlTestSuite().run(0); valueTestSuite().run(0); paramListTestSuite().run(0); registryTestSuite().run(0); serverAbyssTestSuite().run(0); serverPstreamTestSuite().run(0); clientTestSuite().run(0); testXmlRpcCpp(); testsPassed = true; } catch (error const& error) { cout << "Unexpected error thrown: " << error.what() << endl; testsPassed = false; } catch (XmlRpcFault const& fault) { cout << "Unexpected XML-RPC fault when running test suites." << endl << "Fault #" << fault.getFaultCode() << ": " << fault.getFaultString() << endl; testsPassed = false; } catch (...) { cout << "Unexpected exception when running test suites." << endl; testsPassed = false; } if (testsPassed) { cout << "PASSED" << endl; retval = 0; } else { cout << "FAILED" << endl; retval = 1; } return retval; } xmlrpc-c-1.33.14/test/cpp/testclient.cpp000066400000000000000000000757051236133176700200620ustar00rootroot00000000000000/*============================================================================= testclient =============================================================================== Test the client C++ facilities of XML-RPC for C/C++. Contrary to what you might expect, we use the server facilities too because we test much of the client using a simulated server, via the "direct" client XML transport we define herein. =============================================================================*/ #include #include #include #include #include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "transport_config.h" #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/registry.hpp" #include "xmlrpc-c/client.hpp" #include "xmlrpc-c/client_simple.hpp" #include "tools.hpp" #include "testclient.hpp" using namespace xmlrpc_c; using namespace std; namespace { class sampleAddMethod : public method { public: sampleAddMethod() { this->_signature = "i:ii"; this->_help = "This method adds two integers together"; } void execute(xmlrpc_c::paramList const& paramList, value * const retvalP) { int const addend(paramList.getInt(0)); int const adder(paramList.getInt(1)); paramList.verifyEnd(2); *retvalP = value_int(addend + adder); } }; class testApacheDialectMethod : public method { public: void execute(xmlrpc_c::paramList const& paramList, value * const retvalP) { paramList.getNil(0); paramList.verifyEnd(1); *retvalP = value_i8(7ll); } }; class carriageParm_direct : public carriageParm { public: carriageParm_direct(registry * const registryP) : registryP(registryP) {} registry * registryP; }; class clientXmlTransport_direct : public clientXmlTransport { /*---------------------------------------------------------------------------- Though this fills the shoes of a client XML transport, it's really a simulation, because it doesn't transport anything anywhere. The call() method, which is supposed to transport a call to a server and then transport the response back, actually just executes the method itself. Part of a carriage parameter for a transport of this class is the handle of a method registry, so the transport knows how to execute the method. -----------------------------------------------------------------------------*/ public: void call(xmlrpc_c::carriageParm * const carriageParmP, string const& callXml, string * const responseXmlP) { carriageParm_direct * const parmP = dynamic_cast(carriageParmP); if (parmP == NULL) throw(error("Carriage parameter passed to the direct " "transport is not type carriageParm_direct")); parmP->registryP->processCall(callXml, responseXmlP); } }; class clientDirectAsyncTestSuite : public testSuite { /*---------------------------------------------------------------------------- See clientDirectTestSuite for a description of how we use a clientXmlTransport_direct object to test client functions. The object of this class tests the async client functions. With clientXmlTransport_direct, these are pretty simple because the transport doesn't even implement an asynchronous interface; it relies on the base class' emulation of start() using call(). Some day, we should add true asynchronous capability to clientXmlTransport_direct and really test things. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientDirectAsyncTestSuite"; } virtual void runtests(unsigned int const) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; client_xml clientDirect(&transportDirect); paramList paramListSampleAdd1; paramListSampleAdd1.add(value_int(5)); paramListSampleAdd1.add(value_int(7)); paramList paramListSampleAdd2; paramListSampleAdd2.add(value_int(30)); paramListSampleAdd2.add(value_int(-10)); rpcPtr const rpcSampleAdd1P("sample.add", paramListSampleAdd1); rpcSampleAdd1P->start(&clientDirect, &carriageParmDirect); rpcPtr const rpcSampleAdd2P("sample.add", paramListSampleAdd2); rpcSampleAdd2P->start(&clientDirect, &carriageParmDirect); // Note that for clientXmlTransport_direct, start() and call() are // the same thing. I.e. the RPC is guaranteed finished as soon // as it is started. clientDirect.finishAsync(timeout()); clientDirect.finishAsync(timeout(50)); TEST(rpcSampleAdd1P->isFinished()); TEST(rpcSampleAdd1P->isSuccessful()); value_int const result1(rpcSampleAdd1P->getResult()); TEST(static_cast(result1) == 12); TEST(rpcSampleAdd2P->isFinished()); TEST(rpcSampleAdd1P->isSuccessful()); value_int const result2(rpcSampleAdd2P->getResult()); TEST(static_cast(result2) == 20); } }; class MyRpc : public rpc { public: MyRpc(std::string const methodName, paramList const& paramList) : rpc(methodName, paramList) {} void progress(struct xmlrpc_progress_data const& data) const { // The way the tests are currently written, this never actually // runs; we're just testing for ability to compile. cout << "Progress of " << this << ": " << data.call.total << " " << data.call.now << " " << data.response.total << " " << data.response.now << endl; } }; class clientDerivedRpcTestSuite : public testSuite { /*---------------------------------------------------------------------------- The object of this class tests the ability to derive a class from xmlrpc_c::rpc in order to override certain methods. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientDerivedRpcTestSuite"; } virtual void runtests(unsigned int const ) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; client_xml clientDirect(&transportDirect); paramList paramListSampleAdd; paramListSampleAdd.add(value_int(5)); paramListSampleAdd.add(value_int(7)); { /* Test a successful RPC */ rpcPtr rpcSampleAddP(new MyRpc("sample.add", paramListSampleAdd)); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); } } }; class clientDirectTestSuite : public testSuite { /*---------------------------------------------------------------------------- The object of this class tests the client facilities by using a special client XML transport defined above and an XML-RPC server we build ourselves and run inline. We build the server out of a xmlrpc_c::registry object and our transport just delivers XML directly to the registry object and gets the response XML from it and delivers that back. There's no network or socket or pipeline or anything -- the transport actually executes the XML-RPC method. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientDirectTestSuite"; } virtual void runtests(unsigned int const indentation) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; client_xml clientDirect(&transportDirect); paramList paramListSampleAdd; paramListSampleAdd.add(value_int(5)); paramListSampleAdd.add(value_int(7)); paramList paramListEmpty; { /* Test a successful RPC */ rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); } { /* Test a failed RPC */ rpcPtr const rpcSampleAddP("sample.add", paramListEmpty); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(!rpcSampleAddP->isSuccessful()); fault const fault0(rpcSampleAddP->getFault()); TEST(fault0.getCode() == fault::CODE_TYPE); } { /* Test with an auto object transport */ client_xml clientDirect( clientXmlTransportPtr(new clientXmlTransport_direct)); rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); EXPECT_ERROR(fault fault0(rpcSampleAddP->getFault());); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); } { /* Test with implicit RPC -- success */ rpcOutcome outcome; clientDirect.call(&carriageParmDirect, "sample.add", paramListSampleAdd, &outcome); TEST(outcome.succeeded()); value_int const result(outcome.getResult()); TEST(static_cast(result) == 12); } { /* Test with implicit RPC - failure */ rpcOutcome outcome; clientDirect.call(&carriageParmDirect, "nosuchmethod", paramList(), &outcome); TEST(!outcome.succeeded()); TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); TEST(outcome.getFault().getDescription().size() > 0); } int interruptFlag(0); EXPECT_ERROR(transportDirect.setInterrupt(&interruptFlag);); // This transport class isn't interruptible EXPECT_ERROR(clientDirect.setInterrupt(&interruptFlag);); // Same as above clientDirectAsyncTestSuite().run(indentation+1); clientDerivedRpcTestSuite().run(indentation+1); } }; class curlTransportTestSuite : public testSuite { public: virtual string suiteName() { return "curlTransportTestSuite"; } virtual void runtests(unsigned int const) { #if MUST_BUILD_CURL_CLIENT clientXmlTransport_curl transport0; clientXmlTransport_curl transport1("eth0"); clientXmlTransport_curl transport2("eth0", true); clientXmlTransport_curl transport3("eth0", true, true); clientXmlTransport_curl transport4( clientXmlTransport_curl::constrOpt() .network_interface("eth0") .dont_advertise(true) .user_agent("my user agent") .referer("my referer") .no_ssl_verifypeer(true) .no_ssl_verifyhost(true) .ssl_cert("/etc/sslcert") .sslcerttype("PEM") .sslcertpasswd("mypass") .sslkey("/etc/sslkey") .sslkeytype("DER") .sslkeypasswd("mykeypass") .sslengine("mysslengine") .sslengine_default(true) .sslversion(XMLRPC_SSLVERSION_SSLv2) .cainfo("/etc/cainfo") .capath("/etc/cadir") .randomfile("/dev/random") .egdsocket("/tmp/egdsocket") .ssl_cipher_list("RC4-SHA:DEFAULT") .proxy("example.com") .proxy_port(8080) .proxy_userpwd("password") .proxy_type(XMLRPC_HTTPPROXY_SOCKS5) .proxy_auth(XMLRPC_HTTPAUTH_BASIC) .proxy_userpwd("mypassword") .gssapi_delegation(true) ); clientXmlTransport_curl transport5( clientXmlTransport_curl::constrOpt() .no_ssl_verifypeer(false)); clientXmlTransport_curl transport6( clientXmlTransport_curl::constrOpt()); clientXmlTransportPtr transport1P(new clientXmlTransport_curl); clientXmlTransportPtr transport2P; transport2P = transport1P; time_t nowtime = time(NULL); transport2P->finishAsync(timeout()); transport2P->finishAsync(timeout(2000)); transport2P->finishAsync(2000); TEST(time(NULL) <= nowtime + 1); int interruptFlag; transport2P->setInterrupt(&interruptFlag); interruptFlag = 0; transport2P->finishAsync(2000); transport2P->finishAsync(timeout()); #else EXPECT_ERROR(clientXmlTransport_curl transport0;); EXPECT_ERROR(clientXmlTransport_curl transport1("eth0");); EXPECT_ERROR(clientXmlTransport_curl transport0("eth0", true);); EXPECT_ERROR(clientXmlTransport_curl transport0("eth0", true, true);); #endif } }; class libwwwTransportTestSuite : public testSuite { public: virtual string suiteName() { return "libwwwTransportTestSuite"; } virtual void runtests(unsigned int const) { #if MUST_BUILD_LIBWWW_CLIENT clientXmlTransport_libwww transport0; clientXmlTransport_libwww transport1("getbent"); clientXmlTransport_libwww transport2("getbent", "1.0"); clientXmlTransportPtr transport1P(new clientXmlTransport_libwww); clientXmlTransportPtr transport2P; transport2P = transport1P; #else EXPECT_ERROR(clientXmlTransport_libwww transport0;); EXPECT_ERROR(clientXmlTransport_libwww transport1("getbent");); EXPECT_ERROR(clientXmlTransport_libwww transport2("getbent", "1.0");); #endif } }; class wininetTransportTestSuite : public testSuite { public: virtual string suiteName() { return "wininetTransportTestSuite"; } virtual void runtests(unsigned int const) { #if MUST_BUILD_WININET_CLIENT clientXmlTransport_wininet transport0; clientXmlTransport_wininet transport1(true); clientXmlTransportPtr transport1P(new clientXmlTransport_wininet); clientXmlTransportPtr transport2P; transport2P = transport1P; #else EXPECT_ERROR(clientXmlTransport_wininet transport0;); EXPECT_ERROR(clientXmlTransport_wininet transport1(true);); #endif } }; class ambivalentHttpTransportTestSuite : public testSuite { public: virtual string suiteName() { return "ambivalentHttpTransportTestSuite"; } virtual void runtests(unsigned int const) { vector const typeList( clientXmlTransport_http::availableTypes()); TEST(typeList.size() > 0); clientXmlTransportPtr const transportP( clientXmlTransport_http::create()); carriageParm_http0 carriageParm0("http://whatsamatta.edux"); client_xml client0(transportP); rpcOutcome outcome; // Fails because there's no such server EXPECT_ERROR( client0.call(&carriageParm0, "nosuchmethod", paramList(), &outcome); ); } }; class pstreamTransportTestSuite : public testSuite { public: virtual string suiteName() { return "pstreamTransportTestSuite"; } virtual void runtests(unsigned int const) { int const devNullFd(open("/dev/null", 0)); if (devNullFd < 0) throw error("Failed to open /dev/null, needed for test."); EXPECT_ERROR(clientXmlTransport_pstream transport1( clientXmlTransport_pstream::constrOpt() .fd(37) );); // ERROR: no such file descriptor carriageParm_pstream carriageParm0; { clientXmlTransport_pstream transport2( clientXmlTransport_pstream::constrOpt() .fd(devNullFd) ); string callXml("hello"); string responseXml; EXPECT_ERROR(transport2.call(NULL, callXml, &responseXml);); // Error: carriage parm not of type carriageParm_pstream EXPECT_ERROR(transport2.call(&carriageParm0, callXml, &responseXml);); // Error: no response } clientXmlTransportPtr transport1P(new clientXmlTransport_pstream( clientXmlTransport_pstream::constrOpt() .fd(devNullFd) )); clientXmlTransportPtr transport2P; transport2P = transport1P; close(devNullFd); } }; class clientXmlTransportTestSuite : public testSuite { public: virtual string suiteName() { return "clientXmlTransportTestSuite"; } virtual void runtests(unsigned int const indentation) { curlTransportTestSuite().run(indentation + 1); libwwwTransportTestSuite().run(indentation + 1); wininetTransportTestSuite().run(indentation + 1); ambivalentHttpTransportTestSuite().run(indentation + 1); pstreamTransportTestSuite().run(indentation + 1); } }; class clientSimpleTestSuite : public testSuite { public: virtual string suiteName() { return "clientSimpleTestSuite"; } virtual void runtests(unsigned int const) { clientSimple clientS0; paramList paramList0; value result0; // These will fail because there's no such server EXPECT_ERROR(clientS0.call("http://mf.comm", "biteme", &result0);); EXPECT_ERROR( clientS0.call("http://mf.comm", "biteme", "s", &result0, "hard"); ); EXPECT_ERROR( clientS0.call("http://mf.comm", "biteme", paramList0, &result0); ); } }; class clientCurlIntTestSuite : public testSuite { /*---------------------------------------------------------------------------- The object of this class tests interruptibility functions of the combination of a client with Curl transport. We don't have an HTTP server, so we test only superficially. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientCurlIntTestSuite"; } virtual void runtests(unsigned int) { #if MUST_BUILD_CURL_CLIENT clientXmlTransport_curl transportc0; client_xml client0(&transportc0); carriageParm_curl0 carriageParmCurl("http://suckthis.com"); paramList paramList0; rpcOutcome outcome0; int interruptFlag; client0.setInterrupt(&interruptFlag); interruptFlag = 1; // This fails because the call gets immediately interrupted EXPECT_ERROR( client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0); ); interruptFlag = 0; // This fails because server doesn't exist EXPECT_ERROR( client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0); ); #endif } }; class clientCurlTestSuite : public testSuite { /*---------------------------------------------------------------------------- The object of this class tests the combination of a client with Curl transport. We assume Curl transports themselves have already been tested and clients with direct transports have already been tested. We don't have an HTTP server, so we test only superficially. In the future, we could either start a server or use some server that's normally avaailble on the Internet. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "clientCurlTestSuite"; } virtual void runtests(unsigned int const indentation) { #if MUST_BUILD_CURL_CLIENT clientXmlTransport_curl transportc0; client_xml client0(&transportc0); carriageParm_http0 carriageParmHttp("http://suckthis.com"); carriageParm_curl0 carriageParmCurl("http://suckthis.com"); connection connection0(&client0, &carriageParmHttp); paramList paramList0; rpcOutcome outcome0; // This fails because server doesn't exist EXPECT_ERROR( client0.call(&carriageParmHttp, "blowme", paramList0, &outcome0); ); // This fails because server doesn't exist EXPECT_ERROR( client0.call(&carriageParmCurl, "blowme", paramList0, &outcome0); ); rpcPtr rpc0P("blowme", paramList0); // This fails because server doesn't exist EXPECT_ERROR(rpc0P->call(&client0, &carriageParmCurl);); rpcPtr rpc1P("blowme", paramList0); // This fails because server doesn't exist EXPECT_ERROR(rpc1P->call(connection0);); rpcPtr rpc2P("blowme", paramList0); // This RPC fails to execute because the server doesn't exist, // But libcurl "starts" it just fine. rpc2P->start(&client0, &carriageParmCurl); transportc0.finishAsync(5000); TEST(rpc2P->isFinished()); TEST(!rpc2P->isSuccessful()); // Because the RPC did not return an XML-RPC failure (because the // server doesn't exist), this throws: EXPECT_ERROR(rpc2P->getFault();); rpcPtr rpc3P("blowme", paramList0); // This RPC fails to execute because the server doesn't exist rpc3P->start(connection0); transportc0.finishAsync(5000); TEST(rpc2P->isFinished()); TEST(!rpc2P->isSuccessful()); clientCurlIntTestSuite().run(indentation+1); #else // This fails because there is no Curl transport in the library. EXPECT_ERROR(clientXmlTransport_curl transportc0;); #endif } }; class carriageParmTestSuite : public testSuite { public: virtual string suiteName() { return "carriageParmTestSuite"; } virtual void runtests(unsigned int) { carriageParm_http0 carriageParm1("http://suckthis.com"); carriageParm_curl0 carriageParm2("http://suckthis.com"); carriageParm_libwww0 carriageParm3("http://suckthis.com"); carriageParm_wininet0 carriageParm4("http://suckthis.com"); carriageParm_http0Ptr carriageParm_http1P( new carriageParm_http0("http://suckthis.com")); carriageParm_http1P->setBasicAuth("bryanh", "12345"); carriageParm_curl0Ptr carriageParm_curl1P( new carriageParm_curl0("http://suckthis.com")); carriageParm_curl1P->setBasicAuth("bryanh", "12345"); carriageParm_curl1P->setUser("bryanh", "12345"); carriageParm_curl1P->allowAuthBasic(); carriageParm_curl1P->disallowAuthBasic(); carriageParm_curl1P->allowAuthDigest(); carriageParm_curl1P->disallowAuthDigest(); carriageParm_curl1P->allowAuthNegotiate(); carriageParm_curl1P->disallowAuthNegotiate(); carriageParm_curl1P->allowAuthNtlm(); carriageParm_curl1P->disallowAuthNtlm(); carriageParm_libwww0Ptr carriageParm_libwww1P( new carriageParm_libwww0("http://suckthis.com")); carriageParm_libwww1P->setUser("bryanh", "12345"); carriageParm_libwww1P->allowAuthBasic(); carriageParm_wininet0Ptr carriageParm_wininet1P( new carriageParm_wininet0("http://suckthis.com")); carriageParm_wininet1P->setUser("bryanh", "12345"); carriageParm_wininet1P->allowAuthBasic(); } }; class clientRpcTestSuite : public testSuite { public: virtual string suiteName() { return "clientRpcTestSuite"; } virtual void runtests(unsigned int) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParm0(&myRegistry); clientXmlTransport_direct transportDirect; client_xml client0(&transportDirect); paramList paramListSampleAdd; paramListSampleAdd.add(value_int(5)); paramListSampleAdd.add(value_int(7)); paramList paramListEmpty; { /* Test a successful RPC */ rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); TEST(!rpcSampleAddP->isFinished()); // This fails because RPC has not been executed EXPECT_ERROR(value result(rpcSampleAddP->getResult());); rpcSampleAddP->call(&client0, &carriageParm0); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); // This fails because the RPC succeeded EXPECT_ERROR(fault fault0(rpcSampleAddP->getFault());); // This fails because the RPC has already been executed EXPECT_ERROR( rpcSampleAddP->call(&client0, &carriageParm0);); // This fails because the RPC has already been executed EXPECT_ERROR( rpcSampleAddP->start(&client0, &carriageParm0);); } { /* Test a failed RPC */ rpcPtr const rpcSampleAddP("sample.add", paramListEmpty); rpcSampleAddP->call(&client0, &carriageParm0); TEST(rpcSampleAddP->isFinished()); TEST(!rpcSampleAddP->isSuccessful()); fault const fault0(rpcSampleAddP->getFault()); TEST(fault0.getCode() == fault::CODE_TYPE); // This fails because the RPC failed EXPECT_ERROR(value result(rpcSampleAddP->getResult());); // This fails because the RPC has already been executed EXPECT_ERROR( rpcSampleAddP->call(&client0, &carriageParm0);); // This fails because the RPC has already been executed EXPECT_ERROR( rpcSampleAddP->start(&client0, &carriageParm0);); } { /* Test with a connection */ connection connection0(&client0, &carriageParm0); rpcPtr const rpcSampleAddP("sample.add", paramListSampleAdd); rpcSampleAddP->call(connection0); TEST(rpcSampleAddP->isFinished()); value_int const resultDirect(rpcSampleAddP->getResult()); TEST(static_cast(resultDirect) == 12); } } }; class clientPtrTestSuite : public testSuite { public: virtual string suiteName() { return "clientPtrTestSuite"; } virtual void runtests(unsigned int) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; clientPtr clientP(new client_xml(&transportDirect)); clientPtr client2P(clientP); { clientPtr client3P; client3P = client2P; } rpcOutcome outcome; clientP->call(&carriageParmDirect, "nosuchmethod", paramList(), &outcome); TEST(!outcome.succeeded()); TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); } }; class serverAccessorTestSuite : public testSuite { public: virtual string suiteName() { return "serverAccessorTestSuite"; } virtual void runtests(unsigned int) { clientXmlTransportPtr const transportP(new clientXmlTransport_direct); clientPtr const clientP(new client_xml(transportP)); registry myRegistry; carriageParmPtr const carriageParmP( new carriageParm_direct(&myRegistry)); serverAccessor server1(clientP, carriageParmP); rpcOutcome outcome; server1.call("nosuchmethod", paramList(), &outcome); TEST(!outcome.succeeded()); TEST(outcome.getFault().getCode() == fault::CODE_NO_SUCH_METHOD); TEST(outcome.getFault().getDescription().size() > 0); } }; class xmlTestSuite : public testSuite { /*---------------------------------------------------------------------------- This test suite tests the generation an interpretation of XML-RPC XML, by doing RPCs via an XML client and server. Each complete RPC involves generating XML and interpreting it, so this is a handy way to test. A stronger test would be to make an XML transport that actually verifies the XML. We're too lazy for that. -----------------------------------------------------------------------------*/ public: virtual string suiteName() { return "xmlTestSuite"; } virtual void runtests(unsigned int) { registry myRegistry; myRegistry.addMethod("sample.add", methodPtr(new sampleAddMethod)); myRegistry.addMethod("apache", methodPtr(new testApacheDialectMethod)); carriageParm_direct carriageParmDirect(&myRegistry); clientXmlTransport_direct transportDirect; client_xml clientDirect(&transportDirect, xmlrpc_dialect_apache); paramList paramListSampleAdd; paramListSampleAdd.add(value_int(5)); paramListSampleAdd.add(value_int(7)); { rpcPtr rpcSampleAddP("sample.add", paramListSampleAdd); rpcSampleAddP->call(&clientDirect, &carriageParmDirect); TEST(rpcSampleAddP->isFinished()); TEST(rpcSampleAddP->isSuccessful()); value_int const result(rpcSampleAddP->getResult()); TEST(static_cast(result) == 12); } paramList paramListApache; paramListApache.add(value_nil()); { rpcPtr rpcApacheP("apache", paramListApache); rpcApacheP->call(&clientDirect, &carriageParmDirect); TEST(rpcApacheP->isFinished()); TEST(rpcApacheP->isSuccessful()); value_i8 const result(rpcApacheP->getResult()); TEST(static_cast(result) == 7ll); } } }; } // unnamed namespace string clientTestSuite::suiteName() { return "clientTestSuite"; } void clientTestSuite::runtests(unsigned int const indentation) { clientDirectTestSuite().run(indentation+1); clientXmlTransportTestSuite().run(indentation+1); carriageParmTestSuite().run(indentation+1); clientCurlTestSuite().run(indentation+1); clientRpcTestSuite().run(indentation+1); clientPtrTestSuite().run(indentation+1); clientSimpleTestSuite().run(indentation+1); serverAccessorTestSuite().run(indentation+1); xmlTestSuite().run(indentation+1); } xmlrpc-c-1.33.14/test/cpp/testclient.hpp000066400000000000000000000002561236133176700200540ustar00rootroot00000000000000#include "tools.hpp" class clientTestSuite : public testSuite { public: virtual std::string suiteName(); virtual void runtests(unsigned int const indentation); }; xmlrpc-c-1.33.14/test/cpp/testclient_dummy.cpp000066400000000000000000000014071236133176700212610ustar00rootroot00000000000000/*============================================================================= testclient_dummy =============================================================================== This is a substitute for testclient.cpp, for use in a test program that is not linked with the client libraries. It simply passes the test. =============================================================================*/ #include #include #include "tools.hpp" #include "testclient.hpp" using namespace std; string clientTestSuite::suiteName() { return "clientTestSuite"; } void clientTestSuite::runtests(unsigned int const indentation) { cout << string((indentation+1)*2, ' ') << "Running dummy test." << endl; } xmlrpc-c-1.33.14/test/cpp/tools.cpp000066400000000000000000000035161236133176700170330ustar00rootroot00000000000000#include #include #include #ifdef _WIN32 # include # include #else # include #endif #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "tools.hpp" using namespace std; testSuite::~testSuite() { } void testSuite::run(unsigned int const indentation) { try { cout << string(indentation*2, ' ') << "Running " << suiteName() << endl; this->runtests(indentation); } catch (error const& error) { throwf("%s failed. %s", suiteName().c_str(), error.what()); } catch (...) { throw(error(suiteName() + string(" failed. ") + string("It threw an unexpected type of object"))); } cout << string(indentation*2, ' ') << suiteName() << " tests passed." << endl; } // This is a good place to set a breakpoint. void logFailedTest(const char * const fileName, unsigned int const lineNum, const char * const statement) { ostringstream msg; msg << endl << fileName << ":" << lineNum << ": expected (" << statement << ")" << endl; throw(error(msg.str())); } error fileLineError(string const filename, unsigned int const lineNumber, string const description) { ostringstream combined; combined << filename << ":" << lineNumber << " " << description; return error(combined.str()); } struct in_addr test_ipAddrFromDecimal(unsigned int const byte0, unsigned int const byte1, unsigned int const byte2, unsigned int const byte3) { struct in_addr retval; retval.s_addr = htonl((byte0 << 24) + (byte1 << 16) + (byte2 << 8) + (byte3 << 0)); return retval; } xmlrpc-c-1.33.14/test/cpp/tools.hpp000066400000000000000000000044441236133176700170410ustar00rootroot00000000000000#ifndef TEST_HPP_INCLUDED #define TEST_HPP_INCLUDED #ifdef _WIN32 # include /* For XMLRPC_SOCKET (= SOCKET) */ # include #else #include #endif #include #include "xmlrpc-c/girerr.hpp" using girerr::error; class testSuite { /*---------------------------------------------------------------------------- This is a base class for a test suite. Give the suite a name (to be used in messages about it) and some test code via virtual methods suiteName() and runtests(), respectively. runtests() should throw either an 'error' object or an 'XmlRpcFault' object if the test fails. It should throw something else if the test can't run. It should throw nothing if the tests pass. You don't normally keep an object of this class around. You don't even give it a name. You simply refer to a literal object, like so: myTestSuite().run(0) -----------------------------------------------------------------------------*/ public: virtual ~testSuite(); void run(unsigned int const indentation); virtual void runtests(unsigned int const) { throw(error("test suite does not have a runtests() method")); }; virtual std::string suiteName() { return "unnamed test suite"; } }; void logFailedTest(const char * const fileName, unsigned int const lineNum, const char * const statement); error fileLineError(std::string const filename, unsigned int const lineNumber, std::string const description); struct in_addr test_ipAddrFromDecimal(unsigned int const byte0, unsigned int const byte1, unsigned int const byte2, unsigned int const byte3); #define TEST(statement) \ do { \ if (!(statement)) \ logFailedTest(__FILE__, __LINE__, #statement); \ } while (0) #define TEST_PASSED() \ do { } while (0) #define TEST_FAILED(reason) \ do { \ logFailedTest(__FILE__, __LINE__, (reason)); \ } while (0) #define EXPECT_ERROR(statement) \ do { try { statement } catch (error const&) {break;} \ throw(fileLineError(__FILE__, __LINE__, "Expected error; didn't get one")); \ } while (0) #define trickToStraightenOutEmacsIndentation \ ; #endif xmlrpc-c-1.33.14/test/cpp/value.cpp000066400000000000000000000345041236133176700170100ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "xmlrpc-c/girerr.hpp" using girerr::error; #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/oldcppwrapper.hpp" #include "xmlrpc-c/registry.hpp" #include "c_util.h" #include "tools.hpp" #include "value.hpp" using namespace xmlrpc_c; using namespace std; namespace { class intTestSuite : public testSuite { public: virtual string suiteName() { return "intTestSuite"; } virtual void runtests(unsigned int const) { value_int int1(7); TEST(static_cast(int1) == 7); value_int int2(-7); TEST(static_cast(int2) == -7); value val1(int1); TEST(val1.type() == value::TYPE_INT); value_int int3(val1); TEST(static_cast(int3) == 7); try { value_int int4(value_double(3.7)); TEST_FAILED("invalid cast double-int suceeded"); } catch (error const&) {} value const int1x(toValue(7)); TEST(int1x.type() == value::TYPE_INT); TEST(static_cast(value_int(int1x)) == 7); int test1x; fromValue(test1x, int1x); TEST(test1x == 7); } }; class doubleTestSuite : public testSuite { public: virtual string suiteName() { return "doubleTestSuite"; } virtual void runtests(unsigned int const) { value_double double1(3.14); TEST(static_cast(double1) == 3.14); value val1(double1); TEST(val1.type() == value::TYPE_DOUBLE); value_double double2(val1); TEST(static_cast(double2) == 3.14); try { value_double double4(value_int(4)); TEST_FAILED("invalid cast int-double suceeded"); } catch (error const&) {} value const double1x(toValue(3.14)); TEST(double1x.type() == value::TYPE_DOUBLE); TEST(static_cast(value_double(double1x)) == 3.14); double test1x; fromValue(test1x, double1x); TEST(test1x == 3.14); } }; class booleanTestSuite : public testSuite { public: virtual string suiteName() { return "booleanTestSuite"; } virtual void runtests(unsigned int const) { value_boolean boolean1(true); TEST(static_cast(boolean1) == true); value_boolean boolean2(false); TEST(static_cast(boolean2) == false); value val1(boolean1); TEST(val1.type() == value::TYPE_BOOLEAN); value_boolean boolean3(val1); TEST(static_cast(boolean3) == true); try { value_boolean boolean4(value_int(4)); TEST_FAILED("invalid cast int-boolean suceeded"); } catch (error const&) {} value const boolean1x(toValue(true)); TEST(boolean1x.type() == value::TYPE_BOOLEAN); TEST(static_cast(value_boolean(boolean1x)) == true); bool test1x; fromValue(test1x, boolean1x); TEST(test1x == true); } }; #if XMLRPC_HAVE_TIMEVAL static struct timeval makeTv(time_t const secs, unsigned int const usecs) { struct timeval retval; retval.tv_sec = secs; retval.tv_usec = usecs; return retval; } static bool tvIsEqual(struct timeval const comparand, struct timeval const comparator) { return comparand.tv_sec == comparator.tv_sec && comparand.tv_usec == comparator.tv_usec; } #endif #if XMLRPC_HAVE_TIMESPEC static struct timespec makeTs(time_t const secs, unsigned int const usecs) { struct timespec retval; retval.tv_sec = secs; retval.tv_nsec = usecs * 1000; return retval; } static bool tsIsEqual(struct timespec const comparand, struct timespec const comparator) { return comparand.tv_sec == comparator.tv_sec && comparand.tv_nsec == comparator.tv_nsec; } #endif static xmlrpc_datetime const makeXd(time_t const secs, unsigned int const usecs) { struct tm const tm = *gmtime(&secs); xmlrpc_datetime retval; retval.Y = 1900 + tm.tm_year; retval.M = 1 + tm.tm_mon; retval.D = tm.tm_mday; retval.h = tm.tm_hour; retval.m = tm.tm_min; retval.s = tm.tm_sec; retval.u = usecs; return retval; } static bool xdIsEqual(xmlrpc_datetime const comparand, xmlrpc_datetime const comparator) { return comparand.Y == comparator.Y && comparand.M == comparator.M && comparand.D == comparator.D && comparand.h == comparator.h && comparand.m == comparator.m && comparand.s == comparator.s && comparand.u == comparator.u; } class datetimeTestSuite : public testSuite { public: virtual string suiteName() { return "datetimeTestSuite"; } virtual void runtests(unsigned int const) { time_t const testTime(900684535); string const testTime8601("19980717T140855,000000Z"); value_datetime datetime1("19980717T14:08:55"); TEST(static_cast(datetime1) == testTime); value_datetime datetime2(testTime); TEST(static_cast(datetime2) == testTime); value val1(datetime1); TEST(val1.type() == value::TYPE_DATETIME); value_datetime datetime3(val1); TEST(static_cast(datetime3) == testTime); #if XMLRPC_HAVE_TIMEVAL struct timeval const testTimeTv(makeTv(testTime, 0)); value_datetime datetime4(testTimeTv); TEST(static_cast(datetime4) == testTime); TEST(tvIsEqual(static_cast(datetime4), testTimeTv)); #endif #if XMLRPC_HAVE_TIMESPEC struct timespec const testTimeTs(makeTs(testTime, 0)); value_datetime datetime5(testTimeTs); TEST(static_cast(datetime5) == testTime); TEST(tsIsEqual(static_cast(datetime5), testTimeTs)); #endif xmlrpc_datetime const testTimeXd(makeXd(testTime, 5)); value_datetime datetime6(testTimeXd); TEST(static_cast(datetime6) == testTime); TEST(xdIsEqual(static_cast(datetime6), testTimeXd)); string const iso8601Value(datetime1.iso8601Value()); TEST(iso8601Value == testTime8601); try { value_datetime datetime4(value_int(4)); TEST_FAILED("invalid cast int-datetime suceeded"); } catch (error const&) {} } }; class stringTestSuite : public testSuite { public: virtual string suiteName() { return "stringTestSuite"; } virtual void runtests(unsigned int const) { value_string string1("hello world"); TEST(static_cast(string1) == "hello world"); value_string string2("embedded\0null"); TEST(static_cast(string2) == "embedded\0null"); value val1(string1); TEST(val1.type() == value::TYPE_STRING); value_string string3(val1); TEST(static_cast(string3) == "hello world"); try { value_string string4(value_int(4)); TEST_FAILED("invalid cast int-string succeeded"); } catch (error const&) {} value_string string5("hello world", value_string::nlCode_all); TEST(static_cast(string5) == "hello world"); value_string string6("hello\nthere\rworld\r\n\n", value_string::nlCode_all); TEST(static_cast(string6) == "hello\nthere\nworld\n\n"); TEST(string6.crlfValue() == "hello\r\nthere\r\nworld\r\n\r\n"); value_string string7("hello\nthere\rworld\r\n\n", value_string::nlCode_lf); TEST(static_cast(string7) == "hello\nthere\rworld\r\n\n"); value const string1x(toValue("hello world")); TEST(string1x.type() == value::TYPE_STRING); TEST(static_cast(value_string(string1x)) == "hello world"); string test1x; fromValue(test1x, string1x); TEST(test1x == "hello world"); value const string2x(toValue(string("hello world"))); TEST(string2x.type() == value::TYPE_STRING); TEST(static_cast(value_string(string2x)) == "hello world"); } }; class bytestringTestSuite : public testSuite { public: virtual string suiteName() { return "bytestringTestSuite"; } virtual void runtests(unsigned int const) { unsigned char bytestringArray[] = {0x10, 0x11, 0x12, 0x13, 0x14}; cbytestring bytestringData(&bytestringArray[0], &bytestringArray[4]); value_bytestring bytestring1(bytestringData); cbytestring const dataReadBack1(bytestring1.vectorUcharValue()); TEST(dataReadBack1 == bytestringData); value val1(bytestring1); TEST(val1.type() == value::TYPE_BYTESTRING); value_bytestring bytestring2(val1); vector const dataReadBack2( bytestring2.vectorUcharValue()); TEST(dataReadBack2 == bytestringData); try { value_bytestring bytestring4(value_int(4)); TEST_FAILED("invalid cast int-bytestring suceeded"); } catch (error const&) {} value const bytestring1x(toValue(bytestringData)); TEST(bytestring1x.type() == value::TYPE_BYTESTRING); vector const dataReadBack1x( value_bytestring(bytestring1x).vectorUcharValue()); TEST(dataReadBack1x == bytestringData); vector test1x; fromValue(test1x, bytestring1x); TEST(test1x == bytestringData); } }; class nilTestSuite : public testSuite { public: virtual string suiteName() { return "nilTestSuite"; } virtual void runtests(unsigned int const) { value_nil nil1; value val1(nil1); TEST(val1.type() == value::TYPE_NIL); value_nil nil2(val1); try { value_nil nil4(value_int(4)); TEST_FAILED("invalid cast int-nil suceeded"); } catch (error const&) {} } }; class i8TestSuite : public testSuite { public: virtual string suiteName() { return "i8TestSuite"; } virtual void runtests(unsigned int const) { value_i8 int1(7); TEST(static_cast(int1) == 7); value_i8 int2(-7); TEST(static_cast(int2) == -7); value_i8 int5(1ull << 40); TEST(static_cast(int5) == (1ull << 40)); value val1(int1); TEST(val1.type() == value::TYPE_I8); value_i8 int3(val1); TEST(static_cast(int3) == 7); try { value_i8 int4(value_double(3.7)); TEST_FAILED("invalid cast double-i8 suceeded"); } catch (error const&) {} } }; class structTestSuite : public testSuite { public: virtual string suiteName() { return "structTestSuite"; } virtual void runtests(unsigned int const) { cstruct structData; pair member("the_integer", value_int(9)); structData.insert(member); value_struct struct1(structData); map dataReadBack(struct1); TEST(static_cast(value_int(dataReadBack["the_integer"])) == 9); value val1(struct1); TEST(val1.type() == value::TYPE_STRUCT); value_struct struct2(val1); try { value_struct struct4(value_int(4)); TEST_FAILED("invalid cast int-struct suceeded"); } catch (error const&) {} map structDatax; structDatax["one"] = 1; structDatax["two"] = 2; value const struct5(toValue(structDatax)); TEST(struct5.type() == value::TYPE_STRUCT); map dataReadBackx; dataReadBackx = value_struct(struct5); TEST(static_cast(value_int(dataReadBackx["two"])) == 2); map test5x; fromValue(test5x, struct5); TEST(test5x["two"] == 2); } }; class arrayTestSuite : public testSuite { public: virtual string suiteName() { return "arrayTestSuite"; } virtual void runtests(unsigned int const) { carray arrayData; arrayData.push_back(value_int(7)); arrayData.push_back(value_double(2.78)); arrayData.push_back(value_string("hello world")); value_array array1(arrayData); TEST(array1.size() == 3); vector dataReadBack1(array1.vectorValueValue()); TEST(dataReadBack1[0].type() == value::TYPE_INT); TEST(static_cast(value_int(dataReadBack1[0])) == 7); TEST(dataReadBack1[1].type() == value::TYPE_DOUBLE); TEST(static_cast(value_double(dataReadBack1[1])) == 2.78); TEST(dataReadBack1[2].type() == value::TYPE_STRING); TEST(static_cast(value_string(dataReadBack1[2])) == "hello world"); value val1(array1); TEST(val1.type() == value::TYPE_ARRAY); value_array array2(val1); TEST(array2.size() == 3); try { value_array array4(value_int(4)); TEST_FAILED("invalid cast int-array suceeded"); } catch (error const&) {} int const arrayDatax[] = {7, 4}; value const array5( arrayValueArray(arrayDatax, ARRAY_SIZE(arrayDatax))); TEST(array5.type() == value::TYPE_ARRAY); TEST(value_array(array5).size() == 2); vector dataReadBackx(value_array(array5).vectorValueValue()); TEST(dataReadBackx.size() == 2); TEST(static_cast(value_int(dataReadBackx[0])) == 7); vector test5x; fromValue(test5x, array5); TEST(test5x[1] == 4); vector arrayDataVec; arrayDataVec.push_back("hello world"); value const array6(toValue(arrayDataVec)); TEST(array6.type() == value::TYPE_ARRAY); TEST(value_array(array6).size() == 1); } }; } // unnamed namespace string valueTestSuite::suiteName() { return "valueTestSuite"; } void valueTestSuite::runtests(unsigned int const indentation) { intTestSuite().run(indentation+1); doubleTestSuite().run(indentation+1); booleanTestSuite().run(indentation+1); datetimeTestSuite().run(indentation+1); stringTestSuite().run(indentation+1); bytestringTestSuite().run(indentation+1); nilTestSuite().run(indentation+1); i8TestSuite().run(indentation+1); structTestSuite().run(indentation+1); arrayTestSuite().run(indentation+1); } xmlrpc-c-1.33.14/test/cpp/value.hpp000066400000000000000000000002551236133176700170110ustar00rootroot00000000000000#include "tools.hpp" class valueTestSuite : public testSuite { public: virtual std::string suiteName(); virtual void runtests(unsigned int const indentation); }; xmlrpc-c-1.33.14/test/cpp/xml.cpp000066400000000000000000000040361236133176700164710ustar00rootroot00000000000000/*============================================================================= xml =============================================================================== Test the XML generator and parser C++ facilities of XML-RPC for C/C++. =============================================================================*/ #include #include "xmlrpc-c/girerr.hpp" using girerr::error; using girerr::throwf; #include "xmlrpc-c/base.hpp" #include "xmlrpc-c/xml.hpp" #include "tools.hpp" #include "xml.hpp" using namespace xmlrpc_c; using namespace std; namespace { class callTestSuite : public testSuite { public: virtual string suiteName() { return "callTestSuite"; } virtual void runtests(unsigned int const) { string callXml; string const methodName0("myMethod"); paramList const paramList0; xml::generateCall(methodName0, paramList(), &callXml); string methodName; paramList paramList; xml::parseCall(callXml, &methodName, ¶mList); TEST(methodName == methodName0); TEST(paramList.size() == paramList0.size()); } }; class responseTestSuite : public testSuite { public: virtual string suiteName() { return "responseTestSuite"; } virtual void runtests(unsigned int const) { string respXml; rpcOutcome outcome0(value_int(7)); xml::generateResponse(outcome0, &respXml); rpcOutcome outcome; xml::parseResponse(respXml, &outcome); TEST((int)value_int(outcome.getResult()) == (int)value_int(outcome0.getResult())); value result; xml::parseSuccessfulResponse(respXml, &result); TEST((int)value_int(result) == (int)value_int(outcome0.getResult())); } }; } // unnamed namespace string xmlTestSuite::suiteName() { return "XMLTestSuite"; } void xmlTestSuite::runtests(unsigned int const indentation) { callTestSuite().run(indentation+1); responseTestSuite().run(indentation+1); } xmlrpc-c-1.33.14/test/cpp/xml.hpp000066400000000000000000000002531236133176700164730ustar00rootroot00000000000000#include "tools.hpp" class xmlTestSuite : public testSuite { public: virtual std::string suiteName(); virtual void runtests(unsigned int const indentation); }; xmlrpc-c-1.33.14/test/data/000077500000000000000000000000001236133176700153115ustar00rootroot00000000000000xmlrpc-c-1.33.14/test/data/req_no_params.xml000066400000000000000000000004121236133176700206560ustar00rootroot00000000000000 foo xmlrpc-c-1.33.14/test/data/req_out_of_order.xml000066400000000000000000000003561236133176700213740ustar00rootroot00000000000000 2 2 add xmlrpc-c-1.33.14/test/data/req_value_name.xml000066400000000000000000000004661236133176700210240ustar00rootroot00000000000000 foo 0 child elements reversed! xmlrpc-c-1.33.14/test/data/sample_add_call.xml000066400000000000000000000003231236133176700211150ustar00rootroot00000000000000 sample.add 5 7 xmlrpc-c-1.33.14/test/eftest_wrapper.sh000066400000000000000000000006451236133176700177730ustar00rootroot00000000000000#!/bin/sh echo "*** Testing for heap block overruns..." efrpctest if ! test $?; then exit 1; fi echo "*** Testing for heap block underruns..." EF_PROTECT_BELOW=1 efrpctest if ! test $?; then exit 1; fi echo "*** Testing for access to freed heap blocks..." EF_PROTECT_FREE=1 efrpctest if ! test $?; then exit 1; fi echo "*** Testing for single-byte overruns..." EF_ALIGNMENT=0 efrpctest if ! test $?; then exit 1; fi xmlrpc-c-1.33.14/test/http-req-simple.txt000066400000000000000000000003571236133176700202010ustar00rootroot00000000000000POST /cgi-bin/sample-cgi.cgi 1.0 Host: localhost Content-Type: text/xml Content-Length: 141 system.listMethods xmlrpc-c-1.33.14/test/method_registry.c000066400000000000000000000743741236133176700177730ustar00rootroot00000000000000#include #include #include "int.h" #include "casprintf.h" #include "girstring.h" #include "xmlrpc_config.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "testtool.h" #include "xml_data.h" #include "method_registry.h" #define FOO_SERVERINFO ((void*) 0xF00) #define FOO_CALLINFO ((void*) 0xFC0) #define BAR_SERVERINFO ((void*) 0xBAF) #define BAR_CALLINFO ((void*) 0xBAC) #define MULTI_CALLINFO ((void*) 0xFFF) #define DEFAULT_SERVERINFO ((void*) 0xD00) #define DEFAULT_CALLINFO ((void*) 0xDC0) static const char * const barHelp = "This is the help for Method test.bar."; static void testVersion(void) { unsigned int major, minor, point; xmlrpc_server_version(&major, &minor, &point); #ifndef _WIN32 /* xmlrpc_server_version_major, etc. are not exported from a Windows DLL */ TEST(major == xmlrpc_server_version_major); TEST(minor == xmlrpc_server_version_minor); TEST(point == xmlrpc_server_version_point); #endif } static xmlrpc_value * test_foo(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo) { xmlrpc_int32 x, y; TEST_NO_FAULT(envP); TEST(paramArrayP != NULL); TEST(serverInfo == FOO_SERVERINFO); TEST(callInfo == FOO_CALLINFO || callInfo == MULTI_CALLINFO); xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); TEST_NO_FAULT(envP); TEST(x == 25); TEST(y == 17); return xmlrpc_build_value(envP, "i", (xmlrpc_int32) x + y); } static xmlrpc_value * test_foo_type1(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo) { xmlrpc_int32 x, y; TEST_NO_FAULT(envP); TEST(paramArrayP != NULL); TEST(serverInfo == FOO_SERVERINFO); xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); TEST_NO_FAULT(envP); TEST(x == 25); TEST(y == 17); return xmlrpc_build_value(envP, "i", (xmlrpc_int32) x + y); } static xmlrpc_value * test_bar(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, void * const serverInfo, void * const callInfo) { xmlrpc_int32 x, y; TEST_NO_FAULT(envP); TEST(paramArrayP != NULL); TEST(serverInfo == BAR_SERVERINFO); TEST(callInfo == BAR_CALLINFO || callInfo == MULTI_CALLINFO); xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); TEST_NO_FAULT(envP); TEST(x == 25); TEST(y == 17); xmlrpc_env_set_fault(envP, 123, "Test fault"); return NULL; } static xmlrpc_value * test_default(xmlrpc_env * const envP, const char * const callInfo, const char * const methodName, xmlrpc_value * const paramArrayP, void * const serverInfo) { xmlrpc_int32 x, y; TEST_NO_FAULT(envP); TEST(paramArrayP != NULL); TEST(serverInfo == DEFAULT_SERVERINFO); TEST(streq(methodName, "test.nosuch") || streq(methodName, "test.nosuch.old")); if (streq(methodName, "nosuch.method")) TEST(callInfo == DEFAULT_CALLINFO); else if (streq(methodName, "nosuch.method.old")) TEST(callInfo == NULL); xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y); TEST_NO_FAULT(envP); TEST(x == 25); TEST(y == 17); return xmlrpc_build_value(envP, "i", 2 * (x + y)); } static xmlrpc_value * test_exttype(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP ATTR_UNUSED, void * const serverInfo ATTR_UNUSED, void * const callInfo ATTR_UNUSED) { return xmlrpc_build_value(envP, "(In)", (xmlrpc_int64)8); } static void doRpc(xmlrpc_env * const envP, xmlrpc_registry * const registryP, const char * const methodName, xmlrpc_value * const argArrayP, void * const callInfo, xmlrpc_value ** const resultPP) { /*---------------------------------------------------------------------------- Do what an XML-RPC server would do -- pass an XML call to the registry and get XML back. Actually to our caller, we look more like an Xmlrpc-c client. We're both the client and the server all bound together. -----------------------------------------------------------------------------*/ xmlrpc_mem_block * callP; xmlrpc_mem_block * responseP; /* Build a call, and tell the registry to handle it. */ callP = xmlrpc_mem_block_new(envP, 0); TEST_NO_FAULT(envP); xmlrpc_serialize_call(envP, callP, methodName, argArrayP); TEST_NO_FAULT(envP); if (callInfo) xmlrpc_registry_process_call2( envP, registryP, xmlrpc_mem_block_contents(callP), xmlrpc_mem_block_size(callP), callInfo, &responseP); else responseP = xmlrpc_registry_process_call( envP, registryP, NULL, xmlrpc_mem_block_contents(callP), xmlrpc_mem_block_size(callP)); TEST_NO_FAULT(envP); TEST(responseP != NULL); /* Parse the response. */ *resultPP = xmlrpc_parse_response(envP, xmlrpc_mem_block_contents(responseP), xmlrpc_mem_block_size(responseP)); xmlrpc_mem_block_free(callP); xmlrpc_mem_block_free(responseP); } static const char * const validSigString[] = { "i:", "s:d", "n:iIbds86SA", "i:,i:", "i:dd,s:,A:A", "i:,", "b:i,", "b:i,b:,", NULL }; static const char * const invalidSigString[] = { "", "i", "q", "i:q", "i:ddq", ",", ",i:", "i,", "b:i,,b:i", "ii:", "ii:ii", NULL }; static void test_system_methodSignature(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Test system.methodSignature system method. -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * argArrayP; xmlrpc_value * resultP; const char * type0; const char * type1; const char * type2; const char * type3; const char * type4; const char * type5; const char * type6; const char * type7; const char * type8; const char * type9; const char * nosigstring; xmlrpc_env_init(&env); argArrayP = xmlrpc_build_value(&env, "(s)", "test.nosuchmethod"); doRpc(&env, registryP, "system.methodSignature", argArrayP, NULL, &resultP); TEST_FAULT(&env, XMLRPC_NO_SUCH_METHOD_ERROR); xmlrpc_DECREF(argArrayP); argArrayP = xmlrpc_build_value(&env, "(s)", "test.nosig0"); doRpc(&env, registryP, "system.methodSignature", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, resultP, &nosigstring); TEST_NO_FAULT(&env); TEST(streq(nosigstring, "undef")); strfree(nosigstring); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig0"); doRpc(&env, registryP, "system.methodSignature", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, resultP, "((s))", &type0); TEST_NO_FAULT(&env); TEST(streq(type0, "int")); strfree(type0); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig2"); doRpc(&env, registryP, "system.methodSignature", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, resultP, "((ssssssssss))", &type0, &type1, &type2, &type3, &type4, &type5, &type6, &type7, &type8, &type9); TEST_NO_FAULT(&env); TEST(streq(type0, "nil")); TEST(streq(type1, "int")); TEST(streq(type2, "i8")); TEST(streq(type3, "boolean")); TEST(streq(type4, "double")); TEST(streq(type5, "string")); TEST(streq(type6, "dateTime.iso8601")); TEST(streq(type7, "base64")); TEST(streq(type8, "struct")); TEST(streq(type9, "array")); strfree(type0); strfree(type1); strfree(type2); strfree(type3); strfree(type4); strfree(type5); strfree(type6); strfree(type7); strfree(type8); strfree(type9); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); argArrayP = xmlrpc_build_value(&env, "(s)", "test.validsig3"); doRpc(&env, registryP, "system.methodSignature", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, resultP, "((s)(s))", &type0, &type1); TEST_NO_FAULT(&env); TEST(streq(type0, "int")); TEST(streq(type1, "int")); strfree(type0); strfree(type1); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); } static void test_signature(void) { xmlrpc_env env; xmlrpc_registry * registryP; unsigned int i; xmlrpc_env_init(&env); printf(" Running signature tests."); registryP = xmlrpc_registry_new(&env); TEST_NO_FAULT(&env); xmlrpc_registry_add_method2(&env, registryP, "test.nosig0", test_foo, NULL, NULL, FOO_SERVERINFO); TEST_NO_FAULT(&env); xmlrpc_registry_add_method2(&env, registryP, "test.nosig1", test_foo, "?", NULL, FOO_SERVERINFO); TEST_NO_FAULT(&env); for (i = 0; validSigString[i]; ++i) { const char * methodName; casprintf(&methodName, "test.validsig%u", i); xmlrpc_registry_add_method2(&env, registryP, methodName, test_foo, validSigString[i], NULL, FOO_SERVERINFO); TEST_NO_FAULT(&env); strfree(methodName); } for (i = 0; invalidSigString[i]; ++i) { const char * methodName; casprintf(&methodName, "test.invalidsig%u", i); xmlrpc_registry_add_method2(&env, registryP, methodName, test_foo, invalidSigString[i], NULL, FOO_SERVERINFO); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); strfree(methodName); } xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, "test.old", test_foo_type1, FOO_SERVERINFO, NULL, NULL); TEST_NO_FAULT(&env); xmlrpc_registry_add_method_w_doc(&env, registryP, NULL, "test.old.invalid", test_foo_type1, FOO_SERVERINFO, invalidSigString[0], NULL); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); test_system_methodSignature(registryP); xmlrpc_registry_free(registryP); xmlrpc_env_clean(&env); printf("\n"); } static void test_disable_introspection(void) { xmlrpc_env env; xmlrpc_registry * registryP; xmlrpc_value * argArrayP; xmlrpc_value * resultP; xmlrpc_env_init(&env); printf(" Running disable introspection tests."); registryP = xmlrpc_registry_new(&env); TEST_NO_FAULT(&env); xmlrpc_registry_add_method2(&env, registryP, "test.nosig0", test_foo, NULL, NULL, FOO_SERVERINFO); TEST_NO_FAULT(&env); xmlrpc_registry_disable_introspection(registryP); argArrayP = xmlrpc_build_value(&env, "(s)", "test.nosig0"); doRpc(&env, registryP, "system.methodSignature", argArrayP, NULL, &resultP); TEST_FAULT(&env, XMLRPC_INTROSPECTION_DISABLED_ERROR); xmlrpc_DECREF(argArrayP); xmlrpc_registry_free(registryP); xmlrpc_env_clean(&env); printf("\n"); } static const char * const expectedMethodName[] = { /*---------------------------------------------------------------------------- The list we expect back from system.listMethods. -----------------------------------------------------------------------------*/ "system.listMethods", "system.methodExist", "system.methodHelp", "system.methodSignature", "system.multicall", "system.shutdown", "system.capabilities", "system.getCapabilities", "test.foo", "test.bar" }; static void test_system_listMethods(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Test system.listMethods -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_value * argArrayP; const char * methodName[ARRAY_SIZE(expectedMethodName)]; unsigned int size; unsigned int i; xmlrpc_env_init(&env); printf(" Running system.listMethods tests."); argArrayP = xmlrpc_array_new(&env); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.listMethods", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(resultP) == XMLRPC_TYPE_ARRAY); size = xmlrpc_array_size(&env, resultP); TEST_NO_FAULT(&env); TEST(size == ARRAY_SIZE(expectedMethodName)); xmlrpc_decompose_value(&env, resultP, "(ssssssssss)", &methodName[0], &methodName[1], &methodName[2], &methodName[3], &methodName[4], &methodName[5], &methodName[6], &methodName[7], &methodName[8], &methodName[9]); TEST_NO_FAULT(&env); for (i = 0; i < ARRAY_SIZE(expectedMethodName); ++i) { TEST(streq(methodName[i], expectedMethodName[i])); strfree(methodName[i]); } xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); printf("\n"); } static void test_system_methodExist(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Test system.methodExist -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_value * argArrayP; xmlrpc_bool exists; xmlrpc_env_init(&env); printf(" Running system.methodExist tests."); argArrayP = xmlrpc_build_value(&env, "(s)", "test.foo"); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.methodExist", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(resultP) == XMLRPC_TYPE_BOOL); xmlrpc_read_bool(&env, resultP, &exists); TEST_NO_FAULT(&env); TEST(exists); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); argArrayP = xmlrpc_build_value(&env, "(s)", "nosuchmethod"); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.methodExist", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(resultP) == XMLRPC_TYPE_BOOL); xmlrpc_read_bool(&env, resultP, &exists); TEST_NO_FAULT(&env); TEST(!exists); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); printf("\n"); } static void testNoHelp(xmlrpc_registry * const registryP) { xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_value * argArrayP; const char * helpString; xmlrpc_env_init(&env); argArrayP = xmlrpc_build_value(&env, "(s)", "test.foo"); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.methodHelp", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(resultP) == XMLRPC_TYPE_STRING); xmlrpc_read_string(&env, resultP, &helpString); TEST_NO_FAULT(&env); TEST(streq(helpString, "No help is available for this method.")); strfree(helpString); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); } static void testExistentHelp(xmlrpc_registry * const registryP) { xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_value * argArrayP; const char * helpString; xmlrpc_env_init(&env); argArrayP = xmlrpc_build_value(&env, "(s)", "test.bar"); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.methodHelp", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(resultP) == XMLRPC_TYPE_STRING); xmlrpc_read_string(&env, resultP, &helpString); TEST_NO_FAULT(&env); TEST(streq(helpString, barHelp)); strfree(helpString); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); } static void test_system_methodHelp(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Test system.methodHelp -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_env_init(&env); printf(" Running system.methodHelp tests."); testNoHelp(registryP); testExistentHelp(registryP); printf("\n"); } static void test_system_capabilities(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Test system.capabilities -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_value * argArrayP; const char * facility; xmlrpc_int version_major, version_minor, version_point; xmlrpc_int protocol_version; xmlrpc_env_init(&env); printf(" Running system.capabilities tests."); argArrayP = xmlrpc_array_new(&env); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.capabilities", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, resultP, "{s:s,s:i,s:i,s:i,s:i,*}", "facility", &facility, "version_major", &version_major, "version_minor", &version_minor, "version_point", &version_point, "protocol_version", &protocol_version); TEST_NO_FAULT(&env); TEST(streq(facility, "xmlrpc-c")); TEST(protocol_version == 2); strfree(facility); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); printf("\n"); } static void test_system_getCapabilities(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Test system.getCapabilities -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_value * argArrayP; const char * specUrl; int specVersion; xmlrpc_env_init(&env); printf(" Running system.getCapabilities tests."); argArrayP = xmlrpc_array_new(&env); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.getCapabilities", argArrayP, NULL, &resultP); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, resultP, "{s:{s:s,s:i,*},*}", "introspect", "specUrl", &specUrl, "specVersion", &specVersion); TEST_NO_FAULT(&env); TEST(streq(specUrl, "http://xmlrpc-c.sourceforge.net/xmlrpc-c/introspection.html")); TEST(specVersion == 1); strfree(specUrl); xmlrpc_DECREF(resultP); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); printf("\n"); } static void test_system_multicall(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Test system.multicall -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * multiP; xmlrpc_int32 foo1_result, foo2_result; xmlrpc_int32 bar_code, nosuch_code; char *bar_string, *nosuch_string; xmlrpc_value * valueP; xmlrpc_value * argArrayP; xmlrpc_env_init(&env); printf(" Running multicall tests."); /* Build an argument array for our calls. */ argArrayP = xmlrpc_build_value(&env, "(ii)", (xmlrpc_int32) 25, (xmlrpc_int32) 17); TEST_NO_FAULT(&env); multiP = xmlrpc_build_value(&env, "((" "{s:s,s:A}" /* test.foo */ "{s:s,s:A}" /* test.bar */ "{s:s,s:A}" /* test.nosuch */ "{s:s,s:A}" /* test.foo */ "))", "methodName", "test.foo", "params", argArrayP, "methodName", "test.bar", "params", argArrayP, "methodName", "test.nosuch", "params", argArrayP, "methodName", "test.foo", "params", argArrayP); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.multicall", multiP, MULTI_CALLINFO, &valueP); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, valueP, "(" "(i)" /* result of test.foo */ "{s:i,s:s,*}" /* result of test.bar */ "{s:i,s:s,*}" /* result of test.nosuch */ "(i)" /* result of test.foo #2 */ ")", &foo1_result, "faultCode", &bar_code, "faultString", &bar_string, "faultCode", &nosuch_code, "faultString", &nosuch_string, &foo2_result); xmlrpc_DECREF(valueP); TEST_NO_FAULT(&env); TEST(foo1_result == 42); TEST(bar_code == 123); TEST(streq(bar_string, "Test fault")); TEST(nosuch_code == XMLRPC_NO_SUCH_METHOD_ERROR); TEST(foo2_result == 42); xmlrpc_DECREF(multiP); free(bar_string); free(nosuch_string); /* Now for some invalid multi calls */ multiP = xmlrpc_build_value(&env, "(({s:s,s:V}{s:s,s:()}{s:s,s:V}))", "methodName", "test.foo", "params", argArrayP, "methodName", "system.multicall", "params", "methodName", "test.foo", "params", argArrayP); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.multicall", multiP, MULTI_CALLINFO, &valueP); TEST_FAULT(&env, XMLRPC_REQUEST_REFUSED_ERROR); xmlrpc_DECREF(multiP); multiP = xmlrpc_build_value(&env, "(({s:s,s:V}d))", "methodName", "test.foo", "params", argArrayP, 5.0); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.multicall", multiP, MULTI_CALLINFO, &valueP); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_DECREF(multiP); multiP = xmlrpc_build_value(&env, "({s:s,s:V})", "methodName", "test.foo", "params", argArrayP); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.multicall", multiP, MULTI_CALLINFO, &valueP); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_DECREF(multiP); multiP = xmlrpc_build_value(&env, "(({}))"); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.multicall", multiP, MULTI_CALLINFO, &valueP); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_DECREF(multiP); multiP = xmlrpc_build_value(&env, "(({s:s}))", "methodName", "test.foo"); TEST_NO_FAULT(&env); doRpc(&env, registryP, "system.multicall", multiP, MULTI_CALLINFO, &valueP); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_DECREF(multiP); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); printf("\n"); } static void testCall(xmlrpc_registry * const registryP) { xmlrpc_env env; xmlrpc_env env2; xmlrpc_value * argArrayP; xmlrpc_value * valueP; xmlrpc_int32 i; printf(" Running call tests."); xmlrpc_env_init(&env); /* Build an argument array for our calls. */ argArrayP = xmlrpc_build_value(&env, "(ii)", (xmlrpc_int32) 25, (xmlrpc_int32) 17); TEST_NO_FAULT(&env); /* Call test.foo and check the result. */ doRpc(&env, registryP, "test.foo", argArrayP, FOO_CALLINFO, &valueP); TEST_NO_FAULT(&env); TEST(valueP != NULL); xmlrpc_decompose_value(&env, valueP, "i", &i); xmlrpc_DECREF(valueP); TEST_NO_FAULT(&env); TEST(i == 42); /* Call test.bar and check the result. */ xmlrpc_env_init(&env2); doRpc(&env2, registryP, "test.bar", argArrayP, BAR_CALLINFO, &valueP); TEST(env2.fault_occurred); TEST(env2.fault_code == 123); TEST(env2.fault_string && streq(env2.fault_string, "Test fault")); xmlrpc_env_clean(&env2); /* Call a non-existant method and check the result. */ xmlrpc_env_init(&env2); doRpc(&env2, registryP, "test.nosuch", argArrayP, FOO_CALLINFO, &valueP); TEST(valueP == NULL); TEST_FAULT(&env2, XMLRPC_NO_SUCH_METHOD_ERROR); xmlrpc_env_clean(&env2); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); printf("\n"); } static void testDefaultMethod(xmlrpc_registry * const registryP) { xmlrpc_env env; xmlrpc_value * argArrayP; xmlrpc_value * valueP; xmlrpc_int32 i; xmlrpc_env_init(&env); printf(" Running default method tests."); /* Build an argument array for our calls. */ argArrayP = xmlrpc_build_value(&env, "(ii)", (xmlrpc_int32) 25, (xmlrpc_int32) 17); xmlrpc_registry_set_default_method(&env, registryP, &test_default, DEFAULT_SERVERINFO); TEST_NO_FAULT(&env); doRpc(&env, registryP, "test.nosuch", argArrayP, DEFAULT_CALLINFO, &valueP); TEST_NO_FAULT(&env); TEST(valueP != NULL); xmlrpc_decompose_value(&env, valueP, "i", &i); xmlrpc_DECREF(valueP); TEST_NO_FAULT(&env); TEST(i == 84); /* Now try it with old method interface */ doRpc(&env, registryP, "test.nosuch.old", argArrayP, NULL, &valueP); TEST_NO_FAULT(&env); TEST(valueP != NULL); xmlrpc_read_int(&env, valueP, &i); TEST_NO_FAULT(&env); xmlrpc_DECREF(valueP); TEST(i == 84); /* Change the default method. */ xmlrpc_registry_set_default_method(&env, registryP, &test_default, BAR_SERVERINFO); TEST_NO_FAULT(&env); xmlrpc_DECREF(argArrayP); xmlrpc_env_clean(&env); printf("\n"); } static void test_apache_dialect(void) { char const expectedResp[] = XML_PROLOGUE "\r\n" "\r\n" "\r\n" "8\r\n" "\r\n" "\r\n" "\r\n" "\r\n"; xmlrpc_env env; xmlrpc_registry * registryP; xmlrpc_value * argArrayP; xmlrpc_mem_block * callP; xmlrpc_mem_block * responseP; xmlrpc_env_init(&env); printf(" Running apache dialect tests."); registryP = xmlrpc_registry_new(&env); TEST_NO_FAULT(&env); xmlrpc_registry_set_dialect(&env, registryP, xmlrpc_dialect_i8); TEST_NO_FAULT(&env); xmlrpc_registry_set_dialect(&env, registryP, 100); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_registry_set_dialect(&env, registryP, xmlrpc_dialect_apache); TEST_NO_FAULT(&env); xmlrpc_registry_add_method2(&env, registryP, "test_exttype", test_exttype, NULL, NULL, FOO_SERVERINFO); TEST_NO_FAULT(&env); argArrayP = xmlrpc_array_new(&env); TEST_NO_FAULT(&env); callP = xmlrpc_mem_block_new(&env, 0); TEST_NO_FAULT(&env); xmlrpc_serialize_call(&env, callP, "test_exttype", argArrayP); TEST_NO_FAULT(&env); xmlrpc_registry_process_call2( &env, registryP, xmlrpc_mem_block_contents(callP), xmlrpc_mem_block_size(callP), NULL, &responseP); TEST_NO_FAULT(&env); TEST(XMLRPC_MEMBLOCK_SIZE(char, responseP) == strlen(expectedResp)); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, responseP), expectedResp, XMLRPC_MEMBLOCK_SIZE(char, responseP))); xmlrpc_DECREF(argArrayP); xmlrpc_mem_block_free(callP); xmlrpc_mem_block_free(responseP); xmlrpc_registry_free(registryP); xmlrpc_env_clean(&env); printf("\n"); } void test_method_registry(void) { xmlrpc_env env, env2; xmlrpc_value * valueP; xmlrpc_registry * registryP; xmlrpc_mem_block * responseP; xmlrpc_env_init(&env); testVersion(); printf("Running method registry tests."); /* Create a new registry. */ registryP = xmlrpc_registry_new(&env); TEST_NO_FAULT(&env); TEST(registryP != NULL); /* Add some test methods. */ xmlrpc_registry_add_method(&env, registryP, NULL, "test.foo", test_foo_type1, FOO_SERVERINFO); TEST_NO_FAULT(&env); xmlrpc_registry_add_method2(&env, registryP, "test.bar", test_bar, NULL, barHelp, BAR_SERVERINFO); TEST_NO_FAULT(&env); printf("\n"); testCall(registryP); test_system_multicall(registryP); xmlrpc_env_init(&env2); xmlrpc_registry_process_call2(&env, registryP, expat_error_data, strlen(expat_error_data), NULL, &responseP); TEST_NO_FAULT(&env); TEST(responseP != NULL); valueP = xmlrpc_parse_response(&env2, xmlrpc_mem_block_contents(responseP), xmlrpc_mem_block_size(responseP)); TEST(valueP == NULL); TEST_FAULT(&env2, XMLRPC_PARSE_ERROR); xmlrpc_mem_block_free(responseP); xmlrpc_env_clean(&env2); printf("\n"); testDefaultMethod(registryP); test_system_listMethods(registryP); test_system_methodExist(registryP); test_system_methodHelp(registryP); test_system_capabilities(registryP); test_system_getCapabilities(registryP); test_signature(); test_disable_introspection(); test_apache_dialect(); /* Test cleanup code (w/memprof). */ xmlrpc_registry_free(registryP); printf("\n"); xmlrpc_env_clean(&env); } xmlrpc-c-1.33.14/test/method_registry.h000066400000000000000000000001721236133176700177610ustar00rootroot00000000000000#ifndef TEST_METHOD_REGISTRY_H_INCLUDED #define TEST_METHOD_REGISTRY_H_INCLUDED void test_method_registry(void); #endif xmlrpc-c-1.33.14/test/parse_xml.c000066400000000000000000000415341236133176700165450ustar00rootroot00000000000000#include #include #include "xmlrpc_config.h" #include "girstring.h" #include "casprintf.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/xmlparser.h" #include "testtool.h" #include "xml_data.h" #include "parse_xml.h" static void test_expat (void) { xmlrpc_env env; xml_element *elem, *array, *data, *value1, *i4; char *cdata; size_t size; xmlrpc_env_init(&env); /* Parse a moderately complex XML document. */ xml_parse(&env, expat_data, strlen(expat_data), &elem); TEST_NO_FAULT(&env); TEST(elem != NULL); /* Verify our results. */ TEST(streq(xml_element_name(elem), "value")); TEST(xml_element_children_size(elem) == 1); array = xml_element_children(elem)[0]; TEST(streq(xml_element_name(array), "array")); TEST(xml_element_children_size(array) == 1); data = xml_element_children(array)[0]; TEST(streq(xml_element_name(data), "data")); TEST(xml_element_children_size(data) > 1); value1 = xml_element_children(data)[0]; TEST(streq(xml_element_name(value1), "value")); TEST(xml_element_children_size(value1) == 1); i4 = xml_element_children(value1)[0]; TEST(streq(xml_element_name(i4), "i4")); TEST(xml_element_children_size(i4) == 0); cdata = xml_element_cdata(i4); size = xml_element_cdata_size(i4); TEST(size == strlen("2147483647")); TEST(memcmp(cdata, "2147483647", strlen("2147483647")) == 0); /* Test cleanup code (w/memprof). */ xml_element_free(elem); /* Test broken XML */ xml_parse(&env, expat_error_data, strlen(expat_error_data), &elem); TEST(env.fault_occurred); xmlrpc_env_clean(&env); } static void testParseNumberValue(void) { char const xmldata[] = XML_PROLOGUE "\r\n" "test\r\n" "\r\n" "2147483647\r\n" \ "-2147483648\r\n" \ "10\r\n" "10\r\n" "10\r\n" "10\r\n" "10\r\n" "10\r\n" "10.1\r\n" "-10.1\r\n" "+10.1\r\n" "0\r\n" ".01\r\n" "5.\r\n" "5.3E6\r\n" " 1\r\n" "\r\n" "\r\n"; xmlrpc_env env; xmlrpc_value * paramArrayP; const char * methodName; int arraySize; xmlrpc_int int_max, int_min; xmlrpc_int32 i_i1, i_i2, i_i4; xmlrpc_int64 i_i8, i_ex_i8; double d1, d2, d3, d4, d5, d6, d7, d8, d9; xmlrpc_env_init(&env); xmlrpc_parse_call(&env, xmldata, strlen(xmldata), &methodName, ¶mArrayP); TEST_NO_FAULT(&env); arraySize = xmlrpc_array_size(&env, paramArrayP); TEST_NO_FAULT(&env); TEST(arraySize == 16); xmlrpc_decompose_value( &env, paramArrayP, "(iiiiiIIddddddddd)", &int_max, &int_min, &i_i1, &i_i2, &i_i4, &i_i8, &i_ex_i8, &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9); TEST_NO_FAULT(&env); TEST(int_max == INT_MAX); TEST(int_min == INT_MIN); TEST(i_i1 == 10); TEST(i_i2 == 10); TEST(i_i4 == 10); TEST(i_i8 == 10); TEST(i_ex_i8 == 10); TESTFLOATEQUAL(d1, 10.0); TESTFLOATEQUAL(d2, 10.1); TESTFLOATEQUAL(d3, -10.1); TESTFLOATEQUAL(d4, +10.1); TESTFLOATEQUAL(d5, 0.0); TESTFLOATEQUAL(d6, 0.01); TESTFLOATEQUAL(d7, 5.0); TESTFLOATEQUAL(d8, 5.3E6); TESTFLOATEQUAL(d9, 1.0); xmlrpc_DECREF(paramArrayP); strfree(methodName); xmlrpc_env_clean(&env); } static void testParseMiscSimpleValue(void) { char const xmldata[] = XML_PROLOGUE "\r\n" "test\r\n" "\r\n" "hello\r\n" "0\r\n" "1\r\n" "19980717T14:08:55" "\r\n" "" "19980717T14:08:55.123456" "\r\n" "YmFzZTY0IGRhdGE=\r\n" "\r\n" "\r\n" "\r\n" "\r\n"; xmlrpc_env env; xmlrpc_value * paramArrayP; const char * methodName; int arraySize; const char * str_hello; xmlrpc_bool b_false, b_true; const char * datetime_sec; const char * datetime_usec; unsigned char * b64_data; size_t b64_len; xmlrpc_env_init(&env); xmlrpc_parse_call(&env, xmldata, strlen(xmldata), &methodName, ¶mArrayP); TEST_NO_FAULT(&env); arraySize = xmlrpc_array_size(&env, paramArrayP); TEST_NO_FAULT(&env); TEST(arraySize == 8); xmlrpc_decompose_value( &env, paramArrayP, "(sbb886nn)", &str_hello, &b_false, &b_true, &datetime_sec, &datetime_usec, &b64_data, &b64_len); TEST_NO_FAULT(&env); TEST(streq(str_hello, "hello")); TEST(!b_false); TEST(b_true); TEST(streq(datetime_sec, "19980717T14:08:55")); TEST(streq(datetime_usec, "19980717T14:08:55.123456")); TEST(b64_len == 11); TEST(memcmp(b64_data, "base64 data", b64_len) == 0); free(b64_data); strfree(str_hello); strfree(datetime_sec); strfree(datetime_usec); xmlrpc_DECREF(paramArrayP); strfree(methodName); xmlrpc_env_clean(&env); } static void validateParseResponseResult(xmlrpc_value * const valueP) { xmlrpc_env env; xmlrpc_value * s; xmlrpc_int32 int_max; xmlrpc_int32 int_min; xmlrpc_int32 int_one; xmlrpc_bool bool_false; xmlrpc_bool bool_true; char * str_hello; char * str_untagged; char * datetime; unsigned char * b64_data; size_t b64_len; double negone; double zero; double one; xmlrpc_env_init(&env); xmlrpc_decompose_value( &env, valueP, "((iibbs68())idddSs)", &int_max, &int_min, &bool_false, &bool_true, &str_hello, &b64_data, &b64_len, &datetime, &int_one, &negone, &zero, &one, &s, &str_untagged); TEST_NO_FAULT(&env); TEST(int_max == INT_MAX); TEST(int_min == INT_MIN); TEST(!bool_false); TEST(bool_true); TEST(strlen(str_hello) == strlen("Hello, world! <&>")); TEST(streq(str_hello, "Hello, world! <&>")); TEST(b64_len == 11); TEST(memcmp(b64_data, "base64 data", b64_len) == 0); TEST(streq(datetime, "19980717T14:08:55")); TEST(int_one == 1); TEST(negone == -1.0); TEST(zero == 0.0); TEST(one == 1.0); TEST(streq(str_untagged, "Untagged string")); free(str_hello); free(b64_data); free(datetime); free(str_untagged); { /* Analyze the contents of our struct. */ xmlrpc_value * sval; int size, sval_int; TEST(s != NULL); size = xmlrpc_struct_size(&env, s); TEST_NO_FAULT(&env); TEST(size == 2); sval = xmlrpc_struct_get_value(&env, s, "ten <&>"); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, sval, "i", &sval_int); TEST_NO_FAULT(&env); TEST(sval_int == 10); sval = xmlrpc_struct_get_value(&env, s, "twenty"); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, sval, "i", &sval_int); TEST_NO_FAULT(&env); TEST(sval_int == 20); xmlrpc_DECREF(s); } xmlrpc_env_clean(&env); } static void testParseGoodResponse(void) { xmlrpc_env env; xmlrpc_value * valueP; int faultCode; const char * faultString; xmlrpc_env_init(&env); xmlrpc_parse_response2(&env, good_response_xml, strlen(good_response_xml), &valueP, &faultCode, &faultString); TEST_NO_FAULT(&env); TEST(faultString == NULL); validateParseResponseResult(valueP); xmlrpc_DECREF(valueP); /* Try it again with old interface */ valueP = xmlrpc_parse_response(&env, good_response_xml, strlen(good_response_xml)); TEST_NO_FAULT(&env); TEST(valueP != NULL); validateParseResponseResult(valueP); xmlrpc_DECREF(valueP); xmlrpc_env_clean(&env); } static void testParseBadResponseXml(void) { /*---------------------------------------------------------------------------- Test parsing of data that is supposed to be a response, but in not even valid XML. -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_value * valueP; int faultCode; const char * faultString; xmlrpc_env_init(&env); xmlrpc_parse_response2(&env, unparseable_value, strlen(unparseable_value), &valueP, &faultCode, &faultString); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); xmlrpc_env_clean(&env); xmlrpc_env_init(&env); /* And again with the old interface */ valueP = xmlrpc_parse_response(&env, unparseable_value, strlen(unparseable_value)); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); xmlrpc_env_clean(&env); TEST(valueP == NULL); } static void testParseBadResponseXmlRpc(void) { /*---------------------------------------------------------------------------- Test parsing of data that is supposed to be a response, and is valid XML, but is not valid XML-RPC. -----------------------------------------------------------------------------*/ unsigned int i; /* For this test, we test up to but not including the in a successful RPC response. */ /* Next, check for bogus responses. These are all well-formed XML, but ** they aren't legal XML-RPC. */ for (i = 15; bad_responses[i] != NULL; ++i) { const char * const bad_resp = bad_responses[i]; xmlrpc_env env; xmlrpc_value * v; xml_element *elem; xmlrpc_env_init(&env); /* First, check to make sure that our test case is well-formed XML. ** (It's easy to make mistakes when writing the test cases!) */ xml_parse(&env, bad_resp, strlen(bad_resp), &elem); TEST_NO_FAULT(&env); xml_element_free(elem); /* Now, make sure the higher-level routine barfs appropriately. */ v = xmlrpc_parse_response(&env, bad_resp, strlen(bad_resp)); TEST(env.fault_occurred); TEST(env.fault_code != 0); /* We use 0 as a code in our bad faults. */ TEST(v == NULL); xmlrpc_env_clean(&env); } } static void testParseBadResult(void) { /*---------------------------------------------------------------------------- Test parsing of data that is supposed to be a response, but is not valid. It looks like a valid success response, but the result value is not valid XML-RPC. -----------------------------------------------------------------------------*/ unsigned int i; for (i = 0; bad_values[i] != NULL; ++i) { const char * const bad_resp = bad_values[i]; xmlrpc_env env; xmlrpc_value * valueP; xml_element *elem; int faultCode; const char * faultString; xmlrpc_env_init(&env); /* First, check to make sure that our test case is well-formed XML. ** (It's easy to make mistakes when writing the test cases!) */ xml_parse(&env, bad_resp, strlen(bad_resp), &elem); TEST_NO_FAULT(&env); xml_element_free(elem); /* Now, make sure the higher-level routine barfs appropriately. */ xmlrpc_parse_response2(&env, bad_resp, strlen(bad_resp), &valueP, &faultCode, &faultString); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); xmlrpc_env_clean(&env); xmlrpc_env_init(&env); /* And again with the old interface */ valueP = xmlrpc_parse_response(&env, bad_resp, strlen(bad_resp)); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); TEST(valueP == NULL); xmlrpc_env_clean(&env); } } static void testParseBadResponse(void) { /*---------------------------------------------------------------------------- Test parsing of data that is supposed to be a response, but is not valid. Either not valid XML or not valid XML-RPC. -----------------------------------------------------------------------------*/ testParseBadResponseXml(); testParseBadResponseXmlRpc(); testParseBadResult(); } static void testParseFaultResponse(void) { /*---------------------------------------------------------------------------- Test parsing of a valid response that indicates the RPC failed. -----------------------------------------------------------------------------*/ xmlrpc_env env; xmlrpc_env_init(&env); { xmlrpc_value * resultP; int faultCode; const char * faultString; xmlrpc_parse_response2(&env, serialized_fault, strlen(serialized_fault), &resultP, &faultCode, &faultString); TEST_NO_FAULT(&env); TEST(faultString != NULL); TEST(faultCode == 6); TEST(streq(faultString, "A fault occurred")); strfree(faultString); } /* Now with the old interface */ { xmlrpc_value * valueP; xmlrpc_env fault; /* Parse a valid fault. */ xmlrpc_env_init(&fault); valueP = xmlrpc_parse_response(&fault, serialized_fault, strlen(serialized_fault)); TEST(fault.fault_occurred); TEST(fault.fault_code == 6); TEST(streq(fault.fault_string, "A fault occurred")); xmlrpc_env_clean(&fault); } xmlrpc_env_clean(&env); } static void testParseXmlCall(void) { xmlrpc_env env; const char *method_name; xmlrpc_value *params; int i1, i2; const char **bad_call; xml_element *elem; xmlrpc_env_init(&env); /* Parse a valid call. */ xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call), &method_name, ¶ms); TEST_NO_FAULT(&env); TEST(params != NULL); xmlrpc_decompose_value(&env, params, "(ii)", &i1, &i2); xmlrpc_DECREF(params); TEST_NO_FAULT(&env); TEST(streq(method_name, "gloom&doom")); TEST(i1 == 10 && i2 == 20); strfree(method_name); /* Test some poorly-formed XML data. */ xmlrpc_parse_call(&env, unparseable_value, strlen(unparseable_value), &method_name, ¶ms); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); TEST(method_name == NULL && params == NULL); /* Next, check for bogus values. These are all well-formed XML, but they aren't legal XML-RPC. */ for (bad_call = bad_calls; *bad_call != NULL; ++bad_call) { /* First, check to make sure that our test case is well-formed XML. ** (It's easy to make mistakes when writing the test cases!) */ xml_parse(&env, *bad_call, strlen(*bad_call), &elem); TEST_NO_FAULT(&env); xml_element_free(elem); /* Now, make sure the higher-level routine barfs appropriately. */ xmlrpc_parse_call(&env, *bad_call, strlen(*bad_call), &method_name, ¶ms); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); TEST(method_name == NULL && params == NULL); } xmlrpc_env_clean(&env); } static void testParseXmlValue(void) { const char * const xmlInt7 = "7"; const char * const xmlBadVal1 = "hello"; const char * const xmlBadVal2 = ""; xmlrpc_value * valueP; xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_parse_value_xml(&env, xmlInt7, strlen(xmlInt7), &valueP); TEST_NO_FAULT(&env); xmlrpc_DECREF(valueP); xmlrpc_parse_value_xml(&env, xmlBadVal1, strlen(xmlBadVal1), &valueP); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); xmlrpc_env_clean(&env); xmlrpc_env_init(&env); xmlrpc_parse_value_xml(&env, xmlBadVal2, strlen(xmlBadVal2), &valueP); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); xmlrpc_env_clean(&env); } void test_parse_xml(void) { printf("Running XML parsing tests.\n"); test_expat(); testParseNumberValue(); testParseMiscSimpleValue(); testParseGoodResponse(); testParseFaultResponse(); testParseBadResponse(); testParseXmlCall(); testParseXmlValue(); printf("\n"); printf("XML parsing tests done.\n"); } xmlrpc-c-1.33.14/test/parse_xml.h000066400000000000000000000000331236133176700165370ustar00rootroot00000000000000void test_parse_xml(void); xmlrpc-c-1.33.14/test/req_no_params.xml000066400000000000000000000004121236133176700177450ustar00rootroot00000000000000 foo xmlrpc-c-1.33.14/test/serialize.c000066400000000000000000000175351236133176700165460ustar00rootroot00000000000000#include #include #include #include "xmlrpc_config.h" #include "xmlrpc-c/base.h" #include "testtool.h" #include "xml_data.h" #include "girstring.h" #include "serialize_value.h" #include "serialize.h" static void test_serialize_basic(void) { xmlrpc_env env; xmlrpc_value * v; xmlrpc_mem_block *output; size_t size; xmlrpc_env_init(&env); /* Build a nice, messy value to serialize. We should attempt to use ** use every data type except double (which doesn't serialize in a ** portable manner. */ v = xmlrpc_build_value(&env, "(iibbs68())", (xmlrpc_int32) INT_MAX, (xmlrpc_int32) INT_MIN, (xmlrpc_bool) 0, (xmlrpc_bool) 1, "Hello, world! <&>", "base64 data", (size_t) 11, "19980717T14:08:55"); TEST_NO_FAULT(&env); /* Serialize the value. */ output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); xmlrpc_serialize_value(&env, output, v); TEST_NO_FAULT(&env); /* Make sure we serialized the correct value. */ size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); TEST(size == strlen(serialized_data)); TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), serialized_data, size) == 0); /* (Debugging code to display the value.) */ /* XMLRPC_TYPED_MEM_BLOCK_APPEND(char, &env, output, "\0", 1); ** TEST_NO_FAULT(&env); ** printf("%s\n", XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output)); */ /* Clean up our value. */ XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void test_serialize_methodResponse(void) { /* Serialize a methodResponse. */ char const serialized_response[] = XML_PROLOGUE "\r\n" "\r\n" "30\r\n" "\r\n" "\r\n"; xmlrpc_env env; xmlrpc_value * v; xmlrpc_mem_block *output; size_t size; xmlrpc_env_init(&env); output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 30); TEST_NO_FAULT(&env); xmlrpc_serialize_response(&env, output, v); TEST_NO_FAULT(&env); /* Make sure we serialized the correct value. */ size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); TEST(size == strlen(serialized_response)); TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), serialized_response, size) == 0); /* Clean up our methodResponse. */ xmlrpc_DECREF(v); XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); xmlrpc_env_clean(&env); } static void test_serialize_methodCall(void) { /* Serialize a methodCall. */ xmlrpc_env env; xmlrpc_value * v; xmlrpc_mem_block *output; size_t size; xmlrpc_env_init(&env); output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); v = xmlrpc_build_value(&env, "(ii)", (xmlrpc_int32) 10, (xmlrpc_int32) 20); TEST_NO_FAULT(&env); xmlrpc_serialize_call(&env, output, "gloom&doom", v); TEST_NO_FAULT(&env); /* Make sure we serialized the correct value. */ size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); TEST(size == strlen(serialized_call)); TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), serialized_call, size) == 0); /* Clean up our methodCall. */ xmlrpc_DECREF(v); XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); xmlrpc_env_clean(&env); } static void test_serialize_fault(void) { /* Serialize a fault. */ xmlrpc_env env; xmlrpc_env fault; xmlrpc_mem_block *output; size_t size; xmlrpc_env_init(&env); output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); xmlrpc_env_init(&fault); xmlrpc_env_set_fault(&fault, 6, "A fault occurred"); xmlrpc_serialize_fault(&env, output, &fault); TEST_NO_FAULT(&env); /* Make sure we serialized the correct value. */ size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); TEST(size == strlen(serialized_fault)); TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), serialized_fault, size) == 0); /* Clean up our fault. */ xmlrpc_env_clean(&fault); XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); xmlrpc_env_clean(&env); } static void test_serialize_apache_value(void) { char const serializedData[] = "\r\n" "7\r\n" "8\r\n" "\r\n" ""; xmlrpc_env env; xmlrpc_value * valueP; xmlrpc_mem_block * outputP; size_t size; xmlrpc_env_init(&env); valueP = xmlrpc_build_value(&env, "(iIn)", 7, (xmlrpc_int64)8); TEST_NO_FAULT(&env); outputP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); xmlrpc_serialize_value2(&env, outputP, valueP, xmlrpc_dialect_apache); TEST_NO_FAULT(&env); size = XMLRPC_MEMBLOCK_SIZE(char, outputP); TEST(size == strlen(serializedData)); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, outputP), serializedData, size)); XMLRPC_MEMBLOCK_FREE(char, outputP); xmlrpc_DECREF(valueP); xmlrpc_env_clean(&env); } static void test_serialize_apache_params(void) { char const serializedData[] = "\r\n" "7\r\n" "8\r\n" "\r\n"; xmlrpc_env env; xmlrpc_value * paramArrayP; xmlrpc_mem_block * outputP; size_t size; xmlrpc_env_init(&env); paramArrayP = xmlrpc_build_value(&env, "(iI)", 7, (xmlrpc_int64)8); TEST_NO_FAULT(&env); outputP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); xmlrpc_serialize_params2(&env, outputP, paramArrayP, xmlrpc_dialect_apache); TEST_NO_FAULT(&env); size = XMLRPC_MEMBLOCK_SIZE(char, outputP); TEST(size == strlen(serializedData)); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, outputP), serializedData, size)); XMLRPC_MEMBLOCK_FREE(char, outputP); xmlrpc_DECREF(paramArrayP); xmlrpc_env_clean(&env); } static void test_serialize_apache_response(void) { char const serializedData[] = XML_PROLOGUE "\r\n" "\r\n" "8\r\n" "\r\n" "\r\n"; xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_mem_block * outputP; size_t size; xmlrpc_env_init(&env); resultP = xmlrpc_i8_new(&env, 8); TEST_NO_FAULT(&env); outputP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); xmlrpc_serialize_response2(&env, outputP, resultP, xmlrpc_dialect_apache); TEST_NO_FAULT(&env); size = XMLRPC_MEMBLOCK_SIZE(char, outputP); TEST(size == strlen(serializedData)); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, outputP), serializedData, size)); XMLRPC_MEMBLOCK_FREE(char, outputP); xmlrpc_DECREF(resultP); xmlrpc_env_clean(&env); } static void test_serialize_apache(void) { /* Serialize various things using the Apache dialect of XML-RPC */ test_serialize_apache_value(); test_serialize_apache_params(); test_serialize_apache_response(); } void test_serialize(void) { printf("Running serialize tests."); test_serialize_basic(); printf("\n"); test_serialize_value(); test_serialize_methodResponse(); test_serialize_methodCall(); test_serialize_fault(); test_serialize_apache(); printf("\n"); printf("Serialize tests done.\n"); } xmlrpc-c-1.33.14/test/serialize.h000066400000000000000000000000341236133176700165350ustar00rootroot00000000000000void test_serialize(void); xmlrpc-c-1.33.14/test/serialize_value.c000066400000000000000000000147441236133176700177410ustar00rootroot00000000000000#include #include #include #include "xmlrpc_config.h" #include "xmlrpc-c/base.h" #include "testtool.h" #include "girstring.h" #include "serialize_value.h" static void test_serialize_string(void) { /* Test serialize of a string, including all the line ending complexity. */ xmlrpc_env env; xmlrpc_value * v; xmlrpc_mem_block * xmlP; /* Serialized result */ xmlrpc_env_init(&env); TEST_NO_FAULT(&env); v = xmlrpc_string_new(&env, "hello world"); TEST_NO_FAULT(&env); xmlP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); xmlrpc_serialize_value(&env, xmlP, v); TEST_NO_FAULT(&env); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, xmlP), "hello world", XMLRPC_MEMBLOCK_SIZE(char, xmlP))); XMLRPC_MEMBLOCK_FREE(char, xmlP); xmlrpc_DECREF(v); v = xmlrpc_string_new(&env, ""); TEST_NO_FAULT(&env); xmlP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); xmlrpc_serialize_value(&env, xmlP, v); TEST_NO_FAULT(&env); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, xmlP), "", XMLRPC_MEMBLOCK_SIZE(char, xmlP))); XMLRPC_MEMBLOCK_FREE(char, xmlP); xmlrpc_DECREF(v); v = xmlrpc_string_new_lp(&env, 7, "foo\0bar"); TEST_NO_FAULT(&env); xmlP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); xmlrpc_serialize_value(&env, xmlP, v); TEST_NO_FAULT(&env); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, xmlP), "foo\0bar", XMLRPC_MEMBLOCK_SIZE(char, xmlP))); XMLRPC_MEMBLOCK_FREE(char, xmlP); xmlrpc_DECREF(v); v = xmlrpc_string_new_lp(&env, 7, "foo\nbar"); TEST_NO_FAULT(&env); xmlP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); xmlrpc_serialize_value(&env, xmlP, v); TEST_NO_FAULT(&env); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, xmlP), "foo\nbar", XMLRPC_MEMBLOCK_SIZE(char, xmlP))); XMLRPC_MEMBLOCK_FREE(char, xmlP); xmlrpc_DECREF(v); v = xmlrpc_string_new_lp(&env, 8, "foo\r\nbar"); TEST_NO_FAULT(&env); xmlP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); xmlrpc_serialize_value(&env, xmlP, v); TEST_NO_FAULT(&env); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, xmlP), "foo\nbar", XMLRPC_MEMBLOCK_SIZE(char, xmlP))); XMLRPC_MEMBLOCK_FREE(char, xmlP); xmlrpc_DECREF(v); v = xmlrpc_string_new_lp(&env, 7, "foo\rbar"); TEST_NO_FAULT(&env); xmlP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); xmlrpc_serialize_value(&env, xmlP, v); TEST_NO_FAULT(&env); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, xmlP), "foo\nbar", XMLRPC_MEMBLOCK_SIZE(char, xmlP))); XMLRPC_MEMBLOCK_FREE(char, xmlP); xmlrpc_DECREF(v); v = xmlrpc_string_new_lp_cr(&env, 7, "foo\rbar"); TEST_NO_FAULT(&env); xmlP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); xmlrpc_serialize_value(&env, xmlP, v); TEST_NO_FAULT(&env); TEST(memeq(XMLRPC_MEMBLOCK_CONTENTS(char, xmlP), "foo bar", XMLRPC_MEMBLOCK_SIZE(char, xmlP))); XMLRPC_MEMBLOCK_FREE(char, xmlP); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void testOneDouble(double const value) { /* Test serialize of a double. */ xmlrpc_env env; xmlrpc_value * valueP; xmlrpc_mem_block * serializedP; char * result; /* serialized result, as asciiz string */ size_t resultLength; /* Length in characters of the serialized result */ double serializedValue; char nextChar; int itemsMatched; xmlrpc_env_init(&env); /* Build a double to serialize */ valueP = xmlrpc_double_new(&env, value); TEST_NO_FAULT(&env); /* Serialize the value. */ serializedP = XMLRPC_MEMBLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); xmlrpc_serialize_value(&env, serializedP, valueP); TEST_NO_FAULT(&env); /* Make sure we serialized the correct value. Note that because doubles aren't precise, this might serialize as 3.1415899999 or something like that. So we check it arithmetically. */ resultLength = XMLRPC_MEMBLOCK_SIZE(char, serializedP); result = malloc(resultLength + 1); memcpy(result, XMLRPC_MEMBLOCK_CONTENTS(char, serializedP), resultLength); result[resultLength] = '\0'; itemsMatched = sscanf(result, "%lf\r\n%c", &serializedValue, &nextChar); TEST(itemsMatched == 1); TESTFLOATEQUAL(serializedValue, value); free(result); /* Clean up our value. */ XMLRPC_TYPED_MEM_BLOCK_FREE(char, serializedP); xmlrpc_DECREF(valueP); xmlrpc_env_clean(&env); } static void test_serialize_double(void) { testOneDouble(0); testOneDouble(1); testOneDouble(0.3); testOneDouble(4.9); testOneDouble(9.9999999); testOneDouble(-8); testOneDouble(-.7); testOneDouble(-2.5); testOneDouble(3.14159); testOneDouble(1.2E37); testOneDouble(1.2E-37); testOneDouble(-5E200); } static void test_serialize_struct(void) { /* Serialize a simple struct. */ char const serialized_struct[] = "\r\n" \ "<&>\r\n" \ "10\r\n" \ ""; xmlrpc_env env; xmlrpc_value * v; xmlrpc_mem_block *output; size_t size; xmlrpc_env_init(&env); v = xmlrpc_build_value(&env, "{s:i}", "<&>", (xmlrpc_int32) 10); TEST_NO_FAULT(&env); output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0); TEST_NO_FAULT(&env); xmlrpc_serialize_value(&env, output, v); TEST_NO_FAULT(&env); /* Make sure we serialized the correct value. */ size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output); TEST(size == strlen(serialized_struct)); TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), serialized_struct, size) == 0); /* Clean up our struct. */ XMLRPC_TYPED_MEM_BLOCK_FREE(char, output); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } void test_serialize_value(void) { printf(" Running serialize value tests."); test_serialize_string(); test_serialize_double(); test_serialize_struct(); printf("\n"); printf(" Serialize value tests done.\n"); } xmlrpc-c-1.33.14/test/serialize_value.h000066400000000000000000000001611236133176700177320ustar00rootroot00000000000000#ifndef SERIALIZE_VALUE_H_INCLUDED #define SERIALIZE_VALUE_H_INCLUDED void test_serialize_value(void); #endif xmlrpc-c-1.33.14/test/server_abyss.c000066400000000000000000000156101236133176700172560ustar00rootroot00000000000000#define WIN32_LEAN_AND_MEAN /* required by xmlrpc-c/abyss.h */ #include "unistdx.h" #include #include "bool.h" #include "xmlrpc_config.h" #include "girstring.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/abyss.h" #include "xmlrpc-c/server_abyss.h" #include "testtool.h" #include "server_abyss.h" static xmlrpc_call_processor myXmlProcessor; static void myXmlProcessor(xmlrpc_env * const envP ATTR_UNUSED, void * const processorArg ATTR_UNUSED, const char * const callXml ATTR_UNUSED, size_t const callXmlLen ATTR_UNUSED, TSession * const abyssSessionP ATTR_UNUSED, xmlrpc_mem_block ** const responseXmlPP ATTR_UNUSED) { printf("XML processor running\n"); } static void testSetHandlers(TServer * const abyssServerP) { xmlrpc_env env; xmlrpc_registry * registryP; xmlrpc_server_abyss_handler_parms parms; xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); TEST_NO_FAULT(&env); TEST(registryP != NULL); parms.xml_processor = &myXmlProcessor; parms.xml_processor_arg = NULL; parms.xml_processor_max_stack = 512; parms.uri_path = "/RPC6"; parms.chunk_response = true; parms.allow_origin = "*"; xmlrpc_server_abyss_set_handler3( &env, abyssServerP, &parms, XMLRPC_AHPSIZE(xml_processor_arg)); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Parms too short */ xmlrpc_server_abyss_set_handler3( &env, abyssServerP, &parms, XMLRPC_AHPSIZE(allow_origin)); TEST_NO_FAULT(&env); xmlrpc_server_abyss_set_handler2(abyssServerP, "/RPC5", &myXmlProcessor, NULL, 512, true); xmlrpc_server_abyss_set_handler(&env, abyssServerP, "/RPC3", registryP); TEST_NO_FAULT(&env); xmlrpc_server_abyss_set_handlers2(abyssServerP, "/RPC4", registryP); xmlrpc_server_abyss_set_handlers(abyssServerP, registryP); xmlrpc_server_abyss_set_default_handler(abyssServerP); xmlrpc_registry_free(registryP); { xmlrpc_registry * registryP; registryP = xmlrpc_registry_new(&env); xmlrpc_server_abyss_set_handlers(abyssServerP, registryP); xmlrpc_registry_free(registryP); } xmlrpc_env_clean(&env); } static void testServerParms(void) { xmlrpc_server_abyss_parms parms; struct sockaddr sockaddr; parms.config_file_name = NULL; parms.registryP = NULL; parms.port_number = 1000; parms.max_conn = 10; parms.max_conn_backlog = 10; parms.keepalive_timeout = 5; parms.keepalive_max_conn = 4; parms.timeout = 50; parms.dont_advertise = TRUE; parms.uri_path = "/RPC9"; parms.chunk_response = TRUE; parms.allow_origin = "*"; parms.access_ctl_expires = TRUE; parms.access_ctl_max_age = 5; parms.sockaddr_p = &sockaddr; parms.sockaddrlen = sizeof(sockaddr); parms.log_file_name = "/tmp/xmlrpc_logfile"; }; static void testObjectParm(void) { xmlrpc_env env; xmlrpc_server_abyss_parms parms; xmlrpc_registry * registryP; xmlrpc_server_abyss_t * serverP; xmlrpc_env_init(&env); xmlrpc_server_abyss_global_init(&env); TEST_NO_FAULT(&env); registryP = xmlrpc_registry_new(&env); TEST_NO_FAULT(&env); MEMSZERO(&parms); parms.registryP = registryP; xmlrpc_server_abyss_create(&env, &parms, XMLRPC_APSIZE(sockaddrlen), &serverP); TEST_NO_FAULT(&env); TEST(serverP != NULL); xmlrpc_server_abyss_destroy(serverP); xmlrpc_server_abyss_create(&env, &parms, XMLRPC_APSIZE(sockaddr_p), &serverP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* sockaddr_p w/o sockaddrlen */ parms.port_number = 100000; xmlrpc_server_abyss_create(&env, &parms, XMLRPC_APSIZE(sockaddrlen), &serverP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* port number too large */ xmlrpc_server_abyss_create(&env, &parms, XMLRPC_APSIZE(port_number), &serverP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* port number too large */ { struct sockaddr_in localhost; localhost.sin_family = AF_INET; localhost.sin_port = htons(8080); localhost.sin_addr = test_ipAddrFromDecimal(127, 0, 0, 1); parms.sockaddr_p = (const struct sockaddr *)&localhost; parms.sockaddrlen = sizeof(localhost); xmlrpc_server_abyss_create(&env, &parms, XMLRPC_APSIZE(sockaddrlen), &serverP); TEST_NO_FAULT(&env); TEST(serverP != NULL); xmlrpc_server_abyss_destroy(serverP); } xmlrpc_server_abyss_global_term(); xmlrpc_env_clean(&env); } static void testObject(void) { xmlrpc_env env; xmlrpc_server_abyss_parms parms; xmlrpc_server_abyss_t * serverP; xmlrpc_registry * registryP; xmlrpc_server_abyss_sig * oldHandlersP; xmlrpc_env_init(&env); registryP = xmlrpc_registry_new(&env); TEST_NO_FAULT(&env); parms.config_file_name = NULL; parms.registryP = registryP; serverP = NULL; xmlrpc_server_abyss_create(&env, &parms, XMLRPC_APSIZE(registryP), &serverP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Global init not done */ xmlrpc_server_abyss_global_init(&env); TEST_NO_FAULT(&env); xmlrpc_server_abyss_create(&env, &parms, XMLRPC_APSIZE(registryP), &serverP); TEST_NO_FAULT(&env); TEST(serverP != NULL); xmlrpc_server_abyss_terminate(&env, serverP); TEST_NO_FAULT(&env); xmlrpc_server_abyss_reset_terminate(&env, serverP); TEST_NO_FAULT(&env); xmlrpc_server_abyss_setup_sig(&env, serverP, &oldHandlersP); TEST_NO_FAULT(&env); xmlrpc_server_abyss_use_sigchld(serverP); xmlrpc_server_abyss_restore_sig(oldHandlersP); TEST_NO_FAULT(&env); free(oldHandlersP); xmlrpc_server_abyss_destroy(serverP); xmlrpc_registry_free(registryP); xmlrpc_server_abyss_global_term(); xmlrpc_server_abyss_setup_sig(&env, serverP, &oldHandlersP); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Not globally initialized */ testObjectParm(); xmlrpc_env_clean(&env); } void test_server_abyss(void) { TServer abyssServer; printf("Running Abyss XML-RPC server tests...\n"); ServerCreate(&abyssServer, "testserver", 8080, NULL, NULL); testSetHandlers(&abyssServer); ServerSetMaxConn(&abyssServer, 10); ServerSetMaxConnBacklog(&abyssServer, 10); ServerSetKeepaliveTimeout(&abyssServer, 60); ServerSetKeepaliveMaxConn(&abyssServer, 10); ServerSetTimeout(&abyssServer, 0); ServerSetAdvertise(&abyssServer, FALSE); ServerFree(&abyssServer); testServerParms(); testObject(); printf("\n"); printf("Abyss XML-RPC server tests done.\n"); } xmlrpc-c-1.33.14/test/server_abyss.h000066400000000000000000000000361236133176700172570ustar00rootroot00000000000000void test_server_abyss(void); xmlrpc-c-1.33.14/test/test.c000066400000000000000000000565131236133176700155350ustar00rootroot00000000000000/* Copyright information is at the end of the file. */ #ifdef _WIN32 # include #else # include #endif #include #include #include #include #include #include "casprintf.h" #include "xmlrpc_config.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/server.h" #include "xmlrpc-c/string_int.h" #include "bool.h" #include "testtool.h" #include "value.h" #include "serialize.h" #include "parse_xml.h" #include "cgi.h" #include "xml_data.h" #include "client.h" #include "abyss.h" #include "server_abyss.h" #include "method_registry.h" /*========================================================================= ** Test Harness **========================================================================= ** This is a super light-weight test harness. It's vaguely inspired by ** Kent Beck's book on eXtreme Programming (XP)--the output is succinct, ** new tests can be coded quickly, and the whole thing runs in a few ** second's time. ** ** To run the tests, type './rpctest'. ** To check for memory leaks, install RedHat's 'memprof' utility, and ** type 'memprof rpctest'. ** ** If you add new tests to this file, please deallocate any data ** structures you use in the appropriate fashion. This allows us to test ** various destructor code for memory leaks. */ int total_tests = 0; int total_failures = 0; bool const runningUnderWindows = #ifdef _WIN32 true; #else false; #endif /*========================================================================= ** Test Data **========================================================================= ** Some common test data which need to be allocated at a fixed address, ** or which are inconvenient to allocate inline. */ static char* test_string_1 = "foo"; static char* test_string_2 = "bar"; static int test_int_array_1[5] = {1, 2, 3, 4, 5}; static int test_int_array_2[3] = {6, 7, 8}; static int test_int_array_3[8] = {1, 2, 3, 4, 5, 6, 7, 8}; /*========================================================================= ** Test Suites **========================================================================= */ static void testVersion(void) { unsigned int major, minor, point; xmlrpc_version(&major, &minor, &point); #ifndef _WIN32 /* xmlrpc_version_major, etc. are not exported from a Windows DLL */ TEST(major == xmlrpc_version_major); TEST(minor == xmlrpc_version_minor); TEST(point == xmlrpc_version_point); #endif } static void testEnv(void) { xmlrpc_env env, env2; /* Test xmlrpc_env_init. */ xmlrpc_env_init(&env); TEST(!env.fault_occurred); TEST(env.fault_code == 0); TEST(env.fault_string == NULL); /* Test xmlrpc_set_fault. */ xmlrpc_env_set_fault(&env, 1, test_string_1); TEST(env.fault_occurred); TEST(env.fault_code == 1); TEST(env.fault_string != test_string_1); TEST(xmlrpc_streq(env.fault_string, test_string_1)); /* Change an existing fault. */ xmlrpc_env_set_fault(&env, 2, test_string_2); TEST(env.fault_occurred); TEST(env.fault_code == 2); TEST(xmlrpc_streq(env.fault_string, test_string_2)); /* Set a fault with a format string. */ xmlrpc_env_set_fault_formatted(&env, 3, "a%s%d", "bar", 9); TEST(env.fault_occurred); TEST(env.fault_code == 3); TEST(xmlrpc_streq(env.fault_string, "abar9")); /* Test cleanup code (with help from memprof). */ xmlrpc_env_clean(&env); /* Test cleanup code on in absence of xmlrpc_env_set_fault. */ xmlrpc_env_init(&env2); xmlrpc_env_clean(&env2); } static void testMemBlock(void) { xmlrpc_env env; xmlrpc_mem_block* block; xmlrpc_mem_block* typed_heap_block; xmlrpc_mem_block typed_auto_block; void** typed_contents; xmlrpc_env_init(&env); /* Allocate a zero-size block. */ block = xmlrpc_mem_block_new(&env, 0); TEST_NO_FAULT(&env); TEST(block != NULL); TEST(xmlrpc_mem_block_size(block) == 0); /* Grow the block a little bit. */ xmlrpc_mem_block_resize(&env, block, strlen(test_string_1) + 1); TEST_NO_FAULT(&env); TEST(xmlrpc_mem_block_size(block) == strlen(test_string_1) + 1); /* Insert a string into the block, and resize it by large amount. ** We want to cause a reallocation and copy of the block contents. */ strcpy(xmlrpc_mem_block_contents(block), test_string_1); xmlrpc_mem_block_resize(&env, block, 10000); TEST_NO_FAULT(&env); TEST(xmlrpc_mem_block_size(block) == 10000); TEST(xmlrpc_streq(xmlrpc_mem_block_contents(block), test_string_1)); /* Test cleanup code (with help from memprof). */ xmlrpc_mem_block_free(block); /* Allocate a bigger block. */ block = xmlrpc_mem_block_new(&env, 128); TEST_NO_FAULT(&env); TEST(block != NULL); TEST(xmlrpc_mem_block_size(block) == 128); /* Test cleanup code (with help from memprof). */ xmlrpc_mem_block_free(block); /* Allocate a "typed" memory block. */ typed_heap_block = XMLRPC_TYPED_MEM_BLOCK_NEW(void*, &env, 20); TEST_NO_FAULT(&env); TEST(typed_heap_block != NULL); TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 20); typed_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(void*, typed_heap_block); TEST(typed_contents != NULL); /* Resize a typed memory block. */ XMLRPC_TYPED_MEM_BLOCK_RESIZE(void*, &env, typed_heap_block, 100); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 100); /* Test cleanup code (with help from memprof). */ XMLRPC_TYPED_MEM_BLOCK_FREE(void*, typed_heap_block); /* Test _INIT and _CLEAN for stack-based memory blocks. */ XMLRPC_TYPED_MEM_BLOCK_INIT(void*, &env, &typed_auto_block, 30); TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, &typed_auto_block) == 30); XMLRPC_TYPED_MEM_BLOCK_CLEAN(void*, &typed_auto_block); /* Test xmlrpc_mem_block_append. */ block = XMLRPC_TYPED_MEM_BLOCK_NEW(int, &env, 5); TEST_NO_FAULT(&env); memcpy(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block), test_int_array_1, sizeof(test_int_array_1)); XMLRPC_TYPED_MEM_BLOCK_APPEND(int, &env, block, test_int_array_2, 3); TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(int, block) == 8); TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block), test_int_array_3, sizeof(test_int_array_3)) == 0); XMLRPC_TYPED_MEM_BLOCK_FREE(int, block); xmlrpc_env_clean(&env); } static char *(base64_triplets[]) = { "", "", "\r\n", "a", "YQ==", "YQ==\r\n", "aa", "YWE=", "YWE=\r\n", "aaa", "YWFh", "YWFh\r\n", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY" "2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY" "2Rl\r\n" "ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=\r\n", NULL}; static void testBase64Conversion(void) { xmlrpc_env env; char ** triplet; xmlrpc_env_init(&env); for (triplet = base64_triplets; *triplet != NULL; triplet += 3) { char * bin_data; char * nocrlf_ascii_data; char * ascii_data; xmlrpc_mem_block * output; bin_data = *triplet; nocrlf_ascii_data = *(triplet + 1); ascii_data = *(triplet + 2); /* Test our encoding routine. */ output = xmlrpc_base64_encode(&env, (unsigned char*) bin_data, strlen(bin_data)); TEST_NO_FAULT(&env); TEST(output != NULL); TEST(xmlrpc_mem_block_size(output) == strlen(ascii_data)); TEST(memcmp(xmlrpc_mem_block_contents(output), ascii_data, strlen(ascii_data)) == 0); xmlrpc_mem_block_free(output); /* Test our newline-free encoding routine. */ output = xmlrpc_base64_encode_without_newlines(&env, (unsigned char*) bin_data, strlen(bin_data)); TEST_NO_FAULT(&env); TEST(output != NULL); TEST(xmlrpc_mem_block_size(output) == strlen(nocrlf_ascii_data)); TEST(memcmp(xmlrpc_mem_block_contents(output), nocrlf_ascii_data, strlen(nocrlf_ascii_data)) == 0); xmlrpc_mem_block_free(output); /* Test our decoding routine. */ output = xmlrpc_base64_decode(&env, ascii_data, strlen(ascii_data)); TEST_NO_FAULT(&env); TEST(output != NULL); TEST(xmlrpc_mem_block_size(output) == strlen(bin_data)); TEST(memcmp(xmlrpc_mem_block_contents(output), bin_data, strlen(bin_data)) == 0); xmlrpc_mem_block_free(output); } /* Now for something broken... */ { xmlrpc_env env2; xmlrpc_mem_block * output; xmlrpc_env_init(&env2); output = xmlrpc_base64_decode(&env2, "====", 4); TEST(output == NULL); TEST_FAULT(&env2, XMLRPC_PARSE_ERROR); xmlrpc_env_clean(&env2); } /* Now for something broken in a really sneaky way... */ { xmlrpc_env env2; xmlrpc_mem_block * output; xmlrpc_env_init(&env2); output = xmlrpc_base64_decode(&env2, "a==", 4); TEST(output == NULL); TEST_FAULT(&env2, XMLRPC_PARSE_ERROR); xmlrpc_env_clean(&env2); } xmlrpc_env_clean(&env); } static void testBoundsChecks(void) { xmlrpc_env env; xmlrpc_value *array; int i1, i2, i3, i4; /* Get an array to work with. */ xmlrpc_env_init(&env); array = xmlrpc_build_value(&env, "(iii)", 100, 200, 300); TEST_NO_FAULT(&env); xmlrpc_env_clean(&env); /* Test xmlrpc_decompose_value with too few values. */ xmlrpc_env_init(&env); xmlrpc_decompose_value(&env, array, "(iiii)", &i1, &i2, &i3, &i4); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_env_clean(&env); /* Test xmlrpc_decompose_value with too many values. */ xmlrpc_env_init(&env); xmlrpc_decompose_value(&env, array, "(ii)", &i1, &i2, &i3, &i4); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_env_clean(&env); /* Dispose of our array. */ xmlrpc_DECREF(array); } static void testNestingLimit(void) { xmlrpc_env env; xmlrpc_value *val; xmlrpc_env_init(&env); /* Test with an adequate limit for a result value which is an array which contains an element which is a struct, whose values are simple: 3. */ xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 3); val = xmlrpc_parse_response(&env, good_response_xml, strlen(good_response_xml)); TEST_NO_FAULT(&env); TEST(val != NULL); xmlrpc_DECREF(val); /* Test with an inadequate limit. */ xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 2); val = xmlrpc_parse_response(&env, good_response_xml, strlen(good_response_xml)); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); /* BREAKME - Will change. */ TEST(val == NULL); /* Reset the default limit. */ xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, XMLRPC_NESTING_LIMIT_DEFAULT); TEST(xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID) == XMLRPC_NESTING_LIMIT_DEFAULT); xmlrpc_env_clean(&env); } static void testXmlSizeLimit(void) { xmlrpc_env env; const char * methodName; xmlrpc_value * paramsP; /* NOTE - This test suite only verifies the last-ditch size-checking code. There should also be matching code in all server (and preferably all client) modules as well. */ /* Set our XML size limit to something ridiculous. */ xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, 6); /* Attempt to parse a call. */ xmlrpc_env_init(&env); xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call), &methodName, ¶msP); TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR); xmlrpc_env_clean(&env); { xmlrpc_value * resultP; int faultCode; const char * faultString; /* Attempt to parse a response. */ xmlrpc_env_init(&env); xmlrpc_parse_response2(&env, good_response_xml, strlen(good_response_xml), &resultP, &faultCode, &faultString); TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR); xmlrpc_env_clean(&env); } /* Reset the default limit. */ xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, XMLRPC_XML_SIZE_LIMIT_DEFAULT); } /*========================================================================= ** test_sample_files **========================================================================= ** Read in a bunch of sample test files and make sure we get plausible ** results. ** ** We use these files to test strange-but-legal encodings, illegal-but- ** allowed-by-Xmlrpc-c encodings, etc. */ /* The test program is designed to be run with the 'test' source directory (which also contains the test program itself) as the current directory. Except on Windows, where the Bin directory (which also contains the test program itself) is supposed to be the current directory. */ #define TESTDATA_DIR "data" static const char * goodRequests[] = { TESTDATA_DIR DIRECTORY_SEPARATOR "req_out_of_order.xml", TESTDATA_DIR DIRECTORY_SEPARATOR "req_no_params.xml", TESTDATA_DIR DIRECTORY_SEPARATOR "req_value_name.xml", NULL }; #define MAX_SAMPLE_FILE_LEN (16 * 1024) static void reportFileOpenError(const char * const path, int const openErrno) { if (runningUnderWindows) { char cwdname[1024]; char * succeeded; succeeded = getcwd(cwdname, sizeof(cwdname)); if (succeeded) fprintf(stderr, "Running in current work directory '%s'\n", cwdname); } fprintf(stderr, "Could not open file '%s'. errno=%d (%s)\n", path, openErrno, strerror(openErrno)); } static void readFile(const char * const path, const char ** const outDataP, size_t * const outSizeP) { static char fileBuff[MAX_SAMPLE_FILE_LEN]; FILE * fileP; size_t bytesRead; fileP = fopen(path, "r"); if (fileP == NULL) { /* Since this error is fairly likely to happen, give an informative error message... */ reportFileOpenError(path, errno); exit(1); } /* Read in one buffer full of data, and make sure that everything fit. (We perform a lazy error/no-eof/zero-length-file test using 'bytesRead'.) */ bytesRead = fread(fileBuff, sizeof(char), MAX_SAMPLE_FILE_LEN, fileP); TEST(0 < bytesRead && bytesRead < MAX_SAMPLE_FILE_LEN); fclose(fileP); *outDataP = fileBuff; *outSizeP = bytesRead; } static void testSampleFiles(void) { xmlrpc_env env; const char ** pathP; xmlrpc_env_init(&env); /* Test our good requests. */ for (pathP = goodRequests; *pathP != NULL; ++pathP) { const char * const path = *pathP; const char * data; size_t dataLen; const char * methodName; xmlrpc_value * params; readFile(path, &data, &dataLen); xmlrpc_parse_call(&env, data, dataLen, &methodName, ¶ms); TEST_NO_FAULT(&env); strfree(methodName); xmlrpc_DECREF(params); } xmlrpc_env_clean(&env); } /*========================================================================= ** test_utf8_coding **========================================================================= ** We need to test our UTF-8 decoder thoroughly. Most of these test ** cases are taken from the UTF-8-test.txt file by Markus Kuhn ** : ** http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt */ #if HAVE_UNICODE_WCHAR typedef struct { char *utf8; wchar_t wcs[16]; } utf8_and_wcs; static utf8_and_wcs good_utf8[] = { /* Greek 'kosme'. */ {"\316\272\341\275\271\317\203\316\274\316\265", {0x03BA, 0x1F79, 0x03C3, 0x03BC, 0x03B5, 0}}, /* First sequences of a given length. */ /* '\000' is not a legal C string. */ {"\302\200", {0x0080, 0}}, {"\340\240\200", {0x0800, 0}}, /* Last sequences of a given length. */ {"\177", {0x007F, 0}}, {"\337\277", {0x07FF, 0}}, /* 0xFFFF is not a legal Unicode character. */ /* Other boundry conditions. */ {"\001", {0x0001, 0}}, {"\355\237\277", {0xD7FF, 0}}, {"\356\200\200", {0xE000, 0}}, {"\357\277\275", {0xFFFD, 0}}, /* Other random test cases. */ {"", {0}}, {"abc", {0x0061, 0x0062, 0x0063, 0}}, {"[\302\251]", {0x005B, 0x00A9, 0x005D, 0}}, {NULL, {0}} }; static char *(bad_utf8[]) = { /* Continuation bytes. */ "\200", "\277", /* Lonely start characters. */ "\300", "\300x", "\300xx", "\340", "\340x", "\340xx", "\340xxx", /* Last byte missing. */ "\340\200", "\340\200x", "\340\200xx", "\357\277", "\357\277x", "\357\277xx", /* Illegal bytes. */ "\376", "\377", /* Overlong '/'. */ "\300\257", "\340\200\257", /* Overlong ASCII NUL. */ "\300\200", "\340\200\200", /* Maximum overlong sequences. */ "\301\277", "\340\237\277", /* Illegal code positions. */ "\357\277\276", /* U+FFFE */ "\357\277\277", /* U+FFFF */ /* UTF-16 surrogates (unpaired and paired). */ "\355\240\200", "\355\277\277", "\355\240\200\355\260\200", "\355\257\277\355\277\277", /* Valid UCS-4 characters (we don't handle these yet). ** On systems with UCS-4 or UTF-16 wchar_t values, we ** may eventually handle these in some fashion. */ "\360\220\200\200", "\370\210\200\200\200", "\374\204\200\200\200\200", NULL }; #endif /* HAVE_UNICODE_WCHAR */ /* This routine is missing on certain platforms. This implementation ** *appears* to be correct. */ #if 0 #ifndef HAVE_WCSNCMP int wcsncmp(wchar_t *wcs1, wchar_t* wcs2, size_t len) { size_t i; /* XXX - 'unsigned long' should be 'uwchar_t'. */ unsigned long c1, c2; for (i=0; i < len; i++) { c1 = wcs1[i]; c2 = wcs2[i]; /* This clever comparison borrowed from the GNU C Library. */ if (c1 == 0 || c1 != c2) return c1 - c2; } return 0; } #endif /* HAVE_WCSNCMP */ #endif static void test_utf8_coding(void) { #if HAVE_UNICODE_WCHAR xmlrpc_env env, env2; utf8_and_wcs *good_data; char **bad_data; char *utf8; wchar_t *wcs; xmlrpc_mem_block *output; xmlrpc_env_init(&env); /* Test each of our valid UTF-8 sequences. */ for (good_data = good_utf8; good_data->utf8 != NULL; good_data++) { utf8 = good_data->utf8; wcs = good_data->wcs; /* Attempt to validate the UTF-8 string. */ xmlrpc_validate_utf8(&env, utf8, strlen(utf8)); TEST_NO_FAULT(&env); /* Attempt to decode the UTF-8 string. */ output = xmlrpc_utf8_to_wcs(&env, utf8, strlen(utf8)); TEST_NO_FAULT(&env); TEST(output != NULL); TEST(wcslen(wcs) == XMLRPC_TYPED_MEM_BLOCK_SIZE(wchar_t, output)); TEST(0 == wcsncmp(wcs, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, output), wcslen(wcs))); xmlrpc_mem_block_free(output); /* Test the UTF-8 encoder, too. */ output = xmlrpc_wcs_to_utf8(&env, wcs, wcslen(wcs)); TEST_NO_FAULT(&env); TEST(output != NULL); TEST(strlen(utf8) == XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output)); TEST(xmlrpc_strneq(utf8, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), strlen(utf8))); xmlrpc_mem_block_free(output); } /* Test each of our illegal UTF-8 sequences. */ for (bad_data = bad_utf8; *bad_data != NULL; bad_data++) { utf8 = *bad_data; /* Attempt to validate the UTF-8 string. */ xmlrpc_env_init(&env2); xmlrpc_validate_utf8(&env2, utf8, strlen(utf8)); TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR); /* printf("Fault: %s\n", env2.fault_string); --Hand-checked */ xmlrpc_env_clean(&env2); /* Attempt to decode the UTF-8 string. */ xmlrpc_env_init(&env2); output = xmlrpc_utf8_to_wcs(&env2, utf8, strlen(utf8)); TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR); TEST(output == NULL); xmlrpc_env_clean(&env2); } xmlrpc_env_clean(&env); #endif /* HAVE_UNICODE_WCHAR */ } static void test_server_cgi_maybe(void) { #ifndef _WIN32 test_server_cgi(); #endif } static void test_client_maybe(void) { #ifndef _WIN32 /* Must get Windows Curl transport working for this to work */ test_client(); #endif } int main(int argc, char ** argv ATTR_UNUSED) { int retval; if (argc-1 > 0) { fprintf(stderr, "There are no arguments.\n"); retval = 1; } else { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_init(&env); testVersion(); testEnv(); testMemBlock(); testBase64Conversion(); printf("\n"); test_value(); testBoundsChecks(); printf("\n"); test_serialize(); test_parse_xml(); test_method_registry(); testNestingLimit(); testXmlSizeLimit(); testSampleFiles(); printf("\n"); test_server_cgi_maybe(); test_abyss(); test_server_abyss(); test_utf8_coding(); printf("\n"); test_client_maybe(); printf("\n"); xmlrpc_term(); /* Summarize our test run. */ printf("Ran %d tests, %d failed, %.1f%% passed\n", total_tests, total_failures, 100.0 - (100.0 * total_failures) / total_tests); /* Print the final result. */ if (total_failures == 0) { printf("OK\n"); retval = 0; } else { retval = 1; printf("FAILED\n"); } xmlrpc_env_clean(&env); } return retval; } /* Copyright (C) 2001 by First Peer, Inc. 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. The name of the author may not be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. */ xmlrpc-c-1.33.14/test/testtool.c000066400000000000000000000036431236133176700164270ustar00rootroot00000000000000#include #include #ifdef _WIN32 # include # include #else # include #endif #include "xmlrpc_config.h" #include "xmlrpc-c/util.h" #include "xmlrpc-c/util_int.h" #include "testtool.h" /* Defines global variable, 'total_tests', 'total_failures' */ /* This is a good place to set a breakpoint. */ void test_failure(const char * const file, unsigned int const line, const char * const label, const char * const statement) { ++total_failures; printf("\n%s:%u: test failure: %s (%s)\n", file, line, label, statement); /* We abort rather than exit so one can tell from a dump or debug session who called us. */ abort(); } void test_fault(xmlrpc_env * const envP, int const expectedCode, const char * const fileName, unsigned int const lineNumber) { ++total_tests; if (!envP->fault_occurred) test_failure(fileName, lineNumber, "no fault occurred", ""); else if (envP->fault_code != expectedCode) test_failure(fileName, lineNumber, "wrong fault occurred", envP->fault_string); else printf("."); xmlrpc_env_clean(envP); xmlrpc_env_init(envP); } void test_null_string(const char * const string, const char * const fileName, unsigned int const lineNumber) { ++total_tests; if (string != NULL) test_failure(fileName, lineNumber, "string not null", string); else printf("."); } struct in_addr test_ipAddrFromDecimal(unsigned int const byte0, unsigned int const byte1, unsigned int const byte2, unsigned int const byte3) { struct in_addr retval; retval.s_addr = htonl((byte0 << 24) + (byte1 << 16) + (byte2 << 8) + (byte3 << 0)); return retval; } xmlrpc-c-1.33.14/test/testtool.h000066400000000000000000000041651236133176700164340ustar00rootroot00000000000000#ifndef TESTTOOL_H_INCLUDED #define TESTTOOL_H_INCLUDED #include #include #include #ifdef _WIN32 # include # include #else #include #endif #include "xmlrpc-c/util.h" #include "xmlrpc-c/util_int.h" extern int total_tests; extern int total_failures; void test_failure(const char * const file, unsigned int const line, const char * const label, const char * const statement); void test_fault(xmlrpc_env * const envP, int const expectedCode, const char * const fileName, unsigned int const lineNumber); void test_null_string(const char * const string, const char * const fileName, unsigned int const lineNumber); #define TEST(statement) \ do { \ ++total_tests; \ if ((statement)) { \ printf("."); \ } else { \ test_failure(__FILE__, __LINE__, "expected", #statement); \ } \ } while (0) #define TEST_NO_FAULT(env) \ do { \ ++total_tests; \ if (!(env)->fault_occurred) { \ printf("."); \ } else { \ test_failure(__FILE__, __LINE__, "fault occurred", \ (env)->fault_string); \ } \ } while (0) #define TEST_EPSILON 1E-5 #define FORCENONZERO(x) (MAX(fabs(x), TEST_EPSILON)) #define FLOATEQUAL(comparand, comparator) \ ((fabs((comparand)-(comparator)))/FORCENONZERO(comparand) < TEST_EPSILON) #define TESTFLOATEQUAL(comparand, comparator) \ TEST(FLOATEQUAL(comparand, comparator)) #define TEST_FAULT(envP, code) \ do { test_fault(envP, code, __FILE__, __LINE__); } while(0) ; #define TEST_NULL_STRING(string) \ do { test_null_string(string, __FILE__, __LINE__); } while(0) ; #define TEST_ERROR(reason) \ do { \ printf("Unable to test at %s/%u. %s", __FILE__, __LINE__, reason); \ abort(); \ } while (0) ; struct in_addr test_ipAddrFromDecimal(unsigned int const byte0, unsigned int const byte1, unsigned int const byte2, unsigned int const byte3); #endif xmlrpc-c-1.33.14/test/value.c000066400000000000000000001352111236133176700156630ustar00rootroot00000000000000/* Copyright information is at the end of the file. */ #include #include #include #include #include "casprintf.h" #include "girstring.h" #include "xmlrpc_config.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/string_int.h" #include "testtool.h" #include "value_datetime.h" #include "value.h" #if HAVE_UNICODE_WCHAR static bool wcsneq(const wchar_t * const comparand, const wchar_t * const comparator, size_t const length) { return(wcsncmp(comparand, comparator, length) == 0); } #endif /* HAVE_UNICODE_WCHAR */ static void test_value_alloc_dealloc(void) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_env_init(&env); /* Test allocation and deallocation (w/memprof). */ v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 5); TEST_NO_FAULT(&env); TEST(v != NULL); xmlrpc_INCREF(v); xmlrpc_DECREF(v); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void test_value_int(void) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_int32 i; xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_INT), "INT")); v = xmlrpc_int_new(&env, (xmlrpc_int32) 25); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_INT); xmlrpc_read_int(&env, v, &i); TEST_NO_FAULT(&env); TEST(i == 25); xmlrpc_DECREF(v); v = xmlrpc_int_new(&env, (xmlrpc_int32) -25); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_INT); xmlrpc_read_int(&env, v, &i); TEST_NO_FAULT(&env); TEST(i == -25); xmlrpc_DECREF(v); v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 10); TEST_NO_FAULT(&env); TEST(v != NULL); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_INT); xmlrpc_decompose_value(&env, v, "i", &i); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(i == 10); xmlrpc_env_clean(&env); } static void test_value_bool(void) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_bool b; /* Test booleans. */ xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_BOOL), "BOOL")); v = xmlrpc_bool_new(&env, (xmlrpc_bool) 1); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_BOOL == xmlrpc_value_type(v)); xmlrpc_read_bool(&env, v, &b); TEST_NO_FAULT(&env); TEST(b); xmlrpc_DECREF(v); v = xmlrpc_build_value(&env, "b", (xmlrpc_bool) 0); TEST_NO_FAULT(&env); TEST(v != NULL); TEST(XMLRPC_TYPE_BOOL == xmlrpc_value_type(v)); xmlrpc_decompose_value(&env, v, "b", &b); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(!b); xmlrpc_env_clean(&env); } static void test_value_double(void) { xmlrpc_value * v; xmlrpc_env env; double d; xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_DOUBLE), "DOUBLE")); v = xmlrpc_double_new(&env, -3.25); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_DOUBLE == xmlrpc_value_type(v)); xmlrpc_read_double(&env, v, &d); TEST_NO_FAULT(&env); TEST(d == -3.25); xmlrpc_DECREF(v); v = xmlrpc_build_value(&env, "d", 1.0); TEST_NO_FAULT(&env); TEST(v != NULL); TEST(XMLRPC_TYPE_DOUBLE == xmlrpc_value_type(v)); xmlrpc_decompose_value(&env, v, "d", &d); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(d == 1.0); xmlrpc_env_clean(&env); } static xmlrpc_value * test_string_new_va(xmlrpc_env * const envP, const char * const format, ...) { va_list args; xmlrpc_value * v; va_start(args, format); v = xmlrpc_string_new_va(envP, format, args); va_end(args); return v; } static void test_value_string_no_null(void) { /* Test strings (without '\0' bytes). */ xmlrpc_value * v; xmlrpc_env env; const char * str; size_t len; xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_STRING), "STRING")); { const char * const simpleAsciiString = "foo"; v = xmlrpc_string_new(&env, simpleAsciiString); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_STRING); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, simpleAsciiString)); xmlrpc_DECREF(v); strfree(str); } { const char * const utf8String = "KOŚĆ"; v = xmlrpc_string_new(&env, utf8String); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_STRING); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, utf8String)); xmlrpc_DECREF(v); strfree(str); } v = xmlrpc_string_new_f(&env, "String %s, number %d", "xyz", 7); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_STRING); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "String xyz, number 7")); xmlrpc_DECREF(v); strfree(str); v = test_string_new_va(&env, "String %s, number %d", "xyz", 7); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_STRING); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "String xyz, number 7")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_build_value(&env, "s", "foo"); TEST_NO_FAULT(&env); TEST(v != NULL); TEST(XMLRPC_TYPE_STRING == xmlrpc_value_type(v)); xmlrpc_decompose_value(&env, v, "s", &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo")); strfree(str); xmlrpc_decompose_value(&env, v, "s#", &str, &len); TEST_NO_FAULT(&env); TEST(len == strlen("foo")); TEST(xmlrpc_streq(str, "foo")); TEST(strlen(str) == strlen("foo")); strfree(str); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void test_value_string_null(void) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_env env2; const char * str; size_t len; /* Test a string with a '\0' byte. */ xmlrpc_env_init(&env); v = xmlrpc_string_new_lp(&env, 7, "foo\0bar"); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_STRING == xmlrpc_value_type(v)); xmlrpc_read_string_lp(&env, v, &len, &str); TEST_NO_FAULT(&env); TEST(len == 7); TEST(memeq(str, "foo\0bar", 7)); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_build_value(&env, "s#", "foo\0bar", (size_t) 7); TEST_NO_FAULT(&env); TEST(v != NULL); TEST(XMLRPC_TYPE_STRING == xmlrpc_value_type(v)); xmlrpc_decompose_value(&env, v, "s#", &str, &len); TEST_NO_FAULT(&env); TEST(memeq(str, "foo\0bar", 7)); TEST(len == 7); strfree(str); /* Test for type error when decoding a string with a zero byte to a ** regular C string. */ xmlrpc_env_init(&env2); xmlrpc_decompose_value(&env2, v, "s", &str); TEST_FAULT(&env2, XMLRPC_TYPE_ERROR); xmlrpc_env_clean(&env2); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void test_value_string_multiline(void) { xmlrpc_env env; xmlrpc_value * v; const char * str; size_t len; xmlrpc_env_init(&env); /* LF line ending */ v = xmlrpc_string_new(&env, "foo\n"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\n")); strfree(str); xmlrpc_read_string_crlf(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\r\n")); strfree(str); xmlrpc_DECREF(v); v = xmlrpc_string_new(&env, "foo\n\n"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\n\n")); strfree(str); xmlrpc_read_string_crlf(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\r\n\r\n")); strfree(str); xmlrpc_DECREF(v); v = xmlrpc_string_new(&env, "foo\nbar"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar")); strfree(str); xmlrpc_read_string_crlf(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\r\nbar")); strfree(str); xmlrpc_DECREF(v); v = xmlrpc_string_new(&env, "foo\nbar\n"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar\n")); strfree(str); xmlrpc_read_string_crlf(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\r\nbar\r\n")); strfree(str); xmlrpc_DECREF(v); v = xmlrpc_string_new(&env, "foo\nbar\nbaz"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar\nbaz")); strfree(str); xmlrpc_read_string_crlf(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\r\nbar\r\nbaz")); strfree(str); xmlrpc_DECREF(v); /* CR line ending */ v = xmlrpc_string_new(&env, "foo\r"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\n")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new(&env, "foo\r\r"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\n\n")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new(&env, "foo\rbar"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new(&env, "foo\rbar\r"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar\n")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new(&env, "foo\rbar\rbaz"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar\nbaz")); xmlrpc_DECREF(v); strfree(str); /* CRLF line ending */ v = xmlrpc_string_new(&env, "foo\r\n"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\n")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new(&env, "foo\r\n\r\n"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\n\n")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new(&env, "foo\r\nbar"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new(&env, "foo\r\nbar\r\n"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar\n")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new(&env, "foo\r\nbar\r\nbaz"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\nbar\nbaz")); xmlrpc_DECREF(v); strfree(str); /* Embedded null */ v = xmlrpc_string_new_lp(&env, 14, "foo\r\n\0bar\r\nbaz"); TEST_NO_FAULT(&env); xmlrpc_read_string_lp(&env, v, &len, &str); TEST_NO_FAULT(&env); TEST(len == 12); TEST(memeq(str, "foo\n\0bar\nbaz", len)); strfree(str); xmlrpc_read_string_lp_crlf(&env, v, &len, &str); TEST_NO_FAULT(&env); TEST(len == 14); TEST(memeq(str, "foo\r\n\0bar\r\nbaz", len)); strfree(str); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void test_value_string_cr(void) { xmlrpc_env env; xmlrpc_value * v; const char * str; size_t len; xmlrpc_env_init(&env); v = xmlrpc_string_new_cr(&env, "foo\r\nbar\r\nbaz"); TEST_NO_FAULT(&env); xmlrpc_read_string(&env, v, &str); TEST_NO_FAULT(&env); TEST(streq(str, "foo\r\nbar\r\nbaz")); xmlrpc_DECREF(v); strfree(str); v = xmlrpc_string_new_lp_cr(&env, 7, "\0foo\rbar"); TEST_NO_FAULT(&env); xmlrpc_read_string_lp(&env, v, &len, &str); TEST_NO_FAULT(&env); TEST(len == 7); TEST(memeq(str, "\0foo\rbar", len)); xmlrpc_DECREF(v); strfree(str); xmlrpc_env_clean(&env); } #if HAVE_UNICODE_WCHAR /* Here is a 3-character, NUL-terminated string, once in UTF-8 chars, and once in UTF-16 wchar_ts. Note that 2 of the UTF-16 characters translate directly to UTF-8 bytes because only the lower 7 bits of each is nonzero, but the middle UTF-16 character translates to two UTF-8 bytes. */ static char utf8_data[] = "[\xC2\xA9]"; static wchar_t wcs_data[] = {'[', 0x00A9, ']', 0x0000}; static void test_value_string_wide_build(void) { xmlrpc_env env; xmlrpc_value * valueP; const wchar_t * wcs; size_t len; xmlrpc_env_init(&env); /* Build with build_value w# */ valueP = xmlrpc_build_value(&env, "w#", wcs_data, (size_t)3); TEST_NO_FAULT(&env); TEST(valueP != NULL); /* Verify it */ xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(wcs != NULL); TEST(len == 3); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_data, len)); free((void*)wcs); xmlrpc_DECREF(valueP); /* Build with build_value w */ valueP = xmlrpc_build_value(&env, "w", wcs_data); TEST_NO_FAULT(&env); TEST(valueP != NULL); /* Verify it */ xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(wcs != NULL); TEST(len == 3); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_data, len)); free((void*)wcs); xmlrpc_DECREF(valueP); } #endif /* HAVE_UNICODE_WCHAR */ static void test_value_string_wide_line(void) { /* Test with various line delimiters */ #if HAVE_UNICODE_WCHAR xmlrpc_env env; xmlrpc_value * valueP; const wchar_t * wcs; size_t len; wchar_t const wcs_lines[] = {'\n', '\r', '\r', '\n', '\0'}; wchar_t const wcs_lines_lf[] = {'\n', '\n', '\n'}; wchar_t const wcs_lines_crlf[] = { '\r', '\n', '\r', '\n', '\r', '\n' }; xmlrpc_env_init(&env); valueP = xmlrpc_string_w_new(&env, wcs_lines); TEST_NO_FAULT(&env); xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(len == 3); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_lines_lf, len)); free((void*)wcs); xmlrpc_read_string_w_lp_crlf(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(len == 6); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_lines_crlf, len)); free((void*)wcs); xmlrpc_DECREF(valueP); valueP = xmlrpc_string_w_new_cr(&env, wcs_lines); TEST_NO_FAULT(&env); xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(len == 4); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_lines, len)); free((void*)wcs); xmlrpc_DECREF(valueP); xmlrpc_env_clean(&env); #endif /* HAVE_UNICODE_WCHAR */ } static void test_value_string_wide(void) { #if HAVE_UNICODE_WCHAR xmlrpc_env env; xmlrpc_value * valueP; const wchar_t * wcs; size_t len; xmlrpc_env_init(&env); /* Build a string from wchar_t data. */ valueP = xmlrpc_string_w_new_lp(&env, 3, wcs_data); TEST_NO_FAULT(&env); TEST(valueP != NULL); /* Extract it as a wchar_t string. */ xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(wcs != NULL); TEST(len == 3); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_data, len)); free((void*)wcs); xmlrpc_read_string_w(&env, valueP, &wcs); TEST_NO_FAULT(&env); TEST(wcs != NULL); TEST(wcs[3] == '\0'); TEST(wcsneq(wcs, wcs_data, 3)); free((void*)wcs); xmlrpc_decompose_value(&env, valueP, "w#", &wcs, &len); TEST_NO_FAULT(&env); TEST(wcs != NULL); TEST(len == 3); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_data, len)); free((void*)wcs); { /* Extract it as a UTF-8 string. */ const char * str; size_t len; xmlrpc_read_string_lp(&env, valueP, &len, &str); TEST_NO_FAULT(&env); TEST(str != NULL); TEST(len == 4); TEST(str[len] == '\0'); TEST(xmlrpc_strneq(str, utf8_data, len)); free((void*)str); } xmlrpc_DECREF(valueP); /* Build from null-terminated wchar_t string */ valueP = xmlrpc_string_w_new(&env, wcs_data); TEST_NO_FAULT(&env); TEST(valueP != NULL); /* Verify it */ xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(wcs != NULL); TEST(len == 3); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_data, len)); free((void*)wcs); xmlrpc_DECREF(valueP); test_value_string_wide_build(); /* Build a string from UTF-8 data. */ valueP = xmlrpc_string_new(&env, utf8_data); TEST_NO_FAULT(&env); TEST(valueP != NULL); /* Extract it as a wchar_t string. */ xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(wcs != NULL); TEST(len == 3); TEST(wcs[len] == 0x0000); TEST(wcsneq(wcs, wcs_data, len)); free((void*)wcs); xmlrpc_DECREF(valueP); /* Test with embedded NUL. We use a length of 4 so that the terminating NUL actually becomes part of the string. */ valueP = xmlrpc_string_w_new_lp(&env, 4, wcs_data); TEST_NO_FAULT(&env); TEST(valueP != NULL); /* Extract it as a wchar_t string. */ xmlrpc_read_string_w_lp(&env, valueP, &len, &wcs); TEST_NO_FAULT(&env); TEST(wcs != NULL); TEST(len == 4); TEST(wcs[len] == '\0'); TEST(wcsneq(wcs, wcs_data, len)); free((void*)wcs); xmlrpc_read_string_w(&env, valueP, &wcs); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_DECREF(valueP); test_value_string_wide_line(); xmlrpc_env_clean(&env); #endif /* HAVE_UNICODE_WCHAR */ } static void test_value_base64(void) { /* Test data. */ unsigned char const data1[5] = {'a', '\0', 'b', '\n', 'c'}; unsigned char const data2[3] = {'a', '\0', 'b'}; xmlrpc_value * v; xmlrpc_env env; const unsigned char * data; size_t len; xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_BASE64), "BASE64")); v = xmlrpc_base64_new(&env, sizeof(data1), data1); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_BASE64 == xmlrpc_value_type(v)); xmlrpc_read_base64(&env, v, &len, &data); TEST_NO_FAULT(&env); TEST(memeq(data, data1, sizeof(data1))); TEST(len == sizeof(data1)); xmlrpc_DECREF(v); free((void*)data); v = xmlrpc_build_value(&env, "6", data2, sizeof(data2)); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_BASE64 == xmlrpc_value_type(v)); xmlrpc_decompose_value(&env, v, "6", &data, &len); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(len == sizeof(data2)); TEST(memeq(data, data1, sizeof(data2))); free((void *)data); xmlrpc_env_clean(&env); } static void test_value_value(void) { xmlrpc_value *v, *v2, *v3; xmlrpc_env env; /* Test 'V' with building and parsing. */ xmlrpc_env_init(&env); v2 = xmlrpc_int_new(&env, (xmlrpc_int32) 5); TEST_NO_FAULT(&env); v = xmlrpc_build_value(&env, "V", v2); TEST_NO_FAULT(&env); TEST(v == v2); xmlrpc_decompose_value(&env, v2, "V", &v3); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(v2 == v3); xmlrpc_DECREF(v3); xmlrpc_DECREF(v2); xmlrpc_env_clean(&env); } static void test_value_array(void) { xmlrpc_value *v; xmlrpc_env env; size_t len; xmlrpc_value * itemP; /* Basic array-building test. */ xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_ARRAY), "ARRAY")); v = xmlrpc_array_new(&env); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(v)); len = xmlrpc_array_size(&env, v); TEST_NO_FAULT(&env); TEST(len == 0); itemP = xmlrpc_int_new(&env, 7); TEST_NO_FAULT(&env); xmlrpc_array_append_item(&env, v, itemP); TEST_NO_FAULT(&env); len = xmlrpc_array_size(&env, v); TEST_NO_FAULT(&env); TEST(len == 1); xmlrpc_DECREF(itemP); xmlrpc_DECREF(v); v = xmlrpc_build_value(&env, "()"); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(v)); len = xmlrpc_array_size(&env, v); TEST_NO_FAULT(&env); TEST(len == 0); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void test_value_AS(void) { xmlrpc_value *v; xmlrpc_value *v2; xmlrpc_value *v3; xmlrpc_env env; size_t len; /* Test parsing of 'A' and 'S'. */ xmlrpc_env_init(&env); v = xmlrpc_build_value(&env, "((){})"); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, v, "(AS)", &v2, &v3); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(v2)); TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(v3)); len = xmlrpc_array_size(&env, v2); TEST_NO_FAULT(&env); TEST(len == 0); len = xmlrpc_struct_size(&env, v3); TEST_NO_FAULT(&env); TEST(len == 0); xmlrpc_DECREF(v2); xmlrpc_DECREF(v3); xmlrpc_env_clean(&env); } static void test_value_AS_typecheck(void) { xmlrpc_env env; xmlrpc_env env2; xmlrpc_value *v; xmlrpc_value *v2; /* Test typechecks for 'A' and 'S'. */ xmlrpc_env_init(&env); xmlrpc_env_init(&env2); v = xmlrpc_build_value(&env, "s", "foo"); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env2, v, "A", &v2); TEST_FAULT(&env2, XMLRPC_TYPE_ERROR); xmlrpc_decompose_value(&env2, v, "S", &v2); TEST_FAULT(&env2, XMLRPC_TYPE_ERROR); xmlrpc_DECREF(v); xmlrpc_env_clean(&env2); xmlrpc_env_clean(&env); } static void test_value_array2(void) { xmlrpc_value * arrayP; xmlrpc_env env; xmlrpc_int32 i, i1, i2, i3, i4, i5; xmlrpc_value * itemP; xmlrpc_value * subarrayP; size_t len; /* A more complex array. */ xmlrpc_env_init(&env); arrayP = xmlrpc_build_value(&env, "(i(ii)i)", (xmlrpc_int32) 10, (xmlrpc_int32) 20, (xmlrpc_int32) 30, (xmlrpc_int32) 40); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(arrayP)); len = xmlrpc_array_size(&env, arrayP); TEST_NO_FAULT(&env); TEST(len == 3); xmlrpc_array_read_item(&env, arrayP, 1, &subarrayP); TEST_NO_FAULT(&env); len = xmlrpc_array_size(&env, subarrayP); TEST_NO_FAULT(&env); TEST(len == 2); xmlrpc_array_read_item(&env, subarrayP, 0, &itemP); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, itemP, "i", &i); xmlrpc_DECREF(itemP); TEST_NO_FAULT(&env); TEST(i == 20); xmlrpc_DECREF(subarrayP); itemP = xmlrpc_array_get_item(&env, arrayP, 0); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, itemP, "i", &i); TEST_NO_FAULT(&env); TEST(i == 10); xmlrpc_decompose_value(&env, arrayP, "(i(ii)i)", &i1, &i2, &i3, &i4); TEST_NO_FAULT(&env); TEST(i1 == 10 && i2 == 20 && i3 == 30 && i4 == 40); xmlrpc_decompose_value(&env, arrayP, "(i(i*)i)", &i1, &i2, &i3); TEST_NO_FAULT(&env); TEST(i1 == 10 && i2 == 20 && i3 == 40); xmlrpc_decompose_value(&env, arrayP, "(i(ii*)i)", &i1, &i2, &i3, &i4); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, arrayP, "(i(iii)i)", &i1, &i2, &i3, &i4, &i5); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_decompose_value(&env, arrayP, "(i(i)i)", &i1, &i2, &i3, &i4, &i5); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_decompose_value(&env, arrayP, "(i(ii)i*i)", &i1, &i2, &i3, &i4, &i5); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, arrayP, "(i(iiQ)i*i)", &i1, &i2, &i3, &i4, &i5); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, arrayP, "(", &i1, &i2, &i3, &i4, &i5); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, arrayP, "(i", &i1, &i2, &i3, &i4, &i5); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, arrayP, "(i*", &i1, &i2, &i3, &i4, &i5); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Test bounds check on xmlrpc_array_get_item. */ xmlrpc_array_read_item(&env, arrayP, 3, &itemP); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_array_get_item(&env, arrayP, 3); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_array_get_item(&env, arrayP, -1); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_DECREF(arrayP); xmlrpc_env_clean(&env); } static void test_value_array_nil(void) { xmlrpc_value * arrayP; xmlrpc_env env; xmlrpc_int32 i1, i2; xmlrpc_value * itemP; size_t len; xmlrpc_env_init(&env); arrayP = xmlrpc_build_value(&env, "(nini)", (xmlrpc_int32) 10, (xmlrpc_int32) 20); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(arrayP)); len = xmlrpc_array_size(&env, arrayP); TEST_NO_FAULT(&env); TEST(len == 4); itemP = xmlrpc_array_get_item(&env, arrayP, 0); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, itemP, "n"); TEST_NO_FAULT(&env); itemP = xmlrpc_array_get_item(&env, arrayP, 1); TEST_NO_FAULT(&env); { int i; xmlrpc_decompose_value(&env, itemP, "i", &i); TEST_NO_FAULT(&env); TEST(i == 10); } xmlrpc_decompose_value(&env, arrayP, "(nini)", &i1, &i2); TEST_NO_FAULT(&env); TEST(i1 == 10 && i2 == 20); /* Test bounds check on xmlrpc_array_get_item. */ xmlrpc_array_read_item(&env, arrayP, 4, &itemP); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_array_get_item(&env, arrayP, 4); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_DECREF(arrayP); xmlrpc_env_clean(&env); } static void destroyMyCptr(void * const context, void * const objectP) { /*---------------------------------------------------------------------------- This is a xmlrpc_cptr_dtor_fn. -----------------------------------------------------------------------------*/ int * const destroyConfirmationP = context; int * const objectIntP = objectP; *destroyConfirmationP = *objectIntP; } static void test_value_cptr(void) { int destroyConfirmation; xmlrpc_value * v; xmlrpc_env env; void * ptr; int myObject; xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_C_PTR), "C_PTR")); myObject = 7; v = xmlrpc_cptr_new(&env, &myObject); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_C_PTR); xmlrpc_DECREF(v); v = xmlrpc_cptr_new_dtor(&env, &myObject, &destroyMyCptr, &destroyConfirmation); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_C_PTR); destroyConfirmation = 3; xmlrpc_DECREF(v); TEST(destroyConfirmation == 7); // the destructor has set this v = xmlrpc_build_value(&env, "p", (void*) 0x00000017); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_C_PTR == xmlrpc_value_type(v)); xmlrpc_decompose_value(&env, v, "p", &ptr); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(ptr == (void*) 0x00000017); xmlrpc_env_clean(&env); } static void test_value_nil(void) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_NIL), "NIL")); v = xmlrpc_nil_new(&env); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_NIL); xmlrpc_DECREF(v); v = xmlrpc_build_value(&env, "n"); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_NIL == xmlrpc_value_type(v)); xmlrpc_decompose_value(&env, v, "n"); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); xmlrpc_env_clean(&env); } static void test_value_i8(void) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_int64 i; xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_I8), "I8")); v = xmlrpc_i8_new(&env, (xmlrpc_int64) 25); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_I8); xmlrpc_read_i8(&env, v, &i); TEST_NO_FAULT(&env); TEST(i == 25); xmlrpc_DECREF(v); v = xmlrpc_i8_new(&env, (xmlrpc_int64) -25); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_I8); xmlrpc_read_i8(&env, v, &i); TEST_NO_FAULT(&env); TEST(i == -25); xmlrpc_DECREF(v); v = xmlrpc_i8_new(&env, (xmlrpc_int64)1 << 40); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_I8); xmlrpc_read_i8(&env, v, &i); TEST_NO_FAULT(&env); TEST(i == (xmlrpc_int64)1 << 40); xmlrpc_DECREF(v); v = xmlrpc_build_value(&env, "I", (xmlrpc_int64) 10); TEST_NO_FAULT(&env); TEST(v != NULL); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_I8); xmlrpc_decompose_value(&env, v, "I", &i); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(i == 10); xmlrpc_env_clean(&env); } static void test_value_type_mismatch(void) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_env env2; char * str; /* Test for one, simple kind of type mismatch error. We assume that ** if one of these typechecks works, the rest work fine. */ xmlrpc_env_init(&env); xmlrpc_env_init(&env2); v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 5); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env2, v, "s", &str); xmlrpc_DECREF(v); TEST_FAULT(&env2, XMLRPC_TYPE_ERROR); xmlrpc_env_clean(&env2); xmlrpc_env_clean(&env); } static void test_value_invalid_type(void) { xmlrpc_value * v; xmlrpc_env env; /* Test invalid type specifier in format string */ xmlrpc_env_init(&env); v = xmlrpc_build_value(&env, "Q"); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_env_clean(&env); } static void test_value_missing_array_delim(void) { xmlrpc_value * v; xmlrpc_env env; /* Test missing close parenthesis on array */ xmlrpc_env_init(&env); v = xmlrpc_build_value(&env, "("); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); v = xmlrpc_build_value(&env, "(i"); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_env_clean(&env); } static void test_value_missing_struct_delim(void) { xmlrpc_value * v; xmlrpc_env env; /* Test missing closing brace on struct */ xmlrpc_env_init(&env); v = xmlrpc_build_value(&env, "{"); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); v = xmlrpc_build_value(&env, "{s:i", "key1", 7); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); v = xmlrpc_build_value(&env, "{s:i,s:i", "key1", 9, "key2", -4); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_env_clean(&env); } static void test_value_invalid_struct(void) { xmlrpc_value * v; xmlrpc_env env; /* Note that even though the format strings are invalid, we have to supply the variable arguments that xmlrpc_build_value() will be looking for as it tries to parse it. Otherwise, we get wild memory references and consequent Valgrind flags. */ xmlrpc_env_init(&env); v = xmlrpc_build_value(&env, "{s:ii", "key1", 9, 9); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); v = xmlrpc_build_value(&env, "{si:", "key1", 9); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); v = xmlrpc_build_value(&env, "{s", "key1"); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_env_clean(&env); } static void testFailedParseValue(void) { xmlrpc_env env; xmlrpc_value * valueP; const char * stringval; int integerval; xmlrpc_env_init(&env); valueP = xmlrpc_build_value(&env, "{s:s}", "string", "stringval"); TEST_NO_FAULT(&env); /* Fail because "integer" member is missing */ xmlrpc_parse_value(&env, valueP, "{s:s,s:i,*}", "string", &stringval, "integer", &integerval); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_DECREF(valueP); xmlrpc_env_clean(&env); } static void test_value_parse_value(void) { xmlrpc_env env; xmlrpc_value * valueP; const char * datestring = "19980717T14:08:55"; xmlrpc_env_init(&env); valueP = xmlrpc_build_value(&env, "(idb8ss#6(i){s:i}np(i))", 7, 3.14, (xmlrpc_bool)1, datestring, "hello world", "a\0b", (size_t)3, "base64 data", strlen("base64 data"), 15, "member9", 9, &valueP, -5); TEST_NO_FAULT(&env); { xmlrpc_int32 i; xmlrpc_double d; xmlrpc_bool b; const char * dt_str; const char * s1; const char * s2; size_t s2_len; const unsigned char * b64; size_t b64_len; xmlrpc_value * arrayP; xmlrpc_value * structP; void * cptr; xmlrpc_value * subvalP; xmlrpc_parse_value(&env, valueP, "(idb8ss#6ASnpV)", &i, &d, &b, &dt_str, &s1, &s2, &s2_len, &b64, &b64_len, &arrayP, &structP, &cptr, &subvalP); TEST_NO_FAULT(&env); TEST(i == 7); TEST(d == 3.14); TEST(b == (xmlrpc_bool)1); TEST(streq(dt_str, datestring)); TEST(streq(s1, "hello world")); TEST(s2_len == 3); TEST(memeq(s2, "a\0b", 3)); TEST(b64_len == strlen("base64 data")); TEST(memeq(b64, "base64 data", b64_len)); TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(arrayP)); TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(structP)); TEST(cptr == &valueP); TEST(XMLRPC_TYPE_ARRAY == xmlrpc_value_type(subvalP)); xmlrpc_DECREF(valueP); } testFailedParseValue(); xmlrpc_env_clean(&env); } static void test_struct_get_element(xmlrpc_value * const structP, xmlrpc_value * const fooValueP, xmlrpc_value * const weirdValueP, const char * const weirdKey, unsigned int const weirdKeyLen) { xmlrpc_env env; xmlrpc_value * valueP; xmlrpc_value * fooStringP; xmlrpc_value * bogusKeyStringP; xmlrpc_env_init(&env); /* build test tools */ fooStringP = xmlrpc_build_value(&env, "s", "foo"); TEST_NO_FAULT(&env); bogusKeyStringP = xmlrpc_build_value(&env, "s", "doesn't_exist"); TEST_NO_FAULT(&env); /* "find" interface */ xmlrpc_struct_find_value(&env, structP, "foo", &valueP); TEST_NO_FAULT(&env); TEST(valueP == fooValueP); xmlrpc_DECREF(valueP); xmlrpc_struct_find_value(&env, structP, "doesn't_exist", &valueP); TEST_NO_FAULT(&env); TEST(valueP == NULL); xmlrpc_struct_find_value_v(&env, structP, fooStringP, &valueP); TEST_NO_FAULT(&env); TEST(valueP == fooValueP); xmlrpc_DECREF(valueP); xmlrpc_struct_find_value_v(&env, structP, bogusKeyStringP, &valueP); TEST_NO_FAULT(&env); TEST(valueP == NULL); xmlrpc_struct_find_value(&env, fooValueP, "foo", &valueP); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); /* "read" interface */ xmlrpc_struct_read_value(&env, structP, "foo", &valueP); TEST_NO_FAULT(&env); TEST(valueP == fooValueP); xmlrpc_DECREF(valueP); xmlrpc_struct_read_value(&env, structP, "doesn't_exist", &valueP); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_struct_read_value_v(&env, structP, fooStringP, &valueP); TEST_NO_FAULT(&env); TEST(valueP == fooValueP); xmlrpc_DECREF(valueP); xmlrpc_struct_read_value_v(&env, structP, bogusKeyStringP, &valueP); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); xmlrpc_struct_read_value(&env, fooValueP, "foo", &valueP); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); /* obsolete "get" interface. Note that it does not update the reference count of the xmlrpc_value it returns. */ valueP = xmlrpc_struct_get_value(&env, structP, "foo"); TEST_NO_FAULT(&env); TEST(valueP == fooValueP); valueP = xmlrpc_struct_get_value(&env, structP, "doesn't_exist"); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); valueP = xmlrpc_struct_get_value(&env, fooValueP, "foo"); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); valueP = xmlrpc_struct_get_value_n(&env, structP, weirdKey, weirdKeyLen); TEST_NO_FAULT(&env); TEST(valueP == weirdValueP); /* Clean up */ xmlrpc_DECREF(fooStringP); xmlrpc_DECREF(bogusKeyStringP); xmlrpc_env_clean(&env); } static void testStructReadout(xmlrpc_value * const structP, unsigned int const expectedSize) { xmlrpc_env env; xmlrpc_value * keyP; xmlrpc_value * valueP; unsigned int index; xmlrpc_env_init(&env); for (index = 0; index < expectedSize; ++index) { xmlrpc_struct_read_member(&env, structP, index, &keyP, &valueP); TEST_NO_FAULT(&env); xmlrpc_DECREF(keyP); xmlrpc_DECREF(valueP); } xmlrpc_struct_read_member(&env, structP, expectedSize, &keyP, &valueP); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); for (index = 0; index < expectedSize; ++index) { xmlrpc_struct_get_key_and_value(&env, structP, index, &keyP, &valueP); TEST_NO_FAULT(&env); } xmlrpc_env_clean(&env); } static void test_struct_decompose_invalid_format_string( xmlrpc_value * const testStructP) { xmlrpc_env env; xmlrpc_int32 ival; xmlrpc_bool bval; char * sval; xmlrpc_env_init(&env); /* Premature end of format string: */ xmlrpc_decompose_value(&env, testStructP, "{"); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, testStructP, "{s", "baz"); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, testStructP, "{s:", "baz"); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, testStructP, "{s:", "baz"); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, testStructP, "{s:b", "baz", &bval); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, testStructP, "{s:b,", "baz", &bval); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_decompose_value(&env, testStructP, "{s:b,*", "baz", &bval); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Key not 's' */ xmlrpc_decompose_value(&env, testStructP, "{i:s,s:i,*}", "baz", &sval, "foo", &ival); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Missing colon */ xmlrpc_decompose_value(&env, testStructP, "{is,s:i,*}", "baz", &sval, "foo", &ival); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Missing comma */ xmlrpc_decompose_value(&env, testStructP, "{i:ss:i,*}", "baz", &sval, "foo", &ival); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* Undefined format specifier */ xmlrpc_decompose_value(&env, testStructP, "{s:Q,*}", "baz", &sval); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); /* No * at end */ xmlrpc_decompose_value(&env, testStructP, "{s:b,s:s,s:i}", "baz", &bval, "foo", &sval, "bar", &ival); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_env_clean(&env); } static void test_struct_decompose(xmlrpc_value * const testStructP) { xmlrpc_env env; xmlrpc_int32 ival; xmlrpc_bool bval; char * sval; xmlrpc_value * topStructP; xmlrpc_value * value1P; xmlrpc_env_init(&env); /* Make a test struct */ topStructP = xmlrpc_build_value(&env, "{s:S,s:s}", "key1", testStructP, "key2", "my_string_value"); TEST_NO_FAULT(&env); test_struct_decompose_invalid_format_string(testStructP); /* Decompose a struct */ xmlrpc_decompose_value(&env, testStructP, "{s:b,s:s,s:i,*}", "baz", &bval, "foo", &sval, "bar", &ival); TEST_NO_FAULT(&env); TEST(ival == 1); TEST(!bval); TEST(streq(sval, "Hello!")); free(sval); /* Decompose a deep struct */ xmlrpc_decompose_value(&env, topStructP, "{s:S,*}", "key1", &value1P); TEST_NO_FAULT(&env); TEST(xmlrpc_value_type(value1P) == XMLRPC_TYPE_STRUCT); xmlrpc_DECREF(value1P); xmlrpc_decompose_value(&env, topStructP, "{s:{s:b,s:s,s:i,*},*}", "key1", "baz", &bval, "foo", &sval, "bar", &ival); TEST_NO_FAULT(&env); TEST(ival == 1); TEST(!bval); TEST(streq(sval, "Hello!")); free(sval); /* First value of wrong type */ xmlrpc_decompose_value(&env, testStructP, "{s:b,s:i,*}", "baz", &sval, "foo", &ival); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); /* Subsequent value of wrong type */ xmlrpc_decompose_value(&env, testStructP, "{s:s,s:i,*}", "foo", &sval, "baz", &bval); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); /* Nonexistent key */ xmlrpc_decompose_value(&env, testStructP, "{s:b,s:i,*}", "baz", &bval, "nosuch", &sval); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); /* Error subsequent to nested value */ xmlrpc_decompose_value(&env, topStructP, "{s:{s:s,*},s:i,*}", "key1", "foo", &sval, "key2", &ival); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_DECREF(topStructP); xmlrpc_env_clean(&env); } static void test_struct (void) { xmlrpc_env env; xmlrpc_value * value1P; xmlrpc_value *s, *i, *i1, *i2, *i3, *key, *value; size_t size; int present; xmlrpc_bool bval; char const weirdKey[] = {'f', 'o', 'o', '\0', 'b', 'a', 'r'}; xmlrpc_env_init(&env); /* Create a struct. */ s = xmlrpc_struct_new(&env); TEST_NO_FAULT(&env); TEST(s != NULL); TEST(XMLRPC_TYPE_STRUCT == xmlrpc_value_type(s)); size = xmlrpc_struct_size(&env, s); TEST_NO_FAULT(&env); TEST(size == 0); /* Create some elements to insert into our struct. */ i1 = xmlrpc_build_value(&env, "s", "Item #1"); TEST_NO_FAULT(&env); i2 = xmlrpc_build_value(&env, "s", "Item #2"); TEST_NO_FAULT(&env); i3 = xmlrpc_build_value(&env, "s", "Item #3"); TEST_NO_FAULT(&env); /* Insert a single item. */ xmlrpc_struct_set_value(&env, s, "foo", i1); TEST_NO_FAULT(&env); size = xmlrpc_struct_size(&env, s); TEST_NO_FAULT(&env); TEST(size == 1); /* Insert an item whose key has the same hash value as "foo". */ xmlrpc_struct_set_value(&env, s, "qmdebdw", i2); TEST_NO_FAULT(&env); size = xmlrpc_struct_size(&env, s); TEST_NO_FAULT(&env); TEST(size == 2); i = xmlrpc_struct_get_value(&env, s, "foo"); TEST_NO_FAULT(&env); TEST(i == i1); i = xmlrpc_struct_get_value(&env, s, "qmdebdw"); TEST_NO_FAULT(&env); TEST(i == i2); /* Replace an existing element with a different element. */ xmlrpc_struct_set_value(&env, s, "foo", i3); TEST_NO_FAULT(&env); size = xmlrpc_struct_size(&env, s); TEST_NO_FAULT(&env); TEST(size == 2); i = xmlrpc_struct_get_value(&env, s, "foo"); TEST_NO_FAULT(&env); TEST(i == i3); /* Insert an item with a NUL in the key */ xmlrpc_struct_set_value_n(&env, s, weirdKey, sizeof(weirdKey), i2); TEST_NO_FAULT(&env); size = xmlrpc_struct_size(&env, s); TEST_NO_FAULT(&env); TEST(size == 3); test_struct_get_element(s, i3, i2, weirdKey, sizeof(weirdKey)); /* Replace an existing element with the same element (tricky). */ xmlrpc_struct_set_value(&env, s, "foo", i3); TEST_NO_FAULT(&env); size = xmlrpc_struct_size(&env, s); TEST_NO_FAULT(&env); TEST(size == 3); i = xmlrpc_struct_get_value(&env, s, "foo"); TEST_NO_FAULT(&env); TEST(i == i3); /* Test for the presence and absence of elements. */ present = xmlrpc_struct_has_key(&env, s, "foo"); TEST_NO_FAULT(&env); TEST(present); present = xmlrpc_struct_has_key(&env, s, "qmdebdw"); TEST_NO_FAULT(&env); TEST(present); present = xmlrpc_struct_has_key(&env, s, "bogus"); TEST_NO_FAULT(&env); TEST(!present); /* Make sure our typechecks work correctly. */ xmlrpc_struct_size(&env, i1); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_struct_has_key(&env, i1, "foo"); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_struct_set_value(&env, i1, "foo", i2); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_struct_set_value_v(&env, s, s, i2); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); /* Test cleanup code (w/memprof). */ xmlrpc_DECREF(s); s = xmlrpc_build_value(&env, "{s:s,s:i,s:b}", "foo", "Hello!", "bar", (xmlrpc_int32) 1, "baz", (xmlrpc_bool) 0); TEST_NO_FAULT(&env); TEST(s != NULL); TEST(xmlrpc_value_type(s) == XMLRPC_TYPE_STRUCT); size = xmlrpc_struct_size(&env, s); TEST_NO_FAULT(&env); TEST(size == 3); present = xmlrpc_struct_has_key(&env, s, "foo"); TEST_NO_FAULT(&env); TEST(present); present = xmlrpc_struct_has_key(&env, s, "bar"); TEST_NO_FAULT(&env); TEST(present); present = xmlrpc_struct_has_key(&env, s, "baz"); TEST_NO_FAULT(&env); TEST(present); xmlrpc_struct_read_value(&env, s, "baz", &value1P); TEST_NO_FAULT(&env); xmlrpc_read_bool(&env, value1P, &bval); TEST_NO_FAULT(&env); TEST(!bval); xmlrpc_DECREF(value1P); testStructReadout(s, 3); test_struct_decompose(s); /* Test type check. */ xmlrpc_struct_get_key_and_value(&env, i1, 0, &key, &value); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); TEST(key == NULL && value == NULL); /* Test bounds checks. */ xmlrpc_struct_get_key_and_value(&env, s, -1, &key, &value); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); TEST(key == NULL && value == NULL); xmlrpc_struct_get_key_and_value(&env, s, 3, &key, &value); TEST_FAULT(&env, XMLRPC_INDEX_ERROR); TEST(key == NULL && value == NULL); /* Test cleanup code (w/memprof). */ xmlrpc_DECREF(s); xmlrpc_DECREF(i1); xmlrpc_DECREF(i2); xmlrpc_DECREF(i3); xmlrpc_env_clean(&env); } void test_value(void) { printf("Running value tests."); test_value_alloc_dealloc(); test_value_int(); test_value_bool(); test_value_double(); test_value_datetime(); test_value_string_no_null(); test_value_string_null(); test_value_string_multiline(); test_value_string_cr(); test_value_string_wide(); test_value_base64(); test_value_array(); test_value_array2(); test_value_array_nil(); test_value_value(); test_value_AS(); test_value_AS_typecheck(); test_value_cptr(); test_value_nil(); test_value_i8(); test_value_type_mismatch(); test_value_invalid_type(); test_value_missing_array_delim(); test_value_missing_struct_delim(); test_value_invalid_struct(); test_value_parse_value(); test_struct(); printf("\n"); printf("Value tests done.\n"); } xmlrpc-c-1.33.14/test/value.h000066400000000000000000000000301236133176700156560ustar00rootroot00000000000000void test_value(void); xmlrpc-c-1.33.14/test/value_datetime.c000066400000000000000000000255071236133176700175450ustar00rootroot00000000000000#define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include #include "casprintf.h" #include "girstring.h" #include "xmlrpc_config.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/string_int.h" #include "testtool.h" #include "value_datetime.h" static const char * truncateFracSec(const char * const datestring) { /*---------------------------------------------------------------------------- Return 'datestring', but with any fractional seconds chopped off. E.g. if 'datestring' is "20000301T00:00:00.654321", we return "20000301T00:00:00". -----------------------------------------------------------------------------*/ char * buffer; unsigned int i; buffer = strdup(datestring); for (i = 0; i < strlen(buffer); ++i) { if (buffer[i] == '.') buffer[i] = '\0'; } return buffer; } #if XMLRPC_HAVE_TIMEVAL static struct timeval makeTv(time_t const secs, unsigned int const usecs) { struct timeval retval; retval.tv_sec = secs; retval.tv_usec = usecs; return retval; } static bool tvIsEqual(struct timeval const comparand, struct timeval const comparator) { return comparand.tv_sec == comparator.tv_sec && comparand.tv_usec == comparator.tv_usec; } #endif #if XMLRPC_HAVE_TIMESPEC static struct timespec makeTs(time_t const secs, unsigned int const usecs) { struct timespec retval; retval.tv_sec = secs; retval.tv_nsec = usecs * 1000; return retval; } static bool tsIsEqual(struct timespec const comparand, struct timespec const comparator) { return comparand.tv_sec == comparator.tv_sec && comparand.tv_nsec == comparator.tv_nsec; } #endif static const char * make8601(time_t const seconds, unsigned int const usec) { struct tm const tm = *gmtime(&seconds); const char * retval; xmlrpc_asprintf(&retval, "%04u%02u%02uT%02u%02u%02u,%06uZ", 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, usec); return retval; } static void test_value_datetime_varytime(const char * const datestring, time_t const datetime, unsigned int const usec) { xmlrpc_value * v; xmlrpc_env env; const char * readBackString; time_t readBackDt; unsigned int readBackUsec; const char * datestringSec; #if XMLRPC_HAVE_TIMEVAL struct timeval const dtTimeval = makeTv(datetime, usec); struct timeval readBackTv; #endif #if XMLRPC_HAVE_TIMESPEC struct timespec const dtTimespec = makeTs(datetime, usec); struct timespec readBackTs; #endif const char * const dt8601 = make8601(datetime, usec); const char * readBack8601; datestringSec = truncateFracSec(datestring); xmlrpc_env_init(&env); /* Test xmlrpc_datetime_new_str and time read functions*/ v = xmlrpc_datetime_new_str(&env, datestring); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v)); xmlrpc_read_datetime_sec(&env, v, &readBackDt); TEST_NO_FAULT(&env); TEST(readBackDt == datetime); xmlrpc_read_datetime_usec(&env, v, &readBackDt, &readBackUsec); TEST_NO_FAULT(&env); TEST(readBackDt == datetime); TEST(readBackUsec == usec); #if XMLRPC_HAVE_TIMEVAL xmlrpc_read_datetime_timeval(&env, v, &readBackTv); TEST_NO_FAULT(&env); TEST(tvIsEqual(dtTimeval, readBackTv)); #endif #if XMLRPC_HAVE_TIMESPEC xmlrpc_read_datetime_timespec(&env, v, &readBackTs); TEST_NO_FAULT(&env); TEST(tsIsEqual(dtTimespec, readBackTs)); #endif xmlrpc_read_datetime_8601(&env, v, &readBack8601); TEST_NO_FAULT(&env); TEST(xmlrpc_streq(dt8601, readBack8601)); strfree(readBack8601); xmlrpc_DECREF(v); /* Test xmlrpc_datetime_new_sec */ v = xmlrpc_datetime_new_sec(&env, datetime); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v)); xmlrpc_read_datetime_str(&env, v, &readBackString); TEST_NO_FAULT(&env); TEST(streq(readBackString, datestringSec)); strfree(readBackString); xmlrpc_DECREF(v); /* Test xmlrpc_datetime_new_usec */ v = xmlrpc_datetime_new_usec(&env, datetime, usec); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v)); xmlrpc_read_datetime_str(&env, v, &readBackString); TEST_NO_FAULT(&env); TEST(streq(readBackString, datestring)); strfree(readBackString); xmlrpc_DECREF(v); #if XMLRPC_HAVE_TIMEVAL /* Test xmlrpc_datetime_new_timeval */ v = xmlrpc_datetime_new_timeval(&env, dtTimeval); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v)); xmlrpc_read_datetime_str(&env, v, &readBackString); TEST_NO_FAULT(&env); TEST(streq(readBackString, datestring)); strfree(readBackString); xmlrpc_DECREF(v); #endif #if XMLRPC_HAVE_TIMESPEC /* Test xmlrpc_datetime_new_timespec */ v = xmlrpc_datetime_new_timespec(&env, dtTimespec); TEST_NO_FAULT(&env); TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v)); xmlrpc_read_datetime_str(&env, v, &readBackString); TEST_NO_FAULT(&env); TEST(streq(readBackString, datestring)); strfree(readBackString); xmlrpc_DECREF(v); #endif xmlrpc_env_clean(&env); strfree(datestringSec); } static void test_value_datetime_not_unix(const char * const datestring) { xmlrpc_value * v; xmlrpc_env env; time_t dt; xmlrpc_env_init(&env); v = xmlrpc_datetime_new_str(&env, datestring); TEST_NO_FAULT(&env); xmlrpc_read_datetime_sec(&env, v, &dt); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void test_value_datetime_str_invalid1(const char * const datestring) { /* Ideally, xmlrpc_datetime_new_str() would fail on these, but the code doesn't implement that today. However, xmlrpc_read_datetime_sec() does catch many cases, so we use that. Note that xmlrpc_read_datetime_sec() doesn't catch them all. Sometimes it just returns garbage, e.g. returns July 1 for June 31. */ xmlrpc_value * v; xmlrpc_env env; time_t dt; xmlrpc_env_init(&env); v = xmlrpc_datetime_new_str(&env, datestring); TEST_NO_FAULT(&env); xmlrpc_read_datetime_sec(&env, v, &dt); TEST_FAULT(&env, XMLRPC_PARSE_ERROR); xmlrpc_DECREF(v); xmlrpc_env_clean(&env); } static void test_value_datetime_str_invalid2(const char * const datestring) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_env_init(&env); v = xmlrpc_datetime_new_str(&env, datestring); TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR); xmlrpc_env_clean(&env); } static void test_build_decomp_datetime(void) { const char * datestring = "19980717T14:08:55"; time_t const datetime = 900684535; xmlrpc_env env; xmlrpc_value * v; time_t dt; const char * ds; xmlrpc_env_init(&env); v = xmlrpc_build_value(&env, "t", datetime); TEST_NO_FAULT(&env); TEST(v != NULL); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_DATETIME); dt = 0; xmlrpc_read_datetime_sec(&env, v, &dt); TEST(dt == datetime); dt = 0; xmlrpc_decompose_value(&env, v, "t", &dt); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(dt == datetime); v = xmlrpc_int_new(&env, 9); TEST_NO_FAULT(&env); xmlrpc_decompose_value(&env, v, "t", &dt); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_env_clean(&env); xmlrpc_env_init(&env); xmlrpc_decompose_value(&env, v, "8", &ds); TEST_FAULT(&env, XMLRPC_TYPE_ERROR); xmlrpc_env_clean(&env); xmlrpc_env_init(&env); xmlrpc_DECREF(v); v = xmlrpc_build_value(&env, "8", datestring); TEST_NO_FAULT(&env); TEST(v != NULL); TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_DATETIME); xmlrpc_decompose_value(&env, v, "8", &ds); xmlrpc_DECREF(v); TEST_NO_FAULT(&env); TEST(streq(ds, datestring)); strfree(ds); xmlrpc_env_clean(&env); } static void test_value_datetime_basic(void) { xmlrpc_value * v; xmlrpc_env env; xmlrpc_datetime dt; xmlrpc_datetime readBackDt; xmlrpc_env_init(&env); dt.Y = 2001; dt.M = 12; dt.D = 25; dt.h = 1; dt.m = 2; dt.s = 3; dt.u = 4; v = xmlrpc_datetime_new(&env, dt); xmlrpc_read_datetime(&env, v, &readBackDt); TEST_NO_FAULT(&env); TEST(readBackDt.Y = dt.Y); TEST(readBackDt.M = dt.M); TEST(readBackDt.D = dt.D); TEST(readBackDt.h = dt.h); TEST(readBackDt.m = dt.m); TEST(readBackDt.s = dt.s); TEST(readBackDt.u = dt.u); xmlrpc_env_clean(&env); } void test_value_datetime(void) { const char * datestring = "19980717T14:08:55"; time_t const datetime = 900684535; xmlrpc_env env; printf("\n Running datetime value tests"); xmlrpc_env_init(&env); TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_DATETIME), "DATETIME")); test_value_datetime_basic(); /* Valid datetime, generated from XML-RPC string, time_t, and time_t + microseconds */ test_value_datetime_varytime(datestring, datetime, 0); /* test microseconds */ test_value_datetime_varytime("20000301T00:00:00.654321", 951868800, 654321); test_value_datetime_varytime("20040229T23:59:59.123000", 1078099199, 123000); test_value_datetime_varytime("20000229T23:59:59.000123", 951868799, 123); /* Leap years */ test_value_datetime_varytime("20000229T23:59:59", 951868799, 0); test_value_datetime_varytime("20000301T00:00:00", 951868800, 0); test_value_datetime_varytime("20010228T23:59:59", 983404799, 0); test_value_datetime_varytime("20010301T00:00:00", 983404800, 0); test_value_datetime_varytime("20040229T23:59:59", 1078099199, 0); test_value_datetime_varytime("20040301T00:00:00", 1078099200, 0); /* Datetimes that can't be represented as time_t */ test_value_datetime_not_unix("19691231T23:59:59"); /* Invalid datetimes */ /* Note that the code today does a pretty weak job of validating datetimes, so we test only the validation that we know is implemented. */ test_value_datetime_str_invalid1("19700101T25:00:00"); test_value_datetime_str_invalid1("19700101T10:61:01"); test_value_datetime_str_invalid1("19700101T10:59:61"); test_value_datetime_str_invalid1("19700001T10:00:00"); test_value_datetime_str_invalid1("19701301T10:00:00"); test_value_datetime_str_invalid1("19700132T10:00:00"); test_value_datetime_str_invalid2("19700132T10:00:00."); test_value_datetime_str_invalid2("19700132T10:00:00,123"); test_build_decomp_datetime(); xmlrpc_env_clean(&env); printf("\n"); printf(" datetime value tests done.\n"); } xmlrpc-c-1.33.14/test/value_datetime.h000066400000000000000000000001551236133176700175420ustar00rootroot00000000000000#ifndef VALUE_DATETIME_H_INCLUDED #define VALUE_DATETIME_H_INCLUDED void test_value_datetime(void); #endif xmlrpc-c-1.33.14/test/xml_data.c000066400000000000000000000153171236133176700163440ustar00rootroot00000000000000#include #include "xml_data.h" #define RAW_STRING_DATA \ "\r\n" \ "2147483647\r\n" \ "-2147483648\r\n" \ "0\r\n" \ "1\r\n" \ "Hello, world! <&>\r\n" \ "\r\n" \ "YmFzZTY0IGRhdGE=\r\n" \ "\r\n" \ "" \ "19980717T14:08:55" \ "\r\n" \ "\r\n" \ "\r\n" \ "" char const serialized_data[] = RAW_STRING_DATA; char const serialized_call[] = XML_PROLOGUE "\r\n" "gloom&doom\r\n" "\r\n" "10\r\n" "20\r\n" "\r\n" "\r\n"; char const serialized_fault[] = XML_PROLOGUE "\r\n" "\r\n" "\r\n" "faultCode\r\n" "6\r\n" "faultString\r\n" "A fault occurred\r\n" "\r\n" "\r\n" "\r\n"; char const expat_data[] = XML_PROLOGUE RAW_STRING_DATA "\r\n"; char const expat_error_data[] = XML_PROLOGUE \ "abc\r\n"; /* Invalid because there's no closing */ char const good_response_xml[] = XML_PROLOGUE "\r\n" "\r\n" RAW_STRING_DATA "\r\n" "1\r\n" "-1.0\r\n" "0.0\r\n" "1.0\r\n" "\r\n" "ten <&>\r\n" "10\r\n" "twenty\r\n" "20\r\n" "\r\n" "Untagged string\r\n" "\r\n" "\r\n"; #define VALUE_HEADER \ XML_PROLOGUE"\r\n" #define VALUE_FOOTER \ "\r\n" #define MEMBER_HEADER \ VALUE_HEADER"" #define MEMBER_FOOTER \ ""VALUE_FOOTER #define ARBITRARY_VALUE \ "0" char const unparseable_value[] = VALUE_HEADER""VALUE_FOOTER; const char * bad_values[] = { VALUE_HEADER"00"VALUE_FOOTER, VALUE_HEADER""VALUE_FOOTER, VALUE_HEADER"4"VALUE_FOOTER, VALUE_HEADER"2147483648"VALUE_FOOTER, VALUE_HEADER"-2147483649"VALUE_FOOTER, VALUE_HEADER" 0"VALUE_FOOTER, VALUE_HEADER"0 "VALUE_FOOTER, VALUE_HEADER"2"VALUE_FOOTER, VALUE_HEADER"-1"VALUE_FOOTER, VALUE_HEADER""VALUE_FOOTER, VALUE_HEADER"0.0 "VALUE_FOOTER, VALUE_HEADER"a"VALUE_FOOTER, VALUE_HEADER"1.1.1"VALUE_FOOTER, VALUE_HEADER"1a"VALUE_FOOTER, VALUE_HEADER"1.1a"VALUE_FOOTER, VALUE_HEADER""VALUE_FOOTER, VALUE_HEADER""VALUE_FOOTER, VALUE_HEADER""VALUE_FOOTER, VALUE_HEADER""VALUE_FOOTER, VALUE_HEADER""VALUE_FOOTER, MEMBER_HEADER MEMBER_FOOTER, MEMBER_HEADER"a"MEMBER_FOOTER, MEMBER_HEADER"a"ARBITRARY_VALUE""MEMBER_FOOTER, MEMBER_HEADER""ARBITRARY_VALUE MEMBER_FOOTER, MEMBER_HEADER"a"MEMBER_FOOTER, MEMBER_HEADER""ARBITRARY_VALUE MEMBER_FOOTER, NULL }; #define RESPONSE_HEADER \ XML_PROLOGUE"\r\n" #define RESPONSE_FOOTER \ "\r\n" #define PARAMS_RESP_HEADER \ RESPONSE_HEADER"" #define PARAMS_RESP_FOOTER \ ""RESPONSE_FOOTER #define FAULT_HEADER \ RESPONSE_HEADER"" #define FAULT_FOOTER \ ""RESPONSE_FOOTER #define FAULT_STRUCT_HEADER \ FAULT_HEADER"" #define FAULT_STRUCT_FOOTER \ ""FAULT_FOOTER const char * bad_responses[] = { XML_PROLOGUE"\r\n", RESPONSE_HEADER RESPONSE_FOOTER, RESPONSE_HEADER""RESPONSE_FOOTER, RESPONSE_HEADER""RESPONSE_FOOTER, /* Make sure we insist on only one parameter in a response. */ PARAMS_RESP_HEADER PARAMS_RESP_FOOTER, PARAMS_RESP_HEADER "0" "0" PARAMS_RESP_FOOTER, /* Test other sorts of bad parameters. */ PARAMS_RESP_HEADER""PARAMS_RESP_FOOTER, PARAMS_RESP_HEADER""PARAMS_RESP_FOOTER, PARAMS_RESP_HEADER""PARAMS_RESP_FOOTER, PARAMS_RESP_HEADER ""ARBITRARY_VALUE ARBITRARY_VALUE"" PARAMS_RESP_FOOTER, /* Basic fault tests. */ FAULT_HEADER FAULT_FOOTER, FAULT_HEADER""FAULT_FOOTER, FAULT_HEADER""FAULT_FOOTER, FAULT_HEADER"1"FAULT_FOOTER, /* Make sure we insist on the proper members within the fault struct. */ FAULT_STRUCT_HEADER "faultString" "foo" FAULT_STRUCT_FOOTER, FAULT_STRUCT_HEADER "faultCode" "0" FAULT_STRUCT_FOOTER, FAULT_STRUCT_HEADER "faultCode" "0" "faultString" "0" FAULT_STRUCT_FOOTER, FAULT_STRUCT_HEADER "faultCode" "0" "faultString" "foo" FAULT_STRUCT_FOOTER, NULL}; #define CALL_HEADER \ XML_PROLOGUE"\r\n" #define CALL_FOOTER \ "\r\n" const char * bad_calls[] = { XML_PROLOGUE"\r\n", CALL_HEADER CALL_FOOTER, CALL_HEADER"m"CALL_FOOTER, CALL_HEADER""CALL_FOOTER, CALL_HEADER""CALL_FOOTER, NULL}; xmlrpc-c-1.33.14/test/xml_data.h000066400000000000000000000011721236133176700163430ustar00rootroot00000000000000#ifndef XML_DATA_H_INCLUDED #define XML_DATA_H_INCLUDED #define XML_PROLOGUE "\r\n" #define APACHE_URL "http://ws.apache.org/xmlrpc/namespaces/extensions" #define XMLNS_APACHE "xmlns:ex=\"" APACHE_URL "\"" extern char const serialized_data[]; extern char const serialized_call[]; extern char const serialized_fault[]; extern char const expat_data[]; extern char const expat_error_data[]; extern char const good_response_xml[]; extern char const unparseable_value[]; extern const char *(bad_values[]); extern const char *(bad_responses[]); extern const char *(bad_calls[]); #endif xmlrpc-c-1.33.14/tools/000077500000000000000000000000001236133176700145615ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/Makefile000066400000000000000000000013461236133176700162250ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') SRCDIR := $(call updir,$(CURDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools include $(BLDDIR)/config.mk SUBDIRS = \ binmode-rpc-kit \ lib \ turbocharger \ xml \ ifeq ($(MUST_BUILD_CLIENT),yes) SUBDIRS += xmlrpc xmlrpc_transport ifeq ($(ENABLE_CPLUSPLUS),yes) SUBDIRS += xml-rpc-api2cpp xml-rpc-api2txt xmlrpc_cpp_proxy ifeq ($(BUILD_XMLRPC_PSTREAM),yes) SUBDIRS += xmlrpc_pstream endif endif endif .PHONY: all clean distclean install check dep all: $(SUBDIRS:%=%/all) clean: $(SUBDIRS:%=%/clean) distclean: $(SUBDIRS:%=%/distclean) install: $(SUBDIRS:%=%/install) check: dep: $(SUBDIRS:%=%/dep) include $(SRCDIR)/common.mk xmlrpc-c-1.33.14/tools/binmode-rpc-kit/000077500000000000000000000000001236133176700175455ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/binmode-rpc-kit/COPYING000066400000000000000000000026241236133176700206040ustar00rootroot00000000000000Copyright (C) 2001 by Eric Kidd. 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. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. xmlrpc-c-1.33.14/tools/binmode-rpc-kit/Makefile000066400000000000000000000000451236133176700212040ustar00rootroot00000000000000all: clean: distclean: install: dep: xmlrpc-c-1.33.14/tools/binmode-rpc-kit/README000066400000000000000000000022541236133176700204300ustar00rootroot00000000000000Binmode RPC Implementor's Kit ============================= Version: 0.1 Author: Eric Kidd Date: 31 January 2001 The Binmode RPC Implementor's Kit was created as part the xmlrpc-c project. http://xmlrpc-c.sourceforge.net/ The following files are included: README This file COPYING A standard disclaimer, etc. binmode-rpc-rfc.txt The current draft of the standard oct2bin A Perl script for turning the notation used by the standard into actual binary data. binmode-rpc2xml-rpc A script which translates a Binmode RPC packet back into XML. You can use this for dumping wire messages. (It also catches the most obvious ways to misimplement the standard, so try it on your output data.) examples/ Examples and counter-examples from the standard in machine-readable format. If you have any questions, please ask on the xmlrpc-c-devel mailing list: http://xmlrpc-c.sourceforge.net/lists.php Thank you for investigating Binmode RPC. Share and enjoy! xmlrpc-c-1.33.14/tools/binmode-rpc-kit/binmode-rpc-rfc.txt000066400000000000000000000270311236133176700232600ustar00rootroot00000000000000This is a draft, and subject to change. Please do not implement it yet. Thank you! Examples can be found at the bottom of the file. Thank you for your feedback! Eric Kidd eric.kidd@pobox.com 30 January 2001 The Binmode RPC Protocol ======================== Binmode RPC is an ultra-lightweight RPC protocol designed for 100% compatibility with XML-RPC . It emphasizes simplicity, dynamically-typed data, and extreme ease of implementation. Two XML-RPC implementations that implement 'binmode-rpc' may negotiate away the XML part of XML-RPC, and replace it with a simple binary protocol. Design goals: * The complete specification should fit in a 350-line text file. :-) * The protocol should be easy to implement. * The protocol should provide a high degree of compression. * The protocol should be very fast--faster than zlib compression. * The protocol must be implementable in portable ANSI C, with no './configure' checks. * The protocol must not contain any options, variant encodings or similar hair. If you want DCE/RPC, you know where to find it. * All protocol operations must be performed at the byte level (except for UTF-8 encoding and decoding). * The protocol must be semi-readable in a hex dump or Emacs buffer. * The protocol must efficiently encode boxcarred calls that are implemented using 'system.multicall'. * The protocol must enable an efficient encoding for frequently-repeated string values. * The protocol must never be sent to clients or servers which don't understand it. * There must be a way for clients and servers to active the protocol if both ends of the connection understand it. The X-XML-RPC-Extensions Header ------------------------------- (First, we'll need a mechanism for unobtrusively announcing the presence of non-standard capabilities.) An XML-RPC implementation MAY advertise additional, non-standard capabilities using the 'X-XML-RPC-Extensions' header. Rationale: The 'X-XML-RPC-Extensions' header should be available to CGI scripts in the environment variable HTTP_X_XML_RPC_EXTENSIONS. If present, this header MUST contain a comma-separated list of keywords. Parameter information MAY be included, if desired, in the standard fashion used by HTTP 1.1 'Accept-Encoding' headers. X-XML-RPC-Extensions: binmode-rpc X-XML-RPC-Extensions: binmode-rpc, x-telepathic-transport X-XML-RPC-Extensions: binmode-rpc,x-telepathic-transport X-XML-RPC-Extensions: binmode-rpc, x-telepathic-transport;speed=low If a client sends the X-XML-RPC-Extensions header in a request, the server MAY use any of the specified extensions in its response. Rationale: No client may be sent non-standard data without first having advertised the ability to accept it. If the server includes the X-XML-RPC-Extensions header in a response, the client MAY use any of the specified extensions in further requests to that URL. The client MUST NOT assume that the same extensions are available for any other URL on the same server. Rationale: No server may be sent non-standard data without first having advertised the ability to accept it. Furthermore, this permission is URL-specific, since different XML-RPC implementations may be located at different URLs on a single server. The client SHOULD NOT cache extension information about a particular server for an excessive length of time (typically beyond a single program invocation). If the client does cache this information indefinitely, it SHOULD be able to cope if an extension is disabled. Rationale: The XML-RPC implementation used on the server may be changed by the administrator. The 'binmode-rpc' Extension ----------------------- A client or server which sends the 'binmode-rpc' extension MUST accept message bodies of type 'application/x-binmode-rpc' in addition to the regular 'text/xml'. All servers which accept the binmode-rpc extension MUST also accept standard XML-RPC, as described by . The 'application/x-binmode-rpc' Format -------------------------------------- All documents of the type 'application/x-binmode-rpc' MUST begin with the following byte sequence (represented here as a C string): 'binmode-rpc:' This MUST be followed by a Call or a Response, encoded as described below: Call := 'C' String Array A Call consists of a single octet with the ASCII value 'C', followed by a String containing the method name and an Array containing the parameters. Response := 'R' (Value|Fault) A Response MUST contain either a Value or a Fault. Fault := 'F' Struct A Fault contains a regular Struct (with members as specified by the the XML-RPC specification). Trailing data at the end of an 'application/x-binmode-rpc' document MUST be ignored. Byte-Order of Integers ---------------------- (The following integer types don't correspond directly to XML-RPC integers--instead, they'll be used to *build* more complicated types.) SignedLSB := a four-octet, signed, twos'-complement integer, least-significant byte (LSB) first UnsignedLSB := a four-octet, unsigned integer, LSB first Raw integer data is encoded in little-endian format. Rationale: A fixed, mandatory byte ordering is easier to implement than approaches which allow multiple byte orderings, and little-endian CPUs outnumber big-endian CPUs at the time of writing. Values ------ Value := (Integer|Boolean|Double|DateTimeISO8601Binary|Array|Struct| String|Other) Integer := 'I' SignedLSB Boolean := ('t'|'f') Double := 'D' SizeOctet AsciiChar... DateTimeISO8601 := '8' SizeOctet AsciiChar... These two types are encoded with an unsigned size octet followed by the specified number of ASCII characters. The values are encoded in the fashion described by the XML-RPC specification. Rationale: In both these cases, we're punting. Binary floating point formats are highly non-portable, and cannot be easily manipulated by most programming languages. XML-RPC values lack timezone information, and are therefore difficult to convert to a binary format. Binary := 'B' UnsignedLSB Octet... This corresponds to the XML-RPC type, but without any encoding. The UnsignedLSB specifies the number of octets of data. Array := 'A' UnsignedLSB Value... The UnsignedLSB specifies the number of values in the array. Struct := 'S' UnsignedLSB (String,Value)... The UnsignedLSB specifies the number of String,Value pairs in the struct. The strings are keys; the values may be of any type. Other := 'O' String Binary Future XML-RPC types (if any) may be sent a String containing the type name and a Binary block (as above) containing type-specific data. Implementations MUST NOT encode any of the standard types using this construct. Implementations MAY signal an error if data of type Other is encountered. Rationale: This is allowed to cause an error because most applications won't understand the contents anyway. But if new types are added, dumb gateways will be able to manipulate them in encapsulated format (if they so desire). Strings ------- String := (RegularString|RecordedString|RecalledString) We have three types of strings. RegularString := 'U' StringData StringData := UnsignedLSB Utf8Octet... Strings are encoded in UTF-8 format. The UnsignedLSB specifies the number of UTF-8 octets. Implementations SHOULD raise an error if they encounter invalid UTF-8 data (e.g., ISO Latin 1 characters). Rationale: Technically speaking, XML-RPC is limited to plain ASCII characters, and may not contain 8-bit or 16-bit characters in any coding system. But since XML-RPC is based on XML, adding Unicode is a trivial enhancement to the basic protocol, and *somebody* will make it sooner or later. When that day arrives, we want to be able to encode Unicode characters. Implements MUST encode UTF-8 characters using the minimum number of octets. Implementations SHOULD raise an error if they encounter any UTF-8 characters encoded using more than the minimum number of octets. Rationale: Overlong UTF-8 encodings are sometimes used to bypass string validation in security code. They serve no legitimate purpose, either. So to improve the overall security of the Universe, we work hard to discourage them. UTF-8 & Unicode FAQ: http://www.cl.cam.ac.uk/~mgk25/unicode.html RecordedString := '>' CodebookPosition StringData RecalledString := '<' CodebookPosition CodebookPosition := UnsignedOctet The 'binmode' format allows a 256-entry "codebook" of strings. At the start of a data stream, the codebook is empty. When the decoder encounters a RecordedString, it MUST store it into the specified codebook position (and then proceed to decode it as a regular string). When the decoder encounters a RecalledString, it MUST look it up in the specified codebook position. If that codebook position has been set, the implementation MUST use the string value found in the codebook. If the position has not been set, the implementation MUST stop decoding and raise an error. It is legal to change a codebook position once it has been set; the most recent value applies. A RecordedString or a RecalledString may be used anywhere a RegularString may be used. Rationale: XML-RPC data tends to contain large numbers of identical strings. (These are typically the names of members or the names of methods in a multicall.) To get any kind of reasonable data compression, it's necessary to have some way of compressing these values. The codebook mechanism is relatively simple and uncomplicated. Implementations MAY choose not to use this feature when encoding data, but MUST understand it when decoding data. Rationale: On the decoding end of things, this feature is trivial to implement, and must be present for the sake of interoperability. On the encoding end of things, however, making effective use of this feature is slightly trickier, so implementations are allowed (but not encouraged) to omit it. Compliance ---------- Implementations MUST implement all features of this protocol correctly, particularly on the decoding end. In the case of this protocol, a 95% correct implementation is 100% broken. Yes, this statement is redundant. ;-) Examples -------- Non-ASCII octets are specified as in C strings. Continued lines are indicated by a trailing '\'; these should be joined together as one sequence of bytes. binmode-rpc:CU\003\0\0\0addA\002\0\0\0I\002\0\0\0I\002\0\0\0 binmode-rpc:RI\004\0\0\0 binmode-rpc:RFS\002\0\0\0 \ U\011\0\0\0faultCodeI\001\0\0\0 \ U\013\0\0\0faultStringU\021\0\0\0An error occurred binmode-rpc:RA\006\0\0\0 \ >\000\003\0\0\0foo \ >\001\003\0\0\0bar \ <\000 \ >\000\003\0\0\0baz \ <\000 \ <\001 (This deserializes to ['foo', 'bar', 'foo', 'baz', 'baz', 'bar'].) binmode-rpc:RU\042\0\0\0Copyright \302\251 1995 J. Random Hacker (This is based on an example in the Unicode/UTF-8 FAQ (see above).) binmode-rpc:RA\010\0\0\0 \ I\006\0\0\0 \ tf \ D\0042.75 \ 8\02119980717T14:08:55 \ U\003\0\0\0foo \ B\003\0\0\0abc \ S\002\0\0\0U\003\0\0\0runt Counter-Examples ---------------- The following specimens are illegal, and SHOULD be rejected by a compliant implementation. Please test your code. * A different format name: binmode-rpc2:RI\004\0\0\0 * A built-in type incorrectly encoded using 'O': binmode-rpc:ROU\006\0\0\0stringB\003\0\0\0xyz * A recall of an unrecorded string: binmode-rpc:R<\002 * ISO Latin 1 data in a string. (UTF-8 required!) binmode-rpc:RU\041\0\0\0Copyright \251 1995 J. Random Hacker * UTF-8 character encoded with too many octets (based on an example in the Unicode/UTF-8 FAQ): binmode-rpc:RU\041\0\0\0Bad linefeed: \300\212 (too many bytes) A compliant implementation MUST NOT send any of these sequences. xmlrpc-c-1.33.14/tools/binmode-rpc-kit/binmode-rpc2xml-rpc000077500000000000000000000360471236133176700232710ustar00rootroot00000000000000#!/usr/bin/perl -w use strict; # Some constants. my $crlf = "\015\012"; # Try to load our external libraries, but fail gracefully. eval { require Frontier::Client; require MIME::Base64; }; if ($@) { print STDERR <<"EOD"; This script requires Ken MacLeod\'s Frontier::RPC2 module. You can get this from CPAN or from his website at http://bitsko.slc.ut.us/~ken/xml-rpc/ . For installation instructions, see the XML-RPC HOWTO at: http://www.linuxdoc.org/HOWTO/XML-RPC-HOWTO/index.html This script also requires MIME::Base64. You can get this from CPAN. EOD exit 1; } # Parse our command-line arguments. if (@ARGV != 0) { print STDERR "Usage: binmode-rpc2xml-rpc < data.binmode > data.xml\n"; exit 1; } # Perform our I/O in binary mode (hence the name of the protocol). binmode STDIN; # Because we're reading raw binary data. binmode STDOUT; # Because we want our XML left unmolested. # Just suck all our input into one string and glom it together. my $binmode_data = join('', ); # Check for the mandatory header. unless ($binmode_data =~ /^binmode-rpc:/) { die "$0: No 'binmode-rpc:' header present, stopping"; } # Set our decoding-position counter to point just past the header, and # our end pointer to just beyond the end of the entire message. my $position = length('binmode-rpc:'); my $end = length($binmode_data); # Set our starting output indentation to zero (for the pretty-printer). my $indentation = 0; # Build an empty codebook of strings. my @codebook; # Begin the hard work. decode_call_or_response(); # Print a warning if there's leftover data. if ($position != $end) { printf STDERR "binmode-rpc2xml-rpc: warning: Trailing data ignored\n"; } # We're done! exit (0); #-------------------------------------------------------------------------- # Pretty-printing #-------------------------------------------------------------------------- sub escape_string ($) { my ($string) = @_; $string =~ s/&/&/g; $string =~ s/= 0) { die "Perl can't handle 32-bit unsigned integers portably, stopping"; } return $integer; } sub read_signed_lsb () { die "Unexpected end of input" unless ($position + 4 <= $end); my $integer = unpack('V', substr($binmode_data, $position, 4)); $position += 4; die "Weird error decoding integer" unless (defined $integer); return $integer; } sub read_data ($) { my ($length) = @_; die "Unexpected end of input" unless ($position + $length <= $end); my $data = unpack("a$length", substr($binmode_data, $position, $length)); $position += $length; die "Weird error decoding data" unless (defined $data); die "Wrong data length" unless (length($data) == $length); return $data; } sub read_data_w_byte_length () { my $length = read_byte(); return read_data($length); } sub read_data_w_unsigned_lsb_length () { my $length = read_unsigned_lsb(); return read_data($length) } sub read_string_data () { my $string = read_data_w_unsigned_lsb_length(); validate_utf8($string); return $string; } #-------------------------------------------------------------------------- # High-level input routines #-------------------------------------------------------------------------- # These use the low-level input routines to read data from the buffer, # and then convert it into Frontier::RPC2 objects. sub read_value () { my $type = read_character(); #print STDERR "DEBUG: Reading from '$type'\n"; if ($type eq 'I') { return _read_int_value(); } elsif ($type eq 't') { return Frontier::RPC2::Boolean->new(1); } elsif ($type eq 'f') { return Frontier::RPC2::Boolean->new(0); } elsif ($type eq 'D') { return _read_double_value(); } elsif ($type eq '8') { return _read_dateTime_value(); } elsif ($type eq 'B') { return _read_base64_value(); } elsif ($type eq 'A') { return _read_array_value(); } elsif ($type eq 'S') { return _read_struct_value(); } elsif ($type eq 'U') { return _read_regular_string_value(); } elsif ($type eq '>') { return _read_recorded_string_value(); } elsif ($type eq '<') { return _read_recalled_string_value(); } elsif ($type eq 'O') { die "Type 'O' Binmode RPC data not supported"; } else { die "Type '$type' Binmode RPC data does not exist"; } } sub read_value_and_typecheck ($) { my ($wanted_type) = @_; my $value = read_value(); my $value_type = ref($value); die "$0: Expected $wanted_type, got $value_type, stopping" unless ($wanted_type eq $value_type); return $value; } sub _read_int_value () { return Frontier::RPC2::Integer->new(read_signed_lsb); } sub _read_double_value () { return Frontier::RPC2::Double->new(read_data_w_byte_length); } sub _read_dateTime_value () { return Frontier::RPC2::DateTime::ISO8601->new(read_data_w_byte_length); } sub _read_base64_value () { my $binary = read_data_w_unsigned_lsb_length; my $encoded = MIME::Base64::encode_base64($binary, $crlf); return Frontier::RPC2::Base64->new($encoded); } sub _read_array_value () { my $size = read_unsigned_lsb; my @values; for (my $i = 0; $i < $size; $i++) { push @values, read_value; } return \@values; } sub _read_struct_value () { my $size = read_unsigned_lsb; my %struct; for (my $i = 0; $i < $size; $i++) { my $key = read_value_and_typecheck('Frontier::RPC2::String'); $struct{$key->value} = read_value; } return \%struct; } sub _read_regular_string_value () { return Frontier::RPC2::String->new(read_string_data); } sub _read_recorded_string_value () { my $codebook_entry = read_byte; my $string = Frontier::RPC2::String->new(read_string_data); $codebook[$codebook_entry] = $string; return $string; } sub _read_recalled_string_value () { my $codebook_entry = read_byte; my $string = $codebook[$codebook_entry]; unless (defined $string) { die "$0: Attempted to use undefined codebook position $codebook_entry"; } return $string; } #-------------------------------------------------------------------------- # High-level output routines #-------------------------------------------------------------------------- # We don't use Frontier::RPC2's output routines, because we're looking # for maximum readability. This is a debugging tool, after all. sub print_xml_header () { print_xml_line ''; } sub get_escaped_string ($) { my ($value) = @_; return escape_string($value->value); } sub print_simple_value ($$) { my ($tag, $value) = @_; my $string = get_escaped_string($value); print_xml_line "<$tag>$string"; } sub print_value ($) { my ($value) = @_; my $type = ref($value); if ($type eq 'Frontier::RPC2::Integer') { print_simple_value("int", $value); } elsif ($type eq 'Frontier::RPC2::Double') { print_simple_value("double", $value); } elsif ($type eq 'Frontier::RPC2::Boolean') { print_simple_value("boolean", $value); } elsif ($type eq 'Frontier::RPC2::String') { print_simple_value("string", $value); } elsif ($type eq 'Frontier::RPC2::DateTime::ISO8601') { print_simple_value("dateTime.iso8601", $value); } elsif ($type eq 'Frontier::RPC2::Base64') { print_base64_data($value); } elsif ($type eq 'ARRAY') { print_array_value($value); } elsif ($type eq 'HASH') { print_struct_value($value); } else { die "Unxpected type '$type', stopping"; } } sub print_params ($) { my ($params) = @_; die "Wanted array" unless (ref($params) eq 'ARRAY'); print_xml_line ''; push_indentation_level; foreach my $item (@$params) { print_xml_line ''; push_indentation_level; print_value($item); pop_indentation_level; print_xml_line ''; } pop_indentation_level; print_xml_line ''; } sub print_base64_data ($) { my ($value) = @_; print_xml_line ''; push_indentation_level; print_xml_line ''; print $value->value; print_xml_line ''; pop_indentation_level; print_xml_line ''; } sub print_array_value ($) { my ($array) = @_; print_xml_line ''; push_indentation_level; print_xml_line ''; push_indentation_level; print_xml_line ''; push_indentation_level; foreach my $item (@$array) { print_value($item); } pop_indentation_level; print_xml_line ''; pop_indentation_level; print_xml_line ''; pop_indentation_level; print_xml_line ''; } sub print_struct_value ($) { my ($struct) = @_; print_xml_line ''; push_indentation_level; print_xml_line ''; push_indentation_level; for my $key (keys %$struct) { print_xml_line ''; push_indentation_level; my $name = escape_string($key); print_xml_line "$name"; print_value($struct->{$key}); pop_indentation_level; print_xml_line ''; } pop_indentation_level; print_xml_line ''; pop_indentation_level; print_xml_line ''; } #-------------------------------------------------------------------------- # High-level decoder routines #-------------------------------------------------------------------------- # These routines convert Binmode RPC data into the corresponding XML-RPC # documents. sub decode_call_or_response () { my $type = read_character(); if ($type eq 'C') { decode_call(); } elsif ($type eq 'R') { decode_response(); } else { die "$0: Unknown binmode-rpc request type '$type', stopping"; } } sub decode_call () { my $namevalue = read_value_and_typecheck('Frontier::RPC2::String'); my $params = read_value_and_typecheck('ARRAY'); print_xml_header; print_xml_line ''; push_indentation_level; my $name = get_escaped_string($namevalue); print_xml_line "$name"; print_params($params); pop_indentation_level; print_xml_line ''; } sub decode_response () { my $maybe_fault = peek_character; if ($maybe_fault eq 'F') { read_character; my $fault = read_value_and_typecheck('HASH'); print_xml_header; print_xml_line ''; push_indentation_level; print_xml_line ''; push_indentation_level; print_value $fault; pop_indentation_level; print_xml_line ''; pop_indentation_level; print_xml_line ''; } else { my $value = read_value; print_xml_header; print_xml_line ''; push_indentation_level; print_params [$value]; pop_indentation_level; print_xml_line ''; } } #-------------------------------------------------------------------------- # UTF-8 Validation #-------------------------------------------------------------------------- # This is based on the UTF-8 section of the Secure Programs HOWTO. # http://new.linuxnow.com/docs/content/HOWTO/Secure-Programs-HOWTO/ # This code *hasn't* been stress-tested for correctness yet; please see: # http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt # This is not yet good enough to be used as part of a UTF-8 decoder or # security validator, but it's OK to make sure nobody is sending Latin-1. BEGIN { use vars qw{@illegal_initial_bytes @sequence_length_info}; # Bytes are represented as data/mask pairs. @illegal_initial_bytes = (# 10xxxxxx illegal as initial byte of char (80..BF) [0x80, 0xC0], # 1100000x illegal, overlong (C0..C1 80..BF) [0xC0, 0xFE], # 11100000 100xxxxx illegal, overlong (E0 80..9F) [0xE0, 0xFF, 0x80, 0xE0], # 11110000 1000xxxx illegal, overlong (F0 80..8F) [0xF0, 0xFF, 0x80, 0xF0], # 11111000 10000xxx illegal, overlong (F8 80..87) [0xF8, 0xFF, 0x80, 0xF8], # 11111100 100000xx illegal, overlong (FC 80..83) [0xFC, 0xFF, 0x80, 0xFC], # 1111111x illegal; prohibited by spec [0xFE, 0xFE]); # Items are byte, mask, sequence length. @sequence_length_info = (# 110xxxxx 10xxxxxx [0xC0, 0xE0, 2], # 1110xxxx 10xxxxxx 10xxxxxx [0xE0, 0xF0, 3], # 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx [0xF0, 0xF8, 4], # 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx [0xF8, 0xFC, 5], # 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx [0xFC, 0xFE, 6]); } sub validate_utf8 ($) { my ($string) = @_; my $end = length($string); my $i = 0; while ($i < $end) { my $byte = ord(substr($string, $i, 1)); #print STDERR "Checking byte $byte\n"; # Check for illegal bytes at the start of this sequence. NEXT_CANDIDATE: foreach my $illegal_byte_info (@illegal_initial_bytes) { my $offset = 0; for (my $j = 0; $j < @$illegal_byte_info; $j += 2) { my $pattern = $illegal_byte_info->[$j]; my $mask = $illegal_byte_info->[$j+1]; my $data = ord(substr($string, $i+$offset, 1)); #print STDERR " B: $byte P: $pattern M: $mask D: $data\n"; next NEXT_CANDIDATE unless ($data & $mask) == $pattern; $offset++; } die "Illegal UTF-8 sequence (" . substr($string, $i, 2) . ")"; } # Find the length of the sequence, and make sure we have enough data. my $length = 1; foreach my $length_info (@sequence_length_info) { my ($pattern, $mask, $length_candidate) = @$length_info; if (($byte & $mask) == $pattern) { $length = $length_candidate; last; } } die "$0: Unexpected end of UTF-8 sequence, stopping" unless $i + $length <= $end; # Verify the sequence is well-formed. $i++, $length--; while ($length > 0) { die "$0: Malformed UTF-8 sequence, stopping" unless (ord(substr($string, $i, 1)) & 0xC0) == 0x80; $i++, $length--; } } #printf STDERR "DEBUG: Verified $i bytes\n"; } xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/000077500000000000000000000000001236133176700213635ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-1.binmode000066400000000000000000000001201236133176700240010ustar00rootroot00000000000000binmode-rpc:RAItfD2.75819980717T14:08:55UfooBabcSUruntxmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-1.xml000066400000000000000000000015671236133176700232040ustar00rootroot00000000000000 6 1 0 2.75 19980717T14:08:55 foo YWJj run 1 xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-2.binmode000066400000000000000000000000441236133176700240070ustar00rootroot00000000000000binmode-rpc:CUaddAIIxmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-2.xml000066400000000000000000000003721236133176700231760ustar00rootroot00000000000000 add 2 2 xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-3.binmode000066400000000000000000000000221236133176700240040ustar00rootroot00000000000000binmode-rpc:RIxmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-3.xml000066400000000000000000000002441236133176700231750ustar00rootroot00000000000000 4 xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-4.binmode000066400000000000000000000001141236133176700240070ustar00rootroot00000000000000binmode-rpc:RFSU faultCodeIU faultStringUAn error occurredxmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-4.xml000066400000000000000000000006241236133176700232000ustar00rootroot00000000000000 faultString An error occurred faultCode 1 xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-5.binmode000066400000000000000000000000631236133176700240130ustar00rootroot00000000000000binmode-rpc:RA>foo>bar<>baz<<xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-5.xml000066400000000000000000000010161236133176700231750ustar00rootroot00000000000000 foo bar foo baz baz bar xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-6.binmode000066400000000000000000000000641236133176700240150ustar00rootroot00000000000000binmode-rpc:RU"Copyright © 1995 J. Random Hackerxmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/good-6.xml000066400000000000000000000003131236133176700231750ustar00rootroot00000000000000 Copyright © 1995 J. Random Hacker xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/invalid-1.binmode000066400000000000000000000000231236133176700245010ustar00rootroot00000000000000binmode-rpc2:RIxmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/invalid-2.binmode000066400000000000000000000000411236133176700245020ustar00rootroot00000000000000binmode-rpc:ROUstringBxyzxmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/invalid-3.binmode000066400000000000000000000000171236133176700245060ustar00rootroot00000000000000binmode-rpc:R<xmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/invalid-4.binmode000066400000000000000000000000631236133176700245100ustar00rootroot00000000000000binmode-rpc:RU!Copyright 1995 J. Random Hackerxmlrpc-c-1.33.14/tools/binmode-rpc-kit/examples/invalid-5.binmode000066400000000000000000000000631236133176700245110ustar00rootroot00000000000000binmode-rpc:RU!Bad linefeed: (too many bytes)xmlrpc-c-1.33.14/tools/binmode-rpc-kit/oct2bin000077500000000000000000000003531236133176700210340ustar00rootroot00000000000000#!/usr/bin/perl # Turn C-style octal escapes into binary. # Call as "echo -n 'ab\0\001cd' | oct2bin > out.binmode". binmode STDOUT; while (<>) { s/\\(\d\d\d)/chr(oct($1))/ge; s/\\0/chr(0)/ge; s/\\\\/\\/g; print $_; } xmlrpc-c-1.33.14/tools/common.mk000066400000000000000000000011111236133176700163740ustar00rootroot00000000000000CLIENT_LDLIBS = $(shell cat blddir/src/libxmlrpc_client.ldflags) $(LDLIBS_XML) CLIENT_LIBS_DEP = \ $(LIBXMLRPC_CLIENT) \ $(LIBXMLRPC) \ $(LIBXMLRPC_XML) \ $(LIBXMLRPC_UTIL) \ $(BLDDIR)/src/libxmlrpc_client.ldflags \ CLIENTPP_LDLIBS = -Lblddir/src/cpp CLIENTPP_LDLIBS += -lxmlrpc_client++ -lxmlrpc_packetsocket -lxmlrpc++ include $(SRCDIR)/common.mk ifneq ($(OMIT_LIB_RULE),Y) blddir/tools/lib/dumpvalue.o: FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/tools/lib/Makefile $(notdir $@) endif .PHONY: install install: install-common .PHONY: check check: .PHONY: FORCE FORCE: xmlrpc-c-1.33.14/tools/interop-server/000077500000000000000000000000001236133176700175455ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/interop-server/interop-cgi.c000066400000000000000000000146211236133176700221350ustar00rootroot00000000000000/* A CGI which implements all of the test functions need for an interop ** endpoint. */ #include #include #include #include "xmlrpc-c/base.h" #include "xmlrpc-c/cgi.h" #include "version.h" #include "config.h" /* information about this build environment */ /*========================================================================= ** Toolkit Identification **========================================================================= */ static xmlrpc_value * whichToolkit(xmlrpc_env * const env, xmlrpc_value * const param_array, void * const user_data ATTR_UNUSED) { xmlrpc_value * retval; /* Parse our argument array. */ xmlrpc_parse_value(env, param_array, "()"); if (env->fault_occurred) retval = NULL; else { struct utsname utsname; int rc; rc = uname(&utsname); if (rc != 0) { xmlrpc_env_set_fault_formatted(env, XMLRPC_INTERNAL_ERROR, "uname() failed. errno=%d (%s)", errno, strerror(errno)); retval = NULL; } else { /* Assemble our result. */ retval = xmlrpc_build_value(env, "{s:s,s:s,s:s,s:s}", "toolkitDocsUrl", "http://xmlrpc-c.sourceforge.net/", "toolkitName", PACKAGE, "toolkitVersion", XMLRPC_C_VERSION"+", "toolkitOperatingSystem", utsname.sysname); } } return retval; } static char whichToolkit_help[] = "Identify the toolkit used to implement this server. The operating system " "information is based on where the toolkit was compiled, not where it's " "currently running."; /*========================================================================= ** noInParams **========================================================================= ** Test a method with no parameters. */ static xmlrpc_value * noInParams(xmlrpc_env * const env, xmlrpc_value * const param_array, void * const user_data ATTR_UNUSED) { /* Parse our argument array. */ xmlrpc_parse_value(env, param_array, "()"); if (env->fault_occurred) return NULL; /* Assemble our result. */ return xmlrpc_build_value(env, "i", (xmlrpc_int32) 0); } static char noInParams_help[] = "A method with no parameters. Returns an arbitrary int."; /*========================================================================= ** Echo Tests **========================================================================= ** We're lazy--we only implement one actual echo method, but we hook it ** up to lots of different names. */ static xmlrpc_value * echoValue(xmlrpc_env * const env, xmlrpc_value * const param_array, void * const user_data ATTR_UNUSED) { xmlrpc_value *val; /* Parse our argument array. */ xmlrpc_parse_value(env, param_array, "(V)", &val); if (env->fault_occurred) return NULL; /* Create a new reference (because both our parameter list and our ** return value will be DECREF'd when we return). */ xmlrpc_INCREF(val); /* Return our result. */ return val; } static char echoValue_help[] = "Echo an arbitrary XML-RPC value of any type."; static char echoString_help[] = "Echo an arbitrary XML-RPC string."; static char echoInteger_help[] = "Echo an arbitrary XML-RPC integer."; static char echoBoolean_help[] = "Echo an arbitrary XML-RPC boolean value."; static char echoFloat_help[] = "Echo an arbitrary XML-RPC float."; static char echoStruct_help[] = "Echo an arbitrary XML-RPC struct."; static char echoDate_help[] = "Echo an arbitrary XML-RPC date/time value."; static char echoBase64_help[] = "Echo an arbitrary XML-RPC Base64 value."; static char echoStringArray_help[] = "Echo an array of arbitrary XML-RPC strings."; static char echoIntegerArray_help[] = "Echo an array of arbitrary XML-RPC integers."; static char echoFloatArray_help[] = "Echo an array of arbitrary XML-RPC floats."; static char echoStructArray_help[] = "Echo an array of arbitrary XML-RPC structs."; /*========================================================================= ** Server Setup **========================================================================= ** Set up and run our server. */ int main(int const argc ATTR_UNUSED, char ** const argv ATTR_UNUSED) { /* Process our request. */ xmlrpc_cgi_init(XMLRPC_CGI_NO_FLAGS); /* Add a method to identify our toolkit. */ xmlrpc_cgi_add_method_w_doc("interopEchoTests.whichToolkit", &whichToolkit, NULL, "S:", whichToolkit_help); /* Add a whole bunch of test methods. */ xmlrpc_cgi_add_method_w_doc("interopEchoTests.noInParams", &noInParams, NULL, "i:", noInParams_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoValue", &echoValue, NULL, "?", echoValue_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoString", &echoValue, NULL, "s:s", echoString_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoInteger", &echoValue, NULL, "i:i", echoInteger_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoBoolean", &echoValue, NULL, "b:b", echoBoolean_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoFloat", &echoValue, NULL, "d:d", echoFloat_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoStruct", &echoValue, NULL, "S:S", echoStruct_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoDate", &echoValue, NULL, "8:8", echoDate_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoBase64", &echoValue, NULL, "6:6", echoBase64_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoStringArray", &echoValue, NULL, "A:A", echoStringArray_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoIntegerArray", &echoValue, NULL, "A:A", echoIntegerArray_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoFloatArray", &echoValue, NULL, "A:A", echoFloatArray_help); xmlrpc_cgi_add_method_w_doc("interopEchoTests.echoStructArray", &echoValue, NULL, "A:A", echoStructArray_help); xmlrpc_cgi_process_call(); xmlrpc_cgi_cleanup(); return 0; } xmlrpc-c-1.33.14/tools/lib/000077500000000000000000000000001236133176700153275ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/lib/Makefile000066400000000000000000000014151236133176700167700ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') TOOLSDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(TOOLSDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools/lib default: all include $(BLDDIR)/config.mk OMIT_LIB_RULE = Y include $(SRCDIR)/tools/common.mk INCLUDES = \ -Isrcdir/$(SUBDIR)/include \ -Iblddir \ -Isrcdir/include \ -Isrcdir/lib/util/include \ LIBOBJS = \ dumpvalue.o \ .PHONY: all all: $(LIBOBJS) %.o:%.c $(CC) -c $(CFLAGS_ALL) $< # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/tools/common.mk: srcdir blddir include depend.mk .PHONY: dep dep: dep-common .PHONY: clean clean: clean-common .PHONY: distclean distclean: clean distclean-common xmlrpc-c-1.33.14/tools/lib/dumpvalue.c000066400000000000000000000260731236133176700175050ustar00rootroot00000000000000/* dumpvalue() service, which prints to Standard Output the value of an xmlrpc_value. We've put this in a separate module in hopes that it eventually can be used for debugging purposes in other places. */ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include "xmlrpc_config.h" /* information about this build environment */ #include "int.h" #include "casprintf.h" #include "mallocvar.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/string_int.h" #include "dumpvalue.h" static void dumpInt(const char * const prefix, xmlrpc_value * const valueP) { xmlrpc_env env; xmlrpc_int value; xmlrpc_env_init(&env); xmlrpc_read_int(&env, valueP, &value); if (env.fault_occurred) printf("Internal error: unable to extract value of " "integer xmlrpc_value %lx. %s\n", (unsigned long)valueP, env.fault_string); else printf("%sInteger: %d\n", prefix, value); xmlrpc_env_clean(&env); } static void dumpBool(const char * const prefix, xmlrpc_value * const valueP) { xmlrpc_env env; xmlrpc_bool value; xmlrpc_env_init(&env); xmlrpc_read_bool(&env, valueP, &value); if (env.fault_occurred) printf("Internal error: Unable to extract value of " "boolean xmlrpc_value %lx. %s\n", (unsigned long)valueP, env.fault_string); else printf("%sBoolean: %s\n", prefix, value ? "TRUE" : "FALSE"); xmlrpc_env_clean(&env); } static void dumpDouble(const char * const prefix, xmlrpc_value * const valueP) { xmlrpc_env env; xmlrpc_double value; xmlrpc_env_init(&env); xmlrpc_read_double(&env, valueP, &value); if (env.fault_occurred) printf("Internal error: Unable to extract value from " "floating point number xmlrpc_value %lx. %s\n", (unsigned long)valueP, env.fault_string); else printf("%sFloating Point: %f\n", prefix, value); xmlrpc_env_clean(&env); } static void dumpDatetime(const char * const prefix, xmlrpc_value * const valueP) { printf("%sDon't know how to print datetime value %lx.\n", prefix, (unsigned long) valueP); } static size_t nextLineSize(const char * const string, size_t const startPos, size_t const stringSize) { /*---------------------------------------------------------------------------- Return the length of the line that starts at offset 'startPos' in the string 'string', which is 'stringSize' characters long. 'string' in not NUL-terminated. A line begins at beginning of string or after a newline character and runs through the next newline character or end of string. The line includes the newline character at the end, if any. -----------------------------------------------------------------------------*/ size_t i; for (i = startPos; i < stringSize && string[i] != '\n'; ++i); if (i < stringSize) ++i; /* Include the newline */ return i - startPos; } static void dumpMultilineString(const char * const prefix, const char * const value, size_t const length) { size_t cursor; /* Index into value[] */ for (cursor = 0; cursor < length; ) { /* Print one line of buffer */ size_t const lineSize = nextLineSize(value, cursor, length); const char * const printableLine = xmlrpc_makePrintable_lp(&value[cursor], lineSize); printf("%s%s\n", prefix, printableLine); cursor += lineSize; strfree(printableLine); } } static void dumpSimpleString(const char * const value, size_t const length) { const char * const printable = xmlrpc_makePrintable_lp(value, length); printf("'%s'\n", printable); strfree(printable); } static void dumpString(const char * const prefix, xmlrpc_value * const valueP) { xmlrpc_env env; size_t length; const char * value; xmlrpc_env_init(&env); xmlrpc_read_string_lp(&env, valueP, &length, &value); if (env.fault_occurred) printf("Internal error: Unable to extract value from " "string xmlrpc_value %lx. %s\n", (unsigned long)valueP, env.fault_string); else { printf("%sString: ", prefix); if (strlen(value) == length && strchr(value, '\n')) { const char * prefix2; casprintf(&prefix2, "%s ", prefix); printf("\n"); dumpMultilineString(prefix2, value, length); strfree(prefix2); } else dumpSimpleString(value, length); strfree(value); } xmlrpc_env_clean(&env); } static void dumpBase64(const char * const prefix, xmlrpc_value * const valueP) { xmlrpc_env env; const unsigned char * value; size_t length; xmlrpc_env_init(&env); xmlrpc_read_base64(&env, valueP, &length, &value); if (env.fault_occurred) printf("Unable to parse base64 bit string xmlrpc_value %lx. %s\n", (unsigned long)valueP, env.fault_string); else { unsigned int i; printf("%sBit string: ", prefix); for (i = 0; i < length; ++i) printf("%02x", value[i]); free((void*)value); } xmlrpc_env_clean(&env); } static void dumpArray(const char * const prefix, xmlrpc_value * const arrayP) { xmlrpc_env env; unsigned int arraySize; xmlrpc_env_init(&env); XMLRPC_ASSERT_ARRAY_OK(arrayP); arraySize = xmlrpc_array_size(&env, arrayP); if (env.fault_occurred) printf("Unable to get array size. %s\n", env.fault_string); else { int const spaceCount = strlen(prefix); unsigned int i; const char * blankPrefix; printf("%sArray of %u items:\n", prefix, arraySize); casprintf(&blankPrefix, "%*s", spaceCount, ""); for (i = 0; i < arraySize; ++i) { xmlrpc_value * valueP; xmlrpc_array_read_item(&env, arrayP, i, &valueP); if (env.fault_occurred) printf("Unable to get array item %u\n", i); else { const char * prefix2; casprintf(&prefix2, "%s Index %2u ", blankPrefix, i); dumpValue(prefix2, valueP); strfree(prefix2); xmlrpc_DECREF(valueP); } } strfree(blankPrefix); } xmlrpc_env_clean(&env); } static void dumpStructMember(const char * const prefix, xmlrpc_value * const structP, unsigned int const index) { xmlrpc_env env; xmlrpc_value * keyP; xmlrpc_value * valueP; xmlrpc_env_init(&env); xmlrpc_struct_read_member(&env, structP, index, &keyP, &valueP); if (env.fault_occurred) printf("Unable to get struct member %u\n", index); else { int const blankCount = strlen(prefix); const char * prefix2; const char * blankPrefix; casprintf(&blankPrefix, "%*s", blankCount, ""); casprintf(&prefix2, "%s Key: ", blankPrefix); dumpValue(prefix2, keyP); strfree(prefix2); casprintf(&prefix2, "%s Value: ", blankPrefix); dumpValue(prefix2, valueP); strfree(prefix2); strfree(blankPrefix); xmlrpc_DECREF(keyP); xmlrpc_DECREF(valueP); } xmlrpc_env_clean(&env); } static void dumpStruct(const char * const prefix, xmlrpc_value * const structP) { xmlrpc_env env; unsigned int structSize; xmlrpc_env_init(&env); structSize = xmlrpc_struct_size(&env, structP); if (env.fault_occurred) printf("Unable to get struct size. %s\n", env.fault_string); else { unsigned int i; printf("%sStruct of %u members:\n", prefix, structSize); for (i = 0; i < structSize; ++i) { const char * prefix1; if (i == 0) prefix1 = strdup(prefix); else { int const blankCount = strlen(prefix); casprintf(&prefix1, "%*s", blankCount, ""); } dumpStructMember(prefix1, structP, i); strfree(prefix1); } } xmlrpc_env_clean(&env); } static void dumpCPtr(const char * const prefix, xmlrpc_value * const valueP) { xmlrpc_env env; void * value; xmlrpc_env_init(&env); xmlrpc_read_cptr(&env, valueP, &value); if (env.fault_occurred) printf("Unable to parse C pointer xmlrpc_value %lx. %s\n", (unsigned long)valueP, env.fault_string); else printf("%sC pointer: '%lux'\n", prefix, (unsigned long)value); xmlrpc_env_clean(&env); } static void dumpNil(const char * const prefix, xmlrpc_value * const valueP) { xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_read_nil(&env, valueP); if (env.fault_occurred) printf("Internal error: nil value xmlrpc_value %lx " "is not valid. %s\n", (unsigned long)valueP, env.fault_string); else printf("%sNil\n", prefix); xmlrpc_env_clean(&env); } static void dumpI8(const char * const prefix, xmlrpc_value * const valueP) { xmlrpc_env env; xmlrpc_int64 value; xmlrpc_env_init(&env); xmlrpc_read_i8(&env, valueP, &value); if (env.fault_occurred) printf("Internal error: unable to extract value of " "64-bit integer xmlrpc_value %lx. %s\n", (unsigned long)valueP, env.fault_string); else printf("%s64-bit integer: %" XMLRPC_PRId64 "\n", prefix, value); xmlrpc_env_clean(&env); } static void dumpUnknown(const char * const prefix, xmlrpc_value * const valueP) { printf("%sDon't recognize value type %u of xmlrpc_value %lx.\n", prefix, xmlrpc_value_type(valueP), (unsigned long)valueP); printf("%sCan't print it.\n", prefix); } void dumpValue(const char * const prefix, xmlrpc_value * const valueP) { switch (xmlrpc_value_type(valueP)) { case XMLRPC_TYPE_INT: dumpInt(prefix, valueP); break; case XMLRPC_TYPE_BOOL: dumpBool(prefix, valueP); break; case XMLRPC_TYPE_DOUBLE: dumpDouble(prefix, valueP); break; case XMLRPC_TYPE_DATETIME: dumpDatetime(prefix, valueP); break; case XMLRPC_TYPE_STRING: dumpString(prefix, valueP); break; case XMLRPC_TYPE_BASE64: dumpBase64(prefix, valueP); break; case XMLRPC_TYPE_ARRAY: dumpArray(prefix, valueP); break; case XMLRPC_TYPE_STRUCT: dumpStruct(prefix, valueP); break; case XMLRPC_TYPE_C_PTR: dumpCPtr(prefix, valueP); break; case XMLRPC_TYPE_NIL: dumpNil(prefix, valueP); break; case XMLRPC_TYPE_I8: dumpI8(prefix, valueP); break; default: dumpUnknown(prefix, valueP); } } xmlrpc-c-1.33.14/tools/lib/include/000077500000000000000000000000001236133176700167525ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/lib/include/dumpvalue.h000066400000000000000000000002761236133176700211320ustar00rootroot00000000000000#ifndef DUMPVALUE_H_INCLUDED #define DUMPVALUE_H_INCLUDED struct _xmlrpc_value; void dumpValue(const char * const prefix, struct _xmlrpc_value * const valueP); #endif xmlrpc-c-1.33.14/tools/perl_packetsocket/000077500000000000000000000000001236133176700202635ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/perl_packetsocket/PacketSocket.pm000066400000000000000000000072061236133176700232060ustar00rootroot00000000000000############################################################################### # # This Perl module provides a "packet socket" of the kind that # XML-RPC For C/C++ uses for its "packet stream" variation on XML-RPC. # # This module does not use the XML-RPC For C/C++ libraries. It is # pure Perl and layers on top of IO::Socket. # # By Bryan Henderson, San Jose CA 08.03.12. # # Contributed to the public domain by author. # ############################################################################### package IO::PacketSocket; use strict; use warnings; use Exporter; use Carp; use vars qw(@ISA $VERSION @EXPORT); use Errno qw(:POSIX); use English; use IO::Socket::INET $VERSION = 1.00; @ISA = qw(Exporter IO); my ($TRUE, $FALSE) = (1,0); my $ESC = chr(0x1B); # ASCII Escape my $startDelim = $ESC . 'PKT'; my $endDelim = $ESC . 'END'; my $escapedEsc = $ESC . 'ESC'; sub createObject { my ($class, %args) = @_; my $errorRet; # Description of why we can't create the object. Undefined if # we haven't given up yet. my $packetSocket; $packetSocket = {}; bless ($packetSocket, $class); if (defined($args{STREAMSOCKET})) { $packetSocket->{STREAMSOCKET} = $args{STREAMSOCKET}; } else { $errorRet = "You must specify STREAMSOCKET"; } $packetSocket->{RECEIVE_BUFFER} = ''; if ($errorRet && !$args{ERROR}) { carp("Failed to create PacketSocket object. $errorRet"); } if ($args{ERROR}) { $ {$args{ERROR}} = $errorRet; } if ($args{HANDLE}) { $ {$args{HANDLE}} = $packetSocket; } } sub new { my ($class, %args) = @_; $args{HANDLE} = \my $retval; $args{ERROR} = undef; $class->createObject(%args); return $retval; } sub escaped($) { my ($x) = @_; #----------------------------------------------------------------------------- # Return $x, but properly escaped to be inside a packet socket # packet. #----------------------------------------------------------------------------- $x =~ s{$ESC}{$escapedEsc}g; return $x; } sub unescaped($) { my ($x) = @_; #----------------------------------------------------------------------------- # Inverse of escaped() #----------------------------------------------------------------------------- $x =~ s{$escapedEsc}{$ESC}g; return $x; } sub send() { my($this, $payload) = @_; my $retval; my $packet = $startDelim . escaped($payload) . $endDelim; $retval = $this->{STREAMSOCKET}->send($packet); return $retval; } sub havePacket() { my ($this) = @_; return ($this->{RECEIVE_BUFFER} =~ m{$endDelim}); } sub validatePacketStart($) { my ($packetR) = @_; my $delim = substr($$packetR, 0, 4); if ($startDelim !~ m{^$delim}) { die("Received bytes '$delim' are not in any packet. " . "Sender is probably not using a packet socket"); } } sub recv() { my ($this, $payloadR) = @_; my $gotPacket; my $eof; my $escapedPacket; $gotPacket = $FALSE; $eof = $FALSE; while (!$gotPacket && !$eof) { validatePacketStart(\$this->{RECEIVE_BUFFER}); $this->{STREAMSOCKET}->recv(my $buffer, 4096, 0); if ($buffer eq '') { $eof = $TRUE; } else { $this->{RECEIVE_BUFFER} .= $buffer; } validatePacketStart(\$this->{RECEIVE_BUFFER}); if ($this->{RECEIVE_BUFFER} =~ m{^($startDelim)(.*?)($endDelim)(.*)}s) { ($escapedPacket, $this->{RECEIVE_BUFFER}) = ($2, $3); $gotPacket = $TRUE; } } $$payloadR = $eof ? '' : unescaped($escapedPacket); } 1; xmlrpc-c-1.33.14/tools/turbocharger/000077500000000000000000000000001236133176700172505ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/turbocharger/Makefile000066400000000000000000000000441236133176700207060ustar00rootroot00000000000000all: clean: distclean: install: dep:xmlrpc-c-1.33.14/tools/turbocharger/README000066400000000000000000000026571236133176700201420ustar00rootroot00000000000000XML-RPC Turbocharger (Experimental) =================================== This a hacked copy of mod_gzip. In addition to the usual "gzip" encoding, it also handles "deflate" encoding. When used in conjuction with the xmlrpc-c client, this should reduce your outbound XML-RPC network traffic by an amazing amount--compression ratios of 10:1 and 30:1 are not unheard of. If you're clever, you should be able to use this with just about any Apache-based XML-RPC server. You can find the standard distribution of mod_gzip here: http://www.remotecommunications.com/apache/mod_gzip/ The hacked distribution is installed and used in exactly the same fashion as the regular distribution. There's one extra logging directive available: %{mod_gzip_compression_format}n Compression format chosen by client. Go read the mod_gzip documentation; it should all make sense. If you want to discuss the XML-RPC Turbocharger, please sign up for the xmlrpc-c-devel mailing list at: http://xmlrpc-c.sourceforge.net/ This code is highly experimental, and may do some strange things. You'll probably need to screw around with mod_gzip for a while until you get everything to work. Don't run this on your production web server, OK? Eric Kidd eric.kidd@pobox.com P.S. The Turbocharger appears to dump core in mod_gzip decides to serialize a large response to disk. Do you see what I mean by "experimental" and "don't run this on your production web server"? :-) xmlrpc-c-1.33.14/tools/turbocharger/mod_gzip.c000066400000000000000000010452061236133176700212340ustar00rootroot00000000000000/* ==================================================================== * Copyright (c) 1995-2000 The Apache Group. 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. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED 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 APACHE GROUP OR * ITS 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. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see . * */ /* * mod_gzip.c * * Apache gzip compression module. * * This module adds 'on the fly' compression of HTTP content to * any Apache Web Server. It uses the IETF Content-encoding standard(s). * * It will compress both static files and the output of any CGI * program inclding shell scripts, perl scripts, executables, * PHP used as CGI, etc. * * There is NO client-side software required for using this module * other than any fully HTTP 1.1 compliant user agent. * * Any fully HTTP 1.1 compliant user agent will be able to receive and * automatically decode the compressed content. * * All fully HTTP 1.1 compliant user agents that are capable of receiving * gzip encoded data will indicate their ability to do so by adding the * standard "Accept-Encoding: gzip" field to the inbound request header. * * This module may be compiled as a stand-alone external 'plug-in' * or be compiled into the Apache core server as a 'built-in' module. * * Sponsor: Remote Communications, Inc. http://www.RemoteCommunications.com/ * Authors: Konstantin Balashov, Alex Kosobrukhov and Kevin Kiley. * Contact: info@RemoteCommunications.com * * Initial public release date: 13-Oct-2000 * * Miscellaneous release notes: * * THIS IS A COMPLETELY SELF-CONTAINED MODULE. MOD_GZIP.C IS THE * ONY SOURCE CODE FILE THERE IS AND THERE ARE NO MODULE SPECIFIC * HEADER FILES OR THE NEED FOR ANY 3RD PARTY COMPRESSION LIBRARIES. * ALL OF THE COMPRESSION CODE NEEDED BY THIS MODULE IS CONTAINED * WITHIN THIS SINGLE SOURCE FILE. * * Many standard compression libraries are not designed or optimized * for use as real-time compression codecs nor are they guaranteed * to be 'thread-safe'. The internal compression code used by mod_gzip * is all of those things. It is a highly-optimized and thread-safe * implementation of the standard LZ77 + Huffman compression * technique that has come to be known as GZIP. * * MOD_GZIP LOG FORMATS... * * mod_gzip makes a number of statistical items for each transaction * available through the use of Apache's 'LogFormat' directives which * can be specified in the httpd.conf Apache config file * * mod_gzip uses the standard Apache NOTES interface to allow compression * information to be added to the Apache Web Server log files. * * Standard NOTES may be added to Apache logs using the following syntax * in any LogFormat directive... * * %...{Foobar}n: The contents of note "Foobar" from another module. * * Additional notes about logging compression information... * * The Apache LogFormat directive is unable to actually display * the 'percent' symbol since it is used exclusively as a 'pickup' * character in the formatting string and cannot be 'escaped' so * all logging of compression ratios cannot use the PERCENT symbol. * Use ASCII 'pct.' designation instead for all PERCENTAGE values. * * Example: This will display the compression ratio percentage along * with the standard CLF ( Common Log Format ) information... * * Available 'mod_gzip' compression information 'notes'... * * %{mod_gzip_result}n - A short 'result' message. Could be OK or DECLINED, etc. * %{mod_gzip_input_size}n - The size ( in bytes ) of the requested object. * %{mod_gzip_output_size}n - The size ( in bytes ) of the compressed version. * %{mod_gzip_compression_ration}n - The compression rate achieved. * * LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info1 * LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info2 * * If you create your own custom 'LogFormat' lines don't forget that * the entire LogFormat line must be encased in quote marks or you * won't get the right results. The visible effect of there not being * and end-quote on a LogFormat line is that the NAME you are choosing * for the LogFormat line is the only thing that will appear in the * log file that tries to use the unbalanced line. * * Also... when using the %{mod_gzip_xxxxx}n note references in your * LogFormat line don't forget to add the lowercase letter 'n' after * the closing bracket to indicate that this is a module 'note' value. * * Once a LogFormat directive has been added to your httpd.conf file * which displays whatever level of compression information desired * simply use the 'name' associated with that LogFormat line in * the 'CustomLog' directive for 'access.log'. * * Example: The line below simply changes the default access.log format * for Apache to the special mog_gzip information record defined above... * CustomLog logs/access.log common * * CustomLog logs/access.log common_with_mod_gzip_info2 * * Using the 'common_with_mod_gzip_info1' LogFormat line for Apache's * normal access.log file produces the following results in the access.log * file when a gigantic 679,188 byte online CD music collection HTML * document called 'music.htm' is requested and the Server delivers the * file via mod_gzip compressed 93 percent down to only 48,951 bytes... * * 216.20.10.1 [12/Oct...] "GET /music.htm HTTP/1.1" 200 48951 mod_gzip: 93pct. * * The line below shows what will appear in the Apache access.log file * if the more detailed 'common_with_mod_gzip_info2' LogFormat line is used. * The line has been intentionally 'wrapped' for better display below * but would normally appear as a single line entry in access.log. * * 216.20.10.1 [12/Oct...] "GET /music.htm HTTP/1.1" 200 48951 * mod_gzip: OK In:679188 Out:48951:93pct. * * The 'OK' result string shows that the compression was successful. * The 'In:' value is the size (in bytes) of the requested file and * the 'Out:' value is the size (in bytes) after compression followed * by a colon and a number showing that the document was compressed * 93 percent before being returned to the user. * * Please NOTE that if you add any ASCII strings to your LogFormat * string then they will appear in your log file regardless of * whether this module was actually 'called' to process the * transaction or not. If the module was not called to handle the * transaction then the places where the statistical information * associated with the 'NOTES' references would normally appear * will be filled in with 'dashes' to denote 'no value available'. * * MOD_GZIP RUNTIME DEBUG... * * If you set your default Apache logging level to 'LogLevel debug' * in your httpd.conf file then this module will add certain * diagnostic debug messages to your error log for each and every * transaction that is actually passed to the module. * * If Apache does not 'call' this module to handle a particular * transaction then no special log information will appear in * your error log(s) for that transaction. * * MOD_GZIP CONFIGURATION DIRECTIVES... * * The section that follows is a sample mod_gzip configuration * section that will provide basic compression of all static * TEXT and HTML files as well as dynamic compression of most * standard CGI including Shell scripts, Perl, PHP, etc. * * The configuration directives themselves are documented in more * detail in the README and INSTALL files that accompany this module. * * You should be able to simply 'cut and paste' the follwing section * directly into the BOTTOM of your current httpd.conf Apache * configuration file and be able to start using mod_gzip immediately. * # # MOD_GZIP Configuration Directives # # All you should have to do to get up and running using # mod_gzip with some basic STATIC and DYNAMIC compression # capabilites is copy the mod_gzip dynamic library to your # ../modules directory and then add this entire example # configuration section to the BOTTOM of your httpd.conf file. # # Add this entire section including all lines down to where # it says '# End of MOD_GZIP Configuration Directives'. # # The LoadModule command is included here for clarity # but you may want to move it the the BOTTOM of your # current LoadModule list in httpd.conf. # # Change the 'mod_gzip_temp_dir' to the name of a directory # on your machine where temporary workfiles can be created # and destroyed. This directory MUST be readable/writable # by the Server itself while it is running. If the directory # does not exist you must create it yourself with the right # permissions before running the Server. # # If no 'mod_gzip_temp_dir' is specified then the default location # for temporary workfiles will be 'ServerRoot' directory. # # The special mod_gzip log formats are, of course, optional. # # You must, of course, load the right module name for your OS # so make sure the correct 'LoadModule' command is uncommented # directly below... # Load Win32 module... LoadModule gzip_module modules/ApacheModuleGzip.dll # Load UNIX module... # LoadModule gzip_module modules/mod_gzip.so LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info1 LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info2 # NOTE: This 'CustomLog' directive shows how to set your access.log file # to use the mod_gzip format but please remember that for every 'CustomLog' # directive that Apache finds in httpd.conf there will be corresponding # line of output in the access.log file. If you only want ONE line of # results in access.log for each transaction then be sure to comment out # any other 'CustomLog' directives so that this is the only one. CustomLog logs/access.log common_with_mod_gzip_info2 # Runtime control directives... mod_gzip_on Yes mod_gzip_do_cgi Yes mod_gzip_do_static_files Yes mod_gzip_minimum_file_size 300 mod_gzip_maximum_inmem_size 60000 mod_gzip_keep_workfiles No mod_gzip_temp_dir "C:/Program Files/Apache Group/Apache/temp" # Item lists... # # Item names can be any one of the following... # # cgi-script - A valid 'handler' name # text/* - A valid MIME type name ( '*' wildcard allowed ) # .phtml - A valid file type extension # Dynamic items... # # NOTE: FOR NOW ALL DYNAMIC ITEMS SHOULD BE # DECLARED BEFORE ANY STATIC ITEMS TO PREVENT # PICKUP CONFLICTS. IF YOU USE !cgi-script # BE SURE IT IS DECLARED BEFORE ANY text/* # MIME TYPE ENTRIES. # # The items listed here are the types of dynamic # output that will be compressed... # # Dynamic items MUST have the "!" BANG character # on the front of the item name. # mod_gzip_item_include !cgi-script mod_gzip_item_include !.php mod_gzip_item_include !.php3 mod_gzip_item_include !.phtml # Static items... # # The items listed here are the types of static # files that will be compressed... # # NOTE: FOR NOW ALL STATIC INCLUDES MUST # COME AFTER DYNAMIC INCLUDES TO PREVENT # PICKUP CONFLICTS # mod_gzip_item_include text/* # Uncomment this line to compress graphics # when graphics compression is allowed... #mod_gzip_item_include image/* # Exclusions... MIME types and FILE types... # # The items listed here will be EXCLUDED from # any attempt to apply compression... # mod_gzip_item_exclude .js mod_gzip_item_exclude .css # Exclusions... HTTP support levels... # # By specifying a certain minimum level of HTTP support # certain older user agents ( browsers ) can be # automatically excluded from receiving compressed data. # # The item value should be in the same HTTP numeric format # that Apache uses to designate HTTP version levels. # # 1001 = HTTP/1.1 # # So 'mod_gzip_min_http 1001' means that a requesting # user agent ( browser ) must report a minimum HTTP support # level of 1.1 or it will not receive any compressed data. # mod_gzip_min_http 1001 # Debugging... # # If your Apache 'LogLevel' is set to 'debug' then # mod_gzip will add some diagnostic and compression # information to your error.log file for each request # that is processed by mod_gzip. # # LogLevel debug # End of MOD_GZIP Configuration Directives * End of inline comments */ #include /* * Apache headers... */ #define CORE_PRIVATE #include "httpd.h" #include "http_config.h" #include "http_core.h" #include "http_log.h" #include "http_main.h" #include "http_protocol.h" #include "util_script.h" /* * Add this header for ap_server_root[ MAX_STRING_LEN ] global... * * #include "http_conf_globals.h" * * ...or just include what we need from http_conf_globals.h * since that is, in fact, only 1 item at this time. */ extern API_VAR_EXPORT char ap_server_root[ MAX_STRING_LEN ]; /* * Add this header to get 'ap_update_mtime()' prototype... * * #include "http_request.h" * * ...or just include what we need from http_request.h since * that is, in fact, only 1 item at this time. */ extern API_EXPORT(time_t) ap_update_mtime(request_rec *r, time_t dependency_mtime); /* * Version information... * * Since this product is 'married' to the ASF Apache Web Server * the version numbers should always 'match' the changing * version numbers of Apache itself so users can be sure * they have the 'right' module. This allows us to move the * version numbers either backwards or forwards in case issues * arise which require specific versions of mod_gzip for * specific versions of Apache. * * The original code was first tested against the Apache 1.3.14 * release but should be compatible with the entire 1.3.x series. * If earlier 1.3.x versions of Apache required special versions * then the mod_gzip version number will still match the Apache * version number ( As in... mod_gzip v1.3.12.1, if needed ). * * If a special version is required for Apache 2.0 then the * version number(s) will change to match release numbers in * that series. ( As in... mod_gzip v 2.0.1.1, etc. ). * * The first 3 numbers of the version are always the equivalent * Apache release numbers. The fourth number is always the actual * mod_gzip 'build' number for that version of Apache. */ char mod_gzip_version[] = "1.3.14.5"; /* Global version string */ /* * Declare the NAME by which this module will be known. * This is the NAME that will be used in LoadModule command(s). */ extern module MODULE_VAR_EXPORT gzip_module; /* * Allow this module to 'read' config information from * ( and interact with ) the 'real' mod_cgi module... */ extern module cgi_module; /* * Some compile-time code inclusion switches... */ /* * Turn MOD_GZIP_ALLOWS_INTERNAL_COMMANDS switch ON to allow * information requests to be sent via any standard browser. */ #define MOD_GZIP_ALLOWS_INTERNAL_COMMANDS /* * Turn MOD_GZIP_USES_APACHE_LOGS switch ON to include the * code that can update Apache logs with compression information. */ #define MOD_GZIP_USES_APACHE_LOGS /* * Turn MOD_GZIP_USES_AP_SEND_MMAP switch ON to use the * ap_send_mmap() method for transmitting data. If this * switch is OFF then the default is to use ap_rwrite(). * This might need to be platform specific at some point. */ #define MOD_GZIP_USES_AP_SEND_MMAP /* * Turn MOD_GZIP_DEBUG1 switch ON for verbose diags. * This is normally OFF by default and should only be * used for diagnosing problems. The log output is * VERY detailed and the log files will be HUGE. */ /* #define MOD_GZIP_DEBUG1 */ /* * Some useful instance globals... */ #ifndef MOD_GZIP_MAX_PATH_LEN #define MOD_GZIP_MAX_PATH_LEN 512 #endif char mod_gzip_temp_dir[ MOD_GZIP_MAX_PATH_LEN + 2 ]; long mod_gzip_iusn = 0; /* Instance Unique Sequence Number */ long mod_gzip_maximum_inmem_size = 60000L; long mod_gzip_minimum_file_size = 300L; #ifdef _WIN32 char mod_gzip_dirsep[]="\\"; /* Dir separator is a backslash for Windows */ #else /* !_WIN32 */ char mod_gzip_dirsep[]="/"; /* Dir separator is a forward slash for UNIX */ #endif /* _WIN32 */ /* * The Compressed Object Cache control structure... */ #define MOD_GZIP_SEC_ONE_DAY 86400 /* Total seconds in one day */ #define MOD_GZIP_SEC_ONE_HR 3600 /* Total seconds in one hour */ #define MOD_GZIP_DEFAULT_CACHE_SPACE 5 #define MOD_GZIP_DEFAULT_CACHE_MAXEXPIRE MOD_GZIP_SEC_ONE_DAY #define MOD_GZIP_DEFAULT_CACHE_EXPIRE MOD_GZIP_SEC_ONE_HR #define MOD_GZIP_DEFAULT_CACHE_LMFACTOR (0.1) #define MOD_GZIP_DEFAULT_CACHE_COMPLETION (0.9) struct mod_gzip_cache_conf { const char *root; /* The location of the cache directory */ off_t space; /* Maximum cache size (in 1024 bytes) */ char space_set; time_t maxexpire; /* Maximum time to keep cached files (secs) */ char maxexpire_set; time_t defaultexpire; /* Default time to keep cached file (secs) */ char defaultexpire_set; double lmfactor; /* Factor for estimating expires date */ char lmfactor_set; time_t gcinterval; /* Garbage collection interval (secs) */ char gcinterval_set; int dirlevels; /* Number of levels of subdirectories */ char dirlevels_set; int dirlength; /* Length of subdirectory names */ char dirlength_set; }; /* * The Inclusion/Exclusion map item structure... */ #define MOD_GZIP_IMAP_MAXNAMES 256 #define MOD_GZIP_IMAP_MAXNAMELEN 90 #define MOD_GZIP_IMAP_ISMIME 1 #define MOD_GZIP_IMAP_ISEXT 2 #define MOD_GZIP_IMAP_ISHANDLER 3 #define MOD_GZIP_IMAP_STATIC1 9001 #define MOD_GZIP_IMAP_DYNAMIC1 9002 #define MOD_GZIP_IMAP_DECLINED1 9003 typedef struct { int include; /* 1=Include 0=Exclude */ int type; /* _ISMIME, _ISEXT, _ISHANDLER, etc. */ int action; /* _STATIC1, _DYNAMIC1, etc. */ char name[ MOD_GZIP_IMAP_MAXNAMELEN + 2 ]; } mod_gzip_imap; /* * The primary module configuration record... */ typedef struct { struct mod_gzip_cache_conf cache; /* Compressed Object Cache control */ int req; /* 1=mod_gzip handles requests 0=No */ char req_set; /* Mirrors the 'req' flag */ int do_static_files; /* 1=Yes 0=No */ int do_cgi; /* 1=Yes 0=No */ int keep_workfiles; /* 1=Keep workfiles 0=No */ int min_http; /* Minimum HTTP level ( 1001=HTTP/1.1 ) */ long minimum_file_size; /* Minimum size in bytes for compression attempt */ long maximum_inmem_size; /* Maximum size in bytes for im-memory compress */ /* Inclusion/Exclusion list(s)... */ int imap_total_entries; mod_gzip_imap imap[ MOD_GZIP_IMAP_MAXNAMES + 1 ]; } mod_gzip_conf; /* * The GZP request control structure... */ #define GZIP_FORMAT (0) #define DEFLATE_FORMAT (1) typedef struct _GZP_CONTROL { int decompress; /* 0=Compress 1=Decompress */ int compression_format; /* GZIP_FORMAT or DEFLATE_FORMAT */ /* Input control... */ int input_ismem; /* Input source is memory buffer, not file */ char *input_ismem_ibuf; /* Pointer to input memory buffer */ long input_ismem_ibuflen; /* Total length of input data */ char input_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; /* Input file name */ /* Output control... */ int output_ismem; /* Output source is memory buffer, not file */ char *output_ismem_obuf; /* Pointer to output memory buffer */ long output_ismem_obuflen; /* Maximum length of output data buffer */ char output_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; /* Output file name */ /* Results... */ int result_code; /* Result code */ long bytes_out; /* Total number of compressed output bytes */ } GZP_CONTROL; /* * Forward prototypes for internal routines... */ int gzp_main( GZP_CONTROL *gzp ); /* Primary GZP API entry point */ int mod_gzip_request_handler( request_rec *r ); int mod_gzip_cgi_handler( request_rec *r ); int mod_gzip_static_file_handler( request_rec *r ); int mod_gzip_prepare_for_dynamic_call( request_rec *r ); int mod_gzip_imap_show_items( mod_gzip_conf *mgc ); int mod_gzip_get_action_flag( request_rec *r, mod_gzip_conf *conf ); int mod_gzip_ismatch( char *s1, char *s2, int len1, int haswilds ); FILE *mod_gzip_open_output_file( request_rec *r, char *output_filename, int *rc ); int mod_gzip_create_unique_filename( mod_gzip_conf *mgc, char *target, int targetmaxlen ); int mod_gzip_encode_and_transmit( request_rec *r, char *source, int source_is_a_file, long input_size, int nodecline ); #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS int mod_gzip_send_html_command_response( request_rec *r, /* Request record */ char *tmp, /* Response to send */ char *ctype /* Content type string */ ); #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */ /* * Module routines... */ #ifdef MOD_GZIP_DEBUG1 void mod_gzip_printf( const char *fmt, ... ) { int l; FILE *log; va_list ap; char logname[256]; char log_line[4096]; /* Start... */ /* If UNIX then mod_gzip_dirsep = '/' Backward slash */ /* If _WIN32 then mod_gzip_dirsep = '\' Forward slash */ #ifdef FUTURE_USE /* For now we need both startup and runtime diags in the same log so it all goes to ServerRoot. 'mod_gzip_temp_dir' name isn't even valid until late in the startup process so we have to write to ServerRoot anyway until temp dir is known. */ if ( strlen(mod_gzip_temp_dir) ) /* Use temp directory ( if specified )... */ { sprintf( logname, "%s%smod_gzip.log", mod_gzip_temp_dir, mod_gzip_dirsep ); } else /* Just use 'ap_server_root' Apache ServerRoot directory... */ { sprintf( logname, "%s%smod_gzip.log", ap_server_root, mod_gzip_dirsep ); } #endif /* FUTURE_USE */ /* Just use ServerRoot for now... */ sprintf( logname, "%s%smod_gzip.log", ap_server_root, mod_gzip_dirsep ); log = fopen( logname,"a" ); if ( !log ) /* Log file did not open... */ { /* Just turn and burn... */ return; /* Void return */ } /* Get the variable parameter list... */ va_start( ap, fmt ); l = vsprintf(log_line, fmt, ap); /* See if we need to add LF... */ if ( l > 0 ) { if ( log_line[l-1] != '\n' ) { log_line[l]='\n'; l++; } log_line[l+1] = 0; } fprintf( log, "%s", log_line ); fclose( log ); va_end(ap); /* End session */ return; /* Void return */ }/* End of log_d() */ void mod_gzip_hexdump( char *buffer, int buflen ) { int i,o1,o2,o3; int len1; int len2; char ch1; char ch2; char s[40]; char l1[129]; char l2[129]; char l3[300]; long offset1=0L; /* Start... */ o1=0; o2=0; o3=0; l1[0] = 0; l2[0] = 0; l3[0] = 0; offset1 = 0; for ( i=0; i 126) ch2 = DUMPIT_LAPOSTROPHE; else if ( ch1 == 37 ) ch2 = DUMPIT_ASTERISK; /* Mask PERCENT for UNIX */ else if ( ch1 == 92 ) ch2 = DUMPIT_ASTERISK; /* Mask BACKSLASH for UNIX */ else ch2 = ch1; /* ENDIF on MASK_ALL_NON_PRINTABLE_CHARS */ #endif l2[o2++] = ch2; sprintf( s, "%02X", ch1 ); if ( strlen(s) > 2 ) s[2]=0; /* Prevent overflow */ len1 = strlen(s); len2 = strlen(l1); if ( strlen(l1) < (sizeof(l1) - (len1+1)) ) { strcat( l1, s ); strcat( l1, " " ); } if ( o2 >= 16 ) { l2[o2]=0; mod_gzip_printf( "%6lu| %-49.49s| %-16.16s |\n", offset1, l1, l2 ); offset1 += o2; o1=0; o2=0; o3=0; l1[0] = 0; l2[0] = 0; l3[0] = 0; } }/* End 'for( i=0; i 0 ) { l2[o2]=0; mod_gzip_printf( "%6lu| %-49.49s| %-16.16s |\n", offset1, l1, l2 ); offset1 += o2; o1 = o2 = o3 = 0; l1[0] = 0; l2[0] = 0; l3[0] = 0; } }/* End of mod_gzip_hexdump() */ #endif /* MOD_GZIP_DEBUG1 */ static void mod_gzip_init( server_rec *server, pool *p ) { /* * The module initialization procedure... */ FILE *fh1; char filename[ 512 ]; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_init()"; #endif mod_gzip_conf *mgc; /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n", cn ); #endif /* * Set some instance specific globals... * * The default 'temp' dir, lacking an httpd.conf config file * override, is the Apache 'ServerRoot'. Don't assume that /logs * dir exists because some Apache installations just use syslog * or stderr as their log output target. * * On most Apache installations 'ServerRoot' is automatically * readable/writable by the Server while it is running. * * On systems where it is not there MUST be an override * in the httpd.conf file. * * See the comments regarding the 'mod_gzip_temp_dir' directive * in the httpd.conf configuration file. */ mgc = ( mod_gzip_conf * ) ap_get_module_config(server->module_config, &gzip_module); /* Make sure we can read/write the temp directory... */ sprintf( filename, "%s%smod_gzip.id", mgc->cache.root, mod_gzip_dirsep ); fh1 = fopen( filename, "wb" ); if ( !fh1 ) /* Write an ERROR to console and to log(s)... */ { fprintf( stderr, "mod_gzip: Cannot read/write dir/file [%s]\n",filename); fprintf( stderr, "mod_gzip: Make sure the directory exists and that the Server\n"); fprintf( stderr, "mod_gzip: has read/write permission(s) for the directory.\n"); fprintf( stderr, "mod_gzip: See the 'mod_gzip_temp_dir' configuration notes.\n"); /* This is a startup ERROR and has to be fixed... */ ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server, "mod_gzip: Cannot read/write dir/file [%s]", filename); ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server, "mod_gzip: Make sure the directory exists and that the Server"); ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server, "mod_gzip: has read/write permission(s) for the directory."); ap_log_error( "",0,APLOG_NOERRNO|APLOG_ERR, server, "mod_gzip: See the 'mod_gzip_temp_dir' configuration notes."); } else /* File opened OK... just add some data and close it... */ { /* * Since this is just a MARK file we could simply wipe * it out but might as well print the actual version * number into it and leave it there in case there is * any question about which version is actually running. */ fprintf( fh1, "mod_gzip version %s\n", mod_gzip_version ); fclose( fh1 ); } #ifdef MOD_GZIP_DEBUG1 mod_gzip_imap_show_items( (mod_gzip_conf *) mgc ); /* Show item list */ mod_gzip_printf( "%s: Exit > return( void ) >\n", cn ); mod_gzip_printf( "\n" ); /* Separator for log file */ #endif }/* End of mod_gzip_init() */ int mod_gzip_strnicmp( char *s1, char *s2, int len1 ) { /* Behaves just like strnicmp() but IGNORES differences */ /* between FORWARD or BACKWARD slashes in a STRING... */ /* Also uses straight pointers and avoids stdlib calls. */ int i; char ch1; char ch2; /* WARNING! We MUST have a check for 'NULL' on the pointer(s) */ /* themselves or we might GP ( like NETSCAPE does ) */ /* if a 'NULL' pointer is passed to this routine... */ if ( ( s1 == 0 ) || ( s2 == 0 ) ) { /* SAFETY! If pointer itself if NULL */ /* don't enter LOOP or NETSCAPE will GP... */ return( 1 ); /* Return '1' for NOMATCH... */ } for ( i=0; i 96 ) ch1 -= 32; if ( ch2 > 96 ) ch2 -= 32; if ( ch1 == '/' ) ch1 = '\\'; if ( ch2 == '/' ) ch2 = '\\'; if ( ch1 != ch2 ) return( 1 ); /* No match! */ s1++; s2++; }/* End 'i' loop */ /* If we make it to here then everything MATCHED! */ return( 0 ); /* MATCH! */ }/* End mod_gzip_strnicmp() */ extern API_VAR_EXPORT module *top_module; struct _table { array_header a; #ifdef MAKE_TABLE_PROFILE void *creator; #endif }; typedef struct _table _table; const char *mod_gzip_isscript( request_rec *r, _table *t, const char *key) { /* * Get a 'handler' name for a MIME type right out of * the Apache 'Action' table(s)... * * Example: * * If "key" is "applications/x-httpd-php3" * then this search will return "/php3/php.exe" * or whatever the equivalent PHP executable * pathname is as specified by an 'Action' statement * in the httpd.conf configuration file. * * This pathname might still have 'aliases' in it * so we will have to consult with mod_alias * following this call and get any aliases converted. */ table_entry *elts = (table_entry *) t->a.elts; int i; char cn[]="mod_gzip_isscript()"; /* * Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n",cn); mod_gzip_printf( "%s: key=[%s]\n",cn,key ); #endif if ( key == NULL ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 'key' has no length\n",cn); mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: Search key is NULL.",cn); } return NULL; } for (i = 0; i < t->a.nelts; ++i) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: i=%4.4d Comparing [%s] with elts.key[%s].val[%s]\n", cn, i, key, elts[i].key, elts[i].val ); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: i=%4.4d Comparing [%s] with elts.key[%s].val[%s]", cn, i, key, elts[i].key, elts[i].val ); } if (!strcasecmp(elts[i].key, key)) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: MATCH FOUND!",cn); mod_gzip_printf( "%s: Exit > return(%s) >\n",cn,elts[i].val); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: MATCH FOUND...",cn); } return elts[i].val; } }/* End 'i' loop */ if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: NO MATCH FOUND...",cn); } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: NO MATCH FOUND!\n",cn); mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn); #endif return NULL; }/* End of 'mod_gzip_isscript()' */ typedef struct { table *action_types; /* Added with Action... */ char *scripted[METHODS]; /* Added with Script... */ array_header *xmethods; /* Added with Script -- extension methods */ } mod_actions_local_config; int mod_gzip_run_mod_action( request_rec *r ) { module *modp; int count=0; int pass=0; mod_actions_local_config *mod_actions_conf; const char *t=0; const char *action=0; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_run_mod_action()"; #endif #ifdef MOD_GZIP_FUTURE_USE const handler_rec *handp; #endif /* Currently 9 possible 'event' handlers. */ /* Actual content handler in a module is 'extra'. */ #define MOD_GZIP_NMETHODS 9 /* * Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n",cn); mod_gzip_printf( "%s: *IN: r->uri =[%s]\n", cn, r->uri ); mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); mod_gzip_printf( "%s: *IN: r->filename =[%s]\n", cn, r->filename ); mod_gzip_printf( "%s: r->content_type =[%s]\n", cn,r->content_type); mod_gzip_printf( "%s: r->handler =[%s]\n", cn,r->handler); #endif for ( modp = top_module; modp; modp = modp->next ) { /* modp->name list will look like this... */ /*--------------------*/ /* 00 [mod_gzip.c] */ /* 01 [mod_isapi.c] */ /* 02 [mod_setenv.c] */ /* 02 [mod_actions.c] */ /* ............... */ /* ............... */ /* 18 [mod_so.c] */ /* 19 [http_core.c] <- Always bottom of list (last one called) */ /*--------------------*/ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: count=%4.4d modp = %10.10ld modp->name=[%s]\n", cn,count,(long)modp, modp->name ); #endif if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 ) { /* Module information... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ++++++++++ MODULE FOUND!...\n",cn); mod_gzip_printf( "%s: ++++++++++ modp->module_index = %d\n",cn,(int)modp->module_index); #endif /* Get a pointer to the module configuration data... */ mod_actions_conf = (mod_actions_local_config *) ap_get_module_config(r->per_dir_config, modp ); /* Get script name... */ /* Make 2 passes if necessary. If we don't find a */ /* program name associated with MIME type first */ /* then punt and look for a program name associated */ /* with the r->handler name such as [php-script] */ for ( pass = 0; pass < 2; pass++ ) { if ( pass == 0 ) /* Check r->content_type first */ { /* This is the first pass... */ /* Set 'action' search key to 'r->content_type' */ /* so we search for [application/x-httpd-php3] */ action = r->content_type; } else if ( pass == 1 ) /* Try r->handler */ { /* This is the second pass... */ /* Set 'action' search key to 'r->handler' */ /* so we search for [php-script] */ action = r->handler; } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ++++++++++ pass =%d\n", cn,pass); mod_gzip_printf( "%s: ++++++++++ t =[%s]\n",cn,t); mod_gzip_printf( "%s: ++++++++++ r->content_type =[%s]\n",cn,r->content_type); mod_gzip_printf( "%s: ++++++++++ r->handler =[%s]\n",cn,r->handler); mod_gzip_printf( "%s: ++++++++++ action =[%s]\n",cn,action); mod_gzip_printf( "%s: ++++++++++ r->filename =[%s]\n",cn,r->filename); mod_gzip_printf( "%s: ++++++++++ r->uri =[%s]\n",cn,r->uri); mod_gzip_printf( "%s: ++++++++++ Call mod_gzip_isscript()...\n",cn); #endif t = mod_gzip_isscript( r, (_table *) mod_actions_conf->action_types, action ? action : ap_default_type(r) ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ++++++++++ Back mod_gzip_isscript()...\n",cn); mod_gzip_printf( "%s: ++++++++++ t =[%s]\n",cn,t); mod_gzip_printf( "%s: ++++++++++ action =[%s]\n",cn,action); #endif if ( t ) { /* * If a program name was found then make it r->filename * and r->uri will become the input name for the program */ r->filename = ap_pstrdup(r->pool,t); break; } }/* End 'for( pass )' loop */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ++++++++++ r->filename=[%s]\n",cn,r->filename); mod_gzip_printf( "%s: ++++++++++ r->uri =[%s]\n",cn,r->uri); #endif /* If a handler was found we are DONE... */ if ( t ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Handler was found...\n",cn); mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn); #endif return OK; } #ifdef MOD_GZIP_FUTURE_USE #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ++++++++++ METHODS\n",cn); mod_gzip_printf( "%s: ++++++++++ modp->translate_handler = %ld\n",cn,(long)modp->translate_handler); mod_gzip_printf( "%s: ++++++++++ modp->ap_check_user_id = %ld\n",cn,(long)modp->ap_check_user_id); mod_gzip_printf( "%s: ++++++++++ modp->auth_checker = %ld\n",cn,(long)modp->auth_checker); mod_gzip_printf( "%s: ++++++++++ modp->access_checker = %ld\n",cn,(long)modp->access_checker); mod_gzip_printf( "%s: ++++++++++ modp->type_checker = %ld\n",cn,(long)modp->type_checker); mod_gzip_printf( "%s: ++++++++++ modp->fixer_upper = %ld\n",cn,(long)modp->fixer_upper); mod_gzip_printf( "%s: ++++++++++ modp->logger = %ld\n",cn,(long)modp->logger); mod_gzip_printf( "%s: ++++++++++ modp->header_parser = %ld\n",cn,(long)modp->header_parser); mod_gzip_printf( "%s: .......... CONTENT HANDLERS\n",cn); #endif /* MOD_GZIP_DEBUG1 */ if ( !modp->handlers ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: .......... NO CONTENT HANDLERS!\n",cn); #endif } else /* There are some handlers... */ { for ( handp = modp->handlers; handp->content_type; ++handp ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: .......... handp->content_type = [%s]\n", cn,handp->content_type); mod_gzip_printf( "%s: .......... handp->handler = %ld\n",cn,(long)handp->handler); #endif }/* End 'handp' loop */ }/* End 'else' */ #endif /* MOD_GZIP_FUTURE_USE */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: No handler was found...\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif return DECLINED; }/* 'if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )' */ count++; }/* End 'modp' loop... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: No handler found...\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) > ERROR >\n",cn); #endif return DECLINED; }/* End of mod_gzip_run_mod_action() */ int mod_gzip_run_mod_alias( request_rec *r ) { /* * This calls 'translate_alias_redir()' routine in mod_alias.c * which will search/replace keywords in the URI with the correct * 'ScriptAlias' value(s) from the httpd.conf configuration file. * * 'translate_alias_redir()' is the name of routine registered * by mod_alias.c module as the 'translate' hook. */ module *modp; int count=0; int rc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_run_mod_alias()"; #endif const handler_rec *handp; /* Currently 9 possible 'event' handlers. */ /* Actual content handler in a module is 'extra'. */ #define MOD_GZIP_NMETHODS 9 char *save_filename = 0; char *save_uri = 0; char nothing[256]; /* * Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n",cn); mod_gzip_printf( "%s: *IN: r->uri =[%s]\n", cn, r->uri ); mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); mod_gzip_printf( "%s: *IN: r->filename =[%s]\n", cn, r->filename ); #endif for ( modp = top_module; modp; modp = modp->next ) { /* modp->name list will look like this... */ /*--------------------*/ /* 00 [mod_gzip.c] */ /* 01 [mod_isapi.c] */ /* 02 [mod_setenv.c] */ /* 02 [mod_actions.c] */ /* ............... */ /* ............... */ /* 18 [mod_so.c] */ /* 19 [http_core.c] <- Always bottom of list (last one called) */ /*--------------------*/ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: count=%4.4d modp = %10.10ld modp->name=[%s]\n", cn,count,(long)modp, modp->name ); #endif /* There are only 3 modules that normally have 'translate' handlers registered... mod_alias mod_userdir http_core */ if ( ( mod_gzip_strnicmp( (char *) modp->name, "mod_alias.c", 11 ) == 0 ) || ( mod_gzip_strnicmp( (char *) modp->name, "mod_userdir.c", 13 ) == 0 ) || ( mod_gzip_strnicmp( (char *) modp->name, "http_core.c", 11 ) == 0 ) ) { /* Module information... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ++++++++++ MODULE FOUND!...\n",cn); mod_gzip_printf( "%s: ++++++++++ modp->module_index = %d\n",cn,(int)modp->module_index); mod_gzip_printf( "%s: ++++++++++ METHODS\n",cn); mod_gzip_printf( "%s: ++++++++++ modp->translate_handler = %ld\n",cn,(long)modp->translate_handler); mod_gzip_printf( "%s: ++++++++++ modp->ap_check_user_id = %ld\n",cn,(long)modp->ap_check_user_id); mod_gzip_printf( "%s: ++++++++++ modp->auth_checker = %ld\n",cn,(long)modp->auth_checker); mod_gzip_printf( "%s: ++++++++++ modp->access_checker = %ld\n",cn,(long)modp->access_checker); mod_gzip_printf( "%s: ++++++++++ modp->type_checker = %ld\n",cn,(long)modp->type_checker); mod_gzip_printf( "%s: ++++++++++ modp->fixer_upper = %ld\n",cn,(long)modp->fixer_upper); mod_gzip_printf( "%s: ++++++++++ modp->logger = %ld\n",cn,(long)modp->logger); mod_gzip_printf( "%s: ++++++++++ modp->header_parser = %ld\n",cn,(long)modp->header_parser); mod_gzip_printf( "%s: .......... CONTENT HANDLERS\n",cn); #endif /* MOD_GZIP_DEBUG1 */ if ( !modp->handlers ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: .......... NO CONTENT HANDLERS!\n",cn); #endif } else /* There are some handlers... */ { for ( handp = modp->handlers; handp->content_type; ++handp ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: .......... handp->content_type = [%s]\n", cn,handp->content_type); mod_gzip_printf( "%s: .......... handp->handler = %ld\n",cn,(long)handp->handler); #endif }/* End 'handp' loop */ }/* End 'else' */ if ( modp->translate_handler ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: modp->translate_handler is VALID...\n",cn); #endif /* There are only 3 modules that normally have 'translate' handlers registered... mod_alias <- Will translate /php3/xxx to c:/php3017/xx mod_userdir http_core */ /* * This calls 'translate_alias_redir()' routine in mod_alias.c * which will search/replace keywords in the URI with the correct * 'ScriptAlias' value(s) from the httpd.conf configuration file. * * 'translate_alias_redir()' is the name of routine registered * by mod_alias.c module as the 'translate' hook. * * The 'translate_alias_redir()' function in mod_alias.c * is really simple. All it does is check to make sure * that r->uri has some value and, if it does, it calls * another routine in mod_alias.c named 'try_alias_list()' * which replaces any 'ScriptAlias' phrases with their * real values and copies the result to r->filename. * * We must make sure the phrase we want translated is * in r->uri and check for results in r->filename. */ /* * Calling mod_alias.c translate handler will correctly * translate 'ScriptAlias' phrases such as... * * URI value... * /php3/php3.exe * becomes... * c:/php3017/php3.exe */ save_filename = r->filename; save_uri = r->uri; nothing[0] = 0; r->filename = nothing; r->uri = save_filename; /* Phrase to translate */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: r->filename = [%s]\n",cn,r->filename); mod_gzip_printf( "%s: r->uri = [%s]\n",cn,r->uri); mod_gzip_printf( "%s: Call (modp->translate_handler)(r)...\n",cn); #endif /* Call the actual translate routine in mod_action module... */ rc = (modp->translate_handler)( (request_rec *) r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back (modp->translate_handler)(r)...\n",cn); mod_gzip_printf( "%s: r->filename = [%s]\n",cn,r->filename); mod_gzip_printf( "%s: r->uri = [%s]\n",cn,r->uri); #endif /* * If there was a successful translation then the return * code will be OK and the translated URI will be sitting * in r->filename. If there were no phrase replacements * then the return code will be DECLINED. */ #ifdef MOD_GZIP_DEBUG1 if ( rc == OK ) { mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc ); } else if ( rc == DECLINED ) { mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc ); } else if ( rc == DONE ) /* -2 means 'totally done' */ { mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc ); } else /* Probably an HTTP ERROR value... */ { mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc ); } #endif /* MOD_GZIP_DEBUG */ /* * Evaluate the results... */ if ( rc == OK ) /* There was a phrase translation... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: There was a phrase translation...\n",cn ); mod_gzip_printf( "%s: Keeping new 'r->filename'\n",cn ); #endif /* Do NOT restore 'r->filename' to original value... */ /* Just fall-through and continue... */ } else /* No phrases were replaced... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: There were NO phrases translated...\n",cn ); mod_gzip_printf( "%s: Restoring 'r->filename' to original value...\n",cn ); #endif /* Restore 'r->filename' to original value... */ r->filename = save_filename; } /* Always 'restore' URI to original value... */ r->uri = save_uri; /* Turn and burn... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( rc=%d ) >\n",cn,rc); #endif return rc; } else /* modp->translate_handler is NULL... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: modp->translate_handler is NOT VALID.\n",cn); #endif } }/* 'if ( mod_gzip_strnicmp( (char *) modp->name, "mod_actions.c", 13 ) == 0 )' */ count++; }/* End 'modp' loop... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: No handler found...\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) > ERROR >\n",cn); #endif return DECLINED; }/* End of mod_gzip_run_mod_alias() */ static int mod_gzip_handler( request_rec *r ) { /* * The primary module request handler... */ int rc=0; char cn[]="mod_gzip_handler()"; int access_status=0; int access_status2=0; /* * Start... */ if ( r->server->loglevel == APLOG_DEBUG ) { /* * If the user has 'LogLevel debug' set in httpd.conf then * it's ok to go ahead and strike some diagnostic information * to the Apache log(s). * * APLOG_MARK is what supplies __FILE__ and __LINE__ info and * it is actually defined in HTTP_LOG.H as... * * define APLOG_MARK __FILE__,__LINE__ * * Sometimes the original __FILE__ name is very long and is * fairly useless information cluttering up the logs when * there is only 1 possible source file name so * to NOT use it just supply 2 dummy parameters instead. * * The first parameter can be a custom message instead of * the __FILE__ string that would normally be substituted. */ ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: Entry point...",cn); ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: r->the_request = [%s]",cn,r->the_request); ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: r->protocol = [%s]",cn,r->protocol); ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: r->proto_num = %d",cn,(int)r->proto_num); ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: r->filename = [%s]",cn,r->filename); ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: r->uri = [%s]",cn,r->uri); ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: r->content_type = [%s]",cn,r->content_type); ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: r->handler = [%s]",cn,r->handler); }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "\n" ); mod_gzip_printf( "%s: ```` Entry...\n",cn); mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn); mod_gzip_printf( "%s: *IN: r->uri =[%s]\n", cn, r->uri ); mod_gzip_printf( "%s: *IN: r->unparsed_uri =[%s]\n", cn, r->unparsed_uri ); mod_gzip_printf( "%s: *IN: r->filename =[%s]\n", cn, r->filename ); mod_gzip_printf( "%s: *IN: r->path_info =[%s]\n", cn, r->path_info ); mod_gzip_printf( "%s: *IN: r->args =[%s]\n", cn, r->args ); mod_gzip_printf( "%s: *IN: r->header_only =[%s]\n", cn, r->header_only ); mod_gzip_printf( "%s: *IN: r->protocol =[%s]\n", cn, r->protocol ); mod_gzip_printf( "%s: *IN: r->proto_num =%d\n", cn, r->proto_num ); mod_gzip_printf( "%s: *IN: r->hostname =[%s]\n", cn, r->hostname ); mod_gzip_printf( "%s: *IN: r->the_request =[%s]\n", cn, r->the_request ); mod_gzip_printf( "%s: *IN: r->assbackwards =%d\n", cn, r->assbackwards ); mod_gzip_printf( "%s: *IN: r->status_line =[%s]\n", cn, r->status_line ); mod_gzip_printf( "%s: *IN: r->status =%d\n", cn, r->status ); mod_gzip_printf( "%s: *IN: r->method =[%s]\n", cn, r->method ); mod_gzip_printf( "%s: *IN: r->method_number =%d\n", cn, r->method_number ); mod_gzip_printf( "%s: *IN: r->content_type =[%s]\n", cn, r->content_type ); mod_gzip_printf( "%s: *IN: r->handler =[%s]\n", cn, r->handler ); mod_gzip_printf( "%s: *IN: r->content_encoding =[%s]\n", cn, r->content_encoding ); mod_gzip_printf( "%s: *IN: r->content_language =[%s]\n", cn, r->content_language ); mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn); mod_gzip_printf( "%s: *IN: r->parsed_uri.scheme =[%s]\n", cn, r->parsed_uri.scheme ); mod_gzip_printf( "%s: *IN: r->parsed_uri.hostinfo =[%s]\n", cn, r->parsed_uri.hostinfo ); mod_gzip_printf( "%s: *IN: r->parsed_uri.user =[%s]\n", cn, r->parsed_uri.user ); mod_gzip_printf( "%s: *IN: r->parsed_uri.password =[%s]\n", cn, r->parsed_uri.password ); mod_gzip_printf( "%s: *IN: r->parsed_uri.hostname =[%s]\n", cn, r->parsed_uri.hostname ); mod_gzip_printf( "%s: *IN: r->parsed_uri.port_str =[%s]\n", cn, r->parsed_uri.port_str ); mod_gzip_printf( "%s: *IN: r->parsed_uri.port =%u\n", cn, r->parsed_uri.port ); mod_gzip_printf( "%s: *IN: r->parsed_uri.path =[%s]\n", cn, r->parsed_uri.path ); mod_gzip_printf( "%s: *IN: r->parsed_uri.query =[%s]\n", cn, r->parsed_uri.query ); mod_gzip_printf( "%s: *IN: r->parsed_uri.fragment =[%s]\n", cn, r->parsed_uri.fragment ); mod_gzip_printf( "%s: -------------------------------------------------------------\n",cn); #endif /* MOD_GZIP_DEBUG1 */ /* * Call the real transaction handler.... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call mod_gzip_request_handler()...\n", cn ); #endif rc = mod_gzip_request_handler( (request_rec *) r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back mod_gzip_request_handler()... rc=%d\n",cn,rc); #endif if ( r->server->loglevel == APLOG_DEBUG ) { /* * If LogLevel is 'debug' then show the final return code * value in the log(s)... */ if ( rc == OK ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: Exit: return( rc = %d = OK )", cn, rc ); } else if ( rc == DECLINED ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: Exit: return( rc = %d = DECLINED )", cn, rc ); } else /* It's probably an HTTP error code... */ { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "%s: Exit: return( rc = %d = HTTP ERROR CODE? )", cn, rc ); } }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */ #ifdef MOD_GZIP_DEBUG1 if ( rc == OK ) { mod_gzip_printf( "%s: rc = %d OK\n", cn, (int) rc); } else if ( rc == DECLINED ) { mod_gzip_printf( "%s: rc = %d DECLINED\n", cn, (int) rc ); } else /* It's probably an HTTP error code... */ { mod_gzip_printf( "%s: rc = %d ( HTTP ERROR CODE? )\n", cn, (int) rc ); } mod_gzip_printf( "%s: Exit > return( rc = %d ) >\n",cn,rc ); #endif /* MOD_GZIP_DEBUG1 */ return rc; }/* End of mod_gzip_handler() */ typedef struct { table *action_types; /* Added with Action... */ char *scripted[METHODS]; /* Added with Script... */ array_header *xmethods; /* Added with Script -- extension methods */ } action_dir_config2; extern module action_module; int mod_gzip_request_handler( request_rec *r ) { /* * Process a new request... */ int rc = 0; int loglevel = 0; int do_command = 0; int process = 0; int action_flag = 0; long compression_ratio = 0; const char* has_encoding = 0; const char* accept_encoding = 0; #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS char tmp[4096]; /* Scratch buffer for HTML output */ #endif #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_request_handler()"; const char* the_type = 0; #endif #ifdef MOD_GZIP_USES_APACHE_LOGS char log_info[40]; /* Scratch buffer */ #endif void *modconf = r->server->module_config; mod_gzip_conf *conf = 0; /* Pointer to our own config data */ /* * Start... * * Establish a local pointer to module configuration data... */ conf = (mod_gzip_conf *) ap_get_module_config(modconf, &gzip_module); /* * Get the current Apache log level... */ loglevel = r->server->loglevel; #ifdef MOD_GZIP_USES_APACHE_LOGS /* * If the MOD_GZIP_USES_APACHE_LOGS compile-time switch is ON * then the Apache log module interface code is being included. * * Reset the module 'notes' that are used by mod_gzip to * add entries to Apache standard log files... * * See the note farther below about how to add mod_gzip * compression information to any standard Apache log file. */ /* Default for 'mod_result' message is 'DECLINED:NOP'... */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NOP")); /* Default for in/out size is 'n/a'... 'Not available'...*/ sprintf( log_info, "n/a" ); ap_table_setn( r->notes,"mod_gzip_input_size",ap_pstrdup(r->pool,log_info)); ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info)); /* Default for compression ratio is '0' percent... */ ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,"0")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ #ifdef MOD_GZIP_DEBUG1 /* Request info... */ mod_gzip_printf( "%s: Entry...\n",cn); mod_gzip_printf( "%s: mod_gzip_version =[%s]\n", cn, mod_gzip_version); mod_gzip_printf( "%s: conf->req = %d\n", cn, (int) conf->req); mod_gzip_printf( "%s: conf->cache.root =[%s]\n", cn, conf->cache.root); mod_gzip_printf( "%s: *IN: r->uri =[%s]\n", cn, r->uri); mod_gzip_printf( "%s: *IN: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri); mod_gzip_printf( "%s: *IN: r->filename =[%s]\n", cn, r->filename); mod_gzip_printf( "%s: *IN: r->handler =[%s]\n", cn, r->handler); mod_gzip_printf( "%s: r->finfo.st_size = %ld\n", cn, (long) r->finfo.st_size); /* NOTE: The r->headers_out content type value has not normally */ /* been set at this point but grab a pointer to it and show */ /* it just to make sure. The r->content_type value, however, */ /* normally WILL have some value at this point. */ the_type = ap_table_get( r->headers_out,"Content-type" ); mod_gzip_printf( "%s: r->headers_out, Content-type = [%s]\n",cn,the_type); mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type ); /* The r->handler ASCII name string is the all-important */ /* jump table name for the module that will handle the */ /* transaction. If this is a CGI jump then it will normally */ /* have a value of 'cgi-script' at this point. */ mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler ); /* Server info... */ mod_gzip_printf( "%s: r->server->path = [%s]\n",cn,r->server->path ); mod_gzip_printf( "%s: r->server->pathlen = %d\n", cn,r->server->pathlen); mod_gzip_printf( "%s: r->server->server_admin = [%s]\n",cn,r->server->server_admin); mod_gzip_printf( "%s: r->server->server_hostname = [%s]\n",cn,r->server->server_hostname); mod_gzip_printf( "%s: r->server->error_fname = [%s]\n",cn,r->server->error_fname); /* Environment info... */ mod_gzip_printf( "%s: DOCUMENT_ROOT = [%s]\n",cn,ap_document_root(r)); #endif /* MOD_GZIP_DEBUG1 */ /* * Check the 'master' request control switch and see if mod_gzip * is ON (ENABLED) or OFF (DISABLED)... */ if ( conf->req != 1 ) { /* mod_gzip is currently DISABLED so DECLINE the processing... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: conf->req = %d = OFF\n",cn,conf->req); mod_gzip_printf( "%s: The module is currently DISABLED\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:DISABLED")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; }/* End 'if( conf->req != 1 )' */ /* * Check for a default HTTP support level ( if used ). * If no value for conf->min_http was supplied in the * httpd.conf file then the default value will be 0 * so that ALL levels of HTTP will be OK... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: *HTTP CHECK:conf->min_http = %d\n", cn, conf->min_http ); mod_gzip_printf( "%s: *HTTP CHECK:r->proto_num = %d\n", cn, r->proto_num ); mod_gzip_printf( "%s: *HTTP CHECK:r->protocol = [%s]\n", cn, r->protocol ); #endif if ( r->proto_num < conf->min_http ) { /* The HTTPx/x version number does not meet the minimum requirement */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Request HTTP level does not meet minimum requirement\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ sprintf( log_info, "DECLINED:%s:%d", r->protocol, r->proto_num ); ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,log_info)); #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; }/* End 'if ( r->proto_num < conf->min_http )' */ else /* Protocol level is OK... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Request HTTP level is OK...\n",cn); #endif } #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS /* * Internal command pickups... * * If this module was compiled with the * MOD_GZIP_ALLOWS_INTERNAL_COMMANDS switch ON * then the first thing we do is check for valid * URL-based internal commands. * * Rather than check for all possible commands each time * just do 1 quick check for the command prefix and set * a flag to indicate if there is any need to enter the * actual command handler... */ if ( strstr( r->filename, "mod_gzip_command_" ) ) { do_command = 1; /* Process the command */ } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: do_command = %d\n",cn,do_command); #endif if ( do_command ) { /* Determine the exact command and respond... */ if ( strstr( r->filename, "mod_gzip_command_version" ) ) { /*------------------------------------------------------*/ /* Command: 'mod_gzip_command_version' */ /* Purpose: Return the current mod_gzip version number. */ /* Comment: Allows anyone to query any Apache Server at */ /* any URL with a browser and discover if */ /* mod_gzip is in use at that site. */ /*------------------------------------------------------*/ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 'mod_gzip_command_version' seen...\n",cn); #endif /* NOTE: mod_gzip command results are not sent compressed */ /* Build the response buffer... */ sprintf( tmp, "
"
          "mod_gzip is available on this Server\r\n"
          "mod_gzip version = %s\r\n"
          "
", mod_gzip_version ); /* For all mod_gzip commands that are intercepted we */ /* simply return OK. */ return( mod_gzip_send_html_command_response( r, tmp, "text/html" )); } else if ( strstr( r->filename, "mod_gzip_command_showstats" ) ) { /*------------------------------------------------------*/ /* Command: 'mod_gzip_command_showstats' */ /* Purpose: Display compression statistics. */ /* Comment: Allows anyone to query any Apache Server at */ /* any URL with a browser and get a report */ /* about compression results. */ /*------------------------------------------------------*/ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 'mod_gzip_command_showstats' seen...\n",cn); #endif /* NOTE: mod_gzip command results are not sent compressed */ /* Build the response buffer... */ /* NOTE: This command has been temporarily removed */ sprintf( tmp, "
"
          "mod_gzip is available on this Server\r\n"
          "mod_gzip version = %s\r\n\r\n"
          "The 'mod_gzip_command_showstats' command has been temporarily removed.\r\n"
          "
", mod_gzip_version ); /* For all mod_gzip commands that are intercepted we */ /* simply return OK. */ return( mod_gzip_send_html_command_response( r, tmp, "text/html" )); } else if ( strstr( r->filename, "mod_gzip_command_resetstats" ) ) { /*------------------------------------------------------*/ /* Command: 'mod_gzip_command_resetstats' */ /* Purpose: Resets the compression statistics. */ /* Comment: Allows the compression statistics to be */ /* reset using only a browser. */ /*------------------------------------------------------*/ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 'mod_gzip_command_resetstats' seen...\n",cn); #endif /* NOTE: mod_gzip command results are not sent compressed */ /* Build the response buffer... */ /* NOTE: This command has been temporarily removed */ sprintf( tmp, "
"
          "mod_gzip is available on this Server\r\n"
          "mod_gzip version = %s\r\n\r\n"
          "The 'mod_gzip_command_resetstats' command has been temporarily removed.\r\n"
          "
", mod_gzip_version ); /* For all mod_gzip commands that are intercepted we */ /* simply return OK. */ return( mod_gzip_send_html_command_response( r, tmp, "text/html" )); } else /* Unrecognized command... */ { /* The command prefix was 'seen' and the 'do_command' flag */ /* was TRUE but either the command was mis-typed or there */ /* is no such command available. This is not an ERROR and */ /* we should simply fall-through and assume that the URL */ /* is valid for the local Server. A 404 will be returned */ /* if there is no object that actually matches the name. */ } }/* End 'if( do_command )' */ #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */ /* * Sanity checks... */ /* * If the requested file already contains the .gz designation * then we must assume it is pre-compressed and let the * default logic take care of sending the file. This module * doesn't really care if a .gz file was actually requested * or if it is the source target because of a successful * Server side 'negotiation'. Doesn't matter. */ if ( ( r->filename ) && ( strstr( r->filename, ".gz" ) ) ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: r->filename already contains '.gz'.\n",cn); mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HAS.GZ")); if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: Files with .gz file extension are skipped."); } #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; } else /* r->filename doesn not contain '.gz' designator... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: r->filename does NOT contain '.gz'.\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } /* * For now just block all attempts to compress 'image/*' MIME * type even if user is trying to do so. Too many issues with * broken browsers when it comes to decoding compressed images. * * WARNING: Don't submit r->content_type to strstr() it if is * NULL or the API call will GP fault. Go figure. */ if ( ( r->content_type ) && ( strstr( r->content_type, "image/" ) ) ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: r->content_type contains 'image/'.\n",cn); mod_gzip_printf( "%s: Image compression is temporaily BLOCKED\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:IMAGE")); if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: Graphics image compression option is temporarily disabled."); } #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; } /* * Safeguard against situations where some other module or * filter has gotten to this request BEFORE us and has already * added the 'Content-encoding: gzip' field to the output header. * It must be assumed that whoever added the header prior to this * point also took care of the compression itself. * * If the output header already contains "Content-encoding: gzip" * then simply DECLINE the processing and let the default chain * take care of it... */ has_encoding = ap_table_get( r->headers_out, "Content-encoding" ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: has_encoding = [%s]\n",cn,has_encoding); #endif if ( has_encoding ) /* 'Content-encoding' field is present... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Output header already contains 'Content-encoding:' field\n",cn); mod_gzip_printf( "%s: Checking for 'gzip' designator...\n",cn); #endif if ( strstr( has_encoding, "gzip" ) || strstr( has_encoding, "deflate" ) ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' or 'deflate' designator...\n",cn); mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HAS_CE:GZIP")); if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: Header already has 'Content-encoding: gzip'"); } #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; } else /* 'gzip' designator not found... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' or 'deflate' designator...\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } }/* End 'if( has_encoding )' */ else /* Output header does NOT contain 'Content-encoding:' field... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Output header does NOT contain 'Content-encoding:' field.\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } /* * Basic sanity checks completed and we are still here. * * Now we must determine if the User-Agent is capable of receiving * compressed data... * * There are, currently, many reasons why it is actually never * enough to simply trust the 'Accept-encoding: foo, bar' * request header field when it comes to actually determining * if a User-agent is capable of receiving content or transfer * encodings. * * Some of them are... * * 1. There have been several major releases of popular browsers * that actually send the 'Accept-encoding:' request field but * are, in reality, unable to perform the specified decoding(s). * In some cases the result will be that the browser screen * simply fills with garbage ( the binary compressed data * itself ) but in some cases the browser will actually crash. * * 2. There have been other major releases of browsers that are * specifying multiple 'Accept-encoding' techniques with no * 'Q' values whatsoever and they are actually only able to * handle one of the multiple types specified. There is no * way to know which type is 'real' other than by using other * empiricial data extracted from the 'User-agent' field * or other inbound request headers. * * 3. Same as 1 and 2 but relates to SIZE. Some major browser * releases can handle the encoded content but only up to * a certain 'SIZE' limit and then they will fail. There * is no way for a User-agent to specify this limitation * via HTTP so empirical header analysis is the only option. * * 4. The HTTP specification has no way for a Server to distinguish * from the 'Accept encoding: foo, bar' input request field * whether the user agent can only support the specified encodings * as either a Content-encoding OR a Transfer-encoding, but * not both. There is also no way of knowing if the user * agent is able to handle any of the specified types being * used as both a Content-encoding AND a Transfer-encoding * for the same message body. All the Server can do is assume * that the encodings are valid in any/all combinations * and that the user agent can 'Accept' them as either * 'Content' encodings and/or 'Transfer' encodings under * any and all circumstances. This blanket assumption will * cause problems with some release versions of some browsers * because the assumed 'do all' capability is simply not a * reality. * * 5. Many browsers ( such as Netscape 4.75 for UNIX ) are unable * to handle Content-encoding only for specific kinds of HTML * transactions such as Style Sheets even though the browser * says it is HTTP 1.1 compliant and is suppying the standard * 'Accept-encoding: gzip' field. According to the IETF * specifications any user-agent that says it can accept * encodings should be able to do so for all types of HTML * transactions but this is simply not the current reality. * Some will, some won't... even if they say they can. * * This version of this module takes the 'What, me worry' approach * and simply uses the accepted method of relying solely on the * 'Accept-encoding: foo, bar' field and also assumes this means * that the User-agent can accept the specified encodings as * either Content-encodings (CE) and/or Transfer-encodings (TE) * under all circumstances and in any combinations that the * Server decides to send. * * It also assumes that the caller has no preference and should * be able to decode any of the specified encodings equally well. * Most user-agents sending the 'Accept-encoding:' field do NOT * supply any 'Q' values to help with determining preferences. */ accept_encoding = ap_table_get( r->headers_in, "Accept-Encoding" ); #ifdef MOD_GZIP_DEBUG1 if ( accept_encoding ) { mod_gzip_printf( "%s: 'Accept Encoding:' field seen.\n",cn); } else { mod_gzip_printf( "%s: 'Accept Encoding' field NOT seen.\n",cn); } #endif /* MOD_GZIP_DEBUG1 */ /* If Accept-Encoding is applicable to this request...*/ if ( accept_encoding ) { /* ...and if it has the right 'gzip' indicator... */ /* We record the compression format in a request note, so we * can get it again later, and so it can potentially be logged. */ if ( strstr( accept_encoding, "gzip" ) ) { process = 1; /* ...set the 'process' flag TRUE */ ap_table_setn( r->notes,"mod_gzip_compression_format", ap_pstrdup(r->pool,"gzip")); } else if ( strstr( accept_encoding, "deflate" ) ) { process = 1; /* ...set the 'process' flag TRUE */ ap_table_setn( r->notes,"mod_gzip_compression_format", ap_pstrdup(r->pool,"deflate")); } }/* End 'if( accept_encoding )' */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 'process' flag = %d\n",cn,process); #endif if ( !process ) /* Request does not meet criteria for processing... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: No 'gzip' capability specified by user-agent.\n",cn); mod_gzip_printf( "%s: 'process' flag is FALSE.\n",cn); mod_gzip_printf( "%s: This request will not be processed.\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_GZIP")); if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: The inbound request header does not have 'Accept-encoding: gzip'"); } #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; } else /* 'gzip' designator was seen in 'Accept-Encoding:' field */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 'gzip' or 'deflate' capability specified by user-agent.\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } /* * Handle the transaction... * * At this point the inbound header analysis has been completed * and we are assuming that the user agent is capable of accepting * the content encodings we can provide. * * We must now 'do the right thing' based on what type of * request it actually is... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler); mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); mod_gzip_printf( "%s: Call mod_gzip_get_action_flag()...\n",cn); #endif action_flag = mod_gzip_get_action_flag( (request_rec *) r, (mod_gzip_conf *) conf ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back mod_gzip_get_action_flag()...\n",cn); mod_gzip_printf( "%s: action_flag = %d\n",cn,action_flag); mod_gzip_printf( "%s: conf->do_static_files = %d\n",cn,(int)conf->do_static_files); mod_gzip_printf( "%s: conf->do_cgi = %d\n",cn,(int)conf->do_cgi); #endif /* * Perform the right 'action' for this transaction... */ if ( action_flag == MOD_GZIP_IMAP_DECLINED1 ) { /* * If the transaction is to be DECLINED then just set the final * return code to DECLINED, fall through, and return. */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_DECLINED1\n",cn); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: action_flag = MOD_GZIP_IMAP_DECLINED1 "); } rc = DECLINED; } else if ( action_flag == MOD_GZIP_IMAP_DYNAMIC1 ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_DYNAMIC1\n",cn); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: action_flag = MOD_GZIP_IMAP_DYNAMIC1 "); } /* * Check the flag that can control whether or not the * CGI dynamic output handler is ever called... */ if ( conf->do_cgi != 1 ) /* CGI handler is OFF for now... */ { if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: Calls to CGI handler currently DISABLED "); } #ifdef MOD_GZIP_USES_APACHE_LOGS /* Update the result string for Apache log(s)... */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:CGI_OFF")); #endif rc = DECLINED; /* Just set final return code and fall through */ }/* End 'if( conf->do_cgi == 0 )' */ else /* It's OK to call the handler... */ { if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: Calling cgi_handler for r->uri=[%s]",r->uri); } /* Take care of some business BEFORE calling the */ /* dynamic handler... */ mod_gzip_prepare_for_dynamic_call( r ); /* PHP NOTE */ /* r->path_info must be set before ap_add_cgi_vars() */ /* is called from within the upcoming hander or we */ /* won't get PATH_INFO or PATH_TRANSLATED environment */ /* variables set and PHP.EXE will return 'No input file' */ /* error message since it depends on both of these being */ /* set. r->path_info must be set to r->uri */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 1 r->uri = [%s]\n", cn, r->uri ); mod_gzip_printf( "%s: 1 r->path_info = [%s]\n", cn, r->path_info ); mod_gzip_printf( "%s: Setting r->path_info to r->uri for CGI...\n", cn ); #endif r->path_info = r->uri; #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 2 r->uri = [%s]\n", cn, r->uri ); mod_gzip_printf( "%s: 2 r->path_info = [%s]\n", cn, r->path_info ); #endif /* Call the actual handler... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call mod_gzip_cgi_handler()...\n",cn); #endif rc = mod_gzip_cgi_handler( (request_rec *) r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back mod_gzip_cgi_handler()... rc=%d\n",cn,rc); #endif }/* End 'else' - OK to call handler */ } else if ( action_flag == MOD_GZIP_IMAP_STATIC1 ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: action_flag = MOD_GZIP_IMAP_STATIC1\n",cn); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: action_flag = MOD_GZIP_IMAP_STATIC1 "); } /* * Check the flag that can control whether or not the * static handler is ever called... */ if ( conf->do_static_files != 1 ) /* Static handler is OFF for now... */ { if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: Calls to static handler currently DISABLED "); } #ifdef MOD_GZIP_USES_APACHE_LOGS /* Update the result string for Apache log(s)... */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:STATIC_OFF")); #endif rc = DECLINED; /* Just set final return code and fall through */ }/* End 'if( conf->do_static == 0 )' */ else /* It's OK to call the handler... */ { if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: Calling static_handler for r->uri=[%s]",r->uri); } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call mod_gzip_static_file_handler()...\n",cn); #endif rc = mod_gzip_static_file_handler( (request_rec *) r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back mod_gzip_static_file_handler()... rc=%d\n",cn,rc); #endif }/* End 'else' - OK to call the handler */ } else /* Safety catch... No pickup for the 'action' flag... */ { if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: action_flag = MOD_GZIP_IMAP_????? Unknown value"); } if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: No pickup for specified 'action' flag."); } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: action_flag = MOD_GZIP_??? Unknown value\n",cn); #endif rc = DECLINED; } /* * Record results to logs, if applicable, and return... * * The 'r->notes' values that can be used to disply result * information in the standard Apache log files should have * already been updated by the handler that was actually * used to process the transaction. */ #ifdef MOD_GZIP_DEBUG1 if ( rc == OK ) { mod_gzip_printf( "%s: Exit > return( rc=%d OK ) >\n",cn,rc); } else if ( rc == DECLINED ) { mod_gzip_printf( "%s: Exit > return( rc=%d DECLINED ) >\n",cn,rc); } else /* HTTP ERROR VALUE... */ { mod_gzip_printf( "%s: Exit > return( rc=%d HTTP_ERROR ) >\n",cn,rc); } #endif /* MOD_GZIP_DEBUG1 */ return rc; /* Could be OK or DECLINED or HTTP_ERROR */ }/* End of mod_gzip_request_handler() */ int mod_gzip_prepare_for_dynamic_call( request_rec *r ) { int rc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_prepare_for_dynamic_call()"; #endif /* * Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n",cn); #endif /* * mod_gzip can run other modules directly... */ /* * First run mod_action and see it there's a SCRIPT * for this mime type... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: 1 ***: r->uri =[%s]\n", cn, r->uri ); mod_gzip_printf( "%s: 1 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); mod_gzip_printf( "%s: 1 ***: r->filename =[%s]\n", cn, r->filename ); mod_gzip_printf( "%s: 1 ***: r->content_type=[%s]\n", cn, r->content_type ); mod_gzip_printf( "%s: 1 ***: r->handler =[%s]\n", cn, r->handler ); mod_gzip_printf( "%s: Call mod_gzip_run_mod_action(r)...\n",cn); #endif rc = mod_gzip_run_mod_action( (request_rec *) r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back mod_gzip_run_mod_action(r)...\n",cn); if ( rc == OK ) { mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc ); } else if ( rc == DECLINED ) { mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc ); } else if ( rc == DONE ) /* -2 means 'totally done' */ { mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc ); } else /* Probably an HTTP ERROR value... */ { mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc ); } mod_gzip_printf( "%s: 2 ***: r->uri =[%s]\n", cn, r->uri ); mod_gzip_printf( "%s: 2 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); mod_gzip_printf( "%s: 2 ***: r->filename =[%s]\n", cn, r->filename ); mod_gzip_printf( "%s: 2 ***: r->content_type=[%s]\n", cn, r->content_type ); mod_gzip_printf( "%s: 2 ***: r->handler =[%s]\n", cn, r->handler ); #endif /* MOD_GZIP_DEBUG1 */ /* * Now run mod_alias and get any aliases converted * to real pathnames... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call mod_gzip_run_mod_alias(r)...\n",cn); #endif rc = mod_gzip_run_mod_alias( (request_rec *) r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back mod_gzip_run_mod_alias(r)...\n",cn); if ( rc == OK ) { mod_gzip_printf( "%s: rc = %d = OK\n",cn, rc ); } else if ( rc == DECLINED ) { mod_gzip_printf( "%s: rc = %d = DECLINED\n",cn, rc ); } else if ( rc == DONE ) /* -2 means 'totally done' */ { mod_gzip_printf( "%s: rc = %d = DONE\n",cn, rc ); } else /* Probably an HTTP ERROR value... */ { mod_gzip_printf( "%s: rc = %d = HTTP_ERROR?\n",cn, rc ); } mod_gzip_printf( "%s: 3 ***: r->uri =[%s]\n", cn, r->uri ); mod_gzip_printf( "%s: 3 ***: r->unparsed_uri=[%s]\n", cn, r->unparsed_uri ); mod_gzip_printf( "%s: 3 ***: r->filename =[%s]\n", cn, r->filename ); mod_gzip_printf( "%s: 3 ***: r->content_type=[%s]\n", cn, r->content_type ); mod_gzip_printf( "%s: 3 ***: r->handler =[%s]\n", cn, r->handler ); #endif /* MOD_GZIP_DEBUG1 */ return OK; }/* End of mod_gzip_prepare_for_dynamic_call() */ int mod_gzip_static_file_handler( request_rec *r ) { int rc = 0; long input_size = 0; FILE* ifh1 = 0; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_static_file_handler()"; #endif /* * Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Processing file [%s]\n",cn,r->filename); mod_gzip_printf( "%s: r->finfo.st_size = %ld\n", cn, (long) r->finfo.st_size); #endif /* * If there is a valid file size already associated with * the request then we can assume the core stat() call succeeded * and that r->filename actually exists. We shouldn't need * to waste a call to 'fopen()' just to find out for ourselves * if the file exists. * * If the inbound file size was '0' then we need to do some * verifications of our own before we give up since the * absence of size might just be a simple bug in the parent code. */ if ( r->finfo.st_size > 0 ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Source file length already known...\n",cn); #endif input_size = (long) r->finfo.st_size; } else /* Do our own checking... */ { /* * See if the requested source file exists... * Be SURE to open the file in BINARY mode... */ ifh1 = fopen( r->filename, "rb" ); if ( !ifh1 ) /* The file cannot be found or opened... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: The requested source file was NOT FOUND.\n",cn); mod_gzip_printf( "%s: Exit > return( HTTP_NOT_FOUND ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* HTTP ERROR conditions provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:HTTP_NOT_FOUND")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ return HTTP_NOT_FOUND; } else /* The file was found and opened OK... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: The requested source file is now OPEN...\n",cn); #endif } /* * Move the current file pointer to the end of the file... */ if ( fseek( ifh1, 0, SEEK_END ) ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ERROR: fseek() call failed...\n",cn); #endif fclose( ifh1 ); /* FILE is still open so CLOSE it... */ /* fseek() failure could be a platform issue so log the event... */ ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server, "mod_gzip: fseek() failed for r->filename=[%s]",r->filename ); /* Return DECLINED and let default logic finish the request... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FSEEK_FAIL")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; } /* * Get the current SIZE of the requested file... */ input_size = (long) ftell( ifh1 ); if ( input_size == -1l ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ERROR: ftell() call failed...\n",cn); #endif fclose( ifh1 ); /* FILE is still open so CLOSE it... */ /* ftell() failure could be a platform issue so log the event... */ ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server, "mod_gzip: ftell() failed for r->filename=[%s]", r->filename ); /* Return DECLINED and let default logic finish the request... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FTELL_FAIL")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; } /* * Once we have the length just close the file... */ if ( fclose( ifh1 ) == EOF ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ERROR: fclose() following ftell() call failed...\n",cn); #endif /* fclose() failure could be a platform issue so log the event... */ ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server, "mod_gzip: fclose() failed for r->filename=[%s]",r->filename ); /* Return DECLINED and let default logic finish the request... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:FCLOSE_FAIL")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; } }/* End 'else' */ /* * We have the static filename and the length. * That's pretty much all we need at this point so * go ahead and encode/transmit the object... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call mod_gzip_encode_and_transmit()...\n",cn); #endif rc = mod_gzip_encode_and_transmit( (request_rec *) r, /* request_rec */ (char *) r->filename, /* source ( Filename or Memory buffer ) */ (int ) 1, /* 1=Source is a file 0=Memory buffer */ (long ) input_size, /* input_size */ (int ) 0 /* nodecline flag 0=Ok to DECLINE 1=No */ ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back mod_gzip_encode_and_transmit()...\n",cn); #endif /* * The encode/transmit path should have already updated * any relevant 'r->note' values ( if used ) for the transaction * to reflect the results of the operation. * * Just return the result code and finish the transaction. */ #ifdef MOD_GZIP_DEBUG1 if ( rc == OK ) { mod_gzip_printf( "%s: Exit > return( rc = %d OK ) >\n",cn,rc); } else if ( rc == DECLINED ) { mod_gzip_printf( "%s: Exit > return( rc = %d DECLINED ) >\n",cn,rc); } else /* HTTP ERROR */ { mod_gzip_printf( "%s: Exit > return( rc = %d HTTP_ERROR ) >\n",cn,rc); } #endif /* MOD_GZIP_DEBUG1 */ return( rc ); }/* End of mod_gzip_static_file_handler() */ int mod_gzip_create_unique_filename( mod_gzip_conf *mgc, char *target, int targetmaxlen ) { /* * Creates a unique work file name. */ long process_id = 0; /* Current Process ID */ long thread_id = 0; /* Current thread ID */ #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_create_unique_filename()"; #endif /* Start... */ #ifdef _WIN32 process_id = (long) GetCurrentProcessId(); thread_id = (long) GetCurrentThreadId(); #else /* !_WIN32 */ process_id = (long) getpid(); thread_id = (long) process_id; /* TODO: Add pthreads call */ #endif /* _WIN32 */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n",cn ); mod_gzip_printf( "%s: target = %ld\n",cn,(long)target); mod_gzip_printf( "%s: targetmaxlen = %ld\n",cn,(long)targetmaxlen); mod_gzip_printf( "%s: process_id = %ld\n",cn,(long)process_id ); mod_gzip_printf( "%s: thread_id = %ld\n",cn,(long)thread_id ); mod_gzip_printf( "%s: mod_gzip_iusn = %ld\n",cn,(long)mod_gzip_iusn ); #endif /* * Sanity checks... */ if ( ( !target ) || ( targetmaxlen == 0 ) ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Invalid target or targetmaxlen value.\n",cn); mod_gzip_printf( "%s: Exit > return( 1 ) > ERROR >\n",cn ); #endif return 1; } /* * Use the PROCESS + THREAD ID's and the current IUSN * ( Instance Unique Sequence Number ) transaction ID to * create a one-time only unique output workfile name... */ sprintf( target, "%s%s_%ld_%ld_%ld.wrk", mgc->cache.root, /* Either ServerRoot or Config specified dir. */ mod_gzip_dirsep, /* Forward slash for UNIX, backslash for WIN32 */ (long) process_id, /* Current process ID */ (long) thread_id, /* Current thread ID */ (long) mod_gzip_iusn /* Instance Unique Sequence Number */ ); mod_gzip_iusn++; /* Increment Instance Unique Sequence Number */ if ( mod_gzip_iusn > 999999999L ) mod_gzip_iusn = 1; /* Wrap */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: target = [%s]\n",cn,target); mod_gzip_printf( "%s: Exit > return( 0 ) >\n",cn ); #endif return 0; }/* End of mod_gzip_create_unique_filename() */ #ifdef MOD_GZIP_ALLOWS_INTERNAL_COMMANDS int mod_gzip_send_html_command_response( request_rec *r, /* Request record */ char *tmp, /* Response to send */ char *ctype /* Content type string */ ) { /* Generic command response transmitter... */ int tmplen=0; char content_length[20]; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_send_html_command_response()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n",cn); mod_gzip_printf( "%s: ctype=[%s]\n",cn,ctype); #endif /* Add the length of the response to the output header... */ /* The third parameter to ap_table_set() MUST be a string. */ tmplen = strlen( tmp ); sprintf( content_length, "%d", tmplen ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: content_length = [%s]\n",cn,content_length); #endif ap_table_set( r->headers_out, "Content-Length", content_length ); /* Make sure the content type matches this response... */ r->content_type = ctype; /* Actual type passed by caller */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); #endif /* Start a timer... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_soft_timeout()...\n",cn); #endif ap_soft_timeout( "mod_gzip_send_html_command", r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_soft_timeout()...\n",cn); #endif #ifdef MOD_GZIP_COMMANDS_USE_LAST_MODIFIED /* Be sure to update the modifcation 'time' to current */ /* time before calling 'ap_set_last_modified()'. All that */ /* call does is set the r->xxxx value into the output */ /* header. It doesn't actually update the time itself. */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_update_mtime(r,r-finfo.st_mtime)...\n",cn); #endif ap_update_mtime( r, r->finfo.st_mtime ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_update_mtime(r,r-finfo.st_mtime)...\n",cn); #endif /* Update the 'Last modified' stamp in output header... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_set_last_modified()...\n",cn); #endif ap_set_last_modified(r); /* TODO: Add 'no-cache' option(s) to mod_gzip command responses */ /* so user doesn't have hit reload to get fresh data. */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_set_last_modified()...\n",cn); #endif #endif /* MOD_GZIP_COMMANDS_USE_LAST_MODIFIED */ /* Send the HTTP response header... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn); #endif ap_send_http_header(r); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn); #endif /* Send the response BODY... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Sending response...\n%s\n",cn,tmp); #endif #ifdef MOD_GZIP_USES_AP_SEND_MMAP /* Use ap_send_mmap() call to send the data... */ ap_send_mmap( tmp, r, 0, tmplen ); #else /* !MOD_GZIP_USES_AP_SEND_MMAP */ /* Use ap_rwrite() call to send the data... */ ap_rwrite( tmp, tmplen, r ); #endif /* MOD_GZIP_USES_AP_SEND_MMAP */ /* Clean up and exit... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn); #endif ap_kill_timeout(r); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn); mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn); #endif return OK; }/* End of mod_gzip_send_html_command_response() */ #endif /* MOD_GZIP_ALLOWS_INTERNAL_COMMANDS */ static void * mod_gzip_create_config( pool *p, server_rec *s ) { int i; mod_gzip_conf *ps = 0; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_create_config()"; #endif /* * Set all the configuration default values... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); #endif /* * Allocate a new config structure... */ ps = ( mod_gzip_conf * ) ap_pcalloc( p, sizeof( mod_gzip_conf ) ); /* * Set all default values... */ ps->req = 1; /* Default is ON */ ps->req_set = 1; /* Default is ON */ ps->do_static_files = 1; /* Default is ON */ ps->do_cgi = 1; /* Default is ON */ ps->keep_workfiles = 0; /* 1=Keep workfiles 0=No */ ps->min_http = 0; /* 1001=HTTP/1.1 Default=All HTTP levels */ ps->minimum_file_size = (long) mod_gzip_minimum_file_size; /* Minimum file size in bytes */ ps->maximum_inmem_size = (long) mod_gzip_maximum_inmem_size; /* Maximum size for in-memory compression */ /* Compressed object cache control variables... */ /* Using these default values the compressed object cache /* can have 2^18 directories (256,000) */ ps->cache.root = ap_server_root; /* Default DIR is ServerRoot */ ps->cache.space = MOD_GZIP_DEFAULT_CACHE_SPACE; ps->cache.space_set = 0; ps->cache.maxexpire = MOD_GZIP_DEFAULT_CACHE_MAXEXPIRE; ps->cache.maxexpire_set = 0; ps->cache.defaultexpire = MOD_GZIP_DEFAULT_CACHE_EXPIRE; ps->cache.defaultexpire_set = 0; ps->cache.lmfactor = MOD_GZIP_DEFAULT_CACHE_LMFACTOR; ps->cache.lmfactor_set = 0; ps->cache.gcinterval = -1; ps->cache.gcinterval_set = 0; ps->cache.dirlevels = 3; ps->cache.dirlevels_set = 0; ps->cache.dirlength = 1; ps->cache.dirlength_set = 0; /* Initialize the include/exclude item map list... */ /* For now all init values are ZERO but don't use */ /* memset() since this may not always be the case. */ ps->imap_total_entries = 0; for ( i=0; iimap[i].include = 0; ps->imap[i].type = 0; ps->imap[i].action = 0; ps->imap[i].name[0] = 0; }/* End 'i' loop */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ps->imap_total_entries = %d\n", cn, ps->imap_total_entries ); mod_gzip_printf( "%s: Exit > return( ps ) >\n", cn ); #endif return ps; }/* End of mod_gzip_create_config() */ static void * mod_gzip_merge_config( pool *p, void *basev, void *overridesv ) { mod_gzip_conf *ps = ap_pcalloc(p, sizeof(mod_gzip_conf)); mod_gzip_conf *base = (mod_gzip_conf *) basev; mod_gzip_conf *overrides = (mod_gzip_conf *) overridesv; ps->req = (overrides->req_set == 0) ? base->req : overrides->req; ps->cache.root = (overrides->cache.root == NULL) ? base->cache.root : overrides->cache.root; ps->cache.space = (overrides->cache.space_set == 0) ? base->cache.space : overrides->cache.space; ps->cache.maxexpire = (overrides->cache.maxexpire_set == 0) ? base->cache.maxexpire : overrides->cache.maxexpire; ps->cache.defaultexpire = (overrides->cache.defaultexpire_set == 0) ? base->cache.defaultexpire : overrides->cache.defaultexpire; ps->cache.lmfactor = (overrides->cache.lmfactor_set == 0) ? base->cache.lmfactor : overrides->cache.lmfactor; ps->cache.gcinterval = (overrides->cache.gcinterval_set == 0) ? base->cache.gcinterval : overrides->cache.gcinterval; ps->cache.dirlevels = (overrides->cache.dirlevels_set == 0) ? base->cache.dirlevels : overrides->cache.dirlevels; ps->cache.dirlength = (overrides->cache.dirlength_set == 0) ? base->cache.dirlength : overrides->cache.dirlength; return ps; }/* End of mod_gzip_merge_config() */ /* * Module configuration directive handlers... */ static const char * mod_gzip_set_on(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_on()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) ) { /* Set the master 'request control' switches ON... */ mgc->req = 1; /* Yes */ mgc->req_set = 1; /* Yes */ } else /* Set the master 'request control' switches OFF... */ { mgc->req = 0; /* No */ mgc->req_set = 0; /* No */ } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: mgc->req = %ld\n", cn, (long) mgc->req ); mod_gzip_printf( "%s: mgc->req_set = %ld\n", cn, (long) mgc->req_set ); #endif return NULL; } static const char * mod_gzip_set_keep_workfiles(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_keep_workfiles()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) ) { mgc->keep_workfiles = 1; /* Yes */ } else { mgc->keep_workfiles = 0; /* No */ } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: mgc->keep_workfiles = %ld\n", cn, (long) mgc->keep_workfiles ); #endif return NULL; } static const char * mod_gzip_set_min_http(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_min_http()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); mgc->min_http = (int) atoi( arg ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: mgc->min_http = %ld\n", cn, (long) mgc->min_http ); #endif return NULL; } static const char * mod_gzip_imap_add_item( mod_gzip_conf *mgc, char *arg, int flag1 ) { int x; char *p1; int ch1; int this_type=0; int this_action=0; int this_include=flag1; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_imap_add_item()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: 1 arg=[%s]\n", cn, arg ); if ( flag1 == 1 ) { mod_gzip_printf( "%s: flag1 = %d = INCLUDE\n", cn, flag1 ); } else if ( flag1 == 0 ) { mod_gzip_printf( "%s: flag1 = %d = EXCLUDE\n", cn, flag1 ); } else { mod_gzip_printf( "%s: flag1 = %d = ??? Unknown value\n", cn, flag1 ); } mod_gzip_printf( "%s: MOD-GZIP_IMAP_MAXNAMES = %d\n", cn, MOD_GZIP_IMAP_MAXNAMES ); mod_gzip_printf( "%s: mgc->imap_total_entries = %d\n", cn, mgc->imap_total_entries ); #endif /* MOD_GZIP_DEBUG1 */ /* * Parse the config line... */ p1 = arg; while((*p1!=0)&&(*p1<33)) p1++; ch1 = *p1; this_type = MOD_GZIP_IMAP_ISHANDLER; this_action = MOD_GZIP_IMAP_DYNAMIC1; if ( ch1 == '!' ) { arg++; p1 = arg; while((*p1!=0)&&(*p1<33)) p1++; ch1 = *p1; } else { this_action = MOD_GZIP_IMAP_STATIC1; } if ( ch1 == '.' ) { this_type = MOD_GZIP_IMAP_ISEXT; } else { p1 = arg; while (*p1!=0) { if ( *p1 == '/' ) { this_type = MOD_GZIP_IMAP_ISMIME; } p1++; } } /* * Safety checks... */ if ( ( this_type != MOD_GZIP_IMAP_ISMIME ) && ( this_type != MOD_GZIP_IMAP_ISEXT ) && ( this_type != MOD_GZIP_IMAP_ISHANDLER ) ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: this_type = %d = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,this_type); mod_gzip_printf( "%s: return( mod_gzip: ERROR: Unrecognized item 'type'\n",cn); #endif return( "mod_gzip: ERROR: Unrecognized item 'type'" ); } if ( ( this_action != MOD_GZIP_IMAP_DYNAMIC1 ) && ( this_action != MOD_GZIP_IMAP_STATIC1 ) ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: this_action = %d = MOD_GZIP_IMAP_??? Unknown action\n",cn,this_action); mod_gzip_printf( "%s: return( mod_gzip: ERROR: Unrecognized item 'action'\n",cn); #endif return( "mod_gzip: ERROR: Unrecognized item 'action'" ); } /* * Wildcards... */ if ( this_type != MOD_GZIP_IMAP_ISMIME ) { /* * Wildcards are only allowed in MIME strings such as 'image/*' */ p1 = arg; while (*p1!=0) { if ( *p1 == '*' ) { return( "mod_gzip: ERROR: Wildcards are only allowed in MIME strings." ); } p1++; } } /* * If there is room for a new record then add it... */ if ( mgc->imap_total_entries < MOD_GZIP_IMAP_MAXNAMES ) { if ( strlen( arg ) < MOD_GZIP_IMAP_MAXNAMELEN ) { x = mgc->imap_total_entries; p1 = arg; while((*p1!=0)&&(*p1<33)) p1++; strcpy( mgc->imap[x].name, p1 ); mgc->imap[x].include = this_include; mgc->imap[x].type = this_type; mgc->imap[x].action = this_action; mgc->imap_total_entries++; /* Increase onboard items */ } else /* ERROR: Name is too long */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: return( mod_gzip: ERROR: Item name is too long\n",cn); #endif return( "mod_gzip: ERROR: Item name is too long" ); } } else /* ERROR: INDEX is FULL */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: return( mod_gzip: ERROR: Item index is full\n",cn); #endif return( "mod_gzip: ERROR: Item index is full" ); } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn); #endif return NULL; }/* End of mod_gzip_imap_add_item() */ #ifdef MOD_GZIP_DEBUG1 int mod_gzip_imap_show_items( mod_gzip_conf *mgc ) { /* * DEBUG only. Show the complete include/exclude list. * This is normally called from mod_gzip_init() * after all the configuration routines have executed. */ int i; int x; char cn[]="mod_gzip_imap_show_items()"; /* Start... */ mod_gzip_printf( "\n"); mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: mgc->imap_total_entries= %d\n", cn, (long) mgc->imap_total_entries ); for ( i=0; iimap_total_entries; i++ ) { x = i; /* Work variable */ mod_gzip_printf( "\n"); mod_gzip_printf( "%s: mgc->imap[%3.3d].include = %d\n", cn,x,mgc->imap[x].include); mod_gzip_printf( "%s: mgc->imap[%3.3d].type = %d\n", cn,x,mgc->imap[x].type); if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISMIME ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISMIME\n",cn,x); } else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISEXT ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISEXT\n",cn,x); } else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISHANDLER ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISHANDLER\n",cn,x); } else /* Unrecognized item type... */ { mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,x); } mod_gzip_printf( "%s: mgc->imap[%3.3d].action = %d\n", cn,x,mgc->imap[x].action); if ( mgc->imap[x].action == MOD_GZIP_IMAP_DYNAMIC1 ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_DYNAMIC1\n",cn,x); } else if ( mgc->imap[x].action == MOD_GZIP_IMAP_STATIC1 ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_STATIC1\n",cn,x); } else /* Unrecognized action type... */ { mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_??? Unknown action\n",cn,x); } mod_gzip_printf( "%s: mgc->imap[%3.3d].name = [%s]\n",cn,x,mgc->imap[x].name); }/* End 'i' loop */ mod_gzip_printf( "\n"); return 0; }/* End of mod_gzip_imap_show_items() */ #endif /* MOD_GZIP_DEBUG1 */ static const char * mod_gzip_set_item_include(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_item_include()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); /* Pass pre-determined pointer to config structure... */ /* Pass '1' for parm 3 to INCLUDE this item... */ return( mod_gzip_imap_add_item( mgc, arg, 1 ) ); } static const char * mod_gzip_set_item_exclude(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_item_exclude()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); /* Pass pre-determined pointer to config structure... */ /* Pass '0' for parm 3 to EXCLUDE this item... */ return( mod_gzip_imap_add_item( mgc, arg, 0 ) ); } static const char * mod_gzip_set_temp_dir(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; char cn[]="mod_gzip_set_temp_dir()"; /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); mgc->cache.root = arg; /* For now temp dir is used as cache root */ strcpy( mod_gzip_temp_dir, arg ); mgc->cache.root = mod_gzip_temp_dir; #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: mgc->cache.root=[%s]\n", cn, mgc->cache.root ); #endif return NULL; } static const char * mod_gzip_set_minimum_file_size(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; long lval; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_minimum_file_size()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); lval = (long) atol(arg); /* 300 bytes is the minimum at all times */ if ( lval < 300L ) lval = 300L; mgc->minimum_file_size = (long) lval; /* Set config */ mod_gzip_minimum_file_size = (long) lval; /* Set global */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ....mgc->minimum_file_size = %ld\n", cn, (long) mgc->minimum_file_size ); mod_gzip_printf( "%s: mod_gzip_minimum_file_size = %ld\n", cn, (long) mod_gzip_minimum_file_size ); #endif return NULL; } static const char * mod_gzip_set_maximum_inmem_size(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; long lval=0; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_maximum_inmem_size()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); lval = (long) atol(arg); /* 60000 bytes is the current maximum since a malloc() call is used */ if ( lval > 60000L ) lval = 60000L; mgc->maximum_inmem_size = (long) lval; /* Set config */ mod_gzip_maximum_inmem_size = (long) lval; /* Set global */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ....mgc->maximum_inmem_size = %ld\n", cn, (long) mgc->maximum_inmem_size ); mod_gzip_printf( "%s: mod_gzip_maximum_inmem_size = %ld\n", cn, (long) mod_gzip_maximum_inmem_size ); #endif return NULL; } static const char * mod_gzip_set_do_static_files(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_do_static_files()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) ) { mgc->do_static_files = 1; /* Yes */ } else { mgc->do_static_files = 0; /* No */ } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: mgc->do_static_files = %ld\n", cn, (long) mgc->do_static_files ); #endif return NULL; } static const char * mod_gzip_set_do_cgi(cmd_parms *parms, void *dummy, char *arg) { mod_gzip_conf *mgc; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_set_do_cgi()"; #endif /* Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry\n", cn ); mod_gzip_printf( "%s: arg=[%s]\n", cn, arg ); #endif mgc = ( mod_gzip_conf * ) ap_get_module_config(parms->server->module_config, &gzip_module); if ( ( arg[0] == 'Y' )||( arg[0] == 'y' ) ) { mgc->do_cgi = 1; /* Yes */ } else { mgc->do_cgi = 0; /* No */ } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: mgc->do_cgi = %ld\n", cn, (long) mgc->do_cgi ); #endif return NULL; } static const handler_rec mod_gzip_handlers[] = { /* * This is where we associate an ASCII NAME for our 'handler' * which is what gets set into the r->handler field for a * request and allows the function name associated with the * ASCII name to be called and handle the request... */ /* Add a 'name' and some types to our handler... */ {"mod_gzip_handler", mod_gzip_handler}, {CGI_MAGIC_TYPE, mod_gzip_handler}, {"cgi-script", mod_gzip_handler}, {"*", mod_gzip_handler}, {NULL} }; static const command_rec mod_gzip_cmds[] = { /* * Define our httpd.conf configuration diectives and * the local routines that are responsible for processing * those directives when the time comes... */ {"mod_gzip_on", mod_gzip_set_on, NULL, RSRC_CONF, TAKE1, "Yes=mod_gzip will handle requests No=mod_gzip runs in 'passthrough' mode"}, {"mod_gzip_do_static_files", mod_gzip_set_do_static_files, NULL, RSRC_CONF, TAKE1, "'Yes' means mod_gzip will compress static files."}, {"mod_gzip_do_cgi", mod_gzip_set_do_cgi, NULL, RSRC_CONF, TAKE1, "'Yes' means mod_gzip will compress dynamic CGI script output."}, {"mod_gzip_keep_workfiles", mod_gzip_set_keep_workfiles, NULL, RSRC_CONF, TAKE1, "On=Keep work files Off=No"}, {"mod_gzip_min_http", mod_gzip_set_min_http, NULL, RSRC_CONF, TAKE1, "Minimum HTTP support level to receive compression. 1001=HTTP/1.1"}, {"mod_gzip_minimum_file_size", mod_gzip_set_minimum_file_size, NULL, RSRC_CONF, TAKE1, "The minimum size ( in bytes ) before compression will be attempted"}, {"mod_gzip_maximum_inmem_size", mod_gzip_set_maximum_inmem_size, NULL, RSRC_CONF, TAKE1, "The maximum size ( in bytes ) to use for in-memory compression."}, {"mod_gzip_temp_dir", mod_gzip_set_temp_dir, NULL, RSRC_CONF, TAKE1, "The directory to use for work files and compression cache"}, {"mod_gzip_item_include", mod_gzip_set_item_include, NULL, RSRC_CONF, TAKE1, "Add the item the inclusion list"}, {"mod_gzip_item_exclude", mod_gzip_set_item_exclude, NULL, RSRC_CONF, TAKE1, "Add the item the exclusion list"}, {NULL} }; /* * The actual module 'jump' table... * * If one of the fixed 'call' points has a valid function * address then Apache will 'call' into it at the appropriate time. * * When the compressed object cache is engaged we will need to * simply add some handlers for the URI detection and translation * call point(s). */ module MODULE_VAR_EXPORT gzip_module = { STANDARD_MODULE_STUFF, mod_gzip_init, /* initializer */ NULL, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ mod_gzip_create_config, /* create per-server config structure */ mod_gzip_merge_config, /* merge per-server config structures */ mod_gzip_cmds, /* command table */ mod_gzip_handlers, /* handlers */ NULL, /* translate_handler */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* pre-run fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */ }; #ifdef NETWARE int main(int argc, char *argv[]) { ExitThread(TSR_THREAD, 0); } #endif FILE *mod_gzip_open_output_file( request_rec *r, char *output_filename, int *rc ) { FILE *ifh; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_open_output_file():::"; #endif /* * Start... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n",cn); mod_gzip_printf( "%s: output_filename=[%s]\n",cn,output_filename); #endif ifh = fopen( output_filename, "rb" ); /* Open in BINARY mode */ if ( !ifh ) /* The file failed to open... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ERROR: Cannot open file [%s]\n", cn,output_filename); #endif /* * The workfile was created OK but now will not re-open. * This is worth a strike in the ERROR log. */ ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_ERR, r->server, "mod_gzip: Cannot re-open output_filename=[%s]", output_filename ); /* Return DECLINED and let default logic finish the request... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( NULL ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:WORK_OPENFAIL")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ *rc = DECLINED; /* Update caller's result code... */ return NULL; }/* End 'if ( !ifh )' */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: File is now open...\n",cn); mod_gzip_printf( "%s: Exit > return( FILE *ifh ) >\n",cn); #endif *rc = OK; /* Update caller's result code */ return ifh; /* Return the file handle */ }/* End of mod_gzip_open_output_file() */ int mod_gzip_encode_and_transmit( request_rec *r, char *source, int source_is_a_file, long input_size, int nodecline ) { GZP_CONTROL gzc; GZP_CONTROL* gzp = &gzc; int rc = 0; FILE *ifh = 0; int bytesread = 0; long output_size = 0; long compression_ratio = 0; char* gz1_ismem_obuf = 0; int finalize_stats = 1; int gz1_ismem_obuf_was_allocated = 0; char content_length[20]; /* For Content-length updates */ #define MOD_GZIP_LARGE_BUFFER_SIZE 8192 char tmp[ MOD_GZIP_LARGE_BUFFER_SIZE + 2 ]; /* Scratch buffer */ char *actual_content_encoding_name = "gzip"; /* Adjustable */ const char *compression_format; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_encode_and_transmit()"; #endif void *modconf = r->server->module_config; #ifdef MOD_GZIP_USES_APACHE_LOGS char log_info[40]; /* Scratch buffer */ #endif /* * Start... * * Establish a local pointer to module configuration data... */ mod_gzip_conf *conf = (mod_gzip_conf *) ap_get_module_config( modconf, &gzip_module ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n", cn); mod_gzip_printf( "%s: source_is_a_file = %d\n", cn, source_is_a_file); mod_gzip_printf( "%s: nodecline = %d\n", cn, nodecline); if ( source_is_a_file ) /* Show the filename... */ { mod_gzip_printf( "%s: source = [%s]\n", cn, source); } else /* Don't try to print the memory buffer... */ { mod_gzip_printf( "%s: source = MEMORY BUFFER\n", cn ); } mod_gzip_printf( "%s: input_size = %ld\n", cn,(long)input_size); #endif /* MOD_GZIP_DEBUG1 */ #ifdef MOD_GZIP_USES_APACHE_LOGS /* This routine 'assumes' that the final result is 'OK' */ /* and lets the remainder of the processing set the result */ /* string to some other value, if necessary. */ /* Since we are now using the 'nodecline' flag and might */ /* have to 'stand and deliver' then this allows the right */ /* result code to appear in the log files even if we */ /* cannot DECLINE the processing. */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"OK")); /* We can also update the 'input' size right away since it is known */ sprintf( log_info,"%d", (int) input_size ); ap_table_setn( r->notes,"mod_gzip_input_size",ap_pstrdup(r->pool,log_info)); #endif /* MOD_GZIP_USES_APACHE_LOGS */ /* * If the source has no length then DECLINE the processing... */ if ( input_size < 1 ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ERROR: Input source has no valid length.\n",cn); mod_gzip_printf( "%s: This request will not be processed...\n",cn); #endif /* An existing request object with no length is worth a warning... */ ap_log_error( APLOG_MARK,APLOG_NOERRNO|APLOG_WARNING, r->server, "mod_gzip: r->filename=[%s] has no length",r->filename ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_I_LEN")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ return DECLINED; } /* * If we're only supposed to send header information (HEAD request) * then all we need to do is call ap_send_http_header() at this point * and then return 'OK'... */ if ( r->header_only ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: HEAD request only... ignore body data...\n",cn); #endif /* * Set outbound response header fields... * * NOTE: If this is just a HEAD request then * there is no need to make the API call... * * ap_update_mtime( r, r->finfo.st_mtime ); * * ...and update the actual time. Use the time * that's currently associated with the object. */ ap_set_last_modified(r); ap_set_etag(r); ap_table_setn(r->headers_out, "Accept-Ranges", "bytes"); /* Start a timer for this transaction... */ ap_soft_timeout( "mod_gzip: HEAD request handler", r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: r->content_type=[%s]\n",cn,r->content_type); mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn); #endif ap_send_http_header(r); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn); mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn); #endif ap_kill_timeout(r); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn); mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn); #endif #ifdef MOD_GZIP_USES_APACHE_LOGS /* Return OK but distinguish it from a 'GET' request in logs... */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"OK:HEAD_ONLY")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ return OK; }/* End 'if( r->header_only )' */ /* * See if the source meets the MINUMUM SIZE requirement... * * Default to 300 bytes as a minimum size requirement for it * to even be worth a compression attempt. This works well as a * minimum for both GZIP and ZLIB which are both LZ77 based and, * as such, always have the potential to actually increase the * size of the file. * * The value is a module global that can be adjusted 'on the fly' * as load conditions change or as required for other reasons. */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: conf->minimum_file_size = %ld\n", cn, (long) conf->minimum_file_size ); #endif if ( input_size < (long) conf->minimum_file_size ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Source does not meet the minimum size requirement...\n",cn); mod_gzip_printf( "%s: nodecline = %d\n",cn,nodecline); #endif /* Set the 'mod_gzip_result' note value to something */ /* that indicates this was too small... */ #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:TOO_SMALL")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ /* Is it OK to DECLINE?... */ if ( nodecline ) /* We have been told NOT to DECLINE */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn); #endif /* Skip the compression phase and just set the output */ /* control skid up to send the real input data... */ output_size = input_size; if ( source_is_a_file ) /* Source is a workfile... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Force send - source = FILE[%s]\n", cn,source); #endif strcpy( gzp->output_filename, source ); gzp->output_ismem = 0; /* Output is a disk file */ gz1_ismem_obuf = 0; /* Make sure this is NULL */ gzp->output_ismem_obuf = 0; /* Not used for this method */ gzp->output_ismem_obuflen = 0; /* Not used for this method */ ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc ); if ( !ifh ) /* The file failed to open... */ { /* We really MUST decline... */ /* Logs have already been updated... */ return( rc ); } } else /* Source is just a memory buffer... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Force send - source = MEMORY BUFFER\n",cn); #endif gzp->output_ismem = 1; gz1_ismem_obuf = source; gz1_ismem_obuf_was_allocated = 0; /* No 'free' is required */ } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: No compression attempt was made.\n",cn); mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn); #endif goto mod_gzip_encode_and_transmit_send_start; /* Jump */ } else /* It's OK to DECLINE the processing... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: DECLINE is allowed...\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif return DECLINED; } } else /* The source is larger than the minimum size requirement... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Source meets the minimum size requirement.\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } /* * We must now encode the requested object... * * Statistically speaking, most 'text/*' pages are * less than 60k. XML documents are an exception. * * If the size of the requested object is less than 60k * then go ahead and compress the source directly to a * small memory buffer. If the requested object is greater * than 60k then go ahead and swap the results to an output * disk file and then send the contents of the result file. * * We can't ever allocate all the memory we want inside of * a Server task thread so there must always be this kind * of 'decision' making about when we can compress to * a memory buffer ( Less than 60k ) and when we must * compress to DISK. ( Greater than 60k ). * * There is a trade-off here between running the risk of * too many tasks stealing away all the heap space and * still maintaining performance. Given all the variables * involved such as the true efficiency of the compression * algorithm(s) and the speed of the CPU and the amount of * memory/disk space available there is no 'real' answer to * this dilemma other than relying on statistical data * and empirical observations. The 60k limit on in-memory * compression seems to strike a good balance and performs * incredibly well under the heaviest of loads. * * At all times, the greatest benefit being gained is the * appreciable reduction of data that must actually be * sent by the TCP/IP sub-system and the reduced usage * of those resources to perform the transmission task(s), * * The key, then, is to always strive for a balance where * the time and resource usage it takes to compress a * deliverable object will always be less than the processor * burden that would otherwise be realized by handing the * full, uncompressed object to the TCP/IP sub-system which * always extend the time that the thread and all its * locked resources must be maintained as well as the * overhead for keeping a connection active any longer * than is absolutely necessary. * * As long as the resource usage it takes to accomplish * a significant reduction in the amount of data that * must actually be processed by the remainder of the * HTTP task thread and the TCP/IP sub-system itself * is always less than the processor burden seen by * NOT doing so then we are always 'ahead of the game'. */ /* * See if the object size exceeds the current MAXIMUM size * to use for in-memory compression... * * See notes above about a range of 60k or so being the best * value for heavy load conditions. * * This number is currently a global so it can be changed * 'on the fly' and can 'breathe' as the load changes. * It should probably become a thread specific variable * so each task can have its 'own' max value depending * on current load conditions. */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: conf->maximum_inmem_size = %ld\n", cn, (long) conf->maximum_inmem_size ); #endif /* * Set up the INPUT target... */ /* The size and type of the input source is always known */ /* and was passed by the caller... */ if ( source_is_a_file ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Input source is file[%s]\n",cn,source); #endif strcpy( gzp->input_filename, source ); gzp->input_ismem = 0; /* Input is a disk file */ gzp->input_ismem_ibuf = 0; /* Source buffer */ gzp->input_ismem_ibuflen = 0; /* Length of data */ } else { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Input source is a MEMORY BUFFER\n",cn); #endif *gzp->input_filename = 0; /* Not used */ gzp->input_ismem = 1; /* Input is a memory buffer */ gzp->input_ismem_ibuf = source; /* Source buffer */ gzp->input_ismem_ibuflen = input_size; /* Length of data */ } /* * Set up the OUTPUT target... */ gzp->decompress = 0; /* Perform encoding */ /* Recover the compression format we're supposed to use. */ compression_format = ap_table_get(r->notes, "mod_gzip_compression_format"); if (compression_format && strcmp(compression_format, "deflate") == 0) { actual_content_encoding_name = "deflate"; gzp->compression_format = DEFLATE_FORMAT; } else { gzp->compression_format = GZIP_FORMAT; } if ( input_size <= (long) conf->maximum_inmem_size ) { /* The input source is small enough to compress directly */ /* to an in-memory output buffer... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Input source is small enough for in-memory compression.\n",cn); #endif *gzp->output_filename = 0; /* Not used */ gzp->output_ismem = 1; /* Output is a memory buffer */ /* * Allocate a memory buffer to hold compressed output. * * For now this is borrowed from the heap for only * the lifetime of this function call. If the stack * can handle the current in-memory MAXSIZE then * that will work just as well. * * Add at least 1000 bytes in case the compression * algorithm(s) actually expands the source ( which is * not likely but is always a possibility when using * any LZ77 based compression such as GZIP or ZLIB ) */ gz1_ismem_obuf = (char *) malloc( input_size + 1000 ); if ( !gz1_ismem_obuf ) { /* * There wasn't enough memory left for another * in-memory compression buffer so default to using * an output disk file instead... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ERROR: Cannot allocate GZP memory...\n",cn); mod_gzip_printf( "%s: Defaulting to output file method... \n",cn); #endif gzp->output_ismem = 0; /* Switch to using a disk file */ } else /* We got the memory we need for in-memory compression... */ { /* Set the local flag which tells the exit logic */ /* that 'gz1_ismem_obuf' was actually allocated */ /* and not simply set to 'source' so that the */ /* allocation can be 'freed' on exit... */ gz1_ismem_obuf_was_allocated = 1; /* 'free' is required */ /* Compression codecs require a 'clean' buffer so */ /* we need to spend the cycles for a memset() call. */ memset( gz1_ismem_obuf, 0, ( input_size + 1000 ) ); /* Set OUTPUT buffer control variables... */ gzp->output_ismem_obuf = gz1_ismem_obuf; gzp->output_ismem_obuflen = input_size + 1000; } }/* End 'if ( input_size <= conf->maximum_inmem_size )' */ /* * If we are unable ( or it is unadvisable ) to use * an in-memory output buffer at this time then the * 'gzp->output_ismem' flag will still be ZERO at this point. */ if ( gzp->output_ismem != 1 ) { /* * The input source is NOT small enough to compress to an * in-memory output buffer or it is unadvisable to do * so at this time so just use an output file... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Input source too big for in-memory compression.\n",cn); #endif /* * Create the GZP output target name... */ mod_gzip_create_unique_filename( (mod_gzip_conf *) conf, (char *) gzp->output_filename, MOD_GZIP_MAX_PATH_LEN ); /* * COMPRESSION OBJECT CACHE * * TODO: Obviously one place to add the compression cache * logic is right here. If there is already a pre-compressed * version of the requested entity sitting in the special * compression cache and it is 'fresh' then go ahead and * send it as the actual response. Add a CRC/MD5 checksum * to the stored compression object(s) so we can quickly * determine if the compressed object is 'fresh'. Relying * on Content-length and/or modification time/date won't handle * all possible expiration scenarios for compressed objects. */ gzp->output_ismem = 0; /* Output is a disk file */ gz1_ismem_obuf = 0; /* Make sure this is NULL */ /* Set OUTPUT buffer control variables... */ gzp->output_ismem_obuf = 0; /* Not used for this method */ gzp->output_ismem_obuflen = 0; /* Not used for this method */ }/* End 'else' */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: gzp->decompress = %d\n" ,cn,gzp->decompress); mod_gzip_printf( "%s: gzp->compression_format = %d\n",cn,gzp->compression_format); mod_gzip_printf( "%s: gzp->input_ismem = %d\n", cn,gzp->input_ismem); mod_gzip_printf( "%s: gzp->output_ismem = %d\n", cn,gzp->output_ismem); mod_gzip_printf( "%s: gzp->input_filename = [%s]\n",cn,gzp->input_filename); mod_gzip_printf( "%s: gzp->output_filename = [%s]\n",cn,gzp->output_filename); mod_gzip_printf( "%s: Call gzp_main()...\n",cn); #endif rc = gzp_main( gzp ); /* Perform the compression... */ output_size = (long) gzp->bytes_out; #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back gzp_main()...\n",cn); mod_gzip_printf( "%s: input_size = %ld\n",cn,(long)input_size); mod_gzip_printf( "%s: output_size = %ld\n",cn,(long)output_size); mod_gzip_printf( "%s: gzp->bytes_out = %ld\n",cn,(long)gzp->bytes_out); mod_gzip_printf( "%s: Bytes saved = %ld\n",cn, (long)input_size-gzp->bytes_out ); #endif /* Compute the compresion ratio for access.log and */ /* internal statistics update... */ compression_ratio = 0; /* Reset */ /* Prevent 'Divide by zero' error... */ if ( ( input_size > 0 ) && ( output_size > 0 ) ) { compression_ratio = 100 - (int) ( output_size * 100L / input_size ); } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Compression ratio = %ld percent\n",cn, (long) compression_ratio ); #endif /* * Update the logs with output size information * as soon as it is known in case there was an * error or we must DECLINE. At least the logs * will then show the sizes and the results. */ #ifdef MOD_GZIP_USES_APACHE_LOGS sprintf( log_info,"%d", (int) output_size ); ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info)); sprintf( log_info,"%d", (int) compression_ratio ); ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,log_info)); #endif /* MOD_GZIP_USES_APACHE_LOGS */ /* * Evaluate the compression result(s)... * * If the compression pass failed then the output length * will be ZERO bytes... */ if ( output_size < 1 ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Compressed version has no length.\n",cn); mod_gzip_printf( "%s: Sending the original version uncompressed...\n",cn); #endif finalize_stats = 0; /* Don't update stats again */ if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: gzp_main(ERR): r->uri=[%s] input_size=%ld output_size=%ld gzp->output_filename=[%s]", r->uri,(long)input_size,(long)output_size,gzp->output_filename); } /* * NOTE: It's perfectly possible that we have made it all * the way to here and the straight execution of the * compressor is the first time there has been a check for * the actual existence of the requested object. This will * be especially true for STATIC requests. * * The compressor itself will fail if/when it can't find * the input target so 'DECLINED:NO_O_LEN' could simply * means the file was not found. In these cases the Apache * logs should also contain the correct '404 Not Found' code. */ #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:NO_O_LEN")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ /* Is it OK to DECLINE?... */ if ( nodecline ) /* We have been told NOT to DECLINE... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn); #endif /* Just set the output control skid */ /* to send the real input data... */ output_size = input_size; if ( source_is_a_file ) /* Source is a workfile... */ { strcpy( gzp->output_filename, source ); gzp->output_ismem = 0; /* Output is a disk file */ gz1_ismem_obuf = 0; /* Make sure this is NULL */ gzp->output_ismem_obuf = 0; /* Not used for this method */ gzp->output_ismem_obuflen = 0; /* Not used for this method */ ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc ); if ( !ifh ) /* We really must DECLINE... */ { return( rc ); } } else /* Source is just a memory buffer... */ { gzp->output_ismem = 1; gz1_ismem_obuf = source; } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn); #endif goto mod_gzip_encode_and_transmit_send_start; /* Jump */ } else /* It's OK to DECLINE the processing... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: DECLINE is allowed...\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif /* Free the local memory buffer allocation ( if necessary )... */ if ( gz1_ismem_obuf ) { /* The pointer may have been 'borrowed' and was */ /* not actually 'allocated' so check the flag... */ if ( gz1_ismem_obuf_was_allocated ) { free( gz1_ismem_obuf ); gz1_ismem_obuf = 0; gz1_ismem_obuf_was_allocated = 0; }/* End 'if( gz1_ismem_obuf_was_allocated )' */ }/* End 'if( gz1_ismem_obuf )' */ /* Return... */ return DECLINED; } }/* End 'if( output_size < 1 )' */ /* * If we reach this point then the compressed version has * a valid length. Time to see if it it's worth sending. * * If the original source is SMALLER than the COMPRESSED * version ( not likely but possible with LZ77 ) then * just punt and send the original source... */ if ( output_size > input_size ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Compressed version is larger than original.\n",cn); mod_gzip_printf( "%s: Sending the original version uncompressed...\n",cn); #endif finalize_stats = 0; /* Don't update stats again */ #ifdef MOD_GZIP_USES_APACHE_LOGS /* Each 'DECLINE' condition provides a short ':WHYTAG' for logs */ ap_table_setn( r->notes,"mod_gzip_result",ap_pstrdup(r->pool,"DECLINED:ORIGINAL_SMALLER")); #endif /* MOD_GZIP_USES_APACHE_LOGS */ /* Is it OK to DECLINE?... */ if ( nodecline ) /* We have been told NOT to DECLINE... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: DECLINE is NOT allowed...\n",cn); #endif /* Just set the output control skid */ /* to send the real input data... */ output_size = input_size; if ( source_is_a_file ) /* Source is a workfile... */ { strcpy( gzp->output_filename, source ); gzp->output_ismem = 0; /* Output is a disk file */ gz1_ismem_obuf = 0; /* Make sure this is NULL */ gzp->output_ismem_obuf = 0; /* Not used for this method */ gzp->output_ismem_obuflen = 0; /* Not used for this method */ ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc ); if ( !ifh ) /* We really must DECLINE... */ { return( rc ); } } else /* Source is just a memory buffer... */ { gzp->output_ismem = 1; gz1_ismem_obuf = source; gz1_ismem_obuf_was_allocated = 0; /* No 'free' is required */ } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Advancing directly to transmit phase...\n",cn); #endif goto mod_gzip_encode_and_transmit_send_start; /* Jump */ } else /* It's OK to DECLINE the processing... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: DECLINE is allowed...\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif /* Free the local memory buffer allocation ( if necessary )... */ if ( gz1_ismem_obuf ) { /* The pointer may have been 'borrowed' and was */ /* not actually 'allocated' so check the flag... */ if ( gz1_ismem_obuf_was_allocated ) { free( gz1_ismem_obuf ); gz1_ismem_obuf = 0; gz1_ismem_obuf_was_allocated = 0; }/* End 'if( gz1_ismem_obuf_was_allocated )' */ }/* End 'if( gz1_ismem_obuf )' */ /* Return... */ return DECLINED; } } else /* Compressed version is smaller than original... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Compressed version is smaller than original.\n",cn); mod_gzip_printf( "%s: Sending the compressed version...\n",cn); #endif } /* * If an output workfile was used then make SURE it is going * to reopen before beginning the transmit phase. * * If we begin the transmit phase before discovering a problem * re-opening the workfile then we have lost the chance to * DECLINE the processing and allow the default logic to * deliver the requested object. * * This only matters for 'static' files or times when the * 'nodecline' flag is FALSE and it is actually OK to DECLINE. */ if ( !gzp->output_ismem ) /* Workfile was used... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Opening compressed output file [%s]...\n", cn, gzp->output_filename ); #endif ifh = mod_gzip_open_output_file( r, gzp->output_filename, &rc ); if ( !ifh ) /* The file failed to open... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: ERROR: Cannot re-open file [%s]\n", cn,gzp->output_filename); #endif /* We really must DECLINE... */ /* Logs have already been updated... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif return DECLINED; }/* End 'if ( !ifh )' */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Workile re-opened OK...\n",cn); #endif }/* End 'if ( !gzp->output_ismem )' */ /* * IMPORTANT * * If we have made it to here then all is well and only * now can we set the encoding for this response... * * We must do this 'above' any jump points that might * be sending the 'untouched' data or the browser will * get confused regarding the actual content. */ r->content_encoding = actual_content_encoding_name; #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: r->content_encoding is now [%s]\n", cn, r->content_encoding ); #endif /* * Begin the transmission phase... * * Even if the 'nodecline' flag is TRUE if we encounter * any fatal errors at this point we must 'DECLINE'. */ mod_gzip_encode_and_transmit_send_start: ; /* <<-- Jump point */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Starting transmit phase...\n",cn); #endif /* * We are ready to send content so update the "Content-length:" * response field and send the HTTP header. We don't need to * worry about setting the "Content-type:" field since we are * simply accepting the value that was passed to us as indicated * by the inbound r->content_type string. The "Content-type:" * field never changes even when multiple encodings have been * applied to the content itself. * * This version does not make any attempt to use 'Chunked' * transfer encoding since there are so many user agents that * do not support it and when Content-length is known prior * to header transmission ( as is always the case with this * code ) then there is simply no reason to even think about * using the slower and more problematic 'Chunked' encoding * transfer method. */ /* * Set relevant outbound response header fields... * * Be sure to call ap_update_mtime() before calling * ap_set_last_modified() to be sure the 'current' * time is actually updated in outbound response header. */ ap_update_mtime( r, r->finfo.st_mtime ); ap_set_last_modified(r); ap_set_etag(r); ap_table_setn(r->headers_out, "Accept-Ranges", "bytes"); /* * Start a timer for this transaction... */ ap_soft_timeout( "mod_gzip: Encoded data transmit", r ); /* * Return the length of the compressed output in * the response header. * * See notes above about there never being a requirement * to use 'Chunked' transfer encoding since the content * length is always 'known' prior to transmission. */ sprintf( content_length, "%ld", output_size ); ap_table_set (r->headers_out, "Content-Length", content_length ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: output_size = %ld\n",cn,(long)output_size); mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); mod_gzip_printf( "%s: Call ap_send_http_header()...\n",cn); #endif ap_send_http_header(r); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_send_http_header()...\n",cn); #endif /* * Send the response... * * If the requested object was small enough to fit into * our special in-memory output space then send the result * directly from memory. If the requested object exceeded * the minimum size for in-memory compression then an output * file was used so re-open and send the results file... */ if ( gzp->output_ismem ) { /* Send the in-memory output buffer... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Sending the in-memory output buffer...\n",cn); mod_gzip_printf( "%s: output_size = %ld\n",cn,(long)output_size); /* Turn this 'on' for VERY verbose diagnostics... #define MOD_GZIP_DUMP_JUST_BEFORE_SENDING */ #ifdef MOD_GZIP_DUMP_JUST_BEFORE_SENDING mod_gzip_hexdump( gz1_ismem_obuf, output_size ); #endif #endif /* MOD_GZIP_DEBUG1 */ /* This module can use either ap_send_mmap() or ap_rwrite()... */ #ifdef MOD_GZIP_USES_AP_SEND_MMAP /* Use ap_send_mmap() call to send the data... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_send_mmap( gz1_ismem_obuf, bytes=%ld )...\n", cn, (long)output_size ); #endif ap_send_mmap( gz1_ismem_obuf, r, 0, output_size ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_send_mmap( gz1_ismem_obuf, bytes=%ld )...\n", cn, (long)output_size ); #endif #else /* !MOD_GZIP_USES_AP_SEND_MMAP */ /* Use ap_rwrite() call to send the data... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_rwrite( gz1_ismem_obuf, bytes=%ld )...\n", cn, (long)output_size ); #endif ap_rwrite( gz1_ismem_obuf, output_size, r ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_rwrite( gz1_ismem_obuf, bytes=%ld )...\n", cn, (long)output_size ); #endif #endif /* MOD_GZIP_USES_AP_SEND_MMAP */ /* Stop the timer... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn); #endif ap_kill_timeout(r); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn); #endif /* Free the local memory buffer allocation ( if necessary )... */ if ( gz1_ismem_obuf ) { /* The pointer may have been 'borrowed' and was */ /* not actually 'allocated' so check the flag... */ if ( gz1_ismem_obuf_was_allocated ) { free( gz1_ismem_obuf ); gz1_ismem_obuf = 0; gz1_ismem_obuf_was_allocated = 0; }/* End 'if( gz1_ismem_obuf_was_allocated )' */ }/* End 'if( gz1_ismem_obuf )' */ } else /* Output workfile was used so send the contents... */ { /* * NOTE: The workfile was already 're-opened' up above * before the transmit phase began so that we still had * the chance to return DECLINED if, for some reason, the * workfile could not be re-opened. */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: sizeof( tmp ) = %d\n",cn,sizeof(tmp)); mod_gzip_printf( "%s: Transmit buffer size = %d\n",cn,sizeof(tmp)); mod_gzip_printf( "%s: Sending compressed output file...\n",cn); #endif for (;;) { bytesread = fread( tmp, 1, sizeof( tmp ), ifh ); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back fread(): bytesread=%d\n",cn,bytesread); #endif if ( bytesread < 1 ) break; /* File is exhausted... We are done...*/ /* This module can use either ap_send_mmap() or ap_rwrite()... */ #ifdef MOD_GZIP_USES_AP_SEND_MMAP /* Use ap_send_mmap() call to send the data... */ ap_send_mmap( tmp, r, 0, bytesread ); #else /* !MOD_GZIP_USES_AP_SEND_MMAP */ /* Use ap_rwrite() call to send the data... */ ap_rwrite( tmp, bytesread, r ); #endif /* MOD_GZIP_USES_AP_SEND_MMAP */ } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Done Sending compressed output file...\n",cn); mod_gzip_printf( "%s: Closing workfile [%s]...\n", cn, gzp->output_filename ); #endif fclose( ifh ); /* Close the input file */ /* Stop the timer before attempting to delete the workfile... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Call ap_kill_timeout()...\n",cn); #endif ap_kill_timeout(r); #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Back ap_kill_timeout()...\n",cn); #endif /* Delete the workfile if 'keep' flag is OFF... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: conf->keep_workfiles = %d\n", cn, conf->keep_workfiles ); #endif if ( !conf->keep_workfiles ) /* Default is OFF */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Deleting workfile [%s]...\n", cn, gzp->output_filename ); #endif #ifdef _WIN32 DeleteFile( gzp->output_filename ); #else /* !_WIN32 */ unlink( gzp->output_filename ); #endif /* _WIN32 */ } else /* Keep all work files... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Keeping workfile [%s]...\n", cn, gzp->output_filename ); #endif } }/* End 'else' that sends compressed workfile */ /* * The compressed object has been sent... */ #ifdef MOD_GZIP_USES_APACHE_LOGS if ( finalize_stats ) { sprintf( log_info,"%d", (int) output_size ); ap_table_setn( r->notes,"mod_gzip_output_size",ap_pstrdup(r->pool,log_info)); sprintf( log_info,"%d", (int) compression_ratio ); ap_table_setn( r->notes,"mod_gzip_compression_ratio",ap_pstrdup(r->pool,log_info)); } #endif /* MOD_GZIP_USES_APACHE_LOGS */ if ( r->server->loglevel == APLOG_DEBUG ) { /* * If LogLevel is 'debug' then show the compression results * in the log(s)... */ ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: r->uri=[%s] OK: Bytes In:%ld Out:%ld Compression: %ld pct.", r->uri, (long) input_size, (long) output_size, (long) compression_ratio ); }/* End 'if( r->server->loglevel == APLOG_DEBUG )' */ /* * Return OK to the Server to indicate SUCCESS... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( OK ) >\n",cn); #endif return OK; }/* End of mod_gzip_encode_and_transmit() */ int mod_gzip_ismatch( char *s1, char *s2, int len1, int haswilds ) { /* Behaves just like strncmp() but IGNORES differences */ /* between FORWARD or BACKWARD slashes in a STRING, allows */ /* wildcard matches, and can ignore length value. */ /* It uses pointers and is faster than using lib calls. */ /* Unlike strncmp() this routine returns TRUE (1) if the */ /* strings match and FALSE (0) if they do not... */ int i; int l1; int l2; int distance; char ch1; char ch2; /* WARNING! We MUST have a check for 'NULL' on the pointer(s) */ /* themselves or we might GP */ if ( ( s1 == 0 ) || ( s2 == 0 ) ) { /* SAFETY! If pointer itself if NULL */ /* don't enter LOOP... */ return( 0 ); /* Return FALSE for NOMATCH... */ } distance = len1; /* Default to value passed... */ /* If no length was given then the 2 strings must already */ /* have the same length or this is a 'no match'... */ /* Exception to this is if wildcards are present. */ if ( len1 == 0 ) { l1 = strlen( s1 ); l2 = strlen( s2 ); /* If either string had a valid pointer but is EMPTY */ /* then this is an automatic 'no match'... */ if ((l1==0)||(l2==0)) { return( 0 ); /* Return FALSE for NOMATCH... */ } if ( l1 != l2 ) { if ( haswilds == 0 ) { return( 0 ); /* Return FALSE for NOMATCH... */ } } /* If the lengths ARE equal then this is a possible */ /* match. Use the smaller of the 2 values for scan...*/ if ( l1 < l2 ) distance = l1; else distance = l2; } /* Final check... if distance is still 0 then this */ /* is an automatic 'no match'... */ if ( distance == 0 ) { return( 0 ); /* Return FALSE for NOMATCH... */ } /* Do the deed... */ for ( i=0; icontent_type ) clen = strlen( r->content_type ); if ( r->handler ) hlen = strlen( r->handler ); if ( r->filename ) { flen = strlen( r->filename ); p1 = r->filename; while(*p1!=0){if (*p1=='.') file_extension=p1; p1++;} if ( file_extension ) file_extension_len = strlen( file_extension ); } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Entry...\n",cn); mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); mod_gzip_printf( "%s: clen = %d\n", cn,clen); mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler); mod_gzip_printf( "%s: hlen = %d\n", cn,hlen); mod_gzip_printf( "%s: r->filename = [%s]\n",cn,r->filename); mod_gzip_printf( "%s: flen = %d\n", cn,flen); mod_gzip_printf( "%s: file_extension = [%s]\n",cn,file_extension); mod_gzip_printf( "%s: file_extension_len = %d\n", cn,file_extension_len); #endif /* MOD_GZIP_DEBUG1 */ /* * Sanity checks... */ if ( ( hlen == 0 ) && ( clen == 0 ) ) { /* * If the header analysis and/or negotiation phase has * determined this to be a CGI script then the r->content_type * field will be (null) but r->handler will contain "cgi-script". * or "php-script" or the like. * * If the analysis has determined this is a static file * then r->handler will be (null) but the r->content_type * field will be "text/html" or "text/plain" or whatever. * * Both the r->content_type field and the r->handler * field are empty. Ignore this one... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Both hlen and clen are ZERO...\n",cn); mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: There is no valid r->handler or r->content_length "); } return( MOD_GZIP_IMAP_DECLINED1 ); } /* * Perform 2 passes at the Include/Exclude list... * * The first pass is the higher-priority EXCLUSION check. * The second pass is the lower-priority INCLUSION check. */ for ( pass=0; pass<2; pass++ ) { pass_result = 0; /* Reset result */ if ( pass == 0 ) /* EXCLUSION CHECK */ { filter_value = 0; #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: EXCLUSION CHECK...\n",cn); #endif } else if ( pass == 1 ) /* INCLUSION CHECK */ { filter_value = 1; #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: INCLUSION CHECK...\n",cn); #endif } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: pass = %d\n", cn, pass ); mod_gzip_printf( "%s: filter_value = %d\n", cn, filter_value ); mod_gzip_printf( "%s: mgc->imap_total_entries = %d\n", cn, (int) mgc->imap_total_entries ); #endif for ( x=0; ximap_total_entries; x++ ) { if ( r->server->loglevel == APLOG_DEBUG ) { /* Show the lookups in the Apache ERROR log if DEBUG is on */ ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: mgc->imap[%3.3d] = i%2.2d t%4.4d a%4.4d n[%s]", x, mgc->imap[x].include, mgc->imap[x].type, mgc->imap[x].action, mgc->imap[x].name ); } #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: --------------------------------------------\n",cn); mod_gzip_printf( "%s: r->handler = [%s]\n",cn,r->handler); mod_gzip_printf( "%s: r->content_type = [%s]\n",cn,r->content_type); mod_gzip_printf( "%s: r->filename = [%s]\n",cn,r->filename); mod_gzip_printf( "%s: file_extension = [%s]\n",cn,file_extension); mod_gzip_printf( "%s: mgc->imap[%3.3d].include = %d\n",cn,x,mgc->imap[x].include); mod_gzip_printf( "%s: mgc->imap[%3.3d].type = %d\n",cn,x,mgc->imap[x].type); if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISMIME ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISMIME\n",cn,x); } else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISEXT ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISEXT\n",cn,x); } else if ( mgc->imap[x].type == MOD_GZIP_IMAP_ISHANDLER ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_ISHANDLER\n",cn,x); } else /* Unrecognized item type... */ { mod_gzip_printf( "%s: mgc->imap[%3.3d].type = MOD_GZIP_IMAP_IS??? Unknown type\n",cn,x); } mod_gzip_printf( "%s: mgc->imap[%3.3d].action = %d\n", cn,x,mgc->imap[x].action); if ( mgc->imap[x].action == MOD_GZIP_IMAP_DYNAMIC1 ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_DYNAMIC1\n",cn,x); } else if ( mgc->imap[x].action == MOD_GZIP_IMAP_STATIC1 ) { mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_STATIC1\n",cn,x); } else /* Unrecognized action type... */ { mod_gzip_printf( "%s: mgc->imap[%3.3d].action = MOD_GZIP_IMAP_??? Unknown action\n",cn,x); } mod_gzip_printf( "%s: mgc->imap[%3.3d].name = [%s]\n",cn,x,mgc->imap[x].name); #endif /* MOD_GZIP_DEBUG1 */ /* 'filter_value' mirrors 'pass' value for now but this might */ /* not always be true. First pass is EXCLUDE and second is INCLUDE */ if ( mgc->imap[x].include == filter_value ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: This record matches filter_value %d\n", cn, filter_value ); mod_gzip_printf( "%s: The record will be checked...\n",cn); #endif /* * Set work values for this record... */ this_type = mgc->imap[x].type; this_action = mgc->imap[x].action; this_name = mgc->imap[x].name; /* * If the header analysis and/or negotiation phase has * determined this to be a CGI script then the r->content_type * field will be (null) but r->handler will contain "cgi-script". * * If the analysis has determined this is a static file * then r->handler will be (null) but the r->content_type * field will be "text/html" or "text/plain" or whatever. */ if ( hlen > 0 ) /* r->handler field has a value... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: hlen has value...\n",cn); #endif if ( this_type == MOD_GZIP_IMAP_ISHANDLER ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: this_type = ISHANDLER\n",cn); mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,0)...\n", cn, this_name, r->handler ); #endif /* mod_gzip_ismatch()... */ /* The 2 strings must match exactly so */ /* pass '0' for parm 3... */ /* Wildcard matches are not allowed for */ /* handler strings like 'cgi-script' so */ /* Fourth parm should be 0.. */ if ( mod_gzip_ismatch( this_name, (char *)r->handler,0,0) ) { pass_result = 1; /* We found a match */ action_flag = this_action; /* What to do */ break; /* Stop now */ } }/* End 'if ( this_type == MOD_GZIP_IMAP_ISHANDLER )' */ }/* End 'if( hlen > 0 )' */ if ( clen > 0 ) /* r->content_type field has a value... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: clen has value...\n",cn); #endif if ( this_type == MOD_GZIP_IMAP_ISMIME ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: this_type = ISMIME\n",cn); mod_gzip_printf( "%s: Wildcards matches are OK for MIME types.\n",cn); mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,1)...\n", cn, this_name, r->content_type ); #endif /* mod_gzip_ismatch()... */ /* Wildcard matches are ALLOWED for */ /* MIME type strings like 'cgi-script' */ /* so fourth parm should be 1... */ if ( mod_gzip_ismatch( this_name, (char *)r->content_type, 0, 1 ) ) { pass_result = 1; /* We found a match */ action_flag = this_action; /* What to do */ break; /* Stop now */ } }/* End 'if ( this_type == MOD_GZIP_IMAP_ISMIME )' */ }/* End 'if( clen > 0 )' */ if ( flen > 0 ) /* r->filename field has a value... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: flen has value...\n",cn); #endif if ( this_type == MOD_GZIP_IMAP_ISEXT ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: this_type = ISEXT\n",cn); #endif if ( file_extension_len > 0 ) /* There is a file extension */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: file_extension_len has value...\n",cn); mod_gzip_printf( "%s: Call mod_gzip_ismatch(%s,%s,0,0)...\n", cn, this_name, file_extension ); #endif /* mod_gzip_ismatch()... */ /* The 2 strings must match exactly so */ /* pass '0' for parm 3... */ /* Wildcard matches are not allowed for */ /* file extensions like '.html' so */ /* Fourth parm should be 0.. */ if ( mod_gzip_ismatch( this_name, file_extension, 0, 0 ) ) { pass_result = 1; /* We found a match */ action_flag = this_action; /* What to do */ break; /* Stop now */ } }/* End 'if( file_extension_len > 0 )' */ }/* End 'if( this_type == MOD_GZIP)IMAP_ISEXT )' */ }/* End 'if( flen > 0 )' */ }/* End 'if ( mgc->imap[x].include == filter )' */ else /* The record did not match the current 'filter' value... */ { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: This record does NOT match filter_value %d\n", cn, filter_value ); mod_gzip_printf( "%s: The record has been SKIPPED...\n",cn); #endif } }/* End 'x' loop that looks at 'filtered' records... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: --------------------------------------------\n",cn); mod_gzip_printf( "%s: pass_result = %d\n",cn,pass_result); #endif if ( pass_result ) /* We are done... */ { if ( pass == 0 ) item_is_excluded = 1; else item_is_included = 1; break; /* Break out of 'pass' loop now... */ } }/* End 'pass' loop */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: item_is_excluded = %d\n",cn,item_is_excluded); mod_gzip_printf( "%s: item_is_included = %d\n",cn,item_is_included); mod_gzip_printf( "%s: action_flag = %d\n",cn,action_flag); #endif if ( item_is_excluded ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: The item is excluded...\n",cn); mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: This item is EXCLUDED as per httpd.conf"); } return( MOD_GZIP_IMAP_DECLINED1 ); } else if ( item_is_included ) { #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: The item is included...\n",cn); mod_gzip_printf( "%s: Exit > return( action_flag = %d ) >\n",cn,action_flag); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: This item is INCLUDED as per httpd.conf"); } return( action_flag ); /* STATIC1 or DYNAMIC1 */ } /* * Default action is to DECLINE processing... */ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: Exit > return( MOD_GZIP_IMAP_DECLINED1 ) >\n",cn); #endif if ( r->server->loglevel == APLOG_DEBUG ) { ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: This item was NOT FOUND in any mod_gzip httpd item record."); ap_log_error( "",0,APLOG_NOERRNO|APLOG_DEBUG, r->server, "mod_gzip: This item will NOT be processed."); } return( MOD_GZIP_IMAP_DECLINED1 ); }/* End of mod_gzip_get_action_flag() */ /*--------------------------------------------------------------------------*/ /* ALL SOURCE CODE BELOW THIS POINT IS COMPRESSION SPECIFIC... */ /*--------------------------------------------------------------------------*/ #define USE_GATHER extern MODULE_VAR_EXPORT int ap_suexec_enabled; extern API_EXPORT(void) ap_internal_redirect_handler(const char *new_uri, request_rec *); long mod_gzip_ap_send_fb( BUFF *fb, request_rec *r, int *final_return_code ); long mod_gzip_ap_send_fb_length( BUFF *fb, request_rec *r, long length, int *final_return_code ); #define DEFAULT_LOGBYTES 10385760 #define DEFAULT_BUFBYTES 1024 static int mod_gzip_cgi_child(void *child_stuff, child_info *pinfo); typedef struct { char *logname; long logbytes; int bufbytes; } cgi_server_conf; struct mod_gzip_cgi_child_stuff { #ifdef TPF TPF_FORK_CHILD t; #endif request_rec *r; int nph; int debug; char *argv0; }; static int is_scriptaliased( request_rec *r ) { const char *t = ap_table_get(r->notes, "alias-forced-type"); return t && (!strcasecmp(t, "cgi-script")); } static int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret, int show_errno, char *error) { FILE *f; struct stat finfo; ap_log_rerror(APLOG_MARK, show_errno|APLOG_ERR, r, "%s: %s", error, r->filename); if (!conf->logname || ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0) && (finfo.st_size > conf->logbytes)) || ((f = ap_pfopen(r->pool, ap_server_root_relative(r->pool, conf->logname), "a")) == NULL)) { return ret; } fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri, r->args ? "?" : "", r->args ? r->args : "", r->protocol); fprintf(f, "%%%% %d %s\n", ret, r->filename); fprintf(f, "%%error\n%s\n", error); ap_pfclose(r->pool, f); return ret; } static int log_script(request_rec *r, cgi_server_conf * conf, int ret, char *dbuf, const char *sbuf, BUFF *script_in, BUFF *script_err) { array_header *hdrs_arr = ap_table_elts(r->headers_in); table_entry *hdrs = (table_entry *) hdrs_arr->elts; char argsbuffer[HUGE_STRING_LEN]; FILE *f; int i; struct stat finfo; if (!conf->logname || ((stat(ap_server_root_relative(r->pool, conf->logname), &finfo) == 0) && (finfo.st_size > conf->logbytes)) || ((f = ap_pfopen(r->pool, ap_server_root_relative(r->pool, conf->logname), "a")) == NULL)) { while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) continue; #if defined(_WIN32) || defined(NETWARE) while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, r, "%s", argsbuffer); } #else while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) continue; #endif return ret; } fprintf(f, "%%%% [%s] %s %s%s%s %s\n", ap_get_time(), r->method, r->uri, r->args ? "?" : "", r->args ? r->args : "", r->protocol); fprintf(f, "%%%% %d %s\n", ret, r->filename); fputs("%request\n", f); for (i = 0; i < hdrs_arr->nelts; ++i) { if (!hdrs[i].key) continue; fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); } if ((r->method_number == M_POST || r->method_number == M_PUT) && *dbuf) { fprintf(f, "\n%s\n", dbuf); } fputs("%response\n", f); hdrs_arr = ap_table_elts(r->err_headers_out); hdrs = (table_entry *) hdrs_arr->elts; for (i = 0; i < hdrs_arr->nelts; ++i) { if (!hdrs[i].key) continue; fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); } if (sbuf && *sbuf) fprintf(f, "%s\n", sbuf); if (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) { fputs("%stdout\n", f); fputs(argsbuffer, f); while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0) fputs(argsbuffer, f); fputs("\n", f); } if (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { fputs("%stderr\n", f); fputs(argsbuffer, f); while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) fputs(argsbuffer, f); fputs("\n", f); } ap_bclose( script_in ); ap_bclose( script_err ); ap_pfclose(r->pool, f); return ret; } int mod_gzip_cgi_handler( request_rec *r ) { int bytesread; int retval, nph, dbpos = 0; char *argv0, *dbuf = NULL; BUFF *script_out, *script_in, *script_err; char argsbuffer[HUGE_STRING_LEN]; int is_included = !strcmp(r->protocol, "INCLUDED"); void *sconf = r->server->module_config; int final_result = DECLINED; #define MOD_GZIP_ENGAGED #ifdef MOD_GZIP_ENGAGED cgi_server_conf conf_local; cgi_server_conf *conf = &conf_local; char cgi_logname[]=""; #else cgi_server_conf *conf = (cgi_server_conf *) ap_get_module_config(sconf, &cgi_module); #endif const char *location; struct mod_gzip_cgi_child_stuff cld; #ifdef MOD_GZIP_ENGAGED conf->logname = cgi_logname; conf->logbytes = (long) 60000L; conf->bufbytes = (int) 20000; #endif if ( r->method_number == M_OPTIONS ) { r->allowed |= (1 << M_GET); r->allowed |= (1 << M_POST); return DECLINED; } if ((argv0 = strrchr(r->filename, '/')) != NULL) { argv0++; } else { argv0 = r->filename; } nph = !(strncmp(argv0, "nph-", 4)); if ( !(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r) ) { return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, "Options ExecCGI is off in this directory"); } if ( nph && is_included ) { return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, "attempt to include NPH CGI script"); } #if defined(OS2) || defined(_WIN32) if ( r->finfo.st_mode == 0 ) { struct stat statbuf; char *newfile; newfile = ap_pstrcat(r->pool, r->filename, ".EXE", NULL); if ((stat(newfile, &statbuf) != 0) || (!S_ISREG(statbuf.st_mode))) { return log_scripterror(r, conf, NOT_FOUND, 0, "script not found or unable to stat"); } else { r->filename = newfile; } } #else if ( r->finfo.st_mode == 0 ) { return log_scripterror(r, conf, NOT_FOUND, APLOG_NOERRNO, "script not found or unable to stat"); } #endif if ( S_ISDIR( r->finfo.st_mode ) ) { return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, "attempt to invoke directory as script"); } if ( !ap_suexec_enabled ) { if ( !ap_can_exec( &r->finfo ) ) { return log_scripterror(r, conf, FORBIDDEN, APLOG_NOERRNO, "file permissions deny server execution"); } } if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) { return retval; } ap_add_common_vars(r); cld.argv0 = argv0; cld.r = r; cld.nph = nph; cld.debug = conf->logname ? 1 : 0; #ifdef TPF cld.t.filename = r->filename; cld.t.subprocess_env = r->subprocess_env; cld.t.prog_type = FORK_FILE; #endif #ifdef CHARSET_EBCDIC ap_bsetflag( r->connection->client, B_EBCDIC2ASCII, 1 ); #endif if ( !ap_bspawn_child( r->main ? r->main->pool : r->pool, mod_gzip_cgi_child, (void *) &cld, kill_after_timeout, &script_out, &script_in, &script_err ) ) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "couldn't spawn child process: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } else { } if ( ap_should_client_block(r) ) { int dbsize, len_read; if ( conf->logname ) { dbuf = ap_pcalloc( r->pool, conf->bufbytes + 1 ); dbpos = 0; } ap_hard_timeout("copy script args", r); for (;;) { len_read = ap_get_client_block( r, argsbuffer, HUGE_STRING_LEN ); if ( len_read < 1 ) { break; } if (conf->logname) { if ((dbpos + len_read) > conf->bufbytes) { dbsize = conf->bufbytes - dbpos; } else { dbsize = len_read; } memcpy(dbuf + dbpos, argsbuffer, dbsize); dbpos += dbsize; } ap_reset_timeout(r); if ( ap_bwrite(script_out, argsbuffer, len_read) < len_read ) { while ( len_read= ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0) { } break; } else { } } ap_bflush( script_out ); ap_kill_timeout(r); } else { } ap_bclose( script_out ); if ( script_in && !nph ) { char sbuf[MAX_STRING_LEN]; int ret; if ((ret = ap_scan_script_header_err_buff(r, script_in, sbuf))) { return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err); } #ifdef CHARSET_EBCDIC ap_checkconv(r); #endif location = ap_table_get( r->headers_out, "Location" ); if ( location && location[0] == '/' && r->status == 200 ) { ap_hard_timeout("read from script", r); while ( ap_bgets(argsbuffer, HUGE_STRING_LEN, script_in) > 0 ) { continue; } while (ap_bgets(argsbuffer, HUGE_STRING_LEN, script_err) > 0) { continue; } ap_kill_timeout(r); r->method = ap_pstrdup(r->pool, "GET"); r->method_number = M_GET; ap_table_unset( r->headers_in, "Content-Length" ); ap_internal_redirect_handler( location, r ); return OK; } else if ( location && r->status == 200 ) { return REDIRECT; } #ifdef USE_GATHER if ( r->header_only ) { ap_send_http_header(r); } else { } #else /* !USE_GATHER */ ap_send_http_header(r); #endif /* USE_GATHER */ if (!r->header_only) { mod_gzip_ap_send_fb( script_in, r, &final_result ); } ap_bclose( script_in ); ap_soft_timeout("soaking script stderr", r); for (;;) { bytesread = ap_bgets( argsbuffer, HUGE_STRING_LEN, script_err ); if ( bytesread < 1 ) { break; } } ap_kill_timeout(r); ap_bclose( script_err ); } else { } if ( script_in && nph ) { #ifdef RUSSIAN_APACHE if (ra_charset_active(r)) { r->ra_codep=NULL; } #endif mod_gzip_ap_send_fb( script_in, r, &final_result ); } else { } #ifdef ORIGINAL return OK; #endif return final_result; } static int mod_gzip_cgi_child(void *child_stuff, child_info *pinfo) { struct mod_gzip_cgi_child_stuff *cld = (struct mod_gzip_cgi_child_stuff *) child_stuff; request_rec *r = cld->r; char *argv0 = cld->argv0; int child_pid; /* WARNING! If the following DEBUG_CGI switch is ON you may need to */ /* run Apache with the -X switch or the dynamic compression */ /* of some CGI output ( most notable Zope ) will start to fail. */ /* This DEBUG_CGI switch should NEVER be on for production runs. */ /* #define DEBUG_CGI */ #ifdef DEBUG_CGI #ifdef OS2 FILE *dbg = fopen("con", "w"); #else #ifdef _WIN32 FILE *dbg = fopen("c:\\script.dbg", "a" ); #else FILE *dbg = fopen("/dev/tty", "w"); #endif #endif int i; #endif char **env; RAISE_SIGSTOP(CGI_CHILD); #ifdef DEBUG_CGI fprintf(dbg, "Attempting to exec %s as %sCGI child (argv0 = %s)\n", r->filename, cld->nph ? "NPH " : "", argv0); #endif ap_add_cgi_vars(r); env = ap_create_environment(r->pool, r->subprocess_env); #ifdef DEBUG_CGI fprintf(dbg, "Environment: \n"); for (i = 0; env[i]; ++i) fprintf(dbg, "'%s'\n", env[i]); #endif #ifndef _WIN32 #ifdef DEBUG_CGI fprintf(dbg, "Call ap_chdir_file(r->filename=[%s]\n",r->filename); #endif ap_chdir_file(r->filename); #ifdef DEBUG_CGI fprintf(dbg, "Back ap_chdir_file(r->filename=[%s]\n",r->filename); #endif #endif if (!cld->debug) ap_error_log2stderr(r->server); #ifdef TPF #ifdef DEBUG_CGI #ifdef _WIN32 fprintf(dbg, "TPF defined... return( 0 ) now...\n"); if ( dbg ) { fclose(dbg); dbg=0; } #endif #endif return (0); #else #ifdef DEBUG_CGI fprintf(dbg, "Call ap_cleanup_for_exec()...\n"); #endif ap_cleanup_for_exec(); #ifdef DEBUG_CGI fprintf(dbg, "Back ap_cleanup_for_exec()...\n"); fprintf(dbg, "Call ap_call_exec()...\n"); #endif child_pid = ap_call_exec(r, pinfo, argv0, env, 0); #ifdef DEBUG_CGI fprintf(dbg, "Back ap_call_exec()...\n"); #endif #if defined(_WIN32) || defined(OS2) #ifdef DEBUG_CGI #ifdef _WIN32 fprintf(dbg, "_WIN32 or OS2 defined... return( child_pid ) now...\n"); if ( dbg ) { fclose(dbg); dbg=0; } #endif #endif return (child_pid); #else ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", r->filename); exit(0); #ifdef DEBUG_CGI #ifdef _WIN32 if ( dbg ) { fclose(dbg); dbg=0; } #endif #endif return (0); #endif #endif } #define MOD_GZIP_SET_BYTES_SENT(r) \ do { if (r->sent_bodyct) \ ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \ } while (0) long mod_gzip_ap_send_fb( BUFF *fb, request_rec *r, int *final_return_code ) { long lrc; int return_code=DECLINED; lrc = (long ) mod_gzip_ap_send_fb_length( fb, r, -1, &return_code ); *final_return_code = return_code; return lrc; } #ifdef USE_TPF_SELECT #define mod_gzip_ap_select(_a, _b, _c, _d, _e) \ tpf_select(_a, _b, _c, _d, _e) #elif defined(SELECT_NEEDS_CAST) #define mod_gzip_ap_select(_a, _b, _c, _d, _e) \ select((_a), (int *)(_b), (int *)(_c), (int *)(_d), (_e)) #else #define mod_gzip_ap_select(_a, _b, _c, _d, _e) \ select(_a, _b, _c, _d, _e) #endif long mod_gzip_ap_send_fb_length( BUFF *fb, request_rec *r, long length, int *final_return_code ) { char cn[]="mod_gzip_ab_send_fb_length()"; char buf[IOBUFSIZE]; long total_bytes_sent = 0; register int n; register int len; register int fd; fd_set fds; int rc; #ifndef USE_GATHER register int w; register int o; #endif #ifdef USE_GATHER int gather_on = 0; int gather_todisk = 0; int gather_origin = 0; char *gather_bufstart = 0; char *gather_source = 0; char *gather_buf = 0; int gather_bufmaxlen = 60000; int gather_byteswritten = 0; int gather_length = 0; int gather_maxlen = 0; long gather_totlen = 0; FILE *gather_fh1 = 0; char gather_filename[ MOD_GZIP_MAX_PATH_LEN + 2 ]; #endif void *modconf = r->server->module_config; mod_gzip_conf *conf; *final_return_code = DECLINED; conf = (mod_gzip_conf *) ap_get_module_config( modconf, &gzip_module ); if ( length == 0 ) { return 0; } ap_bsetflag( fb, B_RD, 0 ); #ifndef TPF ap_bnonblock( fb, B_RD ); #endif fd = ap_bfileno( fb, B_RD ); #ifdef CHECK_FD_SETSIZE if ( fd >= FD_SETSIZE ) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL, "send body: filedescriptor (%u) larger than FD_SETSIZE (%u) " "found, you probably need to rebuild Apache with a " "larger FD_SETSIZE", fd, FD_SETSIZE); return 0; } else { } #else #endif ap_soft_timeout("send body", r); FD_ZERO( &fds ); #ifdef USE_GATHER gather_on = 0; if ( (long) conf->maximum_inmem_size < (long) gather_bufmaxlen ) { gather_maxlen = (int) conf->maximum_inmem_size; } else { gather_maxlen = (int) gather_bufmaxlen; } gather_bufstart = malloc( (int)(gather_maxlen + 2) ); if ( gather_bufstart ) { gather_on = 1; gather_buf = gather_bufstart; gather_source = gather_bufstart; gather_origin = 0; } else { } #endif while( !r->connection->aborted ) { #ifdef NDELAY_PIPE_RETURNS_ZERO int afterselect = 0; #endif if ( (length > 0) && (total_bytes_sent + IOBUFSIZE) > length ) { len = length - total_bytes_sent; } else { len = IOBUFSIZE; } do { n = ap_bread( fb, buf, len ); #ifdef NDELAY_PIPE_RETURNS_ZERO if ((n > 0) || (n == 0 && afterselect)) { break; } #else if (n >= 0) { break; } #endif if ( r->connection->aborted ) { break; } if ( n < 0 && errno != EAGAIN ) { break; } if ( ap_bflush( r->connection->client ) < 0 ) { ap_log_rerror(APLOG_MARK, APLOG_INFO, r, "client stopped connection before send body completed"); ap_bsetflag( r->connection->client, B_EOUT, 1 ); r->connection->aborted = 1; break; } #ifdef _WIN32 FD_SET( (unsigned) fd, &fds ); #else FD_SET( fd, &fds ); #endif #ifdef FUTURE_USE mod_gzip_ap_select(fd + 1, &fds, NULL, NULL, NULL); #endif #ifdef NDELAY_PIPE_RETURNS_ZERO afterselect = 1; #endif } while ( !r->connection->aborted ); if ( n < 1 || r->connection->aborted ) { break; } #ifdef USE_GATHER if ( gather_on ) { if ( ( gather_length + n ) >= gather_maxlen ) { if ( !gather_fh1 ) { mod_gzip_create_unique_filename( (mod_gzip_conf *) conf, (char *) gather_filename, sizeof( gather_filename ) ); gather_fh1 = fopen( gather_filename, "wb" ); if ( gather_fh1 ) { gather_source = gather_filename; gather_origin = 1; } else { gather_on = 0; } } if ( ( gather_fh1 ) && ( gather_length > 0 ) ) { gather_byteswritten = fwrite( gather_bufstart, 1, gather_length, gather_fh1 ); if ( gather_byteswritten != gather_length ) { gather_on = 0; } } if ( ( gather_fh1 ) && ( n > 0 ) ) { gather_byteswritten = fwrite( buf, 1, n, gather_fh1 ); if ( gather_byteswritten != n ) { gather_on = 0; } } gather_buf = gather_bufstart; gather_length = 0; } else { if ( gather_on ) { memcpy( gather_buf, buf, n ); gather_buf += n; gather_length += n; } } gather_totlen += n; } #endif #ifdef FUTURE_USE o = 0; while ( n && !r->connection->aborted ) { #ifdef RUSSIAN_APACHE unsigned char *newbuf,*p; int newlen=0; if ( ra_charset_active(r) ) { if ( ra_flag( r, RA_WIDE_CHARS_SC ) ) { ra_data_server2client(r,&buf[o],n,&newbuf,&newlen); p=newbuf; while( newlen > 0 ) { w = ap_bwrite( r->connection->client, p, newlen ); if(w<=0) goto RECODE_DONE; newlen-=w; p+=w; } w=n; } else { unsigned char *t = r->ra_codep->cp_otabl_p; unsigned char *b = (unsigned char *)&buf[o]; unsigned char *end = b+n; while( b < end ) { *b = t[*b]; b++; } w = ap_bwrite( r->connection->client, &buf[o], n ); } } else { w = ap_bwrite( r->connection->client, &buf[o], n ); } RECODE_DONE:; #else w = ap_bwrite( r->connection->client, &buf[o], n ); #endif if ( w > 0 ) { ap_reset_timeout(r); total_bytes_sent += w; n -= w; o += w; } else if ( w < 0 ) { if ( !r->connection->aborted ) { ap_log_rerror(APLOG_MARK, APLOG_INFO, r, "client stopped connection before send body completed"); ap_bsetflag(r->connection->client, B_EOUT, 1); r->connection->aborted = 1; } break; } } #endif } ap_kill_timeout(r); MOD_GZIP_SET_BYTES_SENT(r); #ifdef USE_GATHER if ( gather_fh1 ) { if ( gather_length > 0 ) { gather_byteswritten = fwrite( gather_bufstart, 1, gather_length, gather_fh1 ); if ( gather_byteswritten != gather_length ) { gather_on = 0; } } fclose( gather_fh1 ); gather_fh1 = 0; } if ( gather_totlen > 0 ) { rc = mod_gzip_encode_and_transmit( (request_rec *) r, (char *) gather_source, (int ) gather_origin, (long ) gather_totlen, (int ) 1 ); *final_return_code = rc; } if ( gather_bufstart ) { free( gather_bufstart ); gather_bufstart = 0; } gather_on = 0; #endif return total_bytes_sent; } /*--------------------------------------------------------------------------*/ /* COMPRESSION SUPPORT ROUTINES */ /*--------------------------------------------------------------------------*/ #define BIG_MEM typedef unsigned uns; typedef unsigned int uni; typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; typedef int gz1_file_t; #ifdef __STDC__ typedef void *voidp; #else typedef char *voidp; #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if defined(__OS2__) && !defined(OS2) # define OS2 #endif #if defined(OS2) && defined(MSDOS) # undef MSDOS #endif #ifdef MSDOS # ifdef __GNUC__ # define near # else # define MAXSEG_64K # ifdef __TURBOC__ # define NO_OFF_T # ifdef __BORLANDC__ # define DIRENT # else # define NO_UTIME # endif # else # define HAVE_SYS_UTIME_H # define NO_UTIME_H # endif # endif # define PATH_SEP2 '\\' # define PATH_SEP3 ':' # define MAX_PATH_LEN 128 # define NO_MULTIPLE_DOTS # define MAX_EXT_CHARS 3 # define Z_SUFFIX "z" # define NO_CHOWN # define PROTO # define STDC_HEADERS # define NO_SIZE_CHECK # define casemap(c) tolow(c) # include # undef OS_CODE # define OS_CODE 0x00 # define SET_BINARY_MODE(fd) setmode(fd, O_BINARY) # if !defined(NO_ASM) && !defined(ASMV) # define ASMV # endif #else # define near #endif #ifdef OS2 # define PATH_SEP2 '\\' # define PATH_SEP3 ':' # define MAX_PATH_LEN 260 # ifdef OS2FAT # define NO_MULTIPLE_DOTS # define MAX_EXT_CHARS 3 # define Z_SUFFIX "z" # define casemap(c) tolow(c) # endif # define NO_CHOWN # define PROTO # define STDC_HEADERS # include # undef OS_CODE # define OS_CODE 0x06 # define SET_BINARY_MODE(fd) setmode(fd, O_BINARY) # ifdef _MSC_VER # define HAVE_SYS_UTIME_H # define NO_UTIME_H # define MAXSEG_64K # undef near # define near _near # endif # ifdef __EMX__ # define HAVE_SYS_UTIME_H # define NO_UTIME_H # define DIRENT # define EXPAND(argc,argv) \ {_response(&argc, &argv); _wildcard(&argc, &argv);} # endif # ifdef __BORLANDC__ # define DIRENT # endif # ifdef __ZTC__ # define NO_DIR # define NO_UTIME_H # include # define EXPAND(argc,argv) \ {response_expand(&argc, &argv);} # endif #endif #ifdef _WIN32 # define HAVE_SYS_UTIME_H # define NO_UTIME_H # define PATH_SEP2 '\\' # define PATH_SEP3 ':' # undef MAX_PATH_LEN # define MAX_PATH_LEN 260 # define NO_CHOWN # define PROTO # define STDC_HEADERS # define SET_BINARY_MODE(fd) setmode(fd, O_BINARY) # include # ifdef NTFAT # define NO_MULTIPLE_DOTS # define MAX_EXT_CHARS 3 # define Z_SUFFIX "z" # define casemap(c) tolow(c) # endif # undef OS_CODE # define OS_CODE 0x00 #endif #ifdef MSDOS # ifdef __TURBOC__ # include # define DYN_ALLOC void * fcalloc (unsigned items, unsigned size); void fcfree (void *ptr); # else # define fcalloc(nitems,itemsize) halloc((long)(nitems),(itemsize)) # define fcfree(ptr) hfree(ptr) # endif #else # ifdef MAXSEG_64K # define fcalloc(items,size) calloc((items),(size)) # else # define fcalloc(items,size) malloc((size_t)(items)*(size_t)(size)) # endif # define fcfree(ptr) free(ptr) #endif #if defined(VAXC) || defined(VMS) # define PATH_SEP ']' # define PATH_SEP2 ':' # define SUFFIX_SEP ';' # define NO_MULTIPLE_DOTS # define Z_SUFFIX "-gz" # define RECORD_IO 1 # define casemap(c) tolow(c) # undef OS_CODE # define OS_CODE 0x02 # define OPTIONS_VAR "GZIP_OPT" # define STDC_HEADERS # define NO_UTIME # define EXPAND(argc,argv) vms_expand_args(&argc,&argv); # include # define unlink delete # ifdef VAXC # define NO_FCNTL_H # include # endif #endif #ifdef AMIGA # define PATH_SEP2 ':' # define STDC_HEADERS # undef OS_CODE # define OS_CODE 0x01 # define ASMV # ifdef __GNUC__ # define DIRENT # define HAVE_UNISTD_H # else # define NO_STDIN_FSTAT # define SYSDIR # define NO_SYMLINK # define NO_CHOWN # define NO_FCNTL_H # include # define direct dirent extern void _expand_args(int *argc, char ***argv); # define EXPAND(argc,argv) _expand_args(&argc,&argv); # undef O_BINARY # endif #endif #if defined(ATARI) || defined(atarist) # ifndef STDC_HEADERS # define STDC_HEADERS # define HAVE_UNISTD_H # define DIRENT # endif # define ASMV # undef OS_CODE # define OS_CODE 0x05 # ifdef TOSFS # define PATH_SEP2 '\\' # define PATH_SEP3 ':' # define MAX_PATH_LEN 128 # define NO_MULTIPLE_DOTS # define MAX_EXT_CHARS 3 # define Z_SUFFIX "z" # define NO_CHOWN # define casemap(c) tolow(c) # define NO_SYMLINK # endif #endif #ifdef MACOS # define PATH_SEP ':' # define DYN_ALLOC # define PROTO # define NO_STDIN_FSTAT # define NO_CHOWN # define NO_UTIME # define chmod(file, mode) (0) # define OPEN(name, flags, mode) open(name, flags) # undef OS_CODE # define OS_CODE 0x07 # ifdef MPW # define isatty(fd) ((fd) <= 2) # endif #endif #ifdef __50SERIES # define PATH_SEP '>' # define STDC_HEADERS # define NO_MEMORY_H # define NO_UTIME_H # define NO_UTIME # define NO_CHOWN # define NO_STDIN_FSTAT # define NO_SIZE_CHECK # define NO_SYMLINK # define RECORD_IO 1 # define casemap(c) tolow(c) # define put_char(c) put_byte((c) & 0x7F) # define get_char(c) ascii2pascii(get_byte()) # undef OS_CODE # define OS_CODE 0x0F # ifdef SIGTERM # undef SIGTERM # endif #endif #if defined(pyr) && !defined(NOMEMCPY) # define NOMEMCPY #endif #ifdef TOPS20 # undef OS_CODE # define OS_CODE 0x0a #endif #ifndef unix # define NO_ST_INO #endif #ifndef OS_CODE # undef OS_CODE # define OS_CODE 0x03 #endif #ifndef PATH_SEP # define PATH_SEP '/' #endif #ifndef casemap # define casemap(c) (c) #endif #ifndef OPTIONS_VAR # define OPTIONS_VAR "GZIP" #endif #ifndef Z_SUFFIX # define Z_SUFFIX ".gz" #endif #ifdef MAX_EXT_CHARS # define MAX_SUFFIX MAX_EXT_CHARS #else # define MAX_SUFFIX 30 #endif #ifndef MIN_PART # define MIN_PART 3 #endif #ifndef EXPAND # define EXPAND(argc,argv) #endif #ifndef RECORD_IO # define RECORD_IO 0 #endif #ifndef SET_BINARY_MODE # define SET_BINARY_MODE(fd) #endif #ifndef OPEN # define OPEN(name, flags, mode) open(name, flags, mode) #endif #ifndef get_char # define get_char() get_byte() #endif #ifndef put_char # define put_char(c) put_byte(c) #endif #ifndef O_BINARY #define O_BINARY 0 #endif #define OK 0 #define LZ1_ERROR 1 #define WARNING 2 #define STORED 0 #define COMPRESSED 1 #define PACKED 2 #define LZHED 3 #define DEFLATED 8 #define MAX_METHODS 9 #ifndef O_CREAT #include #ifndef O_CREAT #define O_CREAT FCREAT #endif #ifndef O_EXCL #define O_EXCL FEXCL #endif #endif #ifndef S_IRUSR #define S_IRUSR 0400 #endif #ifndef S_IWUSR #define S_IWUSR 0200 #endif #define RW_USER (S_IRUSR | S_IWUSR) #ifndef MAX_PATH_LEN #define MAX_PATH_LEN 256 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #define PACK_MAGIC "\037\036" #define GZIP_MAGIC "\037\213" #define OLD_GZIP_MAGIC "\037\236" #define LZH_MAGIC "\037\240" #define PKZIP_MAGIC "\120\113\003\004" #define ASCII_FLAG 0x01 #define CONTINUATION 0x02 #define EXTRA_FIELD 0x04 #define ORIG_NAME 0x08 #define COMMENT 0x10 #define ENCRYPTED 0x20 #define RESERVED 0xC0 #define UNKNOWN 0xffff #define BINARY 0 #define ASCII 1 #ifndef WSIZE #define WSIZE 0x8000 #endif #ifndef INBUFSIZ #ifdef SMALL_MEM #define INBUFSIZ 0x2000 #else #define INBUFSIZ 0x8000 #endif #endif #define INBUF_EXTRA 64 #ifndef OUTBUFSIZ #ifdef SMALL_MEM #define OUTBUFSIZ 8192 #else #define OUTBUFSIZ 0x4000 #endif #endif #define OUTBUF_EXTRA 2048 #ifndef DIST_BUFSIZE #ifdef SMALL_MEM #define DIST_BUFSIZE 0x2000 #else #define DIST_BUFSIZE 0x8000 #endif #endif #ifndef BITS #define BITS 16 #endif #define LZW_MAGIC "\037\235" #define MIN_MATCH 3 #define MAX_MATCH 258 #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) #define MAX_DIST (WSIZE-MIN_LOOKAHEAD) #ifdef SMALL_MEM #define HASH_BITS 13 #endif #ifdef MEDIUM_MEM #define HASH_BITS 14 #endif #ifndef HASH_BITS #define HASH_BITS 15 #endif #define HASH_SIZE (unsigned)(1<block_start >= 0L ? (char*)&gz1->window[(unsigned)gz1->block_start] : \ (char*)NULL, (long)gz1->strstart - gz1->block_start, (eof)) #ifdef DYN_ALLOC # define ALLOC(type, array, size) { \ array = (type*)fcalloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \ if (array == NULL) error("insufficient memory"); \ } # define FREE(array) {if (array != NULL) fcfree(array), array=NULL;} #else # define ALLOC(type, array, size) # define FREE(array) #endif #define GZ1_MAX(a,b) (a >= b ? a : b) #define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) #define smaller(tree, n, m) \ (tree[n].fc.freq < tree[m].fc.freq || \ (tree[n].fc.freq == tree[m].fc.freq && gz1->depth[n] <= gz1->depth[m])) #define send_code(c, tree) send_bits(gz1,tree[c].fc.code, tree[c].dl.len) #define put_byte(c) {gz1->outbuf[gz1->outcnt++]=(uch)(c); if (gz1->outcnt==OUTBUFSIZ)\ flush_outbuf(gz1);} #define put_short(w) \ { if (gz1->outcnt < OUTBUFSIZ-2) { \ gz1->outbuf[gz1->outcnt++] = (uch) ((w) & 0xff); \ gz1->outbuf[gz1->outcnt++] = (uch) ((ush)(w) >> 8); \ } else { \ put_byte((uch)((w) & 0xff)); \ put_byte((uch)((ush)(w) >> 8)); \ } \ } #define put_long(n) { \ put_short((n) & 0xffff); \ put_short(((ulg)(n)) >> 16); \ } #ifdef CRYPT # define NEXTBYTE() \ (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte()) #else # define NEXTBYTE() (uch)get_byte() #endif #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<>=(n);k-=(n);} #define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) #define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) #define put_ubyte(c) {gz1->window[gz1->outcnt++]=(uch)(c); if (gz1->outcnt==WSIZE)\ flush_window(gz1);} #define WARN(msg) { if (gz1->exit_code == OK) gz1->exit_code = WARNING; } #define get_byte() (gz1->inptr < gz1->insize ? gz1->inbuf[gz1->inptr++] : fill_inbuf(gz1,0)) #define try_byte() (gz1->inptr < gz1->insize ? gz1->inbuf[gz1->inptr++] : fill_inbuf(gz1,1)) #define d_code(dist) \ ((dist) < 256 ? gz1->dist_code[dist] : gz1->dist_code[256+((dist)>>7)]) typedef struct config { ush good_length; ush max_lazy; ush nice_length; ush max_chain; } config; config configuration_table[10] = { {0, 0, 0, 0}, {4, 4, 8, 4}, {4, 5, 16, 8}, {4, 6, 32, 32}, {4, 4, 16, 16}, {8, 16, 32, 32}, {8, 16, 128, 128}, {8, 32, 128, 256}, {32, 128, 258, 1024}, {32, 258, 258, 4096}}; typedef struct ct_data { union { ush freq; ush code; } fc; union { ush dad; ush len; } dl; } ct_data; typedef struct tree_desc { ct_data *dyn_tree; ct_data *static_tree; int *extra_bits; int extra_base; int elems; int max_length; int max_code; } tree_desc; struct huft { uch e; uch b; union { ush n; struct huft *t; } v; }; uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; int extra_lbits[LENGTH_CODES] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; int extra_dbits[D_CODES] = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; int extra_blbits[BL_CODES] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; ulg crc_32_tab[] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; typedef struct _GZ1 { long compression_format; long versionid1; int state; int done; int deflate1_initialized; unsigned deflate1_hash_head; unsigned deflate1_prev_match; int deflate1_flush; int deflate1_match_available; unsigned deflate1_match_length; char ifname[MAX_PATH_LEN]; char ofname[MAX_PATH_LEN]; struct stat istat; gz1_file_t zfile; int input_ismem; char *input_ptr; long input_bytesleft; int output_ismem; char *output_ptr; uns output_maxlen; int compr_level; long time_stamp; long ifile_size; int ifd; int ofd; int part_nb; int last_member; int save_orig_name; long header_bytes; long bytes_in; long bytes_out; uns insize; uns inptr; uns outcnt; uns ins_h; long block_start; uns good_match; uni max_lazy_match; uni prev_length; uns max_chain_length; uns strstart; uns match_start; int eofile; uns lookahead; ush *file_type; int *file_method; ulg opt_len; ulg static_len; ulg compressed_len; ulg input_len; uns last_flags; uch flags; uns last_lit; uns last_dist; uch flag_bit; int heap_len; int heap_max; ulg bb; uns bk; ush bi_buf; int bi_valid; uns hufts; int decrypt; int ascii; int msg_done; int abortflag; int decompress; int do_lzw; int to_stdout; int force; int verbose; int quiet; int list; int test; int ext_header; int pkzip; int method; int level; int no_time; int no_name; int exit_code; int lbits; int dbits; ulg window_size; ulg crc; ulg adler; uch dist_code[512]; uch length_code[MAX_MATCH-MIN_MATCH+1]; int heap[2*L_CODES+1]; uch depth[2*L_CODES+1]; int base_length[LENGTH_CODES]; int base_dist[D_CODES]; ush bl_count[MAX_BITS+1]; uch flag_buf[(LIT_BUFSIZE/8)]; #ifdef DYN_ALLOC uch *inbuf; uch *outbuf; ush *d_buf; uch *window; #else uch inbuf [INBUFSIZ +INBUF_EXTRA]; uch outbuf[OUTBUFSIZ+OUTBUF_EXTRA]; ush d_buf [DIST_BUFSIZE]; uch window[2L*WSIZE]; #endif #ifdef FULL_SEARCH #define nice_match MAX_MATCH #else int nice_match; #endif #ifdef CRYPT uch cc; #endif ct_data static_ltree[L_CODES+2]; ct_data static_dtree[D_CODES]; ct_data dyn_dtree[(2*D_CODES+1)]; ct_data dyn_ltree[HEAP_SIZE]; ct_data bl_tree[2*BL_CODES+1]; tree_desc l_desc; tree_desc d_desc; tree_desc bl_desc; #ifndef MAXSEG_64K ush prev2[1L<prev2 #define head (gz1->prev2+WSIZE) #else ush * prev2; ush * tab_prefix1; #define prev gz1->prev2 #define head gz1->tab_prefix1 #endif } GZ1; typedef GZ1 *PGZ1; int gz1_size = sizeof( GZ1 ); /* Declare some local function protypes... */ /* Any routine name that can/might conflict with */ /* other modules or object code should simply have */ /* the standard prefix 'gz1_' added to the front. */ /* This will only usually be any kind of problem at all */ /* if the code is being compiled directly into the parent */ /* instead of being built as a standalone DLL or DSO library. */ PGZ1 gz1_init ( void ); int gz1_cleanup ( PGZ1 gz1 ); ulg gz1_deflate ( PGZ1 gz1 ); ulg gz1_deflate_fast( PGZ1 gz1 ); /* The rest of the routines should not need the 'gz1_' prefix. */ /* No conflicts reported at this time. */ int inflate ( PGZ1 gz1 ); int inflate_dynamic( PGZ1 gz1 ); int inflate_stored ( PGZ1 gz1 ); int inflate_fixed ( PGZ1 gz1 ); void fill_window ( PGZ1 gz1 ); void flush_outbuf ( PGZ1 gz1 ); void flush_window ( PGZ1 gz1 ); void bi_windup ( PGZ1 gz1 ); void set_file_type ( PGZ1 gz1 ); void init_block ( PGZ1 gz1 ); int build_bl_tree ( PGZ1 gz1 ); void read_error ( PGZ1 gz1 ); void write_error ( PGZ1 gz1 ); int get_header ( PGZ1 gz1, int in ); int inflate_block ( PGZ1 gz1, int *e ); int fill_inbuf ( PGZ1 gz1, int eof_ok ); char *gz1_basename ( PGZ1 gz1, char *fname ); int longest_match ( PGZ1 gz1, unsigned cur_match ); void bi_init ( PGZ1 gz1, gz1_file_t zipfile ); int file_read ( PGZ1 gz1, char *buf, unsigned size ); void write_buf ( PGZ1 gz1, int fd, voidp buf, unsigned cnt ); void error( char *msg ); /* XXX - Precomputed zlib header. If you change the window size or * compression level from the defaults, this will break badly. The * algorithm to build this is fairly complex; you can find it in * the file deflate.c from the zlib distribution. */ #define ZLIB_HEADER "\170" ulg adler32(ulg adler, uch *buf, unsigned len); int zip( PGZ1 gz1, int in, int out ); ulg flush_block( PGZ1 gz1, char *buf, ulg stored_len, int eof ); void copy_block( PGZ1 gz1, char *buf, unsigned len, int header ); int ct_tally( PGZ1 gz1, int dist, int lc ); void send_bits( PGZ1 gz1, int value, int length ); void send_tree( PGZ1 gz1, ct_data *tree, int max_code ); void send_all_trees( PGZ1 gz1, int lcodes, int dcodes, int blcodes ); void ct_init( PGZ1 gz1, ush *attr, int *methodp ); void lm_init( PGZ1 gz1, int pack_level, ush *flags ); void build_tree( PGZ1 gz1, tree_desc *desc ); void compress_block( PGZ1 gz1, ct_data *ltree, ct_data *dtree ); void gen_bitlen( PGZ1 gz1, tree_desc *desc ); void pqdownheap( PGZ1 gz1, ct_data *tree, int k ); int huft_build( PGZ1 gz1, unsigned *b, unsigned n, unsigned s, ush *d, ush *e, struct huft **t, int *m ); ulg updcrc( PGZ1 gz1, uch *s, unsigned n ); int inflate_codes( PGZ1 gz1, struct huft *tl, struct huft *td, int bl, int bd ); void gen_codes( PGZ1 gz1, ct_data *tree, int max_code ); void scan_tree( PGZ1 gz1, ct_data *tree, int max_code ); unsigned bi_reverse( PGZ1 gz1, unsigned code, int len ); int huft_free( PGZ1 gz1, struct huft *t ); PGZ1 gz1_init() { PGZ1 gz1=0; gz1 = (PGZ1) malloc( gz1_size ); if ( !gz1 ) { return 0; } memset( gz1, 0, gz1_size ); ALLOC(uch, gz1->inbuf, INBUFSIZ +INBUF_EXTRA); if ( !gz1->inbuf ) { free( gz1 ); return 0; } ALLOC(uch, gz1->outbuf, OUTBUFSIZ+OUTBUF_EXTRA); if ( !gz1->outbuf ) { FREE( gz1->inbuf ); free( gz1 ); return 0; } ALLOC(ush, gz1->d_buf, DIST_BUFSIZE); if ( !gz1->d_buf ) { FREE( gz1->outbuf ); FREE( gz1->inbuf ); free( gz1 ); return 0; } ALLOC(uch, gz1->window, 2L*WSIZE); if ( !gz1->window ) { FREE( gz1->d_buf ); FREE( gz1->outbuf ); FREE( gz1->inbuf ); free( gz1 ); return 0; } #ifndef MAXSEG_64K #else ALLOC(ush, gz1->prev2, 1L<<(BITS-1) ); if ( !gz1->prev2 ) { FREE( gz1->window ); FREE( gz1->d_buf ); FREE( gz1->outbuf ); FREE( gz1->inbuf ); free( gz1 ); return 0; } ALLOC(ush, gz1->tab_prefix1, 1L<<(BITS-1) ); if ( !gz1->tab_prefix1 ) { FREE( gz1->prev2 ); FREE( gz1->window ); FREE( gz1->d_buf ); FREE( gz1->outbuf ); FREE( gz1->inbuf ); free( gz1 ); return 0; } #endif gz1->method = DEFLATED; gz1->level = 6; gz1->no_time = -1; gz1->no_name = -1; gz1->exit_code = OK; gz1->lbits = 9; gz1->dbits = 6; gz1->window_size = (ulg)2*WSIZE; gz1->crc = (ulg)0xffffffffL; gz1->d_desc.dyn_tree = (ct_data *) gz1->dyn_dtree; gz1->d_desc.static_tree = (ct_data *) gz1->static_dtree; gz1->d_desc.extra_bits = (int *) extra_dbits; gz1->d_desc.extra_base = (int ) 0; gz1->d_desc.elems = (int ) D_CODES; gz1->d_desc.max_length = (int ) MAX_BITS; gz1->d_desc.max_code = (int ) 0; gz1->l_desc.dyn_tree = (ct_data *) gz1->dyn_ltree; gz1->l_desc.static_tree = (ct_data *) gz1->static_ltree; gz1->l_desc.extra_bits = (int *) extra_lbits; gz1->l_desc.extra_base = (int ) LITERALS+1; gz1->l_desc.elems = (int ) L_CODES; gz1->l_desc.max_length = (int ) MAX_BITS; gz1->l_desc.max_code = (int ) 0; gz1->bl_desc.dyn_tree = (ct_data *) gz1->bl_tree; gz1->bl_desc.static_tree = (ct_data *) 0; gz1->bl_desc.extra_bits = (int *) extra_blbits; gz1->bl_desc.extra_base = (int ) 0; gz1->bl_desc.elems = (int ) BL_CODES; gz1->bl_desc.max_length = (int ) MAX_BL_BITS; gz1->bl_desc.max_code = (int ) 0; return (PGZ1) gz1; } int gz1_cleanup( PGZ1 gz1 ) { #ifndef MAXSEG_64K #else FREE( gz1->tab_prefix1 ); FREE( gz1->prev2 ); #endif FREE( gz1->window ); FREE( gz1->d_buf ); FREE( gz1->outbuf ); FREE( gz1->inbuf ); free( gz1 ); gz1 = 0; return 0; } int (*read_buf)(PGZ1 gz1, char *buf, unsigned size); void error( char *msg ) { msg = msg; } int (*work)( PGZ1 gz1, int infile, int outfile ) = 0; #ifdef __BORLANDC__ #pragma argsused #endif int get_header( PGZ1 gz1, int in ) { uch flags; char magic[2]; ulg stamp; unsigned len; unsigned part; if ( gz1->force && gz1->to_stdout ) { magic[0] = (char)try_byte(); magic[1] = (char)try_byte(); } else { magic[0] = (char)get_byte(); magic[1] = (char)get_byte(); } gz1->method = -1; gz1->header_bytes = 0; gz1->last_member = RECORD_IO; gz1->part_nb++; if ( memcmp(magic, GZIP_MAGIC, 2 ) == 0 || memcmp(magic, OLD_GZIP_MAGIC, 2 ) == 0 ) { gz1->method = (int)get_byte(); if ( gz1->method != DEFLATED ) { gz1->exit_code = LZ1_ERROR; return -1; } return -1; if ((flags & ENCRYPTED) != 0) { gz1->exit_code = LZ1_ERROR; return -1; } if ((flags & CONTINUATION) != 0) { gz1->exit_code = LZ1_ERROR; if ( gz1->force <= 1) return -1; } if ((flags & RESERVED) != 0) { gz1->exit_code = LZ1_ERROR; if ( gz1->force <= 1) return -1; } stamp = (ulg)get_byte(); stamp |= ((ulg)get_byte()) << 8; stamp |= ((ulg)get_byte()) << 16; stamp |= ((ulg)get_byte()) << 24; if ( stamp != 0 && !gz1->no_time ) { gz1->time_stamp = stamp; } (void)get_byte(); (void)get_byte(); if ((flags & CONTINUATION) != 0) { part = (unsigned) get_byte(); part |= ((unsigned) get_byte())<<8; } if ((flags & EXTRA_FIELD) != 0) { len = (unsigned) get_byte(); len |= ((unsigned) get_byte())<<8; while (len--) (void)get_byte(); } if ((flags & COMMENT) != 0) { while (get_char() != 0) ; } if ( gz1->part_nb == 1 ) { gz1->header_bytes = gz1->inptr + 2*sizeof(long); } } return gz1->method; } int fill_inbuf( PGZ1 gz1, int eof_ok ) { int len; int bytes_to_copy; gz1->insize = 0; errno = 0; do { if ( gz1->input_ismem ) { if ( gz1->input_bytesleft > 0 ) { bytes_to_copy = INBUFSIZ - gz1->insize; if ( bytes_to_copy > gz1->input_bytesleft ) { bytes_to_copy = gz1->input_bytesleft; } memcpy( (char*)gz1->inbuf+gz1->insize, gz1->input_ptr, bytes_to_copy ); gz1->input_ptr += bytes_to_copy; gz1->input_bytesleft -= bytes_to_copy; len = bytes_to_copy; } else { len = 0; } } else { len = read( gz1->ifd, (char*)gz1->inbuf+gz1->insize, INBUFSIZ-gz1->insize ); } if (len == 0 || len == EOF) break; gz1->insize += len; } while( gz1->insize < INBUFSIZ ); if ( gz1->insize == 0 ) { if( eof_ok ) return EOF; read_error( gz1 ); } gz1->bytes_in += (ulg) gz1->insize; gz1->inptr = 1; return gz1->inbuf[0]; } ulg updcrc( PGZ1 gz1, uch *s, unsigned n ) { register ulg c; if ( s == NULL ) { c = 0xffffffffL; } else { c = gz1->crc; if ( n ) { do{ c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); } while( --n ); } } gz1->crc = c; return( c ^ 0xffffffffL ); } void read_error( PGZ1 gz1 ) { gz1->abortflag = 1; } void mod_gzip_strlwr( char *s ) { char *p1=s; if ( s == 0 ) return; while ( *p1 != 0 ) { if ( *p1 > 96 ) *p1 = *p1 - 32; p1++; } } #ifdef __BORLANDC__ #pragma argsused #endif char *gz1_basename( PGZ1 gz1, char *fname ) { char *p; if ((p = strrchr(fname, PATH_SEP)) != NULL) fname = p+1; #ifdef PATH_SEP2 if ((p = strrchr(fname, PATH_SEP2)) != NULL) fname = p+1; #endif #ifdef PATH_SEP3 if ((p = strrchr(fname, PATH_SEP3)) != NULL) fname = p+1; #endif #ifdef SUFFIX_SEP if ((p = strrchr(fname, SUFFIX_SEP)) != NULL) *p = '\0'; #endif if (casemap('A') == 'a') mod_gzip_strlwr(fname); return fname; } void write_buf( PGZ1 gz1, int fd, voidp buf, unsigned cnt ) { unsigned n; if ( gz1->output_ismem ) { if ( ( gz1->bytes_out + cnt ) < gz1->output_maxlen ) { memcpy( gz1->output_ptr, buf, cnt ); gz1->output_ptr += cnt; } else { write_error( gz1 ); } } else { while ((n = write(fd, buf, cnt)) != cnt) { if (n == (unsigned)(-1)) { write_error( gz1 ); } cnt -= n; buf = (voidp)((char*)buf+n); } } } void write_error( PGZ1 gz1 ) { gz1->abortflag = 1; } #ifdef __TURBOC__ #ifndef BC55 static ush ptr_offset = 0; void * fcalloc( unsigned items, unsigned size ) { void * buf = farmalloc((ulg)items*size + 16L); if (buf == NULL) return NULL; if (ptr_offset == 0) { ptr_offset = (ush)((uch*)buf-0); } else if (ptr_offset != (ush)((uch*)buf-0)) { error("inconsistent ptr_offset"); } *((ush*)&buf+1) += (ptr_offset + 15) >> 4; *(ush*)&buf = 0; return buf; } void fcfree( void *ptr ) { *((ush*)&ptr+1) -= (ptr_offset + 15) >> 4; *(ush*)&ptr = ptr_offset; farfree(ptr); } #endif #endif int zip( PGZ1 gz1, int in, int out ) { uch flags = 0; ush attr = 0; ush deflate_flags = 0; gz1->ifd = in; gz1->ofd = out; gz1->outcnt = 0; gz1->method = DEFLATED; put_byte(GZIP_MAGIC[0]); put_byte(GZIP_MAGIC[1]); put_byte(DEFLATED); if ( gz1->save_orig_name ) { flags |= ORIG_NAME; } put_byte(flags); put_long(gz1->time_stamp); gz1->crc = -1; updcrc( gz1, NULL, 0 ); bi_init( gz1, out ); ct_init( gz1, &attr, &gz1->method ); lm_init( gz1, gz1->level, &deflate_flags ); put_byte((uch)deflate_flags); put_byte(OS_CODE); if ( gz1->save_orig_name ) { char *p = gz1_basename( gz1, gz1->ifname ); do { put_char(*p); } while (*p++); } gz1->header_bytes = (long)gz1->outcnt; (void) gz1_deflate( gz1 ); put_long( gz1->crc ); put_long( gz1->bytes_in ); gz1->header_bytes += 2*sizeof(long); flush_outbuf( gz1 ); return OK; } ulg gz1_deflate( PGZ1 gz1 ) { unsigned hash_head; unsigned prev_match; int flush; int match_available = 0; register unsigned match_length = MIN_MATCH-1; #ifdef DEBUG long isize; #endif if (gz1->compr_level <= 3) { return gz1_deflate_fast(gz1); } while (gz1->lookahead != 0) { gz1->ins_h = (((gz1->ins_h)<window[gz1->strstart+MIN_MATCH-1])) & HASH_MASK; prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ]; head[ gz1->ins_h ] = gz1->strstart; gz1->prev_length = match_length, prev_match = gz1->match_start; match_length = MIN_MATCH-1; if (hash_head != NIL && gz1->prev_length < gz1->max_lazy_match && gz1->strstart - hash_head <= MAX_DIST) { match_length = longest_match( gz1, hash_head ); if (match_length > gz1->lookahead) match_length = gz1->lookahead; if (match_length == MIN_MATCH && gz1->strstart-gz1->match_start > TOO_FAR){ match_length--; } } if (gz1->prev_length >= MIN_MATCH && match_length <= gz1->prev_length) { flush = ct_tally(gz1,gz1->strstart-1-prev_match, gz1->prev_length - MIN_MATCH); gz1->lookahead -= ( gz1->prev_length - 1 ); gz1->prev_length -= 2; do { gz1->strstart++; gz1->ins_h = (((gz1->ins_h)<window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK; prev[ gz1->strstart & WMASK ] = hash_head = head[gz1->ins_h]; head[ gz1->ins_h ] = gz1->strstart; } while (--gz1->prev_length != 0); match_available = 0; match_length = MIN_MATCH-1; gz1->strstart++; if (flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; } else if (match_available) { if (ct_tally( gz1, 0, gz1->window[gz1->strstart-1] )) { FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; } gz1->strstart++; gz1->lookahead--; } else { match_available = 1; gz1->strstart++; gz1->lookahead--; } while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) fill_window(gz1); } if (match_available) ct_tally( gz1, 0, gz1->window[gz1->strstart-1] ); return FLUSH_BLOCK(1); return 0; } void flush_outbuf( PGZ1 gz1 ) { if ( gz1->outcnt == 0 ) { return; } write_buf( gz1, gz1->ofd, (char *)gz1->outbuf, gz1->outcnt ); gz1->bytes_out += (ulg)gz1->outcnt; gz1->outcnt = 0; } void lm_init( PGZ1 gz1, int pack_level, ush *flags ) { register unsigned j; if ( pack_level < 1 || pack_level > 9 ) { error("bad pack level"); } gz1->compr_level = pack_level; #if defined(MAXSEG_64K) && HASH_BITS == 15 for (j = 0; j < HASH_SIZE; j++) head[j] = NIL; #else memset( (char*)head, 0, (HASH_SIZE*sizeof(*head)) ); #endif gz1->max_lazy_match = configuration_table[pack_level].max_lazy; gz1->good_match = configuration_table[pack_level].good_length; #ifndef FULL_SEARCH gz1->nice_match = configuration_table[pack_level].nice_length; #endif gz1->max_chain_length = configuration_table[pack_level].max_chain; if ( pack_level == 1 ) { *flags |= FAST; } else if ( pack_level == 9 ) { *flags |= SLOW; } gz1->strstart = 0; gz1->block_start = 0L; #ifdef ASMV match_init(); #endif gz1->lookahead = read_buf(gz1,(char*)gz1->window, sizeof(int) <= 2 ? (unsigned)WSIZE : 2*WSIZE); if (gz1->lookahead == 0 || gz1->lookahead == (unsigned)EOF) { gz1->eofile = 1, gz1->lookahead = 0; return; } gz1->eofile = 0; while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) { fill_window(gz1); } gz1->ins_h = 0; for ( j=0; jins_h = (((gz1->ins_h)<window[j])) & HASH_MASK; } } void fill_window( PGZ1 gz1 ) { register unsigned n, m; unsigned more = (unsigned)( gz1->window_size - (ulg)gz1->lookahead - (ulg)gz1->strstart ); if ( more == (unsigned)EOF) { more--; } else if ( gz1->strstart >= WSIZE+MAX_DIST ) { memcpy((char*)gz1->window, (char*)gz1->window+WSIZE, (unsigned)WSIZE); gz1->match_start -= WSIZE; gz1->strstart -= WSIZE; gz1->block_start -= (long) WSIZE; for ( n = 0; n < HASH_SIZE; n++ ) { m = head[n]; head[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL); } for ( n = 0; n < WSIZE; n++ ) { m = prev[n]; prev[n] = (ush)(m >= WSIZE ? m-WSIZE : NIL); } more += WSIZE; } if ( !gz1->eofile ) { n = read_buf(gz1,(char*)gz1->window+gz1->strstart+gz1->lookahead, more); if ( n == 0 || n == (unsigned)EOF ) { gz1->eofile = 1; } else { gz1->lookahead += n; } } } ulg gz1_deflate_fast( PGZ1 gz1 ) { unsigned hash_head; int flush; unsigned match_length = 0; gz1->prev_length = MIN_MATCH-1; while (gz1->lookahead != 0) { gz1->ins_h = (((gz1->ins_h)<window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK; prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ]; head[ gz1->ins_h ] = gz1->strstart; if (hash_head != NIL && gz1->strstart - hash_head <= MAX_DIST) { match_length = longest_match( gz1, hash_head ); if (match_length > gz1->lookahead) match_length = gz1->lookahead; } if (match_length >= MIN_MATCH) { flush = ct_tally(gz1,gz1->strstart-gz1->match_start, match_length - MIN_MATCH); gz1->lookahead -= match_length; if (match_length <= gz1->max_lazy_match ) { match_length--; do { gz1->strstart++; gz1->ins_h = (((gz1->ins_h)<window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK; prev[ gz1->strstart & WMASK ] = hash_head = head[ gz1->ins_h ]; head[ gz1->ins_h ] = gz1->strstart; } while (--match_length != 0); gz1->strstart++; } else { gz1->strstart += match_length; match_length = 0; gz1->ins_h = gz1->window[gz1->strstart]; gz1->ins_h = (((gz1->ins_h)<window[gz1->strstart+1])) & HASH_MASK; #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif } } else { flush = ct_tally(gz1, 0, gz1->window[gz1->strstart]); gz1->lookahead--; gz1->strstart++; } if (flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile) fill_window(gz1); } return FLUSH_BLOCK(1); } void ct_init( PGZ1 gz1, ush *attr, int *methodp ) { #ifdef DD1 int i,ii; #endif int n; int bits; int length; int code; int dist; gz1->file_type = attr; gz1->file_method = methodp; gz1->compressed_len = gz1->input_len = 0L; if ( gz1->static_dtree[0].dl.len != 0 ) { return; } length = 0; for ( code = 0; code < LENGTH_CODES-1; code++ ) { gz1->base_length[code] = length; for ( n = 0; n < (1<length_code[length++] = (uch)code; } } gz1->length_code[length-1] = (uch)code; dist = 0; for ( code = 0 ; code < 16; code++ ) { gz1->base_dist[code] = dist; for ( n = 0; n < (1<dist_code[dist++] = (uch)code; } } dist >>= 7; for ( ; code < D_CODES; code++ ) { gz1->base_dist[code] = dist << 7; for ( n = 0; n < (1<<(extra_dbits[code]-7)); n++ ) { gz1->dist_code[256 + dist++] = (uch)code; } } for ( bits = 0; bits <= MAX_BITS; bits++ ) { gz1->bl_count[bits] = 0; } n = 0; while (n <= 143) gz1->static_ltree[n++].dl.len = 8, gz1->bl_count[8]++; while (n <= 255) gz1->static_ltree[n++].dl.len = 9, gz1->bl_count[9]++; while (n <= 279) gz1->static_ltree[n++].dl.len = 7, gz1->bl_count[7]++; while (n <= 287) gz1->static_ltree[n++].dl.len = 8, gz1->bl_count[8]++; gen_codes(gz1,(ct_data *)gz1->static_ltree, L_CODES+1); for ( n = 0; n < D_CODES; n++ ) { gz1->static_dtree[n].dl.len = 5; gz1->static_dtree[n].fc.code = bi_reverse( gz1, n, 5 ); } init_block( gz1 ); } ulg flush_block( PGZ1 gz1, char *buf, ulg stored_len, int eof ) { ulg opt_lenb; ulg static_lenb; int max_blindex; gz1->flag_buf[gz1->last_flags] = gz1->flags; if (*gz1->file_type == (ush)UNKNOWN) set_file_type(gz1); build_tree( gz1, (tree_desc *)(&gz1->l_desc) ); build_tree( gz1, (tree_desc *)(&gz1->d_desc) ); max_blindex = build_bl_tree( gz1 ); opt_lenb = (gz1->opt_len+3+7)>>3; static_lenb = (gz1->static_len+3+7)>>3; gz1->input_len += stored_len; if (static_lenb <= opt_lenb) opt_lenb = static_lenb; #ifdef FORCE_METHOD if ( level == 1 && eof && gz1->compressed_len == 0L ) #else if (stored_len <= opt_lenb && eof && gz1->compressed_len == 0L && 0 ) #endif { if (buf == (char*)0) error ("block vanished"); copy_block( gz1, buf, (unsigned)stored_len, 0 ); gz1->compressed_len = stored_len << 3; *gz1->file_method = STORED; #ifdef FORCE_METHOD } else if (level == 2 && buf != (char*)0) { #else } else if (stored_len+4 <= opt_lenb && buf != (char*)0) { #endif send_bits(gz1,(STORED_BLOCK<<1)+eof, 3); gz1->compressed_len = (gz1->compressed_len + 3 + 7) & ~7L; gz1->compressed_len += (stored_len + 4) << 3; copy_block(gz1, buf, (unsigned)stored_len, 1); #ifdef FORCE_METHOD } else if (level == 3) { #else } else if (static_lenb == opt_lenb) { #endif send_bits(gz1,(STATIC_TREES<<1)+eof, 3); compress_block( gz1, (ct_data *)gz1->static_ltree, (ct_data *)gz1->static_dtree ); gz1->compressed_len += 3 + gz1->static_len; } else { send_bits(gz1,(DYN_TREES<<1)+eof, 3); send_all_trees( gz1, gz1->l_desc.max_code+1, gz1->d_desc.max_code+1, max_blindex+1 ); compress_block( gz1, (ct_data *)gz1->dyn_ltree, (ct_data *)gz1->dyn_dtree ); gz1->compressed_len += 3 + gz1->opt_len; } init_block( gz1 ); if ( eof ) { bi_windup( gz1 ); gz1->compressed_len += 7; } return gz1->compressed_len >> 3; } #ifdef __BORLANDC__ #pragma argsused #endif unsigned bi_reverse( PGZ1 gz1, unsigned code, int len ) { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } void set_file_type( PGZ1 gz1 ) { int n = 0; unsigned ascii_freq = 0; unsigned bin_freq = 0; while (n < 7) bin_freq += gz1->dyn_ltree[n++].fc.freq; while (n < 128) ascii_freq += gz1->dyn_ltree[n++].fc.freq; while (n < LITERALS) bin_freq += gz1->dyn_ltree[n++].fc.freq; *gz1->file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII; } void init_block( PGZ1 gz1 ) { int n; for (n = 0; n < L_CODES; n++) gz1->dyn_ltree[n].fc.freq = 0; for (n = 0; n < D_CODES; n++) gz1->dyn_dtree[n].fc.freq = 0; for (n = 0; n < BL_CODES; n++) gz1->bl_tree[n].fc.freq = 0; gz1->dyn_ltree[END_BLOCK].fc.freq = 1; gz1->opt_len = 0L; gz1->static_len = 0L; gz1->last_lit = 0; gz1->last_dist = 0; gz1->last_flags = 0; gz1->flags = 0; gz1->flag_bit = 1; } void bi_init( PGZ1 gz1, gz1_file_t zipfile ) { gz1->zfile = zipfile; gz1->bi_buf = 0; gz1->bi_valid = 0; if ( gz1->zfile != NO_FILE ) { read_buf = file_read; } } int ct_tally( PGZ1 gz1, int dist, int lc ) { int dcode; gz1->inbuf[gz1->last_lit++] = (uch)lc; if ( dist == 0 ) { gz1->dyn_ltree[lc].fc.freq++; } else { dist--; gz1->dyn_ltree[gz1->length_code[lc]+LITERALS+1].fc.freq++; gz1->dyn_dtree[d_code(dist)].fc.freq++; gz1->d_buf[gz1->last_dist++] = (ush)dist; gz1->flags |= gz1->flag_bit; } gz1->flag_bit <<= 1; if ( (gz1->last_lit & 7) == 0 ) { gz1->flag_buf[gz1->last_flags++] = gz1->flags; gz1->flags = 0, gz1->flag_bit = 1; } if ( gz1->level > 2 && (gz1->last_lit & 0xfff) == 0) { ulg out_length = (ulg) ( gz1->last_lit * 8L ); ulg in_length = (ulg) ( gz1->strstart - gz1->block_start ); for ( dcode = 0; dcode < D_CODES; dcode++ ) { out_length += (ulg) ((gz1->dyn_dtree[dcode].fc.freq)*(5L+extra_dbits[dcode])); } out_length >>= 3; if ( gz1->last_dist < gz1->last_lit/2 && out_length < in_length/2 ) { return 1; } } return( gz1->last_lit == LIT_BUFSIZE-1 || gz1->last_dist == DIST_BUFSIZE ); } void compress_block( PGZ1 gz1, ct_data *ltree, ct_data *dtree ) { unsigned dist; int lc; unsigned lx = 0; unsigned dx = 0; unsigned fx = 0; uch flag = 0; unsigned code; int extra; if (gz1->last_lit != 0) do { if ((lx & 7) == 0) flag = gz1->flag_buf[fx++]; lc = gz1->inbuf[lx++]; if ((flag & 1) == 0) { send_code(lc, ltree); } else { code = gz1->length_code[lc]; send_code(code+LITERALS+1, ltree); extra = extra_lbits[code]; if (extra != 0) { lc -= gz1->base_length[code]; send_bits(gz1,lc, extra); } dist = gz1->d_buf[dx++]; code = d_code(dist); send_code(code, dtree); extra = extra_dbits[code]; if (extra != 0) { dist -= gz1->base_dist[code]; send_bits(gz1,dist, extra); } } flag >>= 1; } while (lx < gz1->last_lit); send_code(END_BLOCK, ltree); } #ifndef ASMV int longest_match( PGZ1 gz1, unsigned cur_match ) { unsigned chain_length = gz1->max_chain_length; register uch *scan = gz1->window + gz1->strstart; register uch *match; register int len; int best_len = gz1->prev_length; unsigned limit = gz1->strstart > (unsigned)MAX_DIST ? gz1->strstart - (unsigned)MAX_DIST : NIL; #if HASH_BITS < 8 || MAX_MATCH != 258 error: Code too clever #endif #ifdef UNALIGNED_OK register uch *strend = gz1->window + gz1->strstart + MAX_MATCH - 1; register ush scan_start = *(ush*)scan; register ush scan_end = *(ush*)(scan+best_len-1); #else register uch *strend = gz1->window + gz1->strstart + MAX_MATCH; register uch scan_end1 = scan[best_len-1]; register uch scan_end = scan[best_len]; #endif if (gz1->prev_length >= gz1->good_match) { chain_length >>= 2; } do { match = gz1->window + cur_match; #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) if (*(ush*)(match+best_len-1) != scan_end || *(ush*)match != scan_start) continue; scan++, match++; do { } while (*(ush*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(match+=2) && scan < strend); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; scan += 2, match++; do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif if (len > best_len) { gz1->match_start = cur_match; best_len = len; if (len >= gz1->nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ush*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & WMASK]) > limit && --chain_length != 0); return best_len; } #endif void send_bits( PGZ1 gz1, int value, int length ) { if ( gz1->bi_valid > (int) BUFSIZE - length ) { gz1->bi_buf |= (value << gz1->bi_valid); put_short(gz1->bi_buf); gz1->bi_buf = (ush)value >> (BUFSIZE - gz1->bi_valid); gz1->bi_valid += length - BUFSIZE; } else { gz1->bi_buf |= value << gz1->bi_valid; gz1->bi_valid += length; } } void build_tree( PGZ1 gz1, tree_desc *desc ) { int elems = desc->elems; ct_data *tree = desc->dyn_tree; ct_data *stree = desc->static_tree; int n; int m; int max_code = -1; int node = elems; int new1; gz1->heap_len = 0, gz1->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].fc.freq != 0) { gz1->heap[++gz1->heap_len] = max_code = n; gz1->depth[n] = 0; } else { tree[n].dl.len = 0; } } while (gz1->heap_len < 2) { new1 = gz1->heap[++gz1->heap_len] = (max_code < 2 ? ++max_code : 0); tree[new1].fc.freq = 1; gz1->depth[new1] = 0; gz1->opt_len--; if (stree) gz1->static_len -= stree[new1].dl.len; } desc->max_code = max_code; for (n = gz1->heap_len/2; n >= 1; n--) pqdownheap(gz1, tree, n); do { n = gz1->heap[SMALLEST]; gz1->heap[SMALLEST] = gz1->heap[gz1->heap_len--]; pqdownheap(gz1, tree, SMALLEST); m = gz1->heap[SMALLEST]; gz1->heap[--gz1->heap_max] = n; gz1->heap[--gz1->heap_max] = m; tree[node].fc.freq = tree[n].fc.freq + tree[m].fc.freq; gz1->depth[node] = (uch) (GZ1_MAX(gz1->depth[n], gz1->depth[m]) + 1); tree[n].dl.dad = tree[m].dl.dad = (ush)node; gz1->heap[SMALLEST] = node++; pqdownheap(gz1, tree, SMALLEST); } while (gz1->heap_len >= 2); gz1->heap[--gz1->heap_max] = gz1->heap[SMALLEST]; gen_bitlen(gz1,(tree_desc *)desc); gen_codes(gz1,(ct_data *)tree, max_code); } int build_bl_tree( PGZ1 gz1 ) { int max_blindex; scan_tree( gz1, (ct_data *)gz1->dyn_ltree, gz1->l_desc.max_code ); scan_tree( gz1, (ct_data *)gz1->dyn_dtree, gz1->d_desc.max_code ); build_tree( gz1, (tree_desc *)(&gz1->bl_desc) ); for ( max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex-- ) { if (gz1->bl_tree[bl_order[max_blindex]].dl.len != 0) break; } gz1->opt_len += 3*(max_blindex+1) + 5+5+4; return max_blindex; } void gen_codes( PGZ1 gz1, ct_data *tree, int max_code ) { ush next_code[MAX_BITS+1]; ush code = 0; int bits; int n; for ( bits = 1; bits <= MAX_BITS; bits++ ) { next_code[bits] = code = (code + gz1->bl_count[bits-1]) << 1; } for ( n = 0; n <= max_code; n++ ) { int len = tree[n].dl.len; if (len == 0) continue; tree[n].fc.code = bi_reverse( gz1, next_code[len]++, len ); } return; } void gen_bitlen( PGZ1 gz1, tree_desc *desc ) { ct_data *tree = desc->dyn_tree; int *extra = desc->extra_bits; int base = desc->extra_base; int max_code = desc->max_code; int max_length = desc->max_length; ct_data *stree = desc->static_tree; int h; int n, m; int bits; int xbits; ush f; int overflow = 0; for (bits = 0; bits <= MAX_BITS; bits++) gz1->bl_count[bits] = 0; tree[gz1->heap[gz1->heap_max]].dl.len = 0; for (h = gz1->heap_max+1; h < HEAP_SIZE; h++) { n = gz1->heap[h]; bits = tree[tree[n].dl.dad].dl.len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].dl.len = (ush)bits; if (n > max_code) continue; gz1->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].fc.freq; gz1->opt_len += (ulg)f * (bits + xbits); if (stree) gz1->static_len += (ulg)f * (stree[n].dl.len + xbits); } if (overflow == 0) return; do { bits = max_length-1; while (gz1->bl_count[bits] == 0) bits--; gz1->bl_count[bits]--; gz1->bl_count[bits+1] += 2; gz1->bl_count[max_length]--; overflow -= 2; } while (overflow > 0); for (bits = max_length; bits != 0; bits--) { n = gz1->bl_count[bits]; while (n != 0) { m = gz1->heap[--h]; if (m > max_code) continue; if (tree[m].dl.len != (unsigned) bits) { gz1->opt_len += ((long)bits-(long)tree[m].dl.len)*(long)tree[m].fc.freq; tree[m].dl.len = (ush)bits; } n--; } } } void copy_block( PGZ1 gz1, char *buf, unsigned len, int header ) { #ifdef CRYPT int t; #endif bi_windup( gz1 ); if ( header ) { put_short((ush)len); put_short((ush)~len); } while( len-- ) { #ifdef CRYPT if (key) zencode(*buf, t); #endif put_byte(*buf++); } } int file_read( PGZ1 gz1, char *buf, unsigned size ) { unsigned len = 0; unsigned bytes_to_copy = 0; if ( gz1->input_ismem ) { if ( gz1->input_bytesleft > 0 ) { bytes_to_copy = size; if ( bytes_to_copy > (unsigned) gz1->input_bytesleft ) { bytes_to_copy = (unsigned) gz1->input_bytesleft; } memcpy( buf, gz1->input_ptr, bytes_to_copy ); gz1->input_ptr += bytes_to_copy; gz1->input_bytesleft -= bytes_to_copy; len = bytes_to_copy; } else { len = 0; } } else { len = read( gz1->ifd, buf, size ); } if ( len == (unsigned)(-1) || len == 0 ) { gz1->crc = gz1->crc ^ 0xffffffffL; /* XXX - Do we need to do something with Adler CRC's here? * I don't think so--they don't seem to need postprocessing. */ return (int)len; } if (gz1->compression_format != DEFLATE_FORMAT) { updcrc( gz1, (uch*)buf, len ); } else { gz1->adler = adler32(gz1->adler, (uch*)buf, len); } gz1->bytes_in += (ulg)len; return (int)len; } void bi_windup( PGZ1 gz1 ) { if ( gz1->bi_valid > 8 ) { put_short(gz1->bi_buf); } else if ( gz1->bi_valid > 0 ) { put_byte(gz1->bi_buf); } gz1->bi_buf = 0; gz1->bi_valid = 0; } void send_all_trees( PGZ1 gz1, int lcodes, int dcodes, int blcodes ) { int rank; send_bits(gz1,lcodes-257, 5); send_bits(gz1,dcodes-1, 5); send_bits(gz1,blcodes-4, 4); for ( rank = 0; rank < blcodes; rank++ ) { send_bits(gz1,gz1->bl_tree[bl_order[rank]].dl.len, 3 ); } send_tree(gz1,(ct_data *)gz1->dyn_ltree, lcodes-1); send_tree(gz1,(ct_data *)gz1->dyn_dtree, dcodes-1); } void send_tree( PGZ1 gz1, ct_data *tree, int max_code ) { int n; int prevlen = -1; int curlen; int nextlen = tree[0].dl.len; int count = 0; int max_count = 7; int min_count = 4; if (nextlen == 0) max_count = 138, min_count = 3; for ( n = 0; n <= max_code; n++ ) { curlen = nextlen; nextlen = tree[n+1].dl.len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(curlen, gz1->bl_tree); } while (--count != 0); } else if (curlen != 0) { if ( curlen != prevlen ) { send_code(curlen, gz1->bl_tree); count--; } send_code( REP_3_6, gz1->bl_tree ); send_bits(gz1,count-3, 2); } else if (count <= 10) { send_code(REPZ_3_10, gz1->bl_tree); send_bits(gz1,count-3, 3); } else { send_code(REPZ_11_138, gz1->bl_tree); send_bits(gz1,count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } void scan_tree( PGZ1 gz1, ct_data *tree, int max_code ) { int n; int prevlen = -1; int curlen; int nextlen = tree[0].dl.len; int count = 0; int max_count = 7; int min_count = 4; if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].dl.len = (ush)0xffff; for ( n = 0; n <= max_code; n++ ) { curlen = nextlen; nextlen = tree[n+1].dl.len; if ( ++count < max_count && curlen == nextlen ) { continue; } else if ( count < min_count ) { gz1->bl_tree[curlen].fc.freq += count; } else if ( curlen != 0 ) { if ( curlen != prevlen ) gz1->bl_tree[curlen].fc.freq++; gz1->bl_tree[REP_3_6].fc.freq++; } else if ( count <= 10 ) { gz1->bl_tree[REPZ_3_10].fc.freq++; } else { gz1->bl_tree[REPZ_11_138].fc.freq++; } count = 0; prevlen = curlen; if ( nextlen == 0 ) { max_count = 138; min_count = 3; } else if (curlen == nextlen) { max_count = 6; min_count = 3; } else { max_count = 7; min_count = 4; } } } void pqdownheap( PGZ1 gz1, ct_data *tree, int k ) { int v = gz1->heap[k]; int j = k << 1; while( j <= gz1->heap_len ) { if (j < gz1->heap_len && smaller(tree, gz1->heap[j+1], gz1->heap[j])) j++; if (smaller(tree, v, gz1->heap[j])) break; gz1->heap[k] = gz1->heap[j]; k = j; j <<= 1; } gz1->heap[k] = v; } #define GZS_ZIP1 1 #define GZS_ZIP2 2 #define GZS_DEFLATE1 3 #define GZS_DEFLATE2 4 int gzs_fsp ( PGZ1 gz1 ); int gzs_zip1 ( PGZ1 gz1 ); int gzs_zip2 ( PGZ1 gz1 ); int gzs_deflate1( PGZ1 gz1 ); int gzs_deflate2( PGZ1 gz1 ); int gzp_main( GZP_CONTROL *gzp ) { PGZ1 gz1 = 0; int rc = 0; int final_exit_code = 0; int ofile_flags = O_RDWR | O_CREAT | O_TRUNC | O_BINARY; gzp->result_code = 0; gzp->bytes_out = 0; gz1 = (PGZ1) gz1_init(); if ( gz1 == 0 ) { return 0; } gz1->decompress = gzp->decompress; gz1->compression_format = gzp->compression_format; strcpy( gz1->ifname, gzp->input_filename ); strcpy( gz1->ofname, gzp->output_filename ); gz1->input_ismem = gzp->input_ismem; gz1->input_ptr = gzp->input_ismem_ibuf; gz1->input_bytesleft = gzp->input_ismem_ibuflen; gz1->output_ismem = gzp->output_ismem; gz1->output_ptr = gzp->output_ismem_obuf; gz1->output_maxlen = gzp->output_ismem_obuflen; if ( gz1->no_time < 0 ) gz1->no_time = gz1->decompress; if ( gz1->no_name < 0 ) gz1->no_name = gz1->decompress; work = zip; if ( !gz1->input_ismem ) { errno = 0; rc = stat( gz1->ifname, &gz1->istat ); if ( rc != 0 ) { gz1_cleanup( gz1 ); return 0; } gz1->ifile_size = gz1->istat.st_size; gz1->ifd = OPEN( gz1->ifname, gz1->ascii && !gz1->decompress ? O_RDONLY : O_RDONLY | O_BINARY, RW_USER ); if ( gz1->ifd == -1 ) { gz1_cleanup( gz1 ); return 0; } } if ( !gz1->output_ismem ) { if ( gz1->ascii && gz1->decompress ) { ofile_flags &= ~O_BINARY; } gz1->ofd = OPEN( gz1->ofname, ofile_flags, RW_USER ); if ( gz1->ofd == -1 ) { if ( gz1->ifd ) { close( gz1->ifd ); gz1->ifd = 0; } gz1_cleanup( gz1 ); return 0; } } gz1->outcnt = 0; gz1->insize = 0; gz1->inptr = 0; gz1->bytes_in = 0L; gz1->bytes_out = 0L; gz1->part_nb = 0; if ( gz1->decompress ) { gz1->method = get_header( gz1, gz1->ifd ); if ( gz1->method < 0 ) { if ( gz1->ifd ) { close( gz1->ifd ); gz1->ifd = 0; } if ( gz1->ofd ) { close( gz1->ofd ); gz1->ofd = 0; } return 0; } } gz1->save_orig_name = 0; gz1->state = GZS_ZIP1; for (;;) { gzs_fsp( gz1 ); if ( gz1->done == 1 ) break; } if ( gz1->ifd ) { close( gz1->ifd ); gz1->ifd = 0; } if ( gz1->ofd ) { close( gz1->ofd ); gz1->ofd = 0; } gzp->result_code = gz1->exit_code; gzp->bytes_out = gz1->bytes_out; final_exit_code = (int) gz1->exit_code; gz1_cleanup( gz1 ); return final_exit_code; } int gzs_fsp( PGZ1 gz1 ) { int rc=0; switch( gz1->state ) { case GZS_ZIP1: rc = gzs_zip1( gz1 ); break; case GZS_ZIP2: rc = gzs_zip2( gz1 ); break; case GZS_DEFLATE1: rc = gzs_deflate1( gz1 ); break; case GZS_DEFLATE2: rc = gzs_deflate2( gz1 ); break; default: gz1->done = 1; break; } return( rc ); } int gzs_zip1( PGZ1 gz1 ) { uch flags = 0; ush attr = 0; ush deflate_flags = 0; gz1->outcnt = 0; gz1->method = DEFLATED; if (gz1->compression_format != DEFLATE_FORMAT) { put_byte(GZIP_MAGIC[0]); put_byte(GZIP_MAGIC[1]); put_byte(DEFLATED); } else { /* Yes, I know RFC 1951 doesn't mention any header at the start of * a deflated document, but zlib absolutely requires one. And since nearly * all "deflate" implementations use zlib, we need to play along with this * brain damage. */ put_byte(ZLIB_HEADER[0]); put_byte(ZLIB_HEADER[1]); } if ( gz1->save_orig_name ) { flags |= ORIG_NAME; } if (gz1->compression_format != DEFLATE_FORMAT) { put_byte(flags); put_long(gz1->time_stamp); gz1->crc = -1; updcrc( gz1, NULL, 0 ); } else { /* Deflate compression uses an Adler32 CRC, not a CRC32. */ gz1->adler = 1L; } gz1->state = GZS_ZIP2; return 0; } int gzs_zip2( PGZ1 gz1 ) { uch flags = 0; ush attr = 0; ush deflate_flags = 0; bi_init( gz1, gz1->ofd ); ct_init( gz1, &attr, &gz1->method ); lm_init( gz1, gz1->level, &deflate_flags ); if (gz1->compression_format != DEFLATE_FORMAT) { put_byte((uch)deflate_flags); put_byte(OS_CODE); if ( gz1->save_orig_name ) { char *p = gz1_basename( gz1, gz1->ifname ); do { put_char(*p); } while (*p++); } } gz1->header_bytes = (long)gz1->outcnt; gz1->state = GZS_DEFLATE1; return 0; } int gzs_deflate1( PGZ1 gz1 ) { if ( !gz1->deflate1_initialized ) { gz1->deflate1_match_available = 0; gz1->deflate1_match_length = MIN_MATCH-1; gz1->deflate1_initialized = 1; } if ( gz1->compr_level <= 3 ) { gz1->done = 1; return 0; } if ( gz1->lookahead == 0 ) { if ( gz1->deflate1_match_available ) { ct_tally( gz1, 0, gz1->window[gz1->strstart-1] ); } gz1->state = GZS_DEFLATE2; return (int) FLUSH_BLOCK(1); } #ifdef STAY_HERE_FOR_A_CERTAIN_AMOUNT_OF_ITERATIONS while( iterations < max_iterations_per_yield ) { #endif gz1->ins_h = (((gz1->ins_h)<window[gz1->strstart+MIN_MATCH-1])) & HASH_MASK; prev[ gz1->strstart & WMASK ] = gz1->deflate1_hash_head = head[ gz1->ins_h ]; head[ gz1->ins_h ] = gz1->strstart; gz1->prev_length = gz1->deflate1_match_length, gz1->deflate1_prev_match = gz1->match_start; gz1->deflate1_match_length = MIN_MATCH-1; if ( gz1->deflate1_hash_head != NIL && gz1->prev_length < gz1->max_lazy_match && gz1->strstart - gz1->deflate1_hash_head <= MAX_DIST) { gz1->deflate1_match_length = longest_match( gz1, gz1->deflate1_hash_head ); if ( gz1->deflate1_match_length > gz1->lookahead ) { gz1->deflate1_match_length = gz1->lookahead; } if (gz1->deflate1_match_length == MIN_MATCH && gz1->strstart-gz1->match_start > TOO_FAR) { gz1->deflate1_match_length--; } } if ( gz1->prev_length >= MIN_MATCH && gz1->deflate1_match_length <= gz1->prev_length ) { gz1->deflate1_flush = ct_tally(gz1,gz1->strstart-1-gz1->deflate1_prev_match, gz1->prev_length - MIN_MATCH); gz1->lookahead -= ( gz1->prev_length - 1 ); gz1->prev_length -= 2; do { gz1->strstart++; gz1->ins_h = (((gz1->ins_h)<window[ gz1->strstart + MIN_MATCH-1])) & HASH_MASK; prev[ gz1->strstart & WMASK ] = gz1->deflate1_hash_head = head[gz1->ins_h]; head[ gz1->ins_h ] = gz1->strstart; } while (--gz1->prev_length != 0); gz1->deflate1_match_available = 0; gz1->deflate1_match_length = MIN_MATCH-1; gz1->strstart++; if (gz1->deflate1_flush) FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; } else { if ( gz1->deflate1_match_available ) { if ( ct_tally( gz1, 0, gz1->window[gz1->strstart-1] ) ) { FLUSH_BLOCK(0), gz1->block_start = gz1->strstart; } gz1->strstart++; gz1->lookahead--; } else { gz1->deflate1_match_available = 1; gz1->strstart++; gz1->lookahead--; } while (gz1->lookahead < MIN_LOOKAHEAD && !gz1->eofile ) { fill_window(gz1); } } return 0; } int gzs_deflate2( PGZ1 gz1 ) { #if !defined(NO_SIZE_CHECK) && !defined(RECORD_IO) if (gz1->ifile_size != -1L && gz1->isize != (ulg)gz1->ifile_size) { } #endif if (gz1->compression_format != DEFLATE_FORMAT) { put_long( gz1->crc ); put_long( gz1->bytes_in ); gz1->header_bytes += 2*sizeof(long); } else { /* Append an Adler32 CRC to our deflated data. * Yes, I know RFC 1951 doesn't mention any CRC at the end of a * deflated document, but zlib absolutely requires one. And since nearly * all "deflate" implementations use zlib, we need to play along with this * brain damage. */ put_byte( (gz1->adler >> 24) ); put_byte( (gz1->adler >> 16) & 0xFF ); put_byte( (gz1->adler >> 8) & 0xFF ); put_byte( (gz1->adler ) & 0xFF ); gz1->header_bytes += 4*sizeof(uch); } flush_outbuf( gz1 ); gz1->done = 1; return OK; } /* ========================================================================= adler32 -- compute the Adler-32 checksum of a data stream Copyright (C) 1995-1998 Mark Adler 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. Modified by Eric Kidd to play nicely with mod_gzip. */ #define BASE 65521L /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {s1 += buf[i]; s2 += s1;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); ulg adler32(ulg adler, uch *buf, unsigned len) { unsigned long s1 = adler & 0xffff; unsigned long s2 = (adler >> 16) & 0xffff; int k; if (buf == NULL) return 1L; while (len > 0) { k = len < NMAX ? len : NMAX; len -= k; while (k >= 16) { DO16(buf); buf += 16; k -= 16; } if (k != 0) do { s1 += *buf++; s2 += s1; } while (--k); s1 %= BASE; s2 %= BASE; } return (s2 << 16) | s1; } /* END OF FILE */ xmlrpc-c-1.33.14/tools/turbocharger/mod_gzip.c.diff000066400000000000000000000246441236133176700221450ustar00rootroot00000000000000--- mod_gzip.c-old Fri Jan 26 10:50:05 2001 +++ mod_gzip.c Fri Jan 26 15:08:26 2001 @@ -575,10 +575,15 @@ * The GZP request control structure... */ +#define GZIP_FORMAT (0) +#define DEFLATE_FORMAT (1) + typedef struct _GZP_CONTROL { int decompress; /* 0=Compress 1=Decompress */ + int compression_format; /* GZIP_FORMAT or DEFLATE_FORMAT */ + /* Input control... */ int input_ismem; /* Input source is memory buffer, not file */ @@ -2209,10 +2214,11 @@ mod_gzip_printf( "%s: Checking for 'gzip' designator...\n",cn); #endif - if ( strstr( has_encoding, "gzip" ) ) + if ( strstr( has_encoding, "gzip" ) || + strstr( has_encoding, "deflate" ) ) { #ifdef MOD_GZIP_DEBUG1 - mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' designator...\n",cn); + mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' or 'deflate' designator...\n",cn); mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn); mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn); #endif @@ -2237,7 +2243,7 @@ else /* 'gzip' designator not found... */ { #ifdef MOD_GZIP_DEBUG1 - mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' designator...\n",cn); + mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' or 'deflate' designator...\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } @@ -2347,10 +2353,21 @@ if ( accept_encoding ) { /* ...and if it has the right 'gzip' indicator... */ - + /* We record the compression format in a request note, so we + * can get it again later, and so it can potentially be logged. + */ if ( strstr( accept_encoding, "gzip" ) ) { process = 1; /* ...set the 'process' flag TRUE */ + ap_table_setn( r->notes,"mod_gzip_compression_format", + ap_pstrdup(r->pool,"gzip")); + + } + else if ( strstr( accept_encoding, "deflate" ) ) + { + process = 1; /* ...set the 'process' flag TRUE */ + ap_table_setn( r->notes,"mod_gzip_compression_format", + ap_pstrdup(r->pool,"deflate")); } }/* End 'if( accept_encoding )' */ @@ -2388,7 +2405,7 @@ else /* 'gzip' designator was seen in 'Accept-Encoding:' field */ { #ifdef MOD_GZIP_DEBUG1 - mod_gzip_printf( "%s: 'gzip' capability specified by user-agent.\n",cn); + mod_gzip_printf( "%s: 'gzip' or 'deflate' capability specified by user-agent.\n",cn); mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn); #endif } @@ -4093,7 +4110,8 @@ char tmp[ MOD_GZIP_LARGE_BUFFER_SIZE + 2 ]; /* Scratch buffer */ - char actual_content_encoding_name[] = "gzip"; /* Adjustable */ + char *actual_content_encoding_name = "gzip"; /* Adjustable */ + const char *compression_format; #ifdef MOD_GZIP_DEBUG1 char cn[]="mod_gzip_encode_and_transmit()"; @@ -4470,6 +4488,18 @@ gzp->decompress = 0; /* Perform encoding */ + /* Recover the compression format we're supposed to use. */ + compression_format = ap_table_get(r->notes, "mod_gzip_compression_format"); + if (compression_format && strcmp(compression_format, "deflate") == 0) + { + actual_content_encoding_name = "deflate"; + gzp->compression_format = DEFLATE_FORMAT; + } + else + { + gzp->compression_format = GZIP_FORMAT; + } + if ( input_size <= (long) conf->maximum_inmem_size ) { /* The input source is small enough to compress directly */ @@ -4591,6 +4621,7 @@ #ifdef MOD_GZIP_DEBUG1 mod_gzip_printf( "%s: gzp->decompress = %d\n" ,cn,gzp->decompress); + mod_gzip_printf( "%s: gzp->compression_format = %d\n",cn,gzp->compression_format); mod_gzip_printf( "%s: gzp->input_ismem = %d\n", cn,gzp->input_ismem); mod_gzip_printf( "%s: gzp->output_ismem = %d\n", cn,gzp->output_ismem); mod_gzip_printf( "%s: gzp->input_filename = [%s]\n",cn,gzp->input_filename); @@ -7256,6 +7287,8 @@ }; typedef struct _GZ1 { + long compression_format; + long versionid1; int state; int done; @@ -7345,6 +7378,7 @@ int dbits; ulg window_size; ulg crc; + ulg adler; uch dist_code[512]; uch length_code[MAX_MATCH-MIN_MATCH+1]; @@ -7449,6 +7483,15 @@ void error( char *msg ); +/* XXX - Precomputed zlib header. If you change the window size or + * compression level from the defaults, this will break badly. The + * algorithm to build this is fairly complex; you can find it in + * the file deflate.c from the zlib distribution. + */ +#define ZLIB_HEADER "\170" + +ulg adler32(ulg adler, uch *buf, unsigned len); + int zip( PGZ1 gz1, int in, @@ -9088,10 +9131,20 @@ if ( len == (unsigned)(-1) || len == 0 ) { gz1->crc = gz1->crc ^ 0xffffffffL; + /* XXX - Do we need to do something with Adler CRC's here? + * I don't think so--they don't seem to need postprocessing. */ return (int)len; } - updcrc( gz1, (uch*)buf, len ); + if (gz1->compression_format != DEFLATE_FORMAT) + { + updcrc( gz1, (uch*)buf, len ); + } + else + { + gz1->adler = adler32(gz1->adler, (uch*)buf, len); + } + gz1->bytes_in += (ulg)len; return (int)len; @@ -9288,6 +9341,7 @@ gz1->heap[k] = v; } + #define GZS_ZIP1 1 #define GZS_ZIP2 2 #define GZS_DEFLATE1 3 @@ -9317,6 +9371,7 @@ } gz1->decompress = gzp->decompress; + gz1->compression_format = gzp->compression_format; strcpy( gz1->ifname, gzp->input_filename ); strcpy( gz1->ofname, gzp->output_filename ); @@ -9489,6 +9544,7 @@ return( rc ); } + int gzs_zip1( PGZ1 gz1 ) { uch flags = 0; @@ -9499,21 +9555,40 @@ gz1->method = DEFLATED; - put_byte(GZIP_MAGIC[0]); - put_byte(GZIP_MAGIC[1]); - put_byte(DEFLATED); + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_byte(GZIP_MAGIC[0]); + put_byte(GZIP_MAGIC[1]); + put_byte(DEFLATED); + } + else + { + /* Yes, I know RFC 1951 doesn't mention any header at the start of + * a deflated document, but zlib absolutely requires one. And since nearly + * all "deflate" implementations use zlib, we need to play along with this + * brain damage. */ + put_byte(ZLIB_HEADER[0]); + put_byte(ZLIB_HEADER[1]); + } if ( gz1->save_orig_name ) { flags |= ORIG_NAME; } - put_byte(flags); - put_long(gz1->time_stamp); - - gz1->crc = -1; + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_byte(flags); + put_long(gz1->time_stamp); - updcrc( gz1, NULL, 0 ); + gz1->crc = -1; + updcrc( gz1, NULL, 0 ); + } + else + { + /* Deflate compression uses an Adler32 CRC, not a CRC32. */ + gz1->adler = 1L; + } gz1->state = GZS_ZIP2; @@ -9529,18 +9604,20 @@ bi_init( gz1, gz1->ofd ); ct_init( gz1, &attr, &gz1->method ); lm_init( gz1, gz1->level, &deflate_flags ); - put_byte((uch)deflate_flags); - - put_byte(OS_CODE); - if ( gz1->save_orig_name ) + if (gz1->compression_format != DEFLATE_FORMAT) { - char *p = gz1_basename( gz1, gz1->ifname ); + put_byte((uch)deflate_flags); + put_byte(OS_CODE); + if ( gz1->save_orig_name ) + { + char *p = gz1_basename( gz1, gz1->ifname ); - do { - put_char(*p); + do { + put_char(*p); - } while (*p++); + } while (*p++); + } } gz1->header_bytes = (long)gz1->outcnt; @@ -9674,10 +9751,25 @@ } #endif - put_long( gz1->crc ); - put_long( gz1->bytes_in ); - - gz1->header_bytes += 2*sizeof(long); + if (gz1->compression_format != DEFLATE_FORMAT) + { + put_long( gz1->crc ); + put_long( gz1->bytes_in ); + gz1->header_bytes += 2*sizeof(long); + } + else + { + /* Append an Adler32 CRC to our deflated data. + * Yes, I know RFC 1951 doesn't mention any CRC at the end of a + * deflated document, but zlib absolutely requires one. And since nearly + * all "deflate" implementations use zlib, we need to play along with this + * brain damage. */ + put_byte( (gz1->adler >> 24) ); + put_byte( (gz1->adler >> 16) & 0xFF ); + put_byte( (gz1->adler >> 8) & 0xFF ); + put_byte( (gz1->adler ) & 0xFF ); + gz1->header_bytes += 4*sizeof(uch); + } flush_outbuf( gz1 ); @@ -9685,6 +9777,67 @@ return OK; } + + +/* ========================================================================= + adler32 -- compute the Adler-32 checksum of a data stream + Copyright (C) 1995-1998 Mark Adler + + 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. + + Modified by Eric Kidd to play nicely with mod_gzip. + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +ulg adler32(ulg adler, uch *buf, unsigned len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + /* END OF FILE */ xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/000077500000000000000000000000001236133176700174775ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/DataType.cpp000066400000000000000000000141311236133176700217160ustar00rootroot00000000000000#include #include #include #include #include #include "xmlrpc-c/oldcppwrapper.hpp" #include "DataType.hpp" using namespace std; //========================================================================= // abstract class DataType //========================================================================= // Instances of DataType know how generate code fragments for manipulating // a specific XML-RPC data type. string DataType::defaultParameterBaseName(unsigned int const position) const { ostringstream nameStream; nameStream << typeName() << position; return nameStream.str(); } class RawDataType : public DataType { public: RawDataType(string const& typeName) : DataType(typeName) {} virtual string parameterFragment(string const& baseName) const; virtual string inputConversionFragment(string const& baseName) const; virtual string returnTypeFragment() const; virtual string outputConversionFragment(string const& varName) const; }; string RawDataType::parameterFragment(string const& baseName) const { return "XmlRpcValue /*" + typeName() + "*/ " + baseName; } string RawDataType::inputConversionFragment(string const& baseName) const { return baseName; } string RawDataType::returnTypeFragment() const { return "XmlRpcValue /*" + typeName() + "*/"; } string RawDataType::outputConversionFragment(string const& varName) const { return varName; } class SimpleDataType : public DataType { string mNativeType; string mMakerFunc; string mGetterFunc; public: SimpleDataType(string const& typeName, string const& nativeType, string const& makerFunc, string const& getterFunc); virtual string parameterFragment(string const& baseName) const; virtual string inputConversionFragment(string const& baseName) const; virtual string returnTypeFragment() const; virtual string outputConversionFragment(string const& varName) const; }; SimpleDataType::SimpleDataType(string const& typeName, string const& nativeType, string const& makerFunc, string const& getterFunc) : DataType(typeName), mNativeType(nativeType), mMakerFunc(makerFunc), mGetterFunc(getterFunc) { } string SimpleDataType::parameterFragment(string const& baseName) const { return mNativeType + " const " + baseName; } string SimpleDataType::inputConversionFragment(string const& baseName) const { return mMakerFunc + "(" + baseName + ")"; } string SimpleDataType::returnTypeFragment() const { return mNativeType; } string SimpleDataType::outputConversionFragment(string const& varName) const { return varName + "." + mGetterFunc + "()"; } class VoidDataType : public DataType { public: VoidDataType() : DataType("void") {} virtual string parameterFragment(string const& baseName) const; virtual string inputConversionFragment(string const& baseName) const; virtual string returnTypeFragment() const; virtual string outputConversionFragment(string const& varName) const; }; string VoidDataType::parameterFragment(string const&) const { throw domain_error("Can't handle functions with 'void' arguments'"); } string VoidDataType::inputConversionFragment(string const&) const { throw domain_error("Can't handle functions with 'void' arguments'"); } string VoidDataType::returnTypeFragment () const { return "void"; } string VoidDataType::outputConversionFragment(string const&) const { return "/* Return value ignored. */"; } static SimpleDataType const intType ("int", "XmlRpcValue::int32", "XmlRpcValue::makeInt", "getInt"); static SimpleDataType const boolType ("bool", "bool", "XmlRpcValue::makeBool", "getBool"); static SimpleDataType const doubleType ("double", "double", "XmlRpcValue::makeDouble", "getDouble"); static SimpleDataType const stringType ("string", "std::string", "XmlRpcValue::makeString", "getString"); static RawDataType const dateTimeType ("dateTime"); static RawDataType const base64Type ("base64"); static RawDataType const structType ("struct"); static RawDataType const arrayType ("array"); static VoidDataType const voidType; const DataType& findDataType(string const& name) { /*---------------------------------------------------------------------------- Given the name of an XML-RPC data type, try to find a corresponding DataType object. -----------------------------------------------------------------------------*/ if (name == "int" || name == "i4") return intType; else if (name == "boolean") return boolType; else if (name == "double") return doubleType; else if (name == "string") return stringType; else if (name == "dateTime.iso8601") return dateTimeType; else if (name == "base64") return base64Type; else if (name == "struct") return structType; else if (name == "array") return arrayType; else if (name == "void") return voidType; else if (name == "INT") return intType; else if (name == "BOOLEAN") return boolType; else if (name == "DOUBLE") return doubleType; else if (name == "STRING") return stringType; else if (name == "DATETIME.ISO8601") return dateTimeType; else if (name == "BASE64") return base64Type; else if (name == "STRUCT") return structType; else if (name == "ARRAY") return arrayType; else if (name == "VOID") return voidType; else if (name == "NIL") return voidType; else throw domain_error("Unknown XML-RPC type name '" + name + "'"); } xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/DataType.hpp000066400000000000000000000022031236133176700217200ustar00rootroot00000000000000#include #include class DataType { std::string mTypeName; DataType(DataType const&) { assert(false); } DataType& operator= (DataType const&) { assert(false); return *this; } public: DataType(const std::string& type_name) : mTypeName(type_name) {} virtual ~DataType () {} // Return the name for this XML-RPC type. virtual std::string typeName() const { return mTypeName; } // Given a parameter position, calculate a unique base name for all // parameter-related variables. virtual std::string defaultParameterBaseName(unsigned int const position) const; // Virtual functions for processing parameters. virtual std::string parameterFragment(std::string const& base_name) const = 0; virtual std::string inputConversionFragment(std::string const& base_name) const = 0; // Virtual functions for processing return values. virtual std::string returnTypeFragment () const = 0; virtual std::string outputConversionFragment(std::string const& var_name) const = 0; }; const DataType& findDataType(const std::string& name); xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/Makefile000066400000000000000000000026261236133176700211450ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') TOOLSDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(TOOLSDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools/xml-rpc-api2cpp default: all include $(BLDDIR)/config.mk PROGS := xml-rpc-api2cpp PROGRAMS_TO_INSTALL := $(PROGS) MAN_FILES_TO_INSTALL := xml-rpc-api2cpp.1 all: $(PROGS) include $(SRCDIR)/tools/common.mk # in Glibc 2.2 has a bug that results in inlining failure, # so we disable warnings for that: CFLAGS_LOCAL = -Wno-inline INCLUDES = -I$(BLDDIR) -I$(BLDDIR)/include -Isrcdir/include ifeq ($(MSVCRT),yes) CLIENT_LDLIBS += -lws2_32 -lwsock32 -lpthread endif LDLIBS = -L$(BLDDIR)/src/cpp -lxmlrpc_cpp -L$(BLDDIR)/src -lxmlrpc_server \ $(CLIENT_LDLIBS) OBJECTS = \ xml-rpc-api2cpp.o \ DataType.o \ XmlRpcFunction.o \ XmlRpcClass.o \ SystemProxy.o \ xml-rpc-api2cpp: \ $(OBJECTS) \ $(LIBXMLRPC_CPP) \ $(CLIENT_LIBS_DEP) \ $(LIBXMLRPC_SERVER) \ $(LIBXMLRPC) \ $(LIBXMLRPC_XML) \ $(LIBXMLRPC_UTIL) $(CXXLD) -o $@ $(LDFLAGS_ALL) $(OBJECTS) $(LDLIBS) %.o:%.cpp $(CXX) -c $(CXXFLAGS_ALL) $< # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/tools/common.mk: srcdir blddir include depend.mk .PHONY: clean clean: clean-common rm -f $(PROGS) .PHONY: distclean distclean: clean distclean-common .PHONY: dep dep: dep-common xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/SystemProxy.cpp000066400000000000000000000025631236133176700225370ustar00rootroot00000000000000// SystemProxy.cc - xmlrpc-c C++ proxy class // Auto-generated by xml-rpc-api2cpp. // But for now, this file is maintained manually. When someone figures // out how stuff in this directory works, maybe we'll make it an automatically // generated file. -Bryan 2005.06.05. #include #include "xmlrpc-c/oldcppwrapper.hpp" #include "SystemProxy.hpp" using namespace std; XmlRpcValue /*array*/ SystemProxy::listMethods () { XmlRpcValue params = XmlRpcValue::makeArray(); XmlRpcValue result = this->mClient.call("system.listMethods", params); return result; } XmlRpcValue /*array*/ SystemProxy::methodSignature (string string1) { XmlRpcValue params = XmlRpcValue::makeArray(); params.arrayAppendItem(XmlRpcValue::makeString(string1)); XmlRpcValue result = this->mClient.call("system.methodSignature", params); return result; } string SystemProxy::methodHelp (string string1) { XmlRpcValue params = XmlRpcValue::makeArray(); params.arrayAppendItem(XmlRpcValue::makeString(string1)); XmlRpcValue result = this->mClient.call("system.methodHelp", params); return result.getString(); } XmlRpcValue /*array*/ SystemProxy::multicall (XmlRpcValue /*array*/ array1) { XmlRpcValue params = XmlRpcValue::makeArray(); params.arrayAppendItem(array1); XmlRpcValue result = this->mClient.call("system.multicall", params); return result; } xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/SystemProxy.hpp000066400000000000000000000031601236133176700225360ustar00rootroot00000000000000// SystemProxy.h - xmlrpc-c C++ proxy class // Auto-generated by xml-rpc-api2cpp. #ifndef _SystemProxy_H_ #define _SystemProxy_H_ 1 #include #include "xmlrpc-c/oldcppwrapper.hpp" class SystemProxy { XmlRpcClient mClient; public: SystemProxy (const XmlRpcClient& client) : mClient(client) {} SystemProxy (const std::string& server_url) : mClient(XmlRpcClient(server_url)) {} SystemProxy (const SystemProxy& o) : mClient(o.mClient) {} SystemProxy& operator= (const SystemProxy& o) { if (this != &o) mClient = o.mClient; return *this; } /* Return an array of all available XML-RPC methods on this server. */ XmlRpcValue /*array*/ listMethods (); /* Given the name of a method, return an array of legal signatures. Each signature is an array of strings. The first item of each signature is the return type, and any others items are parameter types. */ XmlRpcValue /*array*/ methodSignature (std::string string1); /* Given the name of a method, return a help string. */ std::string methodHelp (std::string string1); /* Process an array of calls, and return an array of results. Calls should be structs of the form {'methodName': string, 'params': array}. Each result will either be a single-item array containg the result value, or a struct of the form {'faultCode': int, 'faultString': string}. This is useful when you need to make lots of small calls without lots of round trips. */ XmlRpcValue /*array*/ multicall (XmlRpcValue /*array*/ array1); }; #endif /* _SystemProxy_H_ */ xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/XmlRpcClass.cpp000066400000000000000000000036741236133176700224100ustar00rootroot00000000000000#include #include #include using namespace std; #include "xmlrpc-c/oldcppwrapper.hpp" #include "DataType.hpp" #include "XmlRpcFunction.hpp" #include "XmlRpcClass.hpp" XmlRpcClass::XmlRpcClass(string const& className) : mClassName(className) {} XmlRpcClass::XmlRpcClass(XmlRpcClass const& c) : mClassName(c.mClassName), mFunctions(c.mFunctions) {} XmlRpcClass& XmlRpcClass::operator= (XmlRpcClass const& c) { if (this != &c) { this->mClassName = c.mClassName; this->mFunctions = c.mFunctions; } return *this; } void XmlRpcClass::addFunction(XmlRpcFunction const& function) { mFunctions.push_back(function); } void XmlRpcClass::printDeclaration(ostream & out) const { out << "class " << mClassName << " {" << endl; out << " XmlRpcClient mClient;" << endl; out << endl; out << "public:" << endl; out << " " << mClassName << " (const XmlRpcClient& client)" << endl; out << " : mClient(client) {}" << endl; out << " " << mClassName << " (const std::string& server_url)" << endl; out << " : mClient(XmlRpcClient(server_url)) {}" << endl; out << " " << mClassName << " (const " << mClassName << "& o)" << endl; out << " : mClient(o.mClient) {}" << endl; out << endl; out << " " << mClassName << "& operator= (const " << mClassName << "& o) {" << endl; out << " if (this != &o) mClient = o.mClient;" << endl; out << " return *this;" << endl; out << " }" << endl; vector::const_iterator f; for (f = mFunctions.begin(); f < mFunctions.end(); ++f) { f->printDeclarations(out); } out << "};" << endl; } void XmlRpcClass::printDefinition(ostream & out) const { vector::const_iterator f; for (f = mFunctions.begin(); f < mFunctions.end(); ++f) { f->printDefinitions(out, mClassName); } } xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/XmlRpcClass.hpp000066400000000000000000000011101236133176700223740ustar00rootroot00000000000000#include class XmlRpcClass { // An object of this class contains information about a proxy // class, and knows how to generate code. std::string mClassName; std::vector mFunctions; public: XmlRpcClass (std::string const& className); XmlRpcClass(XmlRpcClass const&); XmlRpcClass& operator= (XmlRpcClass const&); std::string className () const { return mClassName; } void addFunction (const XmlRpcFunction& function); void printDeclaration (ostream& out) const; void printDefinition (ostream& out) const; }; xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/XmlRpcFunction.cpp000066400000000000000000000134421236133176700231220ustar00rootroot00000000000000#include #include #include #include "xmlrpc-c/oldcppwrapper.hpp" #include "DataType.hpp" #include "XmlRpcFunction.hpp" using namespace std; XmlRpcFunction::XmlRpcFunction(string const& functionName, string const& methodName, string const& help, XmlRpcValue const signatureList) : mFunctionName(functionName), mMethodName(methodName), mHelp(help), mSynopsis(signatureList) {} XmlRpcFunction::XmlRpcFunction(XmlRpcFunction const& f) : mFunctionName(f.mFunctionName), mMethodName(f.mMethodName), mHelp(f.mHelp), mSynopsis(f.mSynopsis) {} XmlRpcFunction& XmlRpcFunction::operator= (XmlRpcFunction const& f) { if (this != &f) { this->mFunctionName = f.mFunctionName; this->mMethodName = f.mMethodName; this->mHelp = f.mHelp; this->mSynopsis = f.mSynopsis; } return *this; } void XmlRpcFunction::printDeclarations(ostream & out) const { try { // Print the method help as a comment out << endl << " /* " << mHelp << " */" << endl; size_t end; try { end = mSynopsis.arraySize(); } catch (XmlRpcFault const& fault) { throw(logic_error("Failed to get size of signature array for " "method " + this->mFunctionName + ". " + fault.getFaultString())); } // Print the declarations for all the signatures of this // XML-RPC method. for (size_t i = 0; i < end; ++i) printDeclaration(out, i); } catch (exception const& e) { throw(logic_error("Failed to generate declarations for method " + this->mFunctionName + ". " + e.what())); } } void XmlRpcFunction::printDefinitions(ostream & out, string const& className) const { try { size_t const end(mSynopsis.arraySize()); for (size_t i = 0; i < end; ++i) { out << endl; printDefinition(out, className, i); } } catch (XmlRpcFault const& fault) { throw(logic_error("Failed to generate definitions for class " + this->mFunctionName + ". " + fault.getFaultString())); } } void XmlRpcFunction::printParameters(ostream & out, size_t const synopsisIndex) const { /*---------------------------------------------------------------------------- Print the parameter declarations. -----------------------------------------------------------------------------*/ size_t const end(parameterCount(synopsisIndex)); bool first; first = true; for (size_t i = 0; i < end; ++i) { if (!first) out << ", "; DataType const& ptype(parameterType(synopsisIndex, i)); string const basename(ptype.defaultParameterBaseName(i + 1)); out << ptype.parameterFragment(basename); first = false; } } void XmlRpcFunction::printDeclaration(ostream & out, size_t const synopsisIndex) const { try { DataType const& rtype(returnType(synopsisIndex)); out << " " << rtype.returnTypeFragment() << " " << mFunctionName << " ("; printParameters(out, synopsisIndex); out << ");" << endl; } catch (XmlRpcFault const& fault) { ostringstream msg; msg << "Failed to generate header for signature " << synopsisIndex << " . " << fault.getFaultString(); throw(logic_error(msg.str())); } } void XmlRpcFunction::printDefinition(ostream & out, string const& className, size_t const synopsisIndex) const { DataType const& rtype(returnType(synopsisIndex)); out << rtype.returnTypeFragment() << " " << className << "::" << mFunctionName << " ("; printParameters(out, synopsisIndex); out << ") {" << endl; out << " XmlRpcValue params(XmlRpcValue::makeArray());" << endl; /* Emit code to convert the parameters into an array of XML-RPC objects. */ size_t const end(parameterCount(synopsisIndex)); for (size_t i = 0; i < end; ++i) { DataType const& ptype(parameterType(synopsisIndex, i)); string const basename(ptype.defaultParameterBaseName(i + 1)); out << " params.arrayAppendItem(" << ptype.inputConversionFragment(basename) << ");" << endl; } /* Emit the function call.*/ out << " XmlRpcValue result(this->mClient.call(\"" << mMethodName << "\", params));" << endl; /* Emit the return statement. */ out << " return " << rtype.outputConversionFragment("result") << ";" << endl; out << "}" << endl; } const DataType& XmlRpcFunction::returnType(size_t const synopsisIndex) const { XmlRpcValue const funcSynop(mSynopsis.arrayGetItem(synopsisIndex)); return findDataType(funcSynop.arrayGetItem(0).getString()); } size_t XmlRpcFunction::parameterCount(size_t const synopsisIndex) const { XmlRpcValue const funcSynop(mSynopsis.arrayGetItem(synopsisIndex)); size_t const size(funcSynop.arraySize()); if (size < 1) throw domain_error("Synopsis contained no items"); return size - 1; } DataType const& XmlRpcFunction::parameterType(size_t const synopsisIndex, size_t const parameterIndex) const { XmlRpcValue const funcSynop(mSynopsis.arrayGetItem(synopsisIndex)); XmlRpcValue const param(funcSynop.arrayGetItem(parameterIndex + 1)); return findDataType(param.getString()); } xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/XmlRpcFunction.hpp000066400000000000000000000024171236133176700231270ustar00rootroot00000000000000#include #include using std::string; using std::ostream; class XmlRpcFunction { // An object of this class contains everything we know about a // given XML-RPC method, and knows how to print local bindings. string mFunctionName; string mMethodName; string mHelp; XmlRpcValue mSynopsis; public: XmlRpcFunction(const string& function_name, const string& method_name, const string& help, XmlRpcValue synopsis); XmlRpcFunction (const XmlRpcFunction&); XmlRpcFunction& operator= (const XmlRpcFunction&); void printDeclarations (ostream& out) const; void printDefinitions (ostream& out, const string& className) const; private: void printParameters (ostream& out, size_t synopsis_index) const; void printDeclaration (ostream& out, size_t synopsis_index) const; void printDefinition (ostream& out, const string& className, size_t synopsis_index) const; const DataType& returnType (size_t synopsis_index) const; size_t parameterCount (size_t synopsis_index) const; const DataType& parameterType (size_t synopsis_index, size_t parameter_index) const; }; xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/xml-rpc-api2cpp.1000066400000000000000000000044641236133176700225070ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH XML-RPC-API2CPP 1 "June 27, 2001" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME xml-rpc-api2cpp \- Make a C++ wrapper class for an XML-RPC API .SH SYNOPSIS .B xml-rpc-api2cpp \fIserver-url\fR \fIremote-method-prefix\fR \fIc++-class-name\fR .SH DESCRIPTION xml-rpc-api2cpp queries an XML-RPC server using the XML-RPC Instrospection API designed by Edd Dumbill. It then prints a C++ wrapper class to standard output. This class can be used with xmlrpc-c's C++ API. .PP You can find a list of supported XML-RPC server libraries (and patches for many others) at \fBhttp://xmlrpc-c.sourceforge.net/hacks.php\fR. .SH OPTIONS .TP .I server-url The name of the server to query. Try \fBhttp://xmlrpc-c.sourceforge.net/cgi-bin/interop.cgi\fR. .TP .I remote-method-prefix The prefix of the methods to wrap. For example, to wrap all the system.* calls, you could specify "system". .TP .I c++-class-name The name of the C++ class to generate. Try "SystemProxy". .SH BUGS xml-rpc-api2cpp can't talk to certain PHP servers based on Edd Dumbill's PHP library, because the trailing bytes of the XML-RPC message get truncated in HTTP pipelining mode. It's not clear whether this is a PHP, Apache or w3c-libwww bug. .PP xml-rpc-api2cpp assumes that method descriptions are ASCII text, not HTML as specified in the standard. (In practice, both conventions are often seen.) It may also get unhappy if method descriptions contain "*/". .PP In general, error messages and diagnostics are still fairly poor. .SH SEE ALSO .BR xmlrpc-c (7), .BR xml-rpc-api2txt (1). .PP This program is part of xmlrpc-c. .SH AUTHOR This manual page was written by Eric Kidd . It may be distributed under the same terms as the rest of xmlrpc-c. xmlrpc-c-1.33.14/tools/xml-rpc-api2cpp/xml-rpc-api2cpp.cpp000066400000000000000000000145231236133176700231260ustar00rootroot00000000000000#include #include #include "xmlrpc-c/oldcppwrapper.hpp" #include "DataType.hpp" #include "XmlRpcFunction.hpp" #include "XmlRpcClass.hpp" #include "SystemProxy.hpp" using namespace std; #define NAME "xml-rpc-api2cpp" #define VERSION "0.1" /*---------------------------------------------------------------------------- Command line -----------------------------------------------------------------------------*/ class cmdlineInfo { public: string serverUrl; string methodPrefix; string localClass; cmdlineInfo(int const argc, const char ** const argv); private: cmdlineInfo(); }; cmdlineInfo::cmdlineInfo(int const argc, const char ** const argv) { if (argc-1 != 3) { cerr << argv[0] << ": Usage:" << endl << " xml-rpc-api2cpp " << endl << endl << "Sample arguments:" << endl << " server_url = http://localhost/RPC2" << endl << " method_prefix = system" << endl << " local_class = SystemProxy" << endl; exit(1); } this->serverUrl = string(argv[1]); this->methodPrefix = string(argv[2]); this->localClass = string(argv[3]); } static XmlRpcClass getClassInfo(string const& serverUrl, string const& classPrefix, string const& className) { /*---------------------------------------------------------------------------- Connect to a remote server and extract the information we'll need to build a proxy class. -----------------------------------------------------------------------------*/ XmlRpcClass info(className); SystemProxy system(serverUrl); XmlRpcValue const methods(system.listMethods()); size_t const end = methods.arraySize(); for (size_t i = 0; i < end; ++i) { // Break the method name into two pieces. string const methodName(methods.arrayGetItem(i).getString()); size_t const lastDot(methodName.rfind('.')); string methodPrefix; string functionName; if (lastDot == string::npos) { methodPrefix = ""; functionName = methodName; } else { methodPrefix = string(methodName, 0, lastDot); functionName = string(methodName, lastDot + 1); } if (methodPrefix == classPrefix) { // It's a method User cares about string const help(system.methodHelp(methodName)); XmlRpcValue const signatureList( system.methodSignature(methodName)); if (signatureList.getType() != XMLRPC_TYPE_ARRAY) { // It must be the string "undef", meaning the server // won't tell us any signatures. cerr << "Skipping method " << methodName << " " << "because server does not report any signatures " << "for it (via system.methodSignature method)" << endl; } else { // Add this function to our class information. XmlRpcFunction const method(functionName, methodName, help, signatureList); info.addFunction(method); } } } return info; } static void printHeader(ostream & out, XmlRpcClass const& classInfo) { /*---------------------------------------------------------------------------- Print a complete header for the specified class. -----------------------------------------------------------------------------*/ string const className(classInfo.className()); try { out << "// " << className << ".h - xmlrpc-c C++ proxy class" << endl; out << "// Auto-generated by xml-rpc-api2cpp." << endl; out << endl; string const headerSymbol("_" + className + "_H_"); out << "#ifndef " << headerSymbol << endl; out << "#define " << headerSymbol << " 1" << endl; out << endl; out << "#include " << endl; out << endl; classInfo.printDeclaration(cout); out << endl; out << "#endif /* " << headerSymbol << " */" << endl; } catch (exception const& e) { throw(logic_error("Failed to generate header for class " + className + ". " + e.what())); } } static void printCppFile(ostream & out, XmlRpcClass const& classInfo) { /*---------------------------------------------------------------------------- Print a complete definition for the specified class. -----------------------------------------------------------------------------*/ string const className(classInfo.className()); try { out << "// " << className << ".cc - xmlrpc-c C++ proxy class" << endl; out << "// Auto-generated by xml-rpc-api2cpp." << endl; out << endl; out << "#include " << endl; out << "#include \"" << className << ".h\"" << endl; classInfo.printDefinition(cout); } catch (XmlRpcFault const& fault) { throw(logic_error("Failed to generate definition for class " + className + ". " + fault.getFaultString())); } } int main(int const argc, const char ** const argv) { string const progName(argv[0]); cmdlineInfo const cmdline(argc, argv); int retval; XmlRpcClient::Initialize(NAME, VERSION); try { XmlRpcClass system = getClassInfo(cmdline.serverUrl, cmdline.methodPrefix, cmdline.localClass); printHeader(cout, system); cout << endl; printCppFile(cout, system); retval = 0; } catch (XmlRpcFault& fault) { cerr << progName << ": XML-RPC fault #" << fault.getFaultCode() << ": " << fault.getFaultString() << endl; retval = 1; } catch (logic_error& err) { cerr << progName << ": " << err.what() << endl; retval = 1; } catch (...) { cerr << progName << ": Unknown exception" << endl; retval = 1; } XmlRpcClient::Terminate(); return retval; } xmlrpc-c-1.33.14/tools/xml-rpc-api2txt/000077500000000000000000000000001236133176700175345ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/xml-rpc-api2txt/Makefile000066400000000000000000000012651236133176700212000ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') TOOLSDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(TOOLSDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools/xml-rpc-api2txt default: all include $(BLDDIR)/config.mk PROGS := PROGRAMS_TO_INSTALL := xml-rpc-api2txt MAN_FILES_TO_INSTALL := xml-rpc-api2txt.1 all: $(PROGS) include $(SRCDIR)/tools/common.mk # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/tools/common.mk: srcdir blddir include depend.mk .PHONY: clean clean: clean-common rm -f $(PROGS) .PHONY: distclean distclean: clean distclean-common .PHONY: dep dep: dep-common xmlrpc-c-1.33.14/tools/xml-rpc-api2txt/xml-rpc-api2txt000066400000000000000000000103321236133176700224310ustar00rootroot00000000000000#!/usr/bin/perl -w # # A handy little program to get the documentation of the available # methods from an XML-RPC service (via XML-RPC Introspection) and # print it out nicely formatted. # # (I wrote this in Perl because of all the spiffy report-generation # features.) # # You'll need to get Ken MacLeod's Frontier::RPC2 module from CPAN to use # this. # # Eric Kidd # # This script is part of xmlrpc-c, and may be used and distributed under # the same terms as the rest of the package. use strict; # One global variable for use with Perl's format routines, and one for # use inside an 'exec' block. use vars qw/$helptext $method_list/; # Try to load our Perl XML-RPC bindings, but fail gracefully. eval { require Frontier::Client; }; if ($@) { print STDERR <<"EOD"; This script requires Ken MacLeod\'s Frontier::RPC2 module. You can get this from CPAN or from his website at http://bitsko.slc.ut.us/~ken/xml-rpc/ . For installation instructions, see the XML-RPC HOWTO at: http://www.linuxdoc.org/HOWTO/XML-RPC-HOWTO/index.html EOD exit 1; } # Parse our command-line arguments. if (@ARGV != 1 || $ARGV[0] eq "--help") { print STDERR "Usage: xml-rpc-api2txt serverURL\n"; exit 1; } my $server = Frontier::Client->new(url => $ARGV[0]); # Try (very carefully) to get our a list of methods from the server. local $method_list; eval { $method_list = $server->call('system.listMethods'); }; if ($@) { print STDERR <<"EOD"; An error occurred while trying to talk to the XML-RPC server: $@ This may have been caused by several things--the server might not support introspection, it might not be an XML-RPC server, or your network might be down. Try the following: xml-rpc-api2txt http://xmlrpc-c.sourceforge.net/api/sample.php EOD exit 1; } # Enter the methods into a hashtable. my @methods = sort @$method_list; my %method_table; foreach my $method (@methods) { $method_table{$method} = {}; } # Get more information for the hash table. Since we need to make lots and # lots of very small XML-RPC calls, we'd like to use system.multicall to # reduce the latency. if (defined $method_table{'system.multicall'}) { # This is messy but fast. Everybody hates HTTP round-trip lag, right? my @call; foreach my $method (@methods) { push @call, {methodName => 'system.methodSignature', params => [$method]}; push @call, {methodName => 'system.methodHelp', params => [$method]}; } my @result = @{$server->call('system.multicall', \@call)}; for (my $i = 0; $i < @methods; $i++) { my $method = $methods[$i]; $method_table{$method}->{'signatures'} = $result[2*$i]->[0]; $method_table{$method}->{'help'} = $result[2*$i+1]->[0]; } } else { # This is easy but slow (especially over backbone links). foreach my $method (@methods) { my $signature = $server->call('system.methodSignature', $method); my $help = $server->call('system.methodHelp', $method); $method_table{$method}->{'signatures'} = $signature; $method_table{$method}->{'help'} = $help; } } # Now, we need to dump the API. print <<"EOD"; XML-RPC API for $ARGV[0] See http://www.linuxdoc.org/HOWTO/XML-RPC-HOWTO/index.html for instructions on using XML-RPC with Perl, Python, Java, C, C++, PHP, etc. EOD foreach my $method (@methods) { print "\n"; # Print a synopsis of the function. if ($method_table{$method}->{'signatures'} eq 'undef') { # No documentation. Bad server. No biscuit. print "unknown $method (...)\n"; } else { for my $signature (@{$method_table{$method}->{'signatures'}}) { my $return_type = shift @$signature; my $arguments = join(", ", @$signature); print "$return_type $method ($arguments)\n"; } } print "\n"; my $help = $method_table{$method}->{'help'}; if ($help =~ /\n/) { # Text has already been broken into lines by the server, so just # indent it by two spaces and hope for the best. my @lines = split(/\n/, $help); my $help = " " . join("\n ", @lines); print "$help\n"; } else { # Print our help text in a nicely-wrapped fashion using Perl's # formatting routines. $helptext = $method_table{$method}->{'help'}; write; } } format STDOUT = ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~ $helptext . xmlrpc-c-1.33.14/tools/xml-rpc-api2txt/xml-rpc-api2txt.1000066400000000000000000000032731236133176700225760ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH XML-RPC-API2TXT 1 "June 27, 2001" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME xml-rpc-api2txt \- Print out a description of an XML-RPC API as text .SH SYNOPSIS .B xml-rpc-api2txt \fIserver-url\fR .SH DESCRIPTION xml-rpc-api2txt queries an XML-RPC server using the XML-RPC Instrospection API designed by Edd Dumbill. It then prints the results to standard output in a nicely formatted form, suitable for sending via e-mail. .PP You can find a list of supported XML-RPC server libraries (and patches for many others) at \fBhttp://xmlrpc-c.sourceforge.net/hacks.php\fR. .SH OPTIONS .TP .I server-url The name of the server to query. Try \fBhttp://xmlrpc-c.sourceforge.net/cgi-bin/interop.cgi\fR. .SH BUGS xml-rpc-api2txt assumes that method descriptions are ASCII text, not HTML as specified in the standard. (In practice, both conventions are often seen.) .SH SEE ALSO .BR xmlrpc-c (7), .BR xml-rpc-api2cpp (1). .PP This program is part of xmlrpc-c. .SH AUTHOR This manual page was written by Eric Kidd . It may be distributed under the same terms as the rest of xmlrpc-c. xmlrpc-c-1.33.14/tools/xml/000077500000000000000000000000001236133176700153615ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/xml/Makefile000066400000000000000000000022371236133176700170250ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') TOOLSDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(TOOLSDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools/xml default: all include $(BLDDIR)/config.mk PROGS := xmlrpc_parsecall PROGRAMS_TO_INSTALL = $(PROGS) include $(SRCDIR)/tools/common.mk INCLUDES = \ -I../lib/include \ -Iblddir \ -Iblddir/include \ -Isrcdir/include \ -Isrcdir/lib/util/include all: $(PROGS) UTIL_OBJS = \ casprintf.o \ UTILS = $(UTIL_OBJS:%=$(UTIL_DIR)/%) DUMPVALUE = blddir/tools/lib/dumpvalue.o # Can we just use $(LIBS) in the link? LIBS = $(LIBXMLRPC) $(LIBXMLRPC_XML) $(LIBXMLRPC_UTIL) PARSECALL_OBJS = xmlrpc_parsecall.o $(DUMPVALUE) xmlrpc_parsecall: $(PARSECALL_OBJS) $(LIBS) $(UTILS) $(CCLD) -o $@ $(LDFLAGS_ALL) $^ %.o:%.c $(BLDDIR)/include/xmlrpc-c/config.h $(CC) -c $(CFLAGS_ALL) $< # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/tools/common.mk: srcdir blddir include depend.mk .PHONY: dep dep: dep-common .PHONY: clean clean: clean-common rm -f $(PROGS) .PHONY: distclean distclean: clean distclean-common xmlrpc-c-1.33.14/tools/xml/xmlrpc_parsecall.c000066400000000000000000000042271236133176700210650ustar00rootroot00000000000000#include #include #include #include #include #include "casprintf.h" #include "dumpvalue.h" static void die_if_fault_occurred (xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "Error: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } static void readFile(xmlrpc_env * const envP, FILE * const ifP, xmlrpc_mem_block ** const fileContentsPP) { xmlrpc_mem_block * fileContentsP; fileContentsP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); while (!envP->fault_occurred && !feof(ifP)) { char buffer[4096]; size_t bytesRead; bytesRead = fread(buffer, 1, sizeof(buffer), ifP); XMLRPC_MEMBLOCK_APPEND(char, envP, fileContentsP, buffer, bytesRead); } if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, fileContentsP); *fileContentsPP = fileContentsP; } int main(int argc, const char ** argv) { xmlrpc_env env; const char * methodName; xmlrpc_value * paramArrayP; xmlrpc_mem_block * callXmlP; if (argc-1 > 0) { fprintf(stderr, "No arguments. Input is from Standard Input\n"); if (argv){} /* defeat compiler warning */ exit(99); } xmlrpc_env_init(&env); fprintf(stderr, "Reading call data from Standard Input...\n"); readFile(&env, stdin, &callXmlP); die_if_fault_occurred(&env); xmlrpc_parse_call(&env, XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP), XMLRPC_MEMBLOCK_SIZE(char, callXmlP), &methodName, ¶mArrayP); if (env.fault_occurred) printf("Invalid call. %s\n", env.fault_string); else { printf("Parsed successfully as XML-RPC call.\n"); printf("Method name: '%s'\n", methodName); printf("Parameter array:\n"); dumpValue(" ", paramArrayP); strfree(methodName); xmlrpc_DECREF(paramArrayP); } XMLRPC_MEMBLOCK_FREE(char, callXmlP); xmlrpc_env_clean(&env); return 0; } xmlrpc-c-1.33.14/tools/xmlrpc/000077500000000000000000000000001236133176700160665ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/xmlrpc/Makefile000066400000000000000000000023151236133176700175270ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') TOOLSDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(TOOLSDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools/xmlrpc default: all include $(BLDDIR)/config.mk PROGRAMS_TO_INSTALL = xmlrpc include $(SRCDIR)/tools/common.mk INCLUDES = \ -I../lib/include \ -Iblddir \ -Iblddir/include \ -Isrcdir/include \ -Isrcdir/lib/util/include all: xmlrpc UTIL_OBJS = \ casprintf.o \ cmdline_parser.o \ getoptx.o \ stripcaseeq.o \ string_parser.o \ UTILS = $(UTIL_OBJS:%=$(UTIL_DIR)/%) DUMPVALUE = blddir/tools/lib/dumpvalue.o XMLRPC_OBJS = xmlrpc.o $(DUMPVALUE) ifeq ($(MSVCRT),yes) CLIENT_LDLIBS += -lws2_32 -lwsock32 -lpthread endif xmlrpc: $(XMLRPC_OBJS) $(CLIENT_LIBS_DEP) $(UTILS) $(CCLD) -o $@ $(LDFLAGS_ALL) $(XMLRPC_OBJS) $(UTILS) $(CLIENT_LDLIBS) %.o:%.c $(BLDDIR)/include/xmlrpc-c/config.h $(CC) -c $(CFLAGS_ALL) $< # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/tools/common.mk: srcdir blddir include depend.mk .PHONY: dep dep: dep-common .PHONY: clean clean: clean-common rm -f xmlrpc .PHONY: distclean distclean: clean distclean-common xmlrpc-c-1.33.14/tools/xmlrpc/xmlrpc.c000066400000000000000000000422651236133176700175500ustar00rootroot00000000000000/* Make an XML-RPC call. User specifies details of the call on the command line. We print the result on Standard Output. Example: $ xmlrpc http://localhost:8080/RPC2 sample.add i/3 i/5 Result: Integer: 8 $ xmlrpc localhost:8080 sample.add i/3 i/5 Result: Integer: 8 This is just the beginnings of this program. It should be extended to deal with all types of parameters and results. An example of a good syntax for parameters would be: $ xmlrpc http://www.oreillynet.com/meerkat/xml-rpc/server.php \ meerkat.getItems \ struct/{search:linux,descriptions:i/76,time_period:12hour} Result: Array: Struct: title: String: DatabaseJournal: OpenEdge-Based Finance ... link: String: http://linuxtoday.com/news_story.php3?ltsn=... description: String: "Finance application with embedded ... Struct: title: ... link: ... description: ... */ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include #include #include "xmlrpc_config.h" /* information about this build environment */ #include "bool.h" #include "int.h" #include "mallocvar.h" #include "girstring.h" #include "casprintf.h" #include "string_parser.h" #include "cmdline_parser.h" #include "dumpvalue.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/client.h" #include "xmlrpc-c/string_int.h" #define NAME "xmlrpc command line program" #define VERSION "1.0" struct cmdlineInfo { const char * url; const char * username; const char * password; const char * methodName; unsigned int paramCount; const char ** params; /* Array of parameters, in order. Has 'paramCount' entries. */ const char * transport; /* Name of XML transport he wants to use. NULL if he has no preference. */ const char * curlinterface; /* "network interface" parameter for the Curl transport. (Not valid if 'transport' names a non-Curl transport). */ xmlrpc_bool curlnoverifypeer; xmlrpc_bool curlnoverifyhost; const char * curluseragent; }; static void die_if_fault_occurred (xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "Failed. %s\n", envP->fault_string); exit(1); } } static void GNU_PRINTF_ATTR(2,3) setError(xmlrpc_env * const envP, const char format[], ...) { va_list args; const char * faultString; va_start(args, format); cvasprintf(&faultString, format, args); va_end(args); xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, faultString); strfree(faultString); } static void processArguments(xmlrpc_env * const envP, cmdlineParser const cp, struct cmdlineInfo * const cmdlineP) { if (cmd_argumentCount(cp) < 2) setError(envP, "Not enough arguments. Need at least a URL and " "method name."); else { unsigned int i; cmdlineP->url = cmd_getArgument(cp, 0); cmdlineP->methodName = cmd_getArgument(cp, 1); cmdlineP->paramCount = cmd_argumentCount(cp) - 2; MALLOCARRAY(cmdlineP->params, cmdlineP->paramCount); for (i = 0; i < cmdlineP->paramCount; ++i) cmdlineP->params[i] = cmd_getArgument(cp, i+2); } } static void chooseTransport(xmlrpc_env * const envP ATTR_UNUSED, cmdlineParser const cp, const char ** const transportPP) { const char * transportOpt = cmd_getOptionValueString(cp, "transport"); if (transportOpt) { *transportPP = transportOpt; } else { if (cmd_optionIsPresent(cp, "curlinterface") || cmd_optionIsPresent(cp, "curlnoverifypeer") || cmd_optionIsPresent(cp, "curlnoverifyhost") || cmd_optionIsPresent(cp, "curluseragent")) *transportPP = strdup("curl"); else *transportPP = NULL; } } static void parseCommandLine(xmlrpc_env * const envP, int const argc, const char ** const argv, struct cmdlineInfo * const cmdlineP) { cmdlineParser const cp = cmd_createOptionParser(); const char * error; cmd_defineOption(cp, "transport", OPTTYPE_STRING); cmd_defineOption(cp, "username", OPTTYPE_STRING); cmd_defineOption(cp, "password", OPTTYPE_STRING); cmd_defineOption(cp, "curlinterface", OPTTYPE_STRING); cmd_defineOption(cp, "curlnoverifypeer", OPTTYPE_STRING); cmd_defineOption(cp, "curlnoverifyhost", OPTTYPE_STRING); cmd_defineOption(cp, "curluseragent", OPTTYPE_STRING); cmd_processOptions(cp, argc, argv, &error); if (error) { setError(envP, "Command syntax error. %s", error); strfree(error); } else { cmdlineP->username = cmd_getOptionValueString(cp, "username"); cmdlineP->password = cmd_getOptionValueString(cp, "password"); if (cmdlineP->username && !cmdlineP->password) setError(envP, "When you specify -username, you must also " "specify -password."); else { chooseTransport(envP, cp, &cmdlineP->transport); cmdlineP->curlinterface = cmd_getOptionValueString(cp, "curlinterface"); cmdlineP->curlnoverifypeer = cmd_optionIsPresent(cp, "curlnoverifypeer"); cmdlineP->curlnoverifyhost = cmd_optionIsPresent(cp, "curlnoverifyhost"); cmdlineP->curluseragent = cmd_getOptionValueString(cp, "curluseragent"); if ((!cmdlineP->transport || !streq(cmdlineP->transport, "curl")) && (cmdlineP->curlinterface || cmdlineP->curlnoverifypeer || cmdlineP->curlnoverifyhost || cmdlineP->curluseragent)) setError(envP, "You may not specify a Curl transport " "option unless you also specify -transport=curl"); processArguments(envP, cp, cmdlineP); } } cmd_destroyOptionParser(cp); } static void freeCmdline(struct cmdlineInfo const cmdline) { unsigned int i; strfree(cmdline.url); strfree(cmdline.methodName); if (cmdline.transport) strfree(cmdline.transport); if (cmdline.curlinterface) strfree(cmdline.curlinterface); if (cmdline.curluseragent) strfree(cmdline.curluseragent); if (cmdline.username) strfree(cmdline.username); if (cmdline.password) strfree(cmdline.password); for (i = 0; i < cmdline.paramCount; ++i) strfree(cmdline.params[i]); } static void computeUrl(const char * const urlArg, const char ** const urlP) { if (strstr(urlArg, "://") != 0) casprintf(urlP, "%s", urlArg); else casprintf(urlP, "http://%s/RPC2", urlArg); } static void buildString(xmlrpc_env * const envP, const char * const valueString, xmlrpc_value ** const paramPP) { *paramPP = xmlrpc_string_new(envP, valueString); } static void interpretHex(xmlrpc_env * const envP, const char * const valueString, size_t const valueStringSize, unsigned char * const byteString) { size_t bsCursor; size_t strCursor; for (strCursor = 0, bsCursor = 0; strCursor < valueStringSize && !envP->fault_occurred; ) { int rc; rc = sscanf(&valueString[strCursor], "%2hhx", &byteString[bsCursor++]); if (rc != 1) xmlrpc_faultf(envP, "Invalid hex data '%s'", &valueString[strCursor]); else strCursor += 2; } } static void buildBytestring(xmlrpc_env * const envP, const char * const valueString, xmlrpc_value ** const paramPP) { size_t const valueStringSize = strlen(valueString); if (valueStringSize / 2 * 2 != valueStringSize) xmlrpc_faultf(envP, "Hexadecimal text is not an even " "number of characters (it is %u characters)", (unsigned)strlen(valueString)); else { size_t const byteStringSize = strlen(valueString)/2; unsigned char * byteString; MALLOCARRAY(byteString, byteStringSize); if (byteString == NULL) xmlrpc_faultf(envP, "Failed to allocate %u-byte buffer", (unsigned)byteStringSize); else { interpretHex(envP, valueString, valueStringSize, byteString); if (!envP->fault_occurred) *paramPP = xmlrpc_base64_new(envP, byteStringSize, byteString); free(byteString); } } } static void buildInt(xmlrpc_env * const envP, const char * const valueString, xmlrpc_value ** const paramPP) { if (strlen(valueString) < 1) setError(envP, "Integer argument has nothing after the 'i/'"); else { int value; const char * error; interpretInt(valueString, &value, &error); if (error) { setError(envP, "'%s' is not a valid 32-bit integer. %s", valueString, error); strfree(error); } else *paramPP = xmlrpc_int_new(envP, value); } } static void buildBool(xmlrpc_env * const envP, const char * const valueString, xmlrpc_value ** const paramPP) { if (streq(valueString, "t") || streq(valueString, "true")) *paramPP = xmlrpc_bool_new(envP, true); else if (streq(valueString, "f") || streq(valueString, "false")) *paramPP = xmlrpc_bool_new(envP, false); else setError(envP, "Boolean argument has unrecognized value '%s'. " "recognized values are 't', 'f', 'true', and 'false'.", valueString); } static void buildDouble(xmlrpc_env * const envP, const char * const valueString, xmlrpc_value ** const paramPP) { if (strlen(valueString) < 1) setError(envP, "\"Double\" argument has nothing after the 'd/'"); else { double value; char * tailptr; value = strtod(valueString, &tailptr); if (*tailptr != '\0') setError(envP, "\"Double\" argument has non-decimal crap in it: '%s'", tailptr); else *paramPP = xmlrpc_double_new(envP, value); } } static void buildNil(xmlrpc_env * const envP, const char * const valueString, xmlrpc_value ** const paramPP) { if (strlen(valueString) > 0) setError(envP, "Nil argument has something after the 'n/'"); else { *paramPP = xmlrpc_nil_new(envP); } } static void buildI8(xmlrpc_env * const envP, const char * const valueString, xmlrpc_value ** const paramPP) { if (strlen(valueString) < 1) setError(envP, "Integer argument has nothing after the 'I/'"); else { int64_t value; const char * error; interpretLl(valueString, &value, &error); if (error) { setError(envP, "'%s' is not a valid 64-bit integer. %s", valueString, error); strfree(error); } else *paramPP = xmlrpc_i8_new(envP, value); } } static void computeParameter(xmlrpc_env * const envP, const char * const paramArg, xmlrpc_value ** const paramPP) { if (xmlrpc_strneq(paramArg, "s/", 2)) buildString(envP, ¶mArg[2], paramPP); else if (xmlrpc_strneq(paramArg, "h/", 2)) buildBytestring(envP, ¶mArg[2], paramPP); else if (xmlrpc_strneq(paramArg, "i/", 2)) buildInt(envP, ¶mArg[2], paramPP); else if (xmlrpc_strneq(paramArg, "I/", 2)) buildI8(envP, ¶mArg[2], paramPP); else if (xmlrpc_strneq(paramArg, "d/", 2)) buildDouble(envP, ¶mArg[2], paramPP); else if (xmlrpc_strneq(paramArg, "b/", 2)) buildBool(envP, ¶mArg[2], paramPP); else if (xmlrpc_strneq(paramArg, "n/", 2)) buildNil(envP, ¶mArg[2], paramPP); else { /* It's not in normal type/value format, so we take it to be the shortcut string notation */ buildString(envP, paramArg, paramPP); } } static void computeParamArray(xmlrpc_env * const envP, unsigned int const paramCount, const char ** const params, xmlrpc_value ** const paramArrayPP) { unsigned int i; xmlrpc_value * paramArrayP; paramArrayP = xmlrpc_array_new(envP); for (i = 0; i < paramCount && !envP->fault_occurred; ++i) { xmlrpc_value * paramP; computeParameter(envP, params[i], ¶mP); if (!envP->fault_occurred) { xmlrpc_array_append_item(envP, paramArrayP, paramP); xmlrpc_DECREF(paramP); } } *paramArrayPP = paramArrayP; } static void dumpResult(xmlrpc_value * const resultP) { printf("Result:\n\n"); dumpValue("", resultP); } static void callWithClient(xmlrpc_env * const envP, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_value ** const resultPP) { xmlrpc_env env; xmlrpc_env_init(&env); *resultPP = xmlrpc_client_call_server_params( &env, serverInfoP, methodName, paramArrayP); if (env.fault_occurred) xmlrpc_faultf(envP, "Call failed. %s. (XML-RPC fault code %d)", env.fault_string, env.fault_code); xmlrpc_env_clean(&env); } static void doCall(xmlrpc_env * const envP, const char * const transport, const char * const curlinterface, xmlrpc_bool const curlnoverifypeer, xmlrpc_bool const curlnoverifyhost, const char * const curluseragent, const xmlrpc_server_info * const serverInfoP, const char * const methodName, xmlrpc_value * const paramArrayP, xmlrpc_value ** const resultPP) { struct xmlrpc_clientparms clientparms; XMLRPC_ASSERT(xmlrpc_value_type(paramArrayP) == XMLRPC_TYPE_ARRAY); clientparms.transport = transport; if (transport && streq(transport, "curl")) { struct xmlrpc_curl_xportparms * curlXportParmsP; MALLOCVAR(curlXportParmsP); curlXportParmsP->network_interface = curlinterface; curlXportParmsP->no_ssl_verifypeer = curlnoverifypeer; curlXportParmsP->no_ssl_verifyhost = curlnoverifyhost; curlXportParmsP->user_agent = curluseragent; clientparms.transportparmsP = curlXportParmsP; clientparms.transportparm_size = XMLRPC_CXPSIZE(user_agent); } else { clientparms.transportparmsP = NULL; clientparms.transportparm_size = 0; } xmlrpc_client_init2(envP, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, &clientparms, XMLRPC_CPSIZE(transportparm_size)); if (!envP->fault_occurred) { callWithClient(envP, serverInfoP, methodName, paramArrayP, resultPP); xmlrpc_client_cleanup(); } if (clientparms.transportparmsP) free((void*)clientparms.transportparmsP); } static void createServerInfo(xmlrpc_env * const envP, const char * const serverUrl, const char * const userName, const char * const password, xmlrpc_server_info ** const serverInfoPP) { xmlrpc_server_info * serverInfoP; serverInfoP = xmlrpc_server_info_new(envP, serverUrl); if (!envP->fault_occurred) { if (userName) { xmlrpc_server_info_set_basic_auth( envP, serverInfoP, userName, password); } } *serverInfoPP = serverInfoP; } int main(int const argc, const char ** const argv) { struct cmdlineInfo cmdline; xmlrpc_env env; xmlrpc_value * paramArrayP; xmlrpc_value * resultP; const char * url; xmlrpc_server_info * serverInfoP; xmlrpc_env_init(&env); parseCommandLine(&env, argc, argv, &cmdline); die_if_fault_occurred(&env); computeUrl(cmdline.url, &url); computeParamArray(&env, cmdline.paramCount, cmdline.params, ¶mArrayP); die_if_fault_occurred(&env); createServerInfo(&env, url, cmdline.username, cmdline.password, &serverInfoP); die_if_fault_occurred(&env); doCall(&env, cmdline.transport, cmdline.curlinterface, cmdline.curlnoverifypeer, cmdline.curlnoverifyhost, cmdline.curluseragent, serverInfoP, cmdline.methodName, paramArrayP, &resultP); die_if_fault_occurred(&env); dumpResult(resultP); strfree(url); xmlrpc_DECREF(resultP); freeCmdline(cmdline); xmlrpc_env_clean(&env); return 0; } xmlrpc-c-1.33.14/tools/xmlrpc/xmlrpc.html000066400000000000000000000161501236133176700202640ustar00rootroot00000000000000 Xmlrpc User Manual

xmlrpc makes an XML-RPC remote procedure call (RPC) and displays the response. xmlrpc runs an XML-RPC client.

This program is mainly useful for debugging and learning about XML-RPC servers. XML-RPC is such that the RPCs normally need to be made by a program rather than a person to be of use.

A similar tool done as a web form is at http://gggeek.damacom.it/debugger/

Examples


     $ xmlrpc http://localhost:8080/RPC2 sample.add i/3 i/5
       Result:
         Integer: 8


     $ xmlrpc localhost:8080 sample.add i/3 i/5
       Result:
         Integer: 8
     


     $ xmlrpc http://xmlrpc.example.com/~bryanh echostring \
         "s/This is a string"
     Result:
       String: This is a string



     $ xmlrpc http://xmlrpc.example.com/~bryanh echostring \
         "This is a string in shortcut syntax"
     Result:
       String: This is a string in shortcut syntax



     $ xmlrpc http://xmlrpc.example.com sample.add i/3 i/5 \
         transport=curl -curlinterface=eth1 -username=bryanh -password=passw0rd
       Result:
         Integer: 8
     

Overview

xmlrpc url methodName parameter ... [-transport=transportname] [-username=username -password=password] [-curlinterface={interface|host}] [-curlnoverifypeer] [-curlnoverifyhost]

parameter:

i/integer | s/string | h/hexstring | b/{true|false|t|f} | d/realnum | n/ | string

Minimum unique abbreviation of option is acceptable. You may use double hyphens instead of single hyphen to denote options. You may use white space in place of the equals sign to separate an option name from its value.

Arguments

url
This is the URL of the XML-RPC server. As XML-RPC uses HTTP, this must be an HTTP url. However, if you don't specify a type ("http:") in the URL, xmlrpc assumes an "http://" prefix and a "/RPC2" suffix. RPC2 is the conventional file name for an XML-RPC responder.
methodName
The name of the XML-RPC method you want to invoke.
parameter ...
The list of parameters for the RPC. xmlrpc turns each of these arguments into an XML-RPC parameter, in the order given. You may specify no parameters if you like.

You specify the data type of the parameter with a prefix ending in a slash. Example: i/5. Here, the "i" signifies an integer data type. "5" is the value.

xmlrpc is capable of only a subset of the possible XML-RPC types, as follows by prefix:

i/
integer (<i4>) (32 bit)
s/
string (<string>)
h/
byte string (<base64>). Specify the value in hexadecimal.
b/
boolean (<boolean>). Specify the value as "true" or "t" for true; "false" or "f" for false.
d/
double (<double>) (i.e. real number)
n/
nil (<nil>)
I/
64 bit integer (<i8>)

As a shortcut, if you don't specify a prefix (i.e. your argument does not contain a slash), xmlrpc assumes string data type.

Options

-transport=transportname
This selects the XML transport facility (e.g. libwww) that xmlrpc uses to perform the RPC.

The name transportname is one that the Xmlrpc-c programming library recognizes. This is typically libwww, curl, and wininet.

By default, xmlrpc lets the Xmlrpc-c library choose.

-username=username
-password=password
These options, which must be used together, cause the client to authenticate itself to the server, if the server requires it, using HTTP Basic Authentication and the specified username and password.
-curlinterface={interface|host}
This option gives the "interface" option for a Curl XML transport.

The exact meaning of this option is up to the Curl library, and the best documentation for it is the manual for the 'curl' program that comes with the Curl library.

But essentially, it chooses the local network interface through which to send the RPC. It causes the Curl library to perform a "bind" operation on the socket it uses for the communication. It can be the name of a network interface (e.g. on Linux, "eth1") or an IP address of the interface or a host name that resolves to the IP address of the interface. Unfortunately, you can't explicitly state which form you're specifying, so there's some ambiguity.

Examples:

  • -interface=eth1
  • -interface=64.171.19.66
  • -interface=giraffe.giraffe-data.com

This option causes xmlrpc to default to using the Curl XML transport. You may not specify any other transport.

-curlnoverifypeer
This option gives the "no_ssl_verifypeer" option for the Curl XML transport, which is essentially the CURLOPT_SSL_VERIFYPEER option of the Curl library.

See the curl_easy_setopt() man page for details on this, but essentially it means that the client does not authenticate the server's certificate of identity -- it just believes whatever the server says.

You may want to use -curlnoverifyhost as well. Since you're not authenticating the server's identity, there's not much sense in checking it.

This option causes xmlrpc to default to using the Curl XML transport. You may not specify any other transport.

-curlnoverifyhost
This option gives the "no_ssl_verifyhost" option for the Curl XML transport, which is essentially the CURLOPT_SSL_VERIFYHOST option of the Curl library.

See the curl_easy_setopt() man page for details on this, but essentially it means that the client does not verify the server's identity. It just assumes that if the server answers the IP address of the server as indicated by the URL (probably via host name), then it's the intended server.

You may want to use -curlnoverifypeer as well. As long as you don't care who the server says it is, there's no point in authenticating its identity.

This option causes xmlrpc to default to using the Curl XML transport. You may not specify any other transport.

Limitations

If you run xmlrpc in an environment in which programs get their arguments encoded some way other than UTF-8, xmlrpc will generate garbage for the XML-RPC call and display garbage for the XML-RPC response. Typically, you control this aspect of the environment with a LANG environment variable. One safe value for LANG is "C". xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/000077500000000000000000000000001236133176700201715ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/Makefile000066400000000000000000000025561236133176700216410ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') TOOLSDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(TOOLSDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools/xmlrpc_cpp_proxy default: all include $(BLDDIR)/config.mk PROGRAMS_TO_INSTALL = xmlrpc_cpp_proxy include $(SRCDIR)/tools/common.mk # in Glibc 2.2 has a bug that results in inlining failure, # so we disable warnings for that: CFLAGS_LOCAL = -Wno-inline INCLUDES = -I$(BLDDIR) -I$(BLDDIR)/include -Isrcdir/include all: xmlrpc_cpp_proxy OBJECTS = \ xmlrpc_cpp_proxy.o \ xmlrpcMethod.o \ xmlrpcType.o \ proxyClass.o \ systemProxy.o \ LIBS = \ $(LIBXMLRPC_CLIENTPP) \ $(LIBXMLRPCPP) \ $(CLIENT_LIBS_DEP) \ $(LIBXMLRPC) \ $(LIBXMLRPC_XML) \ $(LIBXMLRPC_UTIL) \ LDLIBS = $(CLIENTPP_LDLIBS) $(CLIENT_LDLIBS) ifeq ($(MSVCRT),yes) LDLIBS += -lws2_32 -lwsock32 -lpthread endif xmlrpc_cpp_proxy: $(OBJECTS) $(LIBS) $(CXXLD) -o $@ $(LDFLAGS_ALL) $(OBJECTS) $(LDLIBS) $(LADD) %.o:%.cpp $(BLDDIR)/include/xmlrpc-c/config.h $(CXX) -c $(CXXFLAGS_ALL) $< # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/tools/common.mk: srcdir blddir include depend.mk .PHONY: clean clean: clean-common rm -f xmlrpc_cpp_proxy .PHONY: distclean distclean: clean distclean-common .PHONY: dep dep: dep-common xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/proxyClass.cpp000066400000000000000000000032351236133176700230470ustar00rootroot00000000000000#include #include #include using namespace std; #include "xmlrpc-c/client_simple.hpp" #include "xmlrpcType.hpp" #include "xmlrpcMethod.hpp" #include "proxyClass.hpp" proxyClass::proxyClass(string const& className) : _className(className) {} proxyClass::proxyClass(proxyClass const& c) : _className(c._className), functions(c.functions) {} string proxyClass::className() const { return this->_className; } void proxyClass::addFunction(xmlrpcMethod const& function) { functions.push_back(function); } void proxyClass::printDeclaration(ostream & out) const { out << "class " << this->_className << " {" << endl; out << endl; out << "public:" << endl; // emit the constructor prototype: out << " " << this->_className << "(std::string const& serverUrl) " << endl << " : serverUrl(serverUrl) {}" << endl; // emit the XML-RPC method method prototypes: vector::const_iterator f; for (f = this->functions.begin(); f < this->functions.end(); ++f) { f->printDeclarations(out); } // emit the private data: out << "private:" << endl; out << " xmlrpc_c::clientSimple client;" << endl; out << " std::string const serverUrl;" << endl; out << " // The URL for the server for which we are proxy" << endl; // emit the class closing: out << "};" << endl; } void proxyClass::printDefinition(ostream & out) const { vector::const_iterator f; for (f = this->functions.begin(); f < this->functions.end(); ++f) { f->printDefinitions(out, this->_className); } } xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/proxyClass.hpp000066400000000000000000000011161236133176700230500ustar00rootroot00000000000000#include #include #include "xmlrpcMethod.hpp" class proxyClass { // An object of this class contains information about a proxy // class, and knows how to generate code. public: proxyClass(std::string const& className); proxyClass(proxyClass const&); std::string className() const; void addFunction(xmlrpcMethod const& function); void printDeclaration(std::ostream& out) const; void printDefinition(std::ostream& out) const; private: std::string const _className; std::vector functions; }; xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/systemProxy.cpp000066400000000000000000000026341236133176700232700ustar00rootroot00000000000000/*============================================================================= systemProxy =============================================================================== This is a proxy class for the introspection system methods of the server. Note that you can use 'xmlrpc_cpp_proxy' itself to generate this file, but we hand-edit it to make it easier to read. =============================================================================*/ #include "systemProxy.hpp" using namespace std; xmlrpc_c::value // array systemProxy::listMethods(string const& serverUrl) { xmlrpc_c::paramList params; xmlrpc_c::value result; this->call(serverUrl, "system.listMethods", &result); return result; } xmlrpc_c::value // array systemProxy::methodSignature(string const& serverUrl, string const& methodName) { xmlrpc_c::paramList params; params.add(xmlrpc_c::value_string(methodName)); xmlrpc_c::value result; this->call(serverUrl, "system.methodSignature", params, &result); return result; } string systemProxy::methodHelp(string const& serverUrl, string const& methodName) { xmlrpc_c::paramList params; params.add(xmlrpc_c::value_string(methodName)); xmlrpc_c::value result; this->call(serverUrl, "system.methodHelp", params, &result); return xmlrpc_c::value_string(result); } xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/systemProxy.hpp000066400000000000000000000010451236133176700232700ustar00rootroot00000000000000#ifndef SYSTEMPROXY_HPP_INCLUDED #define SYSTEMPROXY_HPP_INCLUDED #include #include class systemProxy : public xmlrpc_c::clientSimple { public: systemProxy() {} xmlrpc_c::value /*array*/ listMethods(std::string const& serverUrl); xmlrpc_c::value /*array*/ methodSignature(std::string const& serverUrl, std::string const& methodName); std::string methodHelp(std::string const& serverUrl, std::string const& methodName); }; #endif xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/xmlrpcMethod.cpp000066400000000000000000000141101236133176700233400ustar00rootroot00000000000000#include #include #include #include "xmlrpcType.hpp" #include "xmlrpcMethod.hpp" using namespace std; xmlrpcMethod::xmlrpcMethod(string const& functionName, string const& methodName, string const& help, xmlrpc_c::value_array const& signatureList) : mFunctionName(functionName), mMethodName(methodName), mHelp(help), mSynopsis(signatureList) {} xmlrpcMethod::xmlrpcMethod(xmlrpcMethod const& f) : mFunctionName(f.mFunctionName), mMethodName(f.mMethodName), mHelp(f.mHelp), mSynopsis(f.mSynopsis) {} xmlrpcMethod& xmlrpcMethod::operator= (xmlrpcMethod const& f) { if (this != &f) { this->mFunctionName = f.mFunctionName; this->mMethodName = f.mMethodName; this->mHelp = f.mHelp; this->mSynopsis = f.mSynopsis; } return *this; } size_t xmlrpcMethod::parameterCount(size_t const synopsisIndex) const { xmlrpc_c::value_array const funcSynop( mSynopsis.vectorValueValue()[synopsisIndex]); size_t const size(funcSynop.size()); if (size < 1) throw domain_error("Synopsis contains no items"); return size - 1; } xmlrpcType const& xmlrpcMethod::parameterType(size_t const synopsisIndex, size_t const parameterIndex) const { xmlrpc_c::value_array const funcSynop( mSynopsis.vectorValueValue()[synopsisIndex]); xmlrpc_c::value_string const param( funcSynop.vectorValueValue()[parameterIndex + 1]); return findXmlrpcType(static_cast(param)); } const xmlrpcType& xmlrpcMethod::returnType(size_t const synopsisIndex) const { xmlrpc_c::value_array const funcSynop( mSynopsis.vectorValueValue()[synopsisIndex]); xmlrpc_c::value_string datatype(funcSynop.vectorValueValue()[0]); return findXmlrpcType(static_cast(datatype)); } void xmlrpcMethod::printParameters(ostream & out, size_t const synopsisIndex) const { /*---------------------------------------------------------------------------- Print the parameter declarations. -----------------------------------------------------------------------------*/ size_t const end(parameterCount(synopsisIndex)); bool first; first = true; for (size_t i = 0; i < end; ++i) { if (!first) out << ", "; xmlrpcType const& ptype(parameterType(synopsisIndex, i)); string const localName(ptype.defaultParameterBaseName(i + 1)); out << ptype.parameterFragment(localName); first = false; } } void xmlrpcMethod::printDeclaration(ostream & out, size_t const synopsisIndex) const { try { xmlrpcType const& rtype(returnType(synopsisIndex)); out << " " << rtype.returnTypeFragment() << " " << mFunctionName << " ("; printParameters(out, synopsisIndex); out << ");" << endl; } catch (xmlrpc_c::fault const& f) { ostringstream msg; msg << "Failed to generate header for signature " << synopsisIndex << " . " << f.getDescription(); throw(logic_error(msg.str())); } } void xmlrpcMethod::printDeclarations(ostream & out) const { try { // Print the method help as a comment out << endl << " /* " << mHelp << " */" << endl; size_t end; try { end = mSynopsis.size(); } catch (xmlrpc_c::fault const& f) { throw(logic_error("Failed to get size of signature array for " "method " + this->mFunctionName + ". " + f.getDescription())); } // Print the declarations for all the signatures of this // XML-RPC method. for (size_t i = 0; i < end; ++i) printDeclaration(out, i); } catch (exception const& e) { throw(logic_error("Failed to generate declarations for method " + this->mFunctionName + ". " + e.what())); } } void xmlrpcMethod::printDefinition(ostream & out, string const& className, size_t const synopsisIndex) const { xmlrpcType const& rtype(returnType(synopsisIndex)); out << rtype.returnTypeFragment() << " " << className << "::" << mFunctionName << " ("; printParameters(out, synopsisIndex); out << ") {" << endl; size_t const end(parameterCount(synopsisIndex)); if (end > 0){ // Emit code to generate the parameter list object out << " xmlrpc_c::paramList params;" << endl; for (size_t i = 0; i < end; ++i) { xmlrpcType const& ptype(parameterType(synopsisIndex, i)); string const basename(ptype.defaultParameterBaseName(i + 1)); out << " params.add(" << ptype.inputConversionFragment(basename) << ");" << endl; } } // Emit result holder declaration. out << " xmlrpc_c::value result;" << endl; // Emit the call to the XML-RPC call method out << " this->client.call(" << "this->serverUrl, " << "\"" << mMethodName << "\", "; if (end > 0) out << "params, "; out << "&result);" << endl; // Emit the return statement. out << " return " << rtype.outputConversionFragment("result") << ";" << endl; out << "}" << endl; } void xmlrpcMethod::printDefinitions(ostream & out, string const& className) const { try { size_t const end(mSynopsis.size()); for (size_t i = 0; i < end; ++i) { out << endl; printDefinition(out, className, i); } } catch (xmlrpc_c::fault const& f) { throw(logic_error("Failed to generate definitions for class " + this->mFunctionName + ". " + f.getDescription())); } } xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/xmlrpcMethod.hpp000066400000000000000000000031041236133176700233460ustar00rootroot00000000000000#ifndef XMLRPCMETHOD_HPP #define XMLRPCMETHOD_HPP #include #include #include class xmlrpcMethod { // An object of this class contains everything we know about a // given XML-RPC method, and knows how to print local bindings. std::string mFunctionName; std::string mMethodName; std::string mHelp; xmlrpc_c::value_array mSynopsis; public: xmlrpcMethod(std::string const& function_name, std::string const& method_name, std::string const& help, xmlrpc_c::value_array const& signatureList); xmlrpcMethod(xmlrpcMethod const& f); xmlrpcMethod& operator= (xmlrpcMethod const& f); void printDeclarations(std::ostream& out) const; void printDefinitions(std::ostream & out, std::string const& className) const; private: void printParameters(std::ostream & out, size_t const synopsis_index) const; void printDeclaration(std::ostream & out, size_t const synopsis_index) const; void printDefinition(std::ostream & out, std::string const& className, size_t const synopsis_index) const; const xmlrpcType& returnType(size_t const synopsis_index) const; size_t parameterCount(size_t const synopsis_index) const; const xmlrpcType& parameterType(size_t const synopsis_index, size_t const parameter_index) const; }; #endif xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/xmlrpcType.cpp000066400000000000000000000142761236133176700230560ustar00rootroot00000000000000#include #include #include #include #include #include #include "xmlrpcType.hpp" using namespace std; //========================================================================= // abstract class xmlrpcType //========================================================================= // Instances of xmlrpcType know how generate code fragments for manipulating // a specific XML-RPC data type. string xmlrpcType::defaultParameterBaseName(unsigned int const position) const { ostringstream nameStream; nameStream << typeName() << position; return nameStream.str(); } class rawXmlrpcType : public xmlrpcType { public: rawXmlrpcType(string const& typeName) : xmlrpcType(typeName) {} virtual string parameterFragment(string const& baseName) const; virtual string inputConversionFragment(string const& baseName) const; virtual string returnTypeFragment() const; virtual string outputConversionFragment(string const& varName) const; }; string rawXmlrpcType::parameterFragment(string const& baseName) const { return "xmlrpc_c::value /*" + typeName() + "*/ " + baseName; } string rawXmlrpcType::inputConversionFragment(string const& baseName) const { return baseName; } string rawXmlrpcType::returnTypeFragment() const { return "xmlrpc_c::value /*" + typeName() + "*/"; } string rawXmlrpcType::outputConversionFragment(string const& varName) const { return varName; } class simpleXmlrpcType : public xmlrpcType { string mNativeType; string mMakerFunc; string mGetterFunc; public: simpleXmlrpcType(string const& typeName, string const& nativeType, string const& makerFunc, string const& getterFunc); virtual string parameterFragment(string const& baseName) const; virtual string inputConversionFragment(string const& baseName) const; virtual string returnTypeFragment() const; virtual string outputConversionFragment(string const& varName) const; }; simpleXmlrpcType::simpleXmlrpcType(string const& typeName, string const& nativeType, string const& makerFunc, string const& getterFunc) : xmlrpcType(typeName), mNativeType(nativeType), mMakerFunc(makerFunc), mGetterFunc(getterFunc) { } string simpleXmlrpcType::parameterFragment(string const& baseName) const { return mNativeType + " const " + baseName; } string simpleXmlrpcType::inputConversionFragment(string const& baseName) const { return mMakerFunc + "(" + baseName + ")"; } string simpleXmlrpcType::returnTypeFragment() const { return mNativeType; } string simpleXmlrpcType::outputConversionFragment(string const& varName) const { return mMakerFunc + "(" + varName + ")"; } class voidXmlrpcType : public xmlrpcType { public: voidXmlrpcType() : xmlrpcType("void") {} virtual string parameterFragment(string const& baseName) const; virtual string inputConversionFragment(string const& baseName) const; virtual string returnTypeFragment() const; virtual string outputConversionFragment(string const& varName) const; }; string voidXmlrpcType::parameterFragment(string const&) const { throw domain_error("Can't handle functions with 'void' arguments'"); } string voidXmlrpcType::inputConversionFragment(string const&) const { throw domain_error("Can't handle functions with 'void' arguments'"); } string voidXmlrpcType::returnTypeFragment () const { return "void"; } string voidXmlrpcType::outputConversionFragment(string const&) const { return "/* Return value ignored. */"; } static simpleXmlrpcType const intType ("int", "int", "xmlrpc_c::value_int", "getInt"); static simpleXmlrpcType const boolType ("bool", "bool", "xmlrpc_c::value_boolean", "getBool"); static simpleXmlrpcType const doubleType ("double", "double", "xmlrpc_c::value_double", "getDouble"); static simpleXmlrpcType const stringType ("string", "std::string", "xmlrpc_c::value_string", "getString"); static rawXmlrpcType const dateTimeType ("dateTime"); static rawXmlrpcType const base64Type ("base64"); static rawXmlrpcType const structType ("struct"); static rawXmlrpcType const arrayType ("array"); static voidXmlrpcType const voidType; const xmlrpcType& findXmlrpcType(string const& name) { /*---------------------------------------------------------------------------- Given the name of an XML-RPC data type, try to find a corresponding xmlrpcType object. -----------------------------------------------------------------------------*/ if (name == "int" || name == "i4") return intType; else if (name == "boolean") return boolType; else if (name == "double") return doubleType; else if (name == "string") return stringType; else if (name == "dateTime.iso8601") return dateTimeType; else if (name == "base64") return base64Type; else if (name == "struct") return structType; else if (name == "array") return arrayType; else if (name == "void") return voidType; else if (name == "INT") return intType; else if (name == "BOOLEAN") return boolType; else if (name == "DOUBLE") return doubleType; else if (name == "STRING") return stringType; else if (name == "DATETIME.ISO8601") return dateTimeType; else if (name == "BASE64") return base64Type; else if (name == "STRUCT") return structType; else if (name == "ARRAY") return arrayType; else if (name == "VOID") return voidType; else if (name == "NIL") return voidType; else throw domain_error("Unknown XML-RPC type name '" + name + "'"); } xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/xmlrpcType.hpp000066400000000000000000000022251236133176700230520ustar00rootroot00000000000000#include #include class xmlrpcType { std::string mTypeName; xmlrpcType(xmlrpcType const&) { assert(false); } xmlrpcType& operator= (xmlrpcType const&) { assert(false); return *this; } public: xmlrpcType(const std::string& type_name) : mTypeName(type_name) {} virtual ~xmlrpcType () {} // Return the name for this XML-RPC type. virtual std::string typeName() const { return mTypeName; } // Given a parameter position, calculate a unique base name for all // parameter-related variables. virtual std::string defaultParameterBaseName(unsigned int const position) const; // Virtual functions for processing parameters. virtual std::string parameterFragment(std::string const& base_name) const = 0; virtual std::string inputConversionFragment(std::string const& base_name) const = 0; // Virtual functions for processing return values. virtual std::string returnTypeFragment () const = 0; virtual std::string outputConversionFragment(std::string const& var_name) const = 0; }; const xmlrpcType& findXmlrpcType(const std::string& name); xmlrpc-c-1.33.14/tools/xmlrpc_cpp_proxy/xmlrpc_cpp_proxy.cpp000066400000000000000000000144541236133176700243150ustar00rootroot00000000000000#include #include #include #include "xmlrpcType.hpp" #include "xmlrpcMethod.hpp" #include "proxyClass.hpp" #include "systemProxy.hpp" using namespace std; /*---------------------------------------------------------------------------- Command line -----------------------------------------------------------------------------*/ class cmdlineInfo { public: string serverUrl; string methodPrefix; string localClass; cmdlineInfo(int const argc, const char ** const argv); private: cmdlineInfo(); }; cmdlineInfo::cmdlineInfo(int const argc, const char ** const argv) { if (argc-1 != 3) { cerr << "There are 3 arguments: server URL, " << "prefix for the methods to include (null to include all), " << "and name to give the generated proxy class. " << "You specified " << argc-1 << " arguments." << endl << "Example: " << "xmlrpc_cpp_proxy http://localhost/RPC2 system systemProxy" << endl; exit(1); } this->serverUrl = string(argv[1]); this->methodPrefix = string(argv[2]); this->localClass = string(argv[3]); } static proxyClass getClassInfo(string const& serverUrl, string const& classPrefix, string const& className) { /*---------------------------------------------------------------------------- Connect to a remote server and extract the information we'll need to build a proxy class. -----------------------------------------------------------------------------*/ proxyClass theClass(className); systemProxy system; xmlrpc_c::value_array methods(system.listMethods(serverUrl)); unsigned int arraySize = methods.size(); for (size_t i = 0; i < arraySize; ++i) { // Break the method name into two pieces. xmlrpc_c::value_string val = (methods.vectorValueValue())[i]; string const methodName(static_cast(val)); size_t const lastDot(methodName.rfind('.')); string methodPrefix; string functionName; if (lastDot == string::npos) { methodPrefix = ""; functionName = methodName; } else { methodPrefix = string(methodName, 0, lastDot); functionName = string(methodName, lastDot + 1); } if (methodPrefix == classPrefix) { // It's a method User cares about string const help(system.methodHelp(serverUrl, methodName)); xmlrpc_c::value const signatureList( system.methodSignature(serverUrl, methodName)); if (signatureList.type() != xmlrpc_c::value::TYPE_ARRAY) { // It must be the string "undef", meaning the server // won't tell us any signatures. cerr << "Skipping method " << methodName << " " << "because server does not report any signatures " << "for it (via system.methodSignature method)" << endl; } else { // Add this function to our class information. xmlrpcMethod const method( functionName, methodName, help, xmlrpc_c::value_array(signatureList)); theClass.addFunction(method); } } } return theClass; } static void printHeader(ostream & out, proxyClass const& classInfo) { /*---------------------------------------------------------------------------- Print a complete header for the specified class. -----------------------------------------------------------------------------*/ string const className(classInfo.className()); try { out << "// Interface definition for " << className << " class, " << "an XML-RPC FOR C/C++ proxy class" << endl; out << "// Generated by 'xmlrpc_cpp_proxy'" << endl; out << endl; string const headerSymbol("_" + className + "_H_"); out << "#ifndef " << headerSymbol << endl; out << "#define " << headerSymbol << " 1" << endl; out << endl; out << "#include " << endl; out << "#include " << endl; out << endl; classInfo.printDeclaration(cout); out << endl; out << "#endif /* " << headerSymbol << " */" << endl; } catch (exception const& e) { throw(logic_error("Failed to generate header for class " + className + ". " + e.what())); } } static void printCppFile(ostream & out, proxyClass const& classInfo) { /*---------------------------------------------------------------------------- Print a complete definition for the specified class. -----------------------------------------------------------------------------*/ string const className(classInfo.className()); try { out << "// " << className << " - " << "an XML-RPC FOR C/C++ proxy class" << endl; out << "// Generated by 'xmlrpc_cpp_proxy'" << endl; out << endl; out << "#include \"" << className << ".h\"" << endl; classInfo.printDefinition(cout); } catch (xmlrpc_c::fault const& f) { throw(logic_error("Failed to generate definition for class " + className + ". " + f.getDescription())); } } int main(int const argc, const char ** const argv) { string const myName(argv[0]); cmdlineInfo const cmdline(argc, argv); int retval; try { proxyClass system(getClassInfo(cmdline.serverUrl, cmdline.methodPrefix, cmdline.localClass)); printHeader(cout, system); cout << endl; printCppFile(cout, system); retval = 0; } catch (xmlrpc_c::fault& f) { cerr << myName << ": XML-RPC fault #" << f.getCode() << ": " << f.getDescription() << endl; retval = 1; } catch (exception const& e) { cerr << myName << ": " << e.what() << endl; retval = 1; } catch (...) { cerr << myName << ": Unknown exception" << endl; retval = 1; } return retval; } xmlrpc-c-1.33.14/tools/xmlrpc_pstream/000077500000000000000000000000001236133176700176215ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/xmlrpc_pstream/Makefile000066400000000000000000000026351236133176700212670ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') TOOLSDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(TOOLSDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools/xmlrpc_pstream READLINE_LDLIBS = -lreadline -lncurses default: all include $(BLDDIR)/config.mk PROGRAMS_TO_INSTALL = xmlrpc_pstream include $(SRCDIR)/tools/common.mk INCLUDES = \ -I../lib/include \ -Isrcdir/lib/util/include \ -Iblddir \ -Iblddir/include \ -Isrcdir/include \ all: xmlrpc_pstream OBJECTS = \ xmlrpc_pstream.o \ blddir/tools/lib/dumpvalue.o \ LIBS = \ $(LIBXMLRPC_CLIENTPP) \ $(LIBXMLRPCPP) \ $(CLIENT_LIBS_DEP) \ $(LIBXMLRPC) \ $(LIBXMLRPC_XML) \ $(LIBXMLRPC_UTIL) \ LDLIBS = $(CLIENTPP_LDLIBS) $(CLIENT_LDLIBS) $(READLINE_LDLIBS) UTIL_OBJS = \ casprintf.o \ cmdline_parser_cpp.o \ cmdline_parser.o \ getoptx.o \ string_parser.o \ stripcaseeq.o \ UTILS = $(UTIL_OBJS:%=$(UTIL_DIR)/%) xmlrpc_pstream: $(OBJECTS) $(LIBS) $(UTILS) $(CXXLD) -o $@ $(LDFLAGS_ALL) $(OBJECTS) $(UTILS) $(LDLIBS) $(LADD) %.o:%.cpp blddir/include/xmlrpc-c/config.h $(CXX) -c $(CXXFLAGS_ALL) $< # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/tools/common.mk: srcdir blddir include depend.mk .PHONY: clean clean: clean-common rm -f xmlrpc_pstream .PHONY: distclean distclean: clean distclean-common .PHONY: dep dep: dep-common xmlrpc-c-1.33.14/tools/xmlrpc_pstream/test000077500000000000000000000010411236133176700205220ustar00rootroot00000000000000#! /bin/sh # This is for testing and playing with Xmlrpc_pstream. # To use, first start a packet stream XML-RPC server. The # 'pstream_inetd_server' program from examples/cpp is good: # # $ socketexec -accept -local_port=8080 -- pstream_inetd_server # # Then (in another shell), run this program: # # $ ./test # > sample.add i/3 i/5 # # Result: # Integer: 8 # # > [ctl-D] # $ # # OR: # # $ ./test sample.add i/3 i/5 # $ socketexec -connect -remote_host=localhost -remote_port=8080 --filedes=3 -- \ ./xmlrpc_pstream $* xmlrpc-c-1.33.14/tools/xmlrpc_pstream/xmlrpc_pstream.cpp000066400000000000000000000272331236133176700233740ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include "cmdline_parser.hpp" #include "xmlrpc-c/girerr.hpp" using girerr::throwf; #include // for __BEGIN_DECLS __BEGIN_DECLS #include "dumpvalue.h" /* An internal Xmlrpc-c header file ! */ __END_DECLS #include #include #include using namespace std; using namespace xmlrpc_c; /*---------------------------------------------------------------------------- Command line -----------------------------------------------------------------------------*/ class cmdlineInfo { public: int serverfd; bool interactive; // Valid only if !interactive: string methodName; vector params; cmdlineInfo(int const argc, const char ** const argv); private: cmdlineInfo(); }; static void parseCommandLine(cmdlineInfo * const cmdlineP, int const argc, const char ** const argv) { CmdlineParser cp; cp.defineOption("serverfd", CmdlineParser::UINT); try { cp.processOptions(argc, argv); } catch (exception const& e) { throwf("Command syntax error. %s", e.what()); } if (cp.optionIsPresent("serverfd")) { cmdlineP->serverfd = cp.getOptionValueUint("serverfd"); } else cmdlineP->serverfd = 3; if (cp.argumentCount() < 1) cmdlineP->interactive = true; else { cmdlineP->interactive = false; cmdlineP->methodName = cp.getArgument(0); for (uint argI = 1; argI < cp.argumentCount(); ++argI) cmdlineP->params.push_back(cp.getArgument(argI)); } } cmdlineInfo:: cmdlineInfo(int const argc, const char ** const argv) { try { parseCommandLine(this, argc, argv); } catch (exception const& e) { throwf("Command syntax error. %s", e.what()); } } static value bytestringValFromParm(string const& valueString) { value retval; if (valueString.length() / 2 * 2 != valueString.length()) throwf("Hexadecimal text is not an even " "number of characters (it is %u characters)", (unsigned)valueString.length()); else { vector byteString(valueString.length() / 2); size_t strCursor; strCursor = 0; while (strCursor < valueString.length()) { string const hexByte(valueString.substr(strCursor, 2)); unsigned char byte; int rc; rc = sscanf(hexByte.c_str(), "%2hhx", &byte); byteString.push_back(byte); if (rc != 1) throwf("Invalid hex data '%s'", hexByte.c_str()); else strCursor += 2; } retval = value_bytestring(byteString); } return retval; } static value intValFromParm(string const& valueString) { value retval; if (valueString.length() < 1) throwf("Integer argument has nothing after the 'i/'"); else { long longValue; char * tailptr; errno = 0; longValue = strtol(valueString.c_str(), &tailptr, 10); if (errno == ERANGE) throwf("'%s' is out of range for a 32 bit integer", valueString.c_str()); else if (errno != 0) throwf("Mysterious failure of strtol(), errno=%d (%s)", errno, strerror(errno)); else { if (*tailptr != '\0') throwf("Integer argument has non-digit crap in it: '%s'", tailptr); else retval = value_int(longValue); } } return retval; } static value boolValFromParm(string const& valueString) { value retval; if (valueString == "t" || valueString == "true") retval = value_boolean(true); else if (valueString == "f" || valueString == "false") retval = value_boolean(false); else throwf("Boolean argument has unrecognized value '%s'. " "recognized values are 't', 'f', 'true', and 'false'.", valueString.c_str()); return retval; } static value doubleValFromParm(string const& valueString) { value retval; if (valueString.length() < 1) throwf("\"Double\" argument has nothing after the 'd/'"); else { double value; char * tailptr; value = strtod(valueString.c_str(), &tailptr); if (*tailptr != '\0') throwf("\"Double\" argument has non-decimal crap in it: '%s'", tailptr); else retval = value_double(value); } return retval; } static value nilValFromParm(string const& valueString) { value retval; if (valueString.length() > 0) throwf("Nil argument has something after the 'n/'"); else retval = value_nil(); return retval; } static value i8ValFromParm(string const& valueString) { value retval; if (valueString.length() < 1) throwf("Integer argument has nothing after the 'I/'"); else { long long value; char * tailptr; errno = 0; value = strtoll(valueString.c_str(), &tailptr, 10); if (errno == ERANGE) throwf("'%s' is out of range for a 64 bit integer", valueString.c_str()); else if (errno != 0) throwf("Mysterious failure of strtoll(), errno=%d (%s)", errno, strerror(errno)); else { if (*tailptr != '\0') throwf("64 bit integer argument has non-digit crap " "in it: '%s'", tailptr); else retval = value_i8(value); } } return retval; } static value parameterFromArg(string const& paramArg) { value param; try { if (paramArg.substr(0, 2) == "s/") param = value_string(paramArg.substr(2)); else if (paramArg.substr(0, 2) == "h/") param = bytestringValFromParm(paramArg.substr(2)); else if (paramArg.substr(0, 2) == "i/") param = intValFromParm(paramArg.substr(2)); else if (paramArg.substr(0, 2) == "I/") param = i8ValFromParm(paramArg.substr(2)); else if (paramArg.substr(0, 2) == "d/") param = doubleValFromParm(paramArg.substr(2)); else if (paramArg.substr(0, 2) == "b/") param = boolValFromParm(paramArg.substr(2)); else if (paramArg.substr(0, 2) == "n/") param = nilValFromParm(paramArg.substr(2)); else { /* It's not in normal type/value format, so we take it to be the shortcut string notation */ param = value_string(paramArg); } } catch (exception const& e) { throwf("Failed to interpret parameter argument '%s'. %s", paramArg.c_str(), e.what()); } return param; } static paramList paramListFromParamArgs(vector const& params) { paramList paramList; for (vector::const_iterator p = params.begin(); p != params.end(); ++p) paramList.add(parameterFromArg(*p)); return paramList; } static void callWithClient(client * const clientP, string const& methodName, paramList const& paramList, value * const resultP) { rpcPtr myRpcP(methodName, paramList); carriageParm_pstream myCarriageParm; // Empty - no parm needed try { myRpcP->call(clientP, &myCarriageParm); } catch (exception const& e) { throwf("RPC failed. %s", e.what()); } *resultP = myRpcP->getResult(); } static void dumpResult(value const& result) { cout << "Result:" << endl << endl; /* Here we borrow code from inside Xmlrpc-c, and also use an internal interface of xmlrpc_c::value. This sliminess is one reason that this is Bryan's private code instead of part of the Xmlrpc-c package. Note that you must link with the dumpvalue.o object module from inside an Xmlrpc-c build tree. */ dumpValue("", result.cValueP); } static list parseWordList(string const& wordString) { list retval; unsigned int pos; pos = 0; while (pos < wordString.length()) { pos = wordString.find_first_not_of(' ', pos); if (pos < wordString.length()) { unsigned int const end = wordString.find_first_of(' ', pos); retval.push_back(wordString.substr(pos, end - pos)); pos = end; } } return retval; } static void parseCommand(string const& cmd, string * const methodNameP, vector * const paramListP) { list const wordList(parseWordList(cmd)); list::const_iterator cmdWordP; cmdWordP = wordList.begin(); if (cmdWordP == wordList.end()) throwf("Command '%s' does not have a method name", cmd.c_str()); else { *methodNameP = *cmdWordP++; *paramListP = vector(); // Start empty while (cmdWordP != wordList.end()) paramListP->push_back(*cmdWordP++); } } static void doCommand(client_xml * const clientP, string const& methodName, vector const& paramArgs) { value result; callWithClient(clientP, methodName, paramListFromParamArgs(paramArgs), &result); try { dumpResult(result); } catch(exception const& e) { throwf("Error showing result after RPC completed normally. %s", e.what()); } } static void getCommand(string * const cmdP, bool* const eofP) { const char * cmd; cmd = readline(">"); *eofP = (cmd == NULL); if (cmd != NULL) { *cmdP = string(cmd); free(const_cast(cmd)); } } static void doInteractive(client_xml * const clientP) { bool quitRequested; quitRequested = false; while (!quitRequested) { string cmd; bool eof; getCommand(&cmd, &eof); if (eof) { quitRequested = true; cout << endl; } else { try { string methodName; vector paramArgs; parseCommand(cmd, &methodName, ¶mArgs); doCommand(clientP, methodName, paramArgs); } catch (exception const& e) { cout << "Command failed. " << e.what() << endl; } } } } int main(int const argc, const char ** const argv) { try { cmdlineInfo cmdline(argc, argv); signal(SIGPIPE, SIG_IGN); clientXmlTransport_pstream myTransport( clientXmlTransport_pstream::constrOpt() .fd(cmdline.serverfd)); client_xml myClient(&myTransport); if (cmdline.interactive) { if (cmdline.serverfd == STDIN_FILENO || cmdline.serverfd == STDOUT_FILENO) throwf("Can't use Stdin or Stdout for the server fd when " "running interactively."); doInteractive(&myClient); } else doCommand(&myClient, cmdline.methodName, cmdline.params); } catch (exception const& e) { cerr << "Failed. " << e.what() << endl; } catch (...) { cerr << "Code threw unrecognized exception" << endl; abort(); } return 0; } xmlrpc-c-1.33.14/tools/xmlrpc_pstream/xmlrpc_pstream.html000066400000000000000000000134661236133176700235610ustar00rootroot00000000000000 Xmlrpc_pstream User Manual

xmlrpc_pstream makes a pseudo-XML-RPC remote procedure call (RPC) and displays the response. xmlrpc_pstream runs a pseudo-XML-RPC client.

The difference from true XML-RPC is that xmlrpc_pstream uses XML-RPC For C/C++'s "pstream" transport mechanism instead of HTTP. The pstream transport uses a simple TCP connection.

Examples



     $ socketexec -connect \
         -remote_host=localhost -remote_port=8080 --filedes=3 -- \
         xmlrpc_pstream --serverfd=3

     >sample.add i/3 i/5

       Result:
         Integer: 8



     $ socketexec -connect \
         -remote_host=localhost -remote_port=8080 --filedes=3 -- \
         xmlrpc_pstream sample.add i/3 i/5

       Result:
         Integer: 8

See the manual for the program xmlrpc for more examples; you specify the RPC arguments the same way.

Overview

xmlrpc_pstream [-serverfd=integer] [methodName [parameter ...]]

parameter:

i/integer | s/string | h/hexstring | b/{true|false|t|f} | d/realnum | n/ | string

Minimum unique abbreviation of option is acceptable. You may use double hyphens instead of single hyphen to denote options. You may use white space in place of the equals sign to separate an option name from its value.

Description

This program is mainly useful for debugging and learning about XML-RPC servers. XML-RPC is such that the RPCs normally need to be made by a program rather than a person to be of use.

You supply a TCP connection to the server as an open file descriptor. socketexec is a good way to create that socket and pass it to xmlrpc_pstream.

You run xmlrpc_pstream in one of two modes: interactive and single RPC.

In interactive mode, which you select by giving no arguments to the program, xmlrpc_pstream prompts you for RPCs using the Readline library. You type in an RPC description and xmlrpc_pstream executes it, then asks you for another. This continues until you close the readline session (usually by typing Control-D). Then, the program exits, which causes the server file descriptor to close, which causes the client-server TCP connection to close, which means the client-server XML-RPC connection terminates.

In single RPC mode, you give the RPC information as arguments to the program. xmlrpc_pstream executes one RPC, then exits. But note that when you invoke xmlrpc_pstream with socketexec in single RPC mode, you can't exploit one of the main purposes of a pstream transport: it lets you establish an RPC session with the server. With the single RPC socketexec method, socketexec establishes a session with the server (by creating the TCP connection), then xmlrpc_pstream performs one RPC in that session, then the OS closes the session as xmlrpc_pstream exits (by virtue of closing the TCP socket).

Arguments

There are no arguments in interactive mode. The fact that there are no arguments is what tells xmlrpc_pstream you want interactive mode.

For single RPC mode, the arguments are as follows.

methodName
The name of the XML-RPC method you want to invoke.
parameter ...
The list of parameters for the RPC. xmlrpc_pstream turns each of these arguments into an XML-RPC parameter, in the order given. You may specify no parameters if you like.

You specify the data type of the parameter with a prefix ending in a slash. Example: i/5. Here, the "i" signifies an integer data type. "5" is the value.

xmlrpc_pstream is capable of only a subset of the possible XML-RPC types, as follows by prefix:

i/
integer (<i4>) (32 bit)
s/
string (<string>)
h/
byte string (<base64>). Specify the value in hexadecimal.
b/
boolean (<boolean>). Specify the value as "true" or "t" for true; "false" or "f" for false.
d/
double (<double>) (i.e. real number)
n/
nil (<nil>)
I/
64 bit integer (<i8>)

As a shortcut, if you don't specify a prefix (i.e. your argument does not contain a slash), xmlrpc_pstream assumes string data type.

Options

-serverfd=integer
This identifies the client-server connection (and thus identifies the server). It is the file descriptor (an integer file handle) of the socket associated with an established TCP connection that you set up before invoking xmlrpc_pstream.

In interactive mode, don't use 0 or 1, because those are Standard Input and Standard Output and are used to communicate with you. 2 is a bad choice any time, because that is Standard Error and xmlrpc_pstream uses that to communicate with you.

socketexec is a good way to create the required socket. Use the socketexec's -filedes option to tell it what file descriptor to use for the socket, then use that same value on xmlrpc_pstream's -serverfd option.

The default is 3.

Interactive Commands

Example: > sample_add i/5 i/7

In interactive mode, xmlrpc_pstream prompts you for RPC calls with the prompt ">".

At the prompt, type a series of words, delimited by one or more blanks.

The first word is the XML-RPC method name.

The remaining words are the parameters of the XML-RPC method, in the same form as the xmlrpc_pstream arguments for single RPC mode. xmlrpc-c-1.33.14/tools/xmlrpc_transport/000077500000000000000000000000001236133176700202025ustar00rootroot00000000000000xmlrpc-c-1.33.14/tools/xmlrpc_transport/Makefile000066400000000000000000000021601236133176700216410ustar00rootroot00000000000000ifeq ($(SRCDIR),) updir = $(shell echo $(dir $(1)) | sed 's/.$$//') TOOLSDIR := $(call updir,$(CURDIR)) SRCDIR := $(call updir,$(TOOLSDIR)) BLDDIR := $(SRCDIR) endif SUBDIR := tools/xmlrpc_transport default: all include $(BLDDIR)/config.mk PROGRAMS_TO_INSTALL = xmlrpc_transport include $(SRCDIR)/tools/common.mk INCLUDES = \ -I$(BLDDIR) \ -I$(BLDDIR)/include \ -Isrcdir/include \ -Isrcdir/lib/util/include all: xmlrpc_transport ifeq ($(MSVCRT),yes) CLIENT_LDLIBS += -lws2_32 -lwsock32 -lpthread endif UTIL_OBJS = \ casprintf.o \ cmdline_parser.o \ getoptx.o \ stripcaseeq.o \ string_parser.o \ UTILS = $(UTIL_OBJS:%=$(UTIL_DIR)/%) xmlrpc_transport:%:%.o $(CLIENT_LIBS_DEP) $(UTILS) $(CCLD) -o $@ $(LDFLAGS_ALL) $< $(CLIENT_LDLIBS) $(UTILS) %.o:%.c $(CC) -c $(CFLAGS_ALL) $< # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. $(SRCDIR)/tools/common.mk: srcdir blddir include depend.mk .PHONY: dep dep: dep-common .PHONY: clean clean: clean-common rm -f xmlrpc_transport config.h .PHONY: distclean distclean: clean distclean-common xmlrpc-c-1.33.14/tools/xmlrpc_transport/xmlrpc_transport.c000066400000000000000000000161521236133176700237740ustar00rootroot00000000000000/* Transport some XML to a server and get the response back, as if doing an XML-RPC call. */ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include "xmlrpc_config.h" /* information about this build environment */ #include "casprintf.h" #include "mallocvar.h" #include "cmdline_parser.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/client.h" #define NAME "xmlrpc_transport command line program" #define VERSION "1.0" struct cmdlineInfo { const char * url; const char * username; const char * password; const char * transport; /* Name of XML transport he wants to use. NULL if he has no preference. */ }; static void die_if_fault_occurred (xmlrpc_env * const envP) { if (envP->fault_occurred) { fprintf(stderr, "Error: %s (%d)\n", envP->fault_string, envP->fault_code); exit(1); } } static void GNU_PRINTF_ATTR(2,3) setError(xmlrpc_env * const envP, const char format[], ...) { va_list args; const char * faultString; va_start(args, format); cvasprintf(&faultString, format, args); va_end(args); xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, faultString); strfree(faultString); } static void processArguments(xmlrpc_env * const envP, cmdlineParser const cp, struct cmdlineInfo * const cmdlineP) { if (cmd_argumentCount(cp) < 1) setError(envP, "Not enough arguments. Need a URL."); else { cmdlineP->url = cmd_getArgument(cp, 0); } } static void parseCommandLine(xmlrpc_env * const envP, int const argc, const char ** const argv, struct cmdlineInfo * const cmdlineP) { cmdlineParser const cp = cmd_createOptionParser(); const char * error; cmd_defineOption(cp, "transport", OPTTYPE_STRING); cmd_defineOption(cp, "username", OPTTYPE_STRING); cmd_defineOption(cp, "password", OPTTYPE_STRING); cmd_processOptions(cp, argc, argv, &error); if (error) { setError(envP, "Command syntax error. %s", error); strfree(error); } else { cmdlineP->username = cmd_getOptionValueString(cp, "username"); cmdlineP->password = cmd_getOptionValueString(cp, "password"); if (cmdlineP->username && !cmdlineP->password) setError(envP, "When you specify -username, you must also " "specify -password."); else { cmdlineP->transport = cmd_getOptionValueString(cp, "transport"); processArguments(envP, cp, cmdlineP); } } cmd_destroyOptionParser(cp); } static void freeCmdline(struct cmdlineInfo const cmdline) { strfree(cmdline.url); if (cmdline.username) strfree(cmdline.username); if (cmdline.password) strfree(cmdline.password); if (cmdline.transport) strfree(cmdline.transport); } static void computeUrl(const char * const urlArg, const char ** const urlP) { if (strstr(urlArg, "://") != 0) { *urlP = strdup(urlArg); } else { casprintf(urlP, "http://%s/RPC2", urlArg); } } static void doCall(xmlrpc_env * const envP, const char * const transport, const xmlrpc_server_info * const serverInfoP, xmlrpc_mem_block * const callXmlP, xmlrpc_mem_block ** const respXmlPP) { struct xmlrpc_clientparms clientparms; clientparms.transport = transport; clientparms.transportparmsP = NULL; clientparms.transportparm_size = 0; xmlrpc_client_init2(envP, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, &clientparms, XMLRPC_CPSIZE(transportparm_size)); if (!envP->fault_occurred) { xmlrpc_client_transport_call(envP, NULL, serverInfoP, callXmlP, respXmlPP); xmlrpc_client_cleanup(); } } static void createServerInfo(xmlrpc_env * const envP, const char * const serverUrl, const char * const userName, const char * const password, xmlrpc_server_info ** const serverInfoPP) { xmlrpc_server_info * serverInfoP; serverInfoP = xmlrpc_server_info_new(envP, serverUrl); if (!envP->fault_occurred) { if (userName) { xmlrpc_server_info_set_basic_auth( envP, serverInfoP, userName, password); } } *serverInfoPP = serverInfoP; } static void readFile(xmlrpc_env * const envP, FILE * const ifP, xmlrpc_mem_block ** const fileContentsPP) { xmlrpc_mem_block * fileContentsP; fileContentsP = XMLRPC_MEMBLOCK_NEW(char, envP, 0); while (!envP->fault_occurred && !feof(ifP)) { char buffer[4096]; size_t bytesRead; bytesRead = fread(buffer, 1, sizeof(buffer), ifP); XMLRPC_MEMBLOCK_APPEND(char, envP, fileContentsP, buffer, bytesRead); } if (envP->fault_occurred) XMLRPC_MEMBLOCK_FREE(char, fileContentsP); *fileContentsPP = fileContentsP; } static void writeFile(xmlrpc_env * const envP, FILE * const ofP, xmlrpc_mem_block * const fileContentsP) { size_t totalWritten; totalWritten = 0; while (!envP->fault_occurred && totalWritten < XMLRPC_MEMBLOCK_SIZE(char, fileContentsP)) { size_t bytesWritten; bytesWritten = fwrite( XMLRPC_MEMBLOCK_CONTENTS(char, fileContentsP) + totalWritten, 1, XMLRPC_MEMBLOCK_SIZE(char, fileContentsP) - totalWritten, ofP); if (bytesWritten < 1) xmlrpc_env_set_fault_formatted( envP, XMLRPC_INTERNAL_ERROR, "Error writing output"); totalWritten -= bytesWritten; } } int main(int const argc, const char ** const argv) { struct cmdlineInfo cmdline; xmlrpc_env env; xmlrpc_mem_block * callXmlP; xmlrpc_mem_block * respXmlP; const char * url; xmlrpc_server_info * serverInfoP; xmlrpc_env_init(&env); parseCommandLine(&env, argc, argv, &cmdline); die_if_fault_occurred(&env); computeUrl(cmdline.url, &url); createServerInfo(&env, url, cmdline.username, cmdline.password, &serverInfoP); die_if_fault_occurred(&env); fprintf(stderr, "Reading call data from Standard Input...\n"); readFile(&env, stdin, &callXmlP); die_if_fault_occurred(&env); fprintf(stderr, "Making call...\n"); doCall(&env, cmdline.transport, serverInfoP, callXmlP, &respXmlP); die_if_fault_occurred(&env); fprintf(stderr, "Writing response data to Standard Output\n"); writeFile(&env, stdout, respXmlP); die_if_fault_occurred(&env); XMLRPC_MEMBLOCK_FREE(char, callXmlP); XMLRPC_MEMBLOCK_FREE(char, respXmlP); strfree(url); freeCmdline(cmdline); xmlrpc_env_clean(&env); return 0; } xmlrpc-c-1.33.14/tools/xmlrpc_transport/xmlrpc_transport.html000066400000000000000000000055701236133176700245200ustar00rootroot00000000000000 Xmlrpc_transport User Manual

xmlrpc_transport transports data to a server as if to make an XML-RPC remote procedure call and displays the response from the server.

You supply the call in XML form on Standard Input and get the response in XML form on Standard Output. xmlrpc_transport doesn't really know anything about XML; it sends the characters you supply and displays the characters it gets back.

xmlrpc_transport uses the lower levels of the XML-RPC For C/C++ client libraries.

This program is mainly useful for debugging and learning about XML-RPC servers and the XML-RPC For C/C++ client XML transports.

Examples

<

     $ xmlrpc_transport http://localhost:8080/RPC2 <<-EOF
        <?xml version="1.0" encoding="UTF-8"?>
        <methodCall>
        <methodName>sample.add</methodName>
        <params>
        <param><value><i4>5</i4></value></param>
        <param><value><i4>7</i4></value></param>
        </params>
        </methodCall>
        EOF
     <?xml version="1.0" encoding="UTF-8"?>
     <methodResponse>
     <params>
     <param><value><i4>12</i4></value></param>
     </params>
     </methodResponse>

Overview

xmlrpc_transport url [-transport=transportname] [-username=username -password=password]

Minimum unique abbreviation of option is acceptable. You may use double hyphens instead of single hyphen to denote options. You may use white space in place of the equals sign to separate an option name from its value.

Arguments

url
This is the URL of the XML-RPC server. As XML-RPC uses HTTP, this must be an HTTP url. However, if you don't specify a type ("http:") in the URL, xmlrpc_transport assumes an "http://" prefix and a "/RPC2" suffix. RPC2 is the conventional file name for an XML-RPC responder.

Options

-transport=transportname
This selects the XML transport facility (e.g. libwww) that xmlrpc_transport uses to perform the RPC.

The name transportname is one that the Xmlrpc-c programming library recognizes. This is typically libwww, curl, and wininet.

By default, xmlrpc_transport lets the Xmlrpc-c library choose.

-username=username
-password=password
These options, which must be used together, cause the client to authenticate itself to the server, if the server requires it, using HTTP Basic Authentication and the specified username and password.
xmlrpc-c-1.33.14/transport_config.mk000066400000000000000000000020421236133176700173310ustar00rootroot00000000000000# -*-makefile-*- <-- an Emacs control # The make variables herein come from config.mk, which is included # by the make file that includes us. transport_config.h: $(BLDDIR)/config.mk rm -f $@ echo '/* This file was generated by a make rule */' >>$@ ifeq ($(MUST_BUILD_WININET_CLIENT),yes) echo '#define MUST_BUILD_WININET_CLIENT 1' >>$@ else echo '#define MUST_BUILD_WININET_CLIENT 0' >>$@ endif ifeq ($(MUST_BUILD_CURL_CLIENT),yes) echo '#define MUST_BUILD_CURL_CLIENT 1' >>$@ else echo '#define MUST_BUILD_CURL_CLIENT 0' >>$@ endif ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) echo '#define MUST_BUILD_LIBWWW_CLIENT 1' >>$@ else echo '#define MUST_BUILD_LIBWWW_CLIENT 0' >>$@ endif echo "static const char * const XMLRPC_DEFAULT_TRANSPORT =" >>$@ ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) echo '"libwww";' >>$@ else ifeq ($(MUST_BUILD_CURL_CLIENT),yes) echo '"curl";' >>$@ else ifeq ($(MUST_BUILD_WININET_CLIENT),yes) echo '"wininet";' >>$@ else @echo 'ERROR: no client XML transport configured'; rm $@; false endif endif endif xmlrpc-c-1.33.14/unix-common.mk000066400000000000000000000055421236133176700162310ustar00rootroot00000000000000# -*-makefile-*- <-- an Emacs control # The including make file must define these make variables: # # SHARED_LIBS_TO_BUILD: List of the shared libraries that need to be # built -- just the basic library names. E.g. "libfoo libbar" # # SHARED_LIBS_TO_INSTALL: List of the shared libraries that need to be # installed -- just the basic library names. E.g. "libfoo libbar" # # SHLIB_SUFFIX: Shared library filename suffix, e.g. "so". # # MAJ: Library major version number, e.g. "3" in file name "libfoo.3.1" # # MIN: Library minor version number, e.g. "1" in file name "libfoo.3.1" # # LDFLAGS_SHLIB: linker (Ld) flags needed to link object files together into # a shared library. May use $(SONAME) for the soname of the library. # Include -lc if appropriate. # # LADD: Additional linker flags (normally set on the make command line). # # INSTALL_DATA: beginning of shell command to install a library file. # # DESTDIR: main installation directory # # LIBINST_DIR: directory in which to install libraries, relative to DESTDIR. # # LN_S: beginning of shell command to make symbolic link (e.g. "ln -s"). # # CXXLD: beginning of shell command to link, e.g. "g++". # This make file defines these make variables that the including make file # can use: # # SHLIB_CMD: a command to build a shared library for C linkage # You can use this in a rule to build a shared library # SHLIBPP_CMD: Same, but for C++ linkage # Including make file must contain a rule to build each library file # (e.g. libfoo.3.1) # This make file provides these rules: # # install-shared-libraries: install all shared libraries and the necessary # symbolic links. # SONAME is to be referenced by $(LDFLAGS_SHLIB) in the rule to make # a shared library (in common.mk). I.e. $@ is the name of the shared # library file. # SONAME is the name of the library file being built, with the minor # version number cut off. E.g. if we're building libfoo.so.1.2, SONAME # is libfoo.so.1 . SONAME = $(@:%.$(MIN)=%) SHLIB_CMD = $(CCLD) $(LADD) $(LDFLAGS_SHLIB) -o $@ $^ SHLIB_LE_TARGETS = $(call shliblefn, $(SHARED_LIBS_TO_BUILD)) $(SHLIB_LE_TARGETS):%:%.$(MAJ) rm -f $@ $(LN_S) $< $@ SONAME_TARGETS = $(SHLIB_LE_TARGETS:%=%.$(MAJ)) $(SONAME_TARGETS):%:%.$(MIN) rm -f $@ $(LN_S) $< $@ .PHONY: $(SHLIB_INSTALL_TARGETS) .PHONY: install-shared-libraries SHLIB_INSTALL_TARGETS = $(SHARED_LIBS_TO_INSTALL:%=%/install) #SHLIB_INSTALL_TARGETS is like "libfoo/install libbar/install" install-shared-libraries: $(SHLIB_INSTALL_TARGETS) $(SHLIB_INSTALL_TARGETS):%/install:%.$(SHLIB_SUFFIX).$(MAJ).$(MIN) # $< is a library file name, e.g. libfoo.so.3.1 . $(INSTALL_SHLIB) $< $(DESTDIR)$(LIBINST_DIR)/$< cd $(DESTDIR)$(LIBINST_DIR); \ rm -f $(<:%.$(MIN)=%); \ $(LN_S) $< $(<:%.$(MIN)=%) cd $(DESTDIR)$(LIBINST_DIR); \ rm -f $(<:%.$(MAJ).$(MIN)=%); \ $(LN_S) $(<:%.$(MIN)=%) $(<:%.$(MAJ).$(MIN)=%) xmlrpc-c-1.33.14/version.mk000066400000000000000000000007431236133176700154430ustar00rootroot00000000000000############################################################################### # This is not only a make file inclusion, but a source file for the program # 'mkvers' in the Windows build system. The latter is very particular about # the format of this file. Do not change white space, add comment lines, or # anything! # # ############################################################################### XMLRPC_MAJOR_RELEASE = 1 XMLRPC_MINOR_RELEASE = 33 XMLRPC_POINT_RELEASE = 14 xmlrpc-c-1.33.14/xmlrpc-c-config.main000066400000000000000000000134041236133176700172610ustar00rootroot00000000000000usage="Usage: xmlrpc-c-config ...