#include #include #include #include "atoms.h" #include "structs.h" #include "fmt-util.h" typedef struct getpriv GETPRIV; struct getpriv { unsigned int flags; #define GPF_DISABLE 0x00000001 unsigned char *v; #define GET_BLK_1 0x01 #define GET_BLK_2 0x02 #define GET_BLK_4 0x04 #define GET_BLK_BIN 0x08 #define GET_BLK_TXT 0x10 #define GET_BLK_PAD 0x20 unsigned int a; unsigned int l; } ; static int printpref(FILE *to, const char *pref, const char *ifnil) { if (pref) { return(fprintf(to,"%s",pref)); } else { return(fprintf(to,"%*s",(int)strlen(ifnil),"")); } } static void gp_room(GETPRIV *p, unsigned int n) { if (n > p->a) p->v = realloc(p->v,(p->a=n)*sizeof(*p->v)); } void get_init(FLOW *f) { GETPRIV *p; p = malloc(sizeof(GETPRIV)); p->flags = GPF_DISABLE; p->v = 0; p->a = 0; p->l = 0; f->getpriv = p; } void get_free(FLOW *f) { GETPRIV *p; p = f->getpriv; free(p->v); free(p); f->getpriv = 0; } void get_clear(FLOW *f) { GETPRIV *p; p = f->getpriv; p->flags &= ~GPF_DISABLE; gp_room(p,f->ibfill); p->l = f->ibfill; memset(p->v,0,f->ibfill); } void get_done(FLOW *f, FILE *o) { GETPRIV *p; int i; p = f->getpriv; if (p->l != f->ibfill) abort(); if (p->flags & GPF_DISABLE) return; for (i=0;iibfill;i++) { switch (p->v[i]) { case GET_BLK_1: case GET_BLK_2: case GET_BLK_4: case GET_BLK_BIN: case GET_BLK_TXT: case GET_BLK_PAD: break; default: fprintf(o,"*** map[%d] = %02x\n",i,p->v[i]); break; } } p->flags |= GPF_DISABLE; } void get_disable(FLOW *f) { GETPRIV *p; p = f->getpriv; p->flags |= GPF_DISABLE; } static void get_record_blk(FLOW *f, unsigned int offset, unsigned int len, unsigned char type) { GETPRIV *p; unsigned char *vp; p = f->getpriv; if (p->flags & GPF_DISABLE) return; if ((offset > p->l) || (len > p->l) || (offset+len > p->l)) abort(); gp_room(f->getpriv,offset+len); for (vp=p->v+offset;len>0;len--,vp++) *vp |= type; } void get_pad(FLOW *f, unsigned int offset, unsigned int len) { get_record_blk(f,offset,len,GET_BLK_PAD); } static void get_record(FLOW *f, unsigned int offset, int kind) { switch (kind) { case 1: get_record_blk(f,offset,1,GET_BLK_1); break; case 2: get_record_blk(f,offset,2,GET_BLK_2); break; case 4: get_record_blk(f,offset,4,GET_BLK_4); break; default: abort(); break; } } void print_text_blk(FLOW *f, FILE *o, unsigned int offset, int len, const char *pref1, const char *prefn) { int i; int col; int ch; const unsigned char *blk; get_record_blk(f,offset,len,GET_BLK_TXT); fprintf(o,"%s\"",pref1); blk = f->ibuf + offset; col = 0; for (i=0;i= 50) { fprintf(o,"\"\n"); printpref(o,prefn,pref1); putc('"',o); col = 0; } ch = blk[i]; if (ch < 32) { if ((i+1 < len) && (blk[i+1] >= '0') && (blk[i+1] <= '9')) { col += fprintf(o,"\\%03o",ch); } else { col += fprintf(o,"\\%o",ch); } } else if ((ch >= 127) && (ch < 160)) { col += fprintf(o,"\\%o",ch); } else { putc(ch,o); col ++; } } fprintf(o,"\"\n"); } void print_padded_text_blk(FLOW *f, FILE *o, unsigned int offset, int len, const char *pref1, const char *prefn) { print_text_blk(f,o,offset,len,pref1,prefn); get_pad(f,offset+len,pad(len)); } void print_bin_blk(FLOW *f, FILE *o, unsigned int offset, int len, const char *pref1, const char *prefn) { int i; int n; int ch; unsigned char *blk; unsigned char tbuf[16]; if (len < 1) { fprintf(o,"%s%*s||\n",pref1,(3*16)+1+2-1,""); return; } get_record_blk(f,offset,len,GET_BLK_BIN); fprintf(o,"%s",pref1); blk = f->ibuf + offset; n = 0; for (i=0;i= 127) && (ch < 160))) { tbuf[n] = '·'; } else { tbuf[n] = ch; } if (n) putc(' ',o); fprintf(o,"%02x",ch); n = (n + 1) & 15; if (n == 0) fprintf(o," |%.16s|\n",&tbuf[0]); } if (n) fprintf(o,"%*s|%.*s|\n",((16-n)*3)+2+(n<=8),"",n,&tbuf[0]); } void print_raw_data(FILE *o, FLOW *f) { get_disable(f); print_bin_blk(f,o,0,f->ibfull,"Raw data ",0); } unsigned int get1u(FLOW *f, unsigned int offset) { get_record(f,offset,1); if (offset+1 > f->ibfill) abort(); return(f->ibuf[offset]); } int get1s(FLOW *f, unsigned int offset) { int v; v = get1u(f,offset); return((v&0x80)?v-256:v); } unsigned int get2u(FLOW *f, unsigned int offset) { get_record(f,offset,2); if (offset+2 > f->ibfill) abort(); switch (f->conn->endian) { case END_L: return(f->ibuf[offset]+(f->ibuf[offset+1]*256)); break; case END_B: return(f->ibuf[offset+1]+(f->ibuf[offset]*256)); break; default: abort(); break; } } int get2s(FLOW *f, unsigned int offset) { int v; v = get2u(f,offset); return((v&0x8000)?v-65536:v); } unsigned int get4u(FLOW *f, unsigned int offset) { get_record(f,offset,4); if (offset+4 > f->ibfill) abort(); switch (f->conn->endian) { case END_L: return( f->ibuf[offset ] + (f->ibuf[offset+1] * 0x00000100) + (f->ibuf[offset+2] * 0x00010000) + (f->ibuf[offset+3] * 0x01000000) ); break; case END_B: return( f->ibuf[offset+3] + (f->ibuf[offset+2] * 0x00000100) + (f->ibuf[offset+1] * 0x00010000) + (f->ibuf[offset ] * 0x01000000) ); break; default: abort(); break; } } /* * There's a dilemma here. We'd _like_ to test the 0x80000000 bit and * then maybe subtract 0x100000000, parallel to get2s and get1s. But * the preprocessor can't even test sizeof(int), which isn't the right * test anyway (because we want size in bits, not in chars). We can * test at runtime, with something like 0x80000000U*2U, but the * ">32bit" case involves a number too large for 32 bits, which draws * a warning, and it's a warning we don't want to just turn off. * * I'm not sure what the best answer is. For the moment, we just * blindly assume that int is 32 bits wide. :( */ int get4s(FLOW *f, unsigned int offset) { return(get4u(f,offset)); } unsigned int ltob_u(unsigned int v) { return(v&0xff); } int ltob_s(unsigned int v) { return((v&0x80)?(v&0xff)-0x100:(v&0xff)); } unsigned int ltos_u(unsigned int v) { return(v&0xffff); } int ltos_s(unsigned int v) { return((v&0x8000)?(v&0xffff)-0x10000:(v&0xffff)); } void print_xid_alt(FILE *o, unsigned int id, int nalt, ...) { va_list ap; unsigned int val; const char *s; va_start(ap,nalt); for (;nalt>0;nalt--) { val = va_arg(ap,unsigned int); s = va_arg(ap,const char *); if (id == val) { fprintf(o,"%s",s); return; } } va_end(ap); fprintf(o,XID_FMT,id); } void print_xid_z(FILE *o, unsigned int id, const char *if0) { if (id == 0) fprintf(o,"%s",if0); else fprintf(o,XID_FMT,id); } void print_set_alt(FILE *to, const char *pref1, const char *prefn, unsigned int set, const SETVALS *setv, int nalt, ...) { va_list ap; int i; int col; const char *sep; unsigned int bit; const char *txt; char *hex; void add_string(const char *s) { if (col+strlen(s) > 70) { fprintf(to,"\n"); col = printpref(to,prefn,pref1); sep = ""; } col += fprintf(to,"%s%s",sep,s); sep = " "; } fprintf(to,"%s",pref1); sep = ""; col = strlen(pref1); for (i=0;setv[i].bit;i++) { if (! (set & setv[i].bit)) continue; set &= ~setv[i].bit; add_string(setv[i].string); } va_start(ap,nalt); for (;nalt>0;nalt--) { bit = va_arg(ap,unsigned int); txt = va_arg(ap,const char *); if (set & bit) { set &= ~bit; add_string(txt); } } va_end(ap); if (set) { asprintf(&hex,"0x%x",set); add_string(hex); free(hex); } fprintf(to,"\n"); } void print_set(FILE *to, const char *pref1, const char *prefn, unsigned int set, const SETVALS *setv) { print_set_alt(to,pref1,prefn,set,setv,0); } unsigned int bitcount(unsigned int v) { v = ((v >> 1) & 0x55555555) + (v & 0x55555555); v = ((v >> 2) & 0x33333333) + (v & 0x33333333); v = ((v >> 4) & 0x0f0f0f0f) + (v & 0x0f0f0f0f); v = ((v >> 8) & 0x00ff00ff) + (v & 0x00ff00ff); v = ((v >> 16) & 0x0000ffff) + (v & 0x0000ffff); return(v); } unsigned int pad(unsigned int n) { return("\0\3\2\1"[n&3]); } unsigned int padded(unsigned int n) { return(n+pad(n)); } void *copy_block(const void *data, int len) { void *b; b = malloc(len); bcopy(data,b,len); return(b); } void print_atom(FILE *to, CONN *c, unsigned int a) { const char *an; an = atoms_lookup(c->atoms,a); if (an) { fprintf(to,"%s",an); return; } fprintf(to,XID_FMT" (unknown)",a); } void print_atom_z(FILE *to, CONN *c, unsigned int a, const char *if0) { if (a == 0) { fprintf(to,"%s",if0); } else { print_atom(to,c,a); } } void print_timestamp(FILE *to, unsigned int ts) { if (ts == 0) { fprintf(to,"CurrentTime"); } else { fprintf(to,"%u",ts); } } void print_choice(FILE *o, unsigned int val, int nalt, ...) { va_list ap; unsigned int v; const char *s; va_start(ap,nalt); for (;nalt>0;nalt--) { v = va_arg(ap,unsigned int); s = va_arg(ap,const char *); if (val == v) { fprintf(o,"%s",s); return; } } va_end(ap); fprintf(o,"%u (INVALID)",val); } void minlength(FLOW *f, FILE *o, unsigned int minlen) { if (f->ibfill < minlen) { fprintf(o,"*** Too short (min length %d)\n",minlen); print_raw_data(o,f); set_eof(f); abort_packet_print(); } } void exactlength(FLOW *f, FILE *o, unsigned int len) { if (f->ibfill != len) { fprintf(o,"*** Length wrong (length %d, should be %d)\n",f->ibfill,len); print_raw_data(o,f); set_eof(f); abort_packet_print(); } } void rep_hdr(FLOW *f, FILE *o, const char *name) { fprintf(o,"%s reply, length %d\n",name,f->ibfill); fprintf(o," Sequence number: %04x\n",get2u(f,2)); EXACTLENGTH(32+(4*get4u(f,4))); } void req_hdr_min(FLOW *f, FILE *o, const char *name, int len) { fprintf(o,"%s request, length %d\n",name,f->ibfill); fprintf(o," Sequence number: %08x\n",f->conn->reqseq); MINLENGTH(len); } void req_hdr_exact(FLOW *f, FILE *o, const char *name, int len) { fprintf(o,"%s request, length %d\n",name,f->ibfill); fprintf(o," Sequence number: %08x\n",f->conn->reqseq); EXACTLENGTH(len); } void event_hdr(FLOW *f, FILE *o, const char *name) { fprintf(o,"%s event\n",name); EXACTLENGTH(32); fprintf(o," Sequence number: %04x\n",get2u(f,2)); } void error_hdr(FLOW *f, FILE *o, const char *name) { fprintf(o,"%s error\n",name); EXACTLENGTH(32); fprintf(o," Sequence number: %04x\n",get2u(f,2)); fprintf(o," Minor opcode: %u\n",get2u(f,8)); fprintf(o," Major opcode: %u\n",get1u(f,10)); }