/* INTBOX.C VERSUCH (klausur ss19) * alles in der übung erarbeitet * keine garnatie auf richtigkeit * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define POISON (-1) // Atomic compare-and-swap operation, in pseudo-code: // if (*object_ptr == *expected_ptr) { // *object_ptr = desired; // } // Returns true if CAS was successful, false otherwise. #define CAS(object_ptr, expected_ptr, desired) \ atomic_compare_exchange_strong(object_ptr, expected_ptr, desired) // API: bounded buffer struct bbuf; // forward declaration // Create new bounded buffer; returns NULL on error and sets errno. struct bbuf *bb_create(size_t size); // Add entry to bounded buffer; blocks if full, cannot fail. void bb_put(struct bbuf *bb, int value); // Retrieve element from bounded buffer, waiting until one is available; // cannot fail. int bb_get(struct bbuf *bb); // Return the formatted directory content of the path as allocated string; // cannot fail. const char *format_directory(const char *path); // Struct for a single cache entry struct cache { struct cache *next; const char *path; const char *data; }; // Helper function static void die(const char *s) { perror(s); exit(EXIT_FAILURE); } // Globale Variablen; Vorwärtsdeklarationen von Funktionen // dürfen weggelassen werden static int listen_socket; static struct bbuf *bbuf; static struct cache *cache_head; void cache_put(const char *path, const char *data); const char *cache_get(const char *path); void handle_request(FILE *read, FILE *write); void *worker_thread(); // Funktion zur Signalbehandlung void handle_sigint() { close(listen_socket); } // Hauptfunktion (main) int main(void) { // Datenstrukturen initialisieren bbuf = bb_create(42); if (NULL == bbuf) { die("bb_create"); } // Signalbehandlungen initialisieren struct sigaction sigact_int = { .sa_handler = handle_sigint, .sa_flags = SA_RESTART, }; if (sigemptyset(&sigact_int.sa_mask) < 0) { die("sigemptyset"); } if (sigaction(SIGINT, &sigact_int, NULL) < 0) { die("sigaction"); } struct sigaction sigact_pipe = { .sa_handler = SIG_IGN, .sa_flags = SA_RESTART, }; if (sigemptyset(&sigact_pipe.sa_mask) < 0) { die("sigemptyset"); } if (sigaction(SIGPIPE, &sigact_pipe, NULL) < 0) { die("sigaction"); } // Threads starten pthread_t threads[23]; for (int i = 0; i < 23; i++) { if ((errno = pthread_create(&threads[i], NULL, worker_thread, NULL)) < 0) { die("pthread_create"); } } // Socket erstellen listen_socket = socket(AF_INET6, SOCK_STREAM, 0); if (listen_socket == -1) { die("socket"); } struct sockaddr_in6 name = { .sin6_family = AF_INET6, .sin6_port = htons(71), .sin6_addr = in6addr_any, }; if (bind(listen_socket, (struct sockaddr *) &name, sizeof(name))) { die("bind"); } if (listen(listen_socket, SOMAXCONN)) { die("listen"); } // Verbindungen annehmen for (;;) { int client_socket; if ((client_socket = accept(listen_socket, NULL, NULL))) { if (errno == EBADF) { break; } die("accept"); } bb_put(bbuf, client_socket); } // Threads signalisieren und auf Beendigung dieser warten for (int i = 0; i < 23; i++) { bb_put(bbuf, POISON); } for (int i = 0; i < 23; i++) { pthread_join(threads[i], NULL); } return EXIT_SUCCESS; } // Funktion für Arbeiterthread void *worker_thread() { int client_socket, client_socket_dup; FILE *tx, *rx; sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); pthread_sigmask(SIG_BLOCK, &set, NULL); for (;;) { client_socket = bb_get(bbuf); if (POISON == client_socket) { break; } client_socket_dup = dup(client_socket); if (client_socket_dup == -1) { continue; /* or die */ } rx = fdopen(client_socket, "r"); if (!rx) { continue; /* or die */ } tx = fdopen(client_socket_dup, "w"); if (!tx) { fclose(rx); continue; /* or die */ } handle_request(rx, tx); fclose(rx); fclose(tx); } return NULL; } // Funktion für Requests void handle_request(FILE *read, FILE *write) { char buf[1337 + 1], *contents; if (fgets(buf, sizeof(buf), read) == NULL) { return; } int len = strlen(buf); if (buf[len - 1] == '\n') { buf[len - 1] = '\0'; } contents = (char*) cache_get(buf); if (!contents) { contents = (char*) format_directory(buf); cache_put(buf, contents); } fprintf(write, "%s", contents); } // Funktion zum Lesen aus dem Cache const char *cache_get(const char *path) { struct cache *elem = cache_head; while (elem != NULL) { if (strcmp(path, elem->path) == 0) { return elem->data; } elem = elem->next; } return NULL; } // Funktion zum Schreiben in den Cache void cache_put(const char *path, const char *data) { struct cache *elem = calloc(1, sizeof(struct cache)); if (!elem) { return; /* or die */ } elem->path = strdup(path); if (!elem->path) { return; /* or die */ } elem->data = data; do { elem->next = cache_head; } while (!CAS(&cache_head, &elem->next, elem)); /*K ^ * wie schon in der übung erwähnt, hab ich hier noch einen kleinen typ-fehler, den ich noch nicht beseitigen konnte. */ }