// gcc -Wall -Wextra -o server server.c #include #include #include #include #include #include #include #include #define FIFO_PATH "/tmp/myfifo" int main() { int fd = -1; fd_set readfds; int nsel; char buf[80] = { 0 }; if (unlink (FIFO_PATH) < 0 && errno != ENOENT) { perror ("unlink"); exit (1); } if (mkfifo(FIFO_PATH, 0600) < 0) { fprintf(stderr, "Could not create fifo %s: %s\n", FIFO_PATH, strerror(errno)); return -1; } fd = open(FIFO_PATH, O_RDONLY | O_NONBLOCK); // open() does not block printf("fd = %d\n", fd); if (fd < 0) { fprintf(stderr, "Could not open fifo %s: %s\n", FIFO_PATH, strerror(errno)); return -1; } if (fcntl(fd, F_SETFL, O_RDONLY) == -1) // pragmatic fprintf(stderr, "fcntl F_SETFL: %s\n", strerror(errno)); int flags = fcntl(fd, F_GETFL); if (flags == -1) fprintf(stderr, "fcntl F_GETFL: %s\n", strerror(errno)); printf("flags = 0%o\n", flags); // while(1) { printf("Calling select() ... "); fflush(stdout); FD_ZERO (&readfds); FD_SET (fd, &readfds); /* Different from read(2), select(2) will *block* on the read end of a fifo (or pipe) if the write end has never been opened before (and only in that case), while read(2) will always return with zero (in case of an empty pipe) if the write end is closed/ has been closed. Therefore, calling select(2) before calling read(2), will enable us to block if the pipe has never been openend before (again, and only in that case). */ nsel = select (fd + 1, &readfds, NULL, NULL, NULL); // select() blocks until the write end of the pipe has been opened (while the // write end has never been opened before) and data has been injected. printf ("returned %d\n", nsel); printf("Reading ...\n"); ssize_t status = 0; while (1) { // allow me to reset errno and inspect status ... errno = 0; /* read(2) will block on the read end of a fifo (or pipe) in case the write end of the fifo (or pipe) has been opened and the pipe is empty. [1] [1] only if the O_NONBLOCK open file status flag has been disabled. */ status = read(fd, buf, sizeof(buf)); printf("status = %ld, errno = %d\n", status, errno); // will arrive here only if the write end of fifo has been opened (before it // was closed again) if (status == 0) { // the write end of the fifo has been closed (EOF) close(fd); int fd2; if ((fd2 = open (FIFO_PATH, O_RDONLY | O_NONBLOCK)) < 0) { perror ("open"); exit (1); } if (fcntl(fd, F_SETFL, O_RDONLY) == -1) // pragmatic fprintf(stderr, "fcntl F_SETFL: %s\n", strerror(errno)); int flags = fcntl(fd, F_GETFL); if (flags == -1) fprintf(stderr, "fcntl F_GETFL: %s\n", strerror(errno)); printf("flags = 0%o\n", flags); /* assign the new file descriptor to variable fd; otherwise select(2) will not block on the read end in case the write end of the fifo (or pipe) is closed. */ fd = fd2; printf("fd = %d - refreshed\n", fd); break; } if (status > 0) { if (write(1, buf, status) < 0) { fprintf(stderr, "Error sending message: '%s': %s\n", buf, strerror(errno)); } if (buf[status - 1] != '\n') { write(1, &"\n", 1); } if (strncasecmp(buf, "quit", 4) == 0) { close(fd); remove(FIFO_PATH); exit (0); } } if (status < 0) { /* An error occurred, bail out */ close(fd); perror("read"); exit (1); } } // end while(1) read } // end while(!done) select close(fd); remove(FIFO_PATH); return 0; } //=====