#include #include #include #include #define PP__INLINE #include "pp.h" #include "str.h" #include "pkt-util.h" static void parse_it(const char *data, int datalen, void (*f0)(const void *, const char *), void (*f1)(const void *, const char *, int), void (*f2)(const void *, const char *, int, int), va_list ap) { __label__ ret; int key; const unsigned char *ipp; const unsigned char *ipend; static void tooshort(int n) { (*f2)(ipp,"packet too short (len %d, need at least %d)",datalen,(int)(ipp-(const unsigned char *)data)+n); goto ret; } #define NEED(n) do { if (ipend-ipp < (n)) tooshort((n)); } while (0) ipp = data; ipend = ipp + datalen; while (1) { key = va_arg(ap,int); switch (key) { case PP__SKIP: { int i; i = va_arg(ap,int); NEED(i); ipp += i; } break; case PP__BLOB: { int i; void *vp; i = va_arg(ap,int); vp = va_arg(ap,void *); NEED(i); bcopy(ipp,vp,i); ipp += i; } break; case PP__STRING: { STR *sp; sp = va_arg(ap,STR *); NEED(4); sp->len = get_uint32(ipp); ipp += 4; NEED(sp->len); sp->data = malloc(sp->len); bcopy(ipp,sp->data,sp->len); ipp += sp->len; } break; case PP__STRCALL: { ROSTR s; void (*fn)(ROSTR, void *); void *arg; fn = va_arg(ap,__typeof__(fn)); arg = va_arg(ap,void *); NEED(4); s.len = get_uint32(ipp); ipp += 4; NEED(s.len); s.data = (const void *) ipp; ipp += s.len; (*fn)(s,arg); } break; case PP__BOOL: { int *ip; ip = va_arg(ap,int *); NEED(1); switch (*ipp) { case 0: *ip = 0; break; case 1: *ip = 1; break; default: (*f1)(ipp,"invalid boolean 0x%02x",*ipp); break; } ipp ++; } break; case PP__UINT32: { unsigned int *uip; uip = va_arg(ap,unsigned int *); NEED(4); *uip = get_uint32(ipp); ipp += 4; } break; case PP__MPINT: { int bytes; MP_INT *mip; mip = va_arg(ap,MP_INT *); NEED(4); bytes = get_uint32(ipp); ipp += 4; NEED(bytes); mpz_set_ui(mip,0); for (;bytes>0;bytes--) { mpz_mul_2exp(mip,mip,8); mpz_add_ui(mip,mip,*ipp++); } } break; case PP__ENDSHERE: if (ipp != ipend) (*f0)(ipp,"junk at end of packet"); return; break; default: abort(); break; } } #undef NEED ret:; } /* Annoyingly, we cannot share the bulk of the code between parse_packet and parse_data without going through gyrations with the failure routine. Fortunately, the failure routine is called from only a few places, with only three different call type signatures. */ void parse_packet(BPP *bpp, void (*fail)(BPP *, const void *, const char *, ...), ...) { va_list ap; static void f0(const void *ipp, const char *s) { (*fail)(bpp,ipp,s); } static void f1(const void *ipp, const char *s, int i) { (*fail)(bpp,ipp,s,i); } static void f2(const void *ipp, const char *s, int i1, int i2) { (*fail)(bpp,ipp,s,i1,i2); } va_start(ap,fail); parse_it(&bpp->ipkt[0],bpp->iplen,f0,f1,f2,ap); va_end(ap); } void parse_data(const void *data, int datalen, void (*fail)(const void *, const char *, ...), ...) { va_list ap; static void f0(const void *ipp, const char *s) { (*fail)(ipp,s); } static void f1(const void *ipp, const char *s, int i) { (*fail)(ipp,s,i); } static void f2(const void *ipp, const char *s, int i1, int i2) { (*fail)(ipp,s,i1,i2); } va_start(ap,fail); parse_it(data,datalen,f0,f1,f2,ap); va_end(ap); }