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 "../../core/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  /* unknown 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 */
binrpc_get_int_len(int i)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 */
binrpc_add_tag(struct binrpc_pkt * pkt,int type,int end)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  */
binrpc_write_int(unsigned char * p,unsigned char * end,int i,int * len)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)*/
binrpc_init_pkt(struct binrpc_pkt * pkt,unsigned char * buf,int b_len)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) */
binrpc_pkt_update_buf(struct binrpc_pkt * pkt,unsigned char * new_buf,int new_len)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 */
binrpc_build_hdr(int type,int body_len,unsigned int cookie,unsigned char * buf,int b_len)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) */
binrpc_hdr_change_len(unsigned char * hdr,int hdr_len,int new_len)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>  */
binrpc_add_int_type(struct binrpc_pkt * pkt,int i,int type)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  */
binrpc_add_skip(struct binrpc_pkt * pkt,int bytes)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  */
binrpc_add_str_mark(struct binrpc_pkt * pkt,int type,int l)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 
binrpc_add_str_type(struct binrpc_pkt * pkt,char * s,int len,int type)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, useful to add structure members */
binrpc_addavp(struct binrpc_pkt * pkt,struct binrpc_val * avp)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 
binrpc_addfault(struct binrpc_pkt * pkt,int code,char * s,int len)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 
binrpc_read_int(int * i,int len,unsigned char * s,unsigned char * end,int * err)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  */
binrpc_parse_init(struct binrpc_parse_ctx * ctx,unsigned char * buf,int len,int * err)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;
566 		goto error;
567 	}
568 	ctx->type=buf[1]>>4;
569 	/* type check */
570 	switch(ctx->type){
571 		case BINRPC_REQ:
572 		case BINRPC_REPL:
573 		case BINRPC_FAULT:
574 			break;
575 		default:
576 			*err=E_BINRPC_BADPKT;
577 			goto error;
578 	}
579 	len_len=((buf[1]>>2) & 3) + 1;
580 	c_len=(buf[1]&3) + 1;
581 	if ((BINRPC_TLEN_OFFSET+len_len+c_len)>len){
582 		*err=E_BINRPC_MORE_DATA;
583 		goto error;
584 	}
585 	p=binrpc_read_int((int*)&ctx->tlen, len_len, &buf[BINRPC_TLEN_OFFSET],
586 						&buf[len], err);
587 	/* empty packets (replies) are allowed
588 	   if (ctx->tlen==0){
589 		*err=E_BINRPC_BADPKT;
590 		goto error;
591 	} */
592 	p=binrpc_read_int((int*)&ctx->cookie, c_len, p, &buf[len], err);
593 	ctx->offset=0;
594 	ctx->flags|=BINRPC_F_INIT;
595 	return p;
596 error:
597 	return buf;
598 }
599 
600 
601 
602 /* returns bytes needed (till the end of the packet)
603  * on error (non. init ctx) returns < 0
604  */
binrpc_bytes_needed(struct binrpc_parse_ctx * ctx)605 inline static int binrpc_bytes_needed(struct binrpc_parse_ctx *ctx)
606 {
607 	if (ctx->flags & BINRPC_F_INIT)
608 		return ctx->tlen-ctx->offset;
609 	return E_BINRPC_NOTINIT;
610 }
611 
612 
613 
614 /* prefill v with the requested type, if type==BINRPC_T_ALL it
615  * will be replaced by the actual record type
616  * known problems: no support for arrays inside STRUCT
617  * param smode: allow simple vals inside struct (needed for
618  * not-strict-formatted rpc responses)
619  * returns position after the record and *err==0 if succesfull
620  *         original position and *err<0 if not */
binrpc_read_record(struct binrpc_parse_ctx * ctx,unsigned char * buf,unsigned char * end,struct binrpc_val * v,int smode,int * err)621 inline static unsigned char* binrpc_read_record(struct binrpc_parse_ctx* ctx,
622 												unsigned char* buf,
623 												unsigned char* end,
624 												struct binrpc_val* v,
625 												int smode,
626 												int* err
627 												)
628 {
629 	int type;
630 	int len;
631 	int end_tag;
632 	int tmp;
633 	unsigned char* p;
634 	int i;
635 
636 	p=buf;
637 	end_tag=0;
638 	*err=0;
639 	if (!(ctx->flags & BINRPC_F_INIT)){
640 		*err=E_BINRPC_NOTINIT;
641 		goto error;
642 	}
643 	if (ctx->offset>=ctx->tlen){
644 		*err=E_BINRPC_EOP;
645 		goto error;
646 	}
647 	if (p>=end){
648 		*err=E_BINRPC_MORE_DATA;
649 		goto error;
650 	}
651 	/* read type_len */
652 	type=*p & 0xf;
653 	len=*p>>4;
654 	p++;
655 	if (len & 8){
656 		end_tag=1; /* possible end mark for array or structs */
657 		/* we have to read len bytes and use them as the new len */
658 		p=binrpc_read_int(&len, len&7, p, end, err);
659 		if (*err<0)
660 			goto error;
661 	}
662 	if ((p+len)>end){
663 		*err=E_BINRPC_MORE_DATA;
664 		goto error;
665 	}
666 	if ((v->type!=type) && (v->type !=BINRPC_T_ALL)){
667 		goto error_type;
668 	}
669 	v->type=type;
670 	switch(type){
671 		case BINRPC_T_STRUCT:
672 			if (ctx->in_struct){
673 				if (end_tag){
674 					ctx->in_struct--;
675 					v->u.end=1;
676 				}else{
677 					if(smode==0) {
678 						goto error_record;
679 					} else {
680 						v->u.end=0;
681 						ctx->in_struct++;
682 					}
683 				}
684 			} else {
685 				if (end_tag)
686 					goto error_record;
687 				v->u.end=0;
688 				ctx->in_struct++;
689 			}
690 			break;
691 		case BINRPC_T_AVP:
692 			/* name | value */
693 			if (ctx->in_struct){
694 				v->name.s=(char*)p;
695 				v->name.len=(len-1); /* don't include 0 term */
696 				p+=len;
697 				if (p>=end){
698 					*err=E_BINRPC_MORE_DATA;
699 					goto error;
700 				}
701 				/* avp value type */
702 				type=*p & 0xf;
703 				if ((type!=BINRPC_T_AVP) && (type!=BINRPC_T_ARRAY)){
704 					tmp=ctx->in_struct;
705 					ctx->in_struct=0; /* hack to parse a normal record */
706 					v->type=type; /* hack */
707 					p=binrpc_read_record(ctx, p, end, v, smode, err);
708 					if (*err<0){
709 						ctx->in_struct=tmp;
710 						goto error;
711 					}else{
712 						ctx->in_struct+=tmp;
713 						/* the offset is already updated => skip */
714 						goto no_offs_update;
715 					}
716 				}else{
717 					goto  error_record;
718 				}
719 			} else {
720 				goto error_type;
721 			}
722 			break;
723 		case BINRPC_T_INT:
724 			if (ctx->in_struct && smode==0) goto error_record;
725 			p=binrpc_read_int(&v->u.intval, len, p, end, err);
726 			break;
727 		case BINRPC_T_STR:
728 			if (ctx->in_struct && smode==0) goto error_record;
729 			v->u.strval.s=(char*)p;
730 			v->u.strval.len=(len-1); /* don't include terminating 0 */
731 			p+=len;
732 			break;
733 		case BINRPC_T_BYTES:
734 			if (ctx->in_struct && smode==0) goto error_record;
735 			v->u.strval.s=(char*)p;
736 			v->u.strval.len=len;
737 			p+=len;
738 			break;
739 		case BINRPC_T_ARRAY:
740 			if (ctx->in_struct && smode==0) goto error_record;
741 			if (end_tag){
742 				if (ctx->in_array>0){
743 					ctx->in_array--;
744 					v->u.end=1;
745 				}else{
746 					goto error_record;
747 				}
748 			}else{
749 				ctx->in_array++;
750 				v->u.end=0;
751 			}
752 			break;
753 		case BINRPC_T_DOUBLE: /* FIXME: hack: represented as fixed point
754 		                                      inside an int */
755 			if (ctx->in_struct && smode==0) goto error_record;
756 			p=binrpc_read_int(&i, len, p, end, err);
757 			v->u.fval=((double)i)/1000;
758 			break;
759 		default:
760 			if (ctx->in_struct){
761 				goto error_record;
762 			} else {
763 				goto error_type;
764 			}
765 	}
766 	ctx->offset+=(int)(p-buf);
767 no_offs_update:
768 	return p;
769 error_type:
770 	*err=E_BINRPC_TYPE;
771 	return buf;
772 error_record:
773 	*err=E_BINRPC_RECORD;
774 error:
775 	return buf;
776 }
777 
778 
779 
780 /* reads/skips an entire struct
781  * the struct start/end are saved in v->u.strval.s, v->u.strval.len
782  * return:  - new buffer position  and set *err to 0 if successfull
783  *          - original buffer and *err<0 on error */
binrpc_read_struct(struct binrpc_parse_ctx * ctx,unsigned char * buf,unsigned char * end,struct binrpc_val * v,int * err)784 inline static unsigned char* binrpc_read_struct(struct binrpc_parse_ctx* ctx,
785 												unsigned char* buf,
786 												unsigned char* end,
787 												struct binrpc_val* v,
788 												int* err
789 												)
790 {
791 
792 	int type;
793 	int len;
794 	int end_tag;
795 	unsigned char* p;
796 	int in_struct;
797 
798 	*err=0;
799 	p=buf;
800 	end_tag=0;
801 	if (!(ctx->flags & BINRPC_F_INIT)){
802 		*err=E_BINRPC_NOTINIT;
803 		goto error;
804 	}
805 	if (ctx->offset>=ctx->tlen){
806 		*err=E_BINRPC_EOP;
807 		goto error;
808 	}
809 	if (p>=end){
810 		*err=E_BINRPC_MORE_DATA;
811 		goto error;
812 	}
813 	/* read type_len */
814 	type=*p & 0xf;
815 	len=*p>>4;
816 	p++;
817 	if (len & 8){
818 		end_tag=1; /* possible end mark for array or structs */
819 		/* we have to read len bytes and use them as the new len */
820 		p=binrpc_read_int(&len, len&7, p, end, err);
821 		if (*err<0)
822 			goto error;
823 	}
824 	if ((p+len)>=end){
825 		*err=E_BINRPC_MORE_DATA;
826 		goto error;
827 	}
828 	if (type!=BINRPC_T_STRUCT){
829 		goto error_type;
830 	}
831 	if (end_tag){
832 		goto error_record;
833 	}
834 	p+=len; /* len should be 0 for a struct tag */
835 	in_struct=1;
836 	v->type=type;
837 	v->u.strval.s=(char*)p; /* it will conain the inside of the struc */
838 	while(in_struct){
839 		/* read name */
840 		type=*p & 0xf;
841 		len=*p>>4;
842 		p++;
843 		if (len & 8){
844 			end_tag=1; /* possible end mark for array or structs */
845 			/* we have to read len bytes and use them as the new len */
846 			p=binrpc_read_int(&len, len&7, p, end, err);
847 			if (*err<0)
848 				goto error;
849 		}
850 		if ((type==BINRPC_T_STRUCT) && end_tag){
851 			in_struct--;
852 			if (in_struct<0)
853 				goto error_record;
854 			continue;
855 		}else if (type!=BINRPC_T_AVP){
856 			goto error_record;
857 		}
858 		/* skip over it */
859 		p+=len;
860 		if (p>=end){
861 			*err=E_BINRPC_MORE_DATA;
862 			goto error;
863 		}
864 		/* read value */
865 		type=*p & 0xf;
866 		len=*p>>4;
867 		p++;
868 		if (len & 8){
869 			end_tag=1; /* possible end mark for array or structs */
870 			/* we have to read len bytes and use them as the new len */
871 			p=binrpc_read_int(&len, len&7, p, end, err);
872 			if (*err<0)
873 				goto error;
874 		}
875 		if (type==BINRPC_T_STRUCT){
876 			if (end_tag)
877 				goto error_record;
878 			in_struct++;
879 		};
880 		p+=len;
881 		if (p>=end){
882 			*err=E_BINRPC_MORE_DATA;
883 			goto error;
884 		}
885 	}
886 	/* don't include the end tag */;
887 	v->u.strval.len=(int)(p-(unsigned char*)v->u.strval.s)-1;
888 	return p;
889 
890 error_type:
891 	*err=E_BINRPC_RECORD;
892 	return buf;
893 error_record:
894 	*err=E_BINRPC_TYPE;
895 error:
896 	return buf;
897 }
898 
899 
900 
901 /* error code to string */
902 const char* binrpc_error(int err);
903 #endif
904