lib/binrpc: memset addr variable to avoind uninitialized fields
[sip-router] / lib / binrpc / binrpc_api.c
1 /*
2  * Copyright (C) 2006 iptelorg GmbH
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 /**
22  * send commands using binrpc
23  *
24  */
25
26 #include <sys/types.h>
27 #include <sys/uio.h>
28 #include <stdlib.h> /* realloc, rand ... */
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <ctype.h> /* isprint */
33 #include <time.h> /* time */
34 /* #include <stropts.h>  - is this really needed? --andrei */
35
36 #include "../../modules/ctl/ctl_defaults.h" /* default socket & port */
37 #include "../../modules/ctl/init_socks.h"
38 #include "../../modules/ctl/binrpc.c" /* ugly hack */
39
40 #include "binrpc_api.h"
41
42
43 #define IOVEC_CNT 20
44 #define TEXT_BUFF_ALLOC_CHUNK   4096
45 #define FATAL_ERROR       -1
46
47 #ifndef NAME
48 #define NAME    "binrpc_api"
49 #endif
50
51 #define binrpc_malloc internal_malloc
52 #define binrpc_realloc internal_realloc
53 #define binrpc_free internal_free
54
55 #ifndef UNIX_PATH_MAX
56 #define UNIX_PATH_MAX 104
57 #endif
58
59 #ifndef INT2STR_MAX_LEN
60 #define INT2STR_MAX_LEN  (19+1+1) /* 2^64~= 16*10^18 => 19+1 digits + \0 */
61 #endif
62
63 static void* (*internal_malloc)(size_t size) = malloc;
64 static void* (*internal_realloc)(void* ptr, size_t size) = realloc;
65 static void (*internal_free)(void* ptr) = free;
66
67 static char binrpc_last_errs[1024] = "";
68 static int verbose = 0;
69
70 char *binrpc_get_last_errs()
71 {
72     return binrpc_last_errs;
73 }
74
75 void binrpc_clear_last_err()
76 {
77     binrpc_last_errs[0] = '\0';
78 }
79
80 void binrpc_set_mallocs(void* _malloc, void* _realloc, void* _free)
81 {
82     internal_malloc = _malloc;
83     internal_realloc = _realloc;
84     internal_free = _free;
85 }
86
87 static int gen_cookie()
88 {
89         return rand();
90 }
91
92 static void hexdump(unsigned char* buf, int len, int ascii)
93 {
94         int r, i;
95         
96         /* dump it in hex */
97         for (r=0; r<len; r++){
98                 if ((r) && ((r%16)==0)){
99                         if (ascii){
100                                 putchar(' ');
101                                 for (i=r-16; i<r; i++){
102                                         if (isprint(buf[i]))
103                                                 putchar(buf[i]);
104                                         else
105                                                 putchar('.');
106                                 }
107                         }
108                         putchar('\n');
109                 }
110                 printf("%02x ", buf[r]);
111         };
112         if (ascii){
113                 for (i=r;i%16; i++)
114                         printf("   ");
115                 putchar(' ');
116                 for (i=16*(r/16); i<r; i++){
117                         if (isprint(buf[i]))
118                                 putchar(buf[i]);
119                         else
120                                 putchar('.');
121                 }
122         }
123         putchar('\n');
124 }
125
126 /* opens,  and  connects on a STREAM unix socket
127  * returns socket fd or -1 on error */
128 static int connect_unix_sock(char* name, int type, struct sockaddr_un* mysun,
129                       char* reply_socket, char* sock_dir)
130 {
131         struct sockaddr_un ifsun;
132         int s;
133         int len;
134         int ret;
135         int retries;    
136         
137         retries=0;
138         s=-1;
139         memset(&ifsun, 0, sizeof (struct sockaddr_un));
140         len=strlen(name);
141         if (len>UNIX_PATH_MAX){
142                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
143                                 "connect_unix_sock: name too long "
144                                 "(%d > %d): %s", len, UNIX_PATH_MAX, name);
145                 goto error;
146         }
147         ifsun.sun_family=AF_UNIX;
148         memcpy(ifsun.sun_path, name, len);
149 #ifdef HAVE_SOCKADDR_SA_LEN
150         ifsun.sun_len=len;
151 #endif
152         s=socket(PF_UNIX, type, 0);
153         if (s==-1){
154                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
155                         "connect_unix_sock: cannot create unix socket"
156                         " %s: %s [%d]", 
157                         name, strerror(errno), errno);
158                 goto error;
159         }
160         if (type==SOCK_DGRAM){
161                 /* we must bind so that we can receive replies */
162                 if (reply_socket==0){
163                         if (sock_dir==0)
164                                 sock_dir="/tmp";
165 retry:
166                         ret=snprintf(mysun->sun_path, UNIX_PATH_MAX, "%s/" NAME "_%d",
167                                                         sock_dir, rand()); 
168                         if ((ret<0) ||(ret>=UNIX_PATH_MAX)){
169                                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
170                                                         "connect_unix_sock: buffer overflow while trying to"
171                                                         "generate unix datagram socket name");
172                                 goto error;
173                         }
174                 }else{
175                         if (strlen(reply_socket)>UNIX_PATH_MAX){
176                                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
177                                                         "connect_unix_sock: buffer overflow while trying to"
178                                                         "use the provided unix datagram socket name (%s)",
179                                                         reply_socket);
180                                 goto error;
181                         }
182                         strcpy(mysun->sun_path, reply_socket);
183                 }
184                 mysun->sun_family=AF_UNIX;
185                 if (bind(s, (struct sockaddr*)&mysun, sizeof(struct sockaddr_un))==-1){
186                 //if (bind(s, mysun, sizeof(mysun))==-1){
187                         if (errno==EADDRINUSE && (reply_socket==0) && (retries < 10)){
188                                 retries++;
189                                 /* try another one */
190                                 goto retry;
191                         }
192                         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
193                                         "connect_unix_sock: could not bind the unix socket to"
194                                         " %s: %s (%d)",
195                                         mysun->sun_path, strerror(errno), errno);
196                         goto error;
197                 }
198         }
199         if (connect(s, (struct sockaddr *)&ifsun, sizeof(ifsun))==-1){
200                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
201                                 "connect_unix_sock: connect(%s): %s [%d]",
202                                 name, strerror(errno), errno);
203                 goto error;
204         }
205         return s;
206 error:
207         if (s!=-1) close(s);
208         return FATAL_ERROR;
209 }
210
211 static int connect_tcpudp_socket(char* address, int port, int type)
212 {
213         struct sockaddr_in addr;
214         struct hostent* he;
215         int sock;
216
217         sock=-1;
218         /* resolve destination */
219         he=gethostbyname(address);
220         if (he==0){
221                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
222                                 "connect_tcpudp_socket: could not resolve %s", address);
223                 goto error;
224         }
225         /* open socket*/
226         memset(&addr, 0, sizeof(struct sockaddr_in));
227         addr.sin_family=he->h_addrtype;
228         addr.sin_port=htons(port);
229         memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
230
231         sock = socket(he->h_addrtype, type, 0);
232         if (sock==-1){
233                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
234                         "connect_tcpudp_socket: socket: %s", strerror(errno));
235                 goto error;
236         }
237         if (connect(sock, (struct sockaddr*) &addr, sizeof(struct sockaddr))!=0){
238                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
239                                 "connect_tcpudp_socket: connect: %s", strerror(errno));
240                 goto error;
241         }
242         return sock;
243 error:
244         if (sock!=-1) close(sock);
245         return FATAL_ERROR;
246 }
247
248 /* on exit cleanup */
249 static void cleanup(struct sockaddr_un* mysun)
250 {
251         if (mysun->sun_path[0] != '\0') {
252                 if (unlink(mysun->sun_path) < 0) {
253                         fprintf(stderr, "ERROR: failed to delete %s: %s\n",
254                                         mysun->sun_path, strerror(errno));
255                 }
256         }
257 }
258
259 int binrpc_open_connection(struct binrpc_handle* handle, char* name, int port, int proto,
260                     char* reply_socket, char* sock_dir)
261 {
262         struct sockaddr_un mysun;
263
264         binrpc_last_errs[0] = '\0';
265         binrpc_last_errs[sizeof(binrpc_last_errs)-1] = '\0';  /* snprintf safe terminator */
266
267         handle->socket = -1;
268         handle->buf = NULL;
269         mysun.sun_path[0] = '\0';
270         
271         /* init the random number generator */
272         srand(getpid()+time(0)); /* we don't need very strong random numbers */
273         
274         if (name == NULL) {
275                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
276                         "open_connection: invalid IP address or socket name");
277                 goto error;
278         }
279         
280         handle->proto = proto;
281         switch(proto) {
282                 case UDP_SOCK:
283                 case TCP_SOCK:
284                         if (port == 0) {
285                                 port=DEFAULT_CTL_PORT;
286                         }
287                         
288                         handle->sock_type = (proto == UDP_SOCK) ? SOCK_DGRAM : SOCK_STREAM;
289                         if ((handle->socket = connect_tcpudp_socket(name, port, handle->sock_type)) < 0) {
290                                 goto error;
291                         }
292                         break;
293                 case UNIXS_SOCK:
294                 case UNIXD_SOCK:
295                         handle->sock_type = (proto == UNIXD_SOCK) ? SOCK_DGRAM : SOCK_STREAM;
296                         if ((handle->socket = connect_unix_sock(name, handle->sock_type, &mysun, reply_socket, sock_dir)) < 0) {
297                                 goto error;
298                         }
299                         break;
300                 case UNKNOWN_SOCK:
301                         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
302                                 "open_connection: Bad socket type for %s\n", name); /*vm zmenit*/
303                         goto error;
304         }
305         if (handle->sock_type == SOCK_DGRAM) {
306                 handle->buf_size = 8192;  /* max size of datagram, < SSIZE_MAX, TODO: does a platform dependent constant exist ? */
307         }
308         else {
309                 handle->buf_size = BINRPC_MAX_HDR_SIZE; 
310         }
311         handle->buf = binrpc_malloc(handle->buf_size);
312         if (!handle->buf) {
313                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
314                         "open_connection: not enough memory to allocate buffer. Needed %d bytes", handle->buf_size);    
315                 binrpc_close_connection(handle);
316         }
317         cleanup(&mysun);
318         return 0;
319         
320 error:
321         cleanup(&mysun);
322         return FATAL_ERROR;
323 }
324
325 int binrpc_open_connection_url(struct binrpc_handle* handle, char* url) {
326         static char name[100];
327         char *c, *c2, *rpl_sock;
328         int port, proto, i;
329         handle->socket = -1;
330         handle->buf = NULL;
331         /* parse proto:name:port|unixd_sock */
332         c = url;
333         if (strncasecmp(c, "udp:", 4) == 0)
334                 proto = UDP_SOCK;
335         else if (strncasecmp(c, "tcp:", 4) == 0)
336                 proto = TCP_SOCK;
337         else if (strncasecmp(c, "unix:", 5) == 0 || strncasecmp(c, "unixs:", 6) == 0)
338                 proto = UNIXS_SOCK;
339         else if (strncasecmp(c, "unixd:", 6) == 0)
340                 proto = UNIXD_SOCK;
341         else {
342                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
343                         "open_connection_url: bad protocol in '%s'", c);
344                 return FATAL_ERROR;     
345         }
346         while (*c != ':') c++;
347         c++;
348         c2 = strchr(c, ':');
349         if (!c2)
350                 c2 = c + strlen(c);
351         if (c2 - c > sizeof(name)-1) {
352                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
353                         "open_connection_url: name is too long '%s'", c);
354                 return FATAL_ERROR;     
355         }
356         for (i=0; c<c2; c++, i++) {
357                 name[i] = *c;
358         }
359         name[i] = '\0';
360         if (strlen(name) == 0) {
361                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
362                         "open_connection_url: name is not specified in '%s'", url);
363                 return FATAL_ERROR;     
364         }
365         c = c2;
366         if (*c == ':') c++;
367
368         port = 0;
369         rpl_sock = NULL;
370         switch (proto) {
371                 case UNIXD_SOCK:
372                         if (strlen(c) != 0)
373                                 rpl_sock = c;
374                         break;
375                 case UNIXS_SOCK:
376                         break;
377                 default:
378                         port = atol(c);
379                         if (port == 0) {
380                                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
381                                         "open_connection_url: port is not specified in '%s'", url);
382                                 return FATAL_ERROR;     
383                         }
384                         break;
385         }       
386         return binrpc_open_connection(handle, name, port, proto, rpl_sock, NULL);
387 }
388
389 void binrpc_close_connection(struct binrpc_handle* handle)
390 {
391         if (handle->socket != -1) {
392                 close(handle->socket);
393                 handle->socket = -1;
394         }
395         if (handle->buf) {
396                 binrpc_free(handle->buf);
397                 handle->buf = NULL;
398         }
399 }
400
401 /* returns: -1 on error, number of bytes written on success */
402 static int send_binrpc_cmd(struct binrpc_handle* handle, struct binrpc_pkt *pkt, int cookie)
403 {
404         struct iovec v[IOVEC_CNT];
405         unsigned char msg_hdr[BINRPC_MAX_HDR_SIZE];
406         int n;
407         
408         if ((n=binrpc_build_hdr(BINRPC_REQ, binrpc_pkt_len(pkt), cookie, msg_hdr,
409                                                         BINRPC_MAX_HDR_SIZE)) < 0) {
410                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
411                         "send_binrpc_cmd: build header error: %s",
412                         binrpc_error(n));
413                 return FATAL_ERROR;
414         }
415         v[0].iov_base=msg_hdr;
416         v[0].iov_len=n;
417         v[1].iov_base=pkt->body;
418         v[1].iov_len=binrpc_pkt_len(pkt);
419 write_again:
420         if ((n=writev(handle->socket, v, 2))<0){
421                 if (errno==EINTR)
422                         goto write_again;
423                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
424                         "send_binrpc_cmd: send packet failed: %s (%d)", strerror(errno), errno);
425                 return FATAL_ERROR;
426         }
427         return n;
428 }
429
430
431 /* reads the whole reply
432  * returns < 0 on error, reply size on success + initializes resp_handle */
433 static int get_reply(struct binrpc_handle *handle, 
434                         int cookie, 
435                         struct binrpc_response_handle *resp_handle)
436 {
437         unsigned char *crt, *hdr_end;
438         int n, ret, tl;
439         
440         ret = 0;
441         resp_handle->reply_buf = NULL;
442         hdr_end = crt = handle->buf;
443         
444         do {            
445                 n = read(handle->socket, crt, handle->buf_size - (crt-handle->buf));
446                 if (n <= 0){
447                         if (errno==EINTR)
448                                 continue;
449                         if (n == 0)
450                                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
451                                         "get_reply: read unexpected EOF: received %d bytes"
452                                         " of reply", (int)(long)(crt - handle->buf));
453                         else
454                                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
455                                         "get_reply: read reply failed: %s (%d)",
456                                         strerror(errno), errno);
457                         return FATAL_ERROR;
458                 }
459                 if (verbose >= 3){
460                         /* dump it in hex */
461                         printf("received %d bytes in reply (@offset %d):\n", 
462                                n, (int)(crt-handle->buf));
463                         hexdump(crt, n, 1);
464                 }
465                 crt += n;
466                 hdr_end = binrpc_parse_init(&resp_handle->in_pkt, handle->buf, crt - handle->buf, &ret);
467                 
468         } while (ret == E_BINRPC_MORE_DATA);
469         if (ret < 0){
470                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
471                         "get_reply: reply parsing error: %s",
472                         binrpc_error(ret));
473                 return FATAL_ERROR;
474         }
475
476         if (verbose>1){
477                 printf("new packet: type %02x, len %d, cookie %02x\n",
478                                 resp_handle->in_pkt.type, resp_handle->in_pkt.tlen, resp_handle->in_pkt.cookie);
479         }
480         if (resp_handle->in_pkt.cookie!=cookie){
481                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
482                         "get_reply: reply parsing error: "
483                         "cookie doesn't match: sent: %02x, received: %02x", 
484                         cookie, resp_handle->in_pkt.cookie);
485                 return FATAL_ERROR;
486         }
487
488         /* we know total size and we can allocate buffer for received data */
489         tl = resp_handle->in_pkt.tlen;
490         
491         if (handle->sock_type == SOCK_DGRAM) {
492                 /* we must read all datagram in one read call, otherwise unread part is truncated and lost. Read will block execution */
493                 if (crt - hdr_end < tl) {
494                         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
495                                 "get_reply: datagram truncated. Received: %ld, Expected: %d.",
496                                 (long int)(crt-hdr_end), tl);
497                         return FATAL_ERROR;             
498                 }
499         }
500         if (crt - hdr_end > tl) {
501                 /* header contains probably data from next message, in case of STREAM it could be unread but it's waste of time */
502                 crt = hdr_end + tl;     
503         }
504         
505         resp_handle->reply_buf = (unsigned char *) binrpc_malloc(tl);
506         if (!resp_handle->reply_buf) {
507                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
508                         "get_reply: not enough memory to allocate reply buffer. %d bytes needed.",
509                         resp_handle->in_pkt.tlen);
510                 return FATAL_ERROR;
511         }
512         crt = resp_handle->reply_buf + (crt-hdr_end);
513         memcpy(resp_handle->reply_buf, hdr_end, crt - resp_handle->reply_buf);
514         tl -= crt - resp_handle->reply_buf;
515         while (tl > 0) {
516                 n=read(handle->socket, crt, tl);
517                 if (n < 0){
518                         if (errno==EINTR)
519                                 continue;
520                         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
521                                 "get_reply: read reply failed: %s (%d)",
522                                 strerror(errno), errno);
523                         binrpc_free(resp_handle->reply_buf);
524                         resp_handle->reply_buf = NULL;
525                         return FATAL_ERROR;
526                 }
527                 if (verbose >= 3){
528                         /* dump it in hex */
529                         printf("received %d bytes in reply (@offset %d):\n", 
530                                n, (int)(crt-resp_handle->reply_buf));
531                         hexdump(crt, n, 1);
532                 }
533                 crt += n;
534                 tl -= n;
535         }
536         
537         return (int)(crt-resp_handle->reply_buf);
538 }
539
540 int binrpc_send_command_ex(
541         struct binrpc_handle* handle, struct binrpc_pkt *pkt, 
542         struct binrpc_response_handle *resp_handle)
543 {
544         int cookie;
545         
546         cookie = gen_cookie();
547         if (send_binrpc_cmd(handle, pkt, cookie) < 0) {
548                 return FATAL_ERROR;
549         }
550         /* read reply */
551         memset(&resp_handle->in_pkt, 0, sizeof(resp_handle->in_pkt));
552         if (get_reply(handle, cookie, resp_handle) < 0) {
553                 return FATAL_ERROR;
554         }
555         
556         /* normal exit */
557         return 0;
558 }
559
560 static int parse_arg(struct binrpc_val* v, char* arg)
561 {
562         int i=0;
563         double f;
564         char* tmp;
565         int len;
566
567         f = 0.0;
568
569         if (*arg)
570                 i=strtol(arg, &tmp, 10);
571         else
572                 tmp = 0;
573         if ((tmp==0) || (*tmp)){
574                 if (*arg)
575                         f=strtod(arg, &tmp);
576                 if ((tmp==0) || (*tmp)){
577                         /* not an int or a float => string */
578                         len=strlen(arg);
579                         if ((len>=2) && (arg[0]=='s') && (arg[1]==':')){
580                                 tmp=&arg[2];
581                                 len-=2;
582                         }else{
583                                 tmp=arg;
584                         }
585                         v->type=BINRPC_T_STR;
586                         v->u.strval.s=tmp;
587                         v->u.strval.len=len;
588                 }else{ /* float */
589                         v->type=BINRPC_T_DOUBLE;
590                         v->u.fval=f;
591                 }
592         }else{ /* int */
593                 v->type=BINRPC_T_INT;
594                 v->u.intval=i;
595         }
596         return 0;
597 }
598
599
600 /* parse the body into a malloc allocated,  binrpc_val array */
601 int binrpc_send_command(
602         struct binrpc_handle* handle, char* method, char** args, int arg_count,
603         struct binrpc_response_handle *resp_handle)
604 {
605         struct binrpc_pkt req_pkt;
606         struct binrpc_val v;
607         int i, size, res = FATAL_ERROR, ret = 0;
608         unsigned char *req_buf = NULL;
609
610         memset(&resp_handle->in_pkt, 0, sizeof(resp_handle->in_pkt));   
611         if (!method || strlen(method) == 0) {
612                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
613                         "send_command: method name not specified");
614                 goto fail;
615         
616         }
617         size = BINRPC_MIN_RECORD_SIZE + 8 + strlen(method) + 1; /*max.possible optional value len */    
618         for (i=0; i<arg_count; i++) {
619                 if (parse_arg(&v, args[i]) < 0)
620                         goto fail;
621                 switch (v.type) {
622                         case BINRPC_T_STR:
623                                 size += v.u.strval.len + 1;
624                                 break;
625                         case BINRPC_T_INT:
626                         case BINRPC_T_DOUBLE:
627                                 size += sizeof(int);
628                                 break;
629                         default:
630                                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
631                                         "BUG: send_command: unexpected value type");
632                                 goto fail;
633                 }
634                 size +=  BINRPC_MIN_RECORD_SIZE + 8;
635         }
636         req_buf = binrpc_malloc(size);
637         if (!req_buf) {
638                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
639                         "send_command: not enough memory to allocate buffer. Needed %d bytes", size);
640                 goto fail;
641         }
642         if ((ret = binrpc_init_pkt(&req_pkt, req_buf, size)) < 0) goto fail2;
643
644         if ((ret = binrpc_addstr(&req_pkt, method, strlen(method))) < 0) goto fail2;
645
646         for (i=0; i<arg_count; i++) {
647                 if (parse_arg(&v, args[i]) < 0)
648                         goto fail;
649                 switch (v.type) {
650                         case BINRPC_T_STR:
651                                 if ((ret = binrpc_addstr(&req_pkt,  v.u.strval.s,  v.u.strval.len)) < 0) goto fail2;
652                                 break;
653                         case BINRPC_T_INT:
654                                 if ((ret = binrpc_addint(&req_pkt, v.u.intval)) < 0) goto fail2;
655                                 break;
656                         case BINRPC_T_DOUBLE:
657                                 if ((ret = binrpc_adddouble(&req_pkt, v.u.fval)) < 0) goto fail2;
658                                 break;
659                         default:
660                                 break;
661                 }
662         }
663
664         if (binrpc_send_command_ex(handle, &req_pkt, resp_handle) < 0) {
665                 goto fail;
666         }
667         res = 0;
668 fail:   
669         if (req_buf) binrpc_free(req_buf);
670         return res;     
671 fail2:
672         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
673                 "send_command: error when preparing params: %s", binrpc_error(ret));
674         goto fail;
675 }
676
677 void binrpc_release_response(struct binrpc_response_handle *resp_handle) {
678         if (resp_handle->reply_buf) {
679                 binrpc_free(resp_handle->reply_buf);
680                 resp_handle->reply_buf = NULL;
681         }
682 }
683
684 int binrpc_get_response_type(struct binrpc_response_handle *resp_handle)
685 {
686         switch(resp_handle->in_pkt.type) {
687                 case BINRPC_FAULT:
688                         return 1;
689                         break;
690                 case BINRPC_REPL:
691                         return 0;
692                         break;
693                 default:
694                         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
695                                 "BUG: get_response_type: not a reply");
696                         return FATAL_ERROR;
697         }
698 }
699
700 /* parses strings like "bla bla %v 10%% %v\n test=%v",
701  * and stops at each %v,  returning  a pointer after the %v, setting *size
702  * to the string length (not including %v) and *type to the corresponding
703  * BINRPC type (for now only BINRPC_T_ALL).
704  * To escape a '%', use "%%", and check for type==-1 (which means skip an call
705  *  again parse_fmt).
706  * Usage:
707  *        n="test: %v,%v,%v\n";
708  *        while(*n){
709  *          s=n;
710  *          n=parse_fmt(n, &type, &size);
711  *          printf("%.*s", size, s);
712  *          if (type==-1)
713  *            continue;
714  *          else 
715  *             printf("now we should get & print an object of type %d\n", type)
716  *        }
717  */
718 static char* parse_fmt(char* fmt, int* type, int* size)
719 {
720         char* s;
721
722         s=fmt;
723         do{
724                 for(;*fmt && *fmt!='%'; fmt++);
725                 if (*fmt=='%'){
726                         switch(*(fmt+1)){
727                                 case 'v':
728                                         *type=BINRPC_T_ALL;
729                                         *size=(int)(fmt-s);
730                                         return (fmt+2);
731                                         break;
732                                 case '%':
733                                         /* escaped % */
734                                         *size=(int)(fmt-s)+1;
735                                         *type=-1; /* skip */
736                                         return (fmt+2);
737                                         break;
738                         }
739                 }
740         }while(*fmt);
741         *type=-1; /* no value */
742         *size=(fmt-s);
743         return fmt;
744 }
745
746 static void print_binrpc_val(struct binrpc_val* v, int ident)
747 {
748         int r;
749
750         if ((v->type==BINRPC_T_STRUCT) && !v->u.end)
751                 ident--; /* fix to have strut beg. idented differently */
752         for (r=0; r<ident; r++) putchar('       ');
753         if (v->name.s){
754                 printf("%.*s: ", v->name.len, v->name.s);
755         }
756         switch(v->type){
757                 case BINRPC_T_INT:
758                         printf("%d", v->u.intval);
759                         break;
760                 case BINRPC_T_STR:
761                 case BINRPC_T_BYTES:
762                         printf("%.*s", v->u.strval.len, v->u.strval.s);
763                         break;
764                 case BINRPC_T_ARRAY:
765                         printf("%c", (v->u.end)?']':'[');
766                         break;
767                 case BINRPC_T_STRUCT:
768                         printf("%c", (v->u.end)?'}':'{');
769                         break;
770                         default:
771                                 printf("ERROR: unknown type %d\n", v->type);
772         }
773 }
774
775 int binrpc_print_response(struct binrpc_response_handle *resp_handle, char* fmt)
776 {
777         unsigned char* p;
778         unsigned char* end;
779         struct binrpc_val val;
780         int ret;
781         int rec;
782         char *f;
783         char* s;
784         int f_size;
785         int fmt_has_values;
786         
787         if (!resp_handle) {
788                 goto error;
789         }
790         resp_handle->in_pkt.offset = resp_handle->in_pkt.in_struct = resp_handle->in_pkt.in_array = 0;
791
792         p=resp_handle->reply_buf;
793         end=p+resp_handle->in_pkt.tlen;
794         rec=0;
795         f=fmt;
796         fmt_has_values=0;
797         /* read body */
798         while(p<end){
799                 if (f){
800                                         
801                         do{
802                                 if (*f==0)
803                                         f=fmt; /* reset */
804                                 s=f;
805                                 f=parse_fmt(f, &val.type, &f_size);
806                                 printf("%.*s", f_size, s);
807                                 if (val.type!=-1){
808                                         fmt_has_values=1;
809                                         goto read_value;
810                                 }
811                         }while(*f || fmt_has_values);
812                         val.type=BINRPC_T_ALL;
813                 }else{
814                         val.type=BINRPC_T_ALL;
815                 }
816 read_value:
817                 val.name.s=0;
818                 val.name.len=0;
819                 p=binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
820                 if (ret<0){
821                         if (fmt)
822                                 putchar('\n');
823                         /*if (ret==E_BINRPC_MORE_DATA)
824                                 goto error_read_again;*/
825                         if (ret==E_BINRPC_EOP){
826                                 printf("end of message detected\n");
827                                 break;
828                         }
829                         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
830                                         "error while parsing the record %d,"
831                                         " @%d: %02x : %s", rec,
832                                         resp_handle->in_pkt.offset, *p, binrpc_error(ret));
833                         goto error;
834                 }
835                 rec++;
836                 if (fmt){
837                         print_binrpc_val(&val, 0);
838                 }else{
839                         print_binrpc_val(&val, resp_handle->in_pkt.in_struct+resp_handle->in_pkt.in_array);
840                         putchar('\n');
841                 }
842         }
843         if (fmt && *f){
844                 /* print the rest, with empty values */
845                 while(*f){
846                         s=f;
847                         f=parse_fmt(f, &val.type, &f_size);
848                         printf("%.*s", f_size, s);
849                 }
850         }
851         return 0;
852 error:
853         return FATAL_ERROR;
854 /*error_read_again:
855         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
856                 "ERROR: more data needed");
857         return -2;
858         */
859 }
860
861
862 void binrpc_free_rpc_array(struct binrpc_val* a, int size)
863 {
864         int r;
865         for (r=0; r<size; r++){
866                 if (a[r].name.s)
867                         binrpc_free(a[r].name.s);
868                 if ((a[r].type==BINRPC_T_STR || a[r].type==BINRPC_T_BYTES) &&
869                                 a[r].u.strval.s){
870                         binrpc_free(a[r].u.strval.s);
871                 }
872         }
873         binrpc_free(a);
874 }
875
876
877 #define VAL_ARRAY_CHUNK 100
878 int binrpc_parse_response(struct binrpc_val** vals, int* val_count,
879         struct binrpc_response_handle *resp_handle)
880 {
881         struct binrpc_val val;
882         unsigned char *p, *end;
883         int ret, i;
884
885         resp_handle->in_pkt.offset = resp_handle->in_pkt.in_struct = resp_handle->in_pkt.in_array = 0;
886
887         i=0;
888         if (*val_count==0){
889                 *val_count=VAL_ARRAY_CHUNK; /* start with a reasonable size */
890         }
891         *vals = (struct binrpc_val*) binrpc_malloc(*val_count*sizeof(**vals));
892         if (*vals == 0)
893                 goto error_mem;
894         p = resp_handle->reply_buf;
895         end = p + resp_handle->in_pkt.tlen;
896         
897         /* read body */
898         while(p < end){
899                 val.type = BINRPC_T_ALL;
900                 val.name.s = 0;
901                 val.name.len = 0;
902                 p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
903                 if (ret<0){
904                         if (ret==E_BINRPC_EOP){
905                                 break;
906                         }
907                         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
908                                         "ERROR while parsing the record %d,"
909                                         " @%d: %02x : %s", i,
910                                         resp_handle->in_pkt.offset, *p, binrpc_error(ret));
911                         goto error;
912                 }
913                 if (i >= *val_count){
914                         struct binrpc_val *t;
915                         t= (struct binrpc_val*) binrpc_realloc(*vals, (VAL_ARRAY_CHUNK+(*val_count))*sizeof(**vals));
916                         if (t==0)
917                                 goto error_mem;
918                         *vals = t;
919                         *val_count += VAL_ARRAY_CHUNK;
920                 }
921                 (*vals)[i] = val;
922                 if (val.name.s){
923                         if (((*vals)[i].name.s=binrpc_malloc(val.name.len+1))==0)
924                                 goto error_mem;
925                         memcpy((*vals)[i].name.s, val.name.s, val.name.len);
926                         (*vals)[i].name.s[val.name.len]=0; /* 0-term */
927                 }
928                 if (val.u.strval.s){
929                         if (val.type==BINRPC_T_STR){
930                                 if (((*vals)[i].u.strval.s=
931                                                         binrpc_malloc(val.u.strval.len+1))==0)
932                                         goto error_mem;
933                                 memcpy((*vals)[i].u.strval.s, val.u.strval.s,
934                                                 val.u.strval.len);
935                                 (*vals)[i].u.strval.s[val.u.strval.len]=0; /* 0-term */
936                         }else if (val.type==BINRPC_T_BYTES){
937                                 if (((*vals)[i].u.strval.s=binrpc_malloc(val.u.strval.len))==0)
938                                         goto error_mem;
939                                 memcpy((*vals)[i].u.strval.s, val.u.strval.s, 
940                                                 val.u.strval.len);
941                         }
942                 }
943                 i++;
944         }
945         if (i == 0) {
946                 binrpc_free(*vals);
947                 *vals = NULL;
948         }
949         else if (i<*val_count){
950 /*              do not try to save memory because it causes fragmentation when used ser mem utils and "regualar" memory leak
951                 struct binrpc_val *t;
952                 t = (struct binrpc_val*) binrpc_realloc(*vals, i*sizeof(**vals));
953                 if (t) *vals = t;
954 */
955         }
956         *val_count = i;
957         return 0;
958 error_mem:
959         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
960                 "parse_response: out of memory");
961 error:
962         if (*vals){
963                 binrpc_free_rpc_array(*vals, i);
964                 *vals = NULL;
965         }
966         *val_count=0;
967         return FATAL_ERROR;
968 }
969
970 int binrpc_parse_error_response(
971         struct binrpc_response_handle *resp_handle,
972         int *err_no,
973         char **err) 
974 {
975         struct binrpc_val val;
976         unsigned char *p, *end;
977         int ret;
978
979         resp_handle->in_pkt.offset = resp_handle->in_pkt.in_struct = resp_handle->in_pkt.in_array = 0;
980         p = resp_handle->reply_buf;
981         end = p+resp_handle->in_pkt.tlen;
982         
983         val.type=BINRPC_T_INT;
984         val.name.s=0;
985         val.name.len=0;
986         p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
987         if (ret < 0) {
988                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
989                         "parse_error_response: error when parsing reply (code): %s", binrpc_error(ret)
990                 );
991                 return FATAL_ERROR;
992         }
993         *err_no = val.u.intval;
994
995         val.type=BINRPC_T_STR;
996         p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
997         if (ret < 0) {
998                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
999                         "parse_error_response: error when parsing reply (str): %s", binrpc_error(ret)
1000                 );
1001                 return FATAL_ERROR;
1002         }                                                                                                                                                                                                                                                                               
1003         *err = val.u.strval.s;  /* it's null terminated */
1004         return 0;
1005 }
1006
1007 /* returns a pointer to a static buffer containing l in asciiz & sets len */
1008 static inline char* int2str_internal(unsigned int l, int* len)
1009 {
1010         static char r[INT2STR_MAX_LEN];
1011         int i;
1012         
1013         i=INT2STR_MAX_LEN-2;
1014         r[INT2STR_MAX_LEN-1]=0; /* null terminate */
1015         do{
1016                 r[i]=l%10+'0';
1017                 i--;
1018                 l/=10;
1019         }while(l && (i>=0));
1020         if (l && (i<0)){
1021                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
1022                         "BUG: int2str_internal: overflow");
1023         }
1024         if (len) *len=(INT2STR_MAX_LEN-2)-i;
1025         return &r[i+1];
1026 }
1027
1028 static int realloc_buf(unsigned char** buf, int* buf_len, int req_len)
1029
1030         unsigned char*  tmp_buf;
1031         int orig_len;
1032         
1033         orig_len = (*buf == NULL) ? 0 : strlen((char *) *buf);
1034         *buf_len += (TEXT_BUFF_ALLOC_CHUNK < req_len) ? TEXT_BUFF_ALLOC_CHUNK + req_len : TEXT_BUFF_ALLOC_CHUNK;
1035         
1036         if (*buf == NULL)
1037                 tmp_buf = (unsigned char *) binrpc_malloc(orig_len + *buf_len);
1038         else
1039                 tmp_buf = (unsigned char *) binrpc_realloc(*buf, orig_len + *buf_len);
1040         if (tmp_buf == 0) {
1041                 snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
1042                         "ERROR: out of memory");
1043                 return FATAL_ERROR;
1044         }
1045         
1046         *buf = tmp_buf;
1047         (*buf)[orig_len] = '\0';
1048
1049         return 0;
1050 }
1051
1052 static inline int str2buffer(unsigned char** buf, int* buf_len, int* pos, 
1053                              char* data, int data_len)
1054 {
1055         if (*buf_len < data_len) {
1056                 if(realloc_buf(buf, buf_len, data_len) != 0) {
1057                         return FATAL_ERROR;
1058                 }
1059         }
1060         
1061         memcpy(&(*buf)[*pos], data, data_len);
1062         *pos += data_len;
1063         *buf_len -= data_len;
1064         
1065         return 0;
1066 }
1067
1068 static inline int char2buffer(unsigned char** buf, int* buf_len, int* pos, 
1069                               char data)
1070 {
1071         if (*buf_len < 1) {
1072                 if(realloc_buf(buf, buf_len, 1) != 0) {
1073                         return FATAL_ERROR;
1074                 }
1075         }
1076         
1077         (*buf)[*pos] = data;
1078         ++(*pos);
1079         --(*buf_len);
1080         
1081         return 0;
1082 }
1083
1084 static int val2buffer(struct binrpc_val* v, unsigned char** buf, 
1085                              int *buf_len, int* pos)
1086 {
1087         char *number;
1088         int num_len; 
1089          
1090         if (v->name.s){
1091                 if(str2buffer(buf, buf_len, pos, v->name.s, v->name.len) != 0) {
1092                         return FATAL_ERROR;
1093                 }
1094                 if(str2buffer(buf, buf_len, pos, ": ", strlen(": ")) != 0) {  /* TODO: common format */
1095                         return FATAL_ERROR;
1096                 }
1097                 
1098         }
1099         
1100         switch(v->type){
1101                 case BINRPC_T_INT:
1102                         num_len = 0;
1103                         number = NULL;
1104                         number = int2str_internal(v->u.intval, &num_len);
1105                         if (number == NULL) {
1106                                 printf("ERROR: Conversion of %d into string failed.\n", v->type);
1107                                 return FATAL_ERROR;
1108                         }
1109                         
1110                         if(str2buffer(buf, buf_len, pos, number, num_len) != 0) {
1111                                 return FATAL_ERROR;
1112                         }
1113                         break;
1114                 case BINRPC_T_STR:
1115                 case BINRPC_T_BYTES:
1116                         if(str2buffer(buf, buf_len, pos, v->u.strval.s, v->u.strval.len) != 0) {
1117                                 return FATAL_ERROR;
1118                         }
1119                         break;
1120                 case BINRPC_T_ARRAY:
1121                         if(char2buffer(buf, buf_len, pos, (v->u.end) ? ']' : '[') != 0) {
1122                                 return FATAL_ERROR;
1123                         }
1124                         break;
1125                 case BINRPC_T_STRUCT:
1126                         if(char2buffer(buf, buf_len, pos, (v->u.end) ? '}' : '{') != 0) {
1127                                 return FATAL_ERROR;
1128                         }
1129                         break;
1130                 default:
1131                         printf("ERROR: unknown type %d\n", v->type);
1132                         return FATAL_ERROR;
1133         };
1134         
1135         return 0;
1136 }
1137
1138 int binrpc_response_to_text(
1139         struct binrpc_response_handle *resp_handle,
1140         unsigned char** txt_rsp, int* txt_rsp_len, char delimiter)
1141 {
1142         unsigned char* p;
1143         unsigned char* end;
1144         struct binrpc_val val;
1145         int ret;
1146         int rec;
1147         int pos;
1148         
1149         pos = 0;
1150         
1151         if (!resp_handle) {
1152                 goto error;
1153         }
1154
1155         memset(&val, 0, sizeof(struct binrpc_val));
1156         resp_handle->in_pkt.offset = resp_handle->in_pkt.in_struct = resp_handle->in_pkt.in_array = 0;
1157         
1158         p=resp_handle->reply_buf;
1159         end=p+resp_handle->in_pkt.tlen;
1160         rec=0;
1161         
1162         if (*txt_rsp == NULL) {
1163                 *txt_rsp_len = 0;
1164                 if (realloc_buf(txt_rsp, txt_rsp_len, 0) != 0) {
1165                         goto error;
1166                 } 
1167         }
1168         
1169         /* read body */
1170         while(p<end){
1171                 val.type=BINRPC_T_ALL;
1172                 val.name.s=0;
1173                 val.name.len=0;
1174                 p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, 0, &ret);
1175                 if (ret < 0) {
1176                         if (ret == E_BINRPC_EOP) {
1177                                 printf("end of message detected\n");
1178                                 break;
1179                         }
1180                         snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
1181                                         "ERROR while parsing the record %d,"
1182                                         " @%d: %02x : %s", rec, resp_handle->in_pkt.offset, *p, binrpc_error(ret));
1183                         goto error;
1184                 }
1185                 rec++;
1186                 if (val2buffer(&val, txt_rsp, txt_rsp_len, &pos) != 0) {
1187                         goto error;
1188                 }
1189                 
1190                 if(char2buffer(txt_rsp, txt_rsp_len, &pos, delimiter) != 0) {
1191                         goto error;
1192                 }
1193         }
1194         
1195         /* rewrite last char - we don't need delimiter there */
1196         (*txt_rsp)[pos-1] = '\0';   
1197         /*
1198         if(char2buffer(txt_rsp, txt_rsp_len, &pos, '\0') != 0) {
1199                 goto error;
1200         }
1201         */
1202         return 0;
1203 error:
1204         return FATAL_ERROR;
1205 }
1206
1207 int main(int argc, char** argv)
1208 {
1209         struct binrpc_response_handle resp_handle;
1210         unsigned char* txt_rsp = NULL;
1211         int txt_rsp_len = 0;
1212         struct binrpc_handle handle;
1213         struct binrpc_val *vals = NULL;
1214         int cnt, i, err_no;
1215         char *errs;
1216         
1217         if (argc < 2) goto err;
1218         
1219         if (binrpc_open_connection_url(&handle, argv[1]) < 0) goto err2;
1220         if (binrpc_send_command(&handle, argv[2], argv+3, argc-3, &resp_handle) < 0) {
1221                 binrpc_close_connection(&handle);
1222                 goto err2;
1223         }
1224         binrpc_close_connection(&handle);
1225
1226         if (binrpc_response_to_text(&resp_handle, &txt_rsp, &txt_rsp_len, '\n') < 0) goto err3;
1227         fprintf(stdout, "binrpc_response_to_text():\n--------------------------\n%s\n", txt_rsp);
1228         
1229         fprintf(stdout, "\nbinrpc_print_response():\n------------------------\n");
1230         binrpc_print_response(&resp_handle, NULL);
1231         
1232         fprintf(stdout, "\nbinrpc_parse_response():\n------------------------\n");
1233         cnt = 0;
1234         switch (binrpc_get_response_type(&resp_handle)) {
1235                 case 0:
1236                         if (binrpc_parse_response(&vals, &cnt, &resp_handle) < 0) goto err3;
1237                         fprintf(stdout, "#Records: %d\n", cnt);
1238                         for (i = 0; i < cnt; i++) {
1239                                 fprintf(stdout, "#%.2d: type:%d name:%.*s\n", i, vals[i].type, vals[i].name.len, vals[i].name.s);
1240                         }
1241                         break;
1242                 case 1:
1243                         if (binrpc_parse_error_response(&resp_handle, &err_no, &errs) <0) goto err3;
1244                         fprintf(stdout, "%d %s\n", err_no, errs);
1245                         break;
1246                 default:
1247                         fprintf(stdout, "Unknown response type: %d\n", binrpc_get_response_type(&resp_handle)); 
1248                         break;
1249         }
1250
1251         if (vals != NULL) {
1252                 binrpc_free_rpc_array(vals, cnt);
1253         }       
1254         if (txt_rsp != NULL) {
1255                 binrpc_free(txt_rsp);
1256         }
1257         binrpc_release_response(&resp_handle);
1258         
1259         return 0;
1260 err:
1261         fprintf(stderr, "Usage: %s url mathod [params]\n", NAME);
1262         return -1;
1263 err3:
1264         if (vals != NULL) {
1265                 binrpc_free_rpc_array(vals, cnt);
1266         }       
1267         if (txt_rsp) {
1268                 binrpc_free(txt_rsp);
1269         }
1270         binrpc_release_response(&resp_handle);
1271 err2:
1272         fprintf(stderr, "ERROR: %s\n", binrpc_get_last_errs());
1273         return -2;
1274 }
1275