sem.c:
#include <stdlib.h> #include <stdio.h> #include "sem.h" SEM *sem_init(int n) { SEM *s; s = (SEM *) malloc(sizeof(SEM)); if (s == NULL) { perror("malloc"); exit(EXIT_FAILURE); } pthread_mutex_init(&s->m, NULL); pthread_cond_init(&s->c, NULL); s->s = n; return s; } void P(SEM *s) { pthread_mutex_lock(&s->m); while (s->s < 1) { pthread_cond_wait(&s->c, &s->m); } s->s--; pthread_mutex_unlock(&s->m); } void V(SEM *s) { pthread_mutex_lock(&s->m); s->s++; pthread_cond_broadcast(&s->c); pthread_mutex_unlock(&s->m); }
fdserver.c:
#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <dirent.h> #include <sys/stat.h> #include <pthread.h> #include <string.h> #include "sem.h" #define NTHREAD 25 void *serve(void *arg); void handle(FILE *socket, char path[]); void fhandle(FILE *socket, char path[]); void dhandle(FILE *socket, char path[]); struct bufinfo { SEM *sem_full; SEM *sem_free; pthread_mutex_t lock; int socks[NTHREAD]; int writep; int readp; }; int main(int argc, char *argv[]) { struct bufinfo b; pthread_t tid[NTHREAD]; int i; int sock; struct sockaddr_in saddr; b.writep = 0; b.readp = 0; b.sem_full = sem_init(0); b.sem_free = sem_init(NTHREAD); pthread_mutex_init(&b.lock, NULL); for (i = 0; i < NTHREAD; i++) { pthread_create(&tid[i], NULL, serve, &b); } sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == -1) { perror("socket"); return EXIT_FAILURE; } saddr.sin_family = AF_INET; saddr.sin_port = argc > 1 ? htons(atoi(argv[1])) : htons(31337); saddr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr)) == -1) { perror("bind"); return EXIT_FAILURE; } if (listen(sock, 20) == -1) { perror("listen"); return EXIT_FAILURE; } while (1) { int clsock; struct sockaddr clsaddr; socklen_t clsaddr_len = sizeof(clsaddr); clsock = accept(sock, &clsaddr, &clsaddr_len); if (clsock == -1) { perror("accept"); continue; } P(b.sem_free); b.socks[b.writep] = clsock; b.writep = (b.writep + 1) % NTHREAD; V(b.sem_full); } return 0; } void *serve(void *arg) { struct bufinfo *b = (struct bufinfo *) arg; int s; FILE *fd; char buffer[1024+2]; P(b->sem_full); pthread_mutex_lock(&b->lock); s = b->socks[b->readp]; b->readp = (b->readp + 1) % NTHREAD; pthread_mutex_unlock(&b->lock); V(b->sem_free); fd = fdopen(s, "r+"); while (fgets(buffer, 1024+2, fd) != NULL) { buffer[strlen(buffer)-1] = '\0'; handle(fd, buffer); } return NULL; } void handle(FILE *socket, char path[]) { struct stat statinfo; if (stat(path, &statinfo) == -1) { fprintf(socket, "%s\n", strerror(errno)); return; } if (S_ISDIR(statinfo.st_mode)) { dhandle(socket, path); } else if (S_ISREG(statinfo.st_mode)) { fhandle(socket, path); } else { fprintf(socket, "Error: Something special, but not a file or directory\n"); return; } } void fhandle(FILE *socket, char path[]) { char buf[1024+2]; FILE *fd; fd = fopen(path, "r"); if (fd == NULL) { fprintf(socket, "%s\n", strerror(errno)); return; } while (fgets(buf, 1024+2, fd) != NULL) { if (fputs(buf, socket) == EOF) { perror("errno"); return; } } } void dhandle(FILE *socket, char path[]) { DIR *dir; struct dirent entry; struct dirent *result; int err; dir = opendir(path); if (dir == NULL) { fprintf(socket, "Error: %s\n", strerror(errno)); } while(((err = readdir_r(dir, &entry, &result)) == 0) && result != NULL) { fprintf(socket, "%s\n", entry.d_name); } }