testsf_s.c revision 92d4b6d03e384fcd8d35827200c728b079f8b106
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
22int TST_TOTAL = 1;
23
24#if INET6
25char *TCID = "sendfile6_server";
26#else
27char *TCID = "sendfile_server";
28#endif
29
30int 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