#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; int store; static void need(unsigned int n) { if (ipend-ipp < n) { (*f2)(ipp,"packet too short (%d left, need %u)",(int)(ipend-ipp),n); goto ret; } } ipp = data; ipend = ipp + datalen; store = 1; while (1) { key = va_arg(ap,int); switch (key) { case PP__SKIP: store = 0; continue; break; case PP__BLOB: { int i; void *vp; i = va_arg(ap,int); vp = va_arg(ap,void *); need(i); if (store) bcopy(ipp,vp,i); ipp += i; } break; case PP__STRING: { int len; STR *sp; sp = va_arg(ap,STR *); need(4); len = get_uint32(ipp); ipp += 4; need(len); if (store) { sp->len = 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; if (store) (*fn)(s,arg); } break; case PP__BOOL: { int *ip; ip = va_arg(ap,int *); need(1); switch (*ipp) { case 0: if (store) *ip = 0; break; case 1: if (store) *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); if (store) *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); if (store) { mpz_set_ui(mip,0); for (;bytes>0;bytes--) { mpz_mul_2exp(mip,mip,8); mpz_add_ui(mip,mip,*ipp++); } } else { ipp += bytes; } } break; case PP__ENDSHERE: if (ipp != ipend) (*f0)(ipp,"junk at end of packet"); return; break; case PP__REST: { const void **bp; int *lenp; bp = va_arg(ap,const void **); lenp = va_arg(ap,int *); if (store) { *bp = ipp; *lenp = ipend - ipp; } } return; break; default: abort(); break; } store = 1; } 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); }