• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
main(int argc,char * argv[])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