#include #include #include #include #include #include "test.h" #include "tests.h" typedef struct priv PRIV; struct priv { int l_nbio; int c_nbio; int ld1; int cd1; int ld2; int cd2; int lfd; int cfd; } ; static void set_nbio(int fd) { fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0)|O_NONBLOCK); } static int do_write(const char *who, int fd, const void *data, int peerfd, int delay) { int i; char c; printf("small-writes: %s writing `%s' [delay %d]\n",who,(const char *)data,delay); mustwrite(peerfd,"",1); mustread(peerfd,&c,1); sleep(1+delay); i = write(fd,data,4); if (i < 0) { // Don't check for EWOULDBLOCK; small write shouldn't block printf("small-writes: %s write to connection: %s\n",who,strerror(errno)); test_fail(); return(1); } if (i != 4) { printf("small-writes: %s write to connection returned %d, expected 4\n",who,i); test_fail(); return(1); } mustwrite(peerfd,"",1); mustread(peerfd,&c,1); return(0); } static int do_read(const char *who, int fd, const void *xdata, int nbio, int peerfd, int delay) { unsigned char rbuf[64]; int n; struct pollfd pfd; char c; printf("small-writes: %s reading from connection [delay %d]\n",who,delay); mustread(peerfd,&c,1); mustwrite(peerfd,"",1); sleep(1+delay); while (1) { bzero(&rbuf[0],sizeof(rbuf)); n = read(fd,&rbuf[0],nbio?sizeof(rbuf):4); if (n < 0) { if (nbio && (errno == EWOULDBLOCK)) { pfd.fd = fd; pfd.events = POLLIN | POLLRDNORM; n = poll(&pfd,1,INFTIM); if (n >= 0) continue; if (errno == EINTR) continue; printf("small-writes: %s poll connection: %s\n",who,strerror(errno)); test_fail(); return(1); } printf("small-writes: %s read from connection: %s\n",who,strerror(errno)); test_fail(); return(1); } if (n != 4) { printf("small-writes: %s read from connection returned %d, expected 4\n",who,n); test_fail(); return(1); } break; } if (bcmp(&rbuf[0],xdata,4)) { printf("small-writes: connecter read data wrong\n"); printf("got: %02x %02x %02x %02x\n",rbuf[0],rbuf[1],rbuf[2],rbuf[3]); printf("wanted: %02x %02x %02x %02x\n", ((const unsigned char *)xdata)[0], ((const unsigned char *)xdata)[1], ((const unsigned char *)xdata)[2], ((const unsigned char *)xdata)[3] ); test_fail(); return(1); } mustread(peerfd,&c,1); mustwrite(peerfd,"",1); return(0); } static void run_small_writes_run_l(void *pv) { PRIV *p; pid_t mypid; int fd; int fd2; int i; char c; p = pv; close(p->cfd); mypid = getpid(); printf("small-writes: listener is %d\n",(int)mypid); printf("small-writes: listener establishing connection\n"); mustwrite(p->lfd,&mypid,sizeof(pid_t)); sleep(1); SET_PIDCONN(fd,PIDCONN_LISTEN,0,0); mustwrite(p->lfd,"",1); SET_PIDCONN(fd2,PIDCONN_ACCEPT,fd,0); printf("small-writes: listener writing to listen descriptor\n"); sleep(1); i = write(fd,"abcd",4); if (i >= 0) { printf("small-writes: listener write to listen descriptor worked (%d)\n",i); test_fail(); return; } if (errno != EINVAL) { printf("small-writes: listener write to listen descriptor failed %d, expected %d\n",i,EINVAL); test_fail(); return; } printf("small-writes: listener write to listen descriptor failed correctly\n"); sleep(1); mustwrite(p->lfd,"",1); mustread(p->lfd,&c,1); if (p->l_nbio) set_nbio(fd2); mustwrite(p->lfd,"",1); mustread(p->lfd,&c,1); if (do_write("listener",fd2,"abcd",p->lfd,p->ld1)) return; mustwrite(p->lfd,"",1); mustread(p->lfd,&c,1); if (do_read("listener",fd2,"wxyz",p->l_nbio,p->lfd,p->ld2)) return; mustwrite(p->lfd,"",1); mustread(p->lfd,&c,1); printf("small-writes: listener done\n"); sleep(1); } static void run_small_writes_run_c(void *pv) { PRIV *p; pid_t lpid; int fd; char c; p = pv; close(p->lfd); printf("small-writes: connecter is %d\n",(int)getpid()); mustread(p->cfd,&lpid,sizeof(pid_t)); printf("small-writes: connecter establishing connection to %d\n",(int)lpid); sleep(1); mustread(p->cfd,&c,1); SET_PIDCONN(fd,PIDCONN_CONNECT,0,lpid); sleep(1); mustread(p->cfd,&c,1); mustwrite(p->cfd,"",1); if (p->c_nbio) set_nbio(fd); mustread(p->cfd,&c,1); mustwrite(p->cfd,"",1); if (do_read("connecter",fd,"abcd",p->c_nbio,p->cfd,p->cd1)) return; mustread(p->cfd,&c,1); mustwrite(p->cfd,"",1); if (do_write("connecter",fd,"wxyz",p->cfd,p->cd2)) return; mustread(p->cfd,&c,1); mustwrite(p->cfd,"",1); printf("small-writes: connecter done\n"); sleep(1); } static void do_small_writes(int lb, int cb, int lfirst1, int lfirst2) { PRIV p; KID *kl; KID *kc; printf("small-writes: >>>>>>>> %d %d %d %d\n",lb,cb,lfirst1,lfirst2); local_socketpair(&p.lfd,&p.cfd); p.l_nbio = lb; p.c_nbio = cb; p.ld1 = lfirst1 ? 0 : 1; p.cd1 = lfirst1 ? 1 : 0; p.ld2 = lfirst2 ? 0 : 1; p.cd2 = lfirst2 ? 1 : 0; kl = fork_kid(&run_small_writes_run_l,&p); kc = fork_kid(&run_small_writes_run_c,&p); close(p.lfd); close(p.cfd); reap_kid(kl); reap_kid(kc); } static void run_small_writes(void) { do_small_writes(0,0,0,0); if (! test_failed()) do_small_writes(0,0,0,1); if (! test_failed()) do_small_writes(0,0,1,0); if (! test_failed()) do_small_writes(0,0,1,1); if (! test_failed()) do_small_writes(0,1,0,0); if (! test_failed()) do_small_writes(0,1,0,1); if (! test_failed()) do_small_writes(0,1,1,0); if (! test_failed()) do_small_writes(0,1,1,1); if (! test_failed()) do_small_writes(1,0,0,0); if (! test_failed()) do_small_writes(1,0,0,1); if (! test_failed()) do_small_writes(1,0,1,0); if (! test_failed()) do_small_writes(1,0,1,1); if (! test_failed()) do_small_writes(1,1,0,0); if (! test_failed()) do_small_writes(1,1,0,1); if (! test_failed()) do_small_writes(1,1,1,0); if (! test_failed()) do_small_writes(1,1,1,1); printf("small-writes: done\n"); } const TEST test_small_writes = { &run_small_writes };