/* Unfertiger Stand 24Jan23 */ #define _XOPEN_SOURCE 700 #include #include #include #include #include #include #include #include typedef struct SEM SEM; #define MAX_LINE_LEN 20 struct client { FILE *rx, *tx; SEM *requests; }; struct request { struct client *client; char line[]; }; // vorgegebene Funktionen: void die(const char *name) { perror(name); exit(EXIT_FAILURE); } // parse the string @str as number or pointer into *@dst. // returns 0 on success or in case of an error -1 and sets errno. int parseNumber(const char *str, int *dst); int parsePointer(const char *str, void **dst); // send @fmt to @f as reply to request @line void reply(FILE * f, const char *line, const char *fmt, ...); struct list; // create and return a new list or NULL; sets errno in case of an error struct list *listCreate(void); // add @sem to @list or return -1; sets errno in case of an error int listAppend(struct list *list, SEM * sem); // returns 1 if @list contains @sem, 0 otherwise int listContains(const struct list *list, SEM * sem); // create and return a new semaphore or NULL and set errno in case of an // error SEM *semCreate(int initVal); // destroy a semaphore and free all associated resources. void semDestroy(SEM * sem); // P- and V-operations never fail. void P(SEM * sem); void V(SEM * sem); // Globale Variablen int workerStart(void *(*fn)(void *), void *arg); void *clientProcess(void *arg); struct client *clientCreate(int fd); static struct list* list; int main(int argc, char *argv[]) { list = listCreate(); if (list == NULL) { die("listCreate"); } int sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock == -1) die("socket"); if (bind(sock, (struct sockaddr*)&(struct sockaddr_in6) { .sin6_family = AF_INET6, .sin6_port = htons(7076), .sin6_addr = in6addr_any, }, sizeof(struct sockaddr_in6)) == -1) die("bind"); if (listen(sock, SOMAXCONN) == -1) die("listen"); while (1) { int client_socket = accept(sock, NULL, NULL); if (client_socket == -1) continue; struct client *client = clientCreate(client_socket); if (client == NULL) die("clientCreate"); if (-1 == workerStart(clientProcess, client)) { die("workerStart"); } } } int workerStart(void *(*fn)(void *), void *arg) { pthread_t tid; errno = pthread_create(&tid, NULL, fn, arg); if (errno != 0) return -1; if ((errno = pthread_detach(tid)) != 0) return -1; } struct client *clientCreate(int fd) { struct client client = {0}; client.tx = fdopen(fd, "w"); if (client.tx == NULL) goto fail; fd = dup(fd); if (fd == -1) goto fail; client.rx = fdopen(fd, "r"); if (client.rx == NULL) goto fail; struct client *toreturn = malloc(sizeof(struct client)); if (toreturn == NULL) goto fail; (*toreturn) = client; return toreturn; fail: /* TODO: copy errno to preserve its value */ if (client.tx != NULL) fclose(client.tx); if (client.rx != NULL) fclose(client.rx); if (client.requests != NULL) semDestroy(client.requests); return NULL; } void *handleRequest(void *arg); void clientDestroy(struct client *client); void *clientProcess(void *arg) { struct client *cli = (struct client *) arg; while (!0) { char line[MAX_LINE_LEN + 1] = {0}; int c, i = 0; while ((c = fgetc(cli->rx)) != EOF) { if (i < MAX_LINE_LEN) { line[i] = (char) c; } i++; if (c == '\n') { break; } } // Zeilenlänge prüfen if (i > MAX_LINE_LEN) continue; // Anfrage erstellen und zur Bearbeitung auslagern struct request *req = malloc( sizeof(struct request) + MAX_LINE_LEN); if (req == NULL) { reply(cli->tx, "malloc: %s", strerror(errno)); continue; } req->client = cli; strcpy(req->line, line); workerStart(handleRequest, req); /* TODO: Rethink EOF handling */ if (EOF == c && feof(cli->rx)) { break; } } clientDestroy(cli); } void clientDestroy(struct client *client) { if (client != NULL) { fclose(client->tx); fclose(client->rx); semDestroy(client->requests); free(client); } } int handleI(const struct request *rq); int handlePV(const struct request *rq, void(*fn)(SEM *)); void *handleRequest(void *arg) { struct request *req = (struct request*) arg; switch (req->line[0]) { case 'I': handleI(req); break; case 'P': handlePV(req, P); break; case 'V': handlePV(req, V); break; } } int handleI(const struct request *rq) { int init; parseNumber(rq->line+1, &init); SEM *sem = semCreate(init); if (sem == NULL) { reply(rq->client->tx, "semCreate: %s", strerror(errno)); } if (-1 == listAppend(list, sem)) { reply(rq->client->tx, "listAppend: %s", strerror(errno)); } else { reply(rq->client->tx, "%p", sem); } } int handlePV(const struct request *rq, void(*fn)(SEM *)) { }