Browse code

ctl: skip checking end tag for BINRPC_T_DOUBLE values

- related to GH #3123

Daniel-Constantin Mierla authored on 02/06/2022 10:48:38
Showing 1 changed files
... ...
@@ -730,7 +730,7 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
730 730
 	type=*p & 0xf;
731 731
 	len=*p>>4;
732 732
 	p++;
733
-	if (len & 8){
733
+	if ((type!=BINRPC_T_DOUBLE) && (len & 8)){
734 734
 		end_tag=1; /* possible end mark for array or structs */
735 735
 		/* we have to read len bytes and use them as the new len */
736 736
 		p=binrpc_read_int(&len, len&7, p, end, err);
Browse code

ctl: Fix typos

Bastian Triller authored on 05/05/2022 16:24:21 • Henning Westerholt committed on 08/05/2022 15:30:14
Showing 1 changed files
... ...
@@ -694,7 +694,7 @@ inline static int binrpc_bytes_needed(struct binrpc_parse_ctx *ctx)
694 694
  * known problems: no support for arrays inside STRUCT
695 695
  * param smode: allow simple vals inside struct (needed for 
696 696
  * not-strict-formatted rpc responses)
697
- * returns position after the record and *err==0 if succesfull
697
+ * returns position after the record and *err==0 if successful
698 698
  *         original position and *err<0 if not */
699 699
 inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
700 700
 												unsigned char* buf,
... ...
@@ -829,7 +829,7 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
829 829
 			}
830 830
 			break;
831 831
 		case BINRPC_T_DOUBLE: /* FIXME: hack: represented as fixed point
832
-		                                      inside an long long */
832
+		                                      inside a long long */
833 833
 			if (ctx->in_struct && smode==0) goto error_record;
834 834
 			p=binrpc_read_llong(&ll, len, p, end, err);
835 835
 			v->u.fval=((double)ll)/1000;
Browse code

ctl: float/double values are stored over a long long int instead of int

- cope with larger values than MAX_INT/1000, supporint now
up to MAX_LLONG/1000

Daniel-Constantin Mierla authored on 12/01/2022 16:02:11
Showing 1 changed files
... ...
@@ -205,6 +205,31 @@ inline static int binrpc_add_tag(struct binrpc_pkt* pkt, int type, int end)
205 205
 
206 206
 
207 207
 
208
+/*  writes a minimal long long, returns the new offset and sets
209
+ * len to the number of bytes written (<=8)
210
+ * to check for oveflow use:  returned_value-p != *len
211
+ * (Note: if *len==0 using the test above succeeds even if p>=end)
212
+ */
213
+inline static unsigned char* binrpc_write_llong(	unsigned char* p,
214
+												unsigned char* end,
215
+												long long i, int *len)
216
+{
217
+	int size;
218
+	unsigned long long u;
219
+
220
+	u = (unsigned long long)i;
221
+
222
+	for (size=8; size && ((u & (0xffull<<56))==0); u<<=8, size--);
223
+	*len=size;
224
+	for(; (p<end) && (size); p++, size--){
225
+		*p=(unsigned char)(u>>56);
226
+		u<<=8;
227
+	}
228
+	return p;
229
+}
230
+
231
+
232
+
208 233
 /*  writes a minimal int, returns the new offset and sets
209 234
  * len to the number of bytes written (<=4)
210 235
  * to check for oveflow use:  returned_value-p != *len
... ...
@@ -330,6 +355,23 @@ inline static int binrpc_hdr_change_len(unsigned char* hdr, int hdr_len,
330 355
 }
331 356
 
332 357
 
358
+/* int format:     size TYPE <val>  */
359
+inline static int binrpc_add_llong_type(struct binrpc_pkt* pkt, long long i, int type)
360
+{
361
+
362
+	unsigned char* p;
363
+	int size;
364
+
365
+	p=binrpc_write_llong(pkt->crt+1, pkt->end, i, &size);
366
+	if ((pkt->crt>=pkt->end) || ((int)(p-pkt->crt-1)!=size))
367
+		goto error_len;
368
+	*(pkt->crt)=(size<<4) | type;
369
+	pkt->crt=p;
370
+	return 0;
371
+error_len:
372
+	return E_BINRPC_OVERFLOW;
373
+}
374
+
333 375
 
334 376
 /* int format:     size BINRPC_T_INT <val>  */
335 377
 inline static int binrpc_add_int_type(struct binrpc_pkt* pkt, int i, int type)
... ...
@@ -351,9 +393,9 @@ error_len:
351 393
 
352 394
 
353 395
 /* double format:  FIXME: for now a hack: fixed point represented in
354
- *  an int (=> max 3 decimals, < MAX_INT/1000) */
396
+ *  a long long (=> max 3 decimals, < MAX_LLONG/1000) */
355 397
 #define binrpc_add_double_type(pkt, f, type)\
356
-	binrpc_add_int_type((pkt), (int)((f)*1000), (type))
398
+	binrpc_add_llong_type((pkt), (long long)((f)*1000), (type))
357 399
 
358 400
 
359 401
 
... ...
@@ -516,6 +558,35 @@ static inline int binrpc_addfault(	struct binrpc_pkt* pkt,
516 558
 /* parsing incoming messages */
517 559
 
518 560
 
561
+static inline unsigned char* binrpc_read_llong(	long long* i,
562
+												int len,
563
+												unsigned char* s,
564
+												unsigned char* end,
565
+												int *err
566
+												)
567
+{
568
+	unsigned char* start;
569
+	unsigned long long u;
570
+
571
+	start=s;
572
+	*i=0;
573
+	u = 0;
574
+	*err=0;
575
+	for(;len>0; len--, s++){
576
+		if (s>=end){
577
+			*err=E_BINRPC_MORE_DATA;
578
+			*i = (long long)u;
579
+			return start;
580
+		}
581
+		u<<=8;
582
+		u|=*s;
583
+	};
584
+	*i = (long long)u;
585
+	return s;
586
+}
587
+
588
+
589
+
519 590
 static inline unsigned char* binrpc_read_int(	int* i,
520 591
 												int len,
521 592
 												unsigned char* s,
... ...
@@ -638,8 +709,8 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
638 709
 	int end_tag;
639 710
 	int tmp;
640 711
 	unsigned char* p;
641
-	int i;
642
-	
712
+	long long ll;
713
+
643 714
 	p=buf;
644 715
 	end_tag=0;
645 716
 	*err=0;
... ...
@@ -758,10 +829,10 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
758 829
 			}
759 830
 			break;
760 831
 		case BINRPC_T_DOUBLE: /* FIXME: hack: represented as fixed point
761
-		                                      inside an int */
832
+		                                      inside an long long */
762 833
 			if (ctx->in_struct && smode==0) goto error_record;
763
-			p=binrpc_read_int(&i, len, p, end, err);
764
-			v->u.fval=((double)i)/1000;
834
+			p=binrpc_read_llong(&ll, len, p, end, err);
835
+			v->u.fval=((double)ll)/1000;
765 836
 			break;
766 837
 		default:
767 838
 			if (ctx->in_struct){
Browse code

ctl: use unsigned int for bit left shifting

- deal with runtime error: left shift of X by N places cannot be represented in type 'int'

Daniel-Constantin Mierla authored on 14/11/2021 19:23:08
Showing 1 changed files
... ...
@@ -215,12 +215,15 @@ inline static unsigned char* binrpc_write_int(	unsigned char* p,
215 215
 												int i, int *len)
216 216
 {
217 217
 	int size;
218
+	unsigned int u;
218 219
 
219
-	for (size=4; size && ((i & (0xffu<<24))==0); i<<=8, size--);
220
+	u = (unsigned int)i;
221
+
222
+	for (size=4; size && ((u & (0xffu<<24))==0); u<<=8, size--);
220 223
 	*len=size;
221 224
 	for(; (p<end) && (size); p++, size--){
222
-		*p=(unsigned char)(i>>24);
223
-		i<<=8;
225
+		*p=(unsigned char)(u>>24);
226
+		u<<=8;
224 227
 	}
225 228
 	return p;
226 229
 }
... ...
@@ -515,24 +518,28 @@ static inline int binrpc_addfault(	struct binrpc_pkt* pkt,
515 518
 
516 519
 static inline unsigned char* binrpc_read_int(	int* i,
517 520
 												int len,
518
-												unsigned char* s, 
521
+												unsigned char* s,
519 522
 												unsigned char* end,
520 523
 												int *err
521 524
 												)
522 525
 {
523 526
 	unsigned char* start;
524
-	
527
+	unsigned int u;
528
+
525 529
 	start=s;
526 530
 	*i=0;
531
+	u = 0;
527 532
 	*err=0;
528 533
 	for(;len>0; len--, s++){
529 534
 		if (s>=end){
530 535
 			*err=E_BINRPC_MORE_DATA;
536
+			*i = (int)u;
531 537
 			return start;
532 538
 		}
533
-		*i<<=8;
534
-		*i|=*s;
539
+		u<<=8;
540
+		u|=*s;
535 541
 	};
542
+	*i = (int)u;
536 543
 	return s;
537 544
 }
538 545
 
Browse code

ctl: use unsigned literals for left bit shifting

Daniel-Constantin Mierla authored on 10/11/2021 19:09:24
Showing 1 changed files
... ...
@@ -188,7 +188,7 @@ struct binrpc_val{
188 188
 inline static int binrpc_get_int_len(int i)
189 189
 {
190 190
 	int size;
191
-	for (size=4; size && ((i & (0xff<<24))==0); i<<=8, size--);
191
+	for (size=4; size && ((i & (0xffu<<24))==0); i<<=8, size--);
192 192
 	return size;
193 193
 }
194 194
 
... ...
@@ -216,7 +216,7 @@ inline static unsigned char* binrpc_write_int(	unsigned char* p,
216 216
 {
217 217
 	int size;
218 218
 
219
-	for (size=4; size && ((i & (0xff<<24))==0); i<<=8, size--);
219
+	for (size=4; size && ((i & (0xffu<<24))==0); i<<=8, size--);
220 220
 	*len=size;
221 221
 	for(; (p<end) && (size); p++, size--){
222 222
 		*p=(unsigned char)(i>>24);
Browse code

ctl: small spelling fix in comment

Henning Westerholt authored on 14/05/2020 16:38:31
Showing 1 changed files
... ...
@@ -136,7 +136,7 @@
136 136
 								  more bytes available */
137 137
 #define E_BINRPC_EOP		-5	/* end of packet reached */
138 138
 #define E_BINRPC_NOTINIT	-6  /* parse ctx not initialized */
139
-#define E_BINRPC_TYPE		-7  /* unkown type for record, or requested
139
+#define E_BINRPC_TYPE		-7  /* unknown type for record, or requested
140 140
 								   type doesn't match record type */
141 141
 #define E_BINRPC_RECORD		-8  /* bad record (unexpected, bad struct a.s.o)*/
142 142
 #define E_BINRPC_BUG		-9  /* internal error, bug */
Browse code

ctl: spelling fix in comments (usefull -> useful)

Henning Westerholt authored on 29/09/2019 21:15:11
Showing 1 changed files
... ...
@@ -434,7 +434,7 @@ error_len:
434 434
 
435 435
 
436 436
 
437
-/* adds an avp (name, value) pair, usefull to add structure members */
437
+/* adds an avp (name, value) pair, useful to add structure members */
438 438
 inline static int binrpc_addavp(struct binrpc_pkt* pkt, struct binrpc_val* avp)
439 439
 {
440 440
 	int ret;
Browse code

ctl: close opened sockets in case of errors

Daniel-Constantin Mierla authored on 27/07/2017 07:15:00
Showing 1 changed files
... ...
@@ -705,7 +705,7 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
705 705
 					ctx->in_struct=0; /* hack to parse a normal record */
706 706
 					v->type=type; /* hack */
707 707
 					p=binrpc_read_record(ctx, p, end, v, smode, err);
708
-					if (err<0){
708
+					if (*err<0){
709 709
 						ctx->in_struct=tmp;
710 710
 						goto error;
711 711
 					}else{
... ...
@@ -735,6 +735,7 @@ inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
735 735
 			v->u.strval.s=(char*)p;
736 736
 			v->u.strval.len=len;
737 737
 			p+=len;
738
+			break;
738 739
 		case BINRPC_T_ARRAY:
739 740
 			if (ctx->in_struct && smode==0) goto error_record;
740 741
 			if (end_tag){
Browse code

ctl: handle null string value in rpc response

Daniel-Constantin Mierla authored on 06/01/2017 07:40:17
Showing 1 changed files
... ...
@@ -359,7 +359,7 @@ error_len:
359 359
  */
360 360
 inline static int binrpc_add_skip(struct binrpc_pkt* pkt, int bytes)
361 361
 {
362
-	
362
+
363 363
 	if ((pkt->crt+bytes)>=pkt->end)
364 364
 		return E_BINRPC_OVERFLOW;
365 365
 	pkt->crt+=bytes;
... ...
@@ -373,7 +373,7 @@ inline static int binrpc_add_skip(struct binrpc_pkt* pkt, int bytes)
373 373
  * manually later (and also use binrpc_add_skip(pkt, l) or increase
374 374
  *  pkt->crt directly if you want to continue adding to this pkt).
375 375
  *  Usefull for optimizing str writing (e.g. writev(iovec))
376
- *  WARNING: use with care, low level function, binrpc_addstr or 
376
+ *  WARNING: use with care, low level function, binrpc_addstr or
377 377
  *           binrpc_add_str_type are probably what you want.
378 378
  *  WARNING1: BINRPC_T_STR and BINRPC_T_AVP must be  0 term, the len passed to
379 379
  *            this function, must include the \0 in this case.
... ...
@@ -383,7 +383,7 @@ inline static int binrpc_add_str_mark(struct binrpc_pkt* pkt, int type,
383 383
 {
384 384
 	int size;
385 385
 	unsigned char* p;
386
-	
386
+
387 387
 	if (pkt->crt>=pkt->end) goto error_len;
388 388
 	if (l<8){
389 389
 		size=l;
... ...
@@ -410,7 +410,7 @@ inline static int binrpc_add_str_type(struct binrpc_pkt* pkt, char* s, int len,
410 410
 	int l;
411 411
 	int zero_term; /* whether or not to add an extra 0 at the end */
412 412
 	unsigned char* p;
413
-	
413
+
414 414
 	zero_term=((type==BINRPC_T_STR)||(type==BINRPC_T_AVP));
415 415
 	l=len+zero_term;
416 416
 	if (l<8){
... ...
@@ -439,7 +439,7 @@ inline static int binrpc_addavp(struct binrpc_pkt* pkt, struct binrpc_val* avp)
439 439
 {
440 440
 	int ret;
441 441
 	unsigned char* bak;
442
-	
442
+
443 443
 	bak=pkt->crt;
444 444
 	ret=binrpc_add_str_type(pkt, avp->name.s, avp->name.len, BINRPC_T_AVP);
445 445
 	if (ret<0) return ret;
... ...
@@ -449,7 +449,7 @@ inline static int binrpc_addavp(struct binrpc_pkt* pkt, struct binrpc_val* avp)
449 449
 			break;
450 450
 		case BINRPC_T_STR:
451 451
 		case BINRPC_T_BYTES:
452
-			ret=binrpc_add_str_type(pkt, avp->u.strval.s, 
452
+			ret=binrpc_add_str_type(pkt, avp->u.strval.s,
453 453
 										avp->u.strval.len,
454 454
 										avp->type);
455 455
 			break;
... ...
@@ -457,7 +457,7 @@ inline static int binrpc_addavp(struct binrpc_pkt* pkt, struct binrpc_val* avp)
457 457
 		case BINRPC_T_ARRAY:
458 458
 			ret=binrpc_add_tag(pkt, avp->type, 0);
459 459
 			break;
460
-		case BINRPC_T_DOUBLE: 
460
+		case BINRPC_T_DOUBLE:
461 461
 			ret=binrpc_add_double_type(pkt, avp->u.fval, avp->type);
462 462
 			break;
463 463
 		default:
Browse code

core, lib, modules: updated include paths for header files

Daniel-Constantin Mierla authored on 07/12/2016 11:07:22
Showing 1 changed files
... ...
@@ -94,7 +94,7 @@
94 94
 #define _binrpc_h
95 95
 
96 96
 
97
-#include "../../str.h"
97
+#include "../../core/str.h"
98 98
 #include <string.h>
99 99
 
100 100
 #define BINRPC_MAGIC 0xA
Browse code

core, lib, modules: restructured source code tree

- new folder src/ to hold the source code for main project applications
- main.c is in src/
- all core files are subfolder are in src/core/
- modules are in src/modules/
- libs are in src/lib/
- application Makefiles are in src/
- application binary is built in src/ (src/kamailio)

Daniel-Constantin Mierla authored on 07/12/2016 11:03:51
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,902 @@
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
+/* binrpc is  supposed to be a minimalist binary rpc implementation */
22
+
23
+
24
+
25
+/* packet header:
26
+ * (big endian where it applies)
27
+ *      4b      4b        4b     2b   2b       <var>          <var>
28
+ *  | MAGIC  | VERS  || FLAGS  | LL | CL || total_len ... || cookie ... |
29
+ *  total_len = payload len (doesn't include the packet header)
30
+ *  LL = total length len -1 (number of bytes on which total len is
31
+ *        represented)
32
+ *  CL = cookie length -1 (number of bytes on which the cookie is represented)
33
+ *  E.g.: LL= 0 => total_len is represented on 1 byte (LL+1)
34
+ *        CL= 3 => cookie is represneted on 4 bytes (CL+1)
35
+ */
36
+/* record format:
37
+ *  1b   3b     4b
38
+ * |S | size |  type  || <optional value len> ... || <optional value> ... ||
39
+ *
40
+ * if S==0, size is the size (in bytes) of the value (if size==0 => null value)
41
+ * if S==1, optional_value_len is present, and size is it's size
42
+ *    (if size==0 => and type==array or struct => marks end, else
43
+ *     error, reserved)
44
+ *  Examples:
45
+ *     int (type=0) 0x1234     -> 0x20 0x12 0x34           (optimal)
46
+ *                                0x90 0x02 0x12 0x34      (suboptimal)
47
+ *                                0xA0 0x00 0x02 0x12 0x34 (even worse)
48
+ *                   0x07      -> 0x10 0x07                (optimal)
49
+ *                   0x00      -> 0x00                     (optimal)
50
+ *                                0x10 0x00
51
+ *
52
+ *     str (type=1) - strings are 0 terminated (an extra 0 is added to them
53
+ *                    to make the format easier to parse when asciiz strings
54
+ *                    are required); the length includes the terminating 0
55
+ *                  "abcdef"   -> 0x71 "abcdef" 0x00
56
+ *                  "abcdefhij"-> 0x91 0x0A "abcdefhij" 0x00
57
+ *                  ""         -> 0x11 0x00     (0 len str)
58
+ *     65535 bytes
59
+ *     (using str for it)      -> 0xB1 0x01 0x00 0x00 array 0x00
60
+ *
61
+ *     bytes (type=6) -like str but not 0 terminated
62
+ *                  "abcdef"   -> 0x66 "abcdef"
63
+ *     65535 bytes   *         -> 0xA6 0xff 0xff bytes
64
+ *
65
+ *     arrays (array type=4)
66
+ *       arrays are implemented as anonymous value lists:
67
+ *         array_start value1, value2, ..., array_end
68
+ *                               (start) (1st int)  (2nd elem)  (end array)
69
+ *      ints   [ 0x01 0x02 ]   -> 0x04   0x10 0x01  0x10 0x02        0x84
70
+ *      combo  [ 0x07 "abc"]   -> 0x04   0x10 0x07  0x41 "abc" 0x00  0x84
71
+ *
72
+ *      structs (struct type=3)
73
+ *       structs are implemented as avp list:
74
+ *           struct_start, avp1, avp2 .., struct_end
75
+ *        an avp is a named value pair:  name, value. 
76
+ *          - name behaves like a normal string, but has a diff. type (5)
77
+ *          - avps are legal only inside structs.
78
+ *        avp example:           name part (str)   val part (int here) 
79
+ *         "test", int 0x0b   -> 0x55 "test" 0x00   0x10 0x0b
80
+ *
81
+ *      struct example:
82
+ *                              (start)  (avps)                           (end)
83
+ *      struct{                  0x03        (name )        (val)
84
+ *           intval: int 0x3  ->       0x75 "intval" 0x00 0x10 0x3
85
+ *           s:      str "abc"-        0x25 "s" 0x00      0x41 "abc" 0x00
86
+ *      }                                                                  0x83
87
+ *
88
+ *      Limitations: for now avps cannot have array values =>
89
+ *                   structs cannot contain arrays.
90
+ */
91
+
92
+
93
+#ifndef _binrpc_h
94
+#define _binrpc_h
95
+
96
+
97
+#include "../../str.h"
98
+#include <string.h>
99
+
100
+#define BINRPC_MAGIC 0xA
101
+#define BINRPC_VERS  1
102
+
103
+/* sizes & offsets */
104
+#define BINRPC_FIXED_HDR_SIZE	2
105
+#define BINRPC_TLEN_OFFSET		BINRPC_FIXED_HDR_SIZE
106
+#define BINRPC_MIN_HDR_SIZE	(BINRPC_FIXED_HDR_SIZE+2)
107
+#define BINRPC_MAX_HDR_SIZE	(BINRPC_FIXED_HDR_SIZE+4+4)
108
+#define BINRPC_MIN_RECORD_SIZE	1
109
+/* min pkt size: min header + min. len (1) + min. cookie (1)*/
110
+#define BINRPC_MIN_PKT_SIZE	BINRPC_MIN_HDR_SIZE
111
+
112
+/* message types */
113
+#define BINRPC_REQ   0
114
+#define BINRPC_REPL  1
115
+#define BINRPC_FAULT 3
116
+
117
+/* values types */
118
+#define BINRPC_T_INT	0
119
+#define BINRPC_T_STR	1 /* 0 term, for easier parsing */
120
+#define BINRPC_T_DOUBLE	2
121
+#define BINRPC_T_STRUCT	3
122
+#define BINRPC_T_ARRAY	4
123
+#define BINRPC_T_AVP	5  /* allowed only in structs */
124
+#define BINRPC_T_BYTES	6 /* like STR, but not 0 term */
125
+
126
+#define BINRPC_T_ALL	0xf /* wildcard type, will match any record type
127
+							   in the packet (not allowed inside the pkt)*/
128
+
129
+/* errors */
130
+#define E_BINRPC_INVAL		-1  /* invalid function call parameters */
131
+#define E_BINRPC_OVERFLOW	-2  /* buffer overflow */
132
+#define E_BINRPC_BADPKT		-3  /* something went really bad, the packet is
133
+								   corrupted*/
134
+#define E_BINRPC_MORE_DATA	-4 /* parsing error: more bytes are needed,
135
+								  just repeat the failed op, when you have
136
+								  more bytes available */
137
+#define E_BINRPC_EOP		-5	/* end of packet reached */
138
+#define E_BINRPC_NOTINIT	-6  /* parse ctx not initialized */
139
+#define E_BINRPC_TYPE		-7  /* unkown type for record, or requested
140
+								   type doesn't match record type */
141
+#define E_BINRPC_RECORD		-8  /* bad record (unexpected, bad struct a.s.o)*/
142
+#define E_BINRPC_BUG		-9  /* internal error, bug */
143
+#define E_BINRPC_LAST		-10 /* used to count the errors, keep always
144
+								   last */
145
+
146
+/* flags */
147
+#define BINRPC_F_INIT	1
148
+
149
+struct binrpc_pkt{  /* binrpc body */
150
+	unsigned char* body;
151
+	unsigned char* end;
152
+	unsigned char* crt; /*private */
153
+};
154
+
155
+
156
+struct binrpc_parse_ctx{
157
+	/* header */
158
+	unsigned int tlen; /* total len */
159
+	unsigned int cookie;
160
+	int type; /* request, reply, error */
161
+	
162
+	/* parsing info */
163
+	unsigned int flags;   /* parsing flags */
164
+	unsigned int offset; /* current offset (inside payload) */
165
+	unsigned int in_struct;
166
+	unsigned int in_array;
167
+};
168
+
169
+
170
+
171
+struct binrpc_val{
172
+	str name; /* used only in structs */
173
+	int type;
174
+	union{
175
+		str strval;
176
+		double fval;
177
+		int intval;
178
+		int end;
179
+	}u;
180
+};
181
+
182
+
183
+
184
+/*  helper functions  */
185
+
186
+/* return int size: minimum number of bytes needed to represent it
187
+ * if i=0 returns 0 */
188
+inline static int binrpc_get_int_len(int i)
189
+{
190
+	int size;
191
+	for (size=4; size && ((i & (0xff<<24))==0); i<<=8, size--);
192
+	return size;
193
+}
194
+
195
+
196
+
197
+/* adds a start or end tag (valid only for STRUCT or ARRAY for now */
198
+inline static int binrpc_add_tag(struct binrpc_pkt* pkt, int type, int end)
199
+{
200
+	if (pkt->crt>=pkt->end) return E_BINRPC_OVERFLOW;
201
+	*pkt->crt=(end<<7)|type;
202
+	pkt->crt++;
203
+	return 0;
204
+}
205
+
206
+
207
+
208
+/*  writes a minimal int, returns the new offset and sets
209
+ * len to the number of bytes written (<=4)
210
+ * to check for oveflow use:  returned_value-p != *len
211
+ * (Note: if *len==0 using the test above succeeds even if p>=end)
212
+ */
213
+inline static unsigned char* binrpc_write_int(	unsigned char* p,
214
+												unsigned char* end,
215
+												int i, int *len)
216
+{
217
+	int size;
218
+
219
+	for (size=4; size && ((i & (0xff<<24))==0); i<<=8, size--);
220
+	*len=size;
221
+	for(; (p<end) && (size); p++, size--){
222
+		*p=(unsigned char)(i>>24);
223
+		i<<=8;
224
+	}
225
+	return p;
226
+}
227
+
228
+
229
+
230
+/* API functions */
231
+
232
+/* initialize a binrpc_pkt structure, for packet creation
233
+ * params: pkt         - binrpc body structure that will be initialized 
234
+ *         buf, b_len  -  destination buffer/len
235
+ * returns -1 on error, 0 on success
236
+ *
237
+ * Example usage:
238
+ *  binrpc_init_pkt(pkt, body, BODY_SIZE);
239
+ *  binrpc_addint(pkt, 1);
240
+ *  binrpc_addstr(pkt, "test", sizeof("test")-1);
241
+ *  ...
242
+ *  bytes=binrpc_build_hdr(pkt, BINRPC_REQ, 0x123, hdr_buf, HDR_BUF_LEN);
243
+ *  writev(sock, {{ hdr, bytes}, {pkt->body, pkt->crt-pkt->body}} , 2)*/
244
+inline static int binrpc_init_pkt(struct binrpc_pkt *pkt,
245
+								  unsigned char* buf, int b_len)
246
+{
247
+	if (b_len<BINRPC_MIN_RECORD_SIZE)
248
+		return E_BINRPC_OVERFLOW;
249
+	pkt->body=buf;
250
+	pkt->end=buf+b_len;
251
+	pkt->crt=pkt->body;
252
+	return 0;
253
+};
254
+
255
+
256
+
257
+/* used to update internal contents if the original buffer 
258
+ * (from binrpc_init_pkt) was realloc'ed (and has grown) */
259
+inline static int binrpc_pkt_update_buf(struct binrpc_pkt *pkt,
260
+										unsigned char* new_buf,
261
+										int new_len)
262
+{
263
+	if ((int)(pkt->crt-pkt->body)>new_len){
264
+		return E_BINRPC_OVERFLOW;
265
+	}
266
+	pkt->crt=new_buf+(pkt->crt-pkt->body);
267
+	pkt->body=new_buf;
268
+	pkt->end=new_buf+new_len;
269
+	return 0;
270
+}
271
+
272
+
273
+
274
+/* builds a binrpc header for the binrpc pkt. body pkt and writes it in buf
275
+ * params:  
276
+ *          type     - binrpc packet type (request, reply, fault)
277
+ *          body_len - body len
278
+ *          cookie   - binrpc cookie value
279
+ *          buf,len  - destination buffer & len
280
+ * returns -1 on error, number of bytes written on success */
281
+inline static int binrpc_build_hdr(	int type, int body_len,
282
+									unsigned int cookie,
283
+									unsigned char* buf, int b_len) 
284
+{
285
+	unsigned char* p;
286
+	int len_len;
287
+	int c_len;
288
+	
289
+	len_len=binrpc_get_int_len(body_len);
290
+	c_len=binrpc_get_int_len(cookie);
291
+	if (len_len==0) len_len=1; /* we can't have 0 len */
292
+	if (c_len==0) c_len=1;  /* we can't have 0 len */
293
+	/* size check: 2 bytes header + len_len + cookie len*/
294
+	if (b_len<(BINRPC_FIXED_HDR_SIZE+len_len+c_len)){
295
+		goto error_len;
296
+	}
297
+	p=buf;
298
+	*p=(BINRPC_MAGIC << 4) | BINRPC_VERS;
299
+	p++;
300
+	*p=(type<<4)|((len_len-1)<<2)|(c_len-1);
301
+	p++;
302
+	for(;len_len>0; len_len--,p++){
303
+		*p=(unsigned char)(body_len>>((len_len-1)*8));
304
+	}
305
+	for(;c_len>0; c_len--,p++){
306
+		*p=(unsigned char)(cookie>>((c_len-1)*8));
307
+	}
308
+	return (int)(p-buf);
309
+error_len:
310
+	return E_BINRPC_OVERFLOW;
311
+}
312
+
313
+
314
+
315
+#define binrpc_pkt_len(pkt)		((int)((pkt)->crt-(pkt)->body))
316
+
317
+
318
+
319
+/* changes the length of a header (enough space must be availale) */
320
+inline static int binrpc_hdr_change_len(unsigned char* hdr, int hdr_len,
321
+										int new_len)
322
+{
323
+	int len_len;
324
+	
325
+	binrpc_write_int(&hdr[BINRPC_TLEN_OFFSET], hdr+hdr_len, new_len, &len_len);
326
+	return 0;
327
+}
328
+
329
+
330
+
331
+/* int format:     size BINRPC_T_INT <val>  */
332
+inline static int binrpc_add_int_type(struct binrpc_pkt* pkt, int i, int type)
333
+{
334
+	
335
+	unsigned char* p;
336
+	int size;
337
+	
338
+	p=binrpc_write_int(pkt->crt+1, pkt->end, i, &size);
339
+	if ((pkt->crt>=pkt->end) || ((int)(p-pkt->crt-1)!=size))
340
+		goto error_len;
341
+	*(pkt->crt)=(size<<4) | type;
342
+	pkt->crt=p;
343
+	return 0;
344
+error_len:
345
+	return E_BINRPC_OVERFLOW;
346
+}
347
+
348
+
349
+
350
+/* double format:  FIXME: for now a hack: fixed point represented in
351
+ *  an int (=> max 3 decimals, < MAX_INT/1000) */
352
+#define binrpc_add_double_type(pkt, f, type)\
353
+	binrpc_add_int_type((pkt), (int)((f)*1000), (type))
354
+
355
+
356
+
357
+/* skip bytes bytes (leaves an empty space, for possible future use)
358
+ * WARNING: use with care, low level function
359
+ */
360
+inline static int binrpc_add_skip(struct binrpc_pkt* pkt, int bytes)
361
+{
362
+	
363
+	if ((pkt->crt+bytes)>=pkt->end)
364
+		return E_BINRPC_OVERFLOW;
365
+	pkt->crt+=bytes;
366
+	return 0;
367
+}
368
+
369
+
370
+
371
+/*
372
+ * adds only the string mark and len, you'll have to memcpy the contents
373
+ * manually later (and also use binrpc_add_skip(pkt, l) or increase
374
+ *  pkt->crt directly if you want to continue adding to this pkt).
375
+ *  Usefull for optimizing str writing (e.g. writev(iovec))
376
+ *  WARNING: use with care, low level function, binrpc_addstr or 
377
+ *           binrpc_add_str_type are probably what you want.
378
+ *  WARNING1: BINRPC_T_STR and BINRPC_T_AVP must be  0 term, the len passed to
379
+ *            this function, must include the \0 in this case.
380
+ */
381
+inline static int binrpc_add_str_mark(struct binrpc_pkt* pkt, int type,
382
+										int l)
383
+{
384
+	int size;
385
+	unsigned char* p;
386
+	
387
+	if (pkt->crt>=pkt->end) goto error_len;
388
+	if (l<8){
389
+		size=l;
390
+		p=pkt->crt+1;
391
+	}else{ /* we need a separate len */
392
+		p=binrpc_write_int(pkt->crt+1, pkt->end, l, &size);
393
+		if (((int)(p-pkt->crt-1)!=size))
394
+			goto error_len;
395
+		size|=8; /* mark it as having external len  */
396
+	}
397
+	*(pkt->crt)=(size)<<4|type;
398
+	pkt->crt=p;
399
+	return 0;
400
+error_len:
401
+	return E_BINRPC_OVERFLOW;
402
+}
403
+
404
+
405
+
406
+inline static int binrpc_add_str_type(struct binrpc_pkt* pkt, char* s, int len,
407
+										int type)
408
+{
409
+	int size;
410
+	int l;
411
+	int zero_term; /* whether or not to add an extra 0 at the end */
412
+	unsigned char* p;
413
+	
414
+	zero_term=((type==BINRPC_T_STR)||(type==BINRPC_T_AVP));
415
+	l=len+zero_term;
416
+	if (l<8){
417
+		size=l;
418
+		p=pkt->crt+1;
419
+	}else{ /* we need a separate len */
420
+		p=binrpc_write_int(pkt->crt+1, pkt->end, l, &size);
421
+		/* if ((int)(p-pkt->crt)<(size+1)) goto error_len;  - not needed,
422
+		 *  caught by the next check */
423
+		size|=8; /* mark it as having external len  */
424
+	}
425
+	if ((p+l)>pkt->end) goto error_len;
426
+	*(pkt->crt)=(size)<<4|type;
427
+	memcpy(p, s, len);
428
+	if (zero_term) p[len]=0;
429
+	pkt->crt=p+l;
430
+	return 0;
431
+error_len:
432
+	return E_BINRPC_OVERFLOW;
433
+}
434
+
435
+
436
+
437
+/* adds an avp (name, value) pair, usefull to add structure members */
438
+inline static int binrpc_addavp(struct binrpc_pkt* pkt, struct binrpc_val* avp)
439
+{
440
+	int ret;
441
+	unsigned char* bak;
442
+	
443
+	bak=pkt->crt;
444
+	ret=binrpc_add_str_type(pkt, avp->name.s, avp->name.len, BINRPC_T_AVP);
445
+	if (ret<0) return ret;
446
+	switch (avp->type){
447
+		case BINRPC_T_INT:
448
+			ret=binrpc_add_int_type(pkt, avp->u.intval, avp->type);
449
+			break;
450
+		case BINRPC_T_STR:
451
+		case BINRPC_T_BYTES:
452
+			ret=binrpc_add_str_type(pkt, avp->u.strval.s, 
453
+										avp->u.strval.len,
454
+										avp->type);
455
+			break;
456
+		case BINRPC_T_STRUCT:
457
+		case BINRPC_T_ARRAY:
458
+			ret=binrpc_add_tag(pkt, avp->type, 0);
459
+			break;
460
+		case BINRPC_T_DOUBLE: 
461
+			ret=binrpc_add_double_type(pkt, avp->u.fval, avp->type);
462
+			break;
463
+		default:
464
+			ret=E_BINRPC_BUG;
465
+	}
466
+	if (ret<0)
467
+		pkt->crt=bak; /* roll back */
468
+	return ret;
469
+}
470
+
471
+
472
+
473
+#define binrpc_addint(pkt, i)	binrpc_add_int_type((pkt), (i), BINRPC_T_INT) 
474
+
475
+#define binrpc_adddouble(pkt, f)	\
476
+	binrpc_add_double_type((pkt), (f), BINRPC_T_DOUBLE)
477
+
478
+#define binrpc_addstr(pkt, s, len)	\
479
+	binrpc_add_str_type((pkt), (s), (len), BINRPC_T_STR) 
480
+
481
+#define binrpc_addbytes(pkt, s, len)	\
482
+	binrpc_add_str_type((pkt), (s), (len), BINRPC_T_BYTES) 
483
+
484
+/* struct type format:
485
+ *  start :         0000 | BINRPC_T_STRUCT 
486
+ *  end:            1000 | BINRPC_T_STRUCT
487
+ */
488
+#define  binrpc_start_struct(pkt) binrpc_add_tag((pkt), BINRPC_T_STRUCT, 0)
489
+
490
+#define  binrpc_end_struct(pkt) binrpc_add_tag((pkt), BINRPC_T_STRUCT, 1)
491
+
492
+#define  binrpc_start_array(pkt) binrpc_add_tag((pkt), BINRPC_T_ARRAY, 0)
493
+
494
+#define  binrpc_end_array(pkt) binrpc_add_tag((pkt), BINRPC_T_ARRAY, 1)
495
+
496
+
497
+static inline int binrpc_addfault(	struct binrpc_pkt* pkt,
498
+									int code,
499
+									char* s, int len)
500
+{
501
+	int ret;
502
+	unsigned char* bak;
503
+	
504
+	bak=pkt->crt;
505
+	if ((ret=binrpc_addint(pkt, code))<0)
506
+		return ret;
507
+	ret=binrpc_addstr(pkt, s, len);
508
+	if (ret<0)
509
+		pkt->crt=bak; /* roll back */
510
+	return ret;
511
+}
512
+
513
+/* parsing incoming messages */
514
+
515
+
516
+static inline unsigned char* binrpc_read_int(	int* i,
517
+												int len,
518
+												unsigned char* s, 
519
+												unsigned char* end,
520
+												int *err
521
+												)
522
+{
523
+	unsigned char* start;
524
+	
525
+	start=s;
526
+	*i=0;
527
+	*err=0;
528
+	for(;len>0; len--, s++){
529
+		if (s>=end){
530
+			*err=E_BINRPC_MORE_DATA;
531
+			return start;
532
+		}
533
+		*i<<=8;
534
+		*i|=*s;
535
+	};
536
+	return s;
537
+}
538
+
539
+
540
+
541
+/* initialize parsing context, it tries to read the whole message header,
542
+ * if there is not enough data, sets *err to E_BINRPC_MORE_DATA. In this
543
+ *  case just redo the call when more data is available (len is bigger)
544
+ * on success sets *err to 0 and returns the current position in  buf
545
+ * (=> you can discard the content between buf & the returned value).
546
+ * On error buf is returned back, and *err set.
547
+ */
548
+static inline unsigned char* binrpc_parse_init(	struct binrpc_parse_ctx* ctx,
549
+												unsigned char* buf,
550
+												int len,
551
+												int *err
552
+												)
553
+{
554
+	int len_len, c_len;
555
+	unsigned char *p;
556
+
557
+	*err=0;
558
+	ctx->tlen=0;	/* init to 0 */
559
+	ctx->cookie=0;	/* init to 0 */
560
+	if (len<BINRPC_MIN_PKT_SIZE){
561
+		*err=E_BINRPC_MORE_DATA;
562
+		goto error;
563
+	}
564
+	if (buf[0]!=((BINRPC_MAGIC<<4)|BINRPC_VERS)){
565
+		*err=E_BINRPC_BADPKT;