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