Home | History | Annotate | Download | only in sendfile
      1 /*
      2  * Server for the sendfile test program
      3  * Syntax: testsf_s <own IP addr>
      4  */
      5 
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 #include <unistd.h>
      9 #include <fcntl.h>
     10 #include <sys/file.h>
     11 #include <errno.h>
     12 #include <sys/signal.h>
     13 #include <sys/types.h>
     14 #include <arpa/inet.h>
     15 #include <netinet/in.h>
     16 #include <sys/sendfile.h>
     17 #include <sys/socket.h>
     18 #include <sys/wait.h>
     19 #include "test.h"
     20 #include "netdefs.h"
     21 
     22 int TST_TOTAL = 1;
     23 
     24 #if INET6
     25 char *TCID = "sendfile6_server";
     26 #else
     27 char *TCID = "sendfile_server";
     28 #endif
     29 
     30 int main(int argc, char *argv[])
     31 {
     32 	sai_t sa, *ap;
     33 	sa_t from;
     34 	struct addrinfo *hp;
     35 	struct addrinfo hints;
     36 	int as, fd, gai, rc, s;
     37 	char *lp;
     38 	char *number;
     39 	int pid, nbytes, flen, count;
     40 	char rbuf[PATH_MAX];
     41 	int chunks = 0;
     42 	off_t *offset;
     43 	char nbuf[PATH_MAX];
     44 	int port;
     45 
     46 	if (argc != 3) {
     47 		tst_brkm(TBROK, NULL, "usage: listen-address listen-port");
     48 	}
     49 
     50 	/* open socket */
     51 	if ((s = socket(AFI, SOCK_STREAM, 0)) < 0) {
     52 		tst_brkm(TBROK, NULL, "socket error = %d\n", errno);
     53 	}
     54 
     55 	signal(SIGCHLD, SIG_IGN);	/* ignore signals from children */
     56 
     57 	memset(&hints, 0, sizeof(hints));
     58 	hints.ai_family = PFI;
     59 	if ((gai = getaddrinfo(argv[1], NULL, &hints, &hp)) != 0) {
     60 		tst_brkm(TBROK, NULL, "getaddrinfo failed");
     61 	}
     62 	if (!hp || !hp->ai_addr || hp->ai_addr->sa_family != AFI) {
     63 		tst_brkm(TBROK, NULL, "getaddrinfo failed");
     64 	}
     65 
     66 	/* server IP and port */
     67 	memcpy(&sa, hp->ai_addr, hp->ai_addrlen);
     68 	port = atoi(argv[2]);
     69 #if INET6
     70 	sa.sin6_port = htons(port);
     71 #else
     72 	sa.sin_port = htons(port);
     73 #endif
     74 
     75 	/* bind IP and port to socket */
     76 	if (bind(s, (sa_t *) & sa, sizeof(sa)) < 0) {
     77 		tst_resm(TBROK, "bind error = %d\n", errno);
     78 		close(s);
     79 		tst_exit();
     80 	}
     81 
     82 	/* start to listen socket */
     83 	if (listen(s, LISTEN_BACKLOG) < 0) {
     84 		tst_resm(TBROK, "listen error = %d\n", errno);
     85 		close(s);
     86 		tst_exit();
     87 	}
     88 
     89 	socklen_t fromlen = sizeof(from);
     90 
     91 	/* process connections */
     92 	while (1) {
     93 
     94 		/* accept a connection from a client */
     95 		if ((as = accept(s, &from, &fromlen)) < 0) {
     96 			tst_resm(TBROK, "accept error = %d\n", errno);
     97 			if (errno == EINTR)
     98 				continue;
     99 			close(s);
    100 			tst_exit();
    101 		}
    102 
    103 		ap = (sai_t *) & from;
    104 
    105 		/* create a process to manage the connection */
    106 		if ((pid = fork()) < 0) {
    107 			tst_resm(TBROK, "fork error = %d\n", errno);
    108 			close(as);
    109 			tst_exit();
    110 		}
    111 		if (pid > 0) {	/* parent, go back to accept */
    112 			close(as);
    113 			continue;
    114 		}
    115 
    116 		/* child process to manage a connection */
    117 
    118 		close(s);	/* close service socket */
    119 
    120 		/* get client request information */
    121 		if ((nbytes = read(as, rbuf, PATH_MAX)) <= 0) {
    122 			tst_resm(TBROK, "socket read error = %d\n", errno);
    123 			close(as);
    124 			tst_exit();
    125 		}
    126 		rbuf[nbytes] = '\0';	/* null terminate the info */
    127 		lp = &rbuf[0];
    128 
    129 		/* start with file length, '=' will start the filename */
    130 		count = flen = 0;
    131 		number = &nbuf[0];
    132 		while (*lp != '=') {	/* convert ascii to integer */
    133 			nbuf[count] = *lp;
    134 			count++;
    135 			lp++;
    136 		}
    137 		nbuf[count] = '\0';
    138 		flen = strtol(number, NULL, 10);
    139 
    140 		/* the file name */
    141 		lp++;
    142 
    143 		tst_resm(TINFO, "The file to send is %s\n", lp);
    144 		/* open requested file to send */
    145 		if ((fd = open(lp, O_RDONLY)) < 0) {
    146 			tst_resm(TBROK, "file open error = %d\n", errno);
    147 			close(as);
    148 			tst_exit();
    149 		}
    150 		offset = NULL;
    151 		errno = 0;
    152 		do {		/* send file parts until EOF */
    153 			if ((rc = sendfile(as, fd, offset, flen)) != flen) {
    154 				if ((errno != EWOULDBLOCK) && (errno != EAGAIN)) {
    155 					tst_resm(TBROK,
    156 						 "sendfile error = %d, rc = %d\n",
    157 						 errno, rc);
    158 					close(as);
    159 					close(fd);
    160 					tst_exit();
    161 				}
    162 			}
    163 			chunks++;
    164 		} while (rc != 0);
    165 		tst_resm(TINFO, "File %s sent in %d parts\n", lp, chunks);
    166 
    167 		close(as);	/* close connection */
    168 		close(fd);	/* close requested file */
    169 
    170 		exit(0);
    171 
    172 	}
    173 
    174 	close(s);		/* close parent socket (never reached because of the while (1)) */
    175 
    176 	tst_exit();
    177 
    178 }
    179