diff --git a/src/xml-rpc.c b/src/xml-rpc.c index 655cea56..603fc28e 100644 --- a/src/xml-rpc.c +++ b/src/xml-rpc.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -16,23 +17,142 @@ #include "webserver.h" /* typedefs */ +typedef struct tag_xmlstack { + char *tag; + struct tag_xmlstack *next; +} XMLSTACK; + typedef struct tag_xmlstruct { + WS_CONNINFO *pwsc; + int stack_level; + XMLSTACK stack; } XMLSTRUCT; /* Forwards */ void xml_get_stats(WS_CONNINFO *pwsc); char *xml_entity_encode(char *original); +XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header); +void xml_push(XMLSTRUCT *pxml, char *term); +void xml_pop(XMLSTRUCT *pxml); +void xml_output(XMLSTRUCT *pxml, char *section, char *fmt, ...); +void xml_deinit(XMLSTRUCT *pxml); + /** * create an xml response structure, a helper struct for * building xml responses. * + * @param pwsc the pwsc we are emitting to + * @param emit_header whether or not to throw out html headers and xml header * @returns XMLSTRUCT on success, or NULL if failure */ -XMLSTRUCT *xml_init(void) { +XMLSTRUCT *xml_init(WS_CONNINFO *pwsc, int emit_header) { + XMLSTRUCT *pxml; + + pxml=(XMLSTRUCT*)malloc(sizeof(XMLSTRUCT)); + if(!pxml) { + DPRINTF(E_FATAL,L_XML,"Malloc error\n"); + } + + memset(pxml,0,sizeof(XMLSTRUCT)); + + pxml->pwsc = pwsc; + + if(emit_header) { + ws_addresponseheader(pwsc,"Content-Type","text/xml; charset=utf-8"); + ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n"); + ws_emitheaders(pwsc); + + ws_writefd(pwsc,""); + } + + return pxml; } - +/** + * push a new term on the stack + * + * @param pxml xml struct obtained from xml_init + * @param term next xlm section to start + */ +void xml_push(XMLSTRUCT *pxml, char *term) { + XMLSTACK *pstack; + + pstack = (XMLSTACK *)malloc(sizeof(XMLSTACK)); + pstack->next=pxml->stack.next; + pstack->tag=strdup(term); + pxml->stack.next=pstack; + + pxml->stack_level++; + + ws_writefd(pxml->pwsc,"<%s>",term); +} + +/** + * end an xml section + * + * @param pxml xml struct we are working with + */ +void xml_pop(XMLSTRUCT *pxml) { + XMLSTACK *pstack; + + pstack=pxml->stack.next; + if(!pstack) { + DPRINTF(E_LOG,L_XML,"xml_pop: tried to pop an empty stack\n"); + return; + } + + pxml->stack.next = pstack->next; + + ws_writefd(pxml->pwsc,"",pstack->tag); + free(pstack->tag); + free(pstack); + + pxml->stack_level--; +} + +/** + * output a string + */ +void xml_output(XMLSTRUCT *pxml, char *section, char *fmt, ...) { + va_list ap; + char buf[256]; + char *output; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + output = xml_entity_encode(buf); + if(section) { + xml_push(pxml,section); + } + ws_writefd(pxml->pwsc,"%s",output); + free(output); + if(section) { + xml_pop(pxml); + } +} + +/** + * clean up an xml struct + * + * @param pxml xml struct to clean up + */ +void xml_deinit(XMLSTRUCT *pxml) { + XMLSTACK *pstack; + + if(pxml->stack.next) { + DPRINTF(E_LOG,L_XML,"xml_deinit: entries still on stack (%s)\n",pxml->stack.next->tag); + } + + while((pstack=pxml->stack.next)) { + pxml->stack.next=pstack->next; + free(pstack->tag); + free(pstack); + } + free(pxml); +} /** * main entrypoint for the xmlrpc functions. @@ -66,39 +186,33 @@ void xml_get_stats(WS_CONNINFO *pwsc) { SCAN_STATUS *pss; WSTHREADENUM wste; - - ws_addresponseheader(pwsc,"Content-Type","text/xml; charset=utf-8"); - ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n"); - ws_emitheaders(pwsc); - - ws_writefd(pwsc,""); - ws_writefd(pwsc,""); - - ws_writefd(pwsc,""); - /* enumerate services? */ - ws_writefd(pwsc,""); + XMLSTRUCT *pxml; - ws_writefd(pwsc,""); - /* enumerate thread status */ + pxml=xml_init(pwsc,1); + xml_push(pxml,"status"); + + xml_push(pxml,"service_status"); + xml_pop(pxml); /* service_status */ + + xml_push(pxml,"thread_status"); pci = ws_thread_enum_first(config.server,&wste); while(pci) { pss = ws_get_local_storage(pci); if(pss) { - ws_writefd(pwsc,"%d%s%s", - pss->thread,pss->host,pss->what); + xml_push(pxml,"thread"); + xml_output(pxml,"id","%d",pss->thread); + xml_output(pxml,"sourceip","%s",pss->host); + xml_output(pxml,"action","%s",pss->what); + xml_pop(pxml); /* thread */ } pci=ws_thread_enum_next(config.server,&wste); } - - ws_writefd(pwsc,""); - - ws_writefd(pwsc,""); - /* dump stats */ - - ws_writefd(pwsc,""); + xml_pop(pxml); /* thread_status */ + xml_push(pxml,"statistics"); + r_secs=time(NULL)-config.stats.start_time; r_days=r_secs/(3600 * 24); @@ -126,11 +240,14 @@ void xml_get_stats(WS_CONNINFO *pwsc) { sprintf((char*)&buf[strlen(buf)],"%d second%s ", r_secs, r_secs == 1 ? "" : "s"); - ws_writefd(pwsc,"Uptime"); - ws_writefd(pwsc,"%s",buf); - ws_writefd(pwsc,""); - ws_writefd(pwsc,""); - ws_writefd(pwsc,""); + xml_push(pxml,"stat"); + xml_output(pxml,"name","Uptime"); + xml_output(pxml,"value","%s",buf); + xml_pop(pxml); /* stat */ + xml_pop(pxml); /* statistics */ + xml_pop(pxml); /* status */ + + xml_deinit(pxml); return; }