Browse code

- new fifo/unixsock/xmlrpc like module (implements the rpc api): - supports multiple simultaneous connections over tcp, udp and unix datagram or stream sockets - uses a space efficient binary encoding (for details see the top comments in modules/ctl/binrpc.h) - fast - forks only one extra process - supports also the old fifo protocol, extended to work also on tcp, udp and unix sockets (you could use fifo over telnet for example) - it doesn't depend on any external library see modules/ctl/ctl.cfg for an example config and possible module parameters.

Andrei Pelinescu-Onciul authored on 23/02/2006 19:57:31
Showing 16 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,14 @@
1
+# $Id$
2
+#
3
+# 
4
+# WARNING: do not run this directly, it should be run by the master Makefile
5
+
6
+include ../../Makefile.defs
7
+auto_gen=
8
+NAME=ctl.so
9
+LIBS=
10
+# fifo support
11
+DEFS+=-DUSE_FIFO
12
+
13
+include ../../Makefile.modules
14
+
0 15
new file mode 100644
... ...
@@ -0,0 +1,58 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2006 iptelorg GmbH
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+/* History:
28
+ * --------
29
+ *  2006-02-08  created by andrei
30
+ */
31
+
32
+
33
+
34
+#include "binrpc.h"
35
+
36
+/* WARNING: keep in sync with the errors listed in binrpc.h */
37
+static const char* binrpc_str_errors[]={
38
+	"no error",
39
+	"invalid function arguments",
40
+	"buffer too small (overflow)",
41
+	"corrupted packet",
42
+	"more data needed",
43
+	"end of packet encountered",
44
+	"binrpc parse context not initialized",
45
+	"record doesn't match type",
46
+	"bad record",
47
+	"bug -- internal error",
48
+	"unknown/invalid error code"
49
+};
50
+
51
+
52
+
53
+const char* binrpc_error(int err)
54
+{
55
+	if (err<0) err=-err;
56
+	if (err>(-E_BINRPC_LAST)) err=-E_BINRPC_LAST;
57
+	return binrpc_str_errors[err];
58
+}
0 59
new file mode 100644
... ...
@@ -0,0 +1,891 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2006 iptelorg GmbH
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+/* History:
28
+ * --------
29
+ *  2006-02-08  created by andrei
30
+ */
31
+/* binrpc is  supposed to be a minimalist binary rpc implementation */
32
+
33
+
34
+
35
+/* packet header:
36
+ * (big endian where it applies)
37
+ *      4b      4b        4b     2b   2b       <var>          <var>
38
+ *  | MAGIC  | VERS  || FLAGS  | LL | CL || total_len ... || cookie ... |
39
+ *  total_len = payload len (doesn't include the packet header)
40
+ *  LL = total length len -1 (number of bytes on which total len is
41
+ *        represented)
42
+ *  CL = cookie length -1 (number of bytes on which the cookie is represented)
43
+ *  E.g.: LL= 0 => total_len is represented on 1 byte (LL+1)
44
+ *        CL= 3 => cookie is represneted on 4 bytes (CL+1)
45
+ */
46
+/* record format:
47
+ *  1b   3b     4b
48
+ * |S | size |  type  || <optional value len> ... || <optional value> ... ||
49
+ *
50
+ * if S==0, size is the size (in bytes) of the value (if size==0 => null value)
51
+ * if S==1, optional_value_len is present, and size is it's size
52
+ *    (if size==0 => and type==array or struct => marks end, else
53
+ *     error, reserved)
54
+ *  Examples:
55
+ *     int (type=0) 0x1234     -> 0x20 0x12 0x34           (optimal)
56
+ *                                0x90 0x02 0x12 0x34      (suboptimal)
57
+ *                                0xA0 0x00 0x02 0x12 0x34 (even worse)
58
+ *                   0x07      -> 0x10 0x07                (optimal)
59
+ *                   0x00      -> 0x00                     (optimal)
60
+ *                                0x10 0x00
61
+ *
62
+ *     str (type=1) - strings are 0 terminated (an extra 0 is added to them
63
+ *                    to make the format easier to parse when asciiz strings
64
+ *                    are required); the length includes the terminating 0
65
+ *                  "abcdef"   -> 0x71 "abcdef" 0x00
66
+ *                  "abcdefhij"-> 0x91 0x0A "abcdefhij" 0x00
67
+ *                  ""         -> 0x11 0x00     (0 len str)
68
+ *     65535 bytes
69
+ *     (using str for it)      -> 0xB1 0x01 0x00 0x00 array 0x00
70
+ *
71
+ *     bytes (type=6) -like str but not 0 terminated
72
+ *                  "abcdef"   -> 0x61 "abcdef"
73
+ *     65535 bytes   *         -> 0xA1 0xff 0xff bytes
74
+ *
75
+ *     arrays (array type=4)
76
+ *       arrays are implemented as anonymous value lists:
77
+ *         array_start value1, value2, ..., array_end
78
+ *                               (start) (1st int)  (2nd elem)  (end array)
79
+ *      ints   [ 0x01 0x02 ]   -> 0x04   0x10 0x01  0x10 0x02        0x84
80
+ *      combo  [ 0x07 "abc"]   -> 0x04   0x10 0x07  0x41 "abc" 0x00  0x84
81
+ *
82
+ *      structs (struct type=3)
83
+ *       structs are implemented as avp list:
84
+ *           struct_start, avp1, avp2 .., struct_end
85
+ *        an avp is a named value pair:  name, value. 
86
+ *          - name behaves like a normal string, but has a diff. type (5)
87
+ *          - avps are legal only inside structs.
88
+ *        avp example:           name part (str)   val part (int here) 
89
+ *         "test", int 0x0b   -> 0x55 "test" 0x00   0x10 0x0b
90
+ *
91
+ *      struct example:
92
+ *                              (start)  (avps)                           (end)
93
+ *      struct{                  0x03        (name )        (val)
94
+ *           intval: int 0x3  ->       0x75 "intval" 0x00 0x10 0x3
95
+ *           s:      str "abc"-        0x25 "s" 0x00      0x41 "abc" 0x00
96
+ *      }                                                                  0x83
97
+ *
98
+ *      Limitations: for now avps cannot have array values =>
99
+ *                   structs cannot contain arrays.
100
+ */
101
+
102
+
103
+#ifndef _binrpc_h
104
+#define _binrpc_h
105
+
106
+
107
+#include "../../str.h"
108
+#include <string.h>
109
+
110
+#define BINRPC_MAGIC 0xA
111
+#define BINRPC_VERS  1
112
+
113
+/* sizes & offsets */
114
+#define BINRPC_FIXED_HDR_SIZE	2
115
+#define BINRPC_TLEN_OFFSET		BINRPC_FIXED_HDR_SIZE
116
+#define BINRPC_MIN_HDR_SIZE	(BINRPC_FIXED_HDR_SIZE+2)
117
+#define BINRPC_MAX_HDR_SIZE	(BINRPC_FIXED_HDR_SIZE+4+4)
118
+#define BINRPC_MIN_RECORD_SIZE	1
119
+/* min pkt size: min header + min. len (1) + min. cookie (1) + min record */
120
+#define BINRPC_MIN_PKT_SIZE	(BINRPC_MIN_HDR_SIZE+BINRPC_MIN_RECORD_SIZE)
121
+
122
+/* message types */
123
+#define BINRPC_REQ   0
124
+#define BINRPC_REPL  1
125
+#define BINRPC_FAULT 3
126
+
127
+/* values types */
128
+#define BINRPC_T_INT	0
129
+#define BINRPC_T_STR	1 /* 0 term, for easier parsing */
130
+#define BINRPC_T_DOUBLE	2
131
+#define BINRPC_T_STRUCT	3
132
+#define BINRPC_T_ARRAY	4
133
+#define BINRPC_T_AVP	5  /* allowed only in structs */
134
+#define BINRPC_T_BYTES	6 /* like STR, but not 0 term */
135
+
136
+#define BINRPC_T_ALL	0xf /* wildcard type, will match any record type
137
+							   in the packet (not allowed inside the pkt)*/
138
+
139
+/* errors */
140
+#define E_BINRPC_INVAL		-1  /* invalid function call parameters */
141
+#define E_BINRPC_OVERFLOW	-2  /* buffer overflow */
142
+#define E_BINRPC_BADPKT		-3  /* something went really bad, the packet is
143
+								   corrupted*/
144
+#define E_BINRPC_MORE_DATA	-4 /* parsing error: more bytes are needed,
145
+								  just repeat the failed op, when you have
146
+								  more bytes available */
147
+#define E_BINRPC_EOP		-5	/* end of packet reached */
148
+#define E_BINRPC_NOTINIT	-6  /* parse ctx not initialized */
149
+#define E_BINRPC_TYPE		-7  /* unkown type for record, or requested
150
+								   type doesn't match record type */
151
+#define E_BINRPC_RECORD		-8  /* bad record (unexpected, bad struct a.s.o)*/
152
+#define E_BINRPC_BUG		-9  /* internal error, bug */
153
+#define E_BINRPC_LAST		-10 /* used to count the errors, keep always
154
+								   last */
155
+
156
+/* flags */
157
+#define BINRPC_F_INIT	1
158
+
159
+struct binrpc_pkt{  /* binrpc body */
160
+	unsigned char* body;
161
+	unsigned char* end;
162
+	unsigned char* crt; /*private */
163
+};
164
+
165
+
166
+struct binrpc_parse_ctx{
167
+	/* header */
168
+	unsigned int tlen; /* total len */
169
+	unsigned int cookie;
170
+	int type; /* request, reply, error */
171
+	
172
+	/* parsing info */
173
+	unsigned int flags;   /* parsing flags */
174
+	unsigned int offset; /* current offset (inside payload) */
175
+	unsigned int in_struct;
176
+	unsigned int in_array;
177
+};
178
+
179
+
180
+
181
+struct binrpc_val{
182
+	str name; /* used only in structs */
183
+	int type;
184
+	union{
185
+		str strval;
186
+		double fval;
187
+		int intval;
188
+		int end;
189
+	}u;
190
+};
191
+
192
+
193
+
194
+/*  helper functions  */
195
+
196
+/* return int size: minimum number of bytes needed to represent it
197
+ * if i=0 returns 0 */
198
+inline static int binrpc_get_int_len(int i)
199
+{
200
+	int size;
201
+	for (size=4; size && ((i & (0xff<<24))==0); i<<=8, size--);
202
+	return size;
203
+}
204
+
205
+
206
+
207
+/* adds a start or end tag (valid only for STRUCT or ARRAY for now */
208
+inline static int binrpc_add_tag(struct binrpc_pkt* pkt, int type, int end)
209
+{
210
+	if (pkt->crt>=pkt->end) return E_BINRPC_OVERFLOW;
211
+	*pkt->crt=(end<<7)|type;
212
+	pkt->crt++;
213
+	return 0;
214
+}
215
+
216
+
217
+
218
+/*  writes a minimal int, returns the new offset and sets
219
+ * len to the number of bytes written (<=4)
220
+ * to check for oveflow use: returned_value-p < *len
221
+ */
222
+inline static unsigned char* binrpc_write_int(	unsigned char* p,
223
+												unsigned char* end,
224
+												int i, int *len)
225
+{
226
+	int size;
227
+
228
+	for (size=4; size && ((i & (0xff<<24))==0); i<<=8, size--);
229
+	*len=size;
230
+	for(; (p<end) && (size); p++, size--){
231
+		*p=(unsigned char)(i>>24);
232
+		i<<=8;
233
+	}
234
+	return p;
235
+}
236
+
237
+
238
+
239
+/* API functions */
240
+
241
+/* initialize a binrpc_pkt structure, for packet creation
242
+ * params: pkt         - binrpc body structure that will be initialized 
243
+ *         buf, b_len  -  destination buffer/len
244
+ * returns -1 on error, 0 on success
245
+ *
246
+ * Example usage:
247
+ *  binrpc_init_pkt(pkt, body, BODY_SIZE);
248
+ *  binrpc_addint(pkt, 1);
249
+ *  binrpc_addstr(pkt, "test", sizeof("test")-1);
250
+ *  ...
251
+ *  bytes=binrpc_build_hdr(pkt, BINRPC_REQ, 0x123, hdr_buf, HDR_BUF_LEN);
252
+ *  writev(sock, {{ hdr, bytes}, {pkt->body, pkt->crt-pkt->body}} , 2)*/
253
+inline static int binrpc_init_pkt(struct binrpc_pkt *pkt,
254
+								  unsigned char* buf, int b_len)
255
+{
256
+	if (b_len<BINRPC_MIN_RECORD_SIZE)
257
+		return E_BINRPC_OVERFLOW;
258
+	pkt->body=buf;
259
+	pkt->end=buf+b_len;
260
+	pkt->crt=pkt->body;
261
+	return 0;
262
+};
263
+
264
+
265
+
266
+/* used to update internal contents if the original buffer 
267
+ * (from binrpc_init_pkt) was realloc'ed (and has grown) */
268
+inline static int binrpc_pkt_update_buf(struct binrpc_pkt *pkt,
269
+										unsigned char* new_buf,
270
+										int new_len)
271
+{
272
+	if ((int)(pkt->crt-pkt->body)>new_len){
273
+		return E_BINRPC_OVERFLOW;
274
+	}
275
+	pkt->crt=new_buf+(pkt->crt-pkt->body);
276
+	pkt->body=new_buf;
277
+	pkt->end=new_buf+new_len;
278
+	return 0;
279
+}
280
+
281
+
282
+
283
+/* builds a binrpc header for the binrpc pkt. body pkt and writes it in buf
284
+ * params:  
285
+ *          type     - binrpc packet type (request, reply, fault)
286
+ *          body_len - body len
287
+ *          cookie   - binrpc cookie value
288
+ *          buf,len  - destination buffer & len
289
+ * returns -1 on error, number of bytes written on success */
290
+inline static int binrpc_build_hdr(	int type, int body_len,
291
+									unsigned int cookie,
292
+									unsigned char* buf, int b_len) 
293
+{
294
+	unsigned char* p;
295
+	int len_len;
296
+	int c_len;
297
+	
298
+	len_len=binrpc_get_int_len(body_len);
299
+	c_len=binrpc_get_int_len(cookie);
300
+	if (len_len==0) len_len=1; /* we can't have 0 len */
301
+	if (c_len==0) c_len=1;  /* we can't have 0 len */
302
+	/* size check: 2 bytes header + len_len + cookie len*/
303
+	if (b_len<(BINRPC_FIXED_HDR_SIZE+len_len+c_len)){
304
+		goto error_len;
305
+	}
306
+	p=buf;
307
+	*p=(BINRPC_MAGIC << 4) | BINRPC_VERS;
308
+	p++;
309
+	*p=(type<<4)|((len_len-1)<<2)|(c_len-1);
310
+	p++;
311
+	for(;len_len>0; len_len--,p++){
312
+		*p=(unsigned char)(body_len>>((len_len-1)*8));
313
+	}
314
+	for(;c_len>0; c_len--,p++){
315
+		*p=(unsigned char)(cookie>>((c_len-1)*8));
316
+	}
317
+	return (int)(p-buf);
318
+error_len:
319
+	return E_BINRPC_OVERFLOW;
320
+}
321
+
322
+
323
+
324
+#define binrpc_pkt_len(pkt)		((int)((pkt)->crt-(pkt)->body))
325
+
326
+
327
+
328
+/* changes the length of a header (enough space must be availale) */
329
+inline static int binrpc_hdr_change_len(unsigned char* hdr, int hdr_len,
330
+										int new_len)
331
+{
332
+	int len_len;
333
+	
334
+	binrpc_write_int(&hdr[BINRPC_TLEN_OFFSET], hdr+hdr_len, new_len, &len_len);
335
+	return 0;
336
+}
337
+
338
+
339
+
340
+/* int format:     size BINRPC_T_INT <val>  */
341
+inline static int binrpc_add_int_type(struct binrpc_pkt* pkt, int i, int type)
342
+{
343
+	
344
+	unsigned char* p;
345
+	int size;
346
+	
347
+	p=binrpc_write_int(pkt->crt+1, pkt->end, i, &size);
348
+	if ((int)(p-pkt->crt)<(size+1)) goto error_len;
349
+	*(pkt->crt)=(size<<4) | type;
350
+	pkt->crt=p;
351
+	return 0;
352
+error_len:
353
+	return E_BINRPC_OVERFLOW;
354
+}
355
+
356
+
357
+
358
+/* double format:  FIXME: for now a hack: fixed point represented in
359
+ *  an int (=> max 3 decimals, < MAX_INT/1000) */
360
+#define binrpc_add_double_type(pkt, f, type)\
361
+	binrpc_add_int_type((pkt), (int)((f)*1000), (type))
362
+
363
+
364
+
365
+/* skip bytes bytes (leaves an empty space, for possible future use)
366
+ * WARNING: use with care, low level function
367
+ */
368
+inline static int binrpc_add_skip(struct binrpc_pkt* pkt, int bytes)
369
+{
370
+	
371
+	if ((pkt->crt+bytes)>=pkt->end)
372
+		return E_BINRPC_OVERFLOW;
373
+	pkt->crt+=bytes;
374
+	return 0;
375
+}
376
+
377
+
378
+
379
+/*
380
+ * adds only the string mark and len, you'll have to memcpy the contents
381
+ * manually later (and also use binrpc_add_skip(pkt, l) or increase
382
+ *  pkt->crt directly if you want to continue adding to this pkt).
383
+ *  Usefull for optimizing str writing (e.g. writev(iovec))
384
+ *  WARNING: use with care, low level function, binrpc_addstr or 
385
+ *           binrpc_add_str_type are probably what you want.
386
+ *  WARNING1: BINRPC_T_STR and BINRPC_T_AVP must be  0 term, the len passed to
387
+ *            this function, must include the \0 in this case.
388
+ */
389
+inline static int binrpc_add_str_mark(struct binrpc_pkt* pkt, int type,
390
+										int l)
391
+{
392
+	int size;
393
+	unsigned char* p;
394
+	
395
+	if (l<8){
396
+		size=l;
397
+		p=pkt->crt+1;
398
+	}else{ /* we need a separate len */
399
+		p=binrpc_write_int(pkt->crt+1, pkt->end, l, &size);
400
+		if ((int)(p-pkt->crt)<(size+1)) goto error_len;
401
+		size|=8; /* mark it as having external len  */
402
+	}
403
+	*(pkt->crt)=(size)<<4|type;
404
+	pkt->crt=p;
405
+	return 0;
406
+error_len:
407
+	return E_BINRPC_OVERFLOW;
408
+}
409
+
410
+
411
+
412
+inline static int binrpc_add_str_type(struct binrpc_pkt* pkt, char* s, int len,
413
+										int type)
414
+{
415
+	int size;
416
+	int l;
417
+	int zero_term; /* whether or not to add an extra 0 at the end */
418
+	unsigned char* p;
419
+	
420
+	zero_term=((type==BINRPC_T_STR)||(type==BINRPC_T_AVP));
421
+	l=len+zero_term;
422
+	if (l<8){
423
+		size=l;
424
+		p=pkt->crt+1;
425
+	}else{ /* we need a separate len */
426
+		p=binrpc_write_int(pkt->crt+1, pkt->end, l, &size);
427
+		/* if ((int)(p-pkt->crt)<(size+1)) goto error_len;  - not needed,
428
+		 *  caught by the next check */
429
+		size|=8; /* mark it as having external len  */
430
+	}
431
+	if ((p+l)>=pkt->end) goto error_len;
432
+	*(pkt->crt)=(size)<<4|type;
433
+	memcpy(p, s, len);
434
+	if (zero_term) p[len]=0;
435
+	pkt->crt=p+l;
436
+	return 0;
437
+error_len:
438
+	return E_BINRPC_OVERFLOW;
439
+}
440
+
441
+
442
+
443
+/* adds an avp (name, value) pair, usefull to add structure members */
444
+inline static int binrpc_addavp(struct binrpc_pkt* pkt, struct binrpc_val* avp)
445
+{
446
+	int ret;
447
+	unsigned char* bak;
448
+	
449
+	bak=pkt->crt;
450
+	ret=binrpc_add_str_type(pkt, avp->name.s, avp->name.len, BINRPC_T_AVP);
451
+	if (ret<0) return ret;
452
+	switch (avp->type){
453
+		case BINRPC_T_INT:
454
+			ret=binrpc_add_int_type(pkt, avp->u.intval, avp->type);
455
+			break;
456
+		case BINRPC_T_STR:
457
+		case BINRPC_T_BYTES:
458
+			ret=binrpc_add_str_type(pkt, avp->u.strval.s, 
459
+										avp->u.strval.len,
460
+										avp->type);
461
+			break;
462
+		case BINRPC_T_STRUCT:
463
+		case BINRPC_T_ARRAY:
464
+			ret=binrpc_add_tag(pkt, avp->type, 0);
465
+			break;
466
+		case BINRPC_T_DOUBLE: 
467
+			ret=binrpc_add_double_type(pkt, avp->u.fval, avp->type);
468
+			break;
469
+		default:
470
+			ret=E_BINRPC_BUG;
471
+	}
472
+	if (ret<0)
473
+		pkt->crt=bak; /* roll back */
474
+	return ret;
475
+}
476
+
477
+
478
+
479
+#define binrpc_addint(pkt, i)	binrpc_add_int_type((pkt), (i), BINRPC_T_INT) 
480
+
481
+#define binrpc_adddouble(pkt, f)	\
482
+	binrpc_add_double_type((pkt), (f), BINRPC_T_DOUBLE)
483
+
484
+#define binrpc_addstr(pkt, s, len)	\
485
+	binrpc_add_str_type((pkt), (s), (len), BINRPC_T_STR) 
486
+
487
+#define binrpc_addbytes(pkt, s, len)	\
488
+	binrpc_add_str_type((pkt), (s), (len), BINRPC_T_BYTES) 
489
+
490
+/* struct type format:
491
+ *  start :         0000 | BINRPC_T_STRUCT 
492
+ *  end:            1000 | BINRPC_T_STRUCT
493
+ */
494
+#define  binrpc_start_struct(pkt) binrpc_add_tag((pkt), BINRPC_T_STRUCT, 0)
495
+
496
+#define  binrpc_end_struct(pkt) binrpc_add_tag((pkt), BINRPC_T_STRUCT, 1)
497
+
498
+#define  binrpc_start_array(pkt) binrpc_add_tag((pkt), BINRPC_T_ARRAY, 0)
499
+
500
+#define  binrpc_end_array(pkt) binrpc_add_tag((pkt), BINRPC_T_ARRAY, 1)
501
+
502
+
503
+static inline int binrpc_addfault(	struct binrpc_pkt* pkt,
504
+									int code,
505
+									char* s, int len)
506
+{
507
+	int ret;
508
+	unsigned char* bak;
509
+	
510
+	bak=pkt->crt;
511
+	if ((ret=binrpc_addint(pkt, code))<0)
512
+		return ret;
513
+	ret=binrpc_addstr(pkt, s, len);
514
+	if (ret<0)
515
+		pkt->crt=bak; /* roll back */
516
+	return ret;
517
+}
518
+
519
+/* parsing incoming messages */
520
+
521
+
522
+static inline unsigned char* binrpc_read_int(	int* i,
523
+												int len,
524
+												unsigned char* s, 
525
+												unsigned char* end,
526
+												int *err
527
+												)
528
+{
529
+	unsigned char* start;
530
+	
531
+	start=s;
532
+	*i=0;
533
+	*err=0;
534
+	for(;len>0; len--, s++){
535
+		if (s>=end){
536
+			*err=E_BINRPC_MORE_DATA;
537
+			return start;
538
+		}
539
+		*i<<=8;
540
+		*i|=*s;
541
+	};
542
+	return s;
543
+}
544
+
545
+
546
+
547
+/* initialize parsing context, it tries to read the whole message header,
548
+ * if there is not enough data, sets *err to E_BINRPC_MORE_DATA. In this
549
+ *  case just redo the call when more data is available (len is bigger)
550
+ * on success sets *err to 0 and returns the current position in  buf
551
+ * (=> you can discard the content between buf & the returned value).
552
+ * On error buf is returned back, and *err set.
553
+ */
554
+static inline unsigned char* binrpc_parse_init(	struct binrpc_parse_ctx* ctx,
555
+												unsigned char* buf,
556
+												int len,
557
+												int *err
558
+												)
559
+{
560
+	int len_len, c_len;
561
+	unsigned char *p;
562
+
563
+	*err=0;
564
+	ctx->tlen=0;	/* init to 0 */
565
+	ctx->cookie=0;	/* init to 0 */
566
+	if (len<BINRPC_MIN_PKT_SIZE){
567
+		*err=E_BINRPC_MORE_DATA;
568
+		goto error;
569
+	}
570
+	if (buf[0]!=((BINRPC_MAGIC<<4)|BINRPC_VERS)){
571
+		*err=E_BINRPC_BADPKT;
572
+		goto error;
573
+	}
574
+	ctx->type=buf[1]>>4;
575
+	/* type check */
576
+	switch(ctx->type){
577
+		case BINRPC_REQ:
578
+		case BINRPC_REPL:
579
+		case BINRPC_FAULT:
580
+			break;
581
+		default:
582
+			*err=E_BINRPC_BADPKT;
583
+			goto error;
584
+	}
585
+	len_len=((buf[1]>>2) & 3) + 1;
586
+	c_len=(buf[1]&3) + 1;
587
+	if ((BINRPC_TLEN_OFFSET+len_len+c_len)>len){
588
+		*err=E_BINRPC_MORE_DATA;
589
+		goto error;
590
+	}
591
+	p=binrpc_read_int((int*)&ctx->tlen, len_len, &buf[BINRPC_TLEN_OFFSET],
592
+						&buf[len], err);
593
+	if (ctx->tlen==0){
594
+		*err=E_BINRPC_BADPKT;
595
+		goto error;
596
+	}
597
+	p=binrpc_read_int((int*)&ctx->cookie, c_len, p, &buf[len], err);
598
+	ctx->offset=0;
599
+	ctx->flags|=BINRPC_F_INIT;
600
+	return p;
601
+error:
602
+	return buf;
603
+}
604
+
605
+
606
+
607
+/* returns bytes needed (till the end of the packet)
608
+ * on error (non. init ctx) returns < 0 
609
+ */
610
+inline static int binrpc_bytes_needed(struct binrpc_parse_ctx *ctx)
611
+{
612
+	if (ctx->flags & BINRPC_F_INIT)
613
+		return ctx->tlen-ctx->offset;
614
+	return E_BINRPC_NOTINIT;
615
+}
616
+
617
+
618
+
619
+/* prefill v with the requested type, if type==BINRPC_T_ALL it 
620
+ * will be replaced by the actual record type 
621
+ * known problems: no support for arrays inside STRUCT
622
+ * returns position after the record and *err==0 if succesfull
623
+ *         original position and *err<0 if not */
624
+inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
625
+												unsigned char* buf,
626
+												unsigned char* end,
627
+												struct binrpc_val* v,
628
+												int* err
629
+												)
630
+{
631
+	int type;
632
+	int len;
633
+	int end_tag;
634
+	int tmp;
635
+	unsigned char* p;
636
+	int i;
637
+	
638
+	p=buf;
639
+	end_tag=0;
640
+	*err=0;
641
+	if (!(ctx->flags & BINRPC_F_INIT)){
642
+		*err=E_BINRPC_NOTINIT;
643
+		goto error;
644
+	}
645
+	if (ctx->offset>=ctx->tlen){
646
+		*err=E_BINRPC_EOP;
647
+		goto error;
648
+	}
649
+	if (p>=end){
650
+		*err=E_BINRPC_MORE_DATA;
651
+		goto error;
652
+	}
653
+	/* read type_len */
654
+	type=*p & 0xf;
655
+	len=*p>>4;
656
+	p++;
657
+	if (len & 8){
658
+		end_tag=1; /* possible end mark for array or structs */
659
+		/* we have to read len bytes and use them as the new len */
660
+		p=binrpc_read_int(&len, len&7, p, end, err);
661
+		if (*err<0)
662
+			goto error;
663
+	}
664
+	if ((p+len)>end){
665
+		*err=E_BINRPC_MORE_DATA;
666
+		goto error;
667
+	}
668
+	if ((v->type!=type) && (v->type !=BINRPC_T_ALL)){
669
+		goto error_type;
670
+	}
671
+	v->type=type;
672
+	if (ctx->in_struct){
673
+		switch(type){
674
+			case BINRPC_T_STRUCT:
675
+				if (end_tag){
676
+					ctx->in_struct--;
677
+					v->u.end=1;
678
+				}else{
679
+					goto error_record;
680
+				}
681
+				break;
682
+			case BINRPC_T_AVP:
683
+				/* name | value */
684
+				v->name.s=(char*)p;
685
+				v->name.len=(len-1); /* don't include 0 term */
686
+				p+=len;
687
+				if (p>=end){
688
+					*err=E_BINRPC_MORE_DATA;
689
+					goto error;
690
+				}
691
+				/* avp value type */
692
+				type=*p & 0xf;
693
+				if ((type!=BINRPC_T_AVP) && (type!=BINRPC_T_ARRAY)){
694
+					tmp=ctx->in_struct;
695
+					ctx->in_struct=0; /* hack to parse a normal record */
696
+					v->type=type; /* hack */
697
+					p=binrpc_read_record(ctx, p, end, v, err);
698
+					if (err<0){
699
+						ctx->in_struct=tmp;
700
+						goto error;
701
+					}else{
702
+						ctx->in_struct+=tmp;
703
+						/* the offset is already updated => skip */
704
+						goto no_offs_update;
705
+					}
706
+				}else{
707
+					goto  error_record;
708
+				}
709
+				break;
710
+			default:
711
+				goto error_record;
712
+		}
713
+	}else{
714
+		switch(type){
715
+			case BINRPC_T_INT:
716
+				p=binrpc_read_int(&v->u.intval, len, p, end, err);
717
+				break;
718
+			case BINRPC_T_STR:
719
+				v->u.strval.s=(char*)p;
720
+				v->u.strval.len=(len-1); /* don't include terminating 0 */
721
+				p+=len;
722
+				break;
723
+			case BINRPC_T_BYTES:
724
+				v->u.strval.s=(char*)p;
725
+				v->u.strval.len=len;
726
+				p+=len;
727
+			case BINRPC_T_STRUCT:
728
+				if (end_tag)
729
+					goto error_record;
730
+				v->u.end=0;
731
+				ctx->in_struct++;
732
+				break;
733
+			case BINRPC_T_ARRAY:
734
+				if (end_tag){
735
+					if (ctx->in_array>0){
736
+						ctx->in_array--;
737
+						v->u.end=1;
738
+					}else
739
+						goto error_record;
740
+				}else{
741
+					ctx->in_array++;
742
+					v->u.end=0;
743
+				}
744
+				break;
745
+			case BINRPC_T_DOUBLE: /* FIXME: hack: represented as fixed point
746
+			                                      inside an int */
747
+				p=binrpc_read_int(&i, len, p, end, err);
748
+				v->u.fval=((double)i)/1000;
749
+				break;
750
+			default:
751
+				goto error_type;
752
+		}
753
+	}
754
+	ctx->offset+=(int)(p-buf);
755
+no_offs_update:
756
+	return p;
757
+error_type:
758
+	*err=E_BINRPC_TYPE;
759
+	return buf;
760
+error_record:
761
+	*err=E_BINRPC_RECORD;
762
+error:
763
+	return buf;
764
+}
765
+
766
+
767
+
768
+/* reads/skips an entire struct
769
+ * the struct start/end are saved in v->u.strval.s, v->u.strval.len 
770
+ * return:  - new buffer position  and set *err to 0 if successfull
771
+ *          - original buffer and *err<0 on error */
772
+inline static unsigned char* binrpc_read_struct(struct binrpc_parse_ctx* ctx,
773
+												unsigned char* buf,
774
+												unsigned char* end,
775
+												struct binrpc_val* v,
776
+												int* err
777
+												)
778
+{
779
+
780
+	int type;
781
+	int len;
782
+	int end_tag;
783
+	unsigned char* p;
784
+	int in_struct;
785
+	
786
+	*err=0;
787
+	p=buf;
788
+	end_tag=0;
789
+	if (!(ctx->flags & BINRPC_F_INIT)){
790
+		*err=E_BINRPC_NOTINIT;
791
+		goto error;
792
+	}
793
+	if (ctx->offset>=ctx->tlen){
794
+		*err=E_BINRPC_EOP;
795
+		goto error;
796
+	}
797
+	if (p>=end){
798
+		*err=E_BINRPC_MORE_DATA;
799
+		goto error;
800
+	}
801
+	/* read type_len */
802
+	type=*p & 0xf;
803
+	len=*p>>4;
804
+	p++;
805
+	if (len & 8){
806
+		end_tag=1; /* possible end mark for array or structs */
807
+		/* we have to read len bytes and use them as the new len */
808
+		p=binrpc_read_int(&len, len&7, p, end, err);
809
+		if (*err<0)
810
+			goto error;
811
+	}
812
+	if ((p+len)>=end){
813
+		*err=E_BINRPC_MORE_DATA;
814
+		goto error;
815
+	}
816
+	if (type!=BINRPC_T_STRUCT){
817
+		goto error_type;
818
+	}
819
+	if (end_tag){
820
+		goto error_record;
821
+	}
822
+	p+=len; /* len should be 0 for a struct tag */
823
+	in_struct=1;
824
+	v->type=type;
825
+	v->u.strval.s=(char*)p; /* it will conain the inside of the struc */
826
+	while(in_struct){
827
+		/* read name */
828
+		type=*p & 0xf;
829
+		len=*p>>4;
830
+		p++;
831
+		if (len & 8){
832
+			end_tag=1; /* possible end mark for array or structs */
833
+			/* we have to read len bytes and use them as the new len */
834
+			p=binrpc_read_int(&len, len&7, p, end, err);
835
+			if (*err<0)
836
+				goto error;
837
+		}
838
+		if ((type==BINRPC_T_STRUCT) && end_tag){
839
+			in_struct--;
840
+			if (in_struct<0)
841
+				goto error_record;
842
+			continue;
843
+		}else if (type!=BINRPC_T_AVP){
844
+			goto error_record;
845
+		}
846
+		/* skip over it */
847
+		p+=len;
848
+		if (p>=end){
849
+			*err=E_BINRPC_MORE_DATA;
850
+			goto error;
851
+		}
852
+		/* read value */
853
+		type=*p & 0xf;
854
+		len=*p>>4;
855
+		p++;
856
+		if (len & 8){
857
+			end_tag=1; /* possible end mark for array or structs */
858
+			/* we have to read len bytes and use them as the new len */
859
+			p=binrpc_read_int(&len, len&7, p, end, err);
860
+			if (*err<0)
861
+				goto error;
862
+		}
863
+		if (type==BINRPC_T_STRUCT){
864
+			if (end_tag)
865
+				goto error_record;
866
+			in_struct++;
867
+		};
868
+		p+=len;
869
+		if (p>=end){
870
+			*err=E_BINRPC_MORE_DATA;
871
+			goto error;
872
+		}
873
+	}
874
+	/* don't include the end tag */;
875
+	v->u.strval.len=(int)(p-(unsigned char*)v->u.strval.s)-1;
876
+	return p;
877
+	
878
+error_type:
879
+	*err=E_BINRPC_RECORD;
880
+	return buf;
881
+error_record:
882
+	*err=E_BINRPC_TYPE;
883
+error:
884
+	return buf;
885
+}
886
+
887
+
888
+
889
+/* error code to string */
890
+const char* binrpc_error(int err);
891
+#endif
0 892
new file mode 100644
... ...
@@ -0,0 +1,884 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2006 iptelorg GmbH
5
+ *
6
+ * This file is part of ser, a free SIP server.
7
+ *
8
+ * ser is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser software under conditions
14
+ * other than those described here, or to purchase support for this
15
+ * software, please contact iptel.org by e-mail at the following addresses:
16
+ *    info@iptel.org
17
+ *
18
+ * ser is distributed in the hope that it will be useful,
19
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
+ * GNU General Public License for more details.
22
+ *
23
+ * You should have received a copy of the GNU General Public License 
24
+ * along with this program; if not, write to the Free Software 
25
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
+ */
27
+/* History:
28
+ * --------
29
+ *  2006-02-08  created by andrei
30
+ */
31
+
32
+
33
+#include "binrpc.h"
34
+#include "../../dprint.h"
35
+#include "../../rpc.h"
36
+#include "../../sr_module.h"
37
+#include "../../mem/mem.h"
38
+#include "../../clist.h"
39
+#include "io_listener.h"
40
+
41
+#include <stdio.h>  /* vsnprintf */
42
+#include <stdarg.h>
43
+
44
+#define BINRPC_MAX_BODY	4096  /* maximum body for send */
45
+#define STRUCT_MAX_BODY	1024
46
+#define MAX_MSG_CHUNKS	96
47
+
48
+struct rpc_struct_head{
49
+	struct rpc_struct_l* next;
50
+	struct rpc_struct_l* prev;
51
+};
52
+
53
+
54
+struct rpc_struct_l{
55
+	struct rpc_struct_l* next;
56
+	struct rpc_struct_l* prev;
57
+	struct binrpc_pkt pkt;
58
+	struct rpc_struct_head substructs; /* head */
59
+	int offset; /* byte offset in parent's pkt */
60
+};
61
+
62
+struct binrpc_send_ctx{
63
+	struct binrpc_pkt pkt; /* body */
64
+	struct rpc_struct_head structs; /* list head */
65
+};
66
+
67
+struct binrpc_recv_ctx{
68
+	struct binrpc_parse_ctx ctx;
69
+	unsigned char*  s; /* current position in buffer */
70
+	unsigned char* end;
71
+	int record_no;
72
+	int in_struct;
73
+};
74
+
75
+struct binrpc_ctx{
76
+	struct binrpc_recv_ctx in;
77
+	struct binrpc_send_ctx out;
78
+	void* send_h; /* send handle */
79
+	char* method;
80
+	int replied;
81
+};
82
+
83
+
84
+struct iovec_array{
85
+	struct iovec* v;
86
+	int idx;
87
+	int len;
88
+};
89
+
90
+/* send */
91
+static void rpc_fault(struct binrpc_ctx* ctx, int code, char* fmt, ...);
92
+static int rpc_send(struct binrpc_ctx* ctx);
93
+static int rpc_add(struct binrpc_ctx* ctx, char* fmt, ...);
94
+static int rpc_scan(struct binrpc_ctx* ctx, char* fmt, ...);
95
+static int rpc_printf(struct binrpc_ctx* ctx, char* fmt, ...);
96
+static int rpc_struct_add(struct rpc_struct_l* s, char* fmt, ...);
97
+static int rpc_struct_scan(struct rpc_struct_l* s, char* fmt, ...);
98
+/* struct scan */
99
+static int rpc_struct_printf(struct rpc_struct_l *s, char* name,
100
+								char* fmt, ...);
101
+
102
+
103
+static rpc_t binrpc_callbacks={
104
+	(rpc_fault_f)			rpc_fault,
105
+	(rpc_send_f)			rpc_send,
106
+	(rpc_add_f)				rpc_add,
107
+	(rpc_scan_f)			rpc_scan,
108
+	(rpc_printf_f)			rpc_printf,
109
+	(rpc_struct_add_f)		rpc_struct_add,
110
+	(rpc_struct_scan_f)		rpc_struct_scan,
111
+	(rpc_struct_printf_f)	rpc_struct_printf
112
+};
113
+
114
+
115
+
116
+static struct rpc_struct_l* new_rpc_struct()
117
+{
118
+	struct rpc_struct_l* rs;
119
+	
120
+	/* alloc everything in one chunk */
121
+	rs=pkg_malloc(sizeof(struct rpc_struct_l)+STRUCT_MAX_BODY);
122
+	if (rs==0)
123
+		goto error;
124
+	memset(rs, 0, sizeof(struct rpc_struct_l));
125
+	clist_init(&rs->substructs, next, prev);
126
+	if (binrpc_init_pkt(&rs->pkt,
127
+				(unsigned char*)rs+sizeof(struct rpc_struct_l),
128
+				STRUCT_MAX_BODY)<0){
129
+		pkg_free(rs);
130
+		goto error;
131
+	}
132
+	return rs;
133
+error:
134
+	return 0;
135
+}
136
+
137
+
138
+
139
+/* doubles the size */
140
+static struct rpc_struct_l* grow_rpc_struct(struct rpc_struct_l *rs)
141
+{
142
+	
143
+	struct rpc_struct_l* new_rs;
144
+	int csize; /* body */
145
+	
146
+	csize=binrpc_pkt_len(&rs->pkt);
147
+	csize*=2;
148
+	new_rs=pkg_realloc(rs, sizeof(struct rpc_struct_l)+csize);
149
+	if (new_rs){
150
+		binrpc_pkt_update_buf(&rs->pkt, 
151
+							(unsigned char*)new_rs+sizeof(struct rpc_struct_l),
152
+							csize);
153
+	}
154
+	return new_rs;
155
+}
156
+
157
+
158
+
159
+/* appends buf to an already init. binrpc_pkt */
160
+inline static int append_pkt_body(struct binrpc_pkt* p, unsigned char* buf,
161
+							int len)
162
+{
163
+	
164
+	if ((int)(p->end-p->crt)<len){
165
+		goto error;
166
+#if 0
167
+		size=2*(int)(p->end-p->body);
168
+		offset=binrpc_pkt_len(p);
169
+		for(;(size-offset)<len; size*=2); /* find new size */
170
+		new_b=pkg_realloc(p->body, size);
171
+		if (new_b==0)
172
+			goto error;
173
+		binrpc_pkt_update_buf(p, new_b, size);
174
+#endif
175
+	}
176
+	memcpy(p->crt, buf, len);
177
+	p->crt+=len;
178
+	return 0;
179
+error:
180
+	return -1; /* buff. overflow */
181
+}
182
+
183
+
184
+
185
+inline static int append_iovec(struct iovec_array* a, unsigned char* buf,
186
+								int len)
187
+{
188
+	
189
+	if (a->idx >= a->len)
190
+		goto error;
191
+	a->v[a->idx].iov_base=buf;
192
+	a->v[a->idx].iov_len=len;
193
+	a->idx++;
194
+	return 0;
195
+error:
196
+	return -1; /* overflow */
197
+}
198
+
199
+
200
+
201
+static int body_get_len(struct binrpc_pkt* body,
202
+							struct rpc_struct_head* sl_head)
203
+{
204
+	struct rpc_struct_l* l;
205
+	int len;
206
+	
207
+	len=binrpc_pkt_len(body);
208
+	clist_foreach(sl_head, l, next){
209
+		len+=body_get_len(&l->pkt, &l->substructs);
210
+	}
211
+	return len;
212
+}
213
+
214
+
215
+
216
+static int body_fill_iovec(struct iovec_array* v_a,
217
+							struct binrpc_pkt* body, 
218
+							struct rpc_struct_head* sl_head)
219
+{
220
+	int offs;
221
+	struct rpc_struct_l* l;
222
+	int ret;
223
+	
224
+	offs=0;
225
+	clist_foreach(sl_head, l, next){
226
+		if ((ret=append_iovec(v_a, body->body+offs, l->offset-offs))<0)
227
+			goto error;
228
+		offs=l->offset;
229
+		if ((ret=body_fill_iovec(v_a, &l->pkt, &l->substructs))<0)
230
+			goto error;
231
+	};
232
+	/* copy the rest */
233
+	ret=append_iovec(v_a, body->body+offs, binrpc_pkt_len(body)-offs);
234
+error:
235
+	return ret;
236
+}
237
+
238
+
239
+
240
+/* expects an initialized new_b */
241
+static int build_structs(struct binrpc_pkt *new_b, struct binrpc_pkt* body, 
242
+							struct rpc_struct_head* sl_head)
243
+{
244
+	int offs;
245
+	struct rpc_struct_l* l;
246
+	int ret;
247
+	
248
+	offs=0;
249
+	clist_foreach(sl_head, l, next){
250
+		if ((ret=append_pkt_body(new_b, body->body+offs, l->offset-offs))<0)
251
+			goto error;
252
+		offs=l->offset;
253
+		if ((ret=build_structs(new_b, &l->pkt, &l->substructs))<0)
254
+			goto error;
255
+	};
256
+	/* copy the rest */
257
+	ret=append_pkt_body(new_b, body->body+offs, binrpc_pkt_len(body)-offs);
258
+error:
259
+	return ret;
260
+}
261
+
262
+
263
+
264
+static void free_structs(struct rpc_struct_head* sl_head)
265
+{
266
+	struct rpc_struct_l* l;
267
+	struct rpc_struct_l* tmp;
268
+	
269
+	clist_foreach_safe(sl_head, l, tmp, next){
270
+		free_structs(&l->substructs);
271
+		memset(l, 0, sizeof(struct rpc_struct_l)); /* debugging */
272
+		pkg_free(l);
273
+	};
274
+}
275
+
276
+
277
+
278
+inline static int init_binrpc_ctx(	struct binrpc_ctx* ctx,
279
+									unsigned char* recv_buf,
280
+									int recv_buf_len,
281
+									void* send_handle
282
+								)
283
+{
284
+	int err;
285
+	unsigned char* send_buf;
286
+	int send_buf_len;
287
+	
288
+	memset(ctx, 0, sizeof(struct binrpc_ctx));
289
+	clist_init(&ctx->out.structs, next, prev);
290
+	ctx->send_h=send_handle;
291
+	ctx->in.end=recv_buf+recv_buf_len;
292
+	ctx->in.s=binrpc_parse_init(&ctx->in.ctx, recv_buf, recv_buf_len, &err);
293
+	if (err<0) goto end;
294
+	if ((ctx->in.ctx.tlen+(int)(ctx->in.s-recv_buf))>recv_buf_len){
295
+		err=E_BINRPC_MORE_DATA;
296
+		goto end;
297
+	}
298
+	
299
+	/* alloc temporary body buffer */
300
+	send_buf_len=BINRPC_MAX_BODY;
301
+	send_buf=pkg_malloc(send_buf_len);
302
+	if (send_buf==0){
303
+		err=E_BINRPC_LAST;
304
+		goto end;
305
+	}
306
+	/* we'll keep only the body */
307
+	err=binrpc_init_pkt(&ctx->out.pkt, send_buf, send_buf_len);
308
+end:
309
+	return err;
310
+}
311
+
312
+
313
+
314
+inline void destroy_binrpc_ctx(struct binrpc_ctx* ctx)
315
+{
316
+	free_structs(&ctx->out.structs);
317
+	if (ctx->out.pkt.body){
318
+		pkg_free(ctx->out.pkt.body);
319
+		ctx->out.pkt.body=0;
320
+	}
321
+}
322
+
323
+
324
+
325
+#define MAX_FAULT_LEN 256
326
+#define FAULT_START_BUF (3 /* maxint*/+2/*max str header*/)
327
+static void rpc_fault(struct binrpc_ctx* ctx, int code, char* fmt, ...)
328
+{
329
+	char buf[MAX_FAULT_LEN];
330
+	static unsigned char fault_start[FAULT_START_BUF];
331
+	static unsigned char hdr[BINRPC_MAX_HDR_SIZE];
332
+	struct iovec v[3];
333
+	struct binrpc_pkt body;
334
+	int b_len;
335
+	va_list ap;
336
+	int len;
337
+	int hdr_len;
338
+	int err;
339
+	
340
+	if (ctx->replied){
341
+		LOG(L_ERR, "ERROR: binrpc: rpc_send: rpc method %s tried to reply"
342
+					" more then once\n", ctx->method?ctx->method:"");
343
+		return;
344
+	}
345
+	err=0;
346
+	va_start(ap, fmt);
347
+	len=vsnprintf(buf, MAX_FAULT_LEN, fmt, ap); /* ignore trunc. errors */
348
+	if ((len<0) || (len > MAX_FAULT_LEN))
349
+		len=MAX_FAULT_LEN-1;
350
+	va_end(ap);
351
+	
352
+	len++; /* vnsprintf doesn't include the terminating 0 */
353
+	err=binrpc_init_pkt(&body, fault_start, FAULT_START_BUF);
354
+	if (err<0){
355
+		LOG(L_ERR, "ERROR: binrpc_init_pkt error\n");
356
+		goto error;
357
+	}
358
+	/* adding a fault "manually" to avoid extra memcpys */
359
+	err=binrpc_addint(&body, code);
360
+	if (err<0){
361
+		LOG(L_ERR, "ERROR: rpc_fault: addint error\n");
362
+		goto error;
363
+	}
364
+	err=binrpc_add_str_mark(&body, BINRPC_T_STR, len);
365
+	if (err<0){
366
+		LOG(L_ERR, "ERROR: rpc_fault: add_str_mark error\n");
367
+		goto error;
368
+	}
369
+	/*
370
+	err=binrpc_addfault(&body, code, buf, len); 
371
+	if (err<0){
372
+		LOG(L_ERR, "ERROR: binrpc_addfault error\n");
373
+		goto error;
374
+	}*/
375
+	b_len=binrpc_pkt_len(&body);
376
+	err=hdr_len=binrpc_build_hdr(BINRPC_FAULT, b_len+len,
377
+								ctx->in.ctx.cookie, hdr, BINRPC_MAX_HDR_SIZE);
378
+	if (err<0){
379
+		LOG(L_ERR, "ERROR: binrpc_build_hdr error\n");
380
+		goto error;
381
+	}
382
+	v[0].iov_base=hdr;
383
+	v[0].iov_len=hdr_len;
384
+	v[1].iov_base=body.body;
385
+	v[1].iov_len=b_len;
386
+	v[2].iov_base=buf;
387
+	v[2].iov_len=len;
388
+	if ((err=sock_send_v(ctx->send_h, v, 3))<0){
389
+		if (err==-2){
390
+			LOG(L_ERR, "ERROR: binrpc_fault: send failed: "
391
+					"datagram too big\n");
392
+			return;
393
+		}
394
+		LOG(L_ERR, "ERROR: binrpc_fault: send failed\n");
395
+		return;
396
+	}
397
+	ctx->replied=1;
398
+	return;
399
+error:
400
+	LOG(L_ERR, "ERROR: binrpc_fault: binrpc_* failed with: %s (%d)\n",
401
+			binrpc_error(err), err);
402
+}
403
+
404
+
405
+
406
+/* build the reply from the current body */
407
+static int rpc_send(struct binrpc_ctx* ctx)
408
+{
409
+	int b_len;
410
+	int hdr_len;
411
+	struct iovec v[MAX_MSG_CHUNKS];
412
+	struct iovec_array a;
413
+	static unsigned char hdr[BINRPC_MAX_HDR_SIZE];
414
+	int err;
415
+	
416
+	err=0;
417
+	a.v=v;
418
+	a.idx=1;
419
+	a.len=MAX_MSG_CHUNKS;
420
+	
421
+	if (ctx->replied){
422
+		LOG(L_ERR, "ERROR: binrpc: rpc_send: rpc method %s tried to reply"
423
+					" more then once\n", ctx->method?ctx->method:"");
424
+		goto error;
425
+	}
426
+	b_len=body_get_len(&ctx->out.pkt, &ctx->out.structs);
427
+	err=hdr_len=binrpc_build_hdr( BINRPC_REPL, b_len, ctx->in.ctx.cookie,
428
+									hdr, BINRPC_MAX_HDR_SIZE);
429
+	if (err<0){
430
+		LOG(L_ERR, "ERROR: binrpc: rpc_fault: binrpc_* failed with:"
431
+					" %s (%d)\n", binrpc_error(err), err);
432
+		goto error;
433
+	}
434
+	v[0].iov_base=hdr;
435
+	v[0].iov_len=hdr_len;
436
+	/* fill the rest of the iovecs */
437
+	err=body_fill_iovec(&a, &ctx->out.pkt, &ctx->out.structs);
438
+	if (err<0){
439
+		LOG(L_ERR, "ERROR: binrprc: rpc_send: too many message chunks\n");
440
+		goto error;
441
+	}
442
+	if ((err=sock_send_v(ctx->send_h, v, a.idx))<0){
443
+		if (err==-2){
444
+			LOG(L_ERR, "ERROR: binrpc: rpc_send: send failed: "
445
+					"datagram too big\n");
446
+			goto error;