/* Halb-Bearbeitete Programmieraufgabe "SitzPlatz Planer-Backend" * https://sys.cs.fau.de/extern/lehre/ws23/sp2/pruefung/klausuren/2023s-SP-Klausur_www.pdf */ #include #include #include #include #include #include #include #include #include #include #include #include #define CMD_MAX_LEN 1024 #define THREADS 10 #define PORT 1416 typedef struct BNDBUF BNDBUF; typedef struct SEM SEM; void die(const char *msg) { /* ... */ } struct slot { /* ... */ }; struct params { SEM *active, *sync; BNDBUF *clients; }; // stores @value in the store associated with @key. Never fails! void kvs_add(const char *key, void *value); // returns the value associated with @key if it is in the store or NULL. void *kvs_get(const char *key); // calls @callback for every item in the key value store void kvs_iter(void (*callback)(const char *key, void *value)); // creates and returns a new ‘struct slot‘ reserved by @owner (see slot_own). // On error, errno is set and NULL returned. struct slot *slot_alloc(const char *owner); // atomically reserves @slot for @owner, or releases it if @owner is NULL. // On success, 0 is returned, otherwise -1 and errno is set appropriately. // This may be if the slot is already reserved and @owner is not NULL, or // already free if @owner is NULL, as well as related to required memory // allocations (@owner is dublicated). int slot_own(struct slot *slot, const char *owner); // creates a new semaphore with initial value of @count. // returns NULL on error and sets errno. SEM *semCreate(int count); void P(SEM *); void V(SEM *); // create a new bounded buffer of given @size. // returns NULL on error and sets errno BNDBUF *bbCreate(size_t size); // adds @value into @bb. Blocks if necessary and never fails. void bbPut(BNDBUF *bb, int value); // retrieves next value from @bb. Blocks if necessary and never fails. int bbGet(BNDBUF *bb); int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "USAGE: %s [paths...]\n", argv[0]); return EXIT_FAILURE; } // Parameter verarbeiten for (int i = 1; i < argc; i++) { load(argv[i]); } // Netzwerkkommunikation aufsetzen int sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock == -1) { die("socket"); } struct sockaddr_in6 addr = { .sin6_family = AF_INET6, .sin6_port = htons(PORT), .sin6_addr = in6addr_any, }; int ret = bind(sock, (struct sockaddr) &addr, sizeof(addr)); if (ret == -1) { die("bind"); } ret = listen(sock, SOMAXCONN); if (ret == -1) { die("listen"); } // Thread-Pool aufsetzen struct param p = { 0 }; p.active = semCreate(THREADS); if (p.active == NULL) { die("semCreate"); } p.sync = semCreate(1); if (p.sync == NULL) { die("semCreate"); } p.clients = bbCreate(THREADS); if (p.clients == NULL) { die("bbCreate"); } for (int i = 0; i < THREADS; i++) { pthread_t tid; errno = pthread_create(&tid, NULL, &worker, &p); if (errno != 0) { die("pthread_create"); } } // Anfragen annahmen for (;;) { int client_sock = accept(sock, NULL, NULL); if (client_sock == -1) { perror("accept"); continue; } bbPut(p.clients, cl); } } static void load(const char *path) { // Pfad-Type prüfen struct stat statbuf; if (-1 == lstat(path, &statbuf)) { die("lstat"); } if (S_ISREG(statbuf.st_mode)) { switch (fnmatch("*.slot", path, 0)) { case FNM_NOMATCH: return; case 0: if (-1 == add_slot(path)) { die("add_slot"); } break; default: return; } } else if (S_ISDIR(statbuf.st_mode)) { DIR *d = opendir(path); if (d == NULL) { die("opendir"); } /* readdir */ struct dirent *ent; while (errno = 0, (ent = readdir(d)) != NULL) { char complete_path[strlen(path) + 300]; snprintf(complete_path, strlen(complete_path), "%s/%s", path, ent.d_name); load(complete_path); } if (errno != 0) { die("readdir"); } /* closedir */ if (0 != closedir(d)) { die("closedir"); } } } static int add_slot(const char *path) { FILE *f= fopen(path, "r"); char name[CMD_MAX_LEN] = { 0 }; if (NULL == fgets(name, sizeof(name), f)) { if (ferror(f)) { return -1; } } struct slot *slot = slot_alloc(name); if (slot == NULL) { return -1; } path[strlen(path) - sizeof(".slot") + 1] = '\0'; kvs_add(path, slot); } static void save(const char *key, void *value) { } static void *worker(void *arg) { struct param *p = (struct param*) arg; while (1) { int client_socket = bbGet(p.clients); int copy = dup(client_socket); if (copy == -1) { perror("dup"); continue; } FILE *rx, *tx; tx = fdopen(client_socket, "w"); if (tx == NULL) die("fdopen"); rx = fdopen(copy, "r"); if (rx == NULL) die("fdopen"); // Befehle auslesen und bearbeiten char line[CMD_MAX_LEN]; while (fgets(line, sizeof(line), rx) != NULL) { char *sp; char *slot = strtok_r(line, " \t", &sp); char *owner = strtok_r(NULL, " \t", &sp); fprintf(tx, "%s\n", command(p, slot, owner)); if (EOF == fflush(tx)) { perror("fflush"); break; } } if (ferror(rx)) {perror("fgets");} if (EOF == fclose(rx)) {perror("fclose");} if (EOF == fclose(tx)) {perror("fclose");} } } const char *command(struct params *p, const char *slot, const char *owner) { if (slot != NULL) { // Reservierung verwalten } else { // slot == NULL // Zustand synchronisieren } }