diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-14 14:07:21 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2012-09-14 14:07:21 +0000 |
commit | b12d1dada94cd7083c2a5a023ec2e7a9a51c192a (patch) | |
tree | 78375ed0dfcfed58f45bf266c76a1f9230df01c9 /apps/netutils | |
parent | bf8d0c68312793631ed4ade1541ec36168b3722b (diff) | |
download | nuttx-b12d1dada94cd7083c2a5a023ec2e7a9a51c192a.tar.gz nuttx-b12d1dada94cd7083c2a5a023ec2e7a9a51c192a.tar.bz2 nuttx-b12d1dada94cd7083c2a5a023ec2e7a9a51c192a.zip |
Add XML RPC server plus NXWM build fixes from Max Holtzberg
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5150 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'apps/netutils')
-rw-r--r-- | apps/netutils/Kconfig | 4 | ||||
-rw-r--r-- | apps/netutils/Make.defs | 4 | ||||
-rw-r--r-- | apps/netutils/Makefile | 2 | ||||
-rw-r--r-- | apps/netutils/README.txt | 2 | ||||
-rw-r--r-- | apps/netutils/xmlrpc/Kconfig | 23 | ||||
-rw-r--r-- | apps/netutils/xmlrpc/Makefile | 99 | ||||
-rw-r--r-- | apps/netutils/xmlrpc/response.c | 287 | ||||
-rw-r--r-- | apps/netutils/xmlrpc/xmlparser.c | 416 |
8 files changed, 836 insertions, 1 deletions
diff --git a/apps/netutils/Kconfig b/apps/netutils/Kconfig index aa0f14963..4141e5b03 100644 --- a/apps/netutils/Kconfig +++ b/apps/netutils/Kconfig @@ -56,3 +56,7 @@ endmenu menu "UDP Discovery Utility" source "$APPSDIR/netutils/discover/Kconfig" endmenu + +menu "XML-RPC library" +source "$APPSDIR/netutils/xmlrpc/Kconfig" +endmenu diff --git a/apps/netutils/Make.defs b/apps/netutils/Make.defs index f957009b5..ae72ab0fd 100644 --- a/apps/netutils/Make.defs +++ b/apps/netutils/Make.defs @@ -85,3 +85,7 @@ endif ifeq ($(CONFIG_NETUTILS_DISCOVER),y) CONFIGURED_APPS += netutils/discover endif + +ifeq ($(CONFIG_NETUTILS_XMLRPC),y) +CONFIGURED_APPS += netutils/xmlrpc +endif diff --git a/apps/netutils/Makefile b/apps/netutils/Makefile index 03261c7a3..058b0f629 100644 --- a/apps/netutils/Makefile +++ b/apps/netutils/Makefile @@ -39,7 +39,7 @@ ifeq ($(CONFIG_NET),y) SUBDIRS = uiplib dhcpc dhcpd discover ftpc ftpd resolv smtp telnetd -SUBDIRS += webclient webserver tftpc thttpd +SUBDIRS += webclient webserver tftpc thttpd xmlrpc endif all: nothing diff --git a/apps/netutils/README.txt b/apps/netutils/README.txt index 231cf62c1..73e6689fe 100644 --- a/apps/netutils/README.txt +++ b/apps/netutils/README.txt @@ -66,6 +66,8 @@ highly influenced by uIP) include: CONFIGURED_APPS += uiplib CONFIGURED_APPS += thttpd + xmlrpc - The Embeddable Lightweight XML-RPC Server discussed at + http://www.drdobbs.com/web-development/an-embeddable-lightweight-xml-rpc-server/184405364 Tips for Using Telnetd ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/apps/netutils/xmlrpc/Kconfig b/apps/netutils/xmlrpc/Kconfig new file mode 100644 index 000000000..6765bda07 --- /dev/null +++ b/apps/netutils/xmlrpc/Kconfig @@ -0,0 +1,23 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config NETUTILS_XMLRPC + bool "XML RPC library" + default n + depends on NET_TCP + select NETUTILS_UIPLIB + ---help--- + Enables the Embeddable Lightweight XML-RPC Server discussed at + http://www.drdobbs.com/web-development/an-embeddable-lightweight-xml-rpc-server/184405364 + +if NETUTILS_XMLRPC + +config XMLRPC_STRINGSIZE + int "Maximum string length" + default 64 + ---help--- + Maximum string length for method names and XML RPC string values. + +endif diff --git a/apps/netutils/xmlrpc/Makefile b/apps/netutils/xmlrpc/Makefile new file mode 100644 index 000000000..903506f46 --- /dev/null +++ b/apps/netutils/xmlrpc/Makefile @@ -0,0 +1,99 @@ +############################################################################ +# apps/netutils/xmlrpc/Makefile +# +# Copyright (C) 2012 Max Holtzberg. All rights reserved. +# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. +# +# Authors: Max Holtzberg <mh@uvc.de> +# Gregory Nutt <gnutt@nuttx.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + + +ASRCS = +CSRCS = + +ifeq ($(CONFIG_NET_TCP),y) +CSRCS += xmlparser.c response.c +endif + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(WINTOOL),y) + BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}" +else + BIN = "$(APPDIR)/libapps$(LIBEXT)" +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: context depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + @( for obj in $(OBJS) ; do \ + $(call ARCHIVE, $(BIN), $${obj}); \ + done ; ) + @touch .built + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + @rm -f *.o *~ .*.swp .built + $(call CLEAN) + +distclean: clean + @rm -f Make.dep .depend + +-include Make.dep diff --git a/apps/netutils/xmlrpc/response.c b/apps/netutils/xmlrpc/response.c new file mode 100644 index 000000000..2ae7414a7 --- /dev/null +++ b/apps/netutils/xmlrpc/response.c @@ -0,0 +1,287 @@ +/**************************************************************************** + * apps/netutils/xmlrpc/response.c + * + * Copyright (C) 2012 Max Holtzberg. All rights reserved. + * Author: Max Holtzberg <mh@uvc.de> + * + * Based on the embeddable lightweight XML-RPC server code discussed + * in the article at: http://www.drdobbs.com/web-development/\ + * an-embeddable-lightweight-xml-rpc-server/184405364 + * + * Copyright (c) 2002 Cogito LLC. All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, is hereby granted without fee provided + * that the following conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of Cogito LLC nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY COGITO LLC AND CONTRIBUTERS 'AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COGITO LLC + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARAY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/* + * Lightweight Embedded XML-RPC Server Response Generator + * + * mtj@cogitollc.com + * + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +#include <apps/netutils/xmlrpc.h> + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int xmlrpc_insertlength(struct xmlrpc_s * xmlcall) +{ + int len, digit, xdigit = 1000, i = 0; + char *temp; + + temp = strstr(xmlcall->response, "<?xml"); + len = strlen(temp); + + temp = strstr(xmlcall->response, "xyza"); + + do + { + digit = (len / xdigit); + len -= (digit * xdigit); + xdigit /= 10; + + if ((digit == 0) && (xdigit > 1)) + temp[i++] = ' '; + else + temp[i++] = (0x30 + digit); + } + while (i < 4); + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int xmlrpc_getinteger(struct xmlrpc_s * xmlcall, int *arg) +{ + if ((xmlcall == NULL) || (arg == NULL)) + { + return XMLRPC_INTERNAL_ERROR; + } + + if ((xmlcall->arg < xmlcall->argsize) && + (xmlcall->args[xmlcall->arg] == 'i')) + { + *arg = xmlcall->arguments[xmlcall->arg++].u.i; + return 0; + } + + return XMLRPC_UNEXPECTED_INTEGER_ARG; +} + +int xmlrpc_getbool(struct xmlrpc_s * xmlcall, int *arg) +{ + if ((xmlcall == NULL) || (arg == NULL)) + { + return XMLRPC_INTERNAL_ERROR; + } + + if ((xmlcall->arg < xmlcall->argsize) && + (xmlcall->args[xmlcall->arg] == 'b')) + { + *arg = xmlcall->arguments[xmlcall->arg++].u.i; + return 0; + } + + return XMLRPC_UNEXPECTED_BOOLEAN_ARG; +} + +int xmlrpc_getdouble(struct xmlrpc_s * xmlcall, double *arg) +{ + if ((xmlcall == NULL) || (arg == NULL)) + { + return XMLRPC_INTERNAL_ERROR; + } + + if ((xmlcall->arg < xmlcall->argsize) && + (xmlcall->args[xmlcall->arg] == 'd')) + { + *arg = xmlcall->arguments[xmlcall->arg++].u.d; + return 0; + } + + return XMLRPC_UNEXPECTED_DOUBLE_ARG; +} + +int xmlrpc_getstring(struct xmlrpc_s* xmlcall, char *arg) +{ + if ((xmlcall == NULL) || (arg == NULL)) + { + return XMLRPC_INTERNAL_ERROR; + } + + if ((xmlcall->arg < xmlcall->argsize) && + (xmlcall->args[xmlcall->arg] == 's')) + { + strcpy(arg, xmlcall->arguments[xmlcall->arg++].u.string); + return 0; + } + + return XMLRPC_UNEXPECTED_STRING_ARG; +} + +int xmlrpc_buildresponse(struct xmlrpc_s* xmlcall, char *args, ...) +{ + va_list argp; + int i, ret = 0, index = 0, close = 0; + double d; + char *s; + int isStruct = 0; + + if ((xmlcall == NULL) || (args == NULL)) + { + return -1; + } + + strcpy(xmlcall->response, "HTTP/1.1 200 OK\n" + "Connection: close\n" + "Content-length: xyza\n" + "Content-Type: text/xml\n" + "Server: Lightweight XMLRPC\n\n" + "<?xml version=\"1.0\"?>\n" "<methodResponse>\n"); + + if (xmlcall->error) + { + strcat(&xmlcall->response[strlen(xmlcall->response)], " <fault>\n"); + } + else + { + strcat(&xmlcall->response[strlen(xmlcall->response)], + " <params><param>\n"); + } + + va_start(argp, args); + + while (args[index]) + { + if (isStruct) + { + if ((args[index] != '{') && (args[index] != '}')) + { + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " <member>\n"); + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " <name>%s</name>\n", va_arg(argp, char *)); + close = 1; + } + } + + switch (args[index]) + { + case '{': + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " <value><struct>\n"); + isStruct = 1; + break; + + case '}': + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " </struct></value>\n"); + isStruct = 0; + break; + + case 'i': + i = va_arg(argp, int); + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " <value><int>%d</int></value>\r\n", i); + break; + + case 'b': + i = va_arg(argp, int); + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " <value><boolean>%d</boolean></value>\r\n", i); + break; + + case 'd': + d = va_arg(argp, double); + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " <value><double>%f</double></value>\r\n", d); + break; + + case 's': + s = va_arg(argp, char *); + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " <value><string>%s</string></value>\r\n", s); + break; + + default: + return (XMLRPC_BAD_RESPONSE_ARG); + break; + + } + + if (close) + { + sprintf(&xmlcall->response[strlen(xmlcall->response)], + " </member>\n"); + close = 0; + } + + index++; + } + + va_end(argp); + + if (xmlcall->error) + { + strcat(&xmlcall->response[strlen(xmlcall->response)], " </fault>\r\n"); + } + else + { + strcat(&xmlcall->response[strlen(xmlcall->response)], + " </param></params>\r\n"); + } + + if (ret == 0) + { + strcat(&xmlcall->response[strlen(xmlcall->response)], + "</methodResponse>\r\n"); + + xmlrpc_insertlength(xmlcall); + } + else + { + xmlcall->response[0] = 0; + } + + return ret; +} diff --git a/apps/netutils/xmlrpc/xmlparser.c b/apps/netutils/xmlrpc/xmlparser.c new file mode 100644 index 000000000..72387a08e --- /dev/null +++ b/apps/netutils/xmlrpc/xmlparser.c @@ -0,0 +1,416 @@ +/**************************************************************************** + * apps/netutils/xmlrpc/xmlparser.c + * + * Copyright (C) 2012 Max Holtzberg. All rights reserved. + * Author: Max Holtzberg <mh@uvc.de> + * + * Based on the embeddable lightweight XML-RPC server code discussed + * in the article at: http://www.drdobbs.com/web-development/\ + * an-embeddable-lightweight-xml-rpc-server/184405364 + * + * Copyright (c) 2002 Cogito LLC. All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, is hereby granted without fee provided + * that the following conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * 3. Neither the name of Cogito LLC nor the names of its + * contributors may be used to endorse or promote products + * derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY COGITO LLC AND CONTRIBUTERS 'AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COGITO LLC + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARAY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/* + * Lightweight Embedded XML-RPC Server XML Parser + * + * mtj@cogitollc.com + * + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <apps/netutils/xmlrpc.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define TAG 0 +#define VALUE 1 +#define DONE 2 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct xmlrpc_s g_xmlcall; +static char g_data[CONFIG_XMLRPC_STRINGSIZE+1]; +static struct xmlrpc_entry_s *g_entries = NULL; + +static const char *errorStrings[] = +{ + /* 0 */ "Internal error (unknown)", + /* 1 */ "Parse Error...", + /* 2 */ "Function not found...", + /* 3 */ "Unexpected Integer Argument...", + /* 4 */ "Unexpected Boolean Argument...", + /* 5 */ "Unexpected Double Argument...", + /* 6 */ "Unexpected String Argument...", + /* 7 */ "Bad Response Argument..." +}; + +#define MAX_ERROR_CODE (sizeof(errorStrings)/sizeof(char *)) + +struct parsebuf_s +{ + char *buf; + int len; + int index; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int xmlrpc_call(struct xmlrpc_s * call) +{ + int ret = XMLRPC_NO_SUCH_FUNCTION; + struct xmlrpc_entry_s *entry = g_entries; + + while (entry != NULL) + { + if (strcmp(call->name, entry->name) == 0) + { + ret = entry->func(call); + break; + } + else + { + entry = entry->next; + } + } + + return ret; +} + +static int xmlrpc_getelement(struct parsebuf_s * pbuf, char *data, int dataSize) +{ + int j = 0; + int ret = XMLRPC_NO_ERROR; + + while (!isprint(pbuf->buf[pbuf->index])) + { + pbuf->index++; + } + + if (pbuf->index >= pbuf->len) + { + return DONE; + } + + if (pbuf->buf[pbuf->index] == '<') + { + ret = TAG; + } + else + { + ret = VALUE; + } + + data[j++] = pbuf->buf[pbuf->index++]; + + while (j < dataSize) + { + if (pbuf->buf[pbuf->index] == '>') + { + data[j++] = pbuf->buf[pbuf->index++]; + break; + } + else if ((pbuf->buf[pbuf->index] == '\n') || + (pbuf->buf[pbuf->index] == '<')) + { + break; + } + else + { + data[j++] = pbuf->buf[pbuf->index++]; + if (j >= dataSize) + ret = XMLRPC_PARSE_ERROR; + } + } + + data[j] = 0; + return ret; +} + +static int xmlrpc_parseparam(struct parsebuf_s * pbuf) +{ + int type; + + /* Next, we need a <value> tag */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if (!((type == TAG) && (!strncmp(g_data, "<value>", 7)))) + { + return XMLRPC_PARSE_ERROR; + } + + /* Now we get a variable tag, the type of the value */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if (type != TAG) + { + return XMLRPC_PARSE_ERROR; + } + + if (!strncmp(g_data, "<i4>", 4)) + { + g_xmlcall.args[g_xmlcall.argsize] = 'i'; + } + else if (!strncmp(g_data, "<int>", 5)) + { + g_xmlcall.args[g_xmlcall.argsize] = 'i'; + } + else if (!strncmp(g_data, "<boolean>", 9)) + { + g_xmlcall.args[g_xmlcall.argsize] = 'b'; + } + else if (!strncmp(g_data, "<double>", 8)) + { + g_xmlcall.args[g_xmlcall.argsize] = 'd'; + } + else if (!strncmp(g_data, "<string>", 8)) + { + g_xmlcall.args[g_xmlcall.argsize] = 's'; + } + else + { + return XMLRPC_PARSE_ERROR; + } + + /* Now, parse the actual value */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if (type != VALUE) + { + return XMLRPC_PARSE_ERROR; + } + + switch (g_xmlcall.args[g_xmlcall.argsize]) + { + case 'i': + case 'b': + g_xmlcall.arguments[g_xmlcall.argsize].u.i = atoi(g_data); + break; + case 'd': + g_xmlcall.arguments[g_xmlcall.argsize].u.d = atof(g_data); + break; + case 's': + strcpy(g_xmlcall.arguments[g_xmlcall.argsize].u.string, g_data); + break; + default: + return XMLRPC_PARSE_ERROR; + } + + g_xmlcall.argsize++; + + /* Now we close out the tag, starting with the type */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if (!((type == TAG) && (!strncmp(g_data, "</", 2)))) + { + return XMLRPC_PARSE_ERROR; + } + + /* Next, look for the </value> close */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if (!((type == TAG) && (!strncmp(g_data, "</value>", 8)))) + { + return XMLRPC_PARSE_ERROR; + } + + /* Finally, close out the </param> tag */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if (!((type == TAG) && (!strncmp(g_data, "</param>", 8)))) + { + return XMLRPC_PARSE_ERROR; + } + + return XMLRPC_NO_ERROR; +} + +static int xmlrpc_parseparams(struct parsebuf_s * pbuf) +{ + int type, ret = XMLRPC_PARSE_ERROR; + + /* First, look for the params tag */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if ((type == TAG) && (!strncmp(g_data, "<params>", 8))) + { + while (1) + { + /* Get next tag */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if ((type == TAG) && (!strncmp(g_data, "<param>", 7))) + { + ret = xmlrpc_parseparam(pbuf); + } + else if ((type == TAG) && (!strncmp(g_data, "</params>", 9))) + { + return XMLRPC_NO_ERROR; + } + else + { + return XMLRPC_PARSE_ERROR; + } + } + } + + return ret; +} + +static int xmlrpc_parsemethod(struct parsebuf_s * pbuf) +{ + int type, ret = XMLRPC_PARSE_ERROR; + + bzero((void *)&g_xmlcall, sizeof(struct xmlrpc_s)); + + /* Look for the methodName tag */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if ((type == TAG) && (!strncmp(g_data, "<methodName>", 12))) + { + /* Get the method name for the call */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if (type == VALUE) + { + /* Save the method name */ + + strcpy(g_xmlcall.name, g_data); + + /* Find the closing /methodCall */ + + type = xmlrpc_getelement(pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if ((type == TAG) && (!strncmp(g_data, "</methodName>", 13))) + { + /* Now, it's time to parse the parameters */ + + ret = xmlrpc_parseparams(pbuf); + } + } + } + + return ret; +} + +static void xmlrpc_sendfault(int fault) +{ + fault = -fault; + if (fault >= MAX_ERROR_CODE) + { + fault = 0; + } + + xmlrpc_buildresponse(&g_xmlcall, "{is}", + "faultCode", fault, "faultString", errorStrings[fault]); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int xmlrpc_parse(int sock, char *buffer) +{ + struct parsebuf_s pbuf; + int type; + int ret = XMLRPC_PARSE_ERROR; + + pbuf.buf = buffer; + pbuf.len = strlen(buffer); + pbuf.index = 0; + + /* Parse the xml header tag */ + + type = xmlrpc_getelement(&pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if ((type == TAG) && (!strncmp(g_data, "<?xml", 5))) + { + type = xmlrpc_getelement(&pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if ((type == TAG) && (!strncmp(g_data, "<methodCall>", 12))) + { + /* Parse the remaining tags within the methodCall tag */ + + xmlrpc_parsemethod(&pbuf); + + /* Check for the closing /methodCall */ + + type = xmlrpc_getelement(&pbuf, g_data, CONFIG_XMLRPC_STRINGSIZE); + if ((type == TAG) && (!strncmp(g_data, "</methodCall>", 13))) + { + /* Successful parse, try to call a user function */ + + ret = xmlrpc_call(&g_xmlcall); + } + } + } + + if (ret == 0) + { + write(sock, g_xmlcall.response, strlen(g_xmlcall.response)); + } + else + { + /* Send fault response */ + + g_xmlcall.error = 1; + xmlrpc_sendfault(ret); + write(sock, g_xmlcall.response, strlen(g_xmlcall.response)); + } + + return ret; +} + +void xmlrpc_register(struct xmlrpc_entry_s *entry) +{ + if (g_entries == NULL) + { + g_entries = entry; + entry->next = NULL; + } + else + { + entry->next = g_entries; + g_entries = entry; + } +} |