#define _XOPEN_SOURCE 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LISTEN_BACKLOG 10 #define FPAS_FORM "for port %s and service %s\n" #define FPAS_P cfg->items[i].port #define FPAS_S cfg->items[i].cmd struct config_it{ char * port; char wait; char * cmd; char ** args; }; struct config{ int len; struct config_it * items; }; int sigpipe[2]; void usage(void){ printf("Usage: ./inetd \n"); } struct config * parse_config(char * filename){ FILE * f; f = fopen(filename,"r"); if (f==NULL){ printf("Could not open config file %s\n",filename); exit(1); } int ch; int lines = 0; ch = fgetc(f); while (ch != EOF){ if (ch == '\n') lines++; ch = fgetc(f); } rewind(f); struct config_it * cfg_its; cfg_its = calloc(lines,sizeof(struct config_it)); for (int i=0;ilen = lines; cfg->items = cfg_its; return cfg; } void dump_config(struct config * cfg){ printf("port\twait\tcmd\n"); for (int i=0;ilen;i++){ printf("%s\t%d\t%s\n",cfg->items[i].port,cfg->items[i].wait,cfg->items[i].cmd); } } void handle_sigchld(int sig){ write(sigpipe[1],"!",1); } void handle_error(int mem_errno,int n_srv, int * l_socks, char * msg){ for (int j=0;j<=n_srv;j++){ close(l_socks[j]); } errno = mem_errno; err(1,msg); } void run(struct config * cfg){ printf("Running inetd...\n"); int n_srv; n_srv = cfg->len; int * l_socks; struct addrinfo * addrinfo; struct addrinfo hints; l_socks = malloc(n_srv*sizeof(int)); memset(&hints,0,sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; for (int i=0;iitems[i].port,&hints,&addrinfo)) != 0){ fprintf(stderr,"Error: \"%s\""FPAS_FORM,gai_strerror(gai_res),FPAS_P,FPAS_S); exit(1); } struct addrinfo * orig_ainfo; for (orig_ainfo = addrinfo; addrinfo!=NULL; addrinfo = addrinfo->ai_next){ errno = 0; l_socks[i]=socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); if (l_socks[i]==-1){ warn("Error in socket()"FPAS_FORM,FPAS_P,FPAS_S); continue; } errno = 0; if (bind(l_socks[i],addrinfo->ai_addr,addrinfo->ai_addrlen)!=0){ warn("Error in bind()"FPAS_FORM,FPAS_P,FPAS_S); continue; } break; } if (addrinfo==NULL){ for (int j=0;j<=i;j++){ close(l_socks[j]); } err(1,"Exitting because of errors above"); } freeaddrinfo(orig_ainfo); int opt = 1; errno = 0; setsockopt(l_socks[i], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (errno){ handle_error(errno,n_srv,l_socks,"Error while setting REUSEADDR"); } errno = 0; if (listen(l_socks[i],LISTEN_BACKLOG)!=0){ int mem_errno = errno; for (int j=0;j<=i;j++){ close(l_socks[j]); } errno = mem_errno; err(1,"Error in listen()"FPAS_FORM,FPAS_P,FPAS_S); } } errno = 0; pipe(sigpipe); fcntl(sigpipe[1],F_SETFL, fcntl(sigpipe[1], F_GETFL) | O_NONBLOCK); if (errno) handle_error(errno,n_srv,l_socks,"Error while setting signal pipe"); struct sigaction sa; memset(&sa, 0, sizeof (sa)); sa.sa_handler = handle_sigchld; // sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { handle_error(errno,n_srv,l_socks,"Error while setting signal"); } struct pollfd * pollfds; pid_t * children; pollfds = malloc((n_srv+1)*sizeof(struct pollfd)); children = malloc(n_srv*sizeof(pid_t)); for (int i=0;i 0){ printf("Got %d connections, serving them\n",pol_res); }else if (errno & EINTR){ printf("Interrupted in poll\n"); continue; }else { handle_error(errno,n_srv,l_socks,"Poll failed"); } for (int i=0;iitems[i].wait,FPAS_S); if (cfg->items[i].wait){ if (children[i]!=-1){ // Child may be running printf("Child is running and we are polling!!!\n"); } printf("FORK!\n"); pid_t pid; if ((pid = fork())!=0){ // We are parent // printf("Parent\n"); children[i]=pid; pollfds[i].fd = -pollfds[i].fd; continue; } // We are child for (int j=0;jitems[i].cmd,cfg->items[i].cmd,(char *)NULL); err(1,"Error while running %s",cfg->items[i].cmd); }else { // nowait int rw_sock; rw_sock = accept(l_socks[i],NULL,NULL); if (rw_sock == -1){ err(1,"Error when accepting connection"); } printf("FORK!\n"); if(fork()!=0){ // We are parent close(rw_sock); printf("Parent\n"); continue; } printf("Child\n"); // We are child for (int j=0;jitems[i].cmd,cfg->items[i].cmd,(char *)NULL); err(1,"Error while running %s",cfg->items[i].cmd); } } if (pollfds[n_srv].revents & POLLIN){ char ch; read(sigpipe[0],&ch,1); pid_t dead; dead = waitpid(-1,NULL,WNOHANG); if (dead < 0){ handle_error(errno,n_srv,l_socks,"Waitpid failed"); } if (dead == 0){ printf("All alive!\n"); } printf("Child %d died%c\n",dead,ch); for (int i=0;i