libs/xmlrpc-c/GNUmakefile | 38 +- libs/xmlrpc-c/Windows/mkvers.bat | 10 +- libs/xmlrpc-c/Windows/rpctest.dsp | 10 +- libs/xmlrpc-c/Windows/transport_config_win32.h | 2 +- libs/xmlrpc-c/Windows/xmlrpc_win32_config.h | 2 +- libs/xmlrpc-c/common.mk | 67 +- libs/xmlrpc-c/config.mk.in | 47 +- libs/xmlrpc-c/configure.in | 7 +- libs/xmlrpc-c/dll-common.make | 6 +- libs/xmlrpc-c/dylib-common.make | 6 +- libs/xmlrpc-c/examples/Makefile | 36 +- libs/xmlrpc-c/examples/README | 16 +- libs/xmlrpc-c/examples/cpp/Makefile | 55 +- libs/xmlrpc-c/examples/cpp/pstream_client.cpp | 4 +- .../xmlrpc-c/examples/cpp/pstream_inetd_server.cpp | 4 +- libs/xmlrpc-c/examples/cpp/xmlrpc_inetd_server.cpp | 8 +- libs/xmlrpc-c/examples/interrupted_server.c | 10 +- libs/xmlrpc-c/examples/xmlrpc_inetd_server.c | 10 +- libs/xmlrpc-c/examples/xmlrpc_loop_server.c | 10 +- libs/xmlrpc-c/examples/xmlrpc_sample_add_server.c | 9 +- .../examples/xmlrpc_sample_add_server_cgi.c | 22 +- libs/xmlrpc-c/examples/xmlrpc_socket_server.c | 13 +- libs/xmlrpc-c/include/Makefile | 11 +- libs/xmlrpc-c/include/xmlrpc-c/abyss.h | 23 +- libs/xmlrpc-c/include/xmlrpc-c/base.h | 44 +- libs/xmlrpc-c/include/xmlrpc-c/base.hpp | 9 +- libs/xmlrpc-c/include/xmlrpc-c/c_util.h | 8 +- libs/xmlrpc-c/include/xmlrpc-c/server.h | 20 +- libs/xmlrpc-c/include/xmlrpc-c/string_int.h | 31 +- libs/xmlrpc-c/include/xmlrpc-c/timeout.hpp | 5 +- libs/xmlrpc-c/include/xmlrpc-c/util.h | 4 +- libs/xmlrpc-c/include/xmlrpc-c/util_int.h | 6 +- libs/xmlrpc-c/irix-common.make | 4 +- libs/xmlrpc-c/lib/abyss/src/Makefile | 4 +- libs/xmlrpc-c/lib/abyss/src/channel.c | 4 +- libs/xmlrpc-c/lib/abyss/src/channel.h | 4 +- libs/xmlrpc-c/lib/abyss/src/chanswitch.c | 5 +- libs/xmlrpc-c/lib/abyss/src/chanswitch.h | 3 +- libs/xmlrpc-c/lib/abyss/src/conf.c | 8 +- libs/xmlrpc-c/lib/abyss/src/conn.c | 55 +- libs/xmlrpc-c/lib/abyss/src/conn.h | 12 +- libs/xmlrpc-c/lib/abyss/src/file.c | 6 +- libs/xmlrpc-c/lib/abyss/src/handler.c | 5 +- libs/xmlrpc-c/lib/abyss/src/handler.h | 4 +- libs/xmlrpc-c/lib/abyss/src/http.c | 45 +- libs/xmlrpc-c/lib/abyss/src/main.c | 4 +- libs/xmlrpc-c/lib/abyss/src/response.c | 14 +- libs/xmlrpc-c/lib/abyss/src/server.c | 232 ++- libs/xmlrpc-c/lib/abyss/src/server.h | 10 +- libs/xmlrpc-c/lib/abyss/src/session.c | 4 +- libs/xmlrpc-c/lib/abyss/src/socket.c | 5 +- libs/xmlrpc-c/lib/abyss/src/socket.h | 5 +- libs/xmlrpc-c/lib/abyss/src/socket_unix.c | 111 +- libs/xmlrpc-c/lib/abyss/src/thread.h | 6 +- libs/xmlrpc-c/lib/abyss/src/thread_fork.c | 13 +- libs/xmlrpc-c/lib/abyss/src/thread_pthread.c | 74 +- libs/xmlrpc-c/lib/abyss/src/thread_windows.c | 28 +- libs/xmlrpc-c/lib/curl_transport/Makefile | 12 +- .../lib/curl_transport/xmlrpc_curl_transport.c | 1768 +++++--------------- libs/xmlrpc-c/lib/expat/gennmtab/Makefile | 2 +- libs/xmlrpc-c/lib/expat/xmltok/Makefile | 2 +- libs/xmlrpc-c/lib/expat/xmltok/xmltok_impl.c | 4 +- libs/xmlrpc-c/lib/libutil/Makefile | 2 +- libs/xmlrpc-c/lib/libutil/asprintf.c | 84 +- libs/xmlrpc-c/lib/libutil/make_printable.c | 4 +- libs/xmlrpc-c/lib/libutil/utf8.c | 39 +- libs/xmlrpc-c/lib/libwww_transport/Makefile | 6 +- libs/xmlrpc-c/lib/util/Makefile | 2 +- libs/xmlrpc-c/lib/util/casprintf.c | 85 +- libs/xmlrpc-c/lib/util/include/int.h | 12 +- libs/xmlrpc-c/lib/util/include/mallocvar.h | 3 +- libs/xmlrpc-c/lib/util/string_parser.c | 8 +- libs/xmlrpc-c/lib/util/stripcaseeq.c | 3 +- libs/xmlrpc-c/lib/wininet_transport/Makefile | 6 +- libs/xmlrpc-c/src/Makefile | 25 +- libs/xmlrpc-c/src/cpp/Makefile | 163 ++- libs/xmlrpc-c/src/cpp/base64.cpp | 4 +- libs/xmlrpc-c/src/cpp/client.cpp | 3 +- libs/xmlrpc-c/src/cpp/registry.cpp | 21 +- libs/xmlrpc-c/src/cpp/server_abyss.cpp | 7 +- libs/xmlrpc-c/src/cpp/test/Makefile | 2 +- libs/xmlrpc-c/src/cpp/test/registry.cpp | 24 +- libs/xmlrpc-c/src/cpp/test/test.cpp | 64 +- libs/xmlrpc-c/src/cpp/test/testclient.cpp | 4 +- libs/xmlrpc-c/src/cpp/value.cpp | 54 +- libs/xmlrpc-c/src/double.c | 27 +- libs/xmlrpc-c/src/method.c | 13 +- libs/xmlrpc-c/src/method.h | 7 +- libs/xmlrpc-c/src/parse_value.c | 42 +- libs/xmlrpc-c/src/registry.c | 62 +- libs/xmlrpc-c/src/system_method.c | 74 +- libs/xmlrpc-c/src/test/Makefile | 3 +- libs/xmlrpc-c/src/test/method_registry.c | 83 +- libs/xmlrpc-c/src/test/parse_xml.c | 25 +- libs/xmlrpc-c/src/test/serialize.c | 12 +- libs/xmlrpc-c/src/test/value.c | 197 +--- libs/xmlrpc-c/src/test/xml_data.h | 5 +- libs/xmlrpc-c/src/xmlrpc_datetime.c | 546 +++++-- libs/xmlrpc-c/src/xmlrpc_libxml2.c | 15 +- libs/xmlrpc-c/src/xmlrpc_serialize.c | 46 +- libs/xmlrpc-c/src/xmlrpc_server_abyss.c | 143 +- libs/xmlrpc-c/src/xmlrpc_server_cgi.c | 12 +- libs/xmlrpc-c/src/xmlrpc_server_info.c | 5 +- libs/xmlrpc-c/src/xmlrpc_server_w32httpsys.c | 11 +- libs/xmlrpc-c/tools/Makefile | 4 +- libs/xmlrpc-c/tools/common.mk | 4 +- libs/xmlrpc-c/tools/lib/Makefile | 6 +- libs/xmlrpc-c/tools/lib/dumpvalue.c | 10 +- libs/xmlrpc-c/tools/xml-rpc-api2cpp/Makefile | 6 +- libs/xmlrpc-c/tools/xmlrpc/Makefile | 6 +- libs/xmlrpc-c/tools/xmlrpc/xmlrpc.c | 4 +- libs/xmlrpc-c/tools/xmlrpc_cpp_proxy/Makefile | 4 +- libs/xmlrpc-c/tools/xmlrpc_pstream/Makefile | 8 +- .../tools/xmlrpc_pstream/xmlrpc_pstream.cpp | 3 +- libs/xmlrpc-c/tools/xmlrpc_transport/Makefile | 4 +- .../tools/xmlrpc_transport/xmlrpc_transport.c | 4 +- libs/xmlrpc-c/unix-common.make | 4 +- libs/xmlrpc-c/xmlrpc-c-config.main | 14 +- libs/xmlrpc-c/xmlrpc-c-config.test.main | 14 +- libs/xmlrpc-c/xmlrpc_amconfig.h.in | 5 +- libs/xmlrpc-c/xmlrpc_config.h.in | 24 +- src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c | 4 +- 122 files changed, 2602 insertions(+), 2485 deletions(-) diff --git a/libs/xmlrpc-c/GNUmakefile b/libs/xmlrpc-c/GNUmakefile index be7e423..12d3c00 100644 --- a/libs/xmlrpc-c/GNUmakefile +++ b/libs/xmlrpc-c/GNUmakefile @@ -1,4 +1,4 @@ -include Makefile.srcdir +include srcdir.mk BLDDIR = $(CURDIR) SUBDIR = @@ -6,7 +6,6 @@ SUBDIR = export SRCDIR export BLDDIR -include $(BLDDIR)/Makefile.version include $(BLDDIR)/config.mk SUBDIRS = include lib src tools examples @@ -28,6 +27,17 @@ 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) @@ -61,21 +71,14 @@ src/all: lib/all MAJOR := $(XMLRPC_MAJOR_RELEASE) MINOR := $(XMLRPC_MINOR_RELEASE) POINT := $(XMLRPC_POINT_RELEASE) -version.h: $(SRCDIR)/Makefile.version +version.h: $(SRCDIR)/version.mk rm -f $@ echo "/* Generated by make file rule */" >>$@ - echo "#define XMLRPC_C_VERSION" \ - \"Xmlrpc-c $(MAJOR).$(MINOR).$(POINT)"\"" >>$@ + 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)" >>$@ -# 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 - include transport_config.make # shell_config is a fragment to place inside a Bourne shell program that @@ -95,6 +98,7 @@ shell_config: $(BLDDIR)/config.mk @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_RPATH="$(WININET_RPATH)"' >>$@ @@ -116,9 +120,6 @@ shell_config: $(BLDDIR)/config.mk @echo 'ABS_SRCDIR="$(ABS_SRCDIR)"' >>$@ @echo '#######################################################' >>$@ -# We don't want config.mk's xmlrpc-c-config.test rule: -OMIT_XMLRPC_C_CONFIG_TEST = Y - xmlrpc-c-config xmlrpc-c-config.test:%: %.main shell_config rm -f $@ @echo "Echoes to '$@' suppressed here ..." @@ -140,7 +141,7 @@ clean-local: distclean: $(SUBDIRS:%=%/distclean) distclean-common distclean-local distclean-local: clean-local - rm -f config.log config.status config.mk Makefile.srcdir + 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 @@ -162,11 +163,8 @@ xmlrpc_config.h xmlrpc_amconfig.h \ :%:%.in $(SRCDIR)/configure $(SRCDIR)/configure -include $(SRCDIR)/common.mk - - # A trick to catch a common user error. When you don't run 'configure', -# you don't have a Makefile.srcdir, which means $(SRCDIR) is null. +# you don't have a srcdir.mk, which means $(SRCDIR) is null. /common.mk: @echo ======================================= @@ -180,4 +178,4 @@ include $(SRCDIR)/common.mk .PHONY: tags tags: find . -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" | \ - etags - + etags - \ No newline at end of file diff --git a/libs/xmlrpc-c/Windows/mkvers.bat b/libs/xmlrpc-c/Windows/mkvers.bat index 2f6ec1b..a57cf97 100644 --- a/libs/xmlrpc-c/Windows/mkvers.bat +++ b/libs/xmlrpc-c/Windows/mkvers.bat @@ -1,9 +1,9 @@ @if EXIST ..\version.h goto SHOW -@if NOT EXIST ..\Makefile.version goto ERR1 +@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 (..\Makefile.version) do @call mkvers1 %%i +@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 @@ -11,7 +11,7 @@ @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 "Xmlrpc-c %TEMPX1%.%TEMPX2%.%TEMPX3%" >> %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% @@ -35,7 +35,7 @@ type %TEMP1% :ERR1 -@echo Can not locate ..\Makefile.version ... check name, location ... +@echo Can not locate ..\version.mk ... check name, location ... @pause @goto END :ERR2 @@ -50,4 +50,4 @@ type %TEMP1% @pause @goto END -:END +:END \ No newline at end of file diff --git a/libs/xmlrpc-c/Windows/rpctest.dsp b/libs/xmlrpc-c/Windows/rpctest.dsp index 159692c..fc8c300 100644 --- a/libs/xmlrpc-c/Windows/rpctest.dsp +++ b/libs/xmlrpc-c/Windows/rpctest.dsp @@ -143,6 +143,14 @@ SOURCE=..\src\test\value.c # End Source File # Begin Source File +SOURCE=..\src\test\value_datetime.c +# End Source File +# Begin Source File + +SOURCE=..\src\test\value_datetime.h +# End Source File +# Begin Source File + SOURCE=..\src\test\xml_data.c # End Source File # End Group @@ -207,4 +215,4 @@ SOURCE=..\src\testdata\req_value_name.xml # End Source File # End Group # End Target -# End Project +# End Project \ No newline at end of file diff --git a/libs/xmlrpc-c/Windows/transport_config_win32.h b/libs/xmlrpc-c/Windows/transport_config_win32.h index 54bb9b5..5602233 100644 --- a/libs/xmlrpc-c/Windows/transport_config_win32.h +++ b/libs/xmlrpc-c/Windows/transport_config_win32.h @@ -10,4 +10,4 @@ #define MUST_BUILD_CURL_CLIENT 0 #define MUST_BUILD_LIBWWW_CLIENT 0 static const char * const XMLRPC_DEFAULT_TRANSPORT = -"wininet"; +"wininet"; \ No newline at end of file diff --git a/libs/xmlrpc-c/Windows/xmlrpc_win32_config.h b/libs/xmlrpc-c/Windows/xmlrpc_win32_config.h index e4e34fd..4e6cb28 100644 --- a/libs/xmlrpc-c/Windows/xmlrpc_win32_config.h +++ b/libs/xmlrpc-c/Windows/xmlrpc_win32_config.h @@ -155,4 +155,4 @@ #define strtoll _strtoui64 #define strtoull _strtoui64 -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/common.mk b/libs/xmlrpc-c/common.mk index 5b89fa1..5927f90 100644 --- a/libs/xmlrpc-c/common.mk +++ b/libs/xmlrpc-c/common.mk @@ -9,7 +9,7 @@ # 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)/Makefile.version +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, @@ -17,7 +17,7 @@ include $(SRCDIR)/Makefile.version # fully made. .DELETE_ON_ERROR: -GCC_WARNINGS = -Wall -Wundef -Wimplicit -W -Winline -Wundef +GCC_WARNINGS = -Wall -Wundef -Wimplicit -W -Winline # We need -Wwrite-strings after we fix all the missing consts GCC_C_WARNINGS = $(GCC_WARNINGS) \ @@ -55,12 +55,21 @@ 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 + ############################################################################## # STATIC LINK LIBRARY RULES # ############################################################################## -# To use this rule, the including make file must set a target_specific +# 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 @@ -127,10 +136,10 @@ endif #------ the actual rules ---------------------------------------------------- $(TARGET_SHARED_LIBRARIES) dummyshlib: - $(CCLD) $(LDFLAGS_SHLIB) $(LIBDEP) -o $@ $(LIBOBJECTS) $(LADD) + $(CCLD) $(LADD) $(LDFLAGS_SHLIB) $(LIBOBJECTS) $(LIBDEP) -o $@ $(TARGET_SHARED_LIBS_PP) dummyshlibpp: - $(CXXLD) $(LDFLAGS_SHLIB) $(LIBDEP) -o $@ $(LIBOBJECTS) $(LADD) + $(CXXLD) $(LADD) $(LDFLAGS_SHLIB) $(LIBOBJECTS) $(LIBDEP) -o $@ #---------------------------------------------------------------------------- LIBXMLRPC_UTIL_DIR = $(BLDDIR)/lib/libutil @@ -186,7 +195,6 @@ LIBXMLRPC_ABYSS = \ LIBXMLRPC_ABYSS_A = $(LIBXMLRPC_ABYSS_DIR)/libxmlrpc_abyss.a endif -ifneq ($(OMIT_CPP_LIB_RULES),Y) LIBXMLRPC_CPP = \ $(call shliblefn, $(BLDDIR)/src/cpp/libxmlrpc_cpp) LIBXMLRPC_CPP_A = $(BLDDIR)/src/cpp/libxmlrpc_cpp.a @@ -208,7 +216,6 @@ 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 -endif # 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. @@ -239,7 +246,7 @@ endif # foo.o foo.osh: INCLUDES = -Iinclude -I/usr/include/foostuff # bar.o bar.osh: INCLUDES = -Iinclude -I/usr/include/barstuff # -# include Makefile.common +# include common.mk # # The above generates rules to build foo.o, bar.o, foo.osh, and bar.osh # @@ -343,6 +350,12 @@ 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 $@) @@ -385,6 +398,8 @@ $(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) \ @@ -394,6 +409,7 @@ $(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 @@ -421,12 +437,12 @@ 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 (Makefile.depend), it doesn't exist yet. This means Gcc +# 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 Makefile.common, so the rules +# 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) @@ -471,9 +487,9 @@ $(SUBDIRS:%=$(CURDIR)/%): MKINSTALLDIRS = $(SHELL) $(SRCDIR)/mkinstalldirs -.PHONY: install-common install-ltlibraries install-headers install-bin +.PHONY: install-common install-headers install-bin install-common: \ - install-ltlibraries install-static-libraries install-shared-libraries \ + install-static-libraries install-shared-libraries \ install-headers install-bin INSTALL_LIB_CMD = $(INSTALL_DATA) $$p $(DESTDIR)$(LIBINST_DIR)/$$p @@ -536,29 +552,30 @@ endif .PHONY: distclean-common distclean-common: -# Makefile.depend is generated by 'make dep' and contains only dependencies +# 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 Makefile.depend. +# besides depend.mk. # -# Because of this, a user doesn't need Makefile.depend, because he +# 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 Makefile.depend, because 'make dep' creates Makefile.depend with +# own depend.mk, because 'make dep' creates depend.mk with # absolute pathnames, specific to the developer's system. # -# So we obliterate Makefile.depend here. The build will automatically -# create an empty Makefile.depend when it is needed for the user. The +# 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 -# Makefile.depend, suitable for a developer. We have found that to be +# 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 Makefile.depend + rm -f depend.mk + rm -f Makefile.depend # We used to create a file by this name rm -f srcdir blddir .PHONY: distdir-common @@ -589,17 +606,17 @@ dep-common: FORCE ifneq ($(DEP_SOURCES)x,x) -$(CC) -MM -MG -I. $(INCLUDES) $(DEP_SOURCES) | \ $(DEPEND_MASSAGER) \ - >Makefile.depend + >depend.mk endif -Makefile.depend: +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 Makefile.depend an empty file. A -# developer may do 'make dep' to create a Makefile.depend full of real +# '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. @@ -608,4 +625,4 @@ Makefile.depend: # Use the FORCE target as a dependency to force a target to get remade -FORCE: +FORCE: \ No newline at end of file diff --git a/libs/xmlrpc-c/config.mk.in b/libs/xmlrpc-c/config.mk.in index b583e6e..ee50b0a 100644 --- a/libs/xmlrpc-c/config.mk.in +++ b/libs/xmlrpc-c/config.mk.in @@ -164,7 +164,10 @@ MUST_BUILD_SHLIBLE = N shlibfn = $(1:%=%.shlibdummy) shliblefn = $(1:%=%.shlibledummy) -ifeq ($(HOST_OS),linux-gnu) +# 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 @@ -177,7 +180,7 @@ ifeq ($(HOST_OS),linux-gnu) CFLAGS_SHLIB=-fPIC endif -ifeq ($(findstring solaris,$(HOST_OS)),solaris) +ifeq ($(patsubst solaris%,solaris,$(HOST_OS)),solaris) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y @@ -190,7 +193,7 @@ ifeq ($(findstring solaris,$(HOST_OS)),solaris) CFLAGS_SHLIB = -Kpic endif -ifeq ($(HOST_OS),aix) +ifeq ($(patsubst aix%,aix,$(HOST_OS)),aix) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y @@ -200,7 +203,7 @@ ifeq ($(HOST_OS),aix) LDFLAGS_SHLIB = -qmkshrobj endif -ifeq ($(HOST_OS),hpux) +ifeq ($(patsubst hpux%,hpux,$(HOST_OS)),hpux) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y @@ -210,7 +213,7 @@ ifeq ($(HOST_OS),hpux) LDFLAGS_SHLIB: -shared -fPIC endif -ifeq ($(HOST_OS),osf) +ifeq ($(patsubst osf%,osf,$(HOST_OS)),osf) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y @@ -220,7 +223,19 @@ ifeq ($(HOST_OS),osf) LDFLAGS_SHLIB = -shared -expect_unresolved endif -ifeq ($(findstring netbsd,$(HOST_OS)),netbsd) +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 @@ -232,7 +247,7 @@ ifeq ($(findstring netbsd,$(HOST_OS)),netbsd) NEED_WL_RPATH=yes endif -ifeq ($(HOST_OS),dragonfly) +ifeq ($(patsubst dragonfly%,dragonfly,$(HOST_OS)),dragonfly) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y @@ -243,7 +258,7 @@ ifeq ($(HOST_OS),dragonfly) LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) endif -ifeq ($(HOST_OS),beos) +ifeq ($(patsubst beos%,beos,$(HOST_OS)),beos) SHARED_LIB_TYPE = unix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y @@ -253,18 +268,18 @@ ifeq ($(HOST_OS),beos) LDFLAGS_SHLIB = -nostart endif -ifeq ($(patsubst darwin%, darwin, $(HOST_OS)), darwin) - # (I once saw a system that generated 'darwin8.10.1'). +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 = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) + LDFLAGS_SHLIB = -dynamiclib -undefined suppress -single_module \ + -flat_namespace $(SHLIB_CLIB) endif -ifeq ($(HOST_OS),irix) +ifeq ($(patsubst irix%,irix,$(HOST_OS)),irix) SHARED_LIB_TYPE = irix MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = Y @@ -278,13 +293,13 @@ ifeq ($(HOST_OS),irix) -set_version $(shell perl -e '$(VERSIONPERLPROG)') -lc endif -ifeq ($(HOST_OS),cygwin) +ifeq ($(patsubst cygwin%,cygwin,$(HOST_OS)),cygwin) SHARED_LIB_TYPE = dll MUST_BUILD_SHLIB = Y MUST_BUILD_SHLIBLE = N SHLIB_SUFFIX = dll - shlibfn = $(1:lib%=$(SHLIB_PREFIX)%.$(SHLIB_SUFFIX).$(MAJ).$(MIN)) - shliblefn = $(1:%=%.shlibledummy) + shlibfn = $(1:%=%.$(SHLIB_SUFFIX)) + shliblefn = $(1:%=%.$(SHLIB_SUFFIX)) LDFLAGS_SHLIB = -shared -Wl,-soname,$(SONAME) $(SHLIB_CLIB) endif @@ -333,4 +348,4 @@ DESTDIR = # you to build in a fresh build directory, while your source stays in # the read-only directory /usr/src/mypkg . -VPATH := .:$(SRCDIR)/$(SUBDIR) +VPATH := .:$(SRCDIR)/$(SUBDIR) \ No newline at end of file diff --git a/libs/xmlrpc-c/configure.in b/libs/xmlrpc-c/configure.in index 231a1d3..59f3096 100644 --- a/libs/xmlrpc-c/configure.in +++ b/libs/xmlrpc-c/configure.in @@ -198,7 +198,9 @@ dnl Checks for programs. dnl ======================================================================= AC_PROG_CC -AC_PROG_CXX +if test x"$enable_cplusplus" != xno; then + AC_PROG_CXX +fi dnl ======================================================================= @@ -632,7 +634,7 @@ dnl Note that AM_CONFIG_HEADER at the top of this file outputs another dnl result: xmlrpc_amconfig.h . AC_OUTPUT( \ - Makefile.srcdir \ + srcdir.mk \ config.mk \ xmlrpc_config.h \ ) @@ -650,4 +652,3 @@ if test "$MUST_BUILD_WININET_CLIENT $MUST_BUILD_CURL_CLIENT $MUST_BUILD_LIBWWW_C AC_MSG_NOTICE([\n\n==>We are not building any client XML transport (see earlier messages explaining why), therefore WE WILL NOT BUILD THE CLIENT LIBRARY.]) fi - diff --git a/libs/xmlrpc-c/dll-common.make b/libs/xmlrpc-c/dll-common.make index 0d53c17..9051c3f 100644 --- a/libs/xmlrpc-c/dll-common.make +++ b/libs/xmlrpc-c/dll-common.make @@ -17,6 +17,6 @@ SHLIB_INSTALL_TARGETS = $(SHARED_LIBS_TO_INSTALL:%=%/install) install-shared-libraries: $(SHLIB_INSTALL_TARGETS) -$(SHLIB_INSTALL_TARGETS):lib%/install:$(SHLIB_PREFIX)%.$(SHLIB_SUFFIX).$(MAJ).$(MIN) -# $< is a library file name, e.g. cygfoo.so.3.1 . - $(INSTALL_SHLIB) $< $(DESTDIR)$(LIBINST_DIR)/$< +$(SHLIB_INSTALL_TARGETS):%/install:%.$(SHLIB_SUFFIX) +# $< is a library file name, e.g. libfoo.dll . + $(INSTALL_SHLIB) $< $(DESTDIR)$(LIBINST_DIR)/$< \ No newline at end of file diff --git a/libs/xmlrpc-c/dylib-common.make b/libs/xmlrpc-c/dylib-common.make index a72d416..7bb9818 100644 --- a/libs/xmlrpc-c/dylib-common.make +++ b/libs/xmlrpc-c/dylib-common.make @@ -5,9 +5,9 @@ SONAME = $(@:%.$(MIN)=%) -SHLIB_CMD = $(CCLD) $(LDFLAGS_SHLIB) -o $@ $^ $(LADD) +SHLIB_CMD = $(CCLD) $(LADD) $(LDFLAGS_SHLIB) -o $@ $^ -SHLIBPP_CMD = $(CXXLD) $(LDFLAGS_SHLIB) -o $@ $^ $(LADD) +SHLIBPP_CMD = $(CXXLD) $(LADD) $(LDFLAGS_SHLIB) -o $@ $^ SHLIB_LE_TARGETS = $(call shliblefn, $(SHARED_LIBS_TO_BUILD)) @@ -34,4 +34,4 @@ $(SHLIB_INSTALL_TARGETS):%/install:%.$(MAJ).$(MIN).$(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)) + $(<:%.$(MAJ).$(MIN).$(SHLIB_SUFFIX)=%.$(SHLIB_SUFFIX)) \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/Makefile b/libs/xmlrpc-c/examples/Makefile index 5a9fd19..a69ff17 100644 --- a/libs/xmlrpc-c/examples/Makefile +++ b/libs/xmlrpc-c/examples/Makefile @@ -15,8 +15,8 @@ include $(BLDDIR)/config.mk default: all -CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) -LDFLAGS = $(LADD) +CFLAGS = $(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 @@ -63,17 +63,17 @@ endif INCLUDES = -I. $(shell $(XMLRPC_C_CONFIG) client abyss-server --cflags) -LDADD_CLIENT = \ - $(shell $(XMLRPC_C_CONFIG) client --ldadd) +LIBS_CLIENT = \ + $(shell $(XMLRPC_C_CONFIG) client --libs) -LDADD_SERVER_ABYSS = \ - $(shell $(XMLRPC_C_CONFIG) abyss-server --ldadd) +LIBS_SERVER_ABYSS = \ + $(shell $(XMLRPC_C_CONFIG) abyss-server --libs) -LDADD_SERVER_CGI = \ - $(shell $(XMLRPC_C_CONFIG) cgi-server --ldadd) +LIBS_SERVER_CGI = \ + $(shell $(XMLRPC_C_CONFIG) cgi-server --libs) -LDADD_BASE = \ - $(shell $(XMLRPC_C_CONFIG) --ldadd) +LIBS_BASE = \ + $(shell $(XMLRPC_C_CONFIG) --libs) all: $(PROGS) @@ -90,16 +90,16 @@ $(BLDDIR)/examples/cpp: mkdir $@ $(CLIENTPROGS):%:%.o - $(CCLD) -o $@ $(LDFLAGS) $^ $(LDADD_CLIENT) + $(CCLD) -o $@ $^ $(LIBS_CLIENT) $(LDFLAGS) $(SERVERPROGS_CGI):%.cgi:%_cgi.o - $(CCLD) -o $@ $(LDFLAGS) $^ $(LDADD_SERVER_CGI) + $(CCLD) -o $@ $^ $(LIBS_SERVER_CGI) $(LDFLAGS) $(SERVERPROGS_ABYSS):%:%.o - $(CCLD) -o $@ $(LDFLAGS) $^ $(LDADD_SERVER_ABYSS) + $(CCLD) -o $@ $^ $(LIBS_SERVER_ABYSS) $(LDFLAGS) gen_sample_add_xml:%:%.o - $(CCLD) -o $@ $(LDFLAGS) $^ $(LDADD_BASE) + $(CCLD) -o $@ $^ $(LIBS_BASE) $(LDFLAGS) OBJECTS = $(patsubst %,%.o,$(patsubst %.cgi,%_cgi,$(PROGS))) @@ -119,11 +119,9 @@ config.h: xmlrpc_amconfig.h: $(LN_S) $(BLDDIR)/$@ . -include $(SRCDIR)/common.mk - .PHONY: clean -clean: clean-common - rm -f $(PROGS) config.h xmlrpc_amconfig.h +clean: + rm -f $(PROGS) *.o config.h xmlrpc_amconfig.h $(MAKE) -C cpp clean .PHONY: distclean @@ -155,4 +153,4 @@ 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. +# carefully clean and remake examples as he updates other parts of the tree. \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/README b/libs/xmlrpc-c/examples/README index 46b02b4..f9c75e3 100644 --- a/libs/xmlrpc-c/examples/README +++ b/libs/xmlrpc-c/examples/README @@ -1,15 +1,12 @@ This directory contains working examples of uses of XML-RPC-c. There are XML-RPC servers and XML-RPC clients that use the Xmlrpc-c libraries. -The simplest example is the 'query-meerkat' program, which contacts an -XML-RPC server that O'Reilly operates on the Internet called Meerkat. -Meerkat provides an RPC that returns a list of new articles that match -a specified search pattern. Run 'query-meerkat' like this example: - - $ ./query-meerkat Linux - -This responds with a list of new articles that contain the work "Linux", -according to O'reilly's Meerkat service. +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). Then +you can issue a simple 'make' in this directory. The simplest server program is 'xmlrpc_sample_add_server'. This @@ -31,4 +28,3 @@ print the result on Standard Output. You can run such a client like this: $ ./xmlrpc_sample_add_client - diff --git a/libs/xmlrpc-c/examples/cpp/Makefile b/libs/xmlrpc-c/examples/cpp/Makefile index 1c8b930..2ecc762 100644 --- a/libs/xmlrpc-c/examples/cpp/Makefile +++ b/libs/xmlrpc-c/examples/cpp/Makefile @@ -15,8 +15,8 @@ include $(BLDDIR)/config.mk default: all -CXXFLAGS = $(CXXFLAGS_COMMON) $(CFLAGS_PERSONAL) $(CADD) -LDFLAGS = $(LADD) +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 @@ -24,6 +24,9 @@ LDFLAGS = $(LADD) XMLRPC_C_CONFIG = $(BLDDIR)/xmlrpc-c-config.test +SERVERPROGS_CGI = \ + xmlrpc_sample_add_server.cgi + SERVERPROGS_ABYSS = \ xmlrpc_inetd_server \ xmlrpc_loop_server \ @@ -45,6 +48,10 @@ ifeq ($(MUST_BUILD_CLIENT),yes) PROGS += $(CLIENTPROGS) endif +ifeq ($(ENABLE_CGI_SERVER),yes) + PROGS += $(SERVERPROGS_CGI) +endif + PROGS += pstream_inetd_server ifeq ($(MUST_BUILD_CLIENT),yes) @@ -53,37 +60,43 @@ endif INCLUDES = -I. $(shell $(XMLRPC_C_CONFIG) c++2 client abyss-server --cflags) -LDADD_SERVER_ABYSS = \ - $(shell $(XMLRPC_C_CONFIG) c++2 abyss-server --ldadd) +LIBS_SERVER_ABYSS = \ + $(shell $(XMLRPC_C_CONFIG) c++2 abyss-server --libs) -LDADD_CLIENT = \ - $(shell $(XMLRPC_C_CONFIG) c++2 client --ldadd) +LIBS_SERVER_CGI = \ + $(shell $(XMLRPC_C_CONFIG) c++2 cgi-server --libs) -LDADD_BASE = \ - $(shell $(XMLRPC_C_CONFIG) c++2 --ldadd) +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 $@ $(LDFLAGS) $^ $(LDADD_SERVER_ABYSS) + $(CXXLD) -o $@ $^ $(LIBS_SERVER_ABYSS) $(LDFLAGS) $(CLIENTPROGS):%:%.o - $(CXXLD) -o $@ $(LDFLAGS) $^ $(LDADD_CLIENT) + $(CXXLD) -o $@ $^ $(LIBS_CLIENT) $(LDFLAGS) -LDADD_PSTREAM_CLIENT = \ - $(shell $(XMLRPC_C_CONFIG) c++2 client --ldadd) +LIBS_PSTREAM_CLIENT = \ + $(shell $(XMLRPC_C_CONFIG) c++2 client --libs) pstream_client:%:%.o - $(CXXLD) -o $@ $(LDFLAGS) $^ $(LDADD_PSTREAM_CLIENT) + $(CXXLD) -o $@ $^ $(LIBS_PSTREAM_CLIENT) $(LDFLAGS) -LDADD_PSTREAM_SERVER = \ - $(shell $(XMLRPC_C_CONFIG) c++2 pstream-server --ldadd) +LIBS_PSTREAM_SERVER = \ + $(shell $(XMLRPC_C_CONFIG) c++2 pstream-server --libs) pstream_inetd_server:%:%.o - $(CXXLD) -o $@ $(LDFLAGS) $^ $(LDADD_PSTREAM_SERVER) + $(CXXLD) -o $@ $^ $(LIBS_PSTREAM_SERVER) $(LDFLAGS) -OBJECTS = $(PROGS:%=%.o) +OBJECTS = $(patsubst %,%.o,$(patsubst %.cgi,%_cgi,$(PROGS))) $(OBJECTS):%.o:%.cpp $(CXX) -c $(INCLUDES) $(CXXFLAGS) $< @@ -97,11 +110,9 @@ config.h: xmlrpc_amconfig.h: $(LN_S) $(BLDDIR)/$@ . -include $(SRCDIR)/common.mk - .PHONY: clean -clean: clean-common - rm -f $(PROGS) config.h xmlrpc_amconfig.h +clean: + rm -f $(PROGS) *.o config.h xmlrpc_amconfig.h .PHONY: distclean distclean: clean @@ -111,4 +122,4 @@ 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. +# carefully clean and remake examples as he updates other parts of the tree. \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/cpp/pstream_client.cpp b/libs/xmlrpc-c/examples/cpp/pstream_client.cpp index 7a8f322..d90dd25 100644 --- a/libs/xmlrpc-c/examples/cpp/pstream_client.cpp +++ b/libs/xmlrpc-c/examples/cpp/pstream_client.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -81,4 +81,4 @@ main(int argc, char **) { } return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/cpp/pstream_inetd_server.cpp b/libs/xmlrpc-c/examples/cpp/pstream_inetd_server.cpp index 65f1aa5..d6a58e2 100644 --- a/libs/xmlrpc-c/examples/cpp/pstream_inetd_server.cpp +++ b/libs/xmlrpc-c/examples/cpp/pstream_inetd_server.cpp @@ -22,7 +22,7 @@ #endif #include #include -#include +#include #include #include @@ -87,4 +87,4 @@ main(int const, cerr << "Something threw an error: " << e.what() << endl; } return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/cpp/xmlrpc_inetd_server.cpp b/libs/xmlrpc-c/examples/cpp/xmlrpc_inetd_server.cpp index 0dd902a..98e0bb1 100644 --- a/libs/xmlrpc-c/examples/cpp/xmlrpc_inetd_server.cpp +++ b/libs/xmlrpc-c/examples/cpp/xmlrpc_inetd_server.cpp @@ -49,14 +49,12 @@ main(int const, myRegistry.addMethod("sample.add", sampleAddMethodP); xmlrpc_c::serverAbyss myAbyssServer( - myRegistry, - 8080, // TCP port on which to listen - "/tmp/xmlrpc_log" // Log file - ); + 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; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/interrupted_server.c b/libs/xmlrpc-c/examples/interrupted_server.c index 9d5c593..ad0fe5b 100644 --- a/libs/xmlrpc-c/examples/interrupted_server.c +++ b/libs/xmlrpc-c/examples/interrupted_server.c @@ -105,6 +105,11 @@ 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; @@ -126,8 +131,7 @@ main(int const argc, registryP = xmlrpc_registry_new(&env); dieIfFailed("xmlrpc_registry_new", env); - xmlrpc_registry_add_method2( - &env, registryP, "sample.add", &sample_add, NULL, NULL, NULL); + xmlrpc_registry_add_method3(&env, registryP, &methodInfo); dieIfFailed("xmlrpc_registry_add_method2", env); serverparm.config_file_name = NULL; @@ -158,4 +162,4 @@ main(int const argc, xmlrpc_env_clean(&env); return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/xmlrpc_inetd_server.c b/libs/xmlrpc-c/examples/xmlrpc_inetd_server.c index 196b42a..2eaad93 100644 --- a/libs/xmlrpc-c/examples/xmlrpc_inetd_server.c +++ b/libs/xmlrpc-c/examples/xmlrpc_inetd_server.c @@ -86,6 +86,11 @@ 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; @@ -101,8 +106,7 @@ main(int const argc, registryP = xmlrpc_registry_new(&env); - xmlrpc_registry_add_method2( - &env, registryP, "sample.add", &sample_add, NULL, NULL, NULL); + xmlrpc_registry_add_method3(&env, registryP, &methodInfo); ServerCreateNoAccept(&abyssServer, "XmlRpcServer", NULL, NULL); @@ -118,4 +122,4 @@ main(int const argc, ServerFree(&abyssServer); return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/xmlrpc_loop_server.c b/libs/xmlrpc-c/examples/xmlrpc_loop_server.c index 2553ea6..ce2cfcd 100644 --- a/libs/xmlrpc-c/examples/xmlrpc_loop_server.c +++ b/libs/xmlrpc-c/examples/xmlrpc_loop_server.c @@ -117,6 +117,11 @@ 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; @@ -136,8 +141,7 @@ main(int const argc, registryP = xmlrpc_registry_new(&env); - xmlrpc_registry_add_method2( - &env, registryP, "sample.add", &sample_add, NULL, NULL, NULL); + xmlrpc_registry_add_method3(&env, registryP, &methodInfo); xmlrpc_registry_set_shutdown(registryP, &requestShutdown, &terminationRequested); @@ -167,4 +171,4 @@ main(int const argc, AbyssTerm(); return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/xmlrpc_sample_add_server.c b/libs/xmlrpc-c/examples/xmlrpc_sample_add_server.c index dbd2861..1e30af5 100644 --- a/libs/xmlrpc-c/examples/xmlrpc_sample_add_server.c +++ b/libs/xmlrpc-c/examples/xmlrpc_sample_add_server.c @@ -54,6 +54,10 @@ 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; @@ -70,8 +74,7 @@ main(int const argc, registryP = xmlrpc_registry_new(&env); - xmlrpc_registry_add_method2( - &env, registryP, "sample.add", &sample_add, NULL, NULL, NULL); + 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 @@ -89,4 +92,4 @@ main(int const argc, /* xmlrpc_server_abyss() never returns */ return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/xmlrpc_sample_add_server_cgi.c b/libs/xmlrpc-c/examples/xmlrpc_sample_add_server_cgi.c index fa476a7..134a9ce 100644 --- a/libs/xmlrpc-c/examples/xmlrpc_sample_add_server_cgi.c +++ b/libs/xmlrpc-c/examples/xmlrpc_sample_add_server_cgi.c @@ -1,4 +1,22 @@ -/* A simple standalone XML-RPC server written in C. */ +/* 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 @@ -54,4 +72,4 @@ main(int const argc, xmlrpc_registry_free(registryP); return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/examples/xmlrpc_socket_server.c b/libs/xmlrpc-c/examples/xmlrpc_socket_server.c index 2e2cd8b..bf9e3d1 100644 --- a/libs/xmlrpc-c/examples/xmlrpc_socket_server.c +++ b/libs/xmlrpc-c/examples/xmlrpc_socket_server.c @@ -33,7 +33,8 @@ static xmlrpc_value * sample_add(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, - void * const user_data ATTR_UNUSED) { + void * const serverInfo ATTR_UNUSED, + void * const channelInfo ATTR_UNUSED) { xmlrpc_int32 x, y, z; @@ -61,6 +62,11 @@ 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; @@ -77,8 +83,7 @@ main(int const argc, registryP = xmlrpc_registry_new(&env); - xmlrpc_registry_add_method( - &env, registryP, NULL, "sample.add", &sample_add, NULL); + 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 @@ -99,4 +104,4 @@ main(int const argc, xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(socket_handle)); return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/include/Makefile b/libs/xmlrpc-c/include/Makefile index d396ca7..e555173 100644 --- a/libs/xmlrpc-c/include/Makefile +++ b/libs/xmlrpc-c/include/Makefile @@ -58,7 +58,7 @@ $(BLDDIR)/$(SUBDIR)/xmlrpc-c: 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_server_abyss.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 = \ @@ -119,11 +119,12 @@ default: all all: .PHONY: install-compat-hdr -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_server_w32httpsys.h \ + xmlrpc_server_abyss.h xmlrpc_abyss.h \ + xmlrpc_server_w32httpsys.h \ XmlRpcCpp.h; \ $(COMPAT_LINK_CMDS) @@ -132,8 +133,8 @@ install: install-common install-compat-hdr .PHONY: clean distclean dep clean: -distclean: rm -f xmlrpc-c/config.h +distclean: clean .PHONY: check check: @@ -143,4 +144,4 @@ dep: OMIT_CONFIG_H_RULE = Y -include $(SRCDIR)/common.mk +include $(SRCDIR)/common.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/include/xmlrpc-c/abyss.h b/libs/xmlrpc-c/include/xmlrpc-c/abyss.h index e044008..37f5685 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/abyss.h +++ b/libs/xmlrpc-c/include/xmlrpc-c/abyss.h @@ -242,15 +242,30 @@ typedef abyss_bool (*URIHandler) (TSession *); /* deprecated */ struct URIHandler2; -typedef void (*initHandlerFn)(struct URIHandler2 *, - abyss_bool *); +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 */ +}; + +void +ServerAddHandler3(TServer * const serverP, + const struct ServerReqHandler3 * const handlerP, + abyss_bool * const successP); + typedef struct URIHandler2 { initHandlerFn init; termHandlerFn term; @@ -460,7 +475,7 @@ MIMETypeGuessFromFile(const char * const filename); ** Maximum number of simultaneous connections *********************************************************************/ -#define MAX_CONN 100000 +#define MAX_CONN 16 /********************************************************************* ** General purpose definitions @@ -542,4 +557,4 @@ abyss_bool SessionLog(TSession * const s); ** SUCH DAMAGE. ** ******************************************************************************/ -#endif /* _ABYSS_H_ */ +#endif /* _ABYSS_H_ */ \ No newline at end of file diff --git a/libs/xmlrpc-c/include/xmlrpc-c/base.h b/libs/xmlrpc-c/include/xmlrpc-c/base.h index a68a4f1..e48fc51 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/base.h +++ b/libs/xmlrpc-c/include/xmlrpc-c/base.h @@ -8,12 +8,16 @@ #include #include #include - /* Defines XMLRPC_HAVE_WCHAR, XMLRPC_INT64 */ + /* 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 @@ -150,6 +154,23 @@ xmlrpc_value * xmlrpc_datetime_new_sec(xmlrpc_env * const envP, time_t const value); +xmlrpc_value* +xmlrpc_datetime_new_usec(xmlrpc_env * const envP, + time_t const secs, + unsigned int const usecs); + +#if XMLRPC_HAVE_TIMEVAL +xmlrpc_value * +xmlrpc_datetime_new_timeval(xmlrpc_env * const envP, + struct timeval const value); +#endif + +#if XMLRPC_HAVE_TIMESPEC +xmlrpc_value * +xmlrpc_datetime_new_timespec(xmlrpc_env * const envP, + struct timespec const value); +#endif + void xmlrpc_read_datetime_str(xmlrpc_env * const envP, const xmlrpc_value * const valueP, @@ -160,6 +181,26 @@ xmlrpc_read_datetime_sec(xmlrpc_env * const envP, const xmlrpc_value * const valueP, time_t * const timeValueP); +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 +void +xmlrpc_read_datetime_timeval(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + struct timeval * const timeValueP); +#endif + +#if XMLRPC_HAVE_TIMESPEC +void +xmlrpc_read_datetime_timespec(xmlrpc_env * const envP, + const xmlrpc_value * const valueP, + struct timespec * const timeValueP); +#endif + xmlrpc_value * xmlrpc_string_new(xmlrpc_env * const envP, const char * const stringValue); @@ -713,4 +754,3 @@ extern size_t xmlrpc_limit_get (int const limit_id); ** SUCH DAMAGE. */ #endif - diff --git a/libs/xmlrpc-c/include/xmlrpc-c/base.hpp b/libs/xmlrpc-c/include/xmlrpc-c/base.hpp index ab6fe3e..3a898c4 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/base.hpp +++ b/libs/xmlrpc-c/include/xmlrpc-c/base.hpp @@ -1,12 +1,17 @@ #ifndef XMLRPC_BASE_HPP_INCLUDED #define XMLRPC_BASE_HPP_INCLUDED +#include + #include #include #include #include #include #include +#if XMLRPC_HAVE_TIMEVAL +#include +#endif #include @@ -134,9 +139,11 @@ public: value_datetime(time_t const cvalue); #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); @@ -344,4 +351,4 @@ private: } // namespace -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/include/xmlrpc-c/c_util.h b/libs/xmlrpc-c/include/xmlrpc-c/c_util.h index 8cc72e9..0012bf2 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/c_util.h +++ b/libs/xmlrpc-c/include/xmlrpc-c/c_util.h @@ -1,6 +1,12 @@ #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. +*/ + +#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. @@ -11,4 +17,4 @@ #define GNU_PRINTF_ATTR(a,b) #endif -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/include/xmlrpc-c/server.h b/libs/xmlrpc-c/include/xmlrpc-c/server.h index 70d4896..1a36e94 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/server.h +++ b/libs/xmlrpc-c/include/xmlrpc-c/server.h @@ -77,6 +77,21 @@ xmlrpc_registry_add_method2(xmlrpc_env * const envP, 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; +}; + +void +xmlrpc_registry_add_method3( + xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const struct xmlrpc_method_info3 * const infoP); + void xmlrpc_registry_set_default_method(xmlrpc_env * const envP, xmlrpc_registry * const registryP, @@ -124,6 +139,9 @@ xmlrpc_registry_process_call(xmlrpc_env * const envP, const char * const xmlData, size_t const xmlLen); +size_t +xmlrpc_registry_max_stackSize(xmlrpc_registry * const registryP); + #ifdef __cplusplus } #endif @@ -152,4 +170,4 @@ xmlrpc_registry_process_call(xmlrpc_env * const envP, ** 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 +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/include/xmlrpc-c/string_int.h b/libs/xmlrpc-c/include/xmlrpc-c/string_int.h index fa787cb..7bbda8a 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/string_int.h +++ b/libs/xmlrpc-c/include/xmlrpc-c/string_int.h @@ -46,6 +46,11 @@ xmlrpc_memeq(const void * const a, 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) { @@ -59,6 +64,7 @@ xmlrpc_strcaseeq(const char * const a, #error "This platform has no known case-independent string compare fn" #endif } +#endif static __inline__ bool xmlrpc_strneq(const char * const a, @@ -77,8 +83,31 @@ xmlrpc_makePrintable_lp(const char * const input, 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 +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/include/xmlrpc-c/timeout.hpp b/libs/xmlrpc-c/include/xmlrpc-c/timeout.hpp index ef347e5..2b7f08e 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/timeout.hpp +++ b/libs/xmlrpc-c/include/xmlrpc-c/timeout.hpp @@ -7,7 +7,8 @@ struct timeout { timeout() : finite(false) {} - timeout(unsigned int const duration) : duration(duration) {} + timeout(unsigned int const duration) : + finite(true), duration(duration) {} // 'duration' is the timeout time in milliseconds bool finite; @@ -17,4 +18,4 @@ struct timeout { } // namespace -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/include/xmlrpc-c/util.h b/libs/xmlrpc-c/include/xmlrpc-c/util.h index 2cad286..fa83de8 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/util.h +++ b/libs/xmlrpc-c/include/xmlrpc-c/util.h @@ -40,7 +40,7 @@ extern "C" { */ #define _XMLRPC_STRUCT_MEMBER_OFFSET(TYPE, MBRNAME) \ - ((unsigned long)(char*)&((TYPE *)0)->MBRNAME) + ((size_t)(char*)&((TYPE *)0)->MBRNAME) #define _XMLRPC_STRUCT_MEMBER_SIZE(TYPE, MBRNAME) \ sizeof(((TYPE *)0)->MBRNAME) #define XMLRPC_STRUCTSIZE(TYPE, MBRNAME) \ @@ -325,4 +325,4 @@ xmlrpc_force_to_xml_chars(char * const buffer); } #endif -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/include/xmlrpc-c/util_int.h b/libs/xmlrpc-c/include/xmlrpc-c/util_int.h index 8dbc11c..99f8175 100644 --- a/libs/xmlrpc-c/include/xmlrpc-c/util_int.h +++ b/libs/xmlrpc-c/include/xmlrpc-c/util_int.h @@ -3,15 +3,11 @@ #include "util.h" -#ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif -#ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) -#endif /* 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 +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/irix-common.make b/libs/xmlrpc-c/irix-common.make index 9f4ac62..649f08e 100644 --- a/libs/xmlrpc-c/irix-common.make +++ b/libs/xmlrpc-c/irix-common.make @@ -5,7 +5,7 @@ SONAME = $(@:%.$(MAJ):%) -SHLIB_CMD = $(CCLD) $(LDFLAGS_SHLIB) -o $@ $^ $(LADD) +SHLIB_CMD = $(CCLD) $(LADD) $(LDFLAGS_SHLIB) -o $@ $^ SHLIB_LE_TARGETS = $(call shliblefn, $(SHARED_LIBS_TO_BUILD)) @@ -28,4 +28,4 @@ $(SHLIB_INSTALL_TARGETS):%/install:%.$(SHLIB_SUFFIX).$(MAJ) $(INSTALL_SHLIB) $< $(DESTDIR)$(LIBINST_DIR)/$< cd $(DESTDIR)$(LIBINST_DIR); \ rm -f $< $(<:%.$(MAJ)=%); \ - $(LN_S) $< $(<:%.$(MAJ)=%) + $(LN_S) $< $(<:%.$(MAJ)=%) \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/Makefile b/libs/xmlrpc-c/lib/abyss/src/Makefile index fc57122..2dea258 100644 --- a/libs/xmlrpc-c/lib/abyss/src/Makefile +++ b/libs/xmlrpc-c/lib/abyss/src/Makefile @@ -94,7 +94,7 @@ libxmlrpc_abyss.a: LIBOBJECTS = $(TARGET_MODS:%=%.o) # Abyss library are in common.mk, courtesy of TARGET_MODS. -# Need this dependency for those who don't use Makefile.depend. +# 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 @@ -116,4 +116,4 @@ install: install-common .PHONY: dep dep: dep-common -include Makefile.depend +include depend.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/channel.c b/libs/xmlrpc-c/lib/abyss/src/channel.c index af81c62..704cbd4 100644 --- a/libs/xmlrpc-c/lib/abyss/src/channel.c +++ b/libs/xmlrpc-c/lib/abyss/src/channel.c @@ -13,6 +13,7 @@ #include #include "bool.h" +#include "int.h" #include "mallocvar.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/abyss.h" @@ -83,7 +84,7 @@ ChannelTerm(void) { functions that are particular to an implementation. */ -static uint const channelSignature = 0x06060B; +static unsigned int const channelSignature = 0x06060B; void ChannelCreate(const struct TChannelVtbl * const vtblP, @@ -193,4 +194,3 @@ ChannelFormatPeerInfo(TChannel * const channelP, (*channelP->vtbl.formatPeerInfo)(channelP, peerStringP); } - diff --git a/libs/xmlrpc-c/lib/abyss/src/channel.h b/libs/xmlrpc-c/lib/abyss/src/channel.h index c5924bc..4bf946c 100644 --- a/libs/xmlrpc-c/lib/abyss/src/channel.h +++ b/libs/xmlrpc-c/lib/abyss/src/channel.h @@ -60,7 +60,7 @@ struct TChannelVtbl { }; struct _TChannel { - uint signature; + 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 @@ -109,4 +109,4 @@ void ChannelFormatPeerInfo(TChannel * const channelP, const char ** const peerStringP); -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/chanswitch.c b/libs/xmlrpc-c/lib/abyss/src/chanswitch.c index b89e6de..d2ef1e3 100644 --- a/libs/xmlrpc-c/lib/abyss/src/chanswitch.c +++ b/libs/xmlrpc-c/lib/abyss/src/chanswitch.c @@ -11,6 +11,7 @@ #include #include "bool.h" +#include "int.h" #include "mallocvar.h" #include "xmlrpc-c/util_int.h" #include "xmlrpc-c/abyss.h" @@ -81,7 +82,7 @@ ChanSwitchTerm(void) { functions that are particular to an implementation. */ -static uint const switchSignature = 0x06060A; +static unsigned int const switchSignature = 0x06060A; void ChanSwitchCreate(const struct TChanSwitchVtbl * const vtblP, @@ -164,4 +165,4 @@ ChanSwitchInterrupt(TChanSwitch * const chanSwitchP) { chanSwitchP); (*chanSwitchP->vtbl.interrupt)(chanSwitchP); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/chanswitch.h b/libs/xmlrpc-c/lib/abyss/src/chanswitch.h index 4ff7949..1e43fa1 100644 --- a/libs/xmlrpc-c/lib/abyss/src/chanswitch.h +++ b/libs/xmlrpc-c/lib/abyss/src/chanswitch.h @@ -36,7 +36,7 @@ struct TChanSwitchVtbl { }; struct _TChanSwitch { - uint signature; + 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 @@ -75,4 +75,3 @@ ChanSwitchInterrupt(TChanSwitch * const chanSwitchP); #endif - diff --git a/libs/xmlrpc-c/lib/abyss/src/conf.c b/libs/xmlrpc-c/lib/abyss/src/conf.c index 982615f..1623386 100644 --- a/libs/xmlrpc-c/lib/abyss/src/conf.c +++ b/libs/xmlrpc-c/lib/abyss/src/conf.c @@ -32,6 +32,8 @@ ** ******************************************************************************/ +#define _BSD_SOURCE /* For strcaseeq() */ + #include #include #include @@ -96,10 +98,10 @@ ConfReadLine(TFile * const fileP, if (c == CR || c == LF) break; - *buffer = '\0'; + *z = '\0'; /* Discard comments */ - p = strchr(z, '#'); + p = strchr(buffer, '#'); if (p) *p = '\0'; @@ -398,4 +400,4 @@ ConfReadServerFile(const char * const filename, FileClose(fileP); return TRUE; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/conn.c b/libs/xmlrpc-c/lib/abyss/src/conn.c index f76cc22..812a7fd 100644 --- a/libs/xmlrpc-c/lib/abyss/src/conn.c +++ b/libs/xmlrpc-c/lib/abyss/src/conn.c @@ -31,6 +31,8 @@ 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; @@ -44,11 +46,21 @@ connJob(void * const userHandle) { after we exit. */ - //ThreadExit(0); + + /* 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) { @@ -79,6 +91,7 @@ static void makeThread(TConn * const connectionP, enum abyss_foreback const foregroundBackground, bool const useSigchld, + size_t const jobStackSize, const char ** const errorP) { switch (foregroundBackground) { @@ -91,6 +104,7 @@ makeThread(TConn * const connectionP, connectionP->hasOwnThread = TRUE; ThreadCreate(&connectionP->threadP, connectionP, &connJob, &threadDone, useSigchld, + CONNJOB_STACK + jobStackSize, &error); if (error) { xmlrpc_asprintf(errorP, "Unable to create thread to " @@ -110,6 +124,7 @@ ConnCreate(TConn ** const connectionPP, TChannel * const channelP, void * const channelInfoP, TThreadProc * const job, + size_t const jobStackSize, TThreadDoneFn * const done, enum abyss_foreback const foregroundBackground, bool const useSigchld, @@ -150,7 +165,7 @@ ConnCreate(TConn ** const connectionPP, connectionP->server = serverP; connectionP->channelP = channelP; connectionP->channelInfoP = channelInfoP; - connectionP->buffer[0] = '\0'; + connectionP->buffer.b[0] = '\0'; connectionP->buffersize = 0; connectionP->bufferpos = 0; connectionP->finished = FALSE; @@ -160,7 +175,8 @@ ConnCreate(TConn ** const connectionPP, connectionP->outbytes = 0; connectionP->trace = getenv("ABYSS_TRACE_CONN"); - makeThread(connectionP, foregroundBackground, useSigchld, errorP); + makeThread(connectionP, foregroundBackground, useSigchld, + jobStackSize, errorP); } *connectionPP = connectionP; } @@ -185,6 +201,7 @@ ConnProcess(TConn * const connectionP) { /* 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. */ @@ -199,9 +216,11 @@ ConnProcess(TConn * const connectionP) { void ConnWaitAndRelease(TConn * const connectionP) { - if (connectionP->hasOwnThread) + + if (connectionP->hasOwnThread) { + assert(connectionP->threadP); ThreadWaitAndRelease(connectionP->threadP); - + } free(connectionP); } @@ -220,14 +239,14 @@ ConnReadInit(TConn * const connectionP) { if (connectionP->buffersize > connectionP->bufferpos) { connectionP->buffersize -= connectionP->bufferpos; - memmove(connectionP->buffer, - connectionP->buffer + connectionP->bufferpos, + memmove(connectionP->buffer.b, + connectionP->buffer.b + connectionP->bufferpos, connectionP->buffersize); connectionP->bufferpos = 0; } else connectionP->buffersize = connectionP->bufferpos = 0; - connectionP->buffer[connectionP->buffersize] = '\0'; + connectionP->buffer.b[connectionP->buffersize] = '\0'; connectionP->inbytes = connectionP->outbytes = 0; } @@ -261,9 +280,11 @@ nextLineSize(const char * const string, static void -traceBuffer(const char * const label, - const char * const buffer, - unsigned int const size) { +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[] */ @@ -272,9 +293,9 @@ traceBuffer(const char * const label, for (cursor = 0; cursor < size; ) { /* Print one line of buffer */ - size_t const lineSize = nextLineSize(buffer, cursor, size); + size_t const lineSize = nextLineSize(buffer_t, cursor, size); const char * const printableLine = - xmlrpc_makePrintable_lp(&buffer[cursor], lineSize); + xmlrpc_makePrintable_lp(&buffer_t[cursor], lineSize); fprintf(stderr, "%s\n", printableLine); @@ -293,7 +314,7 @@ traceChannelRead(TConn * const connectionP, if (connectionP->trace) traceBuffer("READ FROM CHANNEL", - connectionP->buffer + connectionP->buffersize, size); + connectionP->buffer.b + connectionP->buffersize, size); } @@ -362,7 +383,7 @@ ConnRead(TConn * const connectionP, bool readFailed; ChannelRead(connectionP->channelP, - connectionP->buffer + connectionP->buffersize, + connectionP->buffer.t + connectionP->buffersize, bufferSpace(connectionP) - 1, &bytesRead, &readFailed); @@ -373,7 +394,7 @@ ConnRead(TConn * const connectionP, traceChannelRead(connectionP, bytesRead); connectionP->inbytes += bytesRead; connectionP->buffersize += bytesRead; - connectionP->buffer[connectionP->buffersize] = '\0'; + connectionP->buffer.t[connectionP->buffersize] = '\0'; gotData = TRUE; } else /* Other end has disconnected */ @@ -522,4 +543,4 @@ ConnFormatClientAddr(TConn * const connectionP, ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** -******************************************************************************/ +******************************************************************************/ \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/conn.h b/libs/xmlrpc-c/lib/abyss/src/conn.h index 51eb169..6f2452b 100644 --- a/libs/xmlrpc-c/lib/abyss/src/conn.h +++ b/libs/xmlrpc-c/lib/abyss/src/conn.h @@ -47,8 +47,15 @@ struct _TConn { */ 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; - char buffer[BUFFER_SIZE]; + union { + unsigned char b[BUFFER_SIZE]; /* Just bytes */ + char t[BUFFER_SIZE]; /* Taken as text */ + } buffer; }; typedef struct _TConn TConn; @@ -63,6 +70,7 @@ ConnCreate(TConn ** const connectionPP, TChannel * const channelP, void * const channelInfoP, TThreadProc * const job, + size_t const jobStackSize, TThreadDoneFn * const done, enum abyss_foreback const foregroundBackground, bool const useSigchld, @@ -105,4 +113,4 @@ void ConnFormatClientAddr(TConn * const connectionP, const char ** const clientAddrPP); -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/file.c b/libs/xmlrpc-c/lib/abyss/src/file.c index b428c0c..843a174 100644 --- a/libs/xmlrpc-c/lib/abyss/src/file.c +++ b/libs/xmlrpc-c/lib/abyss/src/file.c @@ -40,15 +40,11 @@ cause security exposures. */ -#if !defined(_FILE_OFFSET_BITS) #define _FILE_OFFSET_BITS 64 -#endif /* Tell GNU libc to make off_t 64 bits and all the POSIX file functions the versions that handle 64 bit file offsets. */ -#if !defined(_LARGE_FILES) #define _LARGE_FILES -#endif /* Same as above, but for AIX */ #include @@ -414,4 +410,4 @@ FileFindClose(TFileFind * const filefindP) { closedir(filefindP->handle); #endif free(filefindP); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/handler.c b/libs/xmlrpc-c/lib/abyss/src/handler.c index 9f5a7e6..23de934 100644 --- a/libs/xmlrpc-c/lib/abyss/src/handler.c +++ b/libs/xmlrpc-c/lib/abyss/src/handler.c @@ -749,6 +749,9 @@ HandlerDefaultBuiltin(TSession * const sessionP) { +size_t const HandlerDefaultBuiltinStack = 1024; + + /****************************************************************************** ** ** server.c @@ -781,4 +784,4 @@ HandlerDefaultBuiltin(TSession * const sessionP) { ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** -******************************************************************************/ +******************************************************************************/ \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/handler.h b/libs/xmlrpc-c/lib/abyss/src/handler.h index 4f9dc95..3047f53 100644 --- a/libs/xmlrpc-c/lib/abyss/src/handler.h +++ b/libs/xmlrpc-c/lib/abyss/src/handler.h @@ -28,4 +28,6 @@ HandlerAddDefaultFN(BIHandler * const handlerP, abyss_bool HandlerDefaultBuiltin(TSession * const sessionP); -#endif +extern size_t const HandlerDefaultBuiltinStack; + +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/http.c b/libs/xmlrpc-c/lib/abyss/src/http.c index 1e55bc8..539cbf5 100644 --- a/libs/xmlrpc-c/lib/abyss/src/http.c +++ b/libs/xmlrpc-c/lib/abyss/src/http.c @@ -1,5 +1,7 @@ /* Copyright information is at the end of the file */ +#define _BSD_SOURCE /* For strcaseeq() */ + #include #include #include @@ -79,6 +81,8 @@ freeRequestInfo(TRequestInfo * const requestInfoP) { xmlrpc_strfree(requestInfoP->uri); xmlrpc_strfree(requestInfoP->requestline); + + xmlrpc_strfree(requestInfoP->query); /* jlenk added */ } @@ -137,7 +141,7 @@ firstLfPos(TConn * const connectionP, If there is no LF in the buffer at or after 'lineStart', return NULL. -----------------------------------------------------------------------------*/ const char * const bufferEnd = - connectionP->buffer + connectionP->buffersize; + connectionP->buffer.t + connectionP->buffersize; char * p; @@ -168,14 +172,13 @@ getLineInBuffer(TConn * const connectionP, bool error; char * lfPos; - assert(lineStart <= connectionP->buffer + connectionP->buffersize); + 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 { @@ -247,7 +250,7 @@ getRestOfHeader(TConn * const connectionP, buffer so as to join the multiple lines of the header into a single line, and to NUL-terminate the header. -----------------------------------------------------------------------------*/ - char * const headerStart = connectionP->buffer + connectionP->bufferpos; + char * const headerStart = connectionP->buffer.t + connectionP->bufferpos; char * headerEnd; /* End of the header lines we've seen at so far */ @@ -322,7 +325,7 @@ readHeader(TConn * const connectionP, the connection's internal buffer. Iff there is no next header, we return *endOfHeadersP == true and nothing meaningful as *headerP. -----------------------------------------------------------------------------*/ - char * const bufferStart = connectionP->buffer + connectionP->bufferpos; + char * const bufferStart = connectionP->buffer.t + connectionP->bufferpos; bool error; char * lineEnd; @@ -334,7 +337,7 @@ readHeader(TConn * const connectionP, error = TRUE; else if (isEmptyLine(bufferStart)) { /* Consume the EOH mark from the buffer */ - connectionP->bufferpos = lineEnd - connectionP->buffer; + connectionP->bufferpos = lineEnd - connectionP->buffer.t; *endOfHeadersP = TRUE; } else { /* We have the first line of a header; there may be more. */ @@ -353,7 +356,7 @@ readHeader(TConn * const connectionP, you can't reuse that part of the buffer because the string we will return is in it! */ - connectionP->bufferpos = headerEnd - connectionP->buffer; + connectionP->bufferpos = headerEnd - connectionP->buffer.t; } } } @@ -367,7 +370,7 @@ skipToNonemptyLine(TConn * const connectionP, time_t const deadline, bool * const errorP) { - char * const bufferStart = connectionP->buffer + connectionP->bufferpos; + char * const bufferStart = connectionP->buffer.t + connectionP->bufferpos; bool gotNonEmptyLine; bool error; @@ -393,7 +396,7 @@ skipToNonemptyLine(TConn * const connectionP, /* Consume all the empty lines; advance buffer pointer to first non-empty line. */ - connectionP->bufferpos = lineStart - connectionP->buffer; + connectionP->bufferpos = lineStart - connectionP->buffer.t; } *errorP = error; } @@ -426,15 +429,21 @@ readRequestHeader(TSession * const sessionP, are not able to read the request header, or 0 if we can. If we can't, *requestLineP is meaningless. -----------------------------------------------------------------------------*/ - char * line = NULL; - bool error = FALSE; - bool endOfHeaders = FALSE; + char * line; + bool error; + bool endOfHeaders; skipToNonemptyLine(sessionP->conn, deadline, &error); - if (!error) + if (!error) { readHeader(sessionP->conn, deadline, &endOfHeaders, &line, &error); + /* End of headers is delimited by an empty line, and we skipped all + the empty lines above, so readHeader() could not have encountered + EOH: + */ + assert(!endOfHeaders); + } if (error) *httpErrorCodeP = 408; /* Request Timeout */ else { @@ -863,11 +872,9 @@ readAndProcessHeaders(TSession * const sessionP, -----------------------------------------------------------------------------*/ bool endOfHeaders; - /* Calling us doesn't make sense if there is already a valid request */ - if (sessionP->validRequest) { - return; - } - + assert(!sessionP->validRequest); + /* Calling us doesn't make sense if there is already a valid request */ + *httpErrorCodeP = 0; /* initial assumption */ endOfHeaders = false; /* Caller assures us there is at least one header */ @@ -1301,4 +1308,4 @@ HTTPWriteContinue(TSession * const sessionP) { ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** -******************************************************************************/ +******************************************************************************/ \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/main.c b/libs/xmlrpc-c/lib/abyss/src/main.c index e5741f3..6d55182 100644 --- a/libs/xmlrpc-c/lib/abyss/src/main.c +++ b/libs/xmlrpc-c/lib/abyss/src/main.c @@ -42,7 +42,7 @@ #endif /* WIN32 */ #ifdef _UNIX -#include +#include #include #endif @@ -249,4 +249,4 @@ int main(int argc,char **argv) ServerRun(&srv); return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/response.c b/libs/xmlrpc-c/lib/abyss/src/response.c index 75421d4..864671e 100644 --- a/libs/xmlrpc-c/lib/abyss/src/response.c +++ b/libs/xmlrpc-c/lib/abyss/src/response.c @@ -16,6 +16,7 @@ #include "xmlrpc_config.h" #include "bool.h" +#include "int.h" #include "version.h" #include "mallocvar.h" #include "xmlrpc-c/string_int.h" @@ -177,7 +178,7 @@ addServerHeader(TSession * const sessionP) { const char * serverValue; - xmlrpc_asprintf(&serverValue, "XMLRPC_ABYSS/%s", XMLRPC_C_VERSION); + xmlrpc_asprintf(&serverValue, "Xmlrpc-c_Abyss/%s", XMLRPC_C_VERSION); ResponseAddField(sessionP, "Server", serverValue); @@ -188,7 +189,12 @@ addServerHeader(TSession * const sessionP) { 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->conn)->srvP; unsigned int i; @@ -309,6 +315,8 @@ void MIMETypeDestroy(MIMEType * const MIMETypeP) { PoolFree(&MIMETypeP->pool); + + free(MIMETypeP); } @@ -645,7 +653,7 @@ Base64Encode(const char * const chars, '4','5','6','7','8','9','+','/' }; - uint i; + unsigned int i; uint32_t length; char * p; const char * s; @@ -704,4 +712,4 @@ Base64Encode(const char * const chars, ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** -******************************************************************************/ +******************************************************************************/ \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/server.c b/libs/xmlrpc-c/lib/abyss/src/server.c index a52c823..89664ac 100644 --- a/libs/xmlrpc-c/lib/abyss/src/server.c +++ b/libs/xmlrpc-c/lib/abyss/src/server.c @@ -35,6 +35,17 @@ #include "server.h" +struct uriHandler { + initHandlerFn init; + termHandlerFn term; + handleReq3Fn handleReq3; + handleReq2Fn handleReq2; + URIHandler handleReq1; + void * userdata; +}; + + + void ServerTerminate(TServer * const serverP) { @@ -42,12 +53,12 @@ ServerTerminate(TServer * const serverP) { srvP->terminationRequested = true; - if (srvP->chanSwitchP) { + if (srvP->chanSwitchP) ChanSwitchInterrupt(srvP->chanSwitchP); - ChanSwitchDestroy(srvP->chanSwitchP); - } } + + void ServerResetTerminate(TServer * const serverP) { @@ -167,6 +178,7 @@ createServer(struct _TServer ** const srvPP, srvP->timeout = 15; srvP->advertise = TRUE; srvP->useSigchld = FALSE; + srvP->uriHandlerStackSize = 0; initUnixStuff(srvP); @@ -383,7 +395,7 @@ terminateHandlers(TList * const handlersP) { if (handlersP->item) { unsigned int i; for (i = handlersP->size; i > 0; --i) { - URIHandler2 * const handlerP = handlersP->item[i-1]; + struct uriHandler * const handlerP = handlersP->item[i-1]; if (handlerP->term) handlerP->term(handlerP->userdata); } @@ -497,6 +509,22 @@ ServerSetMimeType(TServer * const serverP, +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) { @@ -507,11 +535,14 @@ runUserHandler(TSession * const sessionP, for (i = srvP->handlers.size-1, handled = FALSE; i >= 0 && !handled; --i) { - URIHandler2 * const handlerP = srvP->handlers.item[i]; + const struct uriHandler * const handlerP = srvP->handlers.item[i]; - if (handlerP->handleReq2) - handlerP->handleReq2(handlerP, sessionP, &handled); - else if (handlerP->handleReq1) + 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); } @@ -524,12 +555,38 @@ runUserHandler(TSession * const sessionP, static void -processDataFromClient(TConn * const connectionP, - bool const lastReqOnConn, - uint32_t const timeout, - bool * const keepAliveP) { +handleReqInvalidURI(TSession * const sessionP) { - TSession session = {0}; /* initilization, an afforadble alternative to random memory being misinterpreted! */ + 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. +-----------------------------------------------------------------------------*/ + TSession session; RequestInit(&session, connectionP); @@ -587,16 +644,18 @@ serverFunc(void * const userHandle) { /* Wait to read until timeout */ success = ConnRead(connectionP, srvP->keepalivetimeout); - if (!success) + if (!success) { connectionDone = TRUE; - else { + } else if (srvP->terminationRequested) { + connectionDone = TRUE; + } else { bool const lastReqOnConn = requestCount + 1 >= srvP->keepalivemaxconn; bool keepalive; - processDataFromClient(connectionP, lastReqOnConn, srvP->timeout, - &keepalive); + processRequestFromClient(connectionP, lastReqOnConn, srvP->timeout, + &keepalive); ++requestCount; @@ -611,6 +670,14 @@ serverFunc(void * const userHandle) { +/* 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, @@ -700,10 +767,9 @@ ServerInit(TServer * const serverP) { } if (retError) { TraceMsg("ServerInit() failed. %s", retError); - return 0; xmlrpc_strfree(retError); + return 0; } - return 1; } @@ -920,7 +986,9 @@ acceptAndProcessNextConnection( waitForConnectionCapacity(outstandingConnListP); ConnCreate(&connectionP, serverP, channelP, channelInfoP, - &serverFunc, &destroyChannel, ABYSS_BACKGROUND, + &serverFunc, + SERVER_FUNC_STACK + srvP->uriHandlerStackSize, + &destroyChannel, ABYSS_BACKGROUND, srvP->useSigchld, &error); if (!error) { @@ -998,7 +1066,8 @@ serverRunChannel(TServer * const serverP, ConnCreate(&connectionP, serverP, channelP, channelInfoP, - &serverFunc, NULL, ABYSS_FOREGROUND, srvP->useSigchld, + &serverFunc, SERVER_FUNC_STACK + srvP->uriHandlerStackSize, + NULL, ABYSS_FOREGROUND, srvP->useSigchld, &error); if (error) { xmlrpc_asprintf(errorP, "Couldn't create HTTP connection out of " @@ -1230,24 +1299,43 @@ ServerDaemonize(TServer * const serverP) { -void -ServerAddHandler2(TServer * const serverP, - URIHandler2 * const handlerArgP, - abyss_bool * const successP) { +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; - URIHandler2 * handlerP; + struct uriHandler * handlerP; MALLOCVAR(handlerP); if (handlerP == NULL) *successP = FALSE; else { - *handlerP = *handlerArgP; - + 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 - handlerP->init(handlerP, successP); - + else { + URIHandler2 handler2 = makeUriHandler2(handlerP); + handlerP->init(&handler2, successP); + } if (*successP) *successP = ListAdd(&serverP->srvP->handlers, handlerP); @@ -1258,20 +1346,42 @@ ServerAddHandler2(TServer * const serverP, -static URIHandler2 * -createHandler(URIHandler const function) { +void +ServerAddHandler3(TServer * const serverP, + const struct ServerReqHandler3 * const handlerP, + abyss_bool * const successP) { - URIHandler2 * handlerP; + serverAddHandler(serverP, NULL, handlerP->term, NULL, NULL, + handlerP->handleReq, handlerP->userdata, + handlerP->handleReqStackSize, successP); +} - MALLOCVAR(handlerP); - if (handlerP != NULL) { - handlerP->init = NULL; - handlerP->term = NULL; - handlerP->userdata = NULL; - handlerP->handleReq2 = NULL; - handlerP->handleReq1 = function; - } - return handlerP; + + +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, + handlerArgP->handleReq1, // was NULL, j.l + handlerArgP->handleReq2, + NULL, + handlerArgP->userdata, + 0, + successP); } @@ -1280,35 +1390,45 @@ abyss_bool ServerAddHandler(TServer * const serverP, URIHandler const function) { - URIHandler2 * handlerP; - bool success; + URIHandler2 handler; + abyss_bool success; - handlerP = createHandler(function); + handler.init = NULL; + handler.term = NULL; + handler.userdata = NULL; + handler.handleReq2 = NULL; + handler.handleReq1 = function; - if (handlerP == NULL) - success = FALSE; - else { - success = ListAdd(&serverP->srvP->handlers, handlerP); + ServerAddHandler2(serverP, &handler, &success); - if (!success) - free(handlerP); - } 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) + if (handler) { srvP->defaultHandler = handler; - else { + srvP->uriHandlerStackSize = + MAX(srvP->uriHandlerStackSize, USER_DEFAULT_HANDLER_STACK); + } else { srvP->defaultHandler = HandlerDefaultBuiltin; srvP->defaultHandlerContext = srvP->builtinHandlerP; + srvP->uriHandlerStackSize = + MAX(srvP->uriHandlerStackSize, HandlerDefaultBuiltinStack); } } @@ -1367,4 +1487,4 @@ LogWrite(TServer * const serverP, ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** -******************************************************************************/ +******************************************************************************/ \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/server.h b/libs/xmlrpc-c/lib/abyss/src/server.h index 39aa63e..4353afc 100644 --- a/libs/xmlrpc-c/lib/abyss/src/server.h +++ b/libs/xmlrpc-c/lib/abyss/src/server.h @@ -54,7 +54,7 @@ struct _TServer { Server calls each one in order until one reports that it handled it. - Each item in the list of of type 'URIHandler2'. + Each item in the list of of type 'uriHandler'. */ URIHandler defaultHandler; /* The handler for HTTP requests that aren't claimed by any handler @@ -75,6 +75,12 @@ struct _TServer { 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; @@ -82,4 +88,4 @@ struct _TServer { #endif }; -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/session.c b/libs/xmlrpc-c/lib/abyss/src/session.c index ae3a078..6c9ef25 100644 --- a/libs/xmlrpc-c/lib/abyss/src/session.c +++ b/libs/xmlrpc-c/lib/abyss/src/session.c @@ -75,7 +75,7 @@ SessionGetReadData(TSession * const sessionP, -----------------------------------------------------------------------------*/ uint32_t const bufferPos = sessionP->conn->bufferpos; - *outStartP = &sessionP->conn->buffer[bufferPos]; + *outStartP = &sessionP->conn->buffer.t[bufferPos]; assert(bufferPos <= sessionP->conn->buffersize); @@ -155,4 +155,4 @@ SessionGetDefaultHandlerCtx(TSession * const sessionP) { struct _TServer * const srvP = sessionP->conn->server->srvP; return srvP->defaultHandlerContext; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/socket.c b/libs/xmlrpc-c/lib/abyss/src/socket.c index d76c611..06b5ab3 100644 --- a/libs/xmlrpc-c/lib/abyss/src/socket.c +++ b/libs/xmlrpc-c/lib/abyss/src/socket.c @@ -9,6 +9,7 @@ #include #include +#include "int.h" #include "mallocvar.h" #include "xmlrpc-c/abyss.h" #include "channel.h" @@ -26,7 +27,7 @@ functions that are particular to an implementation. */ -static uint const socketSignature = 0x060609; +static unsigned int const socketSignature = 0x060609; static void @@ -123,4 +124,4 @@ void * SocketGetChannelInfo(TSocket * const socketP) { return socketP->channelInfoP; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/socket.h b/libs/xmlrpc-c/lib/abyss/src/socket.h index 20e8e09..cfa08f7 100644 --- a/libs/xmlrpc-c/lib/abyss/src/socket.h +++ b/libs/xmlrpc-c/lib/abyss/src/socket.h @@ -17,10 +17,12 @@ so there may be few or no users of TSocket. ============================================================================*/ +#include "int.h" + #include "xmlrpc-c/abyss.h" struct _TSocket { - uint signature; + 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 @@ -55,4 +57,3 @@ void * SocketGetChannelInfo(TSocket * const socketP); #endif - diff --git a/libs/xmlrpc-c/lib/abyss/src/socket_unix.c b/libs/xmlrpc-c/lib/abyss/src/socket_unix.c index 6231852..cbeb82c 100644 --- a/libs/xmlrpc-c/lib/abyss/src/socket_unix.c +++ b/libs/xmlrpc-c/lib/abyss/src/socket_unix.c @@ -40,50 +40,42 @@ #include "socket_unix.h" -#define sane_close(_it) do {if (_it > -1) { close(_it) ; _it = -1; }} while (_it > -1) + typedef struct { int interruptorFd; int interrupteeFd; - int inuse; } interruptPipe; static void -initInterruptPipe(interruptPipe * pipeP, +initInterruptPipe(interruptPipe * const pipeP, const char ** const errorP) { - int pipeFd[2] = {-1, -1}; + int pipeFd[2]; int rc; rc = pipe(pipeFd); - if (rc != 0) { + 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)); - pipeP->inuse = 0; - } else { + else { *errorP = NULL; pipeP->interruptorFd = pipeFd[1]; pipeP->interrupteeFd = pipeFd[0]; - pipeP->inuse = 1; } } static void -termInterruptPipe(interruptPipe *pipeP) { - if (pipeP->inuse) { - int x = 0; - write(pipeP->interruptorFd, &x, sizeof(x)); - usleep(500); - shutdown(pipeP->interrupteeFd, 2); - sane_close(pipeP->interruptorFd); - sane_close(pipeP->interrupteeFd); - } +termInterruptPipe(interruptPipe const pipe) { + + close(pipe.interruptorFd); + close(pipe.interrupteeFd); } @@ -158,10 +150,10 @@ channelDestroy(TChannel * const channelP) { struct socketUnix * const socketUnixP = channelP->implP; - termInterruptPipe(&socketUnixP->interruptPipe); + termInterruptPipe(socketUnixP->interruptPipe); if (!socketUnixP->userSuppliedFd) - sane_close(socketUnixP->fd); + close(socketUnixP->fd); free(socketUnixP); } @@ -312,8 +304,7 @@ channelWait(TChannel * const channelP, pollfds[1].events = POLLIN; rc = poll(pollfds, ARRAY_SIZE(pollfds), - timeoutMs == TIME_INFINITE ? -1 : timeoutMs); - + timeoutMs == TIME_INFINITE ? -1 : (int)timeoutMs); if (rc < 0) { if (errno == EINTR) { @@ -493,13 +484,13 @@ makeChannelFromFd(int const fd, 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; @@ -507,6 +498,7 @@ makeChannelFromFd(int const fd, if (!*errorP) { ChannelCreate(&channelVtbl, socketUnixP, &channelP); + if (channelP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for " "channel descriptor."); @@ -515,7 +507,7 @@ makeChannelFromFd(int const fd, *errorP = NULL; } if (*errorP) - termInterruptPipe(&socketUnixP->interruptPipe); + termInterruptPipe(socketUnixP->interruptPipe); } if (*errorP) free(socketUnixP); @@ -569,10 +561,10 @@ chanSwitchDestroy(TChanSwitch * const chanSwitchP) { struct socketUnix * const socketUnixP = chanSwitchP->implP; - termInterruptPipe(&socketUnixP->interruptPipe); + termInterruptPipe(socketUnixP->interruptPipe); if (!socketUnixP->userSuppliedFd) - sane_close(socketUnixP->fd); + close(socketUnixP->fd); free(socketUnixP); } @@ -665,35 +657,42 @@ createChannelForAccept(int const acceptedFd, 'peerAddr' is the address of the client, from accept(). -----------------------------------------------------------------------------*/ - struct socketUnix * acceptedSocketP; + struct abyss_unix_chaninfo * channelInfoP; - MALLOCVAR(acceptedSocketP); - - if (!acceptedSocketP) - xmlrpc_asprintf(errorP, "Unable to allocate memory"); - else { - struct abyss_unix_chaninfo * channelInfoP; - acceptedSocketP->fd = acceptedFd; - acceptedSocketP->userSuppliedFd = FALSE; - - makeChannelInfo(&channelInfoP, peerAddr, sizeof(peerAddr), errorP); - if (!*errorP) { - TChannel * channelP; + makeChannelInfo(&channelInfoP, peerAddr, sizeof(peerAddr), errorP); + if (!*errorP) { + struct socketUnix * acceptedSocketP; - ChannelCreate(&channelVtbl, acceptedSocketP, &channelP); - if (!channelP) - xmlrpc_asprintf(errorP, - "Failed to create TChannel object."); - else { - *errorP = NULL; - *channelPP = channelP; - *channelInfoPP = channelInfoP; + 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(channelInfoP); + free(acceptedSocketP); } if (*errorP) - free(acceptedSocketP); + free(channelInfoP); } } @@ -736,13 +735,13 @@ chanSwitchAccept(TChanSwitch * const chanSwitchP, rc = accept(listenSocketP->fd, &peerAddr, &size); if (rc >= 0) { - int acceptedFd = rc; + int const acceptedFd = rc; createChannelForAccept(acceptedFd, peerAddr, &channelP, channelInfoPP, errorP); if (*errorP) - sane_close(acceptedFd); + close(acceptedFd); } else if (errno == EINTR) interrupted = TRUE; else @@ -810,7 +809,7 @@ createChanSwitch(int const fd, if (!*errorP) { ChanSwitchCreate(&chanSwitchVtbl, socketUnixP, &chanSwitchP); if (*errorP) - termInterruptPipe(&socketUnixP->interruptPipe); + termInterruptPipe(socketUnixP->interruptPipe); if (chanSwitchP == NULL) xmlrpc_asprintf(errorP, "Unable to allocate memory for " @@ -854,7 +853,6 @@ bindSocketToPort(int const fd, struct sockaddr_in name; int rc; - int one = 1; name.sin_family = AF_INET; name.sin_port = htons(portNumber); @@ -863,7 +861,6 @@ bindSocketToPort(int const fd, else name.sin_addr.s_addr = INADDR_ANY; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)); rc = bind(fd, (struct sockaddr *)&name, sizeof(name)); if (rc == -1) @@ -894,7 +891,7 @@ ChanSwitchUnixCreate(unsigned short const portNumber, xmlrpc_asprintf(errorP, "socket() failed with errno %d (%s)", errno, strerror(errno)); else { - int socketFd = rc; + int const socketFd = rc; setSocketOptions(socketFd, errorP); if (!*errorP) { @@ -906,7 +903,7 @@ ChanSwitchUnixCreate(unsigned short const portNumber, } } if (*errorP) - sane_close(socketFd); + close(socketFd); } } @@ -958,4 +955,4 @@ SocketUnixCreateFd(int const fd, xmlrpc_strfree(error); } else *socketPP = socketP; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/thread.h b/libs/xmlrpc-c/lib/abyss/src/thread.h index c214f4b..7d3f1d1 100644 --- a/libs/xmlrpc-c/lib/abyss/src/thread.h +++ b/libs/xmlrpc-c/lib/abyss/src/thread.h @@ -21,6 +21,7 @@ ThreadCreate(TThread ** const threadPP, TThreadProc * const func, TThreadDoneFn * const threadDone, bool const useSigchld, + size_t const stackSize, const char ** const errorP); bool @@ -36,7 +37,8 @@ void ThreadWaitAndRelease(TThread * const threadP); void -ThreadExit(int const retValue); +ThreadExit(TThread * const threadP, + int const retValue); void ThreadRelease(TThread * const threadP); @@ -73,4 +75,4 @@ MutexTryLock(TMutex * const mutexP); void MutexDestroy(TMutex * const mutexP); -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/thread_fork.c b/libs/xmlrpc-c/lib/abyss/src/thread_fork.c index 973e153..db5f7f9 100644 --- a/libs/xmlrpc-c/lib/abyss/src/thread_fork.c +++ b/libs/xmlrpc-c/lib/abyss/src/thread_fork.c @@ -157,6 +157,7 @@ ThreadCreate(TThread ** const threadPP, TThreadProc * const func, TThreadDoneFn * const threadDone, bool const useSigchld, + size_t const stackSize, const char ** const errorP) { TThread * threadP; @@ -189,6 +190,9 @@ ThreadCreate(TThread ** const threadPP, 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 */ @@ -249,7 +253,8 @@ ThreadWaitAndRelease(TThread * const threadP) { void -ThreadExit(int const retValue) { +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 @@ -259,6 +264,10 @@ ThreadExit(int const retValue) { sees we've gone. */ + /* Note that thread cleanup (threadDone) is done by the _parent_, + upon seeing our exit. + */ + exit(retValue); } @@ -320,4 +329,4 @@ MutexTryLock(TMutex * const mutexP ATTR_UNUSED) { void MutexDestroy(TMutex * const mutexP ATTR_UNUSED) { -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/thread_pthread.c b/libs/xmlrpc-c/lib/abyss/src/thread_pthread.c index 5cca825..a7ddaf8 100644 --- a/libs/xmlrpc-c/lib/abyss/src/thread_pthread.c +++ b/libs/xmlrpc-c/lib/abyss/src/thread_pthread.c @@ -7,6 +7,7 @@ #include "bool.h" #include "mallocvar.h" +#include "xmlrpc-c/util_int.h" #include "xmlrpc-c/string_int.h" #include "pthreadx.h" @@ -23,12 +24,12 @@ struct abyss_thread { TThreadDoneFn * threadDone; }; -/* We used to have THREAD_STACK_SIZE = 16K, which was said to be the +/* 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 THREAD_STACK_SIZE (128*1024L) +#define MIN_STACK_SIZE (128*1024L) typedef void * (pthreadStartRoutine)(void *); @@ -49,51 +50,63 @@ pthreadStart(void * const arg) { pthread_cleanup_pop(executeTrue); + /* Note that func() may not return; it may just exit the thread, + by calling ThreadExit(), in which case code here doesn't run. + */ + threadP->threadDone(threadP->userHandle); + 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) { - TThread * threadP; - - MALLOCVAR(threadP); - if (threadP == NULL) - xmlrpc_asprintf(errorP, - "Can't allocate memory for thread descriptor."); + if ((size_t)(int)stackSize != stackSize) + xmlrpc_asprintf(errorP, "Stack size %lu is too big", + (unsigned long)stackSize); else { - pthread_attr_t attr; - int rc; + 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_init(&attr); - pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE); + pthread_attr_setstacksize(&attr, MAX(MIN_STACK_SIZE, stackSize)); - threadP->userHandle = userHandle; - threadP->func = func; - threadP->threadDone = threadDone; - - rc = pthread_create(&threadP->thread, &attr, - pthreadStart, threadP); - if (rc == 0) { - *errorP = NULL; - *threadPP = threadP; - } else - xmlrpc_asprintf( - errorP, "pthread_create() failed, errno = %d (%s)", - errno, strerror(errno)); + threadP->userHandle = userHandle; + threadP->func = func; + threadP->threadDone = threadDone; + + rc = pthread_create(&threadP->thread, &attr, + pthreadStart, 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); + pthread_attr_destroy(&attr); - if (*errorP) - free(threadP); + if (*errorP) + free(threadP); + } } } @@ -134,7 +147,8 @@ ThreadWaitAndRelease(TThread * const threadP) { void -ThreadExit(int const retValue) { +ThreadExit(TThread * const threadP ATTR_UNUSED, + int const retValue) { pthread_exit((void*)&retValue); @@ -242,4 +256,4 @@ MutexDestroy(TMutex * const mutexP) { pthread_mutex_destroy(&mutexP->pthreadMutex); free(mutexP); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/abyss/src/thread_windows.c b/libs/xmlrpc-c/lib/abyss/src/thread_windows.c index dae5bb5..57ebc16 100644 --- a/libs/xmlrpc-c/lib/abyss/src/thread_windows.c +++ b/libs/xmlrpc-c/lib/abyss/src/thread_windows.c @@ -15,6 +15,7 @@ #include "bool.h" #include "int.h" +#include "xmlrpc-c/util_int.h" #include "mallocvar.h" #include "xmlrpc-c/string_int.h" @@ -24,7 +25,6 @@ #include "thread.h" - struct abyss_thread { HANDLE handle; void * userHandle; @@ -32,7 +32,7 @@ struct abyss_thread { TThreadDoneFn * threadDone; }; -#define THREAD_STACK_SIZE (16*1024L) +#define MIN_THREAD_STACK_SIZE (16*1024L) typedef uint32_t (WINAPI WinThreadProc)(void *); @@ -60,6 +60,7 @@ ThreadCreate(TThread ** const threadPP, TThreadProc * const func, TThreadDoneFn * const threadDone, bool const useSigchld, + size_t const stackSize, const char ** const errorP) { TThread * threadP; @@ -76,12 +77,13 @@ ThreadCreate(TThread ** const threadPP, threadP->func = func; threadP->threadDone = threadDone; - threadP->handle = (HANDLE)_beginthreadex(NULL, - THREAD_STACK_SIZE, - threadRun, - threadP, - CREATE_SUSPENDED, - &z); + 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."); @@ -121,13 +123,17 @@ ThreadKill(TThread * const threadP) { void ThreadWaitAndRelease(TThread * const threadP) { + WaitForSingleObject(threadP->handle, INFINITE); ThreadRelease(threadP); } void -ThreadExit(int const retValue) { +ThreadExit(TThread * const threadP, + int const retValue) { + + threadP->threadDone(threadP->userHandle); _endthreadex(retValue); } @@ -138,6 +144,7 @@ void ThreadRelease(TThread * const threadP) { CloseHandle(threadP->handle); + free(threadP); /* jlenk added */ } @@ -190,8 +197,6 @@ MutexCreate(TMutex ** const mutexPP) { *mutexPP = mutexP; - TraceMsg( "Created Mutex %s\n", (succeeded ? "ok" : "FAILED") ); - return succeeded; } @@ -228,4 +233,3 @@ MutexDestroy(TMutex * const mutexP) { free(mutexP); } - diff --git a/libs/xmlrpc-c/lib/curl_transport/Makefile b/libs/xmlrpc-c/lib/curl_transport/Makefile index c9e144f..3db033f 100644 --- a/libs/xmlrpc-c/lib/curl_transport/Makefile +++ b/libs/xmlrpc-c/lib/curl_transport/Makefile @@ -10,13 +10,15 @@ include $(BLDDIR)/config.mk default: all +MODS := xmlrpc_curl_transport curltransaction curlmulti lock_pthread + .PHONY: all -all: xmlrpc_curl_transport.o xmlrpc_curl_transport.osh +all: $(MODS:%=%.o) $(MODS:%=%.osh) # Rules for the above dependencies are in common.mk, # courtesy of TARGET_MODS. -TARGET_MODS = xmlrpc_curl_transport +TARGET_MODS = $(MODS) OMIT_CURL_TRANSPORT_RULE=Y @@ -54,8 +56,8 @@ install: .PHONY: dep dep: dep-common -include Makefile.depend +include depend.mk -# Need this dependency for those who don't use Makefile.depend. +# 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_curl_transport.o xmlrpc_curl_transport.osh: version.h \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/curl_transport/xmlrpc_curl_transport.c b/libs/xmlrpc-c/lib/curl_transport/xmlrpc_curl_transport.c index 29104b9..ceb20a5 100644 --- a/libs/xmlrpc-c/lib/curl_transport/xmlrpc_curl_transport.c +++ b/libs/xmlrpc-c/lib/curl_transport/xmlrpc_curl_transport.c @@ -75,18 +75,24 @@ #include "girstring.h" #include "pthreadx.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 "version.h" #include #include #include #include +#include "lock.h" +#include "lock_pthread.h" +#include "curltransaction.h" +#include "curlmulti.h" +#include "curlversion.h" + #if MSVCRT #if defined(_DEBUG) # include @@ -98,92 +104,8 @@ #endif -#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 - -#undef CMAJOR -#undef CMINOR - - - typedef struct rpc rpc; -typedef struct curlTransaction curlTransaction; - - - -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. - */ - xmlrpc_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. - */ - xmlrpc_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; - unsigned int timeout; - /* 0 = no Curl timeout. This is in milliseconds. */ -}; static int @@ -239,939 +161,229 @@ addMilliseconds(xmlrpc_timespec const addend, -/*============================================================================ - locks -============================================================================== - This is the beginnings of a lock abstraction that will allow this - transport to be used with locks other than pthread locks -============================================================================*/ - -struct lock { - pthread_mutex_t theLock; - void (*lock)(struct lock *); - void (*unlock)(struct lock *); - void (*destroy)(struct lock *); -}; - -typedef struct lock lock; - -static void -lock_pthread(struct lock * const lockP) { - pthread_mutex_lock(&lockP->theLock); -} - -static void -unlock_pthread(struct lock * const lockP) { - pthread_mutex_unlock(&lockP->theLock); -} - -static void -destroyLock_pthread(struct lock * const lockP) { - pthread_mutex_destroy(&lockP->theLock); - free(lockP); -} - - -static struct lock * -createLock_pthread(void) { - struct lock * lockP; - MALLOCVAR(lockP); - if (lockP) { - pthread_mutex_init(&lockP->theLock, NULL); - lockP->lock = &lock_pthread; - lockP->unlock = &unlock_pthread; - lockP->destroy = &destroyLock_pthread; - } - return lockP; -} +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). + */ + const char * userAgent; + /* Prefix for the User-Agent HTTP header, reflecting facilities + outside of Xmlrpc-c. The actual User-Agent header consists + of this prefix plus information about Xmlrpc-c. NULL means + none. + 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. + */ +}; -/*============================================================================= - curlTransaction -=============================================================================*/ -typedef void finishCurlTransactionFn(xmlrpc_env * const, curlTransaction * const); -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. +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. */ - finishCurlTransactionFn * finish; - rpc * rpcP; - /* The RPC which this transaction serves. (If this structure - were a true extension of the Curl library as described above, - this would be a void *, since the Curl library doesn't know what - an RPC is, but since we use it only for that, we might as well - use the specific type here). + CURL * curlSessionP; + /* The Curl session to use for the Curl transaction to perform + the RPC. */ - 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. + 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. */ - 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 */ + struct xmlrpc_call_info * callInfoP; + /* User's identifier for this RPC */ }; - 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 +lockSyncCurlSession(struct xmlrpc_client_transport * const transportP) { + transportP->syncCurlSessionLockP->acquire( + transportP->syncCurlSessionLockP); } 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 +unlockSyncCurlSession(struct xmlrpc_client_transport * const transportP) { + transportP->syncCurlSessionLockP->release( + transportP->syncCurlSessionLockP); } 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; -} - - +initWindowsStuff(xmlrpc_env * const envP ATTR_UNUSED) { -static void -addContentTypeHeader(xmlrpc_env * const envP, - struct curl_slist ** const headerListP) { +#if defined (WIN32) + /* This is CRITICAL so that cURL-Win32 works properly! */ - addHeader(envP, headerListP, "Content-Type: text/xml"); -} - - - -static void -addUserAgentHeader(xmlrpc_env * const envP, - struct curl_slist ** const headerListP, - const char * const userAgent) { - - if (userAgent) { - /* 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. - */ + /* 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); - curl_version_info_data * const curlInfoP = - curl_version_info(CURLVERSION_NOW); - char curlVersion[32]; - const char * userAgentHeader; - - snprintf(curlVersion, sizeof(curlVersion), "%u.%u.%u", - (curlInfoP->version_num >> 16) && 0xff, - (curlInfoP->version_num >> 8) && 0xff, - (curlInfoP->version_num >> 0) && 0xff - ); - - xmlrpc_asprintf(&userAgentHeader, - "User-Agent: %s Xmlrpc-c/%s Curl/%s", - userAgent, XMLRPC_C_VERSION, curlVersion); - - if (userAgentHeader == xmlrpc_strsol) - xmlrpc_faultf(envP, "Couldn't allocate memory for " - "User-Agent header"); - else { - addHeader(envP, headerListP, userAgentHeader); - - xmlrpc_strfree(userAgentHeader); + 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 -addAuthorizationHeader(xmlrpc_env * const envP, - struct curl_slist ** const headerListP, - const char * const hdrValue) { +termWindowsStuff(void) { - const char * authorizationHeader; - - xmlrpc_asprintf(&authorizationHeader, "Authorization: %s", hdrValue); - - if (authorizationHeader == xmlrpc_strsol) - xmlrpc_faultf(envP, "Couldn't allocate memory for " - "Authorization header"); - else { - addHeader(envP, headerListP, authorizationHeader); - - xmlrpc_strfree(authorizationHeader); - } +#if defined (WIN32) + WSACleanup(); +#endif } -static void -createCurlHeaderList(xmlrpc_env * const envP, - const char * const authHdrValue, - const char * const userAgent, - struct curl_slist ** const headerListP) { +static bool +curlHasNosignal(void) { - struct curl_slist * headerList; + bool retval; - headerList = NULL; /* initial value - empty list */ +#if HAVE_CURL_NOSIGNAL + curl_version_info_data * const curlInfoP = + curl_version_info(CURLVERSION_NOW); - addContentTypeHeader(envP, &headerList); - if (!envP->fault_occurred) { - addUserAgentHeader(envP, &headerList, userAgent); - if (!envP->fault_occurred) { - if (authHdrValue) - addAuthorizationHeader(envP, &headerList, authHdrValue); - } - } - if (envP->fault_occurred) - curl_slist_free_all(headerList); - else - *headerListP = headerList; + retval = (curlInfoP->version_num >= 0x070A00); /* 7.10.0 */ +#else + retval = false; +#endif + return retval; } -static void -assertConstantsMatch(void) { +static xmlrpc_timespec +pselectTimeout(xmlrpc_timeoutType const timeoutType, + xmlrpc_timespec const timeoutDt) { /*---------------------------------------------------------------------------- - 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. + 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'. -----------------------------------------------------------------------------*/ - 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); -} + unsigned int const million = 1000000; + unsigned int selectTimeoutMillisec; + xmlrpc_timespec retval; + selectTimeoutMillisec = 0; /* quiet compiler warning */ + /* 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; -static size_t -collect(void * const ptr, - size_t const size, - size_t const nmemb, - FILE * const stream) { -/*---------------------------------------------------------------------------- - This is a Curl output function. Curl calls this to deliver the - HTTP response body to the Curl client. Curl thinks it's writing to - a POSIX stream. ------------------------------------------------------------------------------*/ - xmlrpc_mem_block * const responseXmlP = (xmlrpc_mem_block *) stream; - char * const buffer = ptr; - size_t const length = nmemb * size; + xmlrpc_gettimeofday(&nowTime); + timeLeft = timeDiffMillisec(timeoutDt, nowTime); - size_t retval; - xmlrpc_env env; + selectTimeoutMillisec = MIN(3000, MAX(0, timeLeft)); + } break; + } + retval.tv_sec = selectTimeoutMillisec / 1000; + retval.tv_nsec = (uint32_t)((selectTimeoutMillisec % 1000) * million); - 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 ATTR_UNUSED, - double const dlnow ATTR_UNUSED, - double const ultotal ATTR_UNUSED, - double const ulnow ATTR_UNUSED) { -/*---------------------------------------------------------------------------- - 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. In Xmlrpc-c, we don't - implement this purpose. 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 tell Caller it's time to give up if the transport's - client says it is via his "interrupt" flag. - - This function is not as important as it once was. 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. ------------------------------------------------------------------------------*/ - unsigned int * const interruptP = contextP; +static void +processCurlMessages(xmlrpc_env * const envP, + curlMulti * const curlMultiP) { + + bool endOfMessages; - /* We require anyone setting us up as the Curl progress function to - supply an interrupt flag: - */ - assert(contextP); + endOfMessages = false; /* initial assumption */ - return *interruptP != 0 ? 1 : 0; -} + while (!endOfMessages && !envP->fault_occurred) { + CURLMsg curlMsg; + curlMulti_getMessage(curlMultiP, &endOfMessages, &curlMsg); + if (!endOfMessages) { + if (curlMsg.msg == CURLMSG_DONE) { + curlTransaction * curlTransactionP; -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 *basicAuthHdrParamP an appropriate parameter for the - Authorization: Basic: HTTP header. Otherwise, return - *basicAuthHdrParamP == NULL. ------------------------------------------------------------------------------*/ - if (serverInfoP->allowedAuth.basic) { - CURLcode rc; - rc = curl_easy_setopt(curlSessionP, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_easy_getinfo(curlMsg.easy_handle, CURLINFO_PRIVATE, + &curlTransactionP); - if (rc == CURLE_OK) - *authHdrValueP = NULL; - else { - *authHdrValueP = strdup(serverInfoP->basicAuthHdrValue); - if (*authHdrValueP == NULL) - xmlrpc_faultf(envP, "Unable to allocate memory for basic " - "authentication header"); + curlTransaction_finish(envP, + curlTransactionP, curlMsg.data.result); + } } - } else - *authHdrValueP = NULL; - - /* We don't worry if libcurl is too old for these other kinds of - authentication; they're only defined 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. - */ - - if (serverInfoP->userNamePw) - curl_easy_setopt(curlSessionP, CURLOPT_USERPWD, - serverInfoP->userNamePw); - - if (serverInfoP->allowedAuth.digest) - curl_easy_setopt( - curlSessionP, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); - if (serverInfoP->allowedAuth.gssnegotiate) - curl_easy_setopt( - curlSessionP, CURLOPT_HTTPAUTH, CURLAUTH_GSSNEGOTIATE); - if (serverInfoP->allowedAuth.ntlm) - curl_easy_setopt( - curlSessionP, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); -} - - -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 -setupCurlSession(xmlrpc_env * const envP, - curlTransaction * const curlTransactionP, - xmlrpc_mem_block * const callXmlP, - xmlrpc_mem_block * const responseXmlP, - const xmlrpc_server_info * const serverInfoP, - const char * const userAgent, - int * const interruptP, - const struct curlSetup * const curlSetupP) { -/*---------------------------------------------------------------------------- - Set up the Curl session for the transaction *curlTransactionP 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. - - 'interruptP' is a pointer to an interrupt flag -- a flag that becomes - nonzero when the user wants to abandon this Curl session. NULL means - there is no interrupt flag; user will never want to abandon the session. ------------------------------------------------------------------------------*/ - CURL * const curlSessionP = curlTransactionP->curlSessionP; - - assertConstantsMatch(); - - curl_easy_setopt(curlSessionP, CURLOPT_POST, 1); - curl_easy_setopt(curlSessionP, CURLOPT_URL, curlTransactionP->serverUrl); - - XMLRPC_MEMBLOCK_APPEND(char, envP, callXmlP, "\0", 1); - if (!envP->fault_occurred) { - curl_easy_setopt(curlSessionP, CURLOPT_POSTFIELDS, - XMLRPC_MEMBLOCK_CONTENTS(char, callXmlP)); - curl_easy_setopt(curlSessionP, CURLOPT_WRITEFUNCTION, collect); - curl_easy_setopt(curlSessionP, CURLOPT_FILE, responseXmlP); - curl_easy_setopt(curlSessionP, CURLOPT_HEADER, 0); - curl_easy_setopt(curlSessionP, CURLOPT_ERRORBUFFER, - curlTransactionP->curlError); - if (interruptP) { - curl_easy_setopt(curlSessionP, CURLOPT_NOPROGRESS, 0); - curl_easy_setopt(curlSessionP, CURLOPT_PROGRESSFUNCTION, - curlProgress); - curl_easy_setopt(curlSessionP, CURLOPT_PROGRESSDATA, interruptP); - } 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->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->timeout) - setCurlTimeout(curlSessionP, curlSetupP->timeout); - - { - 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, userAgent, - &headerList); - if (!envP->fault_occurred) { - curl_easy_setopt( - curlSessionP, CURLOPT_HTTPHEADER, headerList); - curlTransactionP->headerList = headerList; - } - if (authHdrValue) - xmlrpc_strfree(authHdrValue); - } - } - } -} - - - -static 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, - const char * const userAgent, - const struct curlSetup * const curlSetupStuffP, - rpc * const rpcP, - int * const interruptP, - curlTransaction ** const curlTransactionPP) { - - curlTransaction * curlTransactionP; - - MALLOCVAR(curlTransactionP); - if (curlTransactionP == NULL) - xmlrpc_faultf(envP, "No memory to create Curl transaction."); - else { - curlTransactionP->finish = NULL; - curlTransactionP->curlSessionP = curlSessionP; - curlTransactionP->rpcP = rpcP; - - curlTransactionP->serverUrl = strdup(serverP->serverUrl); - if (curlTransactionP->serverUrl == NULL) - xmlrpc_faultf(envP, "Out of memory to store server URL."); - else { - setupCurlSession(envP, curlTransactionP, - callXmlP, responseXmlP, - serverP, userAgent, interruptP, - curlSetupStuffP); - - if (envP->fault_occurred) - xmlrpc_strfree(curlTransactionP->serverUrl); - } - if (envP->fault_occurred) - free(curlTransactionP); - } - *curlTransactionPP = curlTransactionP; -} - - - -static void -curlTransaction_destroy(curlTransaction * const curlTransactionP) { - - curl_slist_free_all(curlTransactionP->headerList); - xmlrpc_strfree(curlTransactionP->serverUrl); - - free(curlTransactionP); -} - - - -/*============================================================================= - curlMulti -=============================================================================*/ - -typedef struct { -/*---------------------------------------------------------------------------- - 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. - - Plus, it manages Curl transactions (curlTransaction) instead of Curl - sessions (CURL). ------------------------------------------------------------------------------*/ - 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; - - - -static curlMulti * -curlMulti_create(void) { - - curlMulti * retval; - curlMulti * curlMultiP; - - MALLOCVAR(curlMultiP); - - if (curlMultiP == NULL) - retval = NULL; - else { - curlMultiP->lockP = createLock_pthread(); - - 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; -} - - - -static void -curlMulti_destroy(curlMulti * const curlMultiP) { - - curl_multi_cleanup(curlMultiP->curlMultiP); - - curlMultiP->lockP->destroy(curlMultiP->lockP); - - free(curlMultiP); -} - - - -static void -curlMulti_perform(xmlrpc_env * const envP, - curlMulti * const curlMultiP, - bool * const immediateWorkToDoP, - int * const runningHandlesP) { -/*---------------------------------------------------------------------------- - 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. (Caller can query the multi manager for - messages and find out what it is). - - Return as *runningHandlesP the number of Curl easy handles under the - multi manager's control that are still running -- yet to finish. ------------------------------------------------------------------------------*/ - CURLMcode rc; - - curlMultiP->lockP->lock(curlMultiP->lockP); - - rc = curl_multi_perform(curlMultiP->curlMultiP, runningHandlesP); - - curlMultiP->lockP->unlock(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); - } - } -} - - - -static void -curlMulti_addHandle(xmlrpc_env * const envP, - curlMulti * const curlMultiP, - curlTransaction * const curlTransactionP) { - - CURLMcode rc; - - curlMultiP->lockP->lock(curlMultiP->lockP); - - rc = curl_multi_add_handle(curlMultiP->curlMultiP, - curlTransactionP->curlSessionP); - - curlMultiP->lockP->unlock(curlMultiP->lockP); - - if (rc != CURLM_OK) { - 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); - } -} - - -static void -curlMulti_removeHandle(curlMulti * const curlMultiP, - curlTransaction * const curlTransactionP) { - - curlMultiP->lockP->lock(curlMultiP->lockP); - - curl_multi_remove_handle(curlMultiP->curlMultiP, - curlTransactionP->curlSessionP); - - curlMultiP->lockP->unlock(curlMultiP->lockP); -} - - - -static 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->lock(curlMultiP->lockP); - - privateCurlMsgP = curl_multi_info_read(curlMultiP->curlMultiP, - &remainingMsgCount); - - if (privateCurlMsgP == NULL) - *endOfMessagesP = true; - else { - *endOfMessagesP = false; - *curlMsgP = *privateCurlMsgP; - } - curlMultiP->lockP->unlock(curlMultiP->lockP); -} - - - -static 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->lock(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->unlock(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); - } -} - - - -static 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; -} - - - -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; - - selectTimeoutMillisec = 0; /* quiet compiler warning */ - - /* 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, - &curlTransactionP); - - curlTransactionP->result = curlMsg.data.result; - - if (curlTransactionP->finish) - curlTransactionP->finish(envP, curlTransactionP); - } - } - } + } } @@ -1218,430 +430,160 @@ waitForWork(xmlrpc_env * const envP, */ } else { xmlrpc_timespec const pselectTimeoutArg = - pselectTimeout(timeoutType, deadline); - - int rc; - - 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); - } - } - } -} - - - -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); - - 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 runningHandles; - - immediateWorkToDo = true; /* initial assumption */ - - while (immediateWorkToDo && !envP->fault_occurred) { - curlMulti_perform(envP, curlMultiP, - &immediateWorkToDo, &runningHandles); - } - - /* We either did all the work that's ready to do or hit an error. */ - - if (!envP->fault_occurred) { - /* 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 = runningHandles > 0; - } -} - - - -static void -curlMulti_finish(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. - - 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 call that progress function and get the message). ------------------------------------------------------------------------------*/ - bool rpcStillRunning; - bool timedOut; - - rpcStillRunning = true; /* initial assumption */ - timedOut = false; - - while (rpcStillRunning && !timedOut && !envP->fault_occurred) { - - if (interruptP) { - 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. - */ - doCurlWork(envP, curlMultiP, &rpcStillRunning); - - xmlrpc_gettimeofday(&nowTime); - - timedOut = (timeoutType == timeout_yes && - timeIsAfter(nowTime, deadline)); - } - } -} - - - -/*===========================================================================*/ - - -static void -startCurlTransaction(xmlrpc_env * const envP, - curlTransaction * const curlTransactionP, - curlMulti * const curlMultiP, - finishCurlTransactionFn finish) { - - curlTransactionP->finish = finish; - - /* 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. - */ - curl_easy_setopt(curlTransactionP->curlSessionP, CURLOPT_PRIVATE, - curlTransactionP); - - curlMulti_addHandle(envP, curlMultiP, curlTransactionP); -} - - - -static void -getCurlTransactionError(curlTransaction * const curlTransactionP, - xmlrpc_env * const envP) { - - 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. %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 != 200) - xmlrpc_env_set_fault_formatted( - envP, XMLRPC_NETWORK_ERROR, - "HTTP response code is %ld, not 200", - http_result); - } - } -} - - - -static void -performCurlTransaction(xmlrpc_env * const envP, - curlTransaction * const curlTransactionP, - curlMulti * const curlMultiP, - int * const interruptP) { - - void * const finish = NULL; - /* We don't need a finish function because we're going to wait here - for the transaction to complete and then do the next step - ourselves. - */ - - startCurlTransaction(envP, curlTransactionP, curlMultiP, finish); - - /* 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}; - - curlMulti_finish(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 - work? - */ - getCurlTransactionError(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, curlTransactionP); - } -} - - - -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). - */ - const char * userAgent; - /* Prefix for the User-Agent HTTP header, reflecting facilities - outside of Xmlrpc-c. The actual User-Agent header consists - of this prefix plus information about Xmlrpc-c. NULL means - none. + pselectTimeout(timeoutType, deadline); - 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. + int rc; - NULL means none -- transport never gives up. - */ -}; + 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); + } + } + } +} -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. - */ - 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. - */ - struct xmlrpc_call_info * callInfoP; - /* User's identifier for this RPC */ -}; +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); -static void -lockSyncCurlSession(struct xmlrpc_client_transport * const transportP) { - transportP->syncCurlSessionLockP->lock(transportP->syncCurlSessionLockP); + sigfillset(&allSignals); + + sigprocmask(SIG_BLOCK, &allSignals, &callerBlockSet); + + if (*interruptP == 0) + waitForWork(envP, curlMultiP, timeoutType, deadline, &callerBlockSet); + + sigprocmask(SIG_SETMASK, &callerBlockSet, NULL); +#endif } static void -unlockSyncCurlSession(struct xmlrpc_client_transport * const transportP) { - transportP->syncCurlSessionLockP->unlock(transportP->syncCurlSessionLockP); -} +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 runningHandles; -static void -initWindowsStuff(xmlrpc_env * const envP ATTR_UNUSED) { + immediateWorkToDo = true; /* initial assumption */ -#if defined (WIN32) - /* 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(); + while (immediateWorkToDo && !envP->fault_occurred) { + curlMulti_perform(envP, curlMultiP, + &immediateWorkToDo, &runningHandles); + } + + /* We either did all the work that's ready to do or hit an error. */ + + if (!envP->fault_occurred) { + /* 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 = runningHandles > 0; } -#endif } static void -termWindowsStuff(void) { - -#if defined (WIN32) - WSACleanup(); -#endif -} +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. + 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 call that progress function and get the message). +-----------------------------------------------------------------------------*/ + bool rpcStillRunning; + bool timedOut; -static bool -curlHasNosignal(void) { + rpcStillRunning = true; /* initial assumption */ + timedOut = false; + + while (rpcStillRunning && !timedOut && !envP->fault_occurred) { - bool retval; + if (interruptP) { + waitForWorkInt(envP, curlMultiP, timeoutType, deadline, + interruptP); + } else + waitForWork(envP, curlMultiP, timeoutType, deadline, NULL); -#if HAVE_CURL_NOSIGNAL - curl_version_info_data * const curlInfoP = - curl_version_info(CURLVERSION_NOW); + if (!envP->fault_occurred) { + xmlrpc_timespec nowTime; - retval = (curlInfoP->version_num >= 0x070A00); /* 7.10.0 */ -#else - retval = false; -#endif - return retval; + /* doCurlWork() (among other things) finds Curl + transactions that user wants to abort and finishes + them. + */ + doCurlWork(envP, curlMultiP, &rpcStillRunning); + + xmlrpc_gettimeofday(&nowTime); + + timedOut = (timeoutType == timeout_yes && + timeIsAfter(nowTime, deadline)); + } + } } @@ -1921,7 +863,7 @@ static void makeSyncCurlSession(xmlrpc_env * const envP, struct xmlrpc_client_transport * const transportP) { - transportP->syncCurlSessionLockP = createLock_pthread(); + transportP->syncCurlSessionLockP = curlLock_create_pthread(); if (transportP->syncCurlSessionLockP == NULL) xmlrpc_faultf(envP, "Unable to create lock for " "synchronous Curl session."); @@ -1976,8 +918,6 @@ create(xmlrpc_env * const envP, struct xmlrpc_client_transport * transportP; - assertConstantsMatch(); - MALLOCVAR(transportP); if (transportP == NULL) xmlrpc_faultf(envP, "Unable to allocate transport descriptor."); @@ -2044,6 +984,14 @@ 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); @@ -2070,6 +1018,64 @@ destroy(struct xmlrpc_client_transport * const 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 + 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, @@ -2087,6 +1093,7 @@ createRpc(xmlrpc_env * const envP, xmlrpc_faultf(envP, "Couldn't allocate memory for rpc object"); else { rpcP->transportP = clientTransportP; + rpcP->curlSessionP = curlSessionP; rpcP->callInfoP = callInfoP; rpcP->complete = complete; rpcP->responseXmlP = responseXmlP; @@ -2098,7 +1105,8 @@ createRpc(xmlrpc_env * const envP, clientTransportP->userAgent, &clientTransportP->curlSetupStuff, rpcP, - clientTransportP->interruptP, + complete ? &finishRpcCurlTransaction : NULL, + &curlTransactionProgress, &rpcP->curlTransactionP); if (!envP->fault_occurred) { if (envP->fault_occurred) @@ -2136,11 +1144,11 @@ performRpc(xmlrpc_env * const envP, -static finishCurlTransactionFn finishRpcCurlTransaction; +static curlt_finishFn finishRpcCurlTransaction; static void -finishRpcCurlTransaction(xmlrpc_env * const envP ATTR_UNUSED, - curlTransaction * const curlTransactionP) { +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'. @@ -2150,24 +1158,26 @@ finishRpcCurlTransaction(xmlrpc_env * const envP ATTR_UNUSED, 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 = curlTransactionP->rpcP; + 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); - getCurlTransactionError(curlTransactionP, &env); + curlTransaction_getError(curlTransactionP, &env); rpcP->complete(rpcP->callInfoP, rpcP->responseXmlP, env); xmlrpc_env_clean(&env); } - curlMulti_removeHandle(transportP->asyncCurlMultiP, curlTransactionP); - - curl_easy_cleanup(curlTransactionP->curlSessionP); + curl_easy_cleanup(rpcP->curlSessionP); XMLRPC_MEMBLOCK_FREE(char, rpcP->responseXmlP); @@ -2176,14 +1186,20 @@ finishRpcCurlTransaction(xmlrpc_env * const envP ATTR_UNUSED, +static curlt_progressFn curlTransactionProgress; + static void -startRpc(xmlrpc_env * const envP, - rpc * const rpcP) { +curlTransactionProgress(void * const context, + bool * const abortP) { - startCurlTransaction(envP, - rpcP->curlTransactionP, - rpcP->transportP->asyncCurlMultiP, - &finishRpcCurlTransaction); + rpc * const rpcP = context; + + assert(rpcP); + + if (rpcP->transportP->interruptP) + *abortP = *rpcP->transportP->interruptP; + else + *abortP = false; } @@ -2282,19 +1298,19 @@ finishAsynch( addMilliseconds(waitStartTime, timeout, &waitTimeoutTime); } - curlMulti_finish(&env, clientTransportP->asyncCurlMultiP, - timeoutType, waitTimeoutTime, - clientTransportP->interruptP); + 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 the user, but for now we just do this Hail Mary + problem back up to the user, but for now we just do this Hail Mary response. - Note that a failure of curlMult_finish() does not mean that + 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 @@ -2400,4 +1416,4 @@ struct xmlrpc_client_transport_ops xmlrpc_curl_transport_ops = { &call, &finishAsynch, &setInterrupt, -}; +}; \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/expat/gennmtab/Makefile b/libs/xmlrpc-c/lib/expat/gennmtab/Makefile index 32e76b7..4153c05 100644 --- a/libs/xmlrpc-c/lib/expat/gennmtab/Makefile +++ b/libs/xmlrpc-c/lib/expat/gennmtab/Makefile @@ -47,4 +47,4 @@ gennmtab.o:%.o:%.c gennmtab:%:%.o $(BUILDTOOL_CCLD) -o $@ $(LDFLAGS) $^ -include Makefile.depend +include depend.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/expat/xmltok/Makefile b/libs/xmlrpc-c/lib/expat/xmltok/Makefile index cfcb8dd..e0bfe0b 100644 --- a/libs/xmlrpc-c/lib/expat/xmltok/Makefile +++ b/libs/xmlrpc-c/lib/expat/xmltok/Makefile @@ -105,4 +105,4 @@ $(GENNMTAB): xmltok.o xmltok.osh: nametab.h -include Makefile.depend +include depend.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/expat/xmltok/xmltok_impl.c b/libs/xmlrpc-c/lib/expat/xmltok/xmltok_impl.c index cc9bc59..2a55ea5 100644 --- a/libs/xmlrpc-c/lib/expat/xmltok/xmltok_impl.c +++ b/libs/xmlrpc-c/lib/expat/xmltok/xmltok_impl.c @@ -1711,7 +1711,7 @@ void PREFIX(updatePosition)(const ENCODING *enc, const char *end, POSITION *pos) { - while (ptr != end) { + while (ptr < end) { switch (BYTE_TYPE(enc, ptr)) { #define LEAD_CASE(n) \ case BT_LEAD ## n: \ @@ -1745,4 +1745,4 @@ void PREFIX(updatePosition)(const ENCODING *enc, #undef CHECK_NAME_CASE #undef CHECK_NAME_CASES #undef CHECK_NMSTRT_CASE -#undef CHECK_NMSTRT_CASES +#undef CHECK_NMSTRT_CASES \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/libutil/Makefile b/libs/xmlrpc-c/lib/libutil/Makefile index 7c75a37..b3ea50e 100644 --- a/libs/xmlrpc-c/lib/libutil/Makefile +++ b/libs/xmlrpc-c/lib/libutil/Makefile @@ -92,4 +92,4 @@ distclean: clean distclean-common .PHONY: dep dep: dep-common -include Makefile.depend +include depend.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/libutil/asprintf.c b/libs/xmlrpc-c/lib/libutil/asprintf.c index 9e5a614..6c58943 100644 --- a/libs/xmlrpc-c/lib/libutil/asprintf.c +++ b/libs/xmlrpc-c/lib/libutil/asprintf.c @@ -1,10 +1,56 @@ -//#define _GNU_SOURCE +#define _GNU_SOURCE #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; + } + } +} @@ -15,29 +61,24 @@ simpleVasprintf(char ** const retvalP, /*---------------------------------------------------------------------------- This is a poor man's implementation of vasprintf(), of GNU fame. -----------------------------------------------------------------------------*/ - size_t const initialSize = 4096; char * result; - - result = malloc(initialSize); - if (result != NULL) { - size_t bytesNeeded; - bytesNeeded = XMLRPC_VSNPRINTF(result, initialSize, fmt, varargs); - if (bytesNeeded > initialSize) { - free(result); - result = malloc(bytesNeeded); - if (result != NULL) - XMLRPC_VSNPRINTF(result, bytesNeeded, fmt, varargs); - } else if (bytesNeeded == initialSize) { - if (result[initialSize-1] != '\0') { - /* This is one of those old systems where vsnprintf() - returns the number of bytes it used, instead of the - number that it needed, and it in fact needed more than - we gave it. Rather than mess with this highly unlikely - case (old system and string > 4095 characters), we just - treat this like an out of memory failure. - */ + 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; } } } @@ -113,4 +154,3 @@ xmlrpc_strfreenull(const char * const string) { } - diff --git a/libs/xmlrpc-c/lib/libutil/make_printable.c b/libs/xmlrpc-c/lib/libutil/make_printable.c index fc94f78..b13e663 100644 --- a/libs/xmlrpc-c/lib/libutil/make_printable.c +++ b/libs/xmlrpc-c/lib/libutil/make_printable.c @@ -1,4 +1,4 @@ -//#define _GNU_SOURCE +#define _GNU_SOURCE #include #include @@ -98,4 +98,4 @@ xmlrpc_makePrintableChar(char const input) { retval = xmlrpc_makePrintable(buffer); } return retval; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/libutil/utf8.c b/libs/xmlrpc-c/lib/libutil/utf8.c index d0de07e..60b77b6 100644 --- a/libs/xmlrpc-c/lib/libutil/utf8.c +++ b/libs/xmlrpc-c/lib/libutil/utf8.c @@ -251,19 +251,6 @@ decode_utf8(xmlrpc_env * const envP, -void -xmlrpc_validate_utf8(xmlrpc_env * const env, - const char * const utf8_data, - size_t const utf8_len) { -/*---------------------------------------------------------------------------- - Validate that a string is valid UTF-8. ------------------------------------------------------------------------------*/ - - decode_utf8(env, utf8_data, utf8_len, NULL, NULL); -} - - - xmlrpc_mem_block * xmlrpc_utf8_to_wcs(xmlrpc_env * const envP, const char * const utf8_data, @@ -329,7 +316,8 @@ xmlrpc_wcs_to_utf8(xmlrpc_env * const envP, utf8P = XMLRPC_MEMBLOCK_NEW(char, envP, estimate); if (!envP->fault_occurred) { - unsigned char * const buffer = XMLRPC_MEMBLOCK_CONTENTS(char, utf8P); + unsigned char * const buffer = + XMLRPC_MEMBLOCK_CONTENTS(unsigned char, utf8P); size_t bytesUsed; size_t i; @@ -401,7 +389,7 @@ xmlrpc_force_to_utf8(char * const buffer) { char * p; for (p = &buffer[0]; *p;) { - uint const length = utf8_seq_length[(unsigned char) *p]; + unsigned int const length = utf8_seq_length[(unsigned char) *p]; bool forceDel; uint32_t decoded; @@ -482,7 +470,7 @@ xmlrpc_force_to_xml_chars(char * const buffer) { char * p; for (p = &buffer[0]; *p;) { - uint const length = utf8_seq_length[(unsigned char) *p]; + unsigned int const length = utf8_seq_length[(unsigned char) *p]; if (length == 1) { if (*p < 0x20 && *p != '\r' && *p != '\n' && *p != '\t') @@ -505,7 +493,18 @@ xmlrpc_force_to_xml_chars(char * const buffer) { - - - - +void +xmlrpc_validate_utf8(xmlrpc_env * const env, + const char * const utf8_data, + size_t const utf8_len) { +/*---------------------------------------------------------------------------- + Validate that a string is valid UTF-8. +-----------------------------------------------------------------------------*/ +#if HAVE_UNICODE_WCHAR + decode_utf8(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 +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/libwww_transport/Makefile b/libs/xmlrpc-c/lib/libwww_transport/Makefile index 1bb362c..f573986 100644 --- a/libs/xmlrpc-c/lib/libwww_transport/Makefile +++ b/libs/xmlrpc-c/lib/libwww_transport/Makefile @@ -51,8 +51,8 @@ install: .PHONY: dep dep: dep-common -include Makefile.depend +include depend.mk -# Need this dependency for those who don't use Makefile.depend. +# 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_libwww_transport.o xmlrpc_libwww_transport.osh: version.h \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/util/Makefile b/libs/xmlrpc-c/lib/util/Makefile index a061b2e..0acfc54 100644 --- a/libs/xmlrpc-c/lib/util/Makefile +++ b/libs/xmlrpc-c/lib/util/Makefile @@ -54,7 +54,7 @@ CFLAGS = $(CFLAGS_COMMON) $(INCLUDES) $(CFLAGS_PERSONAL) $(CADD) %.o:%.cpp $(CXX) -c $(CFLAGS) $< -include Makefile.depend +include depend.mk .PHONY: clean distclean clean: clean-common diff --git a/libs/xmlrpc-c/lib/util/casprintf.c b/libs/xmlrpc-c/lib/util/casprintf.c index 959e4ce..337c4c8 100644 --- a/libs/xmlrpc-c/lib/util/casprintf.c +++ b/libs/xmlrpc-c/lib/util/casprintf.c @@ -1,43 +1,84 @@ -//#define _GNU_SOURCE +#define _GNU_SOURCE #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. -----------------------------------------------------------------------------*/ - size_t const initialSize = 4096; char * result; - - result = malloc(initialSize); - if (result != NULL) { - size_t bytesNeeded; - bytesNeeded = XMLRPC_VSNPRINTF(result, initialSize, fmt, varargs); - if (bytesNeeded > initialSize) { - free(result); - result = malloc(bytesNeeded); - if (result != NULL) - XMLRPC_VSNPRINTF(result, bytesNeeded, fmt, varargs); - } else if (bytesNeeded == initialSize) { - if (result[initialSize-1] != '\0') { - /* This is one of those old systems where vsnprintf() - returns the number of bytes it used, instead of the - number that it needed, and it in fact needed more than - we gave it. Rather than mess with this highly unlikely - case (old system and string > 4095 characters), we just - treat this like an out of memory failure. - */ + 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; } } } @@ -90,4 +131,4 @@ strfree(const char * const string) { if (string != strsol) free((void *)string); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/util/include/int.h b/libs/xmlrpc-c/lib/util/include/int.h index 253ea34..4e707f1 100644 --- a/libs/xmlrpc-c/lib/util/include/int.h +++ b/libs/xmlrpc-c/lib/util/include/int.h @@ -11,6 +11,14 @@ 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" @@ -33,9 +41,6 @@ typedef __int64 int64_t; #ifndef uint64_t typedef unsigned __int64 uint64_t; #endif -#ifndef uint -typedef unsigned int uint; -#endif #ifndef uint8_t typedef unsigned char uint8_t; #endif @@ -50,4 +55,3 @@ typedef unsigned char uint8_t; #define LL(x) x ## ll #define ULL(x) x ## ull #endif - diff --git a/libs/xmlrpc-c/lib/util/include/mallocvar.h b/libs/xmlrpc-c/lib/util/include/mallocvar.h index 5dd9fc9..5231107 100644 --- a/libs/xmlrpc-c/lib/util/include/mallocvar.h +++ b/libs/xmlrpc-c/lib/util/include/mallocvar.h @@ -102,10 +102,9 @@ do { \ #define MALLOCVAR(varName) \ - if (varName = malloc(sizeof(*varName))) memset(varName, 0, sizeof(*varName)) + varName = malloc(sizeof(*varName)) #define MALLOCVAR_NOFAIL(varName) \ do {if ((varName = malloc(sizeof(*varName))) == NULL) abort();} while(0) #endif - diff --git a/libs/xmlrpc-c/lib/util/string_parser.c b/libs/xmlrpc-c/lib/util/string_parser.c index 32879f5..98e6cb5 100644 --- a/libs/xmlrpc-c/lib/util/string_parser.c +++ b/libs/xmlrpc-c/lib/util/string_parser.c @@ -94,9 +94,9 @@ interpretLl(const char * const string, void -interpretUint(const char * const string, - uint * const uintP, - const char ** const errorP) { +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 @@ -223,4 +223,4 @@ interpretBinUint(const char * const string, *valueP = (uint64_t) argNumber; } } -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/lib/util/stripcaseeq.c b/libs/xmlrpc-c/lib/util/stripcaseeq.c index 348a868..35795ba 100644 --- a/libs/xmlrpc-c/lib/util/stripcaseeq.c +++ b/libs/xmlrpc-c/lib/util/stripcaseeq.c @@ -1,4 +1,4 @@ -//#define _GNU_SOURCE +#define _GNU_SOURCE #include #include "bool.h" @@ -66,4 +66,3 @@ stripcaseeq(const char * const comparand, } return equal; } - diff --git a/libs/xmlrpc-c/lib/wininet_transport/Makefile b/libs/xmlrpc-c/lib/wininet_transport/Makefile index 648c6c3..7af37ac 100644 --- a/libs/xmlrpc-c/lib/wininet_transport/Makefile +++ b/libs/xmlrpc-c/lib/wininet_transport/Makefile @@ -48,8 +48,8 @@ install: .PHONY: dep dep: dep-common -include Makefile.depend +include depend.mk -# Need this dependency for those who don't use Makefile.depend. +# 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_wininet_transport.o xmlrpc_wininet_transport.osh: version.h \ No newline at end of file diff --git a/libs/xmlrpc-c/src/Makefile b/libs/xmlrpc-c/src/Makefile index 50514b2..9070f2d 100644 --- a/libs/xmlrpc-c/src/Makefile +++ b/libs/xmlrpc-c/src/Makefile @@ -53,6 +53,9 @@ ifeq ($(MUST_BUILD_WININET_CLIENT),yes) 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_MODS += $(BLDDIR)/lib/curl_transport/lock_pthread TRANSPORT_LIBDEP += $(shell curl-config --libs) endif ifeq ($(MUST_BUILD_LIBWWW_CLIENT),yes) @@ -66,8 +69,10 @@ ifeq ($(ENABLE_LIBXML2_BACKEND),yes) XML_PARSER_LIBDEP_DEP = else XMLRPC_XML_PARSER = xmlrpc_expat - XML_PARSER_LIBDEP = -L$(BLDDIR)/lib/expat/xmlparse -lxmlrpc_xmlparse - XML_PARSER_LIBDEP_DEP = $(LIBXMLRPC_XMLPARSE) + XML_PARSER_LIBDEP = \ + -L$(BLDDIR)/lib/expat/xmlparse -lxmlrpc_xmlparse \ + -L$(BLDDIR)/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. @@ -160,7 +165,7 @@ $(LIBXMLRPC_SERVER): \ $(call shliblefn, libxmlrpc) $(LIBXMLRPC_SERVER): LIBOBJECTS = $(LIBXMLRPC_SERVER_MODS:%=%.osh) $(LIBXMLRPC_SERVER): LIBDEP = \ - -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util -L. -lxmlrpc + -L. -lxmlrpc $(XML_PARSER_LIBDEP) -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util LIBXMLRPC_SERVER_ABYSS = $(call shlibfn, libxmlrpc_server_abyss) @@ -172,10 +177,9 @@ $(LIBXMLRPC_SERVER_ABYSS): \ $(call shliblefn, libxmlrpc) $(LIBXMLRPC_SERVER_ABYSS): LIBOBJECTS = $(LIBXMLRPC_SERVER_ABYSS_MODS:%=%.osh) $(LIBXMLRPC_SERVER_ABYSS): LIBDEP = \ - -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util \ -L. -lxmlrpc_server \ -L$(LIBXMLRPC_ABYSS_DIR) -lxmlrpc_abyss \ - -lxmlrpc + -L. -lxmlrpc $(XML_PARSER_LIBDEP) -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util LIBXMLRPC_SERVER_CGI = $(call shlibfn, libxmlrpc_server_cgi) @@ -186,7 +190,8 @@ $(LIBXMLRPC_SERVER_CGI): \ $(call shliblefn, libxmlrpc) $(LIBXMLRPC_SERVER_CGI): LIBOBJECTS = $(LIBXMLRPC_SERVER_CGI_MODS:%=%.osh) $(LIBXMLRPC_SERVER_CGI): LIBDEP = \ - -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util -L. -lxmlrpc_server -lxmlrpc + -L. -lxmlrpc_server \ + -L. -lxmlrpc $(XML_PARSER_LIBDEP) -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util LIBXMLRPC_CLIENT = $(call shlibfn, libxmlrpc_client) @@ -199,10 +204,8 @@ $(LIBXMLRPC_CLIENT): LIBOBJECTS = \ $(LIBXMLRPC_CLIENT_MODS:%=%.osh) \ $(TRANSPORT_MODS:%=%.osh) $(LIBXMLRPC_CLIENT): LIBDEP = \ - -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util \ - -L. -lxmlrpc \ - $(TRANSPORT_LIBDEP) - + $(TRANSPORT_LIBDEP) \ + -L. -lxmlrpc $(XML_PARSER_LIBDEP) -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util libxmlrpc.a: $(LIBXMLRPC_MODS:%=%.o) libxmlrpc.a: LIBOBJECTS = $(LIBXMLRPC_MODS:%=%.o) @@ -293,4 +296,4 @@ xmlrpc_client.o xmlrpc_client.osh: $(BLDDIR)/version.h registry.o registry.osh: $(BLDDIR)/version.h version.o version.osh: $(BLDDIR)/version.h -include Makefile.depend +include depend.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/Makefile b/libs/xmlrpc-c/src/cpp/Makefile index fa2fac4..7fa582b 100644 --- a/libs/xmlrpc-c/src/cpp/Makefile +++ b/libs/xmlrpc-c/src/cpp/Makefile @@ -13,22 +13,26 @@ default: all # libxmlrpc_cpp is the legacy C++ wrapper library. The others are the # more elaborate replacements. -TARGET_LIB_NAMES_PP := \ +TARGET_LIB_NAMES_PP = \ libxmlrpc_cpp \ - libxmlrpc++ \ + lib$(LIBXMLRPCPP_NAME) \ libxmlrpc_server++ \ - libxmlrpc_server_abyss++ \ + 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) +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) \ @@ -45,10 +49,19 @@ 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 = \ base64 env_wrap fault girerr girmem 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 LIBXMLRPC_CLIENTPP_MODS = client client_simple curl libwww wininet pstream LIBXMLRPC_PACKETSOCKET_MODS = packetsocket @@ -58,6 +71,7 @@ TARGET_MODS_PP = \ $(LIBXMLRPCPP_MODS) \ $(LIBXMLRPC_SERVERPP_MODS) \ $(LIBXMLRPC_SERVER_ABYSSPP_MODS) \ + $(LIBXMLRPC_SERVER_CGIPP_MODS) \ $(LIBXMLRPC_SERVER_PSTREAMPP_MODS) \ $(LIBXMLRPC_CLIENTPP_MODS) \ $(LIBXMLRPC_PACKETSOCKET_MODS) \ @@ -104,63 +118,113 @@ all: \ # shlibfn generates e.g. libxmlrpc.so.3.1 # shliblefn generates e.g. libxmlrpc.so -LIBXMLRPC_CPP = $(call shlibfn, libxmlrpc_cpp) +LIBXMLRPC_CPP_SH = $(call shlibfn, libxmlrpc_cpp) -$(LIBXMLRPC_CPP): XmlRpcCpp.osh -$(LIBXMLRPC_CPP): LIBOBJECTS = XmlRpcCpp.osh +$(LIBXMLRPC_CPP_SH): XmlRpcCpp.osh \ + $(LIBXMLRPC_UTIL) +$(LIBXMLRPC_CPP_SH): LIBOBJECTS = XmlRpcCpp.osh +$(LIBXMLRPC_CPP_SH): LIBDEP = \ + -Lblddir/src -lxmlrpc_server -lxmlrpc \ + $(XML_PARSER_LIBDEP) \ + -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util -LIBXMLRPCPP = $(call shlibfn, libxmlrpc++) +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 -$(LIBXMLRPCPP): $(LIBXMLRPCPP_MODS:%=%.osh) \ - $(LIBXMLRPC) -$(LIBXMLRPCPP): LIBOBJECTS = $(LIBXMLRPCPP_MODS:%=%.osh) -$(LIBXMLRPCPP): LIBDEP = -Lblddir/src -lxmlrpc -LIBXMLRPC_SERVERPP = $(call shlibfn, libxmlrpc_server++) +LIBXMLRPC_SERVERPP_SH = $(call shlibfn, libxmlrpc_server++) -$(LIBXMLRPC_SERVERPP): $(LIBXMLRPC_SERVERPP_MODS:%=%.osh) \ +$(LIBXMLRPC_SERVERPP_SH): $(LIBXMLRPC_SERVERPP_MODS:%=%.osh) \ $(LIBXMLRPC_SERVER) \ + $(call shliblefn, lib$(LIBXMLRPCPP_NAME)) \ + $(LIBXMLRPC_UTIL) \ $(LIBXMLRPC) -$(LIBXMLRPC_SERVERPP): LIBOBJECTS = $(LIBXMLRPC_SERVERPP_MODS:%=%.osh) -$(LIBXMLRPC_SERVERPP): LIBDEP = -Lblddir/src -lxmlrpc_server -lxmlrpc +$(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 -LIBXMLRPC_SERVER_ABYSSPP = $(call shlibfn, libxmlrpc_server_abyss++) +LIBXMLRPC_SERVER_ABYSSPP_SH = $(call shlibfn, libxmlrpc_server_abyss++) -$(LIBXMLRPC_SERVER_ABYSSPP): $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.osh) \ +$(LIBXMLRPC_SERVER_ABYSSPP_SH): $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.osh) \ $(LIBXMLRPC_ABYSS) \ $(LIBXMLRPC) -$(LIBXMLRPC_SERVER_ABYSSPP): LIBOBJECTS = $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.osh) -$(LIBXMLRPC_SERVER_ABYSSPP): LIBDEP = \ - -L$(LIBXMLRPC_ABYSS_DIR) -lxmlrpc_abyss -Lblddir/src -lxmlrpc +$(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 \ + +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 -LIBXMLRPC_SERVER_PSTREAMPP = $(call shlibfn, libxmlrpc_server_pstream++) +LIBXMLRPC_SERVER_PSTREAMPP_SH = $(call shlibfn, libxmlrpc_server_pstream++) -$(LIBXMLRPC_SERVER_PSTREAMPP): $(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.osh) \ +$(LIBXMLRPC_SERVER_PSTREAMPP_SH): $(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.osh) \ $(LIBXMLRPC_SERVER) \ - $(LIBXMLRPC_PACKETSOCKET) -$(LIBXMLRPC_SERVER_PSTREAMPP): LIBOBJECTS = $(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.osh) -$(LIBXMLRPC_SERVER_PSTREAMPP): LIBDEP = \ - -Lblddir/src -lxmlrpc_server -L. -lxmlrpc_packetsocket - -LIBXMLRPC_CLIENTPP = $(call shlibfn, libxmlrpc_client++) - -$(LIBXMLRPC_CLIENTPP): $(LIBXMLRPC_CLIENTPP_MODS:%=%.osh) \ - $(LIBXMLRPCPP) \ + $(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 \ + +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) -$(LIBXMLRPC_CLIENTPP): LIBOBJECTS = $(LIBXMLRPC_CLIENTPP_MODS:%=%.osh) -$(LIBXMLRPC_CLIENTPP): LIBDEP = \ - -L. -lxmlrpc++ -Lblddir/src -lxmlrpc_client - -LIBXMLRPC_PACKETSOCKET = $(call shlibfn, libxmlrpc_packetsocket) - -$(LIBXMLRPC_PACKETSOCKET): $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.osh) -$(LIBXMLRPC_PACKETSOCKET): LIBOBJECTS = $(LIBXMLRPC_PACKETSOCKET_MODS:%=%.osh) +$(LIBXMLRPC_CLIENTPP_SH): LIBOBJECTS = $(LIBXMLRPC_CLIENTPP_MODS:%=%.osh) +$(LIBXMLRPC_CLIENTPP_SH): LIBDEP = \ + -L. -l$(LIBXMLRPCPP_NAME) -lxmlrpc_packetsocket \ + -Lblddir/src -lxmlrpc_client -lxmlrpc \ + $(XML_PARSER_LIBDEP) \ + -L$(LIBXMLRPC_UTIL_DIR) -lxmlrpc_util + +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 libxmlrpc_cpp.a: XmlRpcCpp.o libxmlrpc_cpp.a: LIBOBJECTS = XmlRpcCpp.o -libxmlrpc++.a: $(LIBXMLRPCPP_MODS:%=%.o) -libxmlrpc++.a: LIBOBJECTS = $(LIBXMLRPCPP_MODS:%=%.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) @@ -168,6 +232,9 @@ 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) @@ -197,11 +264,15 @@ $(LIBXMLRPC_SERVERPP_MODS:%=%.osh): \ INCLUDES = $(SERVER_INCLUDES) $(LIBXMLRPC_SERVER_ABYSSPP_MODS:%=%.o) \ -$(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:%=%.o): \ +$(LIBXMLRPC_SERVER_PSTREAMPP_MODS:%=%.osh): \ INCLUDES = $(SERVER_INCLUDES) $(LIBXMLRPC_CLIENTPP_MODS:%=%.o) \ @@ -242,4 +313,4 @@ distclean-local: .PHONY: dep dep: dep-common $(BLDDIR)/transport_config.h -include Makefile.depend +include depend.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/base64.cpp b/libs/xmlrpc-c/src/cpp/base64.cpp index f9c0dac..60d0de3 100644 --- a/libs/xmlrpc-c/src/cpp/base64.cpp +++ b/libs/xmlrpc-c/src/cpp/base64.cpp @@ -77,7 +77,7 @@ public: assert(bitsInBuffer >= 8); - *outputP = (this->buffer >> (this->bitsInBuffer - 8)) & 0x3f; + *outputP = (this->buffer >> (this->bitsInBuffer - 8)) & 0xff; this->bitsInBuffer -= 8; } @@ -231,4 +231,4 @@ bytesFromBase64(string const& base64) { return retval; } -} //namespace +} //namespace \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/client.cpp b/libs/xmlrpc-c/src/cpp/client.cpp index 2dba1bd..a3039c4 100644 --- a/libs/xmlrpc-c/src/cpp/client.cpp +++ b/libs/xmlrpc-c/src/cpp/client.cpp @@ -26,6 +26,7 @@ using girmem::autoObject; #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" @@ -1232,4 +1233,4 @@ xmlTransaction_clientPtr::operator->() const { -} // namespace +} // namespace \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/registry.cpp b/libs/xmlrpc-c/src/cpp/registry.cpp index 26bfa95..1ed0686 100644 --- a/libs/xmlrpc-c/src/cpp/registry.cpp +++ b/libs/xmlrpc-c/src/cpp/registry.cpp @@ -173,7 +173,8 @@ pListFromXmlrpcArray(xmlrpc_value * const arrayP) { static xmlrpc_value * c_executeMethod(xmlrpc_env * const envP, xmlrpc_value * const paramArrayP, - void * const methodPtr) { + void * const methodPtr, + void *) { /*---------------------------------------------------------------------------- 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 @@ -298,13 +299,19 @@ registry::addMethod(string const name, this->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_method_w_doc( - &env.env_c, this->c_registryP, NULL, - name.c_str(), &c_executeMethod, - (void*) methodP.get(), - methodP->signature().c_str(), methodP->help().c_str()); + xmlrpc_registry_add_method3(&env.env_c, this->c_registryP, &methodInfo); throwIfError(env); } @@ -425,4 +432,4 @@ registry::c_registry() const { } // namespace -registry::shutdown::~shutdown() {} +registry::shutdown::~shutdown() {} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/server_abyss.cpp b/libs/xmlrpc-c/src/cpp/server_abyss.cpp index 3501f35..b62d535 100644 --- a/libs/xmlrpc-c/src/cpp/server_abyss.cpp +++ b/libs/xmlrpc-c/src/cpp/server_abyss.cpp @@ -71,7 +71,8 @@ sigchld(int const ASSERT_ONLY_ARG(signalClass)) { // This is OK - it's a ptrace notification } else error = true; - } + } else + ServerHandleSigchld(pid); } #endif /* _WIN32 */ } @@ -402,6 +403,8 @@ serverAbyss::run() { ServerRun(&this->cServer); + ServerUseSigchld(&this->cServer); + restoreSignalHandlers(oldHandlers); } @@ -465,4 +468,4 @@ server_abyss_set_handlers(TServer * const srvP, -} // namespace +} // namespace \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/test/Makefile b/libs/xmlrpc-c/src/cpp/test/Makefile index ff6750f..83dc860 100644 --- a/libs/xmlrpc-c/src/cpp/test/Makefile +++ b/libs/xmlrpc-c/src/cpp/test/Makefile @@ -104,4 +104,4 @@ distclean: clean distclean-common .PHONY: dep dep: dep-common -include Makefile.depend +include depend.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/test/registry.cpp b/libs/xmlrpc-c/src/cpp/test/registry.cpp index 6ca265a..4b80efb 100644 --- a/libs/xmlrpc-c/src/cpp/test/registry.cpp +++ b/libs/xmlrpc-c/src/cpp/test/registry.cpp @@ -20,8 +20,14 @@ using namespace xmlrpc_c; using namespace std; -string const xmlPrologue("\r\n"); +static string const +xmlPrologue("\r\n"); +static string const +apacheUrl("http://ws.apache.org/xmlrpc/namespaces/extensions"); + +static string const +xmlnsApache("xmlns:ex=\"" + apacheUrl + "\""); namespace { @@ -128,26 +134,26 @@ string const nonexistentMethodNoDefResponseXml( string const echoI8ApacheCall( xmlPrologue + - "\r\n" + "\r\n" "echo\r\n" "\r\n" - "5\r\n" + "5\r\n" "\r\n" "\r\n" ); string const echoI8ApacheResponse( xmlPrologue + - "\r\n" + "\r\n" "\r\n" - "5\r\n" + "5\r\n" "\r\n" "\r\n" ); string const echoNilApacheCall( xmlPrologue + - "\r\n" + "\r\n" "echo\r\n" "\r\n" "\r\n" @@ -157,9 +163,9 @@ string const echoNilApacheCall( string const echoNilApacheResponse( xmlPrologue + - "\r\n" + "\r\n" "\r\n" - "\r\n" + "\r\n" "\r\n" "\r\n" ); @@ -355,4 +361,4 @@ registryTestSuite::runtests(unsigned int const indentation) { EXPECT_ERROR( // invalid dialect myRegistry.setDialect(static_cast(300)); ); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/test/test.cpp b/libs/xmlrpc-c/src/cpp/test/test.cpp index c92653f..d0e7269 100644 --- a/libs/xmlrpc-c/src/cpp/test/test.cpp +++ b/libs/xmlrpc-c/src/cpp/test/test.cpp @@ -307,6 +307,56 @@ public: +#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 + + + class datetimeTestSuite : public testSuite { public: virtual string suiteName() { @@ -322,6 +372,18 @@ public: 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 try { value_datetime datetime4(value_int(4)); TEST_FAILED("invalid cast int-datetime suceeded"); @@ -637,4 +699,4 @@ main(int argc, char**) { retval = 1; } return retval; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/test/testclient.cpp b/libs/xmlrpc-c/src/cpp/test/testclient.cpp index 6eadf8d..3ca794a 100644 --- a/libs/xmlrpc-c/src/cpp/test/testclient.cpp +++ b/libs/xmlrpc-c/src/cpp/test/testclient.cpp @@ -35,7 +35,7 @@ using namespace std; class sampleAddMethod : public method { public: sampleAddMethod() { - this->_signature = "ii"; + this->_signature = "i:ii"; this->_help = "This method adds two integers together"; } void @@ -858,4 +858,4 @@ clientTestSuite::runtests(unsigned int const indentation) { serverAccessorTestSuite().run(indentation+1); xmlTestSuite().run(indentation+1); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/cpp/value.cpp b/libs/xmlrpc-c/src/cpp/value.cpp index 6dcba93..60f41fd 100644 --- a/libs/xmlrpc-c/src/cpp/value.cpp +++ b/libs/xmlrpc-c/src/cpp/value.cpp @@ -64,6 +64,22 @@ public: 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); } @@ -393,7 +409,7 @@ value_datetime::value_datetime(time_t const cppvalue) { #if XMLRPC_HAVE_TIMEVAL value_datetime::value_datetime(struct timeval const& cppvalue) { - cDatetimeValueWrapper wrapper(cppvalue.tv_sec); + cDatetimeValueWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } @@ -404,7 +420,7 @@ value_datetime::value_datetime(struct timeval const& cppvalue) { #if XMLRPC_HAVE_TIMESPEC value_datetime::value_datetime(struct timespec const& cppvalue) { - cDatetimeValueWrapper wrapper(cppvalue.tv_sec); + cDatetimeValueWrapper wrapper(cppvalue); this->instantiate(wrapper.valueP); } @@ -436,6 +452,38 @@ value_datetime::operator time_t() const { +#if XMLRPC_HAVE_TIMEVAL + +value_datetime::operator timeval() const { + + 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 { + + struct timespec retval; + env_wrap env; + + xmlrpc_read_datetime_timespec(&env.env_c, this->cValueP, &retval); + throwIfError(env); + + return retval; +} +#endif + + + class cNewStringWrapper { public: xmlrpc_value * valueP; @@ -879,4 +927,4 @@ value_i8::operator xmlrpc_int64() const { -} // namespace +} // namespace \ No newline at end of file diff --git a/libs/xmlrpc-c/src/double.c b/libs/xmlrpc-c/src/double.c index 1968d40..7bc0034 100644 --- a/libs/xmlrpc-c/src/double.c +++ b/libs/xmlrpc-c/src/double.c @@ -3,6 +3,7 @@ #include #include "xmlrpc-c/util.h" +#include "xmlrpc-c/util_int.h" #include "double.h" @@ -58,6 +59,23 @@ digitChar(unsigned int const 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, @@ -88,7 +106,8 @@ floatWhole(double const value, */ leastValue = 0; } else - leastValue = (unsigned int)(value - nonLeastAmount * 10); + leastValue = leadDigit(value - nonLeastAmount * 10, + nonLeastPrecision * 10); bufferConcat(formattedP, digitChar(leastValue)); @@ -120,7 +139,7 @@ floatFractionPart(double const value, unsigned int digitValue; d *= 10; - digitValue = (unsigned int) d; + digitValue = leadDigit(d, precision); d -= digitValue; @@ -154,7 +173,7 @@ floatFraction(double const value, precision = DBL_EPSILON; while (d > precision) { - unsigned int const digitValue = (unsigned int) d; + unsigned int const digitValue = leadDigit(d, precision); bufferConcat(formattedP, digitChar(digitValue)); @@ -212,4 +231,4 @@ xmlrpc_formatFloat(xmlrpc_env * const envP, xmlrpc_faultf(envP, "Couldn't allocate memory to format %g", value); else *formattedP = formatted.bytes; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/method.c b/libs/xmlrpc-c/src/method.c index cf58b26..1abb5f0 100644 --- a/libs/xmlrpc-c/src/method.c +++ b/libs/xmlrpc-c/src/method.c @@ -210,7 +210,7 @@ listSignatures(xmlrpc_env * const envP, cursorP = &sigListString[0]; while (!envP->fault_occurred && *cursorP != '\0') { - struct xmlrpc_signature * signatureP = NULL; + struct xmlrpc_signature * signatureP; parseOneSignature(envP, cursorP, &signatureP, &cursorP); @@ -293,6 +293,8 @@ makeSignatureList(xmlrpc_env * const envP, if (env.fault_occurred) xmlrpc_faultf(envP, "Can't interpret signature string '%s'. %s", signatureString, env.fault_string); + + xmlrpc_env_clean(&env); } @@ -304,6 +306,7 @@ xmlrpc_methodCreate(xmlrpc_env * const envP, void * const userData, const char * const signatureString, const char * const helpText, + size_t const stackSize, xmlrpc_methodInfo ** const methodPP) { xmlrpc_methodInfo * methodP; @@ -319,12 +322,15 @@ xmlrpc_methodCreate(xmlrpc_env * const envP, methodP->methodFnType1 = methodFnType1; methodP->methodFnType2 = methodFnType2; methodP->userData = userData; - methodP->helpText = strdup(helpText); + xmlrpc_asprintf(&methodP->helpText, "%s", helpText); + methodP->stackSize = stackSize; makeSignatureList(envP, signatureString, &methodP->signatureListP); - if (envP->fault_occurred) + if (envP->fault_occurred) { + xmlrpc_strfree(methodP->helpText); free(methodP); + } *methodPP = methodP; } @@ -447,4 +453,3 @@ xmlrpc_methodListAdd(xmlrpc_env * const envP, } } } - diff --git a/libs/xmlrpc-c/src/method.h b/libs/xmlrpc-c/src/method.h index 2ceca75..4b29dcd 100644 --- a/libs/xmlrpc-c/src/method.h +++ b/libs/xmlrpc-c/src/method.h @@ -65,6 +65,10 @@ typedef struct { /* 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 @@ -92,6 +96,7 @@ xmlrpc_methodCreate(xmlrpc_env * const envP, void * const userData, const char * const signatureString, const char * const helpText, + size_t const stackSize, xmlrpc_methodInfo ** const methodPP); void @@ -117,4 +122,4 @@ xmlrpc_methodListAdd(xmlrpc_env * const envP, -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/src/parse_value.c b/libs/xmlrpc-c/src/parse_value.c index a00b2a1..bcfa34c 100644 --- a/libs/xmlrpc-c/src/parse_value.c +++ b/libs/xmlrpc-c/src/parse_value.c @@ -188,7 +188,7 @@ parseMember(xmlrpc_env * const envP, " element has %u children. Only one and " "one make sense.", childCount); else { - xml_element * nameElemP = NULL; + xml_element * nameElemP; getNameChild(envP, memberP, &nameElemP); @@ -196,7 +196,7 @@ parseMember(xmlrpc_env * const envP, parseName(envP, nameElemP, keyPP); if (!envP->fault_occurred) { - xml_element * valueElemP = NULL; + xml_element * valueElemP; getValueChild(envP, memberP, &valueElemP); @@ -242,7 +242,7 @@ parseStruct(xmlrpc_env * const envP, setParseFault(envP, "<%s> element found where only " "makes sense", elemName); else { - xmlrpc_value * keyP = NULL; + xmlrpc_value * keyP; xmlrpc_value * valueP; parseMember(envP, members[i], maxRecursion, &keyP, &valueP); @@ -302,12 +302,12 @@ parseInt(xmlrpc_env * const envP, /* Look for out-of-range errors which didn't produce ERANGE. */ if (i < XMLRPC_INT32_MIN) setParseFault(envP, - " value %d is below the range allowed " + " 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 %d is above the range allowed " + " value %ld is above the range allowed " "by XML-RPC (maximum is %d)", i, XMLRPC_INT32_MAX); else { @@ -414,10 +414,10 @@ parseDoubleString(xmlrpc_env * const envP, Design note: in my experiments, using strtod() was 10 times slower than using this function. */ - const char * mantissa = NULL; - const char * mantissaEnd = NULL; - const char * fraction = NULL; - const char * fractionEnd = NULL; + const char * mantissa; + const char * mantissaEnd; + const char * fraction; + const char * fractionEnd; scanAndValidateDoubleString(envP, string, &mantissa, &mantissaEnd, &fraction, &fractionEnd); @@ -500,7 +500,7 @@ parseDouble(xmlrpc_env * const envP, 'str' is that content. -----------------------------------------------------------------------------*/ xmlrpc_env parseEnv; - double valueDouble = 0; + double valueDouble; XMLRPC_ASSERT_ENV_OK(envP); XMLRPC_ASSERT_PTR_OK(str); @@ -640,17 +640,23 @@ parseSimpleValueCdata(xmlrpc_env * const envP, 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. i1 and i2 are just - from my imagination. + 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")) + xmlrpc_streq(elementName, "ex:i1") || + xmlrpc_streq(elementName, "ex:i2")) parseInt(envP, cdata, valuePP); else if (xmlrpc_streq(elementName, "boolean")) parseBoolean(envP, cdata, valuePP); @@ -663,10 +669,10 @@ parseSimpleValueCdata(xmlrpc_env * const envP, else if (xmlrpc_streq(elementName, "base64")) parseBase64(envP, cdata, cdataLength, valuePP); else if (xmlrpc_streq(elementName, "nil") || - xmlrpc_streq(elementName, "ex.nil")) + xmlrpc_streq(elementName, "ex:nil")) *valuePP = xmlrpc_nil_new(envP); else if (xmlrpc_streq(elementName, "i8") || - xmlrpc_streq(elementName, "ex.i8")) + xmlrpc_streq(elementName, "ex:i8")) parseI8(envP, cdata, valuePP); else setParseFault(envP, "Unknown value type -- XML element is named " @@ -748,4 +754,4 @@ xmlrpc_parseValue(xmlrpc_env * const envP, } } } -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/registry.c b/libs/xmlrpc-c/src/registry.c index e7eddd3..5d0bf30 100644 --- a/libs/xmlrpc-c/src/registry.c +++ b/libs/xmlrpc-c/src/registry.c @@ -86,7 +86,8 @@ registryAddMethod(xmlrpc_env * const envP, xmlrpc_method2 method2, const char * const signatureString, const char * const help, - void * const userData) { + void * const userData, + size_t const stackSize) { const char * const helpString = help ? help : "No help is available for this method."; @@ -99,7 +100,7 @@ registryAddMethod(xmlrpc_env * const envP, XMLRPC_ASSERT(method1 != NULL || method2 != NULL); xmlrpc_methodCreate(envP, method1, method2, userData, - signatureString, helpString, &methodP); + signatureString, helpString, stackSize, &methodP); if (!envP->fault_occurred) { xmlrpc_methodListAdd(envP, registryP->methodListP, methodName, @@ -126,7 +127,7 @@ xmlrpc_registry_add_method_w_doc( XMLRPC_ASSERT(host == NULL); registryAddMethod(envP, registryP, methodName, method, NULL, - signatureString, help, serverInfo); + signatureString, help, serverInfo, 0); } @@ -156,7 +157,21 @@ xmlrpc_registry_add_method2(xmlrpc_env * const envP, void * const serverInfo) { registryAddMethod(envP, registryP, methodName, NULL, method, - signatureString, help, serverInfo); + 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); } @@ -182,6 +197,43 @@ xmlrpc_registry_set_default_method( +/* 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( @@ -431,4 +483,4 @@ xmlrpc_registry_process_call(xmlrpc_env * const envP, ** 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. */ +** SUCH DAMAGE. */ \ No newline at end of file diff --git a/libs/xmlrpc-c/src/system_method.c b/libs/xmlrpc-c/src/system_method.c index e1f77c0..b8e53a1 100644 --- a/libs/xmlrpc-c/src/system_method.c +++ b/libs/xmlrpc-c/src/system_method.c @@ -287,6 +287,64 @@ static struct systemMethodReg const methodListMethods = { /*========================================================================= + 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 =========================================================================*/ @@ -338,9 +396,9 @@ system_methodHelp(xmlrpc_env * const envP, "for security reasons"); else getHelpString(envP, methodName, registryP, &retvalP); - } - xmlrpc_strfree(methodName); + xmlrpc_strfree(methodName); + } return retvalP; } @@ -452,7 +510,7 @@ getSignatureList(xmlrpc_env * const envP, signatureP && !envP->fault_occurred; signatureP = signatureP->nextP) { - xmlrpc_value * signatureVP = NULL; + xmlrpc_value * signatureVP; buildSignatureValue(envP, signatureP, &signatureVP); @@ -525,7 +583,7 @@ system_methodSignature(xmlrpc_env * const envP, static struct systemMethodReg const methodMethodSignature = { "system.methodSignature", &system_methodSignature, - "s:s", + "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.", @@ -699,12 +757,15 @@ xmlrpc_installSystemMethods(xmlrpc_env * const envP, if (!envP->fault_occurred) registerSystemMethod(envP, registryP, methodListMethods); - if (!envP->fault_occurred) - registerSystemMethod(envP, registryP, methodMethodSignature); + 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); @@ -743,4 +804,3 @@ xmlrpc_installSystemMethods(xmlrpc_env * const envP, ** 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. */ - diff --git a/libs/xmlrpc-c/src/test/Makefile b/libs/xmlrpc-c/src/test/Makefile index 946a377..ff8c44a 100644 --- a/libs/xmlrpc-c/src/test/Makefile +++ b/libs/xmlrpc-c/src/test/Makefile @@ -37,6 +37,7 @@ TEST_OBJS = \ serialize_value.o \ server_abyss.o \ value.o \ + value_datetime.o \ xml_data.o \ ifeq ($(MUST_BUILD_CLIENT),yes) @@ -94,4 +95,4 @@ distclean: clean distclean-common .PHONY: dep dep: dep-common -include Makefile.depend +include depend.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/src/test/method_registry.c b/libs/xmlrpc-c/src/test/method_registry.c index da8d304..d27ca3a 100644 --- a/libs/xmlrpc-c/src/test/method_registry.c +++ b/libs/xmlrpc-c/src/test/method_registry.c @@ -310,7 +310,7 @@ test_signature(void) { xmlrpc_env env; xmlrpc_registry * registryP; - uint i; + unsigned int i; xmlrpc_env_init(&env); @@ -409,8 +409,9 @@ static const char * const expectedMethodName[] = { The list we expect back from system.listMethods. -----------------------------------------------------------------------------*/ "system.listMethods", - "system.methodSignature", + "system.methodExist", "system.methodHelp", + "system.methodSignature", "system.multicall", "system.shutdown", "system.capabilities", @@ -419,6 +420,7 @@ static const char * const expectedMethodName[] = { }; + static void test_system_listMethods(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- @@ -427,7 +429,7 @@ test_system_listMethods(xmlrpc_registry * const registryP) { xmlrpc_env env; xmlrpc_value * resultP; xmlrpc_value * argArrayP; - const char * methodName[8]; + const char * methodName[ARRAY_SIZE(expectedMethodName)]; unsigned int size; unsigned int i; @@ -449,13 +451,16 @@ test_system_listMethods(xmlrpc_registry * const registryP) { TEST(size == ARRAY_SIZE(expectedMethodName)); - xmlrpc_decompose_value(&env, resultP, "(ssssssss)", + xmlrpc_decompose_value(&env, resultP, "(sssssssss)", &methodName[0], &methodName[1], &methodName[2], &methodName[3], &methodName[4], &methodName[5], - &methodName[6], &methodName[7]); + &methodName[6], &methodName[7], + &methodName[8]); - for (i = 0; i < ARRAY_SIZE(methodName); ++i) { + TEST_NO_FAULT(&env); + + for (i = 0; i < ARRAY_SIZE(expectedMethodName); ++i) { TEST(streq(methodName[i], expectedMethodName[i])); strfree(methodName[i]); } @@ -472,6 +477,62 @@ test_system_listMethods(xmlrpc_registry * const registryP) { 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 test_system_methodHelp(xmlrpc_registry * const registryP) { /*---------------------------------------------------------------------------- Test system.methodHelp @@ -813,11 +874,11 @@ test_apache_dialect(void) { char const expectedResp[] = XML_PROLOGUE - "\r\n" + "\r\n" "\r\n" "\r\n" - "8\r\n" - "\r\n" + "8\r\n" + "\r\n" "\r\n" "\r\n" "\r\n"; @@ -932,6 +993,8 @@ test_method_registry(void) { test_system_listMethods(registryP); + test_system_methodExist(registryP); + test_system_methodHelp(registryP); test_system_capabilities(registryP); @@ -948,4 +1011,4 @@ test_method_registry(void) { printf("\n"); xmlrpc_env_clean(&env); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/test/parse_xml.c b/libs/xmlrpc-c/src/test/parse_xml.c index ff98ab2..27e4785 100644 --- a/libs/xmlrpc-c/src/test/parse_xml.c +++ b/libs/xmlrpc-c/src/test/parse_xml.c @@ -74,7 +74,7 @@ char const xmldata[] = "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" @@ -152,9 +152,12 @@ char const xmldata[] = "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" "\r\n"; @@ -164,7 +167,8 @@ char const xmldata[] = int arraySize; const char * str_hello; xmlrpc_bool b_false, b_true; - const char * datetime; + const char * datetime_sec; + const char * datetime_usec; unsigned char * b64_data; size_t b64_len; @@ -177,24 +181,27 @@ char const xmldata[] = arraySize = xmlrpc_array_size(&env, paramArrayP); TEST_NO_FAULT(&env); - TEST(arraySize == 7); + TEST(arraySize == 8); xmlrpc_decompose_value( - &env, paramArrayP, "(sbb86nn)", - &str_hello, &b_false, &b_true, &datetime, &b64_data, &b64_len); + &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, "19980717T14:08:55")); + 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); + strfree(datetime_sec); + strfree(datetime_usec); xmlrpc_DECREF(paramArrayP); strfree(methodName); @@ -560,4 +567,4 @@ test_parse_xml(void) { test_parse_xml_call(); printf("\n"); printf("XML parsing tests done.\n"); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/test/serialize.c b/libs/xmlrpc-c/src/test/serialize.c index 74fe86c..e706c9b 100644 --- a/libs/xmlrpc-c/src/test/serialize.c +++ b/libs/xmlrpc-c/src/test/serialize.c @@ -176,8 +176,8 @@ test_serialize_apache_value(void) { char const serializedData[] = "\r\n" "7\r\n" - "8\r\n" - "\r\n" + "8\r\n" + "\r\n" ""; xmlrpc_env env; @@ -214,7 +214,7 @@ test_serialize_apache_params(void) { char const serializedData[] = "\r\n" "7\r\n" - "8\r\n" + "8\r\n" "\r\n"; xmlrpc_env env; @@ -251,9 +251,9 @@ test_serialize_apache_response(void) { char const serializedData[] = XML_PROLOGUE - "\r\n" + "\r\n" "\r\n" - "8\r\n" + "8\r\n" "\r\n" "\r\n"; @@ -313,4 +313,4 @@ test_serialize(void) { printf("\n"); printf("Serialize tests done.\n"); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/test/value.c b/libs/xmlrpc-c/src/test/value.c index bda938c..d997157 100644 --- a/libs/xmlrpc-c/src/test/value.c +++ b/libs/xmlrpc-c/src/test/value.c @@ -14,6 +14,8 @@ #include "xmlrpc-c/string_int.h" #include "test.h" +#include "value_datetime.h" + #include "value.h" @@ -158,197 +160,6 @@ test_value_double(void) { -static void -test_value_datetime_varytime(const char * const datestring, - time_t const datetime) { - - xmlrpc_value * v; - xmlrpc_env env; - const char * ds; - time_t dt; - - xmlrpc_env_init(&env); - - 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, &dt); - TEST_NO_FAULT(&env); - TEST(dt == datetime); - - xmlrpc_DECREF(v); - - 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, &ds); - TEST_NO_FAULT(&env); - TEST(streq(ds, datestring)); - strfree(ds); - - xmlrpc_DECREF(v); - - xmlrpc_env_clean(&env); -} - - - -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_invalid(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_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(void) { - - const char * datestring = "19980717T14:08:55"; - time_t const datetime = 900684535; - - xmlrpc_env env; - - xmlrpc_env_init(&env); - - TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_DATETIME), "DATETIME")); - - /* Valid datetime, generated from XML-RPC string */ - - test_value_datetime_varytime(datestring, datetime); - - /* Leap years */ - test_value_datetime_varytime("20000229T23:59:59", 951868799); - test_value_datetime_varytime("20000301T00:00:00", 951868800); - test_value_datetime_varytime("20010228T23:59:59", 983404799); - test_value_datetime_varytime("20010301T00:00:00", 983404800); - test_value_datetime_varytime("20040229T23:59:59", 1078099199); - test_value_datetime_varytime("20040301T00:00:00", 1078099200); - - /* 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_invalid("19700101T25:00:00"); - test_value_datetime_invalid("19700101T10:61:01"); - test_value_datetime_invalid("19700101T10:59:61"); - test_value_datetime_invalid("19700001T10:00:00"); - test_value_datetime_invalid("19701301T10:00:00"); - test_value_datetime_invalid("19700132T10:00:00"); - - test_build_decomp_datetime(); - - xmlrpc_env_clean(&env); -} - - - static xmlrpc_value * test_string_new_va(xmlrpc_env * const envP, const char * const format, @@ -952,7 +763,7 @@ test_value_base64(void) { TEST_NO_FAULT(&env); TEST(len == sizeof(data2)); TEST(memeq(data, data1, sizeof(data2))); - strfree(data); + free((void *)data); xmlrpc_env_clean(&env); } @@ -1982,4 +1793,4 @@ test_value(void) { printf("\n"); printf("Value tests done.\n"); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/test/xml_data.h b/libs/xmlrpc-c/src/test/xml_data.h index 4b34238..e461c34 100644 --- a/libs/xmlrpc-c/src/test/xml_data.h +++ b/libs/xmlrpc-c/src/test/xml_data.h @@ -3,6 +3,9 @@ #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[]; @@ -22,4 +25,4 @@ extern const char *(bad_responses[]); extern const char *(bad_calls[]); -#endif +#endif \ No newline at end of file diff --git a/libs/xmlrpc-c/src/xmlrpc_datetime.c b/libs/xmlrpc-c/src/xmlrpc_datetime.c index 832f4fb..e372b95 100644 --- a/libs/xmlrpc-c/src/xmlrpc_datetime.c +++ b/libs/xmlrpc-c/src/xmlrpc_datetime.c @@ -5,12 +5,14 @@ #include #include #include +#include #if MSVCRT #include #endif #include "bool.h" +#include "xmlrpc-c/c_util.h" #include "xmlrpc-c/base.h" #include "xmlrpc-c/base_int.h" #include "xmlrpc-c/string_int.h" @@ -29,6 +31,9 @@ after 2038. We need to figure out something better. */ +#if HAVE_REGEX +#include "regex.h" +#endif #if MSVCRT @@ -96,6 +101,12 @@ UnixTimeFromSystemTime(xmlrpc_env * const envP, +static const char * const iso8601Regex = + "^([0-9]{4})([0-9]{2})([0-9]{2})T" + "([0-9]{2}):?([0-9]{2}):?([0-9]{2})\\.?([0-9]+)?$"; + + + static void validateDatetimeType(xmlrpc_env * const envP, const xmlrpc_value * const valueP) { @@ -143,14 +154,129 @@ xmlrpc_read_datetime_str_old(xmlrpc_env * const envP, +#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 -parseDateNumbers(const char * const t, - unsigned int * const YP, - unsigned int * const MP, - unsigned int * const DP, - unsigned int * const hP, - unsigned int * const mP, - unsigned int * const sP) { +parseDateNumbersRegex(xmlrpc_env * const envP, + const char * const datetimeString, + unsigned int * const YP, + unsigned int * const MP, + unsigned int * const DP, + unsigned int * const hP, + unsigned int * const mP, + unsigned int * const sP, + unsigned int * const uP) { + + + int status; + char errBuf[1024]; + regex_t re; + + status = regcomp(&re, iso8601Regex, REG_ICASE | REG_EXTENDED); + if (status == 0) { + regmatch_t matches[1024]; + int status; + + status = regexec(&re, datetimeString, ARRAY_SIZE(matches), matches, 0); + + if (status == 0) { + assert(matches[0].rm_so != -1); /* Match of whole regex */ + + *YP = digitStringValue(datetimeString, matches[1]); + *MP = digitStringValue(datetimeString, matches[2]); + *DP = digitStringValue(datetimeString, matches[3]); + *hP = digitStringValue(datetimeString, matches[4]); + *mP = digitStringValue(datetimeString, matches[5]); + *sP = digitStringValue(datetimeString, matches[6]); + + if (matches[7].rm_so == -1) + *uP = 0; + else + *uP = digitStringMillionths(datetimeString, matches[7]); + } else { + regerror(status, &re, errBuf, sizeof(errBuf)); + xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, errBuf); + } + + } else { + regerror(status, &re, errBuf, sizeof(errBuf)); + xmlrpc_faultf(envP, "internal regex error at %s:%d: '%s'", + __FILE__, __LINE__, errBuf); + } + regfree(&re); +} +#endif /* HAVE_REGEX */ + + + +static __inline__ void +parseDateNumbersNoRegex(xmlrpc_env * const envP, + const char * const datetimeString, + unsigned int * const YP, + unsigned int * const MP, + unsigned int * const DP, + unsigned int * const hP, + unsigned int * const mP, + unsigned int * const sP, + unsigned int * const uP) { + + unsigned int const dtStrlen = strlen(datetimeString); char year[4+1]; char month[2+1]; @@ -159,95 +285,196 @@ parseDateNumbers(const char * const t, char minute[2+1]; char second[2+1]; - assert(strlen(t) == 17); - - year[0] = t[ 0]; - year[1] = t[ 1]; - year[2] = t[ 2]; - year[3] = t[ 3]; - year[4] = '\0'; - - month[0] = t[ 4]; - month[1] = t[ 5]; - month[2] = '\0'; + 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; + + *uP = atoi(&datetimeString[18]); + for (i = 0; i < pad; ++i) + *uP *= 10; + } else + *uP = 0; + + *YP = atoi(year); + *MP = atoi(month); + *DP = atoi(day); + *hP = atoi(hour); + *mP = atoi(minute); + *sP = atoi(second); + } +} - day[0] = t[ 6]; - day[1] = t[ 7]; - day[2] = '\0'; - assert(t[ 8] == 'T'); - hour[0] = t[ 9]; - hour[1] = t[10]; - hour[2] = '\0'; +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; - assert(t[11] == ':'); + 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]); - minute[0] = t[12]; - minute[1] = t[13]; - minute[2] = '\0'; + 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]); +} - assert(t[14] == ':'); - second[0] = t[15]; - second[1] = t[16]; - second[2] = '\0'; - *YP = atoi(year); - *MP = atoi(month); - *DP = atoi(day); - *hP = atoi(hour); - *mP = atoi(minute); - *sP = atoi(second); +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 void +static __inline__ void validateFormat(xmlrpc_env * const envP, - const char * const t) { + const char * const dt) { - if (strlen(t) != 17) - xmlrpc_faultf(envP, "%u characters instead of 15.", strlen(t)); - else if (t[8] != 'T') - xmlrpc_faultf(envP, "9th character is '%c', not 'T'", t[8]); + 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", + strlen(dt)); else { - unsigned int i; - - for (i = 0; i < 8 && !envP->fault_occurred; ++i) - if (!isdigit(t[i])) - xmlrpc_faultf(envP, "Not a digit: '%c'", t[i]); - - if (!isdigit(t[9])) - xmlrpc_faultf(envP, "Not a digit: '%c'", t[9]); - if (!isdigit(t[10])) - xmlrpc_faultf(envP, "Not a digit: '%c'", t[10]); - if (t[11] != ':') - xmlrpc_faultf(envP, "Not a colon: '%c'", t[11]); - if (!isdigit(t[12])) - xmlrpc_faultf(envP, "Not a digit: '%c'", t[12]); - if (!isdigit(t[13])) - xmlrpc_faultf(envP, "Not a digit: '%c'", t[13]); - if (t[14] != ':') - xmlrpc_faultf(envP, "Not a colon: '%c'", t[14]); - if (!isdigit(t[15])) - xmlrpc_faultf(envP, "Not a digit: '%c'", t[15]); - if (!isdigit(t[16])) - xmlrpc_faultf(envP, "Not a digit: '%c'", t[16]); + validateFirst17(envP, dt); + + validateFractionalSeconds(envP, dt); } -} +} + + + +static void +parseDateNumbers(xmlrpc_env * const envP, + const char * const datetimeString, + unsigned int * const YP, + unsigned int * const MP, + unsigned int * const DP, + unsigned int * const hP, + unsigned int * const mP, + unsigned int * const sP, + unsigned int * const uP) { + +#if HAVE_REGEX + parseDateNumbersRegex(envP, datetimeString, YP, MP, DP, hP, mP, sP, uP); +#else + /* Note: validation is not as strong without regex */ + validateFormat(envP, datetimeString); + if (!envP->fault_occurred) + parseDateNumbersNoRegex(envP, datetimeString, + YP, MP, DP, hP, mP, sP, uP); +#endif +} static void -parseDatetime(xmlrpc_env * const envP, - const char * const t, - time_t * const timeValueP) { +parseDatetime(xmlrpc_env * const envP, + const char * const datetimeString, + time_t * const timeValueP, + unsigned int * const usecsP) { /*---------------------------------------------------------------------------- Parse a time in the format stored in an xmlrpc_value and return the time that it represents. - t[] is the input time string. We return the result as *timeValueP. + datetimeString[] is the input time string. We return the result as + *timeValueP. Example of the format we parse: "19980717T14:08:55" Note that this is not quite ISO 8601. It's a bizarre combination of @@ -260,33 +487,37 @@ parseDatetime(xmlrpc_env * const envP, And of course the input may not validly represent a datetime at all. In that case too, we fail with fault code XMLRPC_PARSE_ERROR. -----------------------------------------------------------------------------*/ - validateFormat(envP, t); + validateFormat(envP, datetimeString); if (!envP->fault_occurred) { - unsigned int Y, M, D, h, m, s; + unsigned int Y, M, D, h, m, s, u; - parseDateNumbers(t, &Y, &M, &D, &h, &m, &s); - - if (Y < 1970) - xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, - "Year is too early to represent as " - "a standard Unix time"); - else { - struct tm brokenTime; - const char * error; - - brokenTime.tm_sec = s; - brokenTime.tm_min = m; - brokenTime.tm_hour = h; - brokenTime.tm_mday = D; - brokenTime.tm_mon = M - 1; - brokenTime.tm_year = Y - 1900; - - xmlrpc_timegm(&brokenTime, timeValueP, &error); + parseDateNumbers(envP, datetimeString, &Y, &M, &D, &h, &m, &s, &u); - if (error) { - xmlrpc_env_set_fault(envP, XMLRPC_PARSE_ERROR, error); - xmlrpc_strfree(error); + if (!envP->fault_occurred) { + if (Y < 1970) + xmlrpc_env_set_fault_formatted(envP, XMLRPC_INTERNAL_ERROR, + "Year is too early to represent as " + "a standard Unix time"); + else { + struct tm brokenTime; + const char * error; + + brokenTime.tm_sec = s; + brokenTime.tm_min = m; + brokenTime.tm_hour = h; + brokenTime.tm_mday = D; + brokenTime.tm_mon = M - 1; + brokenTime.tm_year = Y - 1900; + + xmlrpc_timegm(&brokenTime, timeValueP, &error); + + if (error) { + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_PARSE_ERROR, error); + xmlrpc_strfree(error); + } else + *usecsP = u; } } } @@ -295,16 +526,69 @@ parseDatetime(xmlrpc_env * const envP, void -xmlrpc_read_datetime_sec(xmlrpc_env * const envP, - const xmlrpc_value * const valueP, - time_t * const timeValueP) { +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) parseDatetime(envP, XMLRPC_MEMBLOCK_CONTENTS(char, &valueP->_block), - timeValueP); + secsP, + usecsP); +} + + + +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 @@ -334,38 +618,82 @@ xmlrpc_datetime_new_str(xmlrpc_env * const envP, -xmlrpc_value * -xmlrpc_datetime_new_sec(xmlrpc_env * const envP, - time_t const value) { +xmlrpc_value* +xmlrpc_datetime_new_usec(xmlrpc_env * const envP, + time_t const secs, + unsigned int const usecs) { xmlrpc_value * valP; - + xmlrpc_createXmlrpcValue(envP, &valP); if (!envP->fault_occurred) { struct tm brokenTime; char timeString[64]; - - valP->_type = XMLRPC_TYPE_DATETIME; - xmlrpc_gmtime(value, &brokenTime); - + xmlrpc_gmtime(secs, &brokenTime); + /* Note that this format is NOT ISO 8601 -- it's a bizarre hybrid of two ISO 8601 formats. */ strftime(timeString, sizeof(timeString), "%Y%m%dT%H:%M:%S", &brokenTime); + + if (usecs != 0) { + char usecString[64]; + assert(usecs < 1000000); + snprintf(usecString, sizeof(usecString), ".%06u", usecs); + STRSCAT(timeString, usecString); + } + + valP->_type = XMLRPC_TYPE_DATETIME; XMLRPC_TYPED_MEM_BLOCK_INIT( char, envP, &valP->_block, strlen(timeString) + 1); + if (!envP->fault_occurred) { char * const contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &valP->_block); - + strcpy(contents, timeString); } - if (envP->fault_occurred) + if (envP->fault_occurred) { free(valP); + valP = NULL; + } } return valP; } + + + +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 \ No newline at end of file diff --git a/libs/xmlrpc-c/src/xmlrpc_libxml2.c b/libs/xmlrpc-c/src/xmlrpc_libxml2.c index 9cba719..10f4337 100644 --- a/libs/xmlrpc-c/src/xmlrpc_libxml2.c +++ b/libs/xmlrpc-c/src/xmlrpc_libxml2.c @@ -240,8 +240,10 @@ typedef struct { */ static void -start_element (void *user_data, const xmlChar *name, const xmlChar **attrs) -{ +start_element(void * const user_data, + const xmlChar * const name, + const xmlChar ** const attrs ATTR_UNUSED) { + parse_context *context; xml_element *elem, *new_current; @@ -281,9 +283,12 @@ start_element (void *user_data, const xmlChar *name, const xmlChar **attrs) } } + + static void -end_element (void *user_data, const xmlChar *name) -{ +end_element(void * const user_data, + const xmlChar * const name ATTR_UNUSED) { + parse_context *context; XMLRPC_ASSERT(user_data != NULL && name != NULL); @@ -424,4 +429,4 @@ xml_parse(xmlrpc_env * const envP, if (context.root) xml_element_free(context.root); } -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/xmlrpc_serialize.c b/libs/xmlrpc-c/src/xmlrpc_serialize.c index 3ca64dd..cd3df76 100644 --- a/libs/xmlrpc-c/src/xmlrpc_serialize.c +++ b/libs/xmlrpc-c/src/xmlrpc_serialize.c @@ -26,8 +26,9 @@ #include "double.h" #define CRLF "\015\012" -#define SMALL_BUFFER_SZ (128) #define XML_PROLOGUE ""CRLF +#define APACHE_URL "http://ws.apache.org/xmlrpc/namespaces/extensions" +#define XMLNS_APACHE "xmlns:ex=\"" APACHE_URL "\"" static void @@ -54,26 +55,31 @@ formatOut(xmlrpc_env * const envP, particular, do NOT use this routine to print XML-RPC string values! -----------------------------------------------------------------------------*/ va_list args; - char buffer[SMALL_BUFFER_SZ]; - int count; + char buffer[128]; + int rc; XMLRPC_ASSERT_ENV_OK(envP); va_start(args, formatString); - count = XMLRPC_VSNPRINTF(buffer, SMALL_BUFFER_SZ, formatString, args); + rc = XMLRPC_VSNPRINTF(buffer, sizeof(buffer), formatString, args); - /* Old C libraries return -1 if vsnprintf overflows its buffer. - ** New C libraries return the number of characters which *would* have - ** been printed if the error did not occur. This is impressively vile. - ** Thank the C99 committee for this bright idea. But wait! We also - ** need to keep track of the trailing NUL. */ + /* 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 (count < 0 || count >= (SMALL_BUFFER_SZ - 1)) + if (rc < 0) xmlrpc_faultf(envP, "formatOut() overflowed internal buffer"); - else - XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, buffer, count); + 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); } @@ -366,7 +372,7 @@ formatValueContent(xmlrpc_env * const envP, case XMLRPC_TYPE_I8: { const char * const elemName = - dialect == xmlrpc_dialect_apache ? "ex.i8" : "i8"; + dialect == xmlrpc_dialect_apache ? "ex:i8" : "i8"; formatOut(envP, outputP, "<%s>%" PRId64 "", elemName, valueP->_value.i8, elemName); } break; @@ -436,7 +442,7 @@ formatValueContent(xmlrpc_env * const envP, case XMLRPC_TYPE_NIL: { const char * const elemName = - dialect == xmlrpc_dialect_apache ? "ex.nil" : "nil"; + dialect == xmlrpc_dialect_apache ? "ex:nil" : "nil"; formatOut(envP, outputP, "<%s/>", elemName); } break; @@ -567,7 +573,9 @@ xmlrpc_serialize_call2(xmlrpc_env * const envP, addString(envP, outputP, XML_PROLOGUE); if (!envP->fault_occurred) { - addString(envP, outputP, ""CRLF""); + 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); @@ -623,8 +631,10 @@ xmlrpc_serialize_response2(xmlrpc_env * const envP, addString(envP, outputP, XML_PROLOGUE); if (!envP->fault_occurred) { - addString(envP, outputP, - ""CRLF""CRLF""); + 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) { @@ -711,4 +721,4 @@ xmlrpc_serialize_fault(xmlrpc_env * const envP, ** 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. */ +** SUCH DAMAGE. */ \ No newline at end of file diff --git a/libs/xmlrpc-c/src/xmlrpc_server_abyss.c b/libs/xmlrpc-c/src/xmlrpc_server_abyss.c index 7cb1ae1..920bab1 100644 --- a/libs/xmlrpc-c/src/xmlrpc_server_abyss.c +++ b/libs/xmlrpc-c/src/xmlrpc_server_abyss.c @@ -39,17 +39,12 @@ struct xmlrpc_server_abyss { -/*========================================================================= -** die_if_fault_occurred -**========================================================================= -** If certain kinds of out-of-memory errors occur during server setup, -** we want to quit and print an error. -*/ +static void +dieIfFaultOccurred(xmlrpc_env * const envP) { -static void die_if_fault_occurred(xmlrpc_env *env) { - if (env->fault_occurred) { + if (envP->fault_occurred) { fprintf(stderr, "Unexpected XML-RPC fault: %s (%d)\n", - env->fault_string, env->fault_code); + envP->fault_string, envP->fault_code); exit(1); } } @@ -471,7 +466,7 @@ processCall(TSession * const abyssSessionP, &env, XMLRPC_LIMIT_EXCEEDED_ERROR, "XML-RPC request too large (%d bytes)", contentSize); else { - xmlrpc_mem_block * body = NULL; + xmlrpc_mem_block * body; /* Read XML data off the wire. */ getBody(&env, abyssSessionP, contentSize, trace, &body); if (!env.fault_occurred) { @@ -543,7 +538,7 @@ termUriHandler(void * const arg) { static void -handleXmlrpcReq(URIHandler2 * const this, +handleXmlrpcReq(void * const handlerArg, TSession * const abyssSessionP, abyss_bool * const handledP) { /*---------------------------------------------------------------------------- @@ -557,9 +552,9 @@ handleXmlrpcReq(URIHandler2 * const this, 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 URIHandler2. + This is an Abyss HTTP Request handler -- type handleReqFn3. -----------------------------------------------------------------------------*/ - struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = this->userdata; + struct uriHandlerXmlrpc * const uriHandlerXmlrpcP = handlerArg; const TRequestInfo * requestInfoP; @@ -626,6 +621,10 @@ handleXmlrpcReq(URIHandler2 * const this, } +/* This doesn't include what the user's method function requires */ +#define HANDLE_XMLRPC_REQ_STACK 1024 + + /*========================================================================= ** xmlrpc_server_abyss_default_handler @@ -671,7 +670,6 @@ setHandler(xmlrpc_env * const envP, bool const chunkResponse) { struct uriHandlerXmlrpc * uriHandlerXmlrpcP; - URIHandler2 uriHandler; abyss_bool success; trace_abyss = getenv("XMLRPC_TRACE_ABYSS"); @@ -681,15 +679,18 @@ setHandler(xmlrpc_env * const envP, uriHandlerXmlrpcP->registryP = registryP; uriHandlerXmlrpcP->uriPath = strdup(uriPath); uriHandlerXmlrpcP->chunkResponse = chunkResponse; - - uriHandler.handleReq2 = handleXmlrpcReq; - uriHandler.handleReq1 = NULL; - uriHandler.userdata = uriHandlerXmlrpcP; - uriHandler.init = NULL; - uriHandler.term = &termUriHandler; - - ServerAddHandler2(srvP, &uriHandler, &success); - + + { + size_t const stackSize = + HANDLE_XMLRPC_REQ_STACK + xmlrpc_registry_max_stackSize(registryP); + struct ServerReqHandler3 const handlerDesc = { + /* .term = */ &termUriHandler, + /* .handleReq = */ &handleXmlrpcReq, + /* .userdata = */ uriHandlerXmlrpcP, + /* .handleReqStackSize = */ stackSize + }; + ServerAddHandler3(srvP, &handlerDesc, &success); + } if (!success) xmlrpc_faultf(envP, "Abyss failed to register the Xmlrpc-c request " "handler. ServerAddHandler2() failed."); @@ -890,8 +891,8 @@ createServerBare(xmlrpc_env * const envP, to use. -----------------------------------------------------------------------------*/ bool socketBound; - unsigned int portNumber = 0; - TOsSocket socketFd = 0; + unsigned int portNumber; + TOsSocket socketFd; const char * logFileName; extractServerCreateParms(envP, parmsP, parmSize, @@ -903,8 +904,13 @@ createServerBare(xmlrpc_env * const envP, createServerBoundSocket(envP, socketFd, logFileName, serverP, chanSwitchPP); else { - ServerCreate(serverP, "XmlRpcServer", portNumber, DEFAULT_DOCS, - logFileName); + abyss_bool success; + + success = ServerCreate(serverP, "XmlRpcServer", portNumber, + DEFAULT_DOCS, logFileName); + + if (!success) + xmlrpc_faultf(envP, "Failed to create an Abyss server object"); *chanSwitchPP = NULL; } @@ -1030,9 +1036,9 @@ xmlrpc_server_abyss_create(xmlrpc_env * const envP, 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 >= %lu " + "That would mean the parameter size would be >= %u " "but you specified a size of %u", - XMLRPC_APSIZE(registryP), parmSize); + (unsigned)XMLRPC_APSIZE(registryP), parmSize); else { MALLOCVAR(serverP); @@ -1270,7 +1276,7 @@ runServerDaemon(TServer * const serverP, static void -oldHighLevelAbyssRun(xmlrpc_env * const envP ATTR_UNUSED, +oldHighLevelAbyssRun(xmlrpc_env * const envP, const xmlrpc_server_abyss_parms * const parmsP, unsigned int const parmSize) { /*---------------------------------------------------------------------------- @@ -1285,31 +1291,37 @@ oldHighLevelAbyssRun(xmlrpc_env * const envP ATTR_UNUSED, flexible API. -----------------------------------------------------------------------------*/ TServer server; - runfirstFn runfirst; - void * runfirstArg; - - ServerCreate(&server, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); + abyss_bool success; + + success = ServerCreate(&server, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); - assert(parmSize >= XMLRPC_APSIZE(config_file_name)); + 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); + ConfReadServerFile(parmsP->config_file_name, &server); - assert(parmSize >= XMLRPC_APSIZE(registryP)); + assert(parmSize >= XMLRPC_APSIZE(registryP)); - setHandlers(&server, "/RPC2", parmsP->registryP, false); + setHandlers(&server, "/RPC2", parmsP->registryP, false); - ServerInit(&server); + ServerInit(&server); - if (parmSize >= XMLRPC_APSIZE(runfirst_arg)) { - runfirst = parmsP->runfirst; - runfirstArg = parmsP->runfirst_arg; - } else { - runfirst = NULL; - runfirstArg = NULL; - } - runServerDaemon(&server, runfirst, runfirstArg); + if (parmSize >= XMLRPC_APSIZE(runfirst_arg)) { + runfirst = parmsP->runfirst; + runfirstArg = parmsP->runfirst_arg; + } else { + runfirst = NULL; + runfirstArg = NULL; + } + runServerDaemon(&server, runfirst, runfirstArg); - ServerFree(&server); + ServerFree(&server); + } } @@ -1363,9 +1375,9 @@ xmlrpc_server_abyss(xmlrpc_env * const envP, 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 >= %lu " + "That would mean the parameter size would be >= %u " "but you specified a size of %u", - XMLRPC_APSIZE(registryP), parmSize); + (unsigned)XMLRPC_APSIZE(registryP), parmSize); else { if (parmsP->config_file_name) oldHighLevelAbyssRun(envP, parmsP, parmSize); @@ -1416,7 +1428,7 @@ xmlrpc_server_abyss_init_registry(void) { xmlrpc_env_init(&env); builtin_registryP = xmlrpc_registry_new(&env); - die_if_fault_occurred(&env); + dieIfFaultOccurred(&env); xmlrpc_env_clean(&env); setHandlers(&globalSrv, "/RPC2", builtin_registryP, false); @@ -1446,7 +1458,7 @@ xmlrpc_server_abyss_add_method(char * const method_name, xmlrpc_env_init(&env); xmlrpc_registry_add_method(&env, builtin_registryP, NULL, method_name, method, user_data); - die_if_fault_occurred(&env); + dieIfFaultOccurred(&env); xmlrpc_env_clean(&env); } @@ -1464,7 +1476,7 @@ xmlrpc_server_abyss_add_method_w_doc(char * const method_name, xmlrpc_registry_add_method_w_doc( &env, builtin_registryP, NULL, method_name, method, user_data, signature, help); - die_if_fault_occurred(&env); + dieIfFaultOccurred(&env); xmlrpc_env_clean(&env); } @@ -1474,16 +1486,23 @@ void xmlrpc_server_abyss_init(int const flags ATTR_UNUSED, const char * const config_file) { - ServerCreate(&globalSrv, "XmlRpcServer", 8080, DEFAULT_DOCS, NULL); - - ConfReadServerFile(config_file, &globalSrv); + abyss_bool success; - xmlrpc_server_abyss_init_registry(); - /* Installs /RPC2 handler and default handler that use the - built-in registry. - */ + success = ServerCreate(&globalSrv, "XmlRpcServer", 8080, + DEFAULT_DOCS, NULL); - ServerInit(&globalSrv); + 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); + } } @@ -1532,4 +1551,4 @@ xmlrpc_server_abyss_run(void) { ** ** There is more copyright information in the bottom half of this file. ** Please see it for more details. -*/ +*/ \ No newline at end of file diff --git a/libs/xmlrpc-c/src/xmlrpc_server_cgi.c b/libs/xmlrpc-c/src/xmlrpc_server_cgi.c index 2f6fe73..99efb94 100644 --- a/libs/xmlrpc-c/src/xmlrpc_server_cgi.c +++ b/libs/xmlrpc-c/src/xmlrpc_server_cgi.c @@ -206,9 +206,15 @@ xmlrpc_server_cgi_process_call(xmlrpc_registry * const registryP) { code = 405; message = "Method Not Allowed"; XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, "Expected HTTP method POST"); } - if (!type || 0 != strcmp(type, "text/xml")) { + if (!type || 0 != strncmp(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, "Expected text/xml content"); + XMLRPC_FAIL(&env, XMLRPC_INTERNAL_ERROR, err); + free(err); } if (!length_str) { code = 411; message = "Length Required"; @@ -320,4 +326,4 @@ void xmlrpc_cgi_process_call(void) { xmlrpc_server_cgi_process_call(globalRegistryP); -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/xmlrpc_server_info.c b/libs/xmlrpc-c/src/xmlrpc_server_info.c index 5cf44c3..6bcb84e 100644 --- a/libs/xmlrpc-c/src/xmlrpc_server_info.c +++ b/libs/xmlrpc-c/src/xmlrpc_server_info.c @@ -229,6 +229,9 @@ xmlrpc_server_info_set_user(xmlrpc_env * const envP, } XMLRPC_MEMBLOCK_FREE(char, userNamePw64); } + if (serverInfoP->userNamePw) + xmlrpc_strfree(serverInfoP->userNamePw); + serverInfoP->userNamePw = userNamePw; } @@ -340,4 +343,4 @@ xmlrpc_server_info_disallow_auth_ntlm( xmlrpc_server_info * const sP) { sP->allowedAuth.ntlm = true; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/src/xmlrpc_server_w32httpsys.c b/libs/xmlrpc-c/src/xmlrpc_server_w32httpsys.c index cf0dad8..701712c 100644 --- a/libs/xmlrpc-c/src/xmlrpc_server_w32httpsys.c +++ b/libs/xmlrpc-c/src/xmlrpc_server_w32httpsys.c @@ -665,7 +665,8 @@ SendHttpResponse( ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/html"); - StringCchPrintfA(szServerHeader,20, "xmlrpc-c %s",XMLRPC_C_VERSION); + StringCchPrintfA(szServerHeader, sizeof(szServerHeader), "Xmlrpc-c/%s", + XMLRPC_C_VERSION); ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader); if(pEntityString) @@ -724,7 +725,8 @@ SendHttpResponseAuthRequired( ADD_KNOWN_HEADER(response, HttpHeaderWwwAuthenticate, "Basic realm=\"xmlrpc\""); - StringCchPrintfA(szServerHeader,20, "xmlrpc-c %s",XMLRPC_C_VERSION); + 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 @@ -878,8 +880,8 @@ processRPCCall( ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/xml"); - StringCchPrintfA(szServerHeader,20, - "xmlrpc-c %s",XMLRPC_C_VERSION); + StringCchPrintfA(szServerHeader, sizeof(szServerHeader), + "Xmlrpc-c/%s", XMLRPC_C_VERSION); ADD_KNOWN_HEADER(response, HttpHeaderServer, szServerHeader); @@ -998,4 +1000,3 @@ Done: ** 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. */ - diff --git a/libs/xmlrpc-c/tools/Makefile b/libs/xmlrpc-c/tools/Makefile index 621dbf9..808732c 100644 --- a/libs/xmlrpc-c/tools/Makefile +++ b/libs/xmlrpc-c/tools/Makefile @@ -7,7 +7,7 @@ SUBDIR := tools include $(BLDDIR)/config.mk -SUBDIRS = binmode-rpc-kit turbocharger +SUBDIRS = lib binmode-rpc-kit turbocharger ifeq ($(MUST_BUILD_CLIENT),yes) SUBDIRS += xmlrpc xmlrpc_transport @@ -33,4 +33,4 @@ check: dep: $(SUBDIRS:%=%/dep) -include $(SRCDIR)/common.mk +include $(SRCDIR)/common.mk \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/common.mk b/libs/xmlrpc-c/tools/common.mk index fe71e97..032ad91 100644 --- a/libs/xmlrpc-c/tools/common.mk +++ b/libs/xmlrpc-c/tools/common.mk @@ -29,7 +29,7 @@ CLIENTPP_LDLIBS += -lxmlrpc_client++ -lxmlrpc_packetsocket -lxmlrpc++ include $(SRCDIR)/common.mk ifneq ($(OMIT_LIB_RULE),Y) -srcdir/tools/lib/dumpvalue.o: FORCE +blddir/tools/lib/dumpvalue.o: FORCE $(MAKE) -C $(dir $@) -f $(SRCDIR)/tools/lib/Makefile $(notdir $@) endif @@ -40,4 +40,4 @@ install: install-common check: .PHONY: FORCE -FORCE: +FORCE: \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/lib/Makefile b/libs/xmlrpc-c/tools/lib/Makefile index 5b04eed..da7b6be 100644 --- a/libs/xmlrpc-c/tools/lib/Makefile +++ b/libs/xmlrpc-c/tools/lib/Makefile @@ -34,9 +34,9 @@ all: $(LIBOBJS) # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. -$(SRCDIR)/tool/common.mk: srcdir blddir +$(SRCDIR)/tools/common.mk: srcdir blddir -include Makefile.depend +include depend.mk .PHONY: dep dep: dep-common @@ -45,4 +45,4 @@ dep: dep-common clean: clean-common .PHONY: distclean -distclean: clean distclean-common +distclean: clean distclean-common \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/lib/dumpvalue.c b/libs/xmlrpc-c/tools/lib/dumpvalue.c index ebcc000..79c7a37 100644 --- a/libs/xmlrpc-c/tools/lib/dumpvalue.c +++ b/libs/xmlrpc-c/tools/lib/dumpvalue.c @@ -5,7 +5,7 @@ used for debugging purposes in other places. */ -//#define _GNU_SOURCE +#define _GNU_SOURCE #include #include @@ -297,12 +297,12 @@ dumpStructMember(const char * const prefix, const char * prefix2; const char * blankPrefix; - casprintf(&prefix2, "%s Key: ", prefix); + casprintf(&blankPrefix, "%*s", blankCount, ""); + + casprintf(&prefix2, "%s Key: ", blankPrefix); dumpValue(prefix2, keyP); strfree(prefix2); - casprintf(&blankPrefix, "%*s", blankCount, ""); - casprintf(&prefix2, "%s Value: ", blankPrefix); dumpValue(prefix2, valueP); strfree(prefix2); @@ -472,4 +472,4 @@ dumpValue(const char * const prefix, default: dumpUnknown(prefix, valueP); } -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/xml-rpc-api2cpp/Makefile b/libs/xmlrpc-c/tools/xml-rpc-api2cpp/Makefile index dbe374f..be19c7a 100644 --- a/libs/xmlrpc-c/tools/xml-rpc-api2cpp/Makefile +++ b/libs/xmlrpc-c/tools/xml-rpc-api2cpp/Makefile @@ -51,9 +51,9 @@ xml-rpc-api2cpp: \ # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. -$(SRCDIR)/common.mk: srcdir blddir +$(SRCDIR)/tools/common.mk: srcdir blddir -include Makefile.depend +include depend.mk .PHONY: clean clean: clean-common @@ -63,4 +63,4 @@ clean: clean-common distclean: clean distclean-common .PHONY: dep -dep: dep-common +dep: dep-common \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/xmlrpc/Makefile b/libs/xmlrpc-c/tools/xmlrpc/Makefile index c1f3b34..d643fc3 100644 --- a/libs/xmlrpc-c/tools/xmlrpc/Makefile +++ b/libs/xmlrpc-c/tools/xmlrpc/Makefile @@ -36,7 +36,7 @@ UTIL_OBJS = \ UTILS = $(UTIL_OBJS:%=$(UTIL_DIR)/%) -DUMPVALUE = srcdir/tools/lib/dumpvalue.o +DUMPVALUE = blddir/tools/lib/dumpvalue.o # Can we just use $(LIBS) in the link? @@ -55,7 +55,7 @@ xmlrpc: $(XMLRPC_OBJS) $(LIBS) $(UTILS) $(SRCDIR)/tools/common.mk: srcdir blddir -include Makefile.depend +include depend.mk .PHONY: dep dep: dep-common @@ -65,4 +65,4 @@ clean: clean-common rm -f xmlrpc .PHONY: distclean -distclean: clean distclean-common +distclean: clean distclean-common \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/xmlrpc/xmlrpc.c b/libs/xmlrpc-c/tools/xmlrpc/xmlrpc.c index c768b7b..34f74bb 100644 --- a/libs/xmlrpc-c/tools/xmlrpc/xmlrpc.c +++ b/libs/xmlrpc-c/tools/xmlrpc/xmlrpc.c @@ -35,7 +35,7 @@ */ -//#define _GNU_SOURCE +#define _GNU_SOURCE #include #include @@ -602,4 +602,4 @@ main(int const argc, xmlrpc_env_clean(&env); return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/xmlrpc_cpp_proxy/Makefile b/libs/xmlrpc-c/tools/xmlrpc_cpp_proxy/Makefile index d6f50a6..58fc1d5 100644 --- a/libs/xmlrpc-c/tools/xmlrpc_cpp_proxy/Makefile +++ b/libs/xmlrpc-c/tools/xmlrpc_cpp_proxy/Makefile @@ -50,7 +50,7 @@ xmlrpc_cpp_proxy: $(OBJECTS) $(LIBS) $(SRCDIR)/tools/common.mk: srcdir blddir -include Makefile.depend +include depend.mk .PHONY: clean clean: clean-common @@ -60,4 +60,4 @@ clean: clean-common distclean: clean distclean-common .PHONY: dep -dep: dep-common +dep: dep-common \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/xmlrpc_pstream/Makefile b/libs/xmlrpc-c/tools/xmlrpc_pstream/Makefile index 2fb24fb..9139098 100644 --- a/libs/xmlrpc-c/tools/xmlrpc_pstream/Makefile +++ b/libs/xmlrpc-c/tools/xmlrpc_pstream/Makefile @@ -31,7 +31,7 @@ all: xmlrpc_pstream OBJECTS = \ xmlrpc_pstream.o \ - $(TOOLSDIR)/lib/dumpvalue.o \ + blddir/lib/dumpvalue.o \ LIBS = \ $(LIBXMLRPC_CLIENTPP) \ @@ -62,9 +62,9 @@ xmlrpc_pstream: $(OBJECTS) $(LIBS) $(UTILS) # This common.mk dependency makes sure the symlinks get built before # this make file is used for anything. -$(SRCDIR)/common.mk: srcdir blddir +$(SRCDIR)/tools/common.mk: srcdir blddir -include Makefile.depend +include depend.mk .PHONY: clean clean: clean-common @@ -74,4 +74,4 @@ clean: clean-common distclean: clean distclean-common .PHONY: dep -dep: dep-common +dep: dep-common \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/xmlrpc_pstream/xmlrpc_pstream.cpp b/libs/xmlrpc-c/tools/xmlrpc_pstream/xmlrpc_pstream.cpp index 399e1b3..13d7f9c 100644 --- a/libs/xmlrpc-c/tools/xmlrpc_pstream/xmlrpc_pstream.cpp +++ b/libs/xmlrpc-c/tools/xmlrpc_pstream/xmlrpc_pstream.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -500,4 +501,4 @@ main(int const argc, abort(); } return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/xmlrpc_transport/Makefile b/libs/xmlrpc-c/tools/xmlrpc_transport/Makefile index 9941eb1..da6bfbe 100644 --- a/libs/xmlrpc-c/tools/xmlrpc_transport/Makefile +++ b/libs/xmlrpc-c/tools/xmlrpc_transport/Makefile @@ -55,7 +55,7 @@ xmlrpc_transport:%:%.o $(LIBS) $(UTILS) $(SRCDIR)/tools/common.mk: srcdir blddir -include Makefile.depend +include depend.mk .PHONY: dep dep: dep-common @@ -65,4 +65,4 @@ clean: clean-common rm -f xmlrpc_transport config.h .PHONY: distclean -distclean: clean distclean-common +distclean: clean distclean-common \ No newline at end of file diff --git a/libs/xmlrpc-c/tools/xmlrpc_transport/xmlrpc_transport.c b/libs/xmlrpc-c/tools/xmlrpc_transport/xmlrpc_transport.c index 0fe671d..fabb449 100644 --- a/libs/xmlrpc-c/tools/xmlrpc_transport/xmlrpc_transport.c +++ b/libs/xmlrpc-c/tools/xmlrpc_transport/xmlrpc_transport.c @@ -2,7 +2,7 @@ an XML-RPC call. */ -//#define _GNU_SOURCE +#define _GNU_SOURCE #include #include @@ -286,4 +286,4 @@ main(int const argc, xmlrpc_env_clean(&env); return 0; -} +} \ No newline at end of file diff --git a/libs/xmlrpc-c/unix-common.make b/libs/xmlrpc-c/unix-common.make index b684c70..79fe8d9 100644 --- a/libs/xmlrpc-c/unix-common.make +++ b/libs/xmlrpc-c/unix-common.make @@ -51,7 +51,7 @@ # is libfoo.so.1 . SONAME = $(@:%.$(MIN)=%) -SHLIB_CMD = $(CCLD) $(LDFLAGS_SHLIB) -o $@ $^ $(LADD) +SHLIB_CMD = $(CCLD) $(LADD) $(LDFLAGS_SHLIB) -o $@ $^ SHLIB_LE_TARGETS = $(call shliblefn, $(SHARED_LIBS_TO_BUILD)) @@ -76,4 +76,4 @@ $(SHLIB_INSTALL_TARGETS):%/install:%.$(SHLIB_SUFFIX).$(MAJ).$(MIN) $(LN_S) $< $(<:%.$(MIN)=%) cd $(DESTDIR)$(LIBINST_DIR); \ rm -f $(<:%.$(MAJ).$(MIN)=%); \ - $(LN_S) $(<:%.$(MIN)=%) $(<:%.$(MAJ).$(MIN)=%) + $(LN_S) $(<:%.$(MIN)=%) $(<:%.$(MAJ).$(MIN)=%) \ No newline at end of file diff --git a/libs/xmlrpc-c/xmlrpc-c-config.main b/libs/xmlrpc-c/xmlrpc-c-config.main index 6fec342..f97bf01 100644 --- a/libs/xmlrpc-c/xmlrpc-c-config.main +++ b/libs/xmlrpc-c/xmlrpc-c-config.main @@ -70,14 +70,22 @@ while test $# -gt 0; do ;; c++2) needCpp=yes - the_libs="-lxmlrpc++ $the_libs" + the_libs="-l$LIBXMLRPCPP_NAME $the_libs" ;; server-util) the_libs="-lxmlrpc_server $the_libs" + if test "${needCpp}" = "yes"; then + the_libs="-lxmlrpc_server++ $the_libs" + fi ;; cgi-server) the_libs="-lxmlrpc_server $the_libs" - the_libs="-lxmlrpc_server_cgi $the_libs" + if test "${needCpp}" = "yes"; then + the_libs="-lxmlrpc_server_cgi++ $the_libs" + the_libs="-lxmlrpc_server++ $the_libs" + else + the_libs="-lxmlrpc_server_cgi $the_libs" + fi ;; abyss-server) if test "${ENABLE_ABYSS_THREADS}" = "yes"; then @@ -180,4 +188,4 @@ while test $# -gt 0; do shift done -exit 0 +exit 0 \ No newline at end of file diff --git a/libs/xmlrpc-c/xmlrpc-c-config.test.main b/libs/xmlrpc-c/xmlrpc-c-config.test.main index da9bf15..f39290c 100644 --- a/libs/xmlrpc-c/xmlrpc-c-config.test.main +++ b/libs/xmlrpc-c/xmlrpc-c-config.test.main @@ -52,14 +52,22 @@ while test $# -gt 0; do ;; c++2) needCpp=yes - the_libs="${BLDDIR}/src/cpp/libxmlrpc++.a $the_libs" + the_libs="${BLDDIR}/src/cpp/lib$LIBXMLRPCPP_NAME.a $the_libs" ;; server-util) the_libs="${BLDDIR}/src/libxmlrpc_server.a $the_libs" + if test "${needCpp}" = "yes"; then + the_libs="${BLDDIR}/src/cpp/libxmlrpc_server++.a $the_libs" + fi ;; cgi-server) the_libs="${BLDDIR}/src/libxmlrpc_server.a $the_libs" - the_libs="${BLDDIR}/src/libxmlrpc_server_cgi.a $the_libs" + if test "${needCpp}" = "yes"; then + the_libs="${BLDDIR}/src/cpp/libxmlrpc_server_cgi++.a $the_libs" + the_libs="${BLDDIR}/src/cpp/libxmlrpc_server++.a $the_libs" + else + the_libs="${BLDDIR}/src/libxmlrpc_server_cgi.a $the_libs" + fi ;; abyss-server) if test "${ENABLE_ABYSS_THREADS}" = "yes"; then @@ -141,4 +149,4 @@ while test $# -gt 0; do shift done -exit 0 +exit 0 \ No newline at end of file diff --git a/libs/xmlrpc-c/xmlrpc_amconfig.h.in b/libs/xmlrpc-c/xmlrpc_amconfig.h.in index cd289f2..415cd09 100644 --- a/libs/xmlrpc-c/xmlrpc_amconfig.h.in +++ b/libs/xmlrpc-c/xmlrpc_amconfig.h.in @@ -22,13 +22,10 @@ #undef HAVE_STRCASECMP #undef HAVE_STRICMP #undef HAVE__STRICMP -#undef HAVE_WCHAR_H -#undef HAVE_SYS_FILIO_H -#undef HAVE_SYS_IOCTL_H /* Define if you have the socket library (-lsocket). */ #undef HAVE_LIBSOCKET /* Name of package */ -#undef PACKAGE +#undef PACKAGE \ No newline at end of file diff --git a/libs/xmlrpc-c/xmlrpc_config.h.in b/libs/xmlrpc-c/xmlrpc_config.h.in index 46e69ae..02c2fbe 100644 --- a/libs/xmlrpc-c/xmlrpc_config.h.in +++ b/libs/xmlrpc-c/xmlrpc_config.h.in @@ -65,15 +65,10 @@ #ifndef HAVE__STRICMP #define HAVE__STRICMP 0 #endif -#ifndef HAVE_WCHAR_H -#define HAVE_WCHAR_H 0 -#endif -#ifndef HAVE_SYS_FILIO_H -#define HAVE_SYS_FILIO_H 0 -#endif -#ifndef HAVE_SYS_IOCTL_H -#define HAVE_SYS_IOCTL_H 0 -#endif + +#define HAVE_WCHAR_H @HAVE_WCHAR_H_DEFINE@ +#define HAVE_SYS_FILIO_H @HAVE_SYS_FILIO_H_DEFINE@ +#define HAVE_SYS_IOCTL_H @HAVE_SYS_IOCTL_H_DEFINE@ #define VA_LIST_IS_ARRAY @VA_LIST_IS_ARRAY_DEFINE@ @@ -128,12 +123,21 @@ #define HAVE_TIMESPEC 1 #endif +/* 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 defined(_MSC_VER) /* Starting with MSVC 8, the runtime library defines various POSIX functions such as strdup() whose names violate the ISO C standard (the standard @@ -152,4 +156,4 @@ #pragma warning(disable:4996) #endif -#endif +#endif \ No newline at end of file diff --git a/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c b/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c index 468190d..60b0062 100644 --- a/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c +++ b/src/mod/xml_int/mod_xml_rpc/mod_xml_rpc.c @@ -680,7 +680,7 @@ abyss_bool handler_hook(TSession * r) break; } - memcpy(qp, r->conn->buffer + r->conn->bufferpos, blen); + memcpy(qp, r->conn->buffer.b + r->conn->bufferpos, blen); qp += blen; if (qlen >= len) { @@ -996,4 +996,4 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_xml_rpc_shutdown) * End: * For VIM: * vim:set softtabstop=4 shiftwidth=4 tabstop=4: - */ + */ \ No newline at end of file