/* 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) { (void) 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 BNDBUF *buf = bbCreate(THREADS+1); if (buf == NULL) die("bbCreate"); SEM *active, *sync; active = semCreate(THREADS); if (active == NULL) die("semCreate"); sync = semCreate(1); if (sync == NULL) die("semCreate"); struct params p = { .active = active, .sync = sync, .clients = buf, }; pthread_t tid; for (int i = 0; i < THREADS; i++) { errno = pthread_create(&tid, NULL, &worker, &p); if (errno != 0) die("pthread_create"); } // Anfragen annehmen for (;;) { int conn = accept(sock, NULL, NULL); if (conn == -1) { die("accept"); } bbPut(buf, conn); } } static void load(const char *path) { // Pfad-Type prüfen struct stat sbuf; if (-1 == stat(path, &sbuf)) die("stat"); if (S_ISREG(sbuf.st_mode)) { /* regular */ char *suffix = strrchr(path, '.'); if (suffix != NULL && strcmp(suffix, ".slot") == 0) { if (-1 == add_slot(path)) die("add_slot"); } } else if (S_ISDIR(sbuf.st_mode)) { /* directory */ DIR *dir = opendir(path); if (dir == NULL) die("opendir"); struct dirent *de; while (errno = 0, (de = readdir(dir)) != NULL) { char subpath[strlen(path) + 1 + strlen(de->d_name) + 1]; sprintf(subpath, "%s/%s", path, de->d_name); load(subpath); } if (errno != 0) die("readdir"); if (-1 == closedir(dir)) die("closedir"); } } static int add_slot(const char *path) { FILE *file = fopen(path, "r"); if (file == NULL) die("fopen"); char owner[CMD_MAX_LEN + 1]; if (NULL == fgets(file, &owner, sizeof(owner))) { if (feof(file)) { fclose(file); return 0; } else { fclose(file); return -1; } } struct slot *slot = slot_alloc(owner); if (NULL == slot) return -1; *strrchr(path, '.') = '\0'; /* I guess this works */ kvs_add(owner, slot); } static void save(const char *key, void *value) { } static void *worker(void *arg) { // Befehle auslesen und bearbeiten } const char *command(struct params *p, const char *slot, const char *owner) { if (slot != NULL) { // Reservierung verwalten } else { // slot == NULL // Zustand synchronisieren } }