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