/* * Server for the sendfile test program * Syntax: testsf_s <own IP addr> */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/file.h> #include <errno.h> #include <sys/signal.h> #include <sys/types.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/sendfile.h> #include <sys/socket.h> #include <sys/wait.h> #include "test.h" #include "netdefs.h" int TST_TOTAL = 1; #if INET6 char *TCID = "sendfile6_server"; #else char *TCID = "sendfile_server"; #endif int main(int argc, char *argv[]) { sai_t sa, *ap; sa_t from; struct addrinfo *hp; struct addrinfo hints; int as, fd, gai, rc, s; char *lp; char *number; int pid, nbytes, flen, count; char rbuf[PATH_MAX]; int chunks = 0; off_t *offset; char nbuf[PATH_MAX]; int port; if (argc != 3) { tst_brkm(TBROK, NULL, "usage: listen-address listen-port"); } /* open socket */ if ((s = socket(AFI, SOCK_STREAM, 0)) < 0) { tst_brkm(TBROK, NULL, "socket error = %d\n", errno); } signal(SIGCHLD, SIG_IGN); /* ignore signals from children */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PFI; if ((gai = getaddrinfo(argv[1], NULL, &hints, &hp)) != 0) { tst_brkm(TBROK, NULL, "getaddrinfo failed"); } if (!hp || !hp->ai_addr || hp->ai_addr->sa_family != AFI) { tst_brkm(TBROK, NULL, "getaddrinfo failed"); } /* server IP and port */ memcpy(&sa, hp->ai_addr, hp->ai_addrlen); port = atoi(argv[2]); #if INET6 sa.sin6_port = htons(port); #else sa.sin_port = htons(port); #endif /* bind IP and port to socket */ if (bind(s, (sa_t *) & sa, sizeof(sa)) < 0) { tst_resm(TBROK, "bind error = %d\n", errno); close(s); tst_exit(); } /* start to listen socket */ if (listen(s, LISTEN_BACKLOG) < 0) { tst_resm(TBROK, "listen error = %d\n", errno); close(s); tst_exit(); } socklen_t fromlen = sizeof(from); /* process connections */ while (1) { /* accept a connection from a client */ if ((as = accept(s, &from, &fromlen)) < 0) { tst_resm(TBROK, "accept error = %d\n", errno); if (errno == EINTR) continue; close(s); tst_exit(); } ap = (sai_t *) & from; /* create a process to manage the connection */ if ((pid = fork()) < 0) { tst_resm(TBROK, "fork error = %d\n", errno); close(as); tst_exit(); } if (pid > 0) { /* parent, go back to accept */ close(as); continue; } /* child process to manage a connection */ close(s); /* close service socket */ /* get client request information */ if ((nbytes = read(as, rbuf, PATH_MAX)) <= 0) { tst_resm(TBROK, "socket read error = %d\n", errno); close(as); tst_exit(); } rbuf[nbytes] = '\0'; /* null terminate the info */ lp = &rbuf[0]; /* start with file length, '=' will start the filename */ count = flen = 0; number = &nbuf[0]; while (*lp != '=') { /* convert ascii to integer */ nbuf[count] = *lp; count++; lp++; } nbuf[count] = '\0'; flen = strtol(number, NULL, 10); /* the file name */ lp++; tst_resm(TINFO, "The file to send is %s\n", lp); /* open requested file to send */ if ((fd = open(lp, O_RDONLY)) < 0) { tst_resm(TBROK, "file open error = %d\n", errno); close(as); tst_exit(); } offset = NULL; errno = 0; do { /* send file parts until EOF */ if ((rc = sendfile(as, fd, offset, flen)) != flen) { if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) { tst_resm(TBROK, "sendfile error = %d, rc = %d\n", errno, rc); close(as); close(fd); tst_exit(); } } chunks++; } while (rc != 0); tst_resm(TINFO, "File %s sent in %d parts\n", lp, chunks); close(as); /* close connection */ close(fd); /* close requested file */ exit(0); } close(s); /* close parent socket (never reached because of the while (1)) */ tst_exit(); }