9 #include <netinet/in.h>
11 #include <sys/types.h>
20 #include <sys/resource.h>
23 #include <sys/socket.h>
31 const int safesigs[]={SIGQUIT,SIGINT,SIGTERM,SIGIOT,SIGALRM,-1}; //SIGCHLD->childsignal anyway
34 void chk(const void *p)
38 VB_FATAL(CRIT,"NULL-check failure, memory exhausted? FATAL: %m");
42 static void *vbchecknull=NULL;
43 static struct varbuf *vbcheckhead=(struct varbuf *)&vbchecknull;
44 static unsigned vbchecknum;
45 #ifdef FATALSIG_INSANE
46 static char vbcheckno;
52 static pthread_mutex_t vbcheckmx=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
53 static void vbchecklock (void)
54 { if (pthread_mutex_lock (&vbcheckmx)) VB_FATAL(CRIT,"Mutex ""lock on vbcheck mx"); }
55 static void vbcheckunlock(void)
56 { if (pthread_mutex_unlock(&vbcheckmx)) VB_FATAL(CRIT,"Mutex unlock on vbcheck mx"); }
59 #define vbcheckunlock()
62 static char vbchecklist(struct varbuf *vb)
70 for (vbs=vbcheckhead;vbs;vbs=vbs->checknext,tot++)
76 assert(vb->checknext);
77 while (tot++,(vbs=vbs->checknext)!=vbchecknull) assert(vb!=vbs);
78 assert(tot==vbchecknum+1);
83 void vbcheck(struct varbuf *vb)
85 struct varbufnode *vbn;
89 if (vbcheckno) return; vbchecklock();
90 assert(vbchecklist(vb));
91 if (vb->done) assert(!!vb->f);
92 if (vb->free) assert(!!vb->l);
93 assert((!vb->f)==(!vb->f));
94 for (vbn=vb->f;vbn;vbn=vbn->next) {
95 if (vbn==vb->f) assert(vb->done<=vbn->size);
96 if (vbn==vb->l) assert(vb->free<=vbn->size);
97 for (s=vbn->buf;s<vbn->buf+vbn->size;s++) touch=*s;
106 if (vbcheckno) return; vbchecklock();
107 assert(!vbchecknull);
108 for (vb=vbcheckhead;vb!=(struct varbuf *)&vbchecknull;vb=vb->checknext) vbcheck(vb);
114 void vbdebug(struct varbuf *vb,const char *msg)
116 struct varbufnode *vbn;
117 fprintf(stderr,"vbdebug(%s): vb=%p",msg,vb);
120 fprintf(stderr,"\n");
123 fprintf(stderr,", first=%p, last=%p, done=%u, free=%u\n",vb->f,vb->l,vb->done,vb->free);
124 for (vbn=vb->f;vbn;vbn=vbn->next) {
126 fprintf(stderr," *VBN: %p: size=%u, buf:",vbn,vbn->size);
127 for (i=0;i<vbn->size;i++) {
129 if (isprint(c)) fprintf(stderr," '%c'",c);
130 else fprintf(stderr," %02x",(unsigned char)c);
132 fprintf(stderr,"\n");
134 fprintf(stderr,"vbdebug(%s): finishing...\n",msg);
138 struct varbufnode *vbnnew(size_t sugsize)
140 struct varbufnode *r;
141 if (!vbnexact && sugsize<VB_DEFSIZE) sugsize=VB_DEFSIZE;
142 chk(r=malloc(sizeof(*r)+sugsize));
148 void vbgrow(struct varbuf *vb,size_t sugsize)
150 struct varbufnode *vbn;
151 vbdebug(vb,"vbgrow");
154 if (vb->l && vb->l->size>sugsize) sugsize=vb->l->size;
155 if (sugsize*2<=VB_MAXSIZE) sugsize*=2;
156 else if (sugsize<VB_MAXSIZE) sugsize=VB_MAXSIZE;
159 if (vb->l) vb->l->next=vbn;
165 void vbinit(struct varbuf *vb)
168 if (!vbcheckno) assert(!vbchecklist(vb));
170 bzero(vb,sizeof(*vb));
173 vb->checknext=vbcheckhead;
181 struct varbufnode *vbremone(struct varbuf *vb)
183 struct varbufnode *r;
184 vbdebug(vb,"vbremone");
196 void vbclear(struct varbuf *vb)
198 vbdebug(vb,"vbclear");
199 while (vb->f) vbremone(vb);
202 void vbrem(struct varbuf *vb)
212 assert(vbchecknum>0);
213 for (vbp=&vbcheckhead;*vbp;vbp=&(*vbp)->checknext)
217 bzero(vb,sizeof(*vb));
222 size_t vbsize(struct varbuf *vb,size_t maxsize)
225 struct varbufnode *vbn=vb->f;
227 vbdebug(vb,"vbsize");
228 while (vbn && (!maxsize || size<maxsize)) {
229 size+=VBNSIZE(vb,vbn);
235 #define GENVARBUFC(argmid) \
236 void vbput##argmid(struct varbuf *vb,const argmid arg) \
237 { vbwrite(vb,&arg,sizeof(arg)); } \
238 char vbget##argmid(struct varbuf *vb,argmid *argp) \
239 { if (sizeof(*argp)>1 && !VBCHKSIZE(vb,sizeof(*argp))) return(0); \
240 return(vbread(vb,argp,sizeof(*argp))); }
242 #ifndef INLINE_PUTGETCHAR
250 void vbwrite(struct varbuf *vb,const void *buf,size_t count)
254 vbdebug(vb,"vbwrite");
258 memcpy(vb->l->buf+VBNSIZEL(vb,vb->l),buf,(now=min(vb->free,count)));
265 assert(vb->free>=count);
266 assert(vb->l&&vb->l->size==vb->free);
267 memcpy(vb->l->buf,buf,count);
272 extern size_t vbputstring(struct varbuf *vb,const char *s)
279 ssize_t vbwritefd(struct varbuf *vb,int fd)
283 vbdebug(vb,"vbwritefd");
285 if (!vb->free) vbgrow(vb,0);
286 now=read(fd,vb->l->buf+vb->l->size-vb->free,vb->free);
287 dbg("vbwritefd: now=%d\n",now);
289 if (errno==EAGAIN) break;
302 size_t vbpeek(struct varbuf *vb,ssize_t offs,void *buf,size_t count)
304 size_t got=0,now,size;
306 struct varbufnode *vbn=vb->f;
308 vbdebug(vb,"vbpeek");
309 if ((doread=(offs==-1))) offs=0;
311 while (vbn && count) {
312 size=VBNSIZEL(vb,vbn);
314 memcpy(buf,vbn->buf+offs,(now=min(count,size-offs)));
325 if (!VBNSIZE(vb,vb->f)) {
335 ssize_t vbchrn(struct varbuf *vb,ssize_t offs,char c,char dir)
339 struct varbufnode *vbn;
341 struct varbufnode *vbn;
342 ssize_t distoffs=0,size=vbsize(vb,0);
345 if (offs==-1 || offs>=size) {
346 if (dir>0) return(-1);
349 if (offs<0) return(-1);
353 while (vbn && offs>=vbn->size) {
355 chk(vbl2=alloca(sizeof(*vbl2)));
365 if (dir<0) for (;;) {
366 if (vbn && offs<VBNSIZEL(vb,vbn)) {
367 ssize_t start=VBNSTART(vb,vbn); // FIXME: not really - GCC bug! (size_t crashes)
368 dbg("seeking back... start=%u,offs=%d,vbn->size=%u\n",start,offs,vbn->size);
369 while (offs>=start&&vbn->buf[offs]!=c) offs--;
370 if (offs>=start) return(distoffs+offs);
379 if (dir>0) while (vbn) {
380 size_t size=VBNSIZEL(vb,vbn);
382 dbg("vbn=%p,offs=%d,size=%d\n",vbn,offs,size);
384 if ((s=memchr(vbn->buf+offs,c,size-offs)))
385 return(distoffs+(s-vbn->buf));
393 ssize_t vbreadfd(struct varbuf *vb,int fd)
397 vbdebug(vb,"vbreadfd");
398 dbg("entering vbreadfd(fd=%d)\n",fd);
400 size_t size=VBNSIZE(vb,vb->f);
401 now=write(fd,vb->f->buf+vb->done,size);
402 dbg("vbreadfd: now=%d\n",now);
403 if (now<0 && errno!=EAGAIN) return(now);
404 if (now<=0) return(got);
406 assert(vb->done<=size);
408 if (!VBNSIZE(vb,vb->f))
416 static void fixupnulls(char *s,size_t len,const char *fname)
421 for (d=s;(d=memchr(d,'\0',s+len-d));) { *d++=' '; tot++; }
423 #define ARG "%s() replaced %u '\\0's by ' ' in: %.*s",fname,tot,(int)len,s
424 #define VB_LOG1(a,b) VB_LOG(a,b)
433 char *vbgetline(struct varbuf *vb,char term)
438 if (!(len=vbchrn(vb,0,term,1)+1)) return(NULL);
441 r=vbread(vb,s,len); assert(r==len);
442 assert(s[len-1]==term);
444 fixupnulls(s,len-1,"vbgetline");
448 size_t chkvsprintf(char **sp,const char *fmt,va_list ap)
450 size_t bufsize=VB_DEFSIZE;
454 chk(*sp=realloc(*sp,bufsize));
455 i=vsnprintf(*sp,bufsize,fmt,ap);
456 dbg("chkvsprintf: bufsize=%u,i=%d,fmt:%s\n",bufsize,i,fmt);
457 if (i>=0&&i<bufsize) break;
464 size_t vbvprintf(struct varbuf *vb,const char *fmt,va_list ap,char remlf)
469 len=chkvsprintf(&buf,fmt,ap);
472 for (s=buf;(c=*s);s++) {
473 if (c<0 || (c>=' '&&c!='\\')) {
479 case '\n' : vbputchar(vb,'n'); break;
480 case '\r' : vbputchar(vb,'r'); break;
481 case 1 ... 9: //FALLTHRU
482 case 11 ... 12: //FALLTHRU
483 case 14 ... 31: vbprintf(vb,"x%02X",c); break;
484 case '\\' : vbputchar(vb,'\\'); break;
489 else vbwrite(vb,buf,len);
494 size_t vbprintf(struct varbuf *vb,const char *fmt,...) //stub
500 r=vbvprintf(vb,fmt,ap,0);
506 #define PSTR_MAX 65535
507 #define PSTR_TYPE short
510 #define PSTR_TYPE char
513 #define PSTR_PUTLEN2(vb,len,type) vbput##type((vb),(type)(len))
514 #define PSTR_PUTLEN1(vb,len,type) PSTR_PUTLEN2(vb,len,type)
515 #define PSTR_PUTLEN(vb,len) PSTR_PUTLEN1((vb),(len),PSTR_TYPE)
517 void vbpstrputstring(struct varbuf *vb,const char *s)
519 size_t len=strlen(s);
521 VB_LOG(CRIT,"String longer (%u) than PSTRing max (%u)",len,PSTR_MAX);
523 dbg("vbpstrputstring-longer than MAX: \"%s\"\n",s);
529 size_t vbpstrcopy(struct varbuf *vbd,struct varbuf *vbs,ssize_t len)
532 if (len==-1) len=vbsize(vbs,0);
533 else if ((size=vbsize(vbs,len))<len) len=size;
536 VB_LOG(CRIT,"String longer (%u) than PSTRing max (%u)",len,PSTR_MAX);
538 vbdebug(vbs,"vbpstrputstring-longer than MAX");
540 PSTR_PUTLEN(vbd,len);
542 if (was!=len) vbdrop(vbs,was-len);
546 void vbpstrprintf(struct varbuf *vb,const char *fmt,...)
549 char buf[PSTR_MAX+1];
553 i=vsnprintf(buf,sizeof(buf),fmt,ap);
556 VB_LOG(CRIT,"Buffer overflow (max=%u) during PSTR printf",PSTR_MAX);
559 assert(i>=0 && i<=PSTR_MAX && !buf[i]);
560 vbpstrputstring(vb,buf);
563 char *vbpstrread(struct varbuf *vb)
565 unsigned PSTR_TYPE len,scan,chgd=0;
569 if (!vbpeek(vb,0,&len,sizeof(len))) return(NULL);
570 if (!VBCHKSIZE(vb,1+len)) return(NULL);
571 chk(buf=malloc(len+1));
572 vbdrop(vb,sizeof(len));
573 r=vbread(vb,buf,len); assert(r==len);
575 for (scan=0;scan<len;scan++)
581 VB_LOG(CRIT,"'\\0's found (%u total) in read PSTR \"%s\", changed to '?'",chgd,buf);
585 size_t vbcopy(struct varbuf *vbd,struct varbuf *vbs,ssize_t count)
589 vbdebug(vbd,"vbcopy-dest");
590 vbdebug(vbs,"vbcopy-src");
591 dbg("vbcopy-count=%d\n",count);
592 got=vbsize(vbs,(count==-1?0:count));
593 if (count==-1 || count>got) count=got;
595 dbg("got=%u, vbd->free=%u, count=%d\n",got,vbd->free,count);
596 if (!count) return(got);
598 dbg("vbd->free=%d path\n",vbd->free);
599 vbdebug(vbd,"vbd->free-s:vbd");
600 assert(vbd->f && vbd->l);
601 r=vbread(vbs,vbd->l->buf+VBNSIZEL(vbd,vbd->l),(now=min(count,vbd->free))); assert(r==now);
602 dbg("now=%u,vbd->free=%u,count=%u\n",now,vbd->free,count);
605 vbdebug(vbd,"vbd->free-e:vbd");
606 if (!count) return(got);
609 dbg("vbs->done=%u\n",vbs->done);
611 assert(!VBEMPTY(vbs));
613 dbg("vbs->done=%d path\n",vbs->done);
614 vbdebug(vbs,"vbs->done-s:vbs");
615 vbdebug(vbd,"vbs->done-s:vbd");
617 vbgrow(vbd,(now=min(count,VBNSIZE(vbs,vbs->f))));
619 assert(vbd->l && vbd->l->size==now && vbd->free==now);
620 r=vbread(vbs,vbd->l->buf,now); assert(r==now);
624 dbg("in vbs->done: count=%d, now=%u\n",count,now);
625 vbdebug(vbs,"vbs->done-e:vbs");
626 vbdebug(vbd,"vbs->done-e:vbd");
627 if (!count) return(got);
630 vbdebug(vbs,"relink:vbs");
631 vbdebug(vbd,"relink:vbd");
632 while (count && VBNSIZEL(vbs,vbs->f)<=count) {
633 struct varbufnode *vbn=vbs->f;
635 if (!(vbs->f=vbn->next)) {
637 count+=(vbd->free=vbs->free);
651 if (!count) return(got);
653 vbdebug(vbs,"final:vbs");
654 vbdebug(vbd,"final:vbd");
656 assert(vbd->l && vbd->l->size>=count && vbd->free==vbd->l->size);
657 vbread(vbs,vbd->l->buf,count);
659 assert(vbd->free>=0);
663 unsigned short vbxsum(struct varbuf *vb)
665 unsigned short xsum=0;
667 struct varbufnode *vbn;
669 vbdebug(vb,"vbxsum");
673 size_t size=VBNSIZEL(vb,vbn);
675 xsum+=(unsigned char)vbn->buf[offs];
681 dbg("vbxsum=%u\n",(unsigned)xsum);
685 char vbremlast(struct varbuf *vb)
687 struct varbufnode *vbn;
689 vbdebug(vb,"vbremlast");
690 if (VBEMPTY(vb)) return(0);
691 assert(vb->l&&vb->free<=vb->l->size);
692 if (vb->free<vb->l->size) {
694 vbdebug(vb,"vbremlast-stdend");
697 assert(vb->f!=vb->l);
698 for (vbn=vb->f;vbn->next!=vb->l;vbn=vbn->next)
705 vbdebug(vb,"vbremlast-blasting-end");
709 void vbdrop(struct varbuf *vb,size_t len)
711 struct varbufnode *vbn;
713 assert(VBCHKSIZE(vb,len));
715 while (vb->f&&vb->done>=VBNSIZEL(vb,vb->f)) {
716 vb->done-=VBNSIZEL(vb,vb->f);
718 if (!(vb->f=vbn->next)) {
725 if (!vb->f) assert(!vb->done&&!vb->free&&!vb->l);
728 void vbgetlinef(struct varbuf *vb,FILE *f)
730 char buf[LOGF_FGETS_BUF],*s;
732 dbg("vbgetlinef(), tell=0x%lx\n",ftell(f));
734 if (!fgets(buf,sizeof(buf),f)) {
735 dbg("vbgetlinef: fgets=NULL\n");
737 VB_FATAL(ERR,"linereading fail: %m");
739 dbg("vbgetlinef: fgets: %s\n",buf);
740 if ((s=strchr(buf,'\n'))) break;
743 vbwrite(vb,buf,s-buf);
744 dbg("vbgetlinef(f), ftell=0x%lx\n",ftell(f));
747 ssize_t vbcopyline(struct varbuf *vbd,struct varbuf *vbs)
750 if ((len=vbchrn(vbs,0,'\n',1))==-1) return(-1);
751 r=vbcopy(vbd,vbs,len); assert(r==len);
756 char vbdropline(struct varbuf *vb)
759 if ((len=vbchrn(vb,0,'\n',1))==-1) return(0);
764 char *vbmemorize(struct varbuf *vb,unsigned flg,size_t *sizep)
766 ssize_t len=vbsize(vb,0),r;
768 if (sizep) *sizep=len;
769 chk(s=malloc(len+!!(flg&VBMEM_ZERO)));
770 r=vbpeek(vb,(flg&VBMEM_REM?-1:0),s,len); assert(r==len);
771 if (flg&VBMEM_ZERO) {
773 fixupnulls(s,len,"vbmemorize");
775 if (flg&VBMEM_REM) assert(VBEMPTY(vb));
779 char *vbstringify(struct varbuf *vb,char rem)
780 { return vbmemorize(vb,VBMEM_ZERO|(rem?VBMEM_REM:0),NULL); }
782 const char *signames[]={
783 "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "IOT", "BUS", "FPE", "KILL",
784 "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT",
785 "STOP", "TSTP", "TTIN", "TTOU", "URG", "XCPU", "XFSZ", "VTALRM", "PROF",
786 "WINCH", "IO", "PWR", "UNUSED" };
788 void abortsignal(int signo)
789 { //no reinstall! (deadlock!)
790 #ifdef FATALSIG_INSANE
793 signal(signo,SIG_DFL);
794 dbg("Got signal %d\n",signo);
798 struct varbuf *chat_vbout;
800 char *chat_cmdpars[CHAT_CMD_MAXPARS];
802 static void chatfn_help(void);
804 static const struct chat_cmdtab chat_cmdint[]={
805 {"help" ,0,chatfn_help ,"This help"},
807 {"quit" ,0,chatfn_quit ,"Close connection"},
808 {"exit" ,0,chatfn_quit ,"Close connection"},
812 static void chatfn_help(void)
815 const struct chat_cmdtab *cmd,*cmdt;
817 vbputstring(chat_vbout,"000 Available commands:\n");
819 for (i=0;i<NELEM(chat_cmdint);) {
820 if (cmdt->name) cmd=cmdt++;
821 else cmd=&chat_cmdint[i++];
822 vbprintf(chat_vbout,"000 %-10s[%d] - %s\n",cmd->name,(int)cmd->npars,cmd->help);
824 vbputstring(chat_vbout,"102 Help end.\n");
827 static inline void chat_parsepars(char *s)
832 if (*s) for (*s++='\0';*s&&isspace(*s);s++);
833 for (c=*s;c&&chat_cmdpar<CHAT_CMD_MAXPARS;chat_cmdpar++) {
835 for (chat_cmdpars[chat_cmdpar]=d=s;*s&&(quote||(!quote&&*s!=','));s++) {
836 if (*s=='"'||*s=='\'') {
837 if (quote==*s) { quote=0; continue; }
838 if (!quote) { quote=*s; continue; }
840 if (*s=='\\'&&s[1]) s++;
847 void chat_proccmd(const char *who,char *buf)
851 const struct chat_cmdtab *cmd,*cmdt;
853 for (cmds=buf;*cmds&&isspace(*cmds);cmds++);
854 for (s=cmds;*s&&!isspace(*s);s++);
856 vbputstring(chat_vbout,"104 Empty command.\n");
861 for (i=0;i<NELEM(chat_cmdint);) {
862 if (cmdt->name) cmd=cmdt++;
863 else cmd=&chat_cmdint[i++];
864 assert(cmd->npars<=CHAT_CMD_MAXPARS);
865 if (!strcmp(cmd->name,cmds)) break;
867 if (i<NELEM(chat_cmdint)) {
868 if (cmd->npars!=chat_cmdpar)
869 vbprintf(chat_vbout,"205 %d parameter%s found, %d expected!\n",chat_cmdpar,(chat_cmdpar==1?"":"s"),cmd->npars);
871 vbprintf(chat_vbout,"001 Running command: %s\n",cmds);
872 VB_LOG(DEBUG,"%s is executing user command \"%s\"",who,cmds);
876 else vbprintf(chat_vbout,"206 Unknown command \"%s\"!\n",cmds);
879 void crfilter(char *sr)
883 if (*sr!='\r') *sw++=*sr;
887 static void tzchange(const char *tz)
889 static char *otz=NULL;
893 if ((otz=getenv("TZ"))) chk(otz=strdup(otz));
906 char *gmctime(time_t tm)
913 if ((s=strchr(r,'\n')))
919 unsigned char *bitshuffle(unsigned char *dst,unsigned char dstb,const unsigned char *src,unsigned char srcb,size_t bits,char lr)
921 unsigned char dstrem,*dstp,srcrem,now;
922 const unsigned char *srcp;
924 if (!dst) chk(dst=malloc((bits+dstb-1)/dstb));
925 dstrem=0; dstp=dst-1;
926 srcrem=0; srcp=src-1;
936 dbg("dstrem=%u,srcrem=%u,bits=%u\n",dstrem,srcrem,bits);
937 assert(dstrem&&srcrem);
938 now=min(dstrem,srcrem);
940 dbg("1:*dstp=0x%02x,*srcp=0x%02x,dstrem=%u,srcrem=%u,now=%u\n",*dstp,*srcp,dstrem,srcrem,now);
941 *dstp|=((*srcp>>(lr?srcrem-now:srcb-srcrem))&((1U<<now)-1))<<(lr?dstrem-now:dstb-dstrem);
945 dbg("2:*dstp=0x%02x,*srcp=0x%02x,dstrem=%u,srcrem=%u,now=%u\n",*dstp,*srcp,dstrem,srcrem,now);
950 char *enbase64(char *dst,const unsigned char *src,size_t bits)
954 if (!dst) chk(dst=malloc(((bits+23)/24)*4+1));
955 d=bitshuffle(dst,6,src,8,bits,1); assert(d==dst);
956 d=dst+(bits=(bits+5)/6);
957 for (s=dst;s<d;s++) switch (*s) {
958 case 0 ... 25: *s+='A'- 0; break;
959 case 26 ... 51: *s+='a'-26; break;
960 case 52 ... 61: *s+='0'-52; break;
961 case 62 : *s ='+' ; break;
962 case 63 : *s ='/' ; break;
965 while (bits++%4) *s++='=';
970 unsigned char *debase64(unsigned char *dst,const char *src,size_t *dstlp)
977 chk(src2=alloca(strlen(src))); /* +1 not needed */
978 for (sd=src2,s=src;*s;s++) switch (*s) {
979 case 'A' ... 'Z': *sd++=*s-('A'- 0); break;
980 case 'a' ... 'z': *sd++=*s-('a'-26); break;
981 case '0' ... '9': *sd++=*s-('0'-52); break;
982 case '+' : *sd++= ( 62); break;
983 case '/' : *sd++= ( 63); break;
985 /* only 0, 1 or 2 '='(s) permitted */
986 if (!s[1] || (s[1]=='=' && (!s[2] || (s[2]=='=' && !s[3]))))
989 default: return(NULL);
992 srcl=sd-src2; if ((srcl%4)==1) return(NULL);
994 if (!dst) chk(dst=malloc(dstl));
995 d=bitshuffle(dst,8,src2,6,dstl*8,1); assert(d==dst);
996 if (dstlp) *dstlp=dstl;