#include #include #include #include #include #include #include #include #include extern const char *__progname; static pid_t kid_busy_a; static pid_t kid_busy_b; static pid_t kid_test_a; static pid_t kid_test_b; static int timing_fd; static void busy_a(int fd) { struct cmsghdr *cmh; struct msghdr mh; struct iovec iov; char *buf; char data; unsigned char reply[64]; int n; int pending; int waiting; int reps; buf = malloc(CMSG_SPACE(sizeof(int))); waiting = 0; pending = 0; reps = 0; while (1) { if (! waiting) { cmh = (void *)buf; cmh->cmsg_len = CMSG_LEN(sizeof(int)); cmh->cmsg_level = SOL_SOCKET; cmh->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmh) = 1; data = 'x'; iov.iov_base = &data; iov.iov_len = 1; mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = buf; mh.msg_controllen = CMSG_SPACE(sizeof(int)); mh.msg_flags = 0; if (sendmsg(fd,&mh,0) < 0) { if (errno == ENOBUFS) { waiting = 1; continue; } fprintf(stderr,"%s: busy a sendmsg: %s\n",__progname,strerror(errno)); exit(1); } #ifdef SLOWDOWN { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000000; nanosleep(&ts,0); } #endif pending ++; reps ++; if (reps >= ((1U<<20)-1)) { write(1,".",1); reps = 0; } continue; } n = recv(fd,&reply[0],sizeof(reply),0); if (n < 0) { fprintf(stderr,"%s: busy a recv: %s\n",__progname,strerror(errno)); exit(1); } pending -= n; waiting = 0; } } static void busy_b(int fd) { int p; struct cmsghdr *cmh; struct msghdr mh; struct iovec iov; char *buf; unsigned char body[64]; int n; buf = malloc(CMSG_SPACE(sizeof(int))); while (1) { iov.iov_base = &body[0]; iov.iov_len = sizeof(body); mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = buf; mh.msg_controllen = CMSG_SPACE(sizeof(int)); mh.msg_flags = 0; n = recvmsg(fd,&mh,0); if (n < 0) { fprintf(stderr,"%s: busy b recvmsg: %s\n",__progname,strerror(errno)); exit(1); } if (n != 1) { fprintf(stderr,"%s: busy b recvmsg got %d not %d\n",__progname,n,1); exit(1); } if (body[0] != 'x') { fprintf(stderr,"%s: busy b recvmsg body %02x not %02x\n",__progname,body[0],'x'); exit(1); } if (mh.msg_controllen < CMSG_LEN(sizeof(int))) { fprintf(stderr,"%s: busy b control len %d < %d\n",__progname,(int)mh.msg_controllen,(int)CMSG_LEN(sizeof(int))); exit(1); } cmh = (void *)buf; if (cmh->cmsg_level != SOL_SOCKET) { fprintf(stderr,"%s: busy b cmsg level %d not %d\n",__progname,(int)cmh->cmsg_level,(int)SOL_SOCKET); exit(1); } if (cmh->cmsg_type != SCM_RIGHTS) { fprintf(stderr,"%s: busy b cmsg type %d not %d\n",__progname,(int)cmh->cmsg_type,(int)SCM_RIGHTS); exit(1); } bcopy(CMSG_DATA(cmh),&p,sizeof(int)); if (close(p) < 0) { fprintf(stderr,"%s: busy b cmsg type %d not %d\n",__progname,(int)cmh->cmsg_type,(int)SCM_RIGHTS); exit(1); } do n = write(fd,"\1",1); while ((n < 0) && (errno == ENOBUFS)); if (n < 0) { fprintf(stderr,"%s: busy b ack write: %s\n",__progname,strerror(errno)); exit(1); } if (n != 1) { fprintf(stderr,"%s: busy b ack write got %d not %d\n",__progname,n,1); exit(1); } } } static void handle_alrm(int sig) { (void)sig; write(timing_fd,"",1); } static int testwrite(const char *proc, int x, int fd, const char *data, int len) { int n; n = write(fd,data,len); if (n < 0) { fprintf(stderr,"%s: test write %s [%d]: %s\n",__progname,proc,x,strerror(errno)); return(1); } if (n != len) { fprintf(stderr,"%s: test write %s [%d] got %d not %d\n",__progname,proc,x,n,len); return(1); } return(0); } static int testget(const char *proc, int x, int fd, const char *data, int len) { int n; unsigned char reply[257]; int i; n = recv(fd,&reply[0],sizeof(reply),MSG_WAITALL); if (n < 0) { fprintf(stderr,"%s: test recv %s [%d]: %s\n",__progname,proc,x,strerror(errno)); return(1); } if (n != len) { fprintf(stderr,"%s: test recv %s [%d] got %d not %d\n",__progname,proc,x,n,len); return(1); } if (bcmp(&reply[0],data,len)) { fprintf(stderr,"%s: test data wrong:",__progname); for (i=0;i=0;n--) { if (socketpair(AF_LOCAL,SOCK_STREAM,0,&p[n][0]) < 0) { fprintf(stderr,"%s: AF_LOCAL SOCK_STREAM socketpair: %s\n",__progname,strerror(errno)); exit(1); } } do { cmh = (void *)buf; cmh->cmsg_len = CMSG_LEN(3*sizeof(int)); cmh->cmsg_level = SOL_SOCKET; cmh->cmsg_type = SCM_RIGHTS; ((int *)CMSG_DATA(cmh))[0] = p[0][0]; ((int *)CMSG_DATA(cmh))[1] = p[1][0]; ((int *)CMSG_DATA(cmh))[2] = p[2][0]; data = 'x'; iov.iov_base = &data; iov.iov_len = 1; mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = buf; mh.msg_controllen = CMSG_SPACE(3*sizeof(int)); mh.msg_flags = 0; if (sendmsg(fd,&mh,0) < 0) { fprintf(stderr,"%s: test 3 sendmsg: %s\n",__progname,strerror(errno)); break; } close(p[0][0]); p[0][0] = -1; close(p[1][0]); p[1][0] = -1; close(p[2][0]); p[2][0] = -1; if ( testwrite("a",0,p[0][1],"hello on 1",10) || testwrite("a",1,p[1][1],"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",52) ) break; for (n=0;n<256;n++) { data = n; if (testwrite("a",2,p[2][1],&data,1)) break; // XXX oh for LCS.... } if (n < 256) break; shutdown(p[0][1],SHUT_WR); shutdown(p[1][1],SHUT_WR); shutdown(p[2][1],SHUT_WR); if ( testget("a",0,p[0][1],"zero",4) || testget("a",1,p[1][1],"one",3) || testget("a",2,p[2][1],"two",3) ) break; close(p[0][1]); p[0][1] = -1; close(p[1][1]); p[1][1] = -1; close(p[2][1]); p[2][1] = -1; } while (0); if (p[0][0] >= 0) close(p[0][0]); if (p[0][1] >= 0) close(p[0][1]); if (p[1][0] >= 0) close(p[1][0]); if (p[1][1] >= 0) close(p[1][1]); if (p[2][0] >= 0) close(p[2][0]); if (p[2][1] >= 0) close(p[2][1]); write(1,"*",1); } } static void test_b(int fd) { int p[3]; struct cmsghdr *cmh; struct msghdr mh; struct iovec iov; char *buf; unsigned char body[256]; int n; buf = malloc(CMSG_SPACE(3*sizeof(int))); while (1) { iov.iov_base = &body[0]; iov.iov_len = sizeof(body); mh.msg_name = 0; mh.msg_namelen = 0; mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = buf; mh.msg_controllen = CMSG_SPACE(3*sizeof(int)); mh.msg_flags = 0; n = recvmsg(fd,&mh,0); if (n < 0) { fprintf(stderr,"%s: test 3 recvmsg: %s\n",__progname,strerror(errno)); exit(1); } if (n != 1) { fprintf(stderr,"%s: test 3 recvmsg got %d not %d\n",__progname,n,1); exit(1); } if (body[0] != 'x') { fprintf(stderr,"%s: test 3 recvmsg body %02x not %02x\n",__progname,body[0],'x'); exit(1); } if (mh.msg_controllen < CMSG_LEN(3*sizeof(int))) { fprintf(stderr,"%s: test 3 control len %d < %d\n",__progname,(int)mh.msg_controllen,(int)CMSG_LEN(3*sizeof(int))); exit(1); } cmh = (void *)buf; if (cmh->cmsg_level != SOL_SOCKET) { fprintf(stderr,"%s: test 3 cmsg level %d not %d\n",__progname,(int)cmh->cmsg_level,(int)SOL_SOCKET); exit(1); } if (cmh->cmsg_type != SCM_RIGHTS) { fprintf(stderr,"%s: test 3 cmsg type %d not %d\n",__progname,(int)cmh->cmsg_type,(int)SCM_RIGHTS); exit(1); } bcopy(CMSG_DATA(cmh),&p[0],3*sizeof(int)); if ( testget("b",0,p[0],"hello on 1",10) || testget("b",1,p[1],"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",52) || testget("b",2,p[2],"\0\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37" " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~\177" "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",256) ) exit(1); if ( testwrite("b",0,p[0],"zero",4) || testwrite("b",1,p[1],"one",3) || testwrite("b",2,p[2],"two",3) ) exit(1); close(p[0]); close(p[1]); close(p[2]); } } static void fork_pair(void (*a)(int), void (*b)(int), pid_t *kap, pid_t *kbp) { int p[2]; pid_t k; if (socketpair(AF_LOCAL,SOCK_DGRAM,0,&p[0]) < 0) { fprintf(stderr,"%s: busy parent socketpair: %s\n",__progname,strerror(errno)); exit(1); } k = fork(); if (k < 0) { fprintf(stderr,"%s: busy parent fork: %s\n",__progname,strerror(errno)); exit(1); } if (k == 0) { close(p[0]); (*a)(p[1]); _exit(0); } *kap = k; k = fork(); if (k < 0) { fprintf(stderr,"%s: busy parent fork: %s\n",__progname,strerror(errno)); exit(1); } if (k == 0) { close(p[1]); (*b)(p[0]); _exit(0); } *kbp = k; close(p[0]); close(p[1]); } static void fork_kids(void) { fork_pair(&busy_a,&busy_b,&kid_busy_a,&kid_busy_b); fork_pair(&test_a,&test_b,&kid_test_a,&kid_test_b); } static void await(void) { pid_t k; while (1) { k = wait4(-1,0,0,0); if (k < 0) { if (errno == EINTR) continue; fprintf(stderr,"%s: parent wait: %s\n",__progname,strerror(errno)); break; } break; } if (k != kid_busy_a) kill(kid_busy_a,SIGKILL); if (k != kid_busy_b) kill(kid_busy_b,SIGKILL); if (k != kid_test_a) kill(kid_test_a,SIGKILL); if (k != kid_test_b) kill(kid_test_b,SIGKILL); } static void ignore_pipe(void) { signal(SIGPIPE,SIG_IGN); } int main(void); int main(void) { ignore_pipe(); fork_kids(); await(); return(0); }