#include #include #include "lx.h" #include "proto.h" #include "internal.h" typedef struct priv_ListHosts PRIV_ListHosts; struct priv_ListHosts { LX_ACCESSCONTROL *acp; LX_HOSTLIST **hlp; LX_HOSTLIST *hl; int sz; int o; int i; } ; static int walk_host_list(LX_CONN *xc, const unsigned char *dp, int len, int (*each)(unsigned char, int, const char *, void *), void *arg) { int o; int f; int n; int np; o = 0; while (o < len) { if (o+4 > len) { lx__protoerr(xc,"ListHosts HOST header overruns response"); return(1); } f = dp[o]; n = r_card16(dp+o+2); np = (n + 3) & ~3; if (o+4+np > len) { lx__protoerr(xc,"ListHosts HOST data overruns response"); return(1); } if ((*each)(f,n,dp+o+4,arg)) return(1); o += 4 + np; } return(0); } static int totalsize(unsigned char f, int n, const char *data, void *pv) { PRIV_ListHosts *p; LX_HOSTTYPE ht; (void)data; p = pv; ht = lx__proto_to_hosttype(f); if (ht == LX_HOSTTYPE_Other) n ++; p->sz += n; p->i ++; return(0); } static int save(unsigned char f, int n, const char *data, void *pv) { PRIV_ListHosts *p; LX_HOSTTYPE ht; int i; p = pv; i = p->i++; if (i >= p->hl->len) lx_abort(); ht = lx__proto_to_hosttype(f); p->hl->types[i] = ht; p->hl->data[i] = p->hl->alldata + p->o; if (ht == LX_HOSTTYPE_Other) { if (p->o+1 > p->sz) lx_abort(); p->hl->alldata[p->o++] = f; p->hl->sizes[i] = n + 1; } else { p->hl->sizes[i] = n; } if (p->o+n > p->sz) lx_abort(); bcopy(data,p->hl->alldata+p->o,n); p->o += n; return(0); } static void done_ListHosts(LX_OP *op, const unsigned char *rep, void *pv) { PRIV_ListHosts *p; LX_ACCESSCONTROL ac; int nhosts; LX_HOSTLIST *hl; int hll; p = pv; do <"ret"> { ac = lx__proto_to_accesscontrol(rep[1]); if (ac == LX__map_error) { lx__protoerr(op->conn,"bad ListHosts access-control value %d",rep[1]); break <"ret">; } nhosts = r_card16(rep+8); hll = r_card32(rep+4) * 4; if (p->hlp) { do <"good"> { do <"fail"> { do <"mem"> { hl = malloc(sizeof(LX_HOSTLIST)); if (! hl) break <"mem">; hl->len = nhosts; hl->types = 0; hl->sizes = 0; hl->data = 0; hl->alldata = 0; hl->types = malloc(nhosts*sizeof(LX_HOSTTYPE)); if (! hl->types) break <"mem">; hl->sizes = malloc(nhosts*sizeof(int)); if (! hl->sizes) break <"mem">; hl->data = malloc(nhosts*sizeof(void *)); if (! hl->data) break <"mem">; p->sz = 0; p->i = 0; if (walk_host_list(op->conn,rep+32,hll,&totalsize,p)) break <"fail">; if (p->i != nhosts) { lx__protoerr(op->conn,"ListHosts host count wrong for data"); break <"fail">; } hl->alldata = malloc(p->sz); if (! hl->alldata) break <"mem">; p->o = 0; p->hl = hl; p->i = 0; if (walk_host_list(op->conn,rep+32,hll,&save,p)) lx_abort(); if ((p->i != nhosts) || (p->o != p->sz)) lx_abort(); *p->hlp = hl; break <"good">; } while (0); lx__nomem_fail(op->conn); } while (0); if (hl) { free(hl->types); free(hl->sizes); free(hl->data); free(hl->alldata); free(hl); } break <"ret">; } while (0); } if (p->acp) *p->acp = ac; } while (0); free(p); } LX_OP *lx_ListHosts(LX_CONN *xc, LX_ACCESSCONTROL *acp, LX_HOSTLIST **hlp) { unsigned char req[4]; PRIV_ListHosts *p; if (xc->flags & XCF_FAIL) { lx__bad_call(xc,"lx_ListHosts"); return(0); } lx__nochain(xc); p = malloc(sizeof(PRIV_ListHosts)); if (! p) { lx__nomem_fail(xc); return(0); } p->acp = acp; p->hlp = hlp; req[0] = XP_REQ_ListHosts; req[1] = 0; w_card16(&req[2],1); return(lx__expect_reply(xc,&req[0],-1,&done_ListHosts,p)); }