Browse code

binrpc library - offers API for using Andrei's binary RPC functionality

Vladimir Marek authored on 06/02/2007 08:00:49
Showing 5 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+# warning: set correct structure aligment!
1
+CFLAGS   += -ggdb -fPIC -malign-double
2
+
3
+# name of result executable or library
4
+NAME = binrpc
5
+
6
+# override using 'make lib-type=static'
7
+# TYPE=lib => shared or static library, executable otherwise
8
+TYPE = lib
9
+
10
+include ../Makefile.defs
11
+
0 12
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+LIBNAME  = binrpc
1
+OUT_NAME = libbinrpc.so
2
+OUT_TYPE = lib
3
+
4
+CFLAGS += -g0 -O9 -fPIC
5
+
6
+include ../Makefile.ser.defs
7
+
0 8
new file mode 100644
... ...
@@ -0,0 +1,34 @@
0
+binrcp library
1
+--------------
2
+
3
+prepared by Vladimir Marek
4
+inspirated by sercmd from Andrei Pelinescu-Onciul
5
+
6
+Description:
7
+------------
8
+
9
+This library using binrpc implementation from CTL module of SER and encapsulets
10
+it for socket communication. It offers simple functional interface for sending
11
+messages over UNIX sockets, TCP or UDP protocol. The messages are encoded into
12
+binary RCP format that is much more efficient then standard XMLRPC.
13
+
14
+
15
+Purpose:
16
+--------
17
+
18
+This library offers common interface for communicating with CTL module over UNIX
19
+socket, TCP and UDP protocol. Binary RCP makes XMLRPC more efficient using 
20
+binary format for transporting messgae from client to server and vice versa.
21
+
22
+
23
+Description of interface:
24
+-------------------------
25
+
26
+The detail description of interface is a part of binrpc_api.h header file. It is
27
+also possible generate documentation from this file by using DoxyGen.
28
+
29
+Warning
30
+-------
31
+
32
+Double check alignment which is used for compilation to avoid nasty problem with
33
+structure size (if using libbinrpc library). This may occur e.g. in binrpc_parse_response!!!
0 34
\ No newline at end of file
1 35
new file mode 100644
... ...
@@ -0,0 +1,1238 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2006 iptelorg GmbH
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License 
23
+ * along with this program; if not, write to the Free Software 
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+ 
27
+/*
28
+ * send commands using binrpc
29
+ *
30
+ * History:
31
+ * --------
32
+ *  2006-11-09  created by vlada
33
+ *  2006-12-20  extended by tma
34
+ */
35
+
36
+#include <stdlib.h> /* realloc, rand ... */
37
+#include <stdio.h>
38
+#include <unistd.h>
39
+#include <errno.h>
40
+#include <ctype.h> /* isprint */
41
+#include <time.h> /* time */
42
+#include <stropts.h>
43
+
44
+#include "../../modules/ctl/ctl_defaults.h" /* default socket & port */
45
+#include "../../modules/ctl/init_socks.h"
46
+#include "../../modules/ctl/binrpc.c" /* ugly hack */
47
+
48
+#include "binrpc_api.h"
49
+
50
+
51
+#define IOVEC_CNT 20
52
+#define TEXT_BUFF_ALLOC_CHUNK   4096
53
+#define FATAL_ERROR       -1
54
+
55
+#ifndef NAME
56
+#define NAME    "binrpc_api"
57
+#endif
58
+
59
+#define binrpc_malloc internal_malloc
60
+#define binrpc_realloc internal_realloc
61
+#define binrpc_free internal_free
62
+
63
+#ifndef UNIX_PATH_MAX
64
+#define UNIX_PATH_MAX 108
65
+#endif
66
+
67
+#define INT2STR_MAX_LEN  (19+1+1) /* 2^64~= 16*10^18 => 19+1 digits + \0 */
68
+
69
+static void* (*internal_malloc)(size_t size) = malloc;
70
+static void* (*internal_realloc)(void* ptr, size_t size) = realloc;
71
+static void (*internal_free)(void* ptr) = free;
72
+
73
+static char binrpc_last_errs[1024] = "";
74
+static int verbose = 0;
75
+
76
+char *binrpc_get_last_errs() 
77
+{
78
+    return binrpc_last_errs;
79
+}
80
+
81
+void binrpc_clear_last_err()
82
+{
83
+    binrpc_last_errs[0] = '\0';
84
+}
85
+
86
+void binrpc_set_mallocs(void* _malloc, void* _realloc, void* _free)
87
+{
88
+    internal_malloc = _malloc;
89
+    internal_realloc = _realloc;
90
+    internal_free = _free;
91
+}
92
+
93
+static int gen_cookie()
94
+{
95
+	return rand();
96
+}
97
+
98
+static void hexdump(unsigned char* buf, int len, int ascii)
99
+{
100
+	int r, i;
101
+	
102
+	/* dump it in hex */
103
+	for (r=0; r<len; r++){
104
+		if ((r) && ((r%16)==0)){
105
+			if (ascii){
106
+				putchar(' ');
107
+				for (i=r-16; i<r; i++){
108
+					if (isprint(buf[i]))
109
+						putchar(buf[i]);
110
+					else
111
+						putchar('.');
112
+				}
113
+			}
114
+			putchar('\n');
115
+		}
116
+		printf("%02x ", buf[r]);
117
+	};
118
+	if (ascii){
119
+		for (i=r;i%16; i++)
120
+			printf("   ");
121
+		putchar(' ');
122
+		for (i=16*(r/16); i<r; i++){
123
+			if (isprint(buf[i]))
124
+				putchar(buf[i]);
125
+			else
126
+				putchar('.');
127
+		}
128
+	}
129
+	putchar('\n');
130
+}
131
+
132
+/* opens,  and  connects on a STREAM unix socket
133
+ * returns socket fd or -1 on error */
134
+static int connect_unix_sock(char* name, int type, struct sockaddr_un* mysun,
135
+                      char* reply_socket, char* sock_dir)
136
+{
137
+	struct sockaddr_un ifsun;
138
+	int s;
139
+	int len;
140
+	int ret;
141
+	int retries;	
142
+	
143
+	retries=0;
144
+	s=-1;
145
+	memset(&ifsun, 0, sizeof (struct sockaddr_un));
146
+	len=strlen(name);
147
+	if (len>UNIX_PATH_MAX){
148
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
149
+				"connect_unix_sock: name too long "
150
+				"(%d > %d): %s", len, UNIX_PATH_MAX, name);
151
+		goto error;
152
+	}
153
+	ifsun.sun_family=AF_UNIX;
154
+	memcpy(ifsun.sun_path, name, len);
155
+#ifdef HAVE_SOCKADDR_SA_LEN
156
+	ifsun.sun_len=len;
157
+#endif
158
+	s=socket(PF_UNIX, type, 0);
159
+	if (s==-1){
160
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
161
+			"connect_unix_sock: cannot create unix socket"
162
+			" %s: %s [%d]", 
163
+			name, strerror(errno), errno);
164
+		goto error;
165
+	}
166
+	if (type==SOCK_DGRAM){
167
+		/* we must bind so that we can receive replies */
168
+		if (reply_socket==0){
169
+			if (sock_dir==0)
170
+				sock_dir="/tmp";
171
+retry:
172
+			ret=snprintf(mysun->sun_path, UNIX_PATH_MAX, "%s/" NAME "_%d",
173
+							sock_dir, rand()); 
174
+			if ((ret<0) ||(ret>=UNIX_PATH_MAX)){
175
+				snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
176
+							"connect_unix_sock: buffer overflow while trying to"
177
+							"generate unix datagram socket name");
178
+				goto error;
179
+			}
180
+		}else{
181
+			if (strlen(reply_socket)>UNIX_PATH_MAX){
182
+				snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
183
+							"connect_unix_sock: buffer overflow while trying to"
184
+							"use the provided unix datagram socket name (%s)",
185
+							reply_socket);
186
+				goto error;
187
+			}
188
+			strcpy(mysun->sun_path, reply_socket);
189
+		}
190
+		mysun->sun_family=AF_UNIX;
191
+		if (bind(s, (struct sockaddr*)&mysun, sizeof(struct sockaddr_un))==-1){
192
+		//if (bind(s, mysun, sizeof(mysun))==-1){
193
+			if (errno==EADDRINUSE && (reply_socket==0) && (retries < 10)){
194
+				retries++;
195
+				/* try another one */
196
+				goto retry;
197
+			}
198
+			snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
199
+					"connect_unix_sock: could not bind the unix socket to"
200
+					" %s: %s (%d)",
201
+					mysun->sun_path, strerror(errno), errno);
202
+			goto error;
203
+		}
204
+	}
205
+	if (connect(s, (struct sockaddr *)&ifsun, sizeof(ifsun))==-1){
206
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
207
+				"connect_unix_sock: connect(%s): %s [%d]",
208
+				name, strerror(errno), errno);
209
+		goto error;
210
+	}
211
+	return s;
212
+error:
213
+	if (s!=-1) close(s);
214
+	return FATAL_ERROR;
215
+}
216
+
217
+static int connect_tcpudp_socket(char* address, int port, int type)
218
+{
219
+	struct sockaddr_in addr;
220
+	struct hostent* he;
221
+	int sock;
222
+	
223
+	sock=-1;
224
+	/* resolve destination */
225
+	he=gethostbyname(address);
226
+	if (he==0){
227
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
228
+				"connect_tcpudp_socket: could not resolve %s", address);
229
+		goto error;
230
+	}
231
+	/* open socket*/
232
+	addr.sin_family=he->h_addrtype;
233
+	addr.sin_port=htons(port);
234
+	memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
235
+	
236
+	sock = socket(he->h_addrtype, type, 0);
237
+	if (sock==-1){
238
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
239
+			"connect_tcpudp_socket: socket: %s", strerror(errno));
240
+		goto error;
241
+	}
242
+	if (connect(sock, (struct sockaddr*) &addr, sizeof(struct sockaddr))!=0){
243
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
244
+				"connect_tcpudp_socket: connect: %s", strerror(errno));
245
+		goto error;
246
+	}
247
+	return sock;
248
+error:
249
+	if (sock!=-1) close(sock);
250
+	return FATAL_ERROR;
251
+}
252
+
253
+/* on exit cleanup */
254
+static void cleanup(struct sockaddr_un* mysun)
255
+{	
256
+	if (mysun->sun_path[0] != '\0') {
257
+		if (unlink(mysun->sun_path) < 0) {
258
+			fprintf(stderr, "ERROR: failed to delete %s: %s\n",
259
+					mysun->sun_path, strerror(errno));
260
+		}
261
+	}
262
+}
263
+
264
+int binrpc_open_connection(struct binrpc_handle* handle, char* name, int port, int proto,
265
+		    char* reply_socket, char* sock_dir)
266
+{
267
+	struct sockaddr_un mysun;
268
+		
269
+	binrpc_last_errs[0] = '\0';
270
+	binrpc_last_errs[sizeof(binrpc_last_errs)-1] = '\0';  /* snprintf safe terminator */
271
+
272
+	handle->socket = -1;
273
+	handle->buf = NULL;
274
+	mysun.sun_path[0] = '\0';
275
+	
276
+	/* init the random number generator */
277
+	srand(getpid()+time(0)); /* we don't need very strong random numbers */
278
+	
279
+	if (name == NULL) {
280
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
281
+			"open_connection: invalid IP address or socket name");
282
+		goto error;
283
+	}
284
+	
285
+	handle->proto = proto;
286
+	switch(proto) {
287
+		case UDP_SOCK:
288
+		case TCP_SOCK:
289
+			if (port == 0) {
290
+				port=DEFAULT_CTL_PORT;
291
+			}
292
+			
293
+			handle->sock_type = (proto == UDP_SOCK) ? SOCK_DGRAM : SOCK_STREAM;
294
+			if ((handle->socket = connect_tcpudp_socket(name, port, handle->sock_type)) < 0) {
295
+				goto error;
296
+			}
297
+			break;
298
+		case UNIXS_SOCK:
299
+		case UNIXD_SOCK:
300
+			handle->sock_type = (proto == UNIXD_SOCK) ? SOCK_DGRAM : SOCK_STREAM;
301
+			if ((handle->socket = connect_unix_sock(name, handle->sock_type, &mysun, reply_socket, sock_dir)) < 0) {
302
+				goto error;
303
+			}
304
+			break;
305
+		case UNKNOWN_SOCK:
306
+			snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
307
+				"open_connection: Bad socket type for %s\n", name); /*vm zmenit*/
308
+			goto error;
309
+	}
310
+	if (handle->sock_type == SOCK_DGRAM) {
311
+		handle->buf_size = 8192;  /* max size of datagram, < SSIZE_MAX, TODO: does a platform dependent constant exist ? */
312
+	}
313
+	else {
314
+		handle->buf_size = BINRPC_MAX_HDR_SIZE;	
315
+	}
316
+	handle->buf = binrpc_malloc(handle->buf_size);
317
+	if (!handle->buf) {
318
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
319
+			"open_connection: not enough memory to allocate buffer. Needed %d bytes", handle->buf_size);	
320
+		binrpc_close_connection(handle);
321
+	}
322
+	cleanup(&mysun);
323
+	return 0;
324
+	
325
+error:
326
+	cleanup(&mysun);
327
+	return FATAL_ERROR;
328
+}
329
+
330
+int binrpc_open_connection_url(struct binrpc_handle* handle, char* url) {
331
+	static char name[100];
332
+	char *c, *c2, *rpl_sock;
333
+	int port, proto, i;
334
+	handle->socket = -1;
335
+	handle->buf = NULL;
336
+	/* parse proto:name:port|unixd_sock */
337
+	c = url;
338
+	if (strncasecmp(c, "udp:", 4) == 0)
339
+		proto = UDP_SOCK;
340
+	else if (strncasecmp(c, "tcp:", 4) == 0)
341
+		proto = TCP_SOCK;
342
+	else if (strncasecmp(c, "unix:", 5) == 0 || strncasecmp(c, "unixs:", 6) == 0)
343
+		proto = UNIXS_SOCK;
344
+	else if (strncasecmp(c, "unixd:", 6) == 0)
345
+		proto = UNIXD_SOCK;
346
+	else {
347
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
348
+			"open_connection_url: bad protocol in '%s'", c);
349
+		return FATAL_ERROR;	
350
+	}
351
+	while (*c != ':') c++;
352
+	c++;
353
+	c2 = strchr(c, ':');
354
+	if (!c2)
355
+		c2 = c + strlen(c);
356
+	if (c2 - c > sizeof(name)-1) {
357
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
358
+			"open_connection_url: name is too long '%s'", c);
359
+		return FATAL_ERROR;	
360
+	}
361
+	for (i=0; c<c2; c++, i++) {
362
+		name[i] = *c;
363
+	}
364
+	name[i] = '\0';
365
+	if (strlen(name) == 0) {
366
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
367
+			"open_connection_url: name is not specified in '%s'", url);
368
+		return FATAL_ERROR;	
369
+	}
370
+	c = c2;
371
+	if (*c == ':') c++;
372
+
373
+	port = 0;
374
+	rpl_sock = NULL;
375
+	switch (proto) {
376
+		case UNIXD_SOCK:
377
+			if (strlen(c) != 0)
378
+				rpl_sock = c;
379
+			break;
380
+		case UNIXS_SOCK:
381
+			break;
382
+		default:
383
+			port = atol(c);
384
+			if (port == 0) {
385
+				snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
386
+					"open_connection_url: port is not specified in '%s'", url);
387
+				return FATAL_ERROR;	
388
+			}
389
+			break;
390
+	}	
391
+	return binrpc_open_connection(handle, name, port, proto, rpl_sock, NULL);
392
+}
393
+
394
+void binrpc_close_connection(struct binrpc_handle* handle)
395
+{
396
+	if (handle->socket != -1) {
397
+		close(handle->socket);
398
+		handle->socket = -1;
399
+	}
400
+	if (handle->buf) {
401
+		binrpc_free(handle->buf);
402
+		handle->buf = NULL;
403
+	}
404
+}
405
+
406
+/* returns: -1 on error, number of bytes written on success */
407
+static int send_binrpc_cmd(struct binrpc_handle* handle, struct binrpc_pkt *pkt, int cookie)
408
+{
409
+	struct iovec v[IOVEC_CNT];
410
+	unsigned char msg_hdr[BINRPC_MAX_HDR_SIZE];
411
+	int n;
412
+	
413
+	if ((n=binrpc_build_hdr(BINRPC_REQ, binrpc_pkt_len(pkt), cookie, msg_hdr,
414
+							BINRPC_MAX_HDR_SIZE)) < 0) {
415
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
416
+			"send_binrpc_cmd: build header error: %s",
417
+			binrpc_error(n));
418
+		return FATAL_ERROR;
419
+	}
420
+	v[0].iov_base=msg_hdr;
421
+	v[0].iov_len=n;
422
+	v[1].iov_base=pkt->body;
423
+	v[1].iov_len=binrpc_pkt_len(pkt);
424
+write_again:
425
+	if ((n=writev(handle->socket, v, 2))<0){
426
+		if (errno==EINTR)
427
+			goto write_again;
428
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1, 
429
+			"send_binrpc_cmd: send packet failed: %s (%d)", strerror(errno), errno);
430
+		return FATAL_ERROR;
431
+	}
432
+	return n;
433
+}
434
+
435
+
436
+/* reads the whole reply
437
+ * returns < 0 on error, reply size on success + initializes resp_handle */
438
+static int get_reply(struct binrpc_handle *handle, 
439
+			int cookie, 
440
+			struct binrpc_response_handle *resp_handle)
441
+{
442
+	unsigned char *crt, *hdr_end;
443
+	int n, ret, tl;
444
+	
445
+	ret = 0;
446
+	resp_handle->reply_buf = NULL;
447
+	hdr_end = crt = handle->buf;
448
+	
449
+	do {		
450
+		n = read(handle->socket, crt, handle->buf_size - (crt-handle->buf));
451
+		if (n < 0){
452
+			if (errno==EINTR)
453
+				continue;
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: %d, Expected: %d.",
496
+				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;
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, &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
+#define VAL_ARRAY_CHUNK 100
862
+int binrpc_parse_response(struct binrpc_val** vals, int* val_count,
863
+	struct binrpc_response_handle *resp_handle)
864
+{
865
+	struct binrpc_val val;
866
+	unsigned char *p, *end;
867
+	int ret, i;
868
+
869
+	resp_handle->in_pkt.offset = resp_handle->in_pkt.in_struct = resp_handle->in_pkt.in_array = 0;
870
+
871
+	if (*val_count==0){
872
+		*val_count=VAL_ARRAY_CHUNK; /* start with a reasonable size */
873
+	}
874
+	*vals = (struct binrpc_val*) binrpc_malloc(*val_count*sizeof(**vals));
875
+	if (*vals == 0)
876
+		goto error_mem;
877
+	p = resp_handle->reply_buf;
878
+	end = p + resp_handle->in_pkt.tlen;
879
+	i=0;
880
+	
881
+	/* read body */
882
+	while(p < end){
883
+		val.type = BINRPC_T_ALL;
884
+		val.name.s = 0;
885
+		val.name.len = 0;
886
+		p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
887
+		if (ret<0){
888
+			if (ret==E_BINRPC_EOP){
889
+				break;
890
+			}
891
+			snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
892
+					"ERROR while parsing the record %d,"
893
+					" @%d: %02x : %s", i,
894
+					resp_handle->in_pkt.offset, *p, binrpc_error(ret));
895
+			goto error;
896
+		}
897
+		if (i >= *val_count){
898
+			struct binrpc_val *t;
899
+			t= (struct binrpc_val*) binrpc_realloc(*vals, (VAL_ARRAY_CHUNK+(*val_count))*sizeof(**vals));
900
+			if (t==0)
901
+				goto error_mem;
902
+			*vals = t;
903
+			*val_count += VAL_ARRAY_CHUNK;
904
+		}
905
+		(*vals)[i] = val;
906
+		i++;
907
+	}
908
+	if (i == 0) {
909
+		binrpc_free(*vals);
910
+		*vals = NULL;
911
+	}
912
+	else if (i<*val_count){
913
+/*		do not try to save memory because it causes fragmentation when used ser mem utils and "regualar" memory leak
914
+		struct binrpc_val *t;
915
+		t = (struct binrpc_val*) binrpc_realloc(*vals, i*sizeof(**vals));
916
+		if (t) *vals = t;
917
+*/
918
+	}
919
+	*val_count = i;
920
+	return 0;
921
+error_mem:
922
+	snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
923
+		"parse_response: out of memory");
924
+error:
925
+	if (*vals){
926
+		binrpc_free(*vals);
927
+		*vals = NULL;
928
+	}
929
+	*val_count=0;
930
+	return FATAL_ERROR;
931
+}
932
+
933
+int binrpc_parse_error_response(
934
+	struct binrpc_response_handle *resp_handle,
935
+	int *err_no,
936
+	char **err) 
937
+{
938
+	struct binrpc_val val;
939
+	unsigned char *p, *end;
940
+	int ret;
941
+
942
+	resp_handle->in_pkt.offset = resp_handle->in_pkt.in_struct = resp_handle->in_pkt.in_array = 0;
943
+	p = resp_handle->reply_buf;
944
+	end = p+resp_handle->in_pkt.tlen;
945
+	
946
+	val.type=BINRPC_T_INT;
947
+	val.name.s=0;
948
+	val.name.len=0;
949
+	p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
950
+	if (ret < 0) {
951
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
952
+			"parse_error_response: error when parsing reply (code): %s", binrpc_error(ret)
953
+		);
954
+		return FATAL_ERROR;
955
+	}
956
+	*err_no = val.u.intval;
957
+
958
+	val.type=BINRPC_T_STR;
959
+	p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
960
+	if (ret < 0) {
961
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
962
+			"parse_error_response: error when parsing reply (str): %s", binrpc_error(ret)
963
+		);
964
+		return FATAL_ERROR;
965
+	}																																		
966
+	*err = val.u.strval.s;  /* it's null terminated */
967
+	return 0;
968
+}
969
+
970
+/* returns a pointer to a static buffer containing l in asciiz & sets len */
971
+static inline char* int2str(unsigned int l, int* len)
972
+{
973
+	static char r[INT2STR_MAX_LEN];
974
+	int i;
975
+	
976
+	i=INT2STR_MAX_LEN-2;
977
+	r[INT2STR_MAX_LEN-1]=0; /* null terminate */
978
+	do{
979
+		r[i]=l%10+'0';
980
+		i--;
981
+		l/=10;
982
+	}while(l && (i>=0));
983
+	if (l && (i<0)){
984
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
985
+			"BUG: int2str: overflow");
986
+	}
987
+	if (len) *len=(INT2STR_MAX_LEN-2)-i;
988
+	return &r[i+1];
989
+}
990
+
991
+static int realloc_buf(unsigned char** buf, int* buf_len, int req_len)
992
+{ 
993
+	unsigned char*	tmp_buf;
994
+	int orig_len;
995
+	
996
+	orig_len = (*buf == NULL) ? 0 : strlen((char *) *buf);
997
+	*buf_len += (TEXT_BUFF_ALLOC_CHUNK < req_len) ? TEXT_BUFF_ALLOC_CHUNK + req_len : TEXT_BUFF_ALLOC_CHUNK;
998
+	
999
+	if (*buf == NULL)
1000
+		tmp_buf = (unsigned char *) binrpc_malloc(orig_len + *buf_len);
1001
+	else
1002
+		tmp_buf = (unsigned char *) binrpc_realloc(*buf, orig_len + *buf_len);
1003
+	if (tmp_buf == 0) {
1004
+		snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
1005
+			"ERROR: out of memory");
1006
+		return FATAL_ERROR;
1007
+	}
1008
+	
1009
+	*buf = tmp_buf;
1010
+	(*buf)[orig_len] = '\0';
1011
+
1012
+	return 0;
1013
+}
1014
+
1015
+static inline int str2buffer(unsigned char** buf, int* buf_len, int* pos, 
1016
+			     char* data, int data_len)
1017
+{
1018
+	if (*buf_len < data_len) {
1019
+		if(realloc_buf(buf, buf_len, data_len) != 0) {
1020
+			return FATAL_ERROR;
1021
+		}
1022
+	}
1023
+	
1024
+	memcpy(&(*buf)[*pos], data, data_len);
1025
+	*pos += data_len;
1026
+	*buf_len -= data_len;
1027
+	
1028
+	return 0;
1029
+}
1030
+
1031
+static inline int char2buffer(unsigned char** buf, int* buf_len, int* pos, 
1032
+			      char data)
1033
+{
1034
+	if (*buf_len < 1) {
1035
+		if(realloc_buf(buf, buf_len, 1) != 0) {
1036
+			return FATAL_ERROR;
1037
+		}
1038
+	}
1039
+	
1040
+	(*buf)[*pos] = data;
1041
+	++(*pos);
1042
+	--(*buf_len);
1043
+	
1044
+	return 0;
1045
+}
1046
+
1047
+static int val2buffer(struct binrpc_val* v, unsigned char** buf, 
1048
+			     int *buf_len, int* pos)
1049
+{
1050
+	char *number;
1051
+	int num_len; 
1052
+	 
1053
+	if (v->name.s){
1054
+		if(str2buffer(buf, buf_len, pos, v->name.s, v->name.len) != 0) {
1055
+			return FATAL_ERROR;
1056
+		}
1057
+		if(str2buffer(buf, buf_len, pos, ": ", strlen(": ")) != 0) {  /* TODO: common format */
1058
+			return FATAL_ERROR;
1059
+		}
1060
+		
1061
+	}
1062
+	
1063
+	switch(v->type){
1064
+		case BINRPC_T_INT:
1065
+			num_len = 0;
1066
+			number = NULL;
1067
+			number = int2str(v->u.intval, &num_len);
1068
+			if (number == NULL) {
1069
+				printf("ERROR: Conversion of %d into string failed.\n", v->type);
1070
+				return FATAL_ERROR;
1071
+			}
1072
+			
1073
+			if(str2buffer(buf, buf_len, pos, number, num_len) != 0) {
1074
+				return FATAL_ERROR;
1075
+			}
1076
+			break;
1077
+		case BINRPC_T_STR:
1078
+		case BINRPC_T_BYTES:
1079
+			if(str2buffer(buf, buf_len, pos, v->u.strval.s, v->u.strval.len) != 0) {
1080
+				return FATAL_ERROR;
1081
+			}
1082
+			break;
1083
+		case BINRPC_T_ARRAY:
1084
+			if(char2buffer(buf, buf_len, pos, (v->u.end) ? ']' : '[') != 0) {
1085
+				return FATAL_ERROR;
1086
+			}
1087
+			break;
1088
+		case BINRPC_T_STRUCT:
1089
+			if(char2buffer(buf, buf_len, pos, (v->u.end) ? '}' : '{') != 0) {
1090
+				return FATAL_ERROR;
1091
+			}
1092
+			break;
1093
+		default:
1094
+			printf("ERROR: unknown type %d\n", v->type);
1095
+			return FATAL_ERROR;
1096
+	};
1097
+	
1098
+	return 0;
1099
+}
1100
+
1101
+int binrpc_response_to_text(
1102
+	struct binrpc_response_handle *resp_handle,
1103
+	unsigned char** txt_rsp, int* txt_rsp_len, char delimiter)
1104
+{
1105
+	unsigned char* p;
1106
+	unsigned char* end;
1107
+	struct binrpc_val val;
1108
+	int ret;
1109
+	int rec;
1110
+	int pos;
1111
+	
1112
+	pos = 0;
1113
+	
1114
+	if (!resp_handle) {
1115
+		goto error;
1116
+	}
1117
+
1118
+	resp_handle->in_pkt.offset = resp_handle->in_pkt.in_struct = resp_handle->in_pkt.in_array = 0;
1119
+	
1120
+	p=resp_handle->reply_buf;
1121
+	end=p+resp_handle->in_pkt.tlen;
1122
+	rec=0;
1123
+	
1124
+	if (*txt_rsp == NULL) {
1125
+		*txt_rsp_len = 0;
1126
+		if (realloc_buf(txt_rsp, txt_rsp_len, 0) != 0) {
1127
+			goto error;
1128
+		} 
1129
+	}
1130
+	
1131
+	/* read body */
1132
+	while(p<end){
1133
+		val.type=BINRPC_T_ALL;
1134
+		val.name.s=0;
1135
+		val.name.len=0;
1136
+		p = binrpc_read_record(&resp_handle->in_pkt, p, end, &val, &ret);
1137
+		if (ret < 0) {
1138
+			if (ret == E_BINRPC_EOP) {
1139
+				printf("end of message detected\n");
1140
+				break;
1141
+			}
1142
+			snprintf(binrpc_last_errs, sizeof(binrpc_last_errs)-1,
1143
+					"ERROR while parsing the record %d,"
1144
+					" @%d: %02x : %s", rec,	resp_handle->in_pkt.offset, *p, binrpc_error(ret));
1145
+			goto error;
1146
+		}
1147
+		rec++;
1148
+		if (val2buffer(&val, txt_rsp, txt_rsp_len, &pos) != 0) {
1149
+			goto error;
1150
+		}
1151
+		
1152
+		if(char2buffer(txt_rsp, txt_rsp_len, &pos, delimiter) != 0) {
1153
+			goto error;
1154
+		}
1155
+	}
1156
+	
1157
+	/* rewrite last char - we don't need delimiter there */
1158
+	(*txt_rsp)[pos-1] = '\0';   
1159
+	/*
1160
+	if(char2buffer(txt_rsp, txt_rsp_len, &pos, '\0') != 0) {
1161
+		goto error;
1162
+	}
1163
+	*/
1164
+	return 0;
1165
+error:
1166
+	return FATAL_ERROR;
1167
+}
1168
+
1169
+int main(int argc, char** argv)
1170
+{
1171
+	struct binrpc_response_handle resp_handle;
1172
+	unsigned char* txt_rsp = NULL;
1173
+	int txt_rsp_len = 0;
1174
+	struct binrpc_handle handle;
1175
+	struct binrpc_val *vals = NULL;
1176
+	int cnt, i, err_no;
1177
+	char *errs;
1178
+	
1179
+	if (argc < 2) goto err;
1180
+	
1181
+	if (binrpc_open_connection_url(&handle, argv[1]) < 0) goto err2;
1182
+	if (binrpc_send_command(&handle, argv[2], argv+3, argc-3, &resp_handle) < 0) {
1183
+		binrpc_close_connection(&handle);
1184
+		goto err2;
1185
+	}
1186
+	binrpc_close_connection(&handle);
1187
+
1188
+	if (binrpc_response_to_text(&resp_handle, &txt_rsp, &txt_rsp_len, '\n') < 0) goto err3;
1189
+	fprintf(stdout, "binrpc_response_to_text():\n--------------------------\n%s\n", txt_rsp);
1190
+	
1191
+	fprintf(stdout, "\nbinrpc_print_response():\n------------------------\n");
1192
+	binrpc_print_response(&resp_handle, NULL);
1193
+	
1194
+	fprintf(stdout, "\nbinrpc_parse_response():\n------------------------\n");
1195
+	cnt = 0;
1196
+	switch (binrpc_get_response_type(&resp_handle)) {
1197
+		case 0:
1198
+			if (binrpc_parse_response(&vals, &cnt, &resp_handle) < 0) goto err3;
1199
+			fprintf(stdout, "#Records: %d\n", cnt);
1200
+			for (i = 0; i < cnt; i++) {
1201
+				fprintf(stdout, "#%.2d: type:%d name:%.*s\n", i, vals[i].type, vals[i].name.len, vals[i].name.s);
1202
+			}
1203
+			break;
1204
+		case 1:
1205
+			if (binrpc_parse_error_response(&resp_handle, &err_no, &errs) <0) goto err3;
1206
+			fprintf(stdout, "%d %s\n", err_no, errs);
1207
+			break;
1208
+		default:
1209
+			fprintf(stdout, "Unknown response type: %d\n", binrpc_get_response_type(&resp_handle));	
1210
+			break;
1211
+	}
1212
+
1213
+	if (vals != NULL) {
1214
+		binrpc_free(vals);
1215
+	}	
1216
+	if (txt_rsp != NULL) {
1217
+		binrpc_free(txt_rsp);
1218
+	}
1219
+	binrpc_release_response(&resp_handle);
1220
+	
1221
+	return 0;
1222
+err:
1223
+	fprintf(stderr, "Usage: %s url mathod [params]\n", NAME);
1224
+	return -1;
1225
+err3:
1226
+	if (vals != NULL) {
1227
+		binrpc_free(vals);
1228
+	}	
1229
+	if (txt_rsp) {
1230
+		binrpc_free(txt_rsp);
1231
+	}
1232
+	binrpc_release_response(&resp_handle);
1233
+err2:
1234
+	fprintf(stderr, "ERROR: %s\n", binrpc_get_last_errs());
1235
+	return -2;
1236
+}
1237
+
0 1238
new file mode 100644
... ...
@@ -0,0 +1,291 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2006 iptelorg GmbH
4
+ *
5
+ * This file is part of ser, a free SIP server.
6
+ *
7
+ * ser is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * For a license to use the ser software under conditions
13
+ * other than those described here, or to purchase support for this
14
+ * software, please contact iptel.org by e-mail at the following addresses:
15
+ *    info@iptel.org
16
+ *
17
+ * ser is distributed in the hope that it will be useful,
18
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
+ * GNU General Public License for more details.
21
+ *
22
+ * You should have received a copy of the GNU General Public License 
23
+ * along with this program; if not, write to the Free Software 
24
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
+ */
26
+
27
+/*
28
+ * History:
29
+ * --------
30
+ *  2006-11-09  created (vlada)
31
+ */
32
+
33
+#ifndef BINRPC_API_H_
34
+#define BINRPC_API_H_
35
+
36
+#include "../../modules/ctl/binrpc.h"
37
+
38
+struct binrpc_handle {
39
+	int socket;
40
+	int proto;
41
+	int sock_type;
42
+	unsigned char* buf;
43
+	int buf_size;
44
+};
45
+
46
+struct binrpc_response_handle {
47
+	unsigned char *reply_buf;
48
+	struct binrpc_parse_ctx in_pkt;
49
+};
50
+
51
+/**
52
+ * Function: binrpc_open_connection
53
+ * 
54
+ * Description:
55
+ *   The function open_connection ensures opening of appropriate device for 
56
+ *   future communication. It can create unix socket or TCP/UDP connection 
57
+ *   depending on input parameteres.
58
+ * 
59
+ * @param handler [in]: handler that will be used for saving of obtained socket;
60
+ *   if this function succeed, this handler must be freed via calling of 
61
+ *   binrpc_close_connection function
62
+ * @param name [in]: host IP address or FQDN or unix socket name
63
+ * @param port [in]: host port; in case of unix socket the value is omitted
64
+ * @param proto [in]: type of communication protocol; allowed values are 
65
+ *   UDP_SOCK, TCP_SOCK, UNIXS_SOCK, UNIXD_SOCK
66
+ * @param reply_socket [in]: force reply socket name, for the unix datagram 
67
+ *   socket mode
68
+ * @param sock_dir [in]: specify directory where the reply socket will be 
69
+ *   created; if set to NULL, the default value will be used (/tmp)
70
+ * 
71
+ * @return 0 on success, -1 on failure.
72
+ * 
73
+ * */ 
74
+int binrpc_open_connection(
75
+	struct binrpc_handle* handle,
76
+	char* name, int port, int proto,
77
+	char* reply_socket, char* sock_dir);
78
+
79
+/**
80
+ * Function: binrpc_open_connection_url
81
+ * 
82
+ * Description:
83
+ *   The function is similar as open_connection but target is specified using url.
84
+ * 
85
+ * @param handle [in]: handler that will be used for saving of obtained socket;
86
+ *   if this function succeed, this handle must be freed via calling of 
87
+ *   binrpc_close_connection function
88
+ * @param url [in]: [tcp|udp|unix|unixs|unixd] ":" host_socket ":" [port | reply_socket]
89
+ *   Note: unix = unixs
90
+ * 
91
+ * @return 0 on success, -1 on failure.
92
+ * 
93
+ * */ 
94
+
95
+int binrpc_open_connection_url(struct binrpc_handle* handle, char* url);
96
+                    
97
+/**
98
+ * Function: binrpc_close_connection
99
+ * 
100
+ * Description:
101
+ *   The function close_connection ensures freeing of active socket that is 
102
+ *   represent by handler
103
+ *
104
+ * @param handle [in]: active connection descriptor
105
+ * 
106
+ * @return 0 on success, -1 on failure.
107
+ *   none
108
+ * */
109
+void binrpc_close_connection(struct binrpc_handle* handle);
110
+
111
+/**
112
+ * Function: binrpc_send_command