chiark / gitweb /
+ * Add pre-generated versions of m4-generated files in regress/.
[adns.git] / regress / hplayback.c
1 #include <assert.h>
2 #include <string.h>
3 #include <errno.h>
4 #include <stdlib.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 static FILE *Tinputfile, *Treportfile;
13 static vbuf vb2;
14 extern void Tshutdown(void) {
15   adns__vbuf_free(&vb2);
16 }
17 static void Tensurereportfile(void) {
18   const char *fdstr;
19   int fd;
20   if (Treportfile) return;
21   Treportfile= stderr;
22   fdstr= getenv("ADNS_TEST_REPORT_FD"); if (!fdstr) return;
23   fd= atoi(fdstr);
24   Treportfile= fdopen(fd,"a"); if (!Treportfile) Tfailed("fdopen ADNS_TEST_REPORT_FD");
25 }
26 static void Psyntax(const char *where) {
27   fprintf(stderr,"adns test harness: syntax error in test log input file: %s\n",where);
28   exit(-1);
29 }
30 static void Pcheckinput(void) {
31   if (ferror(Tinputfile)) Tfailed("read test log input file");
32   if (feof(Tinputfile)) Psyntax("eof at syscall reply");
33 }
34 static void Tensureinputfile(void) {
35   const char *fdstr;
36   int fd;
37   int chars;
38   unsigned long sec, usec;
39   if (Tinputfile) return;
40   Tinputfile= stdin;
41   fdstr= getenv("ADNS_TEST_IN_FD");
42   if (fdstr) {
43     fd= atoi(fdstr);
44     Tinputfile= fdopen(fd,"r"); if (!Tinputfile) Tfailed("fdopen ADNS_TEST_IN_FD");
45   }
46   setvbuf(Tinputfile,0,_IONBF,0);
47   if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
48   fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
49   chars= -1;
50   sscanf(vb2.buf," start %lu.%lu%n",&sec,&usec,&chars);
51   if (chars==-1) Psyntax("start time invalid");
52   currenttime.tv_sec= sec;
53   currenttime.tv_usec= usec;
54   if (vb2.buf[chars] != '\n') Psyntax("not newline after start time");
55 }
56 static void Parg(const char *argname) {
57   int l;
58   if (vb2.buf[vb2.used++] != ' ') Psyntax("not a space before argument");
59   l= strlen(argname);
60   if (memcmp(vb2.buf+vb2.used,argname,l)) Psyntax("argument name wrong");
61   vb2.used+= l;
62   if (vb2.buf[vb2.used++] != '=') Psyntax("not = after argument name");
63 }
64 static int Pstring_maybe(const char *string) {
65   int l;
66   l= strlen(string);
67   if (memcmp(vb2.buf+vb2.used,string,l)) return 0;
68   vb2.used+= l;
69   return 1;
70 }
71 static void Pstring(const char *string, const char *emsg) {
72   if (Pstring_maybe(string)) return;
73   Psyntax(emsg);
74 }
75 static int Perrno(const char *stuff) {
76   const struct Terrno *te;
77   int r;
78   char *ep;
79   for (te= Terrnos; te->n && strcmp(te->n,stuff); te++);
80   if (te->n) return te->v;
81   r= strtoul(stuff+2,&ep,10);
82   if (*ep) Psyntax("errno value not recognised, not numeric");
83   return r;
84 }
85 static void P_updatetime(void) {
86   int chars;
87   unsigned long sec, usec;
88   if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
89   fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
90   chars= -1;
91   sscanf(vb2.buf," +%lu.%lu%n",&sec,&usec,&chars);
92   if (chars==-1) Psyntax("update time invalid");
93   currenttime.tv_sec+= sec;
94   currenttime.tv_usec+= usec;
95   if (currenttime.tv_usec > 1000000) {
96     currenttime.tv_sec++;
97     currenttime.tv_usec -= 1000000;
98   }
99   if (vb2.buf[chars] != '\n') Psyntax("not newline after update time");
100 }
101 static void Pfdset(fd_set *set, int max) {
102   int r, c;
103   char *ep;
104   if (vb2.buf[vb2.used++] != '[') Psyntax("fd set start not [");
105   FD_ZERO(set);
106   if (vb2.buf[vb2.used] == ']') { vb2.used++; return; }
107   for (;;) {
108     r= strtoul(vb2.buf+vb2.used,&ep,10);
109     if (r>=max) Psyntax("fd set member > max");
110     if (ep == (char*)vb2.buf+vb2.used) Psyntax("empty entry in fd set");
111     FD_SET(r,set);
112     vb2.used= ep - (char*)vb2.buf;
113     c= vb2.buf[vb2.used++];
114     if (c == ']') break;
115     if (c != ',') Psyntax("fd set separator not ,");
116   }
117 }
118 #ifdef HAVE_POLL
119 static int Ppollfdevents(void) {
120   int events;
121   if (Pstring_maybe("0")) return 0;
122   events= 0;
123   if (Pstring_maybe("POLLIN")) {
124     events |= POLLIN;
125     if (!Pstring_maybe("|")) return events;
126   }
127   if (Pstring_maybe("POLLOUT")) {
128     events |= POLLOUT;
129     if (!Pstring_maybe("|")) return events;
130   }
131   Pstring("POLLPRI","pollfdevents PRI?");
132   return events;
133 }
134 static void Ppollfds(struct pollfd *fds, int nfds) {
135   int i;
136   char *ep;
137   const char *comma= "";
138   if (vb2.buf[vb2.used++] != '[') Psyntax("pollfds start not [");
139   for (i=0; i<nfds; i++) {
140     Pstring("{fd=","{fd= in pollfds");
141     fds->fd= strtoul(vb2.buf+vb2.used,&ep,10);
142     vb2.used= ep - (char*)vb2.buf;    
143     Pstring(", events=",", events= in pollfds");
144     fds->events= Ppollfdevents();
145     Pstring(", revents=",", revents= in pollfds");
146     fds->revents= Ppollfdevents();
147     Pstring("}","} in pollfds");
148     Pstring(comma,"separator in pollfds");
149     comma= ", ";
150   }
151   if (vb2.buf[vb2.used++] != ']') Psyntax("pollfds end not ]");
152 }
153 #endif
154 static void Paddr(struct sockaddr *addr, int *lenr) {
155   struct sockaddr_in *sa= (struct sockaddr_in*)addr;
156   char *p, *ep;
157   long ul;
158   assert(*lenr >= sizeof(*sa));
159   p= strchr(vb2.buf+vb2.used,':');
160   if (!p) Psyntax("no port on address");
161   *p++= 0;
162   memset(sa,0,sizeof(*sa));
163   sa->sin_family= AF_INET;
164   if (!inet_aton(vb2.buf+vb2.used,&sa->sin_addr)) Psyntax("invalid address");
165   ul= strtoul(p,&ep,10);
166   if (*ep && *ep != ' ') Psyntax("invalid port (bad syntax)");
167   if (ul >= 65536) Psyntax("port too large");
168   sa->sin_port= htons(ul);
169   *lenr= sizeof(*sa);
170   vb2.used= ep - (char*)vb2.buf;
171 }
172 static int Pbytes(byte *buf, int maxlen) {
173   static const char hexdigits[]= "0123456789abcdef";
174   int c, v, done;
175   const char *pf;
176   done= 0;
177   for (;;) {
178     c= getc(Tinputfile); Pcheckinput();
179     if (c=='\n' || c==' ' || c=='\t') continue;
180     if (c=='.') break;
181     pf= strchr(hexdigits,c); if (!pf) Psyntax("invalid first hex digit");
182     v= (pf-hexdigits)<<4;
183     c= getc(Tinputfile); Pcheckinput();
184     pf= strchr(hexdigits,c); if (!pf) Psyntax("invalid second hex digit");
185     v |= (pf-hexdigits);
186     if (maxlen<=0) Psyntax("buffer overflow in bytes");
187     *buf++= v;
188     maxlen--; done++;
189   }
190   for (;;) {
191     c= getc(Tinputfile); Pcheckinput();
192     if (c=='\n') return done;
193   }
194 }
195 void Q_vb(void) {
196   int r;
197   const char *nl;
198   Tensureinputfile();
199   if (!adns__vbuf_ensure(&vb2,vb.used+2)) Tnomem();
200   r= fread(vb2.buf,1,vb.used+2,Tinputfile);
201   if (feof(Tinputfile)) {
202     fprintf(stderr,"adns test harness: input ends prematurely; program did:\n %.*s\n",
203            vb.used,vb.buf);
204     exit(-1);
205   }
206   Pcheckinput();
207   if (vb2.buf[0] != ' ') Psyntax("not space before call");
208   if (memcmp(vb.buf,vb2.buf+1,vb.used) ||
209       vb2.buf[vb.used+1] != '\n') {
210     fprintf(stderr,
211             "adns test harness: program did unexpected:\n %.*s\n"
212             "was expecting:\n %.*s\n",
213             vb.used,vb.buf, vb.used,vb2.buf+1);
214     exit(1);
215   }
216   Tensurereportfile();
217   nl= memchr(vb.buf,'\n',vb.used);
218   fprintf(Treportfile," %.*s\n", (int)(nl ? nl - (const char*)vb.buf : vb.used), vb.buf);
219 }
220 int Hselect(    int max , fd_set *rfds , fd_set *wfds , fd_set *efds , struct timeval *to       ) {
221  int r, amtread;
222  char *ep;
223  Qselect(       max , rfds , wfds , efds , to   );
224  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
225  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
226  Tensurereportfile();
227  fprintf(Treportfile,"%s",vb2.buf);
228  amtread= strlen(vb2.buf);
229  if (amtread<=0 || vb2.buf[--amtread]!='\n')
230   Psyntax("badly formed line");
231  vb2.buf[amtread]= 0;
232  if (memcmp(vb2.buf," select=",8)) Psyntax("syscall reply mismatch");
233  if (vb2.buf[8] == 'E') {
234   int e;
235   e= Perrno(vb2.buf+8);
236   P_updatetime();
237   errno= e;
238   return -1;
239  }
240   r= strtoul(vb2.buf+8,&ep,10);
241   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
242   vb2.used= ep - (char*)vb2.buf;
243         Parg("rfds"); Pfdset(rfds,max); 
244         Parg("wfds"); Pfdset(wfds,max); 
245         Parg("efds"); Pfdset(efds,max); 
246  assert(vb2.used <= amtread);
247  if (vb2.used != amtread) Psyntax("junk at end of line");
248  P_updatetime();
249  return r;
250 }
251 #ifdef HAVE_POLL
252 int Hpoll(      struct pollfd *fds , int nfds , int timeout     ) {
253  int r, amtread;
254  char *ep;
255  Qpoll( fds , nfds , timeout    );
256  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
257  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
258  Tensurereportfile();
259  fprintf(Treportfile,"%s",vb2.buf);
260  amtread= strlen(vb2.buf);
261  if (amtread<=0 || vb2.buf[--amtread]!='\n')
262   Psyntax("badly formed line");
263  vb2.buf[amtread]= 0;
264  if (memcmp(vb2.buf," poll=",6)) Psyntax("syscall reply mismatch");
265  if (vb2.buf[6] == 'E') {
266   int e;
267   e= Perrno(vb2.buf+6);
268   P_updatetime();
269   errno= e;
270   return -1;
271  }
272   r= strtoul(vb2.buf+6,&ep,10);
273   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
274   vb2.used= ep - (char*)vb2.buf;
275         Parg("fds"); Ppollfds(fds,nfds); 
276  assert(vb2.used <= amtread);
277  if (vb2.used != amtread) Psyntax("junk at end of line");
278  P_updatetime();
279  return r;
280 }
281 #endif
282 int Hsocket(    int domain , int type , int protocol    ) {
283  int r, amtread;
284  char *ep;
285         Tmust("socket","domain",domain==AF_INET); 
286   Tmust("socket","type",type==SOCK_STREAM || type==SOCK_DGRAM); 
287  Qsocket(        type   );
288  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
289  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
290  Tensurereportfile();
291  fprintf(Treportfile,"%s",vb2.buf);
292  amtread= strlen(vb2.buf);
293  if (amtread<=0 || vb2.buf[--amtread]!='\n')
294   Psyntax("badly formed line");
295  vb2.buf[amtread]= 0;
296  if (memcmp(vb2.buf," socket=",8)) Psyntax("syscall reply mismatch");
297  if (vb2.buf[8] == 'E') {
298   int e;
299   e= Perrno(vb2.buf+8);
300   P_updatetime();
301   errno= e;
302   return -1;
303  }
304   r= strtoul(vb2.buf+8,&ep,10);
305   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
306   vb2.used= ep - (char*)vb2.buf;
307  assert(vb2.used <= amtread);
308  if (vb2.used != amtread) Psyntax("junk at end of line");
309  P_updatetime();
310  return r;
311 }
312 int Hfcntl(     int fd , int cmd , ...  ) {
313  int r, amtread;
314         va_list al; long arg; 
315   Tmust("fcntl","cmd",cmd==F_SETFL || cmd==F_GETFL);
316   if (cmd == F_SETFL) {
317     va_start(al,cmd); arg= va_arg(al,long); va_end(al);
318   } else {
319     arg= 0;
320   } 
321  Qfcntl(        fd , cmd , arg  );
322  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
323  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
324  Tensurereportfile();
325  fprintf(Treportfile,"%s",vb2.buf);
326  amtread= strlen(vb2.buf);
327  if (amtread<=0 || vb2.buf[--amtread]!='\n')
328   Psyntax("badly formed line");
329  vb2.buf[amtread]= 0;
330  if (memcmp(vb2.buf," fcntl=",7)) Psyntax("syscall reply mismatch");
331  if (vb2.buf[7] == 'E') {
332   int e;
333   e= Perrno(vb2.buf+7);
334   P_updatetime();
335   errno= e;
336   return -1;
337  }
338   r= 0;
339   if (cmd == F_GETFL) {
340     if (!memcmp(vb2.buf+7,"O_NONBLOCK|...",14)) {
341       r= O_NONBLOCK;
342       vb2.used= 7+14;
343     } else if (!memcmp(vb2.buf+7,"~O_NONBLOCK&...",15)) {
344       vb2.used= 7+15;
345     } else {
346       Psyntax("fcntl flags not O_NONBLOCK|... or ~O_NONBLOCK&...");
347     }
348   } else if (cmd == F_SETFL) {
349   if (memcmp(vb2.buf+7,"OK",2)) Psyntax("success/fail not E* or OK");
350   vb2.used= 7+2;
351   r= 0;
352   } else {
353     Psyntax("fcntl not F_GETFL or F_SETFL");
354   }
355  assert(vb2.used <= amtread);
356  if (vb2.used != amtread) Psyntax("junk at end of line");
357  P_updatetime();
358  return r;
359 }
360 int Hconnect(   int fd , const struct sockaddr *addr , int addrlen      ) {
361  int r, amtread;
362  Qconnect(      fd , addr , addrlen     );
363  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
364  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
365  Tensurereportfile();
366  fprintf(Treportfile,"%s",vb2.buf);
367  amtread= strlen(vb2.buf);
368  if (amtread<=0 || vb2.buf[--amtread]!='\n')
369   Psyntax("badly formed line");
370  vb2.buf[amtread]= 0;
371  if (memcmp(vb2.buf," connect=",9)) Psyntax("syscall reply mismatch");
372  if (vb2.buf[9] == 'E') {
373   int e;
374   e= Perrno(vb2.buf+9);
375   P_updatetime();
376   errno= e;
377   return -1;
378  }
379   if (memcmp(vb2.buf+9,"OK",2)) Psyntax("success/fail not E* or OK");
380   vb2.used= 9+2;
381   r= 0;
382  assert(vb2.used <= amtread);
383  if (vb2.used != amtread) Psyntax("junk at end of line");
384  P_updatetime();
385  return r;
386 }
387 int Hclose(     int fd  ) {
388  int r, amtread;
389  Qclose(        fd      );
390  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
391  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
392  Tensurereportfile();
393  fprintf(Treportfile,"%s",vb2.buf);
394  amtread= strlen(vb2.buf);
395  if (amtread<=0 || vb2.buf[--amtread]!='\n')
396   Psyntax("badly formed line");
397  vb2.buf[amtread]= 0;
398  if (memcmp(vb2.buf," close=",7)) Psyntax("syscall reply mismatch");
399  if (vb2.buf[7] == 'E') {
400   int e;
401   e= Perrno(vb2.buf+7);
402   P_updatetime();
403   errno= e;
404   return -1;
405  }
406   if (memcmp(vb2.buf+7,"OK",2)) Psyntax("success/fail not E* or OK");
407   vb2.used= 7+2;
408   r= 0;
409  assert(vb2.used <= amtread);
410  if (vb2.used != amtread) Psyntax("junk at end of line");
411  P_updatetime();
412  return r;
413 }
414 int Hsendto(    int fd , const void *msg , int msglen , unsigned int flags , const struct sockaddr *addr , int addrlen  ) {
415  int r, amtread;
416  char *ep;
417         Tmust("sendto","flags",flags==0); 
418  Qsendto(       fd , msg , msglen , addr , addrlen      );
419  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
420  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
421  Tensurereportfile();
422  fprintf(Treportfile,"%s",vb2.buf);
423  amtread= strlen(vb2.buf);
424  if (amtread<=0 || vb2.buf[--amtread]!='\n')
425   Psyntax("badly formed line");
426  vb2.buf[amtread]= 0;
427  if (memcmp(vb2.buf," sendto=",8)) Psyntax("syscall reply mismatch");
428  if (vb2.buf[8] == 'E') {
429   int e;
430   e= Perrno(vb2.buf+8);
431   P_updatetime();
432   errno= e;
433   return -1;
434  }
435   r= strtoul(vb2.buf+8,&ep,10);
436   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
437   vb2.used= ep - (char*)vb2.buf;
438  assert(vb2.used <= amtread);
439  if (vb2.used != amtread) Psyntax("junk at end of line");
440  P_updatetime();
441  return r;
442 }
443 int Hrecvfrom(  int fd , void *buf , int buflen , unsigned int flags , struct sockaddr *addr , int *addrlen     ) {
444  int r, amtread;
445         Tmust("recvfrom","flags",flags==0); 
446         Tmust("recvfrom","*addrlen",*addrlen>=sizeof(struct sockaddr_in)); 
447  Qrecvfrom(     fd , buflen , *addrlen  );
448  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
449  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
450  Tensurereportfile();
451  fprintf(Treportfile,"%s",vb2.buf);
452  amtread= strlen(vb2.buf);
453  if (amtread<=0 || vb2.buf[--amtread]!='\n')
454   Psyntax("badly formed line");
455  vb2.buf[amtread]= 0;
456  if (memcmp(vb2.buf," recvfrom=",10)) Psyntax("syscall reply mismatch");
457  if (vb2.buf[10] == 'E') {
458   int e;
459   e= Perrno(vb2.buf+10);
460   P_updatetime();
461   errno= e;
462   return -1;
463  }
464   if (memcmp(vb2.buf+10,"OK",2)) Psyntax("success/fail not E* or OK");
465   vb2.used= 10+2;
466   r= 0;
467         Parg("addr"); Paddr(addr,addrlen); 
468  assert(vb2.used <= amtread);
469  if (vb2.used != amtread) Psyntax("junk at end of line");
470         r= Pbytes(buf,buflen); 
471  P_updatetime();
472  return r;
473 }
474 int Hread(      int fd , void *buf , size_t buflen      ) {
475  int r, amtread;
476  Qread( fd , buflen     );
477  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
478  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
479  Tensurereportfile();
480  fprintf(Treportfile,"%s",vb2.buf);
481  amtread= strlen(vb2.buf);
482  if (amtread<=0 || vb2.buf[--amtread]!='\n')
483   Psyntax("badly formed line");
484  vb2.buf[amtread]= 0;
485  if (memcmp(vb2.buf," read=",6)) Psyntax("syscall reply mismatch");
486  if (vb2.buf[6] == 'E') {
487   int e;
488   e= Perrno(vb2.buf+6);
489   P_updatetime();
490   errno= e;
491   return -1;
492  }
493   if (memcmp(vb2.buf+6,"OK",2)) Psyntax("success/fail not E* or OK");
494   vb2.used= 6+2;
495   r= 0;
496  assert(vb2.used <= amtread);
497  if (vb2.used != amtread) Psyntax("junk at end of line");
498         r= Pbytes(buf,buflen); 
499  P_updatetime();
500  return r;
501 }
502 int Hwrite(     int fd , const void *buf , size_t len   ) {
503  int r, amtread;
504  char *ep;
505  Qwrite(        fd , buf , len  );
506  if (!adns__vbuf_ensure(&vb2,1000)) Tnomem();
507  fgets(vb2.buf,vb2.avail,Tinputfile); Pcheckinput();
508  Tensurereportfile();
509  fprintf(Treportfile,"%s",vb2.buf);
510  amtread= strlen(vb2.buf);
511  if (amtread<=0 || vb2.buf[--amtread]!='\n')
512   Psyntax("badly formed line");
513  vb2.buf[amtread]= 0;
514  if (memcmp(vb2.buf," write=",7)) Psyntax("syscall reply mismatch");
515  if (vb2.buf[7] == 'E') {
516   int e;
517   e= Perrno(vb2.buf+7);
518   P_updatetime();
519   errno= e;
520   return -1;
521  }
522   r= strtoul(vb2.buf+7,&ep,10);
523   if (*ep && *ep!=' ') Psyntax("return value not E* or positive number");
524   vb2.used= ep - (char*)vb2.buf;
525  assert(vb2.used <= amtread);
526  if (vb2.used != amtread) Psyntax("junk at end of line");
527  P_updatetime();
528  return r;
529 }