/***************************************************************************** * Softwaresysteme I - Klausur Februar 2001 * * Datei: fileserver.c * Autor: Goethe * Datum: 03.09.2005 *****************************************************************************/ /* Includes */ #include #include #include #include #include #include #include #include #include #include #include /* Joblistenverwaltung von Aufgabe 7 - libjl.a, weicht etwas von Klausur ab */ #include "joblist.h" #define MAXCHAR 256 /* * Funktion zum Entfernen von Carriage-Return und/oder Newline * am Ende eines Strings. */ void trim( char* line ) { int i; for( i = strlen(line)-1; i >= 0; i-- ) { if( line[i] == '\n' || line[i] == 13 ) line[i] = '\0'; } } /* * Deklaration von Funktionen, die bei der Programmierung von * main benötigt werden und die im Rahmen dieser * Aufgabe (zusätzlich zu main) zu programmieren sind */ /* Funktion, welche die Anforderung der Clients bearbeitet. * Der Fiedeskriptor fd bezeichnet die Verbindung zum Client. * Im Erfolgsfall wird 0 zurückgegeben, sonst -1. */ int verbindung_bearbeiten( int client_sock_fd ); /* Signalhandler */ void sigchld_handler(); /* Funktion, die den Signalhandler installiert */ void install_signalhandler(); /* Blockieren und Deblockieren des Signals SIGCHLD */ void sigblock(); void sigunblock(); /* * Globale Variablen */ jl_t jobs; /* * Funktion main */ int main( int argc, char *argv[] ) { /* Variablendefinitionen */ int port; struct sockaddr_in sin; int sd, cd; /* Socketdeskriptoren */ pid_t pid; /* für fork() */ /* Auswerten der Aufrufparameter */ if( argc != 2 ) { fprintf( stderr, "Falsche Anzahl an Parametern.\n" ); exit( EXIT_FAILURE ); } port = atoi( argv[1] ); /* wandle String in int um */ jobs = jl_new(); /* Signalhandler für SIGCHLD installieren */ install_signalhandler(); /* * Socket erzeugen und initialisieren */ if( (sd = socket( PF_INET, SOCK_STREAM, 0 )) == -1 ) { perror( "Fehler beim Erzeugen des Sockets" ); exit( EXIT_FAILURE ); } sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(port); if( bind( sd, (struct sockaddr*)&sin, sizeof(sin) ) == -1 ) { perror( "Fehler beim Binden des Socket" ); exit( EXIT_FAILURE ); } if( listen( sd, 5 ) == -1 ) { perror( "Fehler beim Initialisieren des Socket" ); exit( EXIT_FAILURE ); } while(1) { /* * Neue Verbindung akzeptieren */ if( (cd = accept( sd, NULL, 0 )) == -1 ) { if( errno != EINTR ) perror( "Fehler beim Akzeptieren einer Verbindung" ); continue; } /* Neuen Prozess erzeugen und in die Jobliste eintragen. * Verbindung in diesem Prozess bearbeiten (durch * Aufruf von verbindung_bearbeiten() ) * Fehler beim Bearbeiten der Verbindung soll der * Kindprozess durch seinen Exit-Status anzeigen. */ pid = fork(); switch( pid ) { case -1: perror( "Fehler beim Erzeugen des Kindprozesses" ); close(cd); continue; case 0: /* child process */ close(sd); return verbindung_bearbeiten(cd); } sigblock(); if( jl_insert( jobs, pid, NULL ) == -1 ) perror( "Fehler beim Einfügen der PID des Kindprozesses" ); sigunblock(); } /* gehört zu while(1) */ } /* gehört zu main() */ /* Funktion, welche die Anforderung eines Clients bearbeitet. * Der Filedeskriptor fd bezeichnet die Verbindung zum Client. * Im Erfolgsfall wird 0 zurückgegeben, sonst -1. */ int verbindung_bearbeiten( int fd ) { char line[MAXCHAR+2]; char output[MAXCHAR+20]; int c; struct stat buf; if( !(fd > 0) ) { errno = EBADF; return -1; } while(1) { while( (c = read( fd, line, MAXCHAR+1 )) == -1 ) { if( errno == EINTR ) continue; return -1; } if( c == MAXCHAR+1 ) { write( fd, "Anfrage zu lang.\n", 18 ); while(1) { c = read( fd, line, 1 ); if( c == -1 ) { if( errno == EINTR ) continue; else return -1; } if( line[0] == '\n' ) break; } continue; } line[c+1] = '\0'; trim(line); if( strcmp( line, "exit" ) == 0 ) return 0; if( lstat( line, &buf ) == -1 ) { strcpy( output, strerror(errno) ); strcat( output, "\n" ); write( fd, output, strlen(output) ); continue; } snprintf( output, sizeof(output), "%s %d\n", line, (int)buf.st_size ); if( write( fd, output, strlen(output)+1 ) == -1 ) { close(fd); return -1; } } close(fd); return -1; } /* * Signalhandler für SIGCHLD installieren */ void install_signalhandler() { struct sigaction act; memset( &act, 0, sizeof(act) ); act.sa_handler = sigchld_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if( sigaction( SIGCHLD, &act, NULL ) == -1 ) perror( "Fehler beim Installieren des Signalhandlers" ); } /* * Signalhandler für SIGCHLD */ void sigchld_handler( int sig ) { pid_t pid; int status; while( (pid = waitpid( -1, &status, WNOHANG )) != 0 ) { if( pid == -1 ) break; if( jl_remove_pid( jobs, pid, NULL, 0 ) == -1 ) perror( "Fehler beim Entfernen der PID aus der Jobliste" ); if( WIFEXITED(status) ) fprintf( stdout, "Exitstatus = %d", WEXITSTATUS(status) ); } } /* * Signal SIGCHLD blockieren */ void sigblock() { sigset_t set; sigemptyset( &set ); sigaddset( &set, SIGCHLD ); sigprocmask( SIG_BLOCK, &set, NULL ); } /* * Signal SIGCHLD deblockieren */ void sigunblock() { sigset_t set; sigemptyset( &set ); sigaddset( &set, SIGCHLD ); sigprocmask( SIG_UNBLOCK, &set, NULL ); }