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