/* This file is in the public domain. */ #include #include #include #include #include #include extern const char *__progname; #include "errf.h" #include "panic.h" #include "dequal.h" #include "oq.h" struct oqe { OQE *link; int special; union { struct { const char *data; int left; char *datafree; } norm; struct { void *vp; int i; } spec; } ; } ; static void queue_common(OQ *q, OQE *e) { e->link = 0; *q->tail = e; q->tail = &e->link; } static void queue_norm(OQ *q, OQE *e, int len) { e->special = 0; e->norm.left = len; q->len += len; queue_common(q,e); } void oq_init(OQ *q) { q->len = 0; q->head = 0; q->tail = &q->head; } unsigned int oq_qlen(OQ *q) { return(q->len); } int oq_empty(OQ *q) { return(q->head == 0); } int oq_nonempty(OQ *q) { return(q->head != 0); } void oq_queue_point(OQ *q, const void *data, int len) { OQE *e; if (len == OQ_STRLEN) len = strlen(data); if (len == 0) return; if (len < 1) panic("bad length"); e = malloc(sizeof(OQE)); e->norm.data = data; e->norm.datafree = 0; queue_norm(q,e,len); } void oq_queue_copy(OQ *q, const void *data, int len) { OQE *e; if (len == OQ_STRLEN) len = strlen(data); if (len == 0) return; if (len < 1) panic("bad length"); e = malloc(sizeof(OQE)+len); e->norm.data = (void *) (e+1); e->norm.datafree = 0; bcopy(data,e+1,len); queue_norm(q,e,len); } void oq_queue_free(OQ *q, void *data, int len) { OQE *e; if (len == OQ_STRLEN) len = strlen(data); if (len == 0) { free(data); return; } if (len < 1) panic("bad length"); e = malloc(sizeof(OQE)); e->norm.data = data; e->norm.datafree = data; queue_norm(q,e,len); } void oq_queue_special(OQ *q, void *vp, int i) { OQE *e; e = malloc(sizeof(OQE)); e->special = 1; e->spec.vp = vp; e->spec.i = i; queue_common(q,e); } int oq_writev(OQ *q, int fd, int (*dospecial)(void *, int)) { static int maxiov = -1; static struct iovec *iov; static int iovn; int iovl; OQE *e; if (maxiov < 0) { int mib[2]; size_t oldlen; mib[0] = CTL_KERN; mib[1] = KERN_IOV_MAX; oldlen = sizeof(maxiov); if (sysctl(&mib[0],2,&maxiov,&oldlen,0,0) < 0) { logmsg(LM_ERR|LM_PEER,"can't get kern.iov_max: %s",strerror(errno)); exit(1); } if (maxiov > 64) maxiov = 64; if (maxiov < 1) maxiov = 1; iov = 0; iovn = 0; } iovl = 0; for (e=q->head;e;e=e->link) { if (iovl >= maxiov) break; if (e->special) { int rv; if (iovl > 0) break; rv = (*dospecial)(e->spec.vp,e->spec.i); if (! (q->head = e->link)) q->tail = &q->head; free(e); return(rv); } if (iovl >= iovn) iov = realloc(iov,(iovn=iovl+4)*sizeof(*iov)); iov[iovl++] = (struct iovec){ .iov_base=dequal(e->norm.data), .iov_len=e->norm.left }; } return(writev(fd,iov,iovl)); } int oq_dropdata(OQ *q, int n) { OQE *e; while ((e=q->head) && n && (n >= e->norm.left)) { if (e->special) panic("dropping special"); q->head = e->link; q->len -= e->norm.left; n -= e->norm.left; free(e->norm.datafree); free(e); } if (e) { if (n) { e->norm.data += n; e->norm.left -= n; q->len -= n; } return(0); } else { q->tail = &q->head; if (q->len) panic("empty queue with nonzero length"); return(1); } } int oq_canthappen(void *vp __attribute__((__unused__)), int i __attribute__((__unused__))) { panic("called"); } void oq_flush(OQ *q) { OQE *e; while (q->head) { e = q->head; q->head = e->link; if (! e->special) free(e->norm.datafree); free(e); } q->len = 0; q->tail = &q->head; }