/********************************************************************** SERVER su socket di tipo STREAM per compito del 4/9/02 (come cliente utilizzare telnet) **********************************************************************/ #include #include #include #include #include #include #include #include #include #define DEFAULTPORT 10101 #define DEFAULTTIMEOUT 3660 #define FAILAUTHMESG "You are outside my network and cannot be authorized to this service\n" #define FAILAUTHLEN strlen(FAILAUTHMESG) sigset_t sigmask, oldmask,zeromask; int nreq; int pid1,pid2; int sock; void sigusr1_handler() { printf("%d requests received so far\n",nreq); } void sigint_handler() { printf("Whoops, got SIGINT: process exits\n"); shutdown(sock,2); exit(0); } pipingchild(int msgsock) { int i,ns,piped[2]; char *com1[32]; char *com2[32]; char command1[1024]; char command2[1024]; char *p; sigset_t sigmask; sigemptyset( &sigmask); sigaddset(&sigmask, SIGINT); sigprocmask(SIG_BLOCK, &sigmask, &oldmask); if (pipe(piped) < 0) return 2; read(msgsock,command1,1024); read(msgsock,command2,1024); // Per semplicita' non viene gestita l'estrazione degli argomenti p=command1; while(*p != '\r') p++; *p=0; p=command2; while(*p != '\r') p++; *p=0; com1[0]=command1; com1[1]=NULL; com2[0]=command2; com2[1]=NULL; if((pid2=fork())==0) { /* Lo stdin corrente non interessa a com2 (lettore): chiude il descrittore 0 */ close(0); /* Si richiede un nuovo descrittore per la lettura dalla pipe: il primo descrittore libero e' lo 0 (stdin) che viene associato alla lettura dalla pipe */ dup(piped[0]); /* Gli altri descrittori delle pipe non servono piu': il lettore usa stdin per leggere dalla pipe */ close(piped[0]); close(piped[1]); /* Esecuzione del comando 2 (che ha la pipe come stdin) */ // printf("Executing %s (%s)\n",com2[0],command2); execvp(com2[0], com2); perror("exec com2"); return 4; } else if((pid1=fork())==0) { /* Lo stdout corrente non interessa a com1 (scrittore): chiude il descrittore 1 */ close(1); /* Si richiede un nuovo descrittore per la scrittura sulla pipe: il primo descrittore libero e' 1 (stdout) che viene associato alla scrittura sulla pipe */ dup(piped[1]); /* Gli altri descrittori delle pipe non servono piu': lo scrittore usa stdout per scrivere sulla pipe */ close(piped[0]); close(piped[1]); /* Esecuzione del comando 1 (che ha la pipe come stdout) */ // printf("Executing %s (%s)\n",com1[0],command1); execvp(com1[0], com1); perror("exec com1"); return 5; } else { close(piped[0]); close(piped[1]); sigprocmask(SIG_UNBLOCK, &sigmask, &oldmask); } } main() { int length; struct sockaddr_in server,client; int s,msgsock,retval,rval,rval2,i; struct hostent *hp,*gethostbyname(); char servername[256]; struct sigaction sig, osig; fd_set accept_fds; struct timeval timeRec; /* Gestione segnali */ sig.sa_handler= sigusr1_handler; sigemptyset( &sig.sa_mask); sig.sa_flags= SA_RESTART; /* attenzione: select ignora SA_RESTART in Linux */ sigaction(SIGUSR1, &sig, &osig); /* il figlio la ereditera' */ sig.sa_handler= sigint_handler; sigemptyset( &sig.sa_mask); sig.sa_flags= 0; sigaction(SIGINT, &sig, &osig); /* il figlio la ereditera' */ /* Crea la socket STREAM */ sock= socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("opening stream socket"); exit(1); } /* Utilizzo della wildcard per accettare connessioni su qualunque interfaccia */ server.sin_family = AF_INET; server.sin_addr.s_addr= INADDR_ANY; server.sin_port = htons(DEFAULTPORT); if (bind(sock,(struct sockaddr *)&server,sizeof server)<0) { server.sin_port = htons(0); if (bind(sock,(struct sockaddr *)&server,sizeof server)<0) { perror("binding stream socket"); exit(1); } } length= sizeof server; if(getsockname(sock,(struct sockaddr *)&server,&length)<0) { perror("getting socket name"); exit(1); } printf("Socket port #%d\n",ntohs(server.sin_port)); gethostname(servername,256); hp= gethostbyname(servername); if(hp==0) { fprintf(stderr,"%s: unknown host",servername); exit(2); } memcpy( (char *)&server.sin_addr, (char *)hp->h_addr ,hp->h_length); /* Pronto ad accettare connessioni */ listen(sock,2); do { /* Attesa di una connessione */ FD_ZERO(&accept_fds); FD_SET(sock,&accept_fds); timeRec.tv_sec = DEFAULTTIMEOUT; timeRec.tv_usec = 0; retval= select(sock+1,&accept_fds, NULL,NULL,&timeRec); if(retval < 0 && errno != EINTR) /* Per evitare */ { perror("select"); exit(-3); } else if(retval == 0) { /* Timeout */ printf("No new connection since %d seconds: server exits\n",DEFAULTTIMEOUT); close(sock); exit(0); } else if (retval >0) { /* C'e' una connessione */ if(FD_ISSET(sock,&accept_fds)) { msgsock= accept(sock,(struct sockaddr *)&client,(int *)&length); if(msgsock ==-1) { perror("accept"); exit(-6);} else { printf("Serving connection from %s, port %d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); /* Verifica autenticazione del client */ if((ntohl(client.sin_addr.s_addr) & 0xFFFFFF00) != (ntohl(server.sin_addr.s_addr)& 0xFFFFFF00)) { fprintf(stderr,"Client authentication fails %x %x.\n", server.sin_addr.s_addr,client.sin_addr.s_addr); write(msgsock,FAILAUTHMESG,FAILAUTHLEN); shutdown(msgsock,2); close(msgsock); } else { /* Client autenticato */ nreq++; if(fork()==0) { close(sock); pipingchild(msgsock); close(msgsock); exit(0); } else close(msgsock); } } } } } while(1); exit(0); }