/*
* 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();
}