void main(int argc, char **argv) { static char data[1024], dir[1024], ndir[1024]; int ctl, nctl, fd; verbose = 1; if(!verbose){ close(1); fd = open("/dev/null", O_WRONLY); if(fd != 1){ dup2(fd, 1); close(fd); } } argc--, argv++; printf("listen started\n"); ctl = announce9(argv[0], dir, 0); if(ctl < 0){ fprintf(stderr, "announce %s: %r", argv[0]); exit(1); } for(;;){ nctl = listen9(dir, ndir, 0); if(nctl < 0){ fprintf(stderr, "listen %s: %r", argv[0]); exit(1); } //switch(rfork(RFFDG|RFPROC|RFNOWAIT|RFENVG|RFNAMEG|RFNOTEG)){ switch(fork()){ case -1: reject9(nctl, ndir, "host overloaded"); close(nctl); continue; case 0: fd = accept9(nctl, ndir); if(fd < 0){ fprintf(stderr, "accept %s: can't open %s/data: %r\n", argv[0], ndir); exit(1); } printf("incoming call for %s from %s in %s\n", argv[0], remoteaddr(ndir), ndir); //fprintf(nctl, "keepalive"); close(ctl); close(nctl); //putenv("net", ndir); /* this is for children that open /dev/cons. Too bad. snprintf(data, sizeof data, "%s/data", ndir); bind(data, "/dev/cons", MREPL); */ dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); execv(argv[1], argv+1); // if(argv[1][0] != '/') // exec(smprintf("%s", argv[1]), argv+1); fprintf(stderr, "exec: %r\n"); exit(1); default: /* reap any available children */ while (waitpid(-1, 0, WNOHANG) > 0) ; close(nctl); break; } } }
int main() { int ret; int afd, dfd, lcfd, listen_fd; char adir[40], ldir[40]; int n; char buf[256]; /* We'll use this to see if we actually did epoll_waits instead of blocking * calls. It's not 100%, but with a human on the other end, it should be * fine. */ bool has_epolled = FALSE; #ifdef PLAN9NET printf("Using Plan 9's networking stack\n"); /* This clones a conversation (opens /net/tcp/clone), then reads the cloned * fd (which is the ctl) to givure out the conv number (the line), then * writes "announce [addr]" into ctl. This "announce" command often has a * "bind" in it too. plan9 bind just sets the local addr/port. TCP * announce also does this. Returns the ctlfd. */ afd = announce9("tcp!*!23", adir, 0); if (afd < 0) { perror("Announce failure"); return -1; } printf("Announced on line %s\n", adir); #else printf("Using the BSD socket shims over Plan 9's networking stack\n"); int srv_socket, con_socket; struct sockaddr_in dest, srv = {0}; srv.sin_family = AF_INET; srv.sin_addr.s_addr = htonl(INADDR_ANY); srv.sin_port = htons(23); socklen_t socksize = sizeof(struct sockaddr_in); /* Equiv to cloning a converstation in plan 9. The shim returns the data FD * for the conversation. */ srv_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (srv_socket < 0) { perror("Socket failure"); return -1; } /* bind + listen is equiv to announce() in plan 9. Note that the "bind" * command is used, unlike in the plan9 announce. */ /* Binds our socket to the given addr/port in srv. */ ret = bind(srv_socket, (struct sockaddr*)&srv, sizeof(struct sockaddr_in)); if (ret < 0) { perror("Bind failure"); return -1; } /* marks the socket as a listener/server */ ret = listen(srv_socket, 1); if (ret < 0) { perror("Listen failure"); return -1; } printf("Listened on port %d\n", ntohs(srv.sin_port)); #endif /* at this point, the server has done all the prep necessary to be able to * sleep/block/wait on an incoming connection. */ #define EP_SET_SZ 10 /* this is actually the ID of the largest FD */ int epfd = epoll_create(EP_SET_SZ); struct epoll_event ep_ev; struct epoll_event results[EP_SET_SZ]; if (epfd < 0) { perror("epoll_create"); exit(-1); } ep_ev.events = EPOLLIN | EPOLLET; #ifdef PLAN9NET snprintf(buf, sizeof(buf), "%s/listen", adir); listen_fd = open(buf, O_PATH); if (listen_fd < 0){ perror("listen fd"); return -1; } /* This is a little subtle. We're putting a tap on the listen file / * listen_fd. When this fires, we get an event because of that listen_fd. * But we don't actually listen or do anything to that listen_fd. It's * solely for monitoring. We open a path, below, and we'll reattempt to do * *that* operation when someone tells us that our listen tap fires. */ ep_ev.data.fd = listen_fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &ep_ev)) { perror("epoll_ctl_add listen"); exit(-1); } has_epolled = FALSE; while (1) { /* Opens the conversation's listen file. This blocks til someone * connects. When they do, a new conversation is created, and that open * returned an FD for the new conv's ctl. listen() reads that to find * out the conv number (the line) for this new conv. listen() returns * the ctl for this new conv. * * Non-block is for the act of listening, and applies to lcfd. */ lcfd = listen9(adir, ldir, O_NONBLOCK); if (lcfd >= 0) break; if (errno != EAGAIN) { perror("Listen failure"); return -1; } if (epoll_wait(epfd, results, EP_SET_SZ, -1) != 1) { perror("epoll_wait"); exit(-1); } has_epolled = TRUE; assert(results[0].data.fd == listen_fd); assert(results[0].events == EPOLLIN); } printf("Listened and got line %s\n", ldir); assert(has_epolled); /* No longer need listen_fd. You should CTL_DEL before closing. */ if (epoll_ctl(epfd, EPOLL_CTL_DEL, listen_fd, &ep_ev)) { perror("epoll_ctl_del"); exit(-1); } close(listen_fd); /* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file and * returns that fd. Writing "accept" is a noop for most of our protocols. * */ dfd = accept9(lcfd, ldir); if (dfd < 0) { perror("Accept failure"); return -1; } #else ep_ev.data.fd = srv_socket; if (epoll_ctl(epfd, EPOLL_CTL_ADD, srv_socket, &ep_ev)) { perror("epoll_ctl_add srv_socket"); exit(-1); } has_epolled = FALSE; while (1) { /* returns an FD for a new socket. */ dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize); if (dfd >= 0) break; if (errno != EAGAIN) { perror("Accept failure"); return -1; } if (epoll_wait(epfd, results, EP_SET_SZ, -1) != 1) { perror("epoll_wait"); exit(-1); } has_epolled = TRUE; assert(results[0].data.fd == srv_socket); assert(results[0].events == EPOLLIN); } printf("Accepted and got dfd %d\n", dfd); assert(has_epolled); if (epoll_ctl(epfd, EPOLL_CTL_DEL, srv_socket, &ep_ev)) { perror("epoll_ctl_del"); while (1); exit(-1); } #endif /* In lieu of accept4, we set the new socket's nonblock status manually. * Both OSs do this. */ ret = fcntl(dfd, F_SETFL, O_NONBLOCK); if (ret < 0) { perror("setfl dfd"); exit(-1); } ep_ev.data.fd = dfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, dfd, &ep_ev)) { perror("epoll_ctl_add dvd"); exit(-1); } /* echo until EOF */ has_epolled = FALSE; printf("Server read: "); while (1) { while ((n = read(dfd, buf, sizeof(buf))) > 0) { for (int i = 0; i < n; i++) printf("%c", buf[i]); fflush(stdout); /* Should epoll on this direction too. */ if (write(dfd, buf, n) < 0) { perror("writing"); exit(-1); } } if (n == 0) break; if (epoll_wait(epfd, results, EP_SET_SZ, -1) != 1) { perror("epoll_wait 2"); exit(-1); } has_epolled = TRUE; assert(results[0].data.fd == dfd); /* you might get a HUP, but keep on reading! */ } assert(has_epolled); if (epoll_ctl(epfd, EPOLL_CTL_DEL, dfd, &ep_ev)) { perror("epoll_ctl_del dfd"); exit(-1); } #ifdef PLAN9NET close(dfd); /* data fd for the new conv, from listen */ close(lcfd); /* ctl fd for the new conv, from listen */ close(afd); /* ctl fd for the listening conv */ #else close(dfd); /* new connection socket, from accept */ close(srv_socket); #endif }
int main(void) { int ret; int afd, dfd, lcfd, listen_fd; char adir[40], ldir[40]; int n; char buf[256]; /* We'll use this to see if we actually did a select instead of blocking * calls. It's not 100%, but with a human on the other end, it should be * fine. */ bool has_selected = FALSE; #ifdef PLAN9NET printf("Using Plan 9's networking stack\n"); /* This clones a conversation (opens /net/tcp/clone), then reads the cloned * fd (which is the ctl) to givure out the conv number (the line), then * writes "announce [addr]" into ctl. This "announce" command often has a * "bind" in it too. plan9 bind just sets the local addr/port. TCP * announce also does this. Returns the ctlfd. */ afd = announce9("tcp!*!23", adir, O_NONBLOCK); if (afd < 0) { perror("Announce failure"); return -1; } printf("Announced on line %s\n", adir); #else printf("Using the BSD socket shims over Plan 9's networking stack\n"); int srv_socket; struct sockaddr_in dest, srv = {0}; srv.sin_family = AF_INET; srv.sin_addr.s_addr = htonl(INADDR_ANY); srv.sin_port = htons(23); socklen_t socksize = sizeof(struct sockaddr_in); /* Equiv to cloning a converstation in plan 9. The shim returns the data FD * for the conversation. */ srv_socket = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (srv_socket < 0) { perror("Socket failure"); return -1; } /* bind + listen is equiv to announce() in plan 9. Note that the "bind" * command is used, unlike in the plan9 announce. */ /* Binds our socket to the given addr/port in srv. */ ret = bind(srv_socket, (struct sockaddr*)&srv, sizeof(struct sockaddr_in)); if (ret < 0) { perror("Bind failure"); return -1; } /* marks the socket as a listener/server */ ret = listen(srv_socket, 1); if (ret < 0) { perror("Listen failure"); return -1; } printf("Listened on port %d\n", ntohs(srv.sin_port)); #endif /* at this point, the server has done all the prep necessary to be able to * sleep/block/wait on an incoming connection. */ fd_set rfds; #ifdef PLAN9NET snprintf(buf, sizeof(buf), "%s/listen", adir); listen_fd = open(buf, O_PATH); if (listen_fd < 0) { perror("listen fd"); return -1; } FD_ZERO(&rfds); FD_SET(listen_fd, &rfds); has_selected = FALSE; while (1) { /* Opens the conversation's listen file. This blocks til someone * connects. When they do, a new conversation is created, and that open * returned an FD for the new conv's ctl. listen() reads that to find * out the conv number (the line) for this new conv. listen() returns * the ctl for this new conv. * * Non-block is for the new connection. Not the act of listening. */ lcfd = listen9(adir, ldir, O_NONBLOCK); if (lcfd >= 0) break; if (errno != EAGAIN) { perror("Listen failure"); return -1; } if (select(listen_fd + 1, &rfds, 0, 0, 0) < 0) { perror("select"); return -1; } has_selected = TRUE; assert(FD_ISSET(listen_fd, &rfds)); } printf("Listened and got line %s\n", ldir); assert(has_selected); /* No longer need listen_fd. */ close(listen_fd); /* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file and * returns that fd. Writing "accept" is a noop for most of our protocols. * */ dfd = accept9(lcfd, ldir); if (dfd < 0) { perror("Accept failure"); return -1; } #else FD_ZERO(&rfds); FD_SET(srv_socket, &rfds); has_selected = FALSE; while (1) { /* returns an FD for a new socket. */ dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize); if (dfd >= 0) break; if (errno != EAGAIN) { perror("Accept failure"); return -1; } if (select(srv_socket + 1, &rfds, 0, 0, 0) < 0) { perror("select"); return -1; } has_selected = TRUE; assert(FD_ISSET(srv_socket, &rfds)); } printf("Accepted and got dfd %d\n", dfd); assert(has_selected); /* In lieu of accept4, we set the new socket's nonblock status manually */ ret = fcntl(dfd, F_SETFL, O_NONBLOCK); if (ret < 0) { perror("setfl dfd"); exit(-1); } #endif FD_SET(dfd, &rfds); /* echo until EOF */ has_selected = FALSE; printf("Server read: "); while (1) { while ((n = read(dfd, buf, sizeof(buf))) > 0) { for (int i = 0; i < n; i++) printf("%c", buf[i]); fflush(stdout); /* Should select on this direction too. */ if (write(dfd, buf, n) < 0) { perror("writing"); exit(-1); } } if (n == 0) break; if (select(dfd + 1, &rfds, 0, 0, 0) < 0) { perror("select 2"); exit(-1); } has_selected = TRUE; assert(FD_ISSET(dfd, &rfds)); /* you might get a HUP, but keep on reading! */ } assert(has_selected); #ifdef PLAN9NET close(dfd); /* data fd for the new conv, from listen */ close(lcfd); /* ctl fd for the new conv, from listen */ close(afd); /* ctl fd for the listening conv */ #else close(dfd); /* new connection socket, from accept */ close(srv_socket); #endif }
int main() { int ret; int afd, dfd, lcfd; char adir[40], ldir[40]; int n; char buf[256]; char debugbuf[256]; #ifdef PLAN9NET /* This clones a conversation (opens /net/tcp/clone), then reads the cloned * fd (which is the ctl) to givure out the conv number (the line), then * writes "announce [addr]" into ctl. This "announce" command often has a * "bind" in it too. plan9 bind just sets the local addr/port. TCP * announce also does this. Returns the ctlfd. */ afd = announce9("tcp!*!23", adir, 0); if (afd < 0) { perror("Announce failure"); return -1; } printf("Announced on line %s\n", adir); #else int srv_socket, con_socket; struct sockaddr_in dest, srv = {0}; srv.sin_family = AF_INET; srv.sin_addr.s_addr = htonl(INADDR_ANY); srv.sin_port = htons(23); socklen_t socksize = sizeof(struct sockaddr_in); /* Equiv to cloning a converstation in plan 9. The shim returns the data FD * for the conversation. */ srv_socket = socket(AF_INET, SOCK_STREAM, 0); if (srv_socket < 0) { perror("Socket failure"); return -1; } /* bind + listen is equiv to announce() in plan 9. Note that the "bind" * command is used, unlike in the plan9 announce. */ /* Binds our socket to the given addr/port in srv. */ ret = bind(srv_socket, (struct sockaddr*)&srv, sizeof(struct sockaddr_in)); if (ret < 0) { perror("Bind failure"); return -1; } /* marks the socket as a listener/server */ ret = listen(srv_socket, 1); if (ret < 0) { perror("Listen failure"); return -1; } #endif /* at this point, the server has done all the prep necessary to be able to * sleep/block/wait on an incoming connection. */ #ifdef PLAN9NET /* Opens the conversation's listen file. This blocks til someone connects. * When they do, a new conversation is created, and that open returned an FD * for the new conv's ctl. listen() reads that to find out the conv number * (the line) for this new conv. listen() returns the ctl for this new * conv. */ lcfd = listen9(adir, ldir, 0); if (lcfd < 0) { perror("Listen failure"); return -1; } printf("Listened and got line %s\n", ldir); /* Writes "accept [NUM]" into the ctlfd, then opens the conv's data file and * returns that fd. Writing "accept" is a noop for most of our protocols. * */ dfd = accept9(lcfd, ldir); if (dfd < 0) { perror("Accept failure"); return -1; } #else /* returns an FD for a new socket. */ dfd = accept(srv_socket, (struct sockaddr*)&dest, &socksize); if (dfd < 0) { perror("Accept failure"); return -1; } #endif /* echo until EOF */ while ((n = read(dfd, buf, sizeof(buf))) > 0) { snprintf(debugbuf, n, "%s", buf); printf("Server read: %s", debugbuf); write(dfd, buf, n); } #ifdef PLAN9NET close(dfd); /* data fd for the new conv, from listen */ close(lcfd); /* ctl fd for the new conv, from listen */ close(afd); /* ctl fd for the listening conv */ #else close(dfd); /* new connection socket, from accept */ close(srv_socket); #endif }