1 /*****************************************************************************
2  *
3  * FILE:	sxmlrpc.c
4  * DESCRIPTION:	Skimpy XML-RPC library file
5  * DATE:	Sat, Mar 18 2006
6  * UPDATED:	Mon, Jan 26 2009
7  * AUTHOR:	Kouichi ABE (WALL) / ��������
8  * E-MAIL:	kouichi@MysticWALL.COM
9  * URL:		http://www.MysticWALL.COM/
10  * COPYRIGHT:	(c) 2006-2009 �������졿Kouichi ABE (WALL), All rights reserved.
11  * LICENSE:
12  *
13  *  Copyright (c) 2006-2009 Kouichi ABE (WALL) <kouichi@MysticWALL.COM>,
14  *  All rights reserved.
15  *
16  *  Redistribution and use in source and binary forms, with or without
17  *  modification, are permitted provided that the following conditions
18  *  are met:
19  *
20  *   1. Redistributions of source code must retain the above copyright
21  *      notice, this list of conditions and the following disclaimer.
22  *   2. Redistributions in binary form must reproduce the above copyright
23  *      notice, this list of conditions and the following disclaimer in the
24  *      documentation and/or other materials provided with the distribution.
25  *
26  *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27  *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30  *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  *   SUCH DAMAGE.
37  *
38  * $Id: sxmlrpc.c,v 1.11 2010/03/26 07:56:17 kouichi Exp $
39  *
40  *****************************************************************************/
41 
42 #if	HAVE_CONFIG_H
43 #include "config.h"
44 #endif	/* HAVE_CONFIG_H */
45 
46 #include <stdio.h>
47 #if	HAVE_STDLIB_H
48 #include <stdlib.h>
49 #endif	/* HAVE_STDLIB_H */
50 #if	HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif	/* HAVE_UNISTD_H */
53 #if	HAVE_STRING_H
54 #include <string.h>
55 #endif	/* HAVE_STRING_H */
56 #if	HAVE_FCNTL_H
57 #include <fcntl.h>
58 #endif	/* HAVE_FCNTL_H */
59 #if	HAVE_NETINET_IN_H
60 #include <netinet/in.h>
61 #endif	/* HAVE_NETINET_IN_H */
62 #if	HAVE_SYS_TYPES_H
63 #include <sys/types.h>
64 #endif	/* HAVE_SYS_TYPES_H */
65 #if	HAVE_SYS_STAT_H
66 #include <sys/stat.h>
67 #endif	/* HAVE_SYS_STAT_H */
68 #include <sys/mman.h>
69 #if	HAVE_SYS_SOCKET_H
70 #include <sys/socket.h>
71 #endif	/* HAVE_SYS_SOCKET_H */
72 #if	HAVE_NETDB_H
73 #include <netdb.h>
74 #endif	/* HAVE_NETDB_H */
75 #if	HAVE_NETINET_IN_H
76 #include <netinet/in.h>
77 #endif	/* HAVE_NETINET_IN_H */
78 #include <arpa/inet.h>
79 #if	TIME_WITH_SYS_TIME
80 # include <sys/time.h>
81 # include <time.h>
82 #else
83 # if	HAVE_SYS_TIME_H
84 #  include <sys/time.h>
85 # else
86 #  include <time.h>
87 # endif	/* HAVE_SYS_TIME_H */
88 #endif	/* TIME_WITH_SYS_TIME */
89 #include <signal.h>
90 #include <errno.h>
91 #include "sxml.h"
92 #include "sxmlrpc.h"
93 
94 /******************************************************************************
95  *
96  *	Macros and structures definition
97  *
98  *****************************************************************************/
99 #define	EOL	'\0'
100 #define	LF	'\012'
101 #define	CR	'\015'
102 #define	SPC	'\040'
103 #define	CRLF	"\015\012"
104 
105 /* easy network I/O manager */
106 typedef struct _netfd {
107 #define	netfd_fileno(x)	((x)->osfd)
108   int		osfd;		/* underlying OS file descriptor */
109 #define	NETFD_BUFSIZE	(1024*4)
110   struct {	/* read buffer */
111     int		total;	/* initialize to 0 */
112     char *	bufp;	/* initialize to buf */
113     char	buf[NETFD_BUFSIZE];
114   } rb;
115 } netfd_t;
116 #define	NETFD_SEEK_SET	SEEK_SET
117 #define	NETFD_SEEK_CUR	SEEK_CUR
118 #define	NETFD_SEEK_END	SEEK_END
119 
120 #define	NETFD_DEF_BACKLOG	(8)
121 
122 /* default encoding */
123 #if	1
124 #define	SXMLRPC_ENCODING	"us-ascii"
125 #else
126 #define	SXMLRPC_ENCODING	"utf-8"
127 #endif
128 
129 /* default XML-RPC XML version */
130 #define	SXMLRPC_XML_VERSION	"1.0"
131 
132 /* default User-Agent of Request Header */
133 #define	SXMLRPC_USER_AGENT	SXMLRPC_VERSION
134 
135 /* default Server of Response Header */
136 #define	SXMLRPC_SERVER		SXMLRPC_VERSION
137 
138 /* default Content-Type of Request Header */
139 #define	SXMLRPC_CONTENT_TYPE	"text/xml"
140 
141 /* headers */
142 #define	CONTENT_LENGTH		"Content-Length"
143 #define	CONTENT_TYPE		"Content-Type"
144 
145 /* mkstemp(3) */
146 #define	SXMLRPC_TEMPLATE	"/tmp/.sxmlrpc.XXXXXX"
147 
148 #define	xfree(x) \
149 	do { if ((x)!=NULL) { free((x)); (x)=NULL; } } while (0)
150 
151 /******************************************************************************
152  *
153  *	Lobal functions declaration
154  *
155  *****************************************************************************/
156 static void		flush_params(sxmlrpc_params_t *);
157 static int		make_request_body(sxmlrpc_t *, const char *,
158 					  sxmlrpc_param_t *, size_t);
159 static sxml_node_t *	graft_request_body(const char *, sxmlrpc_param_t *,
160 					   size_t);
161 static int		make_request_head(sxmlrpc_t *);
162 static int		make_response_body(sxmlrpc_t *, sxmlrpc_param_t *);
163 static sxml_node_t *	graft_response_body(sxmlrpc_param_t *);
164 static sxml_node_t *	graft_fault_body(sxmlrpc_param_t *);
165 static int		make_response_head(sxmlrpc_t *);
166 static int		send_message(sxmlrpc_t *, netfd_t *, netfd_t *);
167 static sxml_node_t *	recv_message(sxmlrpc_t *, netfd_t *, netfd_t *);
168 static int		parse_start_line(sxmlrpc_t *, char *);
169 static int		make_new_value(sxml_node_t *, sxmlrpc_value_t *);
170 static int		get_call_params(sxmlrpc_t *, sxml_node_t *);
171 static size_t		set_call_params(sxmlrpc_t *, sxml_node_t *);
172 static sxml_node_t *	get_response_value(sxmlrpc_t *, sxml_node_t *);
173 static int		set_value(sxmlrpc_value_t *, sxml_node_t *);
174 static int		set_value_member(sxmlrpc_member_t *, sxml_node_t *);
175 static int		set_value_array(sxmlrpc_value_t *, sxml_node_t *);
176 static size_t		count_children(sxml_node_t *);
177 
178 static netfd_t *	netfd_open(const char *, int, mode_t);
179 static netfd_t *	netfd_fdopen(int);
180 static netfd_t *	netfd_new(int);
181 static int		netfd_close(netfd_t *);
182 static off_t		netfd_seek(netfd_t *, off_t, int);
183 static ssize_t		netfd_read(netfd_t *, void *, size_t);
184 static ssize_t		netfd_write(netfd_t *, const void *, size_t);
185 static ssize_t		netfd_readline(netfd_t *, void *, size_t);
186 static ssize_t		one_read(netfd_t *, char *);
187 static int		netfd_readbuf(netfd_t *);
188 static netfd_t *	netfd_mkstemp(char *);
189 #if	HAVE_FREEBSD_SENDFILE
190 static int		netfd_sendfile(netfd_t *, netfd_t *, off_t, size_t,
191 				       struct sf_hdtr *, off_t *, int);
192 #elif	HAVE_LINUX_SENDFILE
193 static int		netfd_sendfile(netfd_t *, netfd_t *, off_t, size_t,
194 				       void *, off_t *, int);
195 #else
196 static int		netfd_sendfile(netfd_t *, netfd_t *, off_t, size_t,
197 				       void *, off_t *, int);
198 #endif
199 static void		sigalrm(int signo);
200 static netfd_t *	netfd_tcp_client(const char *, const char *);
201 static netfd_t *	netfd_tcp_server(const char *, const char *, const int);
202 static netfd_t *	netfd_accept(netfd_t *, struct sockaddr *, socklen_t *);
203 static int		netfd_sock_ntop(const struct sockaddr * sa0,
204 					char ** ipaddr);
205 static int		my_close(int fd);
206 
207 /******************************************************************************
208  *
209  *	Lobal variable definition
210  *
211  *****************************************************************************/
212 static sig_atomic_t	timedout = 0;	/* flag for connect() */
213 
214 /******************************************************************************
215  *
216  *	Functions definition
217  *
218  *****************************************************************************/
219 sxmlrpc_t *
sxmlrpc_new(hostname,servname,path)220 sxmlrpc_new(hostname, servname, path)
221 	const char *	hostname;
222 	const char *	servname;
223 	const char *	path;
224 {
225   sxmlrpc_t *	new;
226 
227   new = (sxmlrpc_t *)calloc(1, sizeof(sxmlrpc_t));
228   if (new != NULL) {
229     new->hostname = strdup(hostname);
230     new->servname = strdup(servname);
231     new->path	  = strdup(path);
232     new->encoding = NULL;
233   }
234 
235   return new;
236 }
237 
238 void
sxmlrpc_free(sxRPC)239 sxmlrpc_free(sxRPC)
240 	sxmlrpc_t *	sxRPC;
241 {
242   if (sxRPC != NULL) {
243     xfree(sxRPC->hostname);
244     xfree(sxRPC->servname);
245     xfree(sxRPC->path);
246     xfree(sxRPC->encoding);
247     xfree(sxRPC);
248   }
249 }
250 
251 void
sxmlrpc_flush(sxRPC)252 sxmlrpc_flush(sxRPC)
253 	sxmlrpc_t *	sxRPC;
254 {
255   if (sxRPC != NULL) {
256     switch (sxRPC->role) {
257       case SXMLRPC_ROLE_SERVER:
258 	xfree(sxRPC->call_method);
259 	flush_params(&sxRPC->call_params);
260 	break;
261       case SXMLRPC_ROLE_CLIENT:
262 	sxmlrpc_flush_value(&sxRPC->response_value);
263       default:
264 	break;
265     }
266   }
267 }
268 
269 void
sxmlrpc_flush_value(v)270 sxmlrpc_flush_value(v)
271 	sxmlrpc_value_t *	v;
272 {
273   if (v != NULL) {
274     register size_t	i;
275 
276     switch (v->type) {
277       case SXMLRPC_VALUE_STRING:
278       case SXMLRPC_VALUE_DATETIME:
279       case SXMLRPC_VALUE_BASE64:
280 	xfree(v->u.sval);
281 	break;
282       case SXMLRPC_VALUE_STRUCT:
283 	for (i = 0; i < v->u.tval.size; i++) {
284 	  xfree(v->u.tval.member[i].name);
285 	  sxmlrpc_flush_value(&v->u.tval.member[i].value);
286 	}
287 	xfree(v->u.tval.member);
288 	v->u.tval.size = 0;
289 	break;
290       case SXMLRPC_VALUE_ARRAY:
291 	for (i = 0; i < v->u.aval.size; i++) {
292 	  sxmlrpc_flush_value(&v->u.aval.value[i]);
293 	}
294 	xfree(v->u.aval.value);
295 	v->u.aval.size = 0;
296 	break;
297       default:
298 	break;
299     }
300   }
301 }
302 
303 static void
flush_params(params)304 flush_params(params)
305 	sxmlrpc_params_t *	params;
306 {
307   if (params->param != NULL) {
308     register size_t	i;
309 
310     for (i = 0; i < params->size; i++) {
311       sxmlrpc_flush_value(&params->param[i].value);
312     }
313     xfree(params->param);
314     params->size = 0;
315   }
316 }
317 
318 /*****************************************************************************/
319 
320 int
sxmlrpc_call(sxRPC,method_name,param,param_num)321 sxmlrpc_call(sxRPC, method_name, param, param_num)
322 	sxmlrpc_t *		sxRPC;
323 	const char *		method_name;
324 	sxmlrpc_param_t *	param;
325 	size_t			param_num;
326 {
327   netfd_t *	nfd;
328   char		template[] = SXMLRPC_TEMPLATE;
329   int		status	   = -1;
330 
331   if (sxRPC == NULL) {
332     errno = EINVAL;
333     return -1;
334   }
335 
336   nfd = netfd_mkstemp(template);
337   if (nfd != NULL) {
338     sxRPC->msgbdy_fd = netfd_fileno(nfd);
339     sxRPC->role	     = SXMLRPC_ROLE_CLIENT;
340     sxRPC->method    = SXMLRPC_METHOD_CALL;
341     if (make_request_body(sxRPC, method_name, param, param_num) == 0) {
342       if (make_request_head(sxRPC) == 0) {
343 	netfd_t *	nsd;
344 
345 	nsd = netfd_tcp_client(sxRPC->hostname, sxRPC->servname);
346 	if (nsd != NULL) {
347 	  status = send_message(sxRPC, nfd, nsd);
348 	  if (status == 0) {
349 	    netfd_close(nfd);
350 	    nfd = netfd_open(template, O_RDWR|O_TRUNC, 0600);
351 	    if (nfd != NULL) {
352 	      sxml_node_t *	root;
353 
354 	      root = recv_message(sxRPC, nfd, nsd);
355 	      if (root != NULL) {
356 		sxml_node_t *	np;
357 
358 		np = get_response_value(sxRPC, root);
359 		if (np != NULL) {
360 		  status = set_value(&sxRPC->response_value, np);
361 		}
362 		sxml_delete_node(root);
363 	      }
364 	    }
365 	  }
366 	  netfd_close(nsd);
367 	}
368       }
369     }
370     unlink(template);
371     netfd_close(nfd);
372   }
373 
374   return status;
375 }
376 
377 static int
make_request_body(sxRPC,method_name,param,param_num)378 make_request_body(sxRPC, method_name, param, param_num)
379 	sxmlrpc_t *		sxRPC;
380 	const char *		method_name;
381 	sxmlrpc_param_t *	param;
382 	size_t			param_num;
383 {
384   int	fd;
385   int	status = -1;
386 
387   fd = dup(sxRPC->msgbdy_fd);
388   if (fd != -1) {
389     register FILE *	fout;
390 
391     fout = fdopen(fd, "r+");
392     if (fout != NULL) {
393       sxml_node_t *	root;
394 
395       root = graft_request_body(method_name, param, param_num);
396       if (root != NULL) {
397 	sxml_node_t *	np;
398 
399 	np = sxml_new_prolog(root, "xml");
400 	if (np != NULL) {
401 	  sxml_set_attribute(np, "encoding",
402 			     sxRPC->encoding ? sxRPC->encoding
403 					     : SXMLRPC_ENCODING);
404 	  sxml_set_attribute(np, "version", SXMLRPC_XML_VERSION);
405 	}
406 	sxml_print_tree(root, fout);
407 	sxml_delete_node(root);
408 	if (fseek(fout, 0L, SEEK_SET) == 0) {
409 	  struct stat	sbuf;
410 
411 	  status = fstat(fd, &sbuf);
412 	  if (status == 0) {
413 	    sxRPC->msgbdy_size = (size_t)sbuf.st_size;
414 	  }
415 	}
416       }
417       fclose(fout);
418     }
419     close(fd);
420   }
421 
422   return status;
423 }
424 
425 static sxml_node_t *
graft_request_body(method_name,param,param_num)426 graft_request_body(method_name, param, param_num)
427 	const char *		method_name;
428 	sxmlrpc_param_t *	param;
429 	size_t			param_num;
430 {
431   sxml_node_t *	root;
432 
433   root = sxml_new_vertex();
434   if (root != NULL) {
435     sxml_node_t *	mc;
436 
437     mc = sxml_new_element(root, "methodCall");
438     if (mc != NULL) {
439       sxml_node_t *	ps;
440 
441       sxml_set_node(mc, "methodName", method_name);
442       ps = sxml_new_element(mc, "params");
443       if (ps != NULL) {
444 	register size_t	i;
445 
446 	for (i = 0; i < param_num; i++) {
447 	  sxml_node_t *	p;
448 
449 	  p = sxml_new_element(ps, "param");
450 	  if (p != NULL) {
451 	    make_new_value(p, &param[i].value);
452 	  }
453 	}
454       }
455     }
456   }
457 
458   return root;
459 }
460 
461 static int
make_request_head(sxRPC)462 make_request_head(sxRPC)
463 	sxmlrpc_t *	sxRPC;
464 {
465   sxRPC->msghdr_size = asprintf(&sxRPC->msghdr_text,
466 	"POST %s HTTP/1.0" CRLF
467 	"Host: %s:%s" CRLF
468 	"User-Agent: " SXMLRPC_USER_AGENT CRLF
469 	"Content-Type: " SXMLRPC_CONTENT_TYPE CRLF
470 	"Content-Length: %d" CRLF
471 	CRLF ,
472 	sxRPC->path, sxRPC->hostname, sxRPC->servname,
473 	sxRPC->msgbdy_size);
474   return (sxRPC->msghdr_text != NULL) ? 0 : -1;
475 }
476 
477 /*****************************************************************************/
478 
479 static sxmlrpc_boolean_t	forever = true;
480 
trap(int signo)481 static void trap(int signo) { forever = false; }
482 
483 int
sxmlrpc_server(sxRPC,backlog,callback)484 sxmlrpc_server(sxRPC, backlog, callback)
485 	sxmlrpc_t *		sxRPC;
486 	const int		backlog;
487 	sxmlrpc_callback_t	callback;
488 {
489   netfd_t *	listenfd;
490 
491   if (callback == NULL) {
492     errno = EINVAL;
493     return -1;
494   }
495 
496   listenfd = netfd_tcp_server(sxRPC->hostname, sxRPC->servname, backlog);
497   if (listenfd != NULL) {
498     struct sigaction	act;
499 
500     sigemptyset(&act.sa_mask);
501     act.sa_flags	= 0;
502     act.sa_handler	= (void *)trap;
503     sigaction(SIGINT,  &act, NULL);
504     sigaction(SIGQUIT, &act, NULL);
505     sigaction(SIGTERM, &act, NULL);
506     sigaction(SIGBUS,  &act, NULL);
507     sigaction(SIGSEGV, &act, NULL);
508 
509     while (forever) {
510       netfd_t *		connfd;
511       struct sockaddr	addr;
512       socklen_t		addrlen;
513 
514       connfd = netfd_accept(listenfd, &addr, &addrlen);
515       if (connfd != NULL) {
516 	netfd_t *	nfd;
517 	char		template[] = SXMLRPC_TEMPLATE;
518 
519 	nfd = netfd_mkstemp(template);
520 	if (nfd != NULL) {
521 	  sxml_node_t *	root;
522 
523 	  sxRPC->msgbdy_fd = netfd_fileno(nfd);
524 
525 	  root = recv_message(sxRPC, nfd, connfd);
526 	  if (root != NULL) {
527 	    int	status;
528 
529 	    status = get_call_params(sxRPC, root);
530 	    if (status != -1) {
531 	      sxmlrpc_param_t	param;
532 	      char *		client;
533 
534 	      status = netfd_sock_ntop(&addr, &client);
535 	      if ((*callback)(client, sxmlrpc_method_name(sxRPC),
536 			      &sxmlrpc_call_params(sxRPC), &param) == 0) {
537 		sxmlrpc_response_ok(sxRPC);
538 	      }
539 	      else {
540 		sxmlrpc_response_fault(sxRPC);
541 	      }
542 	      if (status == 0) { free(client); }
543 
544 	      netfd_close(nfd);
545 	      nfd = netfd_open(template, O_RDWR|O_TRUNC, 0600);
546 	      if (nfd != NULL) {
547 		if (make_response_body(sxRPC, &param) == 0) {
548 		  if (make_response_head(sxRPC) == 0) {
549 		    send_message(sxRPC, nfd, connfd);
550 		  }
551 		}
552 	      }
553 	      sxmlrpc_flush(sxRPC);
554 	      sxmlrpc_flush_value(&param.value);
555 	    }
556 	    sxml_delete_node(root);
557 	  }
558 	  unlink(template);
559 	  netfd_close(nfd);
560 	}
561 	netfd_close(connfd);
562       }
563     }
564     netfd_close(listenfd);
565   }
566 
567   return 0;
568 }
569 
570 static int
make_response_body(sxRPC,param)571 make_response_body(sxRPC, param)
572 	sxmlrpc_t *		sxRPC;
573 	sxmlrpc_param_t *	param;
574 {
575   int	fd;
576   int	status = -1;
577 
578   fd = dup(sxRPC->msgbdy_fd);
579   if (fd != -1) {
580     register FILE *	fout;
581 
582     fout = fdopen(fd, "r+");
583     if (fout != NULL) {
584       sxml_node_t *	root = NULL;
585 
586       switch (sxRPC->method) {
587 	case SXMLRPC_METHOD_RESPONSE:
588 	  root = graft_response_body(param);
589 	  break;
590 	case SXMLRPC_METHOD_RESPONSE_FAULT:
591 	  root = graft_fault_body(param);
592 	  break;
593 	default:
594 	  break;
595       }
596       if (root != NULL) {
597 	sxml_node_t *	np;
598 
599 	np = sxml_new_prolog(root, "xml");
600 	if (np != NULL) {
601 	  sxml_set_attribute(np, "encoding",
602 			     sxRPC->encoding ? sxRPC->encoding
603 					     : SXMLRPC_ENCODING);
604 	  sxml_set_attribute(np, "version", SXMLRPC_XML_VERSION);
605 	}
606 	sxml_print_tree(root, fout);
607 	sxml_delete_node(root);
608 	if (fseek(fout, 0L, SEEK_SET) == 0) {
609 	  struct stat	sbuf;
610 
611 	  status = fstat(fd, &sbuf);
612 	  if (status == 0) {
613 	    sxRPC->msgbdy_size = (size_t)sbuf.st_size;
614 	  }
615 	}
616       }
617       fclose(fout);
618     }
619     close(fd);
620   }
621 
622   return status;
623 }
624 
625 static sxml_node_t *
graft_response_body(param)626 graft_response_body(param)
627 	sxmlrpc_param_t *	param;
628 {
629   sxml_node_t *	root;
630 
631   root = sxml_new_vertex();
632   if (root != NULL) {
633     sxml_node_t *	mr;
634 
635     mr = sxml_new_element(root, "methodResponse");
636     if (mr != NULL) {
637       sxml_node_t *	ps;
638 
639       ps = sxml_new_element(mr, "params");
640       if (ps != NULL) {
641 	sxml_node_t *	p;
642 
643 	p = sxml_new_element(ps, "param");
644 	if (p != NULL) {
645 	  make_new_value(p, &param->value);
646 	}
647       }
648     }
649   }
650 
651   return root;
652 }
653 
654 static sxml_node_t *
graft_fault_body(param)655 graft_fault_body(param)
656 	sxmlrpc_param_t *	param;
657 {
658   sxml_node_t *	root;
659 
660   root = sxml_new_vertex();
661   if (root != NULL) {
662     sxml_node_t *	mr;
663 
664     mr = sxml_new_element(root, "methodResponse");
665     if (mr != NULL) {
666       sxml_node_t *	fp;
667 
668       fp = sxml_new_element(mr, "fault");
669       if (fp != NULL) {
670 	make_new_value(fp, &param->value);
671       }
672     }
673   }
674 
675   return root;
676 }
677 
678 static int
make_response_head(sxRPC)679 make_response_head(sxRPC)
680 	sxmlrpc_t *	sxRPC;
681 {
682   sxRPC->msghdr_size = asprintf(&sxRPC->msghdr_text,
683 	"HTTP/1.0 200 OK" CRLF
684 	"Connection: close" CRLF
685 	"Content-Type: " SXMLRPC_CONTENT_TYPE CRLF
686 	"Content-Length: %d" CRLF
687 	"Server: " SXMLRPC_SERVER CRLF
688 	CRLF ,
689 	sxRPC->msgbdy_size);
690   return (sxRPC->msghdr_text != NULL) ? 0 : -1;
691 }
692 
693 
694 /*****************************************************************************/
695 
696 static int
send_message(sxRPC,nfd,nsd)697 send_message(sxRPC, nfd, nsd)
698 	sxmlrpc_t *	sxRPC;
699 	netfd_t *	nfd;
700 	netfd_t *	nsd;
701 {
702   int		status = -1;
703   ssize_t	n;
704 
705   n = netfd_write(nsd, sxRPC->msghdr_text, (size_t)sxRPC->msghdr_size);
706   if (n == (ssize_t)sxRPC->msghdr_size) {
707     off_t	sbytes;
708 
709     status = netfd_sendfile(nfd, nsd, 0, sxRPC->msgbdy_size, NULL, &sbytes, 0);
710   }
711   xfree(sxRPC->msghdr_text);
712 
713   return status;
714 }
715 
716 static sxml_node_t *
recv_message(sxRPC,nfd,nsd)717 recv_message(sxRPC, nfd, nsd)
718 	sxmlrpc_t *	sxRPC;
719 	netfd_t *	nfd;
720 	netfd_t *	nsd;
721 {
722   char		buf[BUFSIZ];
723   ssize_t	n;
724 
725   memset(buf, 0, sizeof(buf));
726   n = netfd_readline(nsd, buf, sizeof(buf));
727   if (n > 0) {
728     size_t	len = 0;	/* Content-Length */
729     size_t	l;
730 
731     if (parse_start_line(sxRPC, buf) == -1) {
732       return NULL;
733     }
734 
735     do {
736 #define	MAX_TOKEN	(2)
737       char **	ap;
738       char *	args[MAX_TOKEN];
739       char *	p;
740 
741       memset(buf, 0, sizeof(buf));
742       n = netfd_readline(nsd, buf, sizeof(buf));
743       if (n <= 0) {
744 	return NULL;
745       }
746       for (n = 0, p = buf, ap = args; (*ap = strsep(&p, ": \r\n")) != NULL; ) {
747 	if (**ap != EOL) {
748 	  n++;
749 	  if (++ap >= &args[MAX_TOKEN]) {
750 	    break;
751 	  }
752 	}
753       }
754       if (n == MAX_TOKEN) {
755 	if (strncmp(args[0], CONTENT_LENGTH, sizeof(CONTENT_LENGTH) - 1) == 0) {
756 	  len = (size_t)strtol(args[1], (char **)NULL, 10);
757 	}
758 	else if (strncmp(args[0], CONTENT_TYPE,
759 			 sizeof(CONTENT_TYPE) - 1) == 0) {
760 	  if (strncmp(args[1], SXMLRPC_CONTENT_TYPE,
761 		      sizeof(SXMLRPC_CONTENT_TYPE) - 1) != 0) {
762 	    return NULL;
763 	  }
764 	}
765       }
766     } while (buf[0] != EOL);
767 
768     for (n = 0, l = 0; l < len; l += n) {
769       memset(buf, 0, sizeof(buf));
770       n = netfd_read(nsd, buf, sizeof(buf));
771       if (n > 0) {
772 	if (netfd_write(nfd, buf, (size_t)n) != n) {
773 	  return NULL;
774 	}
775       }
776       else {
777 	return NULL;
778       }
779     }
780     netfd_seek(nfd, 0L, NETFD_SEEK_SET);
781 
782     return sxml_parse_file(nfd->osfd);
783   }
784 
785   return NULL;
786 }
787 
788 static int
parse_start_line(sxRPC,buf)789 parse_start_line(sxRPC, buf)
790 	sxmlrpc_t *	sxRPC;
791 	char *		buf;
792 {
793 #define	MAX_START_LINE_TOKEN	(3)
794   char **	ap;
795   char *	args[MAX_START_LINE_TOKEN];
796   char *	p;
797   int		n;
798 
799   for (n = 0, p = buf, ap = args; (*ap = strsep(&p, " \r\n")) != NULL; ) {
800     if (**ap != EOL) {
801       n++;
802       if (++ap >= &args[MAX_START_LINE_TOKEN]) {
803 	break;
804       }
805     }
806   }
807   if (n == MAX_START_LINE_TOKEN) {
808     switch (sxRPC->role) {
809       case SXMLRPC_ROLE_SERVER:
810 	return (strcmp(args[0], "POST") == 0) ? 0 : -1;
811       case SXMLRPC_ROLE_CLIENT:
812 	return (strcmp(args[1], "200") == 0) ? 0 : -1;
813       default:
814 	break;
815     }
816   }
817 
818   return -1;
819 }
820 
821 /*****************************************************************************/
822 
823 static int
make_new_value(node,value)824 make_new_value(node, value)
825 	sxml_node_t *		node;
826 	sxmlrpc_value_t *	value;
827 {
828   sxml_node_t *	ep;
829 
830   ep = sxml_new_element(node, "value");
831   if (ep != NULL) {
832     sxml_node_t *	np = NULL;
833     char *		s;
834 
835     switch (value->type) {
836       case SXMLRPC_VALUE_INTEGER:
837 	asprintf(&s, "%d", value->u.ival);
838 	if (s != NULL) {
839 	  np = sxml_set_node(ep, "int", s);
840 	  free(s);
841 	}
842 	break;
843       case SXMLRPC_VALUE_DOUBLE:
844 	asprintf(&s, "%f", value->u.dval);
845 	if (s != NULL) {
846 	  np = sxml_set_node(ep, "double", s);
847 	  free(s);
848 	}
849 	break;
850       case SXMLRPC_VALUE_BOOLEAN:
851 	asprintf(&s, "%d", value->u.bval);
852 	if (s != NULL) {
853 	  np = sxml_set_node(ep, "boolean", s);
854 	  free(s);
855 	}
856 	break;
857       case SXMLRPC_VALUE_STRING:
858 	np = sxml_set_node(ep, "string", value->u.sval);
859 	break;
860       case SXMLRPC_VALUE_DATETIME:
861 	np = sxml_set_node(ep, "dateTime.iso8601", value->u.sval);
862 	break;
863       case SXMLRPC_VALUE_BASE64:
864 	np = sxml_set_node(ep, "base64", value->u.sval);
865 	break;
866       case SXMLRPC_VALUE_STRUCT:
867 	np = sxml_new_element(ep, "struct");
868 	if (np != NULL) {
869 	  register size_t	i;
870 
871 	  for (i = 0; i < value->u.tval.size; i++) {
872 	    sxml_node_t *	mp;
873 
874 	    mp = sxml_new_element(np, "member");
875 	    if (mp != NULL) {
876 	      sxml_set_node(mp, "name", value->u.tval.member[i].name);
877 	      make_new_value(mp, &value->u.tval.member[i].value);
878 	    }
879 	  }
880 	}
881 	break;
882       case SXMLRPC_VALUE_ARRAY:
883 	np = sxml_new_element(ep, "array");
884 	if (np != NULL) {
885 	  sxml_node_t *	dp;
886 
887 	  dp = sxml_new_element(np, "data");
888 	  if (dp != NULL) {
889 	    register size_t	i;
890 
891 	    for (i = 0; i < value->u.aval.size; i++) {
892 	      make_new_value(dp, &value->u.aval.value[i]);
893 	    }
894 	  }
895 	}
896 	break;
897       default:
898 	break;
899     }
900     return np != NULL ? 0 : -1;
901   }
902 
903   return -1;
904 }
905 
906 static int
get_call_params(sxRPC,root)907 get_call_params(sxRPC, root)
908 	sxmlrpc_t *	sxRPC;
909 	sxml_node_t *	root;
910 {
911   register sxml_node_t *	np;
912 
913   sxRPC->role	 = SXMLRPC_ROLE_SERVER;
914   sxRPC->method  = SXMLRPC_METHOD_NONE;
915 
916   np = sxml_find_element(root, "methodCall", NULL, NULL);
917   if (np != NULL) {
918     for (np = np->child; np != NULL; np = np->next) {
919       const char *	content;
920 
921       if (np->type != SXML_ELEMENT)	{ continue; }
922       if (np->value.element.name == NULL)	{ continue; }
923 
924       content = sxml_get_content(np->child);
925       if (strcmp(np->value.element.name, "methodName") == 0) {
926 	sxRPC->call_method = strdup(content);
927       }
928       else if (strcmp(np->value.element.name, "params") == 0) {
929 	return set_call_params(sxRPC, np->child) > 0 ? 0 : -1;
930       }
931     }
932   }
933 
934   return -1;
935 }
936 
937 static size_t
set_call_params(sxRPC,node)938 set_call_params(sxRPC, node)
939 	sxmlrpc_t *	sxRPC;
940 	sxml_node_t *	node;
941 {
942   size_t	status;
943 
944   status = sxRPC->call_params.size = count_children(node);
945   if (sxRPC->call_params.size > 0) {
946     sxRPC->call_params.param
947 	= (sxmlrpc_param_t *)calloc(sxRPC->call_params.size,
948 				    sizeof(sxmlrpc_param_t));
949     if (sxRPC->call_params.param != NULL) {
950       register sxml_node_t *	np;
951       register size_t		i;
952 
953       for (np = node, i = 0; np != NULL && i < sxRPC->call_params.size;
954 	   np = np->next, i++) {
955 	if (np->child != NULL &&
956 	    strcmp(np->child->value.element.name, "value") == 0) {
957 	  set_value(&sxRPC->call_params.param[i].value, np->child->child);
958 	}
959       }
960     }
961   }
962 
963   return status;
964 }
965 
966 static sxml_node_t *
get_response_value(sxRPC,root)967 get_response_value(sxRPC, root)
968 	sxmlrpc_t *	sxRPC;
969 	sxml_node_t *	root;
970 {
971   register sxml_node_t *	np;
972 
973   np = sxml_find_element(root, "methodResponse", NULL, NULL);
974   if (np != NULL) {
975     np = np->child;
976     if (np != NULL) {
977       if (strcmp(np->value.element.name, "params") == 0) {
978 	np = np->child;
979 	if (np != NULL && strcmp(np->value.element.name, "param") == 0) {
980 	  np = np->child;
981 	  if (np != NULL && strcmp(np->value.element.name, "value") == 0) {
982 	    sxmlrpc_response_ok(sxRPC);
983 	    return np->child;
984 	  }
985 	}
986       }
987       else if (strcmp(np->value.element.name, "fault") == 0) {
988 	np = np->child;
989 	if (np != NULL && strcmp(np->value.element.name, "value") == 0) {
990 	  sxmlrpc_response_fault(sxRPC);
991 	  return np->child;
992 	}
993       }
994     }
995   }
996 
997   return NULL;
998 }
999 
1000 static int
set_value(v,node)1001 set_value(v, node)
1002 	sxmlrpc_value_t *	v;
1003 	sxml_node_t *		node;
1004 {
1005   register sxml_node_t *	np;
1006 
1007   for (np = node; np != NULL; np = np->next) {
1008     const char *	content;
1009 
1010     if (np->type != SXML_ELEMENT)	{ continue; }
1011     if (np->value.element.name == NULL)	{ continue; }
1012 
1013     content = sxml_get_content(np->child);
1014     if (strcmp(np->value.element.name, "i4") == 0 ||
1015 	strcmp(np->value.element.name, "int") == 0) {
1016       v->type	= SXMLRPC_VALUE_INTEGER;
1017       v->u.ival	= (sxmlrpc_int_t)strtol(content, (char **)NULL, 10);
1018     }
1019     else if (strcmp(np->value.element.name, "double") == 0) {
1020       v->type	= SXMLRPC_VALUE_DOUBLE;
1021       v->u.dval	= (sxmlrpc_double_t)strtod(content, (char **)NULL);
1022     }
1023     else if (strcmp(np->value.element.name, "boolean") == 0) {
1024       v->type	= SXMLRPC_VALUE_BOOLEAN;
1025       v->u.bval	= (sxmlrpc_boolean_t)strtol(content, (char **)NULL, 10);
1026     }
1027     else if (strcmp(np->value.element.name, "string") == 0) {
1028       v->type	= SXMLRPC_VALUE_STRING;
1029       v->u.sval	= (sxmlrpc_string_t)strdup(content);
1030     }
1031     else if (strcmp(np->value.element.name, "dateTime.iso8601") == 0) {
1032       v->type	= SXMLRPC_VALUE_DATETIME;
1033       v->u.sval	= (sxmlrpc_string_t)strdup(content);
1034     }
1035     else if (strcmp(np->value.element.name, "base64") == 0) {
1036       v->type	= SXMLRPC_VALUE_BASE64;
1037       v->u.sval	= (sxmlrpc_string_t)strdup(content);
1038     }
1039     else if (strcmp(np->value.element.name, "struct") == 0) {
1040       sxmlrpc_struct_t	tval;
1041 
1042       tval.size	= count_children(np->child);
1043       if (tval.size > 0) {
1044 	tval.member = (sxmlrpc_member_t *)calloc(tval.size,
1045 						 sizeof(sxmlrpc_member_t));
1046 	if (tval.member != NULL) {
1047 	  set_value_member(tval.member, np->child);
1048 	}
1049       }
1050       v->type	= SXMLRPC_VALUE_STRUCT;
1051       v->u.tval	= tval;
1052     }
1053     else if (strcmp(np->value.element.name, "array") == 0) {
1054       np = np->child;
1055       if (np != NULL && strcmp(np->value.element.name, "data") == 0) {
1056 	sxmlrpc_array_t	aval;
1057 
1058 	aval.size = count_children(np->child);
1059 	if (aval.size > 0) {
1060 	  aval.value = (sxmlrpc_value_t *)calloc(aval.size,
1061 						 sizeof(sxmlrpc_value_t));
1062 	  if (aval.value != NULL) {
1063 	    set_value_array(aval.value, np->child);
1064 	  }
1065 	}
1066 	v->type	  = SXMLRPC_VALUE_ARRAY;
1067 	v->u.aval = aval;
1068       }
1069     }
1070     else {
1071       return -1;	/* error */
1072     }
1073   }
1074 
1075   return 0;
1076 }
1077 
1078 static int
set_value_member(m,node)1079 set_value_member(m, node)
1080 	sxmlrpc_member_t *	m;
1081 	sxml_node_t *		node;
1082 {
1083   register sxml_node_t *	np;
1084   register int			i = 0;
1085 
1086   for (np = node; np != NULL; np = np->next) {
1087     if (np->type != SXML_ELEMENT)	{ continue; }
1088     if (np->value.element.name == NULL)	{ continue; }
1089 
1090     if (strcmp(np->value.element.name, "member") == 0) {
1091       register sxml_node_t *	mp;
1092 
1093       for (mp = np->child; mp != NULL; mp = mp->next) {
1094 	const char *	content;
1095 
1096 	content = sxml_get_content(mp->child);
1097 	if (strcmp(mp->value.element.name, "name") == 0 && content != NULL) {
1098 	  m[i].name = strdup(content);
1099 	}
1100 	else if (strcmp(mp->value.element.name, "value") == 0) {
1101 	  set_value(&m[i].value, mp->child);
1102 	}
1103       }
1104       i++;
1105     }
1106   }
1107 
1108   return 0;
1109 }
1110 
1111 static int
set_value_array(v,node)1112 set_value_array(v, node)
1113 	sxmlrpc_value_t *	v;
1114 	sxml_node_t *		node;
1115 {
1116   register sxml_node_t *	np;
1117   register int			i = 0;
1118 
1119   for (np = node; np != NULL; np = np->next) {
1120     if (np->type != SXML_ELEMENT)	{ continue; }
1121     if (np->value.element.name == NULL)	{ continue; }
1122 
1123     if (strcmp(np->value.element.name, "value") == 0) {
1124       set_value(&v[i], np->child);
1125       i++;
1126     }
1127   }
1128 
1129   return 0;
1130 }
1131 
1132 static size_t
count_children(node)1133 count_children(node)
1134 	sxml_node_t *	node;
1135 {
1136   register sxml_node_t *	np;
1137   register size_t		c;
1138 
1139   for (c = 0, np = node; np != NULL; np = np->next, c++) {
1140     ;	/* nothing to do */
1141   }
1142 
1143   return c;
1144 }
1145 
1146 /*****************************************************************************/
1147 
1148 int
sxmlrpc_set_value_int(value,ival)1149 sxmlrpc_set_value_int(value, ival)
1150 	sxmlrpc_value_t *	value;
1151 	sxmlrpc_int_t		ival;
1152 {
1153   if (value == NULL) {
1154     errno = EINVAL;
1155     return -1;
1156   }
1157 
1158   value->type	= SXMLRPC_VALUE_INTEGER;
1159   value->u.ival	= ival;
1160 
1161   return 0;
1162 }
1163 
1164 int
sxmlrpc_set_value_double(value,dval)1165 sxmlrpc_set_value_double(value, dval)
1166 	sxmlrpc_value_t *	value;
1167 	sxmlrpc_double_t	dval;
1168 {
1169   if (value == NULL) {
1170     errno = EINVAL;
1171     return -1;
1172   }
1173 
1174   value->type	= SXMLRPC_VALUE_DOUBLE;
1175   value->u.dval	= dval;
1176 
1177   return 0;
1178 }
1179 
1180 int
sxmlrpc_set_value_boolean(value,bval)1181 sxmlrpc_set_value_boolean(value, bval)
1182 	sxmlrpc_value_t *	value;
1183 	sxmlrpc_boolean_t	bval;
1184 {
1185   if (value == NULL) {
1186     errno = EINVAL;
1187     return -1;
1188   }
1189 
1190   value->type	= SXMLRPC_VALUE_BOOLEAN;
1191   value->u.bval	= bval;
1192 
1193   return 0;
1194 }
1195 
1196 int
sxmlrpc_set_value_string(value,sval)1197 sxmlrpc_set_value_string(value, sval)
1198 	sxmlrpc_value_t *	value;
1199 	sxmlrpc_string_t	sval;
1200 {
1201   if (value == NULL) {
1202     errno = EINVAL;
1203     return -1;
1204   }
1205 
1206   value->type	= SXMLRPC_VALUE_STRING;
1207   value->u.sval	= strdup(sval);
1208 
1209   return 0;
1210 }
1211 
1212 int
sxmlrpc_set_value_datetime(value,sval)1213 sxmlrpc_set_value_datetime(value, sval)
1214 	sxmlrpc_value_t *	value;
1215 	sxmlrpc_string_t	sval;
1216 {
1217   if (value == NULL) {
1218     errno = EINVAL;
1219     return -1;
1220   }
1221 
1222   value->type	= SXMLRPC_VALUE_DATETIME;
1223   value->u.sval	= strdup(sval);
1224 
1225   return 0;
1226 }
1227 
1228 int
sxmlrpc_set_value_base64(value,sval)1229 sxmlrpc_set_value_base64(value, sval)
1230 	sxmlrpc_value_t *	value;
1231 	sxmlrpc_string_t	sval;
1232 {
1233   if (value == NULL) {
1234     errno = EINVAL;
1235     return -1;
1236   }
1237 
1238   value->type	= SXMLRPC_VALUE_BASE64;
1239   value->u.sval	= strdup(sval);
1240 
1241   return 0;
1242 }
1243 
1244 int
sxmlrpc_set_value_struct(value,tval)1245 sxmlrpc_set_value_struct(value, tval)
1246 	sxmlrpc_value_t *	value;
1247 	sxmlrpc_struct_t	tval;
1248 {
1249   if (value == NULL) {
1250     errno = EINVAL;
1251     return -1;
1252   }
1253 
1254   value->type	= SXMLRPC_VALUE_STRUCT;
1255   value->u.tval	= tval;
1256 
1257   return 0;
1258 }
1259 
1260 int
sxmlrpc_set_value_array(value,aval)1261 sxmlrpc_set_value_array(value, aval)
1262 	sxmlrpc_value_t *	value;
1263 	sxmlrpc_array_t		aval;
1264 {
1265   if (value == NULL) {
1266     errno = EINVAL;
1267     return -1;
1268   }
1269 
1270   value->type	= SXMLRPC_VALUE_ARRAY;
1271   value->u.aval	= aval;
1272 
1273   return 0;
1274 }
1275 
1276 
1277 int
sxmlrpc_set_param(param,value)1278 sxmlrpc_set_param(param, value)
1279 	sxmlrpc_param_t *	param;
1280 	sxmlrpc_value_t		value;
1281 {
1282   if (param == NULL) {
1283     errno = EINVAL;
1284     return -1;
1285   }
1286 
1287   param->value = value;
1288 
1289   return 0;
1290 }
1291 
1292 int
sxmlrpc_set_fault(param,code,string)1293 sxmlrpc_set_fault(param, code, string)
1294 	sxmlrpc_param_t *	param;
1295 	int			code;
1296 	sxmlrpc_string_t	string;
1297 {
1298   sxmlrpc_member_t *	mval;
1299 
1300   mval = (sxmlrpc_member_t *)calloc(2, sizeof(sxmlrpc_member_t));
1301   if (mval != NULL) {
1302     mval[0].name = strdup("faultCode");
1303     sxmlrpc_set_value_int(&mval[0].value, code);
1304     mval[1].name = strdup("faultString");
1305     sxmlrpc_set_value_string(&mval[1].value, string);
1306     param->value.u.tval.size	= 2;
1307     param->value.u.tval.member	= mval;
1308   }
1309   else {
1310     param->value.u.tval.size	= 0;
1311     param->value.u.tval.member	= NULL;
1312   }
1313   param->value.type		= SXMLRPC_VALUE_STRUCT;
1314 
1315   return -1;	/* fixed value returns */
1316 }
1317 
1318 /*****************************************************************************/
1319 
1320 int
sxmlrpc_get_fault_code(sxRPC)1321 sxmlrpc_get_fault_code(sxRPC)
1322 	sxmlrpc_t *	sxRPC;
1323 {
1324   return (sxRPC->method == SXMLRPC_METHOD_RESPONSE_FAULT)
1325 	? sxRPC->fault_code
1326 	: 0;
1327 }
1328 
1329 sxmlrpc_string_t
sxmlrpc_get_fault_string(sxRPC)1330 sxmlrpc_get_fault_string(sxRPC)
1331 	sxmlrpc_t *	sxRPC;
1332 {
1333   return (sxRPC->method == SXMLRPC_METHOD_RESPONSE_FAULT)
1334 	? sxRPC->fault_string
1335 	: NULL;
1336 }
1337 
1338 sxmlrpc_value_t *
sxmlrpc_get_response_value(sxRPC)1339 sxmlrpc_get_response_value(sxRPC)
1340 	sxmlrpc_t *	sxRPC;
1341 {
1342   return (sxRPC->method == SXMLRPC_METHOD_RESPONSE)
1343 	? &sxRPC->response_value
1344 	: NULL;
1345 }
1346 
1347 void
sxmlrpc_print_value(v,fout)1348 sxmlrpc_print_value(v, fout)
1349 	sxmlrpc_value_t *	v;
1350 	register FILE *		fout;
1351 {
1352   switch (sxmlrpc_get_value_type(v)) {
1353     case SXMLRPC_VALUE_INTEGER:
1354       fprintf(fout, "%d\n", sxmlrpc_get_value_int(v));
1355       break;
1356     case SXMLRPC_VALUE_DOUBLE:
1357       fprintf(fout, "%f\n", sxmlrpc_get_value_double(v));
1358       break;
1359     case SXMLRPC_VALUE_BOOLEAN:
1360       fprintf(fout, "%d\n", sxmlrpc_get_value_boolean(v));
1361       break;
1362     case SXMLRPC_VALUE_STRING:
1363       fprintf(fout, "%s\n", sxmlrpc_get_value_string(v));
1364       break;
1365     case SXMLRPC_VALUE_DATETIME:
1366       fprintf(fout, "%s\n", sxmlrpc_get_value_datetime(v));
1367       break;
1368     case SXMLRPC_VALUE_BASE64:
1369       fprintf(fout, "%s\n", sxmlrpc_get_value_base64(v));
1370       break;
1371     case SXMLRPC_VALUE_STRUCT: {
1372 	sxmlrpc_member_t *	mval;
1373 	register size_t		i;
1374 
1375 	mval = sxmlrpc_get_struct_member(v);
1376 	for (i = 0; i < sxmlrpc_get_struct_size(v); i++) {
1377 	  fprintf(fout, "%s:\t", mval[i].name);
1378 	  sxmlrpc_print_value(&mval[i].value, fout);
1379 	}
1380       }
1381       break;
1382     case SXMLRPC_VALUE_ARRAY: {
1383 	sxmlrpc_value_t *	val;
1384 	register size_t		i;
1385 
1386 	val = sxmlrpc_get_array_value(v);
1387 	for (i = 0; i < sxmlrpc_get_array_size(v); i++) {
1388 	  sxmlrpc_print_value(&val[i], fout);
1389 	}
1390       }
1391     default:
1392       break;
1393   }
1394 }
1395 
1396 void
sxmlrpc_copy_value(dst,src)1397 sxmlrpc_copy_value(dst, src)
1398 	sxmlrpc_value_t *	dst;
1399 	sxmlrpc_value_t *	src;
1400 {
1401   dst->type = src->type;
1402   switch (src->type) {
1403     case SXMLRPC_VALUE_INTEGER:
1404       dst->u.ival = src->u.ival;
1405       break;
1406     case SXMLRPC_VALUE_DOUBLE:
1407       dst->u.dval = src->u.dval;
1408       break;
1409     case SXMLRPC_VALUE_BOOLEAN:
1410       dst->u.bval = src->u.bval;
1411       break;
1412     case SXMLRPC_VALUE_STRING:
1413     case SXMLRPC_VALUE_DATETIME:
1414     case SXMLRPC_VALUE_BASE64:
1415       dst->u.sval = strdup(src->u.sval);
1416       break;
1417     case SXMLRPC_VALUE_STRUCT:
1418       dst->u.tval.size = src->u.tval.size;
1419       dst->u.tval.member = (sxmlrpc_member_t *)calloc(src->u.tval.size,
1420 						      sizeof(sxmlrpc_member_t));
1421       if (dst->u.tval.member != NULL) {
1422 	register size_t	i;
1423 
1424 	for (i = 0; i < src->u.tval.size; i++) {
1425 	  dst->u.tval.member[i].name = strdup(src->u.tval.member[i].name);
1426   	  sxmlrpc_copy_value(&dst->u.tval.member[i].value,
1427  			     &src->u.tval.member[i].value);
1428   	}
1429       }
1430       break;
1431     case SXMLRPC_VALUE_ARRAY:
1432       dst->u.aval.size = src->u.aval.size;
1433       dst->u.aval.value = (sxmlrpc_value_t *)calloc(src->u.tval.size,
1434 						    sizeof(sxmlrpc_value_t));
1435       if (dst->u.aval.value != NULL) {
1436 	register size_t	i;
1437 
1438 	for (i = 0; i < src->u.aval.size; i++) {
1439   	  sxmlrpc_copy_value(&dst->u.aval.value[i], &src->u.aval.value[i]);
1440    	}
1441       }
1442       break;
1443     default:
1444       break;
1445   }
1446 }
1447 
1448 /*****************************************************************************/
1449 
1450 static netfd_t *
netfd_open(path,flags,mode)1451 netfd_open(path, flags, mode)
1452 	const char *	path;
1453 	int		flags;
1454 	mode_t		mode;
1455 {
1456   int		fd;
1457   netfd_t *	newfd;
1458 
1459   while ((fd = open(path, flags, mode)) < 0) {
1460     if (errno != EINTR) {
1461       return NULL;
1462     }
1463   }
1464 
1465   newfd = netfd_new(fd);
1466   if (newfd == NULL) {
1467     my_close(fd);
1468   }
1469 
1470   return newfd;
1471 }
1472 
1473 static netfd_t *
netfd_fdopen(osfd)1474 netfd_fdopen(osfd)
1475 	int	osfd;
1476 {
1477   return (osfd > 0) ? netfd_new(osfd) : NULL;
1478 }
1479 
1480 static netfd_t *
netfd_new(osfd)1481 netfd_new(osfd)
1482 	int	osfd;
1483 {
1484   netfd_t *	nfd;
1485 
1486   nfd = (netfd_t *)malloc(sizeof(netfd_t));
1487   if (nfd != NULL) {
1488     nfd->osfd	     = osfd;
1489     nfd->rb.total    = 0;
1490     nfd->rb.bufp     = nfd->rb.buf;
1491     memset(nfd->rb.buf, 0, sizeof(nfd->rb.buf));
1492   }
1493 
1494   return nfd;
1495 }
1496 
1497 static int
netfd_close(nfd)1498 netfd_close(nfd)
1499 	register netfd_t *	nfd;
1500 {
1501   int	status = -1;
1502 
1503   if (nfd == NULL) {
1504     errno  = EINVAL;
1505   }
1506   else {
1507     status = my_close(nfd->osfd);
1508     free(nfd);
1509   }
1510 
1511   return status;
1512 }
1513 
1514 static off_t
netfd_seek(nfd,offset,whence)1515 netfd_seek(nfd, offset, whence)
1516 	register netfd_t *	nfd;
1517 	off_t			offset;
1518 	int			whence;
1519 {
1520   struct stat	sbuf;
1521 
1522   if (fstat(nfd->osfd, &sbuf) == 0 && S_ISREG(sbuf.st_mode)) {
1523     off_t	pos;
1524 
1525     pos = lseek(nfd->osfd, offset, whence);
1526     if (pos != -1) {
1527       return pos;
1528     }
1529     errno = EINVAL;
1530   }
1531 
1532   return -1;
1533 }
1534 
1535 static ssize_t
netfd_read(nfd,buf,nbytes)1536 netfd_read(nfd, buf, nbytes)
1537 	netfd_t *	nfd;
1538 	void *		buf;
1539 	size_t		nbytes;
1540 {
1541   register ssize_t	n   = 0;
1542   register char *	ptr = (char *)buf;
1543 
1544   do {
1545     if (netfd_readbuf(nfd) < 0)	{ return -1; }
1546     if (nfd->rb.total == 0)	{ break; }
1547     *ptr++ = *nfd->rb.bufp++;
1548     nfd->rb.total--;
1549   } while ((size_t)n++ < nbytes && nfd->rb.total > 0);
1550 
1551   return n;
1552 }
1553 
1554 static ssize_t
netfd_write(nfd,buf,nbyte)1555 netfd_write(nfd, buf, nbyte)
1556 	netfd_t *	nfd;
1557 	const void *	buf;
1558 	size_t		nbyte;
1559 {
1560   size_t	resid = nbyte;
1561   ssize_t	n;
1562 
1563   while (resid > 0) {
1564     n = write(nfd->osfd, buf, resid);
1565     if (n == -1) {
1566       if (errno == EINTR) { continue; }
1567       return -1;
1568     }
1569     else {
1570       resid -= n;
1571       if (resid == 0) { break; }
1572       buf = (const void *)((const char *)buf + n);
1573     }
1574   }
1575 
1576   return (ssize_t)(nbyte - resid);
1577 }
1578 
1579 static ssize_t
netfd_readline(nfd,buf,maxlen)1580 netfd_readline(nfd, buf, maxlen)
1581 	netfd_t *	nfd;
1582 	void *		buf;
1583 	size_t		maxlen;
1584 {
1585   register ssize_t	n;
1586   register char *	ptr = (char *)buf;
1587 
1588   for (n = 1; (size_t)n < maxlen; n++) {
1589     char	c;
1590     int		status;
1591 
1592     status = one_read(nfd, &c);
1593     if (status == 1) {
1594       *ptr++ = c;
1595       if (c == LF)  { break; }
1596       if (c == EOL) { return 0; }	/* EOF?, null data read */
1597     }
1598     else if (status == 0) {
1599       if (n == 1) { return 0; }		/* EOF, no data read */
1600       else	  { break; }		/* EOF, some data was read */
1601     }
1602     else {
1603       return -1;			/* error */
1604     }
1605   }
1606   *ptr = EOL;
1607 
1608   return n;
1609 }
1610 
1611 static ssize_t
one_read(nfd,ptr)1612 one_read(nfd, ptr)
1613 	netfd_t *	nfd;
1614 	char *		ptr;
1615 {
1616   if (netfd_readbuf(nfd) < 0) { return -1; }
1617   if (nfd->rb.total == 0)     { return  0; }
1618   nfd->rb.total--;
1619   *ptr = *nfd->rb.bufp++;
1620 
1621   return 1;
1622 }
1623 
1624 static int
netfd_readbuf(nfd)1625 netfd_readbuf(nfd)
1626 	netfd_t *	nfd;
1627 {
1628   if (nfd->rb.total <= 0) {
1629     memset(nfd->rb.buf, 0, sizeof(nfd->rb.buf));
1630     errno = 0;
1631     while ((nfd->rb.total = read(nfd->osfd,
1632 				 nfd->rb.buf, sizeof(nfd->rb.buf))) < 0) {
1633       if (errno == EINTR) { continue; }
1634       return -1;
1635     }
1636     nfd->rb.bufp = nfd->rb.buf;
1637   }
1638 
1639   return nfd->rb.total;
1640 }
1641 
1642 static netfd_t *
netfd_mkstemp(template)1643 netfd_mkstemp(template)
1644 	char *	template;
1645 {
1646   int	fd;
1647 
1648   fd = mkstemp(template);
1649   return (fd == -1) ? NULL : netfd_new(fd);
1650 }
1651 
1652 
1653 #if	HAVE_FREEBSD_SENDFILE
1654 static int
netfd_sendfile(nfd,nsd,init_offset,nbytes,hdtr,ret_sbytes,flags)1655 netfd_sendfile(nfd, nsd, init_offset, nbytes, hdtr, ret_sbytes, flags)
1656 	netfd_t *		nfd;
1657 	netfd_t *		nsd;
1658 	off_t			init_offset;
1659 	size_t			nbytes;
1660 	struct sf_hdtr *	hdtr;
1661 	off_t *			ret_sbytes;
1662 	int			flags;
1663 {
1664   off_t	offset;
1665   off_t	sbytes;
1666 
1667   offset = init_offset;
1668   while (sendfile(nfd->osfd, nsd->osfd, offset, nbytes, hdtr, &sbytes,
1669 		  flags) < 0) {
1670     offset += sbytes;
1671     nbytes -= sbytes;
1672     if (errno == EINTR) { continue; }
1673     return -1;
1674   }
1675   if (ret_sbytes != NULL) {
1676     *ret_sbytes = offset + sbytes;
1677   }
1678 
1679   return 0;
1680 }
1681 #else
1682 #if	HAVE_LINUX_SENDFILE
1683 /*
1684  * I have no linux environments. Is this routine ok?
1685  */
1686 static int
netfd_sendfile(nfd,nsd,init_offset,nbytes,hdtr,ret_sbytes,flags)1687 netfd_sendfile(nfd, nsd, init_offset, nbytes, hdtr, ret_sbytes, flags)
1688 	netfd_t *	nfd;
1689 	netfd_t *	nsd;
1690 	off_t		init_offset;
1691 	size_t		nbytes;
1692 	void *		hdtr;
1693 	off_t *		ret_sbytes;
1694 	int		flags;
1695 {
1696   off_t	offset;
1697   off_t	sbytes;
1698 
1699   offset = init_offset;
1700   while (sendfile(nfd->osfd, nsd->osfd, &sbytes, nbytes) < 0) {
1701     offset += sbytes;
1702     nbytes -= sbytes;
1703     if (errno == EINTR) { continue; }
1704     return -1;
1705   }
1706   if (ret_sbytes != NULL) {
1707     *ret_sbytes = offset + sbytes;
1708   }
1709 
1710   return 0;
1711 }
1712 #else	/* No sendfile(2) */
1713 static int
netfd_sendfile(nfd,nsd,offset,nbytes,hdtr,sbytes,flags)1714 netfd_sendfile(nfd, nsd, offset, nbytes, hdtr, sbytes, flags)
1715 	netfd_t *	nfd;
1716 	netfd_t *	nsd;
1717 	off_t		offset;
1718 	size_t		nbytes;
1719 	void *		hdtr;	// unused
1720 	off_t *		sbytes;
1721 	int		flags;	// unused
1722 {
1723   void *	buf;
1724   size_t	len;
1725   ssize_t	n;
1726   int		status = 0;
1727 
1728   if (nbytes == 0) {
1729     off_t	off;
1730     /* get whole file size */
1731     off = netfd_seek(nfd, 0, NETFD_SEEK_END);
1732     if (off == -1) {
1733       return -1;
1734     }
1735     len = (size_t)off;
1736   }
1737   else {
1738     len = nbytes;
1739   }
1740   buf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, nfd->osfd, offset);
1741   if (buf == MAP_FAILED) {
1742     return -1;
1743   }
1744   n = netfd_write(nsd, buf, len);
1745   if (n == -1) {
1746     status = -1;
1747   }
1748   if (sbytes != NULL) {
1749     *sbytes = (size_t)n;
1750   }
1751   munmap(buf, len);
1752 
1753   return status;
1754 }
1755 #endif	/* HAVE_LINUX_SENDFILE */
1756 #endif	/* HAVE_FREEBSD_SENDFILE */
1757 
1758 static void
sigalrm(signo)1759 sigalrm(signo)
1760 	int	signo;	// unused
1761 {
1762   timedout = 1;	/* set flag */
1763 }
1764 
1765 static netfd_t *
netfd_tcp_client(hostname,service)1766 netfd_tcp_client(hostname, service)
1767 	const char *	hostname;
1768 	const char *	service;
1769 {
1770   struct addrinfo	hints;
1771   struct addrinfo *	res;
1772 
1773   memset((char *)&hints, 0, sizeof(hints));
1774   hints.ai_family	= AF_UNSPEC;
1775   hints.ai_socktype	= SOCK_STREAM;
1776   hints.ai_protocol	= IPPROTO_TCP;
1777   hints.ai_flags	= 0;
1778 
1779   if (getaddrinfo(hostname, service, &hints, &res) == 0) {
1780     struct itimerval	value;	/* new */
1781     struct itimerval	ovalue;	/* old */
1782     struct sigaction	act;	/* new */
1783     struct sigaction	oact;	/* old */
1784     struct addrinfo *	res_save;
1785     int			sd;
1786 
1787 #define	DEF_CONNECT_TIMEOUT	(10000)	/* msec */
1788     sigemptyset(&act.sa_mask);
1789     act.sa_flags	= 0;
1790     act.sa_handler	= (void *)sigalrm;
1791     sigaction(SIGALRM, &act, &oact);
1792     value.it_interval.tv_sec = value.it_interval.tv_usec = 0;
1793     value.it_value.tv_sec  = DEF_CONNECT_TIMEOUT / 1000;
1794     value.it_value.tv_usec = (DEF_CONNECT_TIMEOUT % 1000) * 1000;
1795     setitimer(ITIMER_REAL, &value, &ovalue);
1796     timedout = 0;	/* clear flag */
1797 
1798     res_save = res;
1799     do {
1800       errno = 0;
1801       /* create a socket */
1802       sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1803       if (sd == -1) {
1804 	continue;	/*ignore this one */
1805       }
1806       /* initiate a connection on a socket */
1807       if (connect(sd, res->ai_addr, res->ai_addrlen) == 0) {
1808 	break;
1809       }
1810       if (errno == EINTR) {
1811 	if (timedout) { errno = ETIMEDOUT; }
1812       }
1813       my_close(sd);	/* ignore this one */
1814     } while ((res = res->ai_next) != NULL && errno == 0);
1815     freeaddrinfo(res_save);
1816     sigaction(SIGALRM, &oact, NULL);
1817     setitimer(ITIMER_REAL, &ovalue, NULL);
1818 
1819     if (res != NULL) {
1820       netfd_t *	nfd;
1821 
1822       nfd = netfd_fdopen(sd);
1823       if (nfd != NULL) {
1824 	return nfd;
1825       }
1826       my_close(sd);
1827     }
1828   }
1829 
1830   return NULL;
1831 }
1832 
1833 static netfd_t *
netfd_tcp_server(hostname,service,backlog)1834 netfd_tcp_server(hostname, service, backlog)
1835 	const char *	hostname;
1836 	const char *	service;
1837 	const int	backlog;
1838 {
1839   struct addrinfo	hints;
1840   struct addrinfo *	res;
1841 
1842   memset((char *)&hints, 0, sizeof(hints));
1843   hints.ai_family	= AF_UNSPEC;
1844   hints.ai_socktype	= SOCK_STREAM;
1845   hints.ai_protocol	= IPPROTO_TCP;
1846   hints.ai_flags	= AI_PASSIVE;
1847 
1848   if (getaddrinfo(hostname, service, &hints, &res) == 0) {
1849     struct addrinfo *	res_save;
1850     int			sd;
1851 
1852     res_save = res;
1853     do {
1854       static const int	on = 1;
1855 
1856       /* create a socket */
1857       sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
1858       if (sd < 0) {
1859 	continue;	/*error, try next one */
1860       }
1861       /* allow reuse of local address */
1862       (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
1863       /* bind a socket */
1864       if (bind(sd, res->ai_addr, res->ai_addrlen) == 0) {
1865 	break;	/* success */
1866       }
1867       my_close(sd);	/* bind error, close and try next one */
1868     } while ((res = res->ai_next) != NULL);
1869     freeaddrinfo(res_save);
1870 
1871     if (res != NULL) {
1872       /* listen for connection on the socket */
1873       if (listen(sd, backlog > 0 ? backlog : NETFD_DEF_BACKLOG) == 0) {
1874 	netfd_t *	nfd;
1875 
1876 	nfd = netfd_fdopen(sd);
1877 	if (nfd != NULL) {
1878 	  return nfd;
1879 	}
1880 	my_close(sd);
1881       }
1882     }
1883   }
1884 
1885   return NULL;
1886 }
1887 
1888 static netfd_t *
netfd_accept(nfd,addr,addrlen)1889 netfd_accept(nfd, addr, addrlen)
1890 	netfd_t *		nfd;
1891 	struct sockaddr *	addr;
1892 	socklen_t *		addrlen;
1893 {
1894   int		sd;
1895   netfd_t *	newfd;
1896 
1897 #if	0
1898   while ((sd = accept(nfd->osfd, addr, (socklen_t *)addrlen)) < 0) {
1899     if (errno == EINTR) {
1900       continue;
1901     }
1902     return NULL;
1903   }
1904 #else
1905   if ((sd = accept(nfd->osfd, addr, addrlen)) < 0) {
1906     return NULL;
1907   }
1908 #endif
1909 
1910   newfd = netfd_fdopen(sd);
1911   if (newfd == NULL) {
1912     my_close(sd);
1913   }
1914 
1915   return newfd;
1916 }
1917 
1918 static int
netfd_sock_ntop(sa0,ipaddr)1919 netfd_sock_ntop(sa0, ipaddr)
1920 	const struct sockaddr *	sa0;
1921 	char **			ipaddr;
1922 {
1923   static char	host[132];	/* Unix domain is largest */
1924   int		status = -1;
1925 
1926   memset(host, 0, sizeof(host));
1927   switch (sa0->sa_family) {
1928     case AF_INET: {
1929 	struct sockaddr_in *	sa = (struct sockaddr_in *)sa0;
1930 
1931 	if (inet_ntop(AF_INET, &sa->sin_addr, host, sizeof(host)) != NULL) {
1932 	  status = 0;
1933 	}
1934       }
1935       break;
1936     case AF_INET6: {
1937 	struct sockaddr_in6 *	sa = (struct sockaddr_in6 *)sa0;
1938 
1939 	if (inet_ntop(AF_INET6, &sa->sin6_addr, host, sizeof(host)) != NULL) {
1940 	  status = 0;
1941 	}
1942       }
1943       break;
1944     default:
1945       break;
1946   }
1947 
1948   if (ipaddr != NULL) {
1949     if (status == 0) {
1950       *ipaddr = strdup(host);
1951     }
1952     else {
1953       *ipaddr = NULL;
1954     }
1955   }
1956 
1957   return status;
1958 }
1959 
1960 static int
my_close(fd)1961 my_close(fd)
1962 	int	fd;
1963 {
1964   int	status;
1965   int	saved_errno = errno;
1966   while (((status = close(fd)) < 0) && (errno == EINTR)) { continue; }
1967   errno = saved_errno;
1968   return status;
1969 }
1970 
1971 /*****************************************************************************/
1972 
1973 const char *
sxmlrpc_get_datetime_iso8601(t)1974 sxmlrpc_get_datetime_iso8601(t)
1975 	const time_t	t;
1976 {
1977   static char	iso8601[sizeof("20060401T16:55:31")];
1978   struct tm *	tp;
1979 
1980   tp = localtime(&t);
1981   if (tp == NULL) {
1982     return NULL;
1983   }
1984   memset(iso8601, 0, sizeof(iso8601));
1985   snprintf(iso8601, sizeof(iso8601), "%04d%02d%02dT%02d:%02d:%02d",
1986 	   tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday,
1987 	   tp->tm_hour, tp->tm_min, tp->tm_sec);
1988 
1989   return iso8601;
1990 }
1991 
1992 const char *
sxmlrpc_get_current_datetime_iso8601(void)1993 sxmlrpc_get_current_datetime_iso8601(void)
1994 {
1995   time_t	now;
1996 
1997   time(&now);
1998 
1999   return sxmlrpc_get_datetime_iso8601(now);
2000 }
2001 
2002 /*
2003  * bit sequence for mask
2004  *
2005  * 0xfc = 11111100
2006  * 0x03 = 00000011
2007  * 0xf0 = 11110000
2008  * 0x0f = 00001111
2009  * 0xc0 = 11000000
2010  * 0x3f = 00111111
2011  * 0x30 = 00110000
2012  * 0x3c = 00111100
2013  */
2014 
2015 /*
2016  * Base64 alphabet
2017  */
2018 static const char	base64[] =
2019 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
2020 
2021 int
sxmlrpc_base64_encode(str,rbuf,rsize)2022 sxmlrpc_base64_encode(str, rbuf, rsize)
2023 	const char *	str;
2024 	char *		rbuf;	/* return base64 encoded string */
2025 	size_t		rsize;	/* return buffer size */
2026 {
2027   size_t	len;
2028   register int	i;
2029   register int	n;
2030 
2031   len = strlen(str);
2032   if (rsize < (size_t)((double)len * 1.33) + 1) {
2033     return -1;
2034   }
2035 
2036   /*
2037    * encode 3-bytes (24-bits) at a time
2038    */
2039   memset(rbuf, 0, rsize);
2040   for (i = n = 0; i < len - (len % 3); i += 3, n += 4) {
2041     rbuf[n]   = base64[( str[i]	  & 0xfc) >> 2];
2042     rbuf[n+1] = base64[((str[i]   & 0x03) << 4) | ((str[i+1] & 0xf0) >> 4)];
2043     rbuf[n+2] = base64[((str[i+1] & 0x0f) << 2) | ((str[i+2] & 0xc0) >> 6)];
2044     rbuf[n+3] = base64[( str[i+2] & 0x3f)];
2045   }
2046 
2047   i = len - (len % 3);	/* rest size */
2048   switch (len % 3) {
2049     case 2:	/* one character padding */
2050       rbuf[n]	= base64[( str[i]   & 0xfc) >> 2];
2051       rbuf[n+1] = base64[((str[i]   & 0x03) << 4) | ((str[i+1] & 0xf0) >> 4)];
2052       rbuf[n+2] = base64[( str[i+1] & 0x0f) << 2];
2053       rbuf[n+3] = base64[64];	/* Pad	*/
2054       n += 4;
2055       break;
2056     case 1:	/* two character padding */
2057       rbuf[n]	= base64[(str[i] & 0xfc) >> 2];
2058       rbuf[n+1]	= base64[(str[i] & 0x03) << 4];
2059       rbuf[n+2] = base64[64];	/* Pad	*/
2060       rbuf[n+3] = base64[64];	/* Pad	*/
2061       n += 4;
2062       break;
2063     default:
2064       break;
2065   }
2066   rbuf[n] = '\0';
2067 
2068   return n;
2069 }
2070 
2071 int
sxmlrpc_base64_decode(str,rbuf,rsize)2072 sxmlrpc_base64_decode(str, rbuf, rsize)
2073 	const char *	str;
2074 	char *		rbuf;	/* return base64 decoded string */
2075 	size_t		rsize;	/* return buffer size */
2076 {
2077 #define	VAL(x)	(str[(x)] == '=' ? 0 : strchr(base64, str[(x)]) - base64)
2078   size_t	len;
2079   register int	i;
2080   register int	n;
2081 
2082   len = strlen(str);
2083   if (rsize < (size_t)((double)len * 0.75) + 1) {
2084     return -1;
2085   }
2086 
2087   /*
2088    * work on 4-words (24-bits) at a time
2089    */
2090   memset(rbuf, 0, rsize);
2091   for (i = n = 0; i < len; i += 4, n += 3) {
2092     rbuf[n]   =  (VAL(i) << 2)		 | ((VAL(i+1) & 0x30) >> 4);
2093     rbuf[n+1] = ((VAL(i+1) & 0x0f) << 4) | ((VAL(i+2) & 0x3c) >> 2);
2094     rbuf[n+2] = ((VAL(i+2) & 0x03) << 6) |  (VAL(i+3) & 0x3f);
2095   }
2096   /* remove padding data */
2097   if (str[len - 1] == '=') { n--; }
2098   if (str[len - 2] == '=') { n--; }
2099 
2100   return n;
2101 }
2102 
2103 /*****************************************************************************/
2104 
2105 int
sxmlrpc_get_call_params(sxRPC,infd)2106 sxmlrpc_get_call_params(sxRPC, infd)
2107 	sxmlrpc_t *	sxRPC;
2108 	int		infd;
2109 {
2110   sxml_node_t *	root;
2111   int		status = -1;
2112 
2113   root = sxml_parse_file(infd);
2114   if (root != NULL) {
2115     status = get_call_params(sxRPC, root);
2116     sxml_delete_node(root);
2117   }
2118 
2119   return status;
2120 }
2121 
2122 int
sxmlrpc_set_response_param(sxRPC,param,outfd)2123 sxmlrpc_set_response_param(sxRPC, param, outfd)
2124 	sxmlrpc_t *		sxRPC;
2125 	sxmlrpc_param_t *	param;
2126 	int			outfd;
2127 {
2128   int	stkfd;
2129   int	status;
2130 
2131   stkfd = sxRPC->msgbdy_fd;
2132   sxRPC->msgbdy_fd = outfd;
2133   status = make_response_body(sxRPC, param);
2134   sxRPC->msgbdy_fd = stkfd;
2135 
2136   return status;
2137 }
2138 
2139 void
sxmlrpc_set_encoding(sxRPC,ctype)2140 sxmlrpc_set_encoding(sxRPC, ctype)
2141 	sxmlrpc_t *	sxRPC;
2142 	const char *	ctype;
2143 {
2144   sxRPC->encoding = strdup(ctype);
2145 }
2146