Restliche Lösungen siehe StuvePad. ===== Aufgabe 2: Timebox ===== #include #include #include #include #include #include #include #include #include #include #include #include "sem.h" #define BUFFERSIZE 16 #define MAX_LINE_LEN 1024 static const char BASEDIR[] = "timebox-dir"; static const char CONFIG[] = "config"; static const unsigned int DEFAULT_THREADS = 2; static const int LISTEN_PORT = 2016; static const int DEAD_PILL = (int) 0xdeaddead; static void die(const char msg[]) { fprintf(stderr, "Error: %s\n", msg); exit(EXIT_FAILURE); } // Funktionsdeklarationen, globale Variablen usw. const char *cmd_fail_str = "Error: unknown cmd\n"; static int bb[BUFFERSIZE]; static SEM *bb_sem_data, *bb_sem_free, *bb_out_mutex; static volatile int bb_in_idx, bb_out_idx; static volatile int reread_config = 0; static volatile int cur_threads; static void usr_handler(int); static void parse_config(void); static void *thread_handler(void *); static void handleCommand(FILE*, FILE*); static void bbPut(int); static int bbGet(void); // Test with // pkill timebox -SIGUSR1 // netcat localhost 2016 int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) { bb_sem_data = semCreate(0); bb_sem_free = semCreate(BUFFERSIZE); bb_out_mutex = semCreate(1); if (!bb_sem_data || !bb_sem_free || !bb_out_mutex) { die("Sem creation"); } if (chdir(BASEDIR) == -1) die("chdir"); sigset_t emptyset; sigemptyset(&emptyset); struct sigaction sig_pipe= { .sa_handler = SIG_IGN, .sa_mask = emptyset }; if (sigaction(SIGPIPE, &sig_pipe, NULL) == -1) die("sigpipe"); struct sigaction sig_usr = { .sa_handler = usr_handler, .sa_mask = emptyset, .sa_flags = SA_RESTART }; if (sigaction(SIGUSR1, &sig_usr, NULL) == -1) die("sigusr"); sigset_t usrblock; sigemptyset(&usrblock); sigaddset(&usrblock, SIGUSR1); if (pthread_sigmask(SIG_BLOCK, &usrblock, NULL) != 0) die("sigmask"); parse_config(); if (pthread_sigmask(SIG_UNBLOCK, &usrblock, NULL) != 0) die("sigmask"); // Socket erstellen und auf Verbindungsannahme vorbereiten int sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock == -1) die("socket"); // Nur zum Testen! const int reuseaddr_flag = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_flag, sizeof(reuseaddr_flag)) == -1) { perror("Failed setting SO_REUSE_ADDR"); exit(EXIT_FAILURE); } struct sockaddr_in6 name= { .sin6_family = AF_INET6, .sin6_port = htons((uint16_t) LISTEN_PORT), .sin6_addr = IN6ADDR_ANY_INIT }; if (bind(sock, (const struct sockaddr *) &name, sizeof(name)) == -1) die("bind"); if (listen(sock, SOMAXCONN) == -1) die ("listen"); while (1) { // Verbindungen annehmen und bearbeiten int client = accept(sock, NULL, NULL); if (client == -1) { perror("accept failed, retrying..."); continue; } if (reread_config) { if (pthread_sigmask(SIG_BLOCK, &usrblock, NULL) != 0) die("sigmask"); parse_config(); reread_config = 0; if (pthread_sigmask(SIG_UNBLOCK, &usrblock, NULL) != 0) die("sigmask"); } bbPut(client); } } static void usr_handler(int signum __attribute__((unused))) { reread_config = 1; } static void parse_config(void) { FILE *f = fopen(CONFIG, "r"); int new_count = (int) DEFAULT_THREADS; if (f != NULL) { int c; if (fscanf(f, "%d", &c) == 1 && c >= 1) { new_count = c; } fclose(f); } for (int i = cur_threads; i < new_count; i++) { pthread_t t; errno = pthread_create(&t, NULL, thread_handler, NULL); if (errno != 0) die("thread creation"); if (pthread_detach(t) != 0) die("detach"); } for (int i = new_count; i < cur_threads; i++) { bbPut(DEAD_PILL); } cur_threads = new_count; // Nur zum Testen printf("New amount of threads: %d\n", cur_threads); } static void *thread_handler(void *a __attribute__((unused))) { while (1) { int client = bbGet(); if (client == DEAD_PILL) break; int client2 = dup(client); if (client2 == -1) { perror("dup"); close(client); continue; } FILE *rx = fdopen(client, "r"); if (!rx) { perror("fdopen"); close(client); close(client2); continue; } FILE *tx = fdopen(client2, "w"); if (!tx) { perror("fdopen"); fclose(rx); close(client2); continue; } handleCommand(rx, tx); fclose(rx); fclose(tx); } return NULL; } static void handleCommand(FILE *rx, FILE *tx) { char buf[MAX_LINE_LEN + 1]; if (fgets(buf, MAX_LINE_LEN + 1, rx) == NULL) { fprintf(tx, cmd_fail_str); return; } char *saveptr; char *cmd = strtok_r(buf, " \n", &saveptr); if (!cmd || strcmp(cmd, "TIME") != 0) { fprintf(tx, cmd_fail_str); return; } char *relpath = strtok_r(NULL, " \n", &saveptr); if (!relpath) { fprintf(tx, cmd_fail_str); return; } struct stat s; if (lstat(relpath, &s) == -1) { fprintf(tx, "file not found or permission error\n"); return; } fprintf(tx, "%ld\n", s.st_mtime); } static void bbPut(int v) { // only one writer P(bb_sem_free); bb[bb_in_idx] = v; bb_in_idx = (bb_in_idx + 1) % BUFFERSIZE; V(bb_sem_data); } static int bbGet(void) { P(bb_sem_data); int idx; P(bb_out_mutex); idx = bb_out_idx; int v = bb[idx]; bb_out_idx = (bb_out_idx + 1) % BUFFERSIZE; V(bb_out_mutex); V(bb_sem_free); return v; }