chiark / gitweb /
branch is closed
[adns.git] / regress / hcommon.c
1 #include <string.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include "harness.h"
12 #include "internal.h"
13 vbuf vb;
14 FILE *Toutputfile= 0;
15 struct timeval currenttime;
16 const struct Terrno Terrnos[]= {
17   { "EBADF",                     EBADF                        },
18   { "EAGAIN",                    EAGAIN                       },
19   { "EINPROGRESS",               EINPROGRESS                  },
20   { "EINTR",                     EINTR                        },
21   { "EINVAL",                    EINVAL                       },
22   { "EMSGSIZE",                  EMSGSIZE                     },
23   { "ENOBUFS",                   ENOBUFS                      },
24   { "ENOENT",                    ENOENT                       },
25   { "ENOPROTOOPT",               ENOPROTOOPT                  },
26   { "ENOSPC",                    ENOSPC                       },
27   { "EWOULDBLOCK",               EWOULDBLOCK                  },
28   { "EHOSTUNREACH",              EHOSTUNREACH                 },
29   { "ECONNRESET",                ECONNRESET                   },
30   { "ECONNREFUSED",              ECONNREFUSED                 },
31   { "EPIPE",                     EPIPE                        },
32   { "ENOTSOCK",                  ENOTSOCK                     },
33   {  0,                          0                            }
34 };
35 static vbuf vbw;
36 int Hgettimeofday(struct timeval *tv, struct timezone *tz) {
37   Tmust("gettimeofday","tz",!tz);
38   *tv= currenttime;
39   return 0;
40 }
41 int Hwritev(int fd, const struct iovec *vector, size_t count) {
42   size_t i;
43   vbw.used= 0;
44   for (i=0; i<count; i++, vector++) {
45     if (!adns__vbuf_append(&vbw,vector->iov_base,vector->iov_len)) Tnomem();
46   }
47   return Hwrite(fd,vbw.buf,vbw.used);
48 }
49 void Qselect(   int max , const fd_set *rfds , const fd_set *wfds , const fd_set *efds , struct timeval *to     ) {
50  vb.used= 0;
51  Tvba("select");
52         Tvbf(" max=%d",max); 
53         Tvbf(" rfds="); Tvbfdset(max,rfds); 
54         Tvbf(" wfds="); Tvbfdset(max,wfds); 
55         Tvbf(" efds="); Tvbfdset(max,efds); 
56   if (to) Tvbf(" to=%ld.%06ld",(long)to->tv_sec,(long)to->tv_usec);
57   else Tvba(" to=null"); 
58   Q_vb();
59 }
60 #ifdef HAVE_POLL
61 void Qpoll(     const struct pollfd *fds , int nfds , int timeout       ) {
62  vb.used= 0;
63  Tvba("poll");
64         Tvbf(" fds="); Tvbpollfds(fds,nfds); 
65         Tvbf(" timeout=%d",timeout); 
66   Q_vb();
67 }
68 #endif
69 void Qsocket(    int type       ) {
70  vb.used= 0;
71  Tvba("socket");
72   Tvbf(type==SOCK_STREAM ? " type=SOCK_STREAM" : " type=SOCK_DGRAM"); 
73   Q_vb();
74 }
75 void Qfcntl(    int fd , int cmd , long arg     ) {
76  vb.used= 0;
77  Tvba("fcntl");
78         Tvbf(" fd=%d",fd); 
79   if (cmd == F_SETFL) {
80    Tvbf(" cmd=F_SETFL %s",arg & O_NONBLOCK ? "O_NONBLOCK|..." : "~O_NONBLOCK&...");
81   } else if (cmd == F_GETFL) {
82    Tvba(" cmd=F_GETFL");
83   } else {
84    Tmust("cmd","F_GETFL/F_SETFL",0);
85   } 
86   Q_vb();
87 }
88 void Qconnect(  int fd , const struct sockaddr *addr , int addrlen      ) {
89  vb.used= 0;
90  Tvba("connect");
91         Tvbf(" fd=%d",fd); 
92         Tvba(" addr="); Tvbaddr(addr,addrlen); 
93   Q_vb();
94 }
95 void Qclose(    int fd  ) {
96  vb.used= 0;
97  Tvba("close");
98         Tvbf(" fd=%d",fd); 
99   Q_vb();
100 }
101 void Qsendto(   int fd , const void *msg , int msglen , const struct sockaddr *addr , int addrlen       ) {
102  vb.used= 0;
103  Tvba("sendto");
104         Tvbf(" fd=%d",fd); 
105         Tvba(" addr="); Tvbaddr(addr,addrlen); 
106         Tvbbytes(msg,msglen); 
107   Q_vb();
108 }
109 void Qrecvfrom( int fd , int buflen , int addrlen       ) {
110  vb.used= 0;
111  Tvba("recvfrom");
112         Tvbf(" fd=%d",fd); 
113         Tvbf(" buflen=%lu",(unsigned long)buflen); 
114         Tvbf(" *addrlen=%d",addrlen); 
115   Q_vb();
116 }
117 void Qread(     int fd , size_t buflen  ) {
118  vb.used= 0;
119  Tvba("read");
120         Tvbf(" fd=%d",fd); 
121         Tvbf(" buflen=%lu",(unsigned long)buflen); 
122   Q_vb();
123 }
124 void Qwrite(    int fd , const void *buf , size_t len   ) {
125  vb.used= 0;
126  Tvba("write");
127         Tvbf(" fd=%d",fd); 
128         Tvbbytes(buf,len); 
129   Q_vb();
130 }
131 void Tvbaddr(const struct sockaddr *addr, int len) {
132   const struct sockaddr_in *ai= (const struct sockaddr_in*)addr;
133   assert(len==sizeof(struct sockaddr_in));
134   assert(ai->sin_family==AF_INET);
135   Tvbf("%s:%u",inet_ntoa(ai->sin_addr),htons(ai->sin_port));
136 }
137 void Tvbbytes(const void *buf, int len) {
138   const byte *bp;
139   int i;
140   if (!len) { Tvba("\n     ."); return; }
141   for (i=0, bp=buf; i<len; i++, bp++) {
142     if (!(i&31)) Tvba("\n     ");
143     else if (!(i&3)) Tvba(" ");
144     Tvbf("%02x",*bp);
145   }
146   Tvba(".");
147 }
148 void Tvbfdset(int max, const fd_set *fds) {
149   int i;
150   const char *comma= "";
151   Tvba("[");
152   for (i=0; i<max; i++) {
153     if (!FD_ISSET(i,fds)) continue;
154     Tvba(comma);
155     Tvbf("%d",i);
156     comma= ",";
157   }
158   Tvba("]");
159 }
160 static void Tvbpollevents(int events) {
161   const char *delim= "";
162   events &= (POLLIN|POLLOUT|POLLPRI);
163   if (!events) { Tvba("0"); return; }
164   if (events & POLLIN) { Tvba("POLLIN"); delim= "|"; }
165   if (events & POLLOUT) { Tvba(delim); Tvba("POLLOUT"); delim= "|"; }
166   if (events & POLLPRI) { Tvba(delim); Tvba("POLLPRI"); }
167 }
168 void Tvbpollfds(const struct pollfd *fds, int nfds) {
169   const char *comma= "";
170   Tvba("[");
171   while (nfds>0) {
172     Tvba(comma);
173     Tvbf("{fd=%d, events=",fds->fd);
174     Tvbpollevents(fds->events);
175     Tvba(", revents=");
176     Tvbpollevents(fds->revents);
177     Tvba("}");
178     comma= ", ";
179     nfds--; fds++;
180   }
181   Tvba("]");
182 }
183 void Tvberrno(int e) {
184   const struct Terrno *te;
185   for (te= Terrnos; te->n && te->v != e; te++);
186   assert(te->n);
187   Tvba(te->n);
188 }
189 void Tvba(const char *str) {
190   if (!adns__vbuf_appendstr(&vb,str)) Tnomem();
191 }
192 void Tvbvf(const char *fmt, va_list al) {
193   char buf[1000];
194   buf[sizeof(buf)-2]= '\t';
195   vsnprintf(buf,sizeof(buf),fmt,al);
196   assert(buf[sizeof(buf)-2] == '\t');
197   Tvba(buf);
198 }
199 void Tvbf(const char *fmt, ...) {
200   va_list al;
201   va_start(al,fmt);
202   Tvbvf(fmt,al);
203   va_end(al);
204 }
205 void Tmust(const char *call, const char *arg, int cond) {
206   if (cond) return;
207   fprintf(stderr,"adns test harness: case not handled: system call %s, arg %s",call,arg);
208   exit(-1);
209 }
210 void Tfailed(const char *why) {
211   fprintf(stderr,"adns test harness: failure: %s: %s\n",why,strerror(errno));
212   exit(-1);
213 }
214 void Tnomem(void) {
215   Tfailed("unable to malloc/realloc");
216 }
217 void Toutputerr(void) {
218   Tfailed("write error on test harness output");
219 }
220 struct malloced {
221   struct malloced *next, *back;
222   size_t sz;
223   unsigned long count;
224   struct { double d; long ul; void *p; void (*fp)(void); } data;
225 };
226 static unsigned long malloccount, mallocfailat;
227 static struct { struct malloced *head, *tail; } mallocedlist;
228 #define MALLOCHSZ ((char*)&mallocedlist.head->data - (char*)mallocedlist.head)
229 void *Hmalloc(size_t sz) {
230   struct malloced *newnode;
231   const char *mfavar;
232   char *ep;
233   assert(sz);
234   newnode= malloc(MALLOCHSZ + sz);  if (!newnode) Tnomem();
235   LIST_LINK_TAIL(mallocedlist,newnode);
236   newnode->sz= sz;
237   newnode->count= ++malloccount;
238   if (!mallocfailat) {
239     mfavar= getenv("ADNS_REGRESS_MALLOCFAILAT");
240     if (mfavar) {
241       mallocfailat= strtoul(mfavar,&ep,10);
242       if (!mallocfailat || *ep) Tfailed("ADNS_REGRESS_MALLOCFAILAT bad value");
243     } else {
244       mallocfailat= ~0UL;
245     }
246   }
247   assert(newnode->count != mallocfailat);
248   memset(&newnode->data,0xc7,sz);
249   return &newnode->data;
250 }
251 void Hfree(void *ptr) {
252   struct malloced *oldnode;
253   if (!ptr) return;
254   oldnode= (void*)((char*)ptr - MALLOCHSZ);
255   LIST_UNLINK(mallocedlist,oldnode);
256   memset(&oldnode->data,0x38,oldnode->sz);
257   free(oldnode);
258 }
259 void *Hrealloc(void *op, size_t nsz) {
260   struct malloced *oldnode;
261   void *np;
262   size_t osz;
263   if (op) { oldnode= (void*)((char*)op - MALLOCHSZ); osz= oldnode->sz; } else { osz= 0; }
264   np= Hmalloc(nsz);
265   memcpy(np,op, osz>nsz ? nsz : osz);
266   Hfree(op);
267   return np;
268 }
269 void Hexit(int rv) {
270   struct malloced *loopnode;
271   Tshutdown();
272   adns__vbuf_free(&vb);
273   adns__vbuf_free(&vbw);
274   if (mallocedlist.head) {
275     fprintf(stderr,"adns test harness: memory leaked:");
276     for (loopnode=mallocedlist.head; loopnode; loopnode=loopnode->next)
277       fprintf(stderr," %lu(%lu)",loopnode->count,(unsigned long)loopnode->sz);
278     putc('\n',stderr);
279     if (ferror(stderr)) exit(-1);
280   }
281   exit(rv);
282 }