summaryrefslogtreecommitdiffabout
path: root/tests
authorSergey Poznyakoff <gray@gnu.org>2019-06-09 15:54:58 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-06-09 15:54:58 (GMT)
commitc4dbd40477bb658cdc5c5e01b8f80057e587cd88 (patch) (unidiff)
tree73534b2cd2fff99e16c26ed4be8cf115cf4b3960 /tests
parentc33922f128403f5d05d24f19abeaad2368ce5467 (diff)
downloadpies-c4dbd40477bb658cdc5c5e01b8f80057e587cd88.tar.gz
pies-c4dbd40477bb658cdc5c5e01b8f80057e587cd88.tar.bz2
Test inetd components.
* lib/Makefile.am: Add urlconn.c * lib/libpies.h (url_connect): New proto. * lib/urlconn.c: New file. * src/piesctl.c (shttp_connect): Use url_connect. * tests/.gitignore: Update. * tests/Makefile.am: New auxtool: aux/in.test New test: inet.at * tests/aux/in.test: New file. * tests/inet.at: New file. * tests/iobuf.h: New file. * tests/nt.c: New file. * tests/testsuite.at: Add new test. * tests/to.c: explicitly terminate the child process on timeout.
Diffstat (limited to 'tests') (more/less context) (ignore whitespace changes)
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am9
-rwxr-xr-xtests/aux/in.test22
-rw-r--r--tests/inet.at38
-rw-r--r--tests/iobuf.h141
-rw-r--r--tests/nt.c339
-rw-r--r--tests/testsuite.at1
-rw-r--r--tests/to.c50
8 files changed, 590 insertions, 11 deletions
diff --git a/tests/.gitignore b/tests/.gitignore
index 459fa44..68159e3 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -7,3 +7,4 @@ testsuite
7testsuite.dir 7testsuite.dir
8testsuite.log 8testsuite.log
9to 9to
10nt
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 14f5b4f..0290f61 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -20,7 +20,8 @@ AUXTOOLS = \
20 aux/mailer\ 20 aux/mailer\
21 aux/touchfile\ 21 aux/touchfile\
22 aux/sleepexit\ 22 aux/sleepexit\
23 aux/startcheck 23 aux/startcheck\
24 aux/in.test
24 25
25EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 $(AUXTOOLS) 26EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 $(AUXTOOLS)
26DISTCLEANFILES = atconfig $(check_SCRIPTS) 27DISTCLEANFILES = atconfig $(check_SCRIPTS)
@@ -52,6 +53,7 @@ TESTSUITE_AT = \
52 cyclic.at\ 53 cyclic.at\
53 env.at\ 54 env.at\
54 envop.at\ 55 envop.at\
56 inet.at\
55 respawn.at\ 57 respawn.at\
56 redirect.at\ 58 redirect.at\
57 ret-exec.at\ 59 ret-exec.at\
@@ -64,9 +66,12 @@ TESTSUITE_AT = \
64TESTSUITE = $(srcdir)/testsuite 66TESTSUITE = $(srcdir)/testsuite
65M4=m4 67M4=m4
66 68
67noinst_PROGRAMS = envtest to lines 69noinst_PROGRAMS = envtest to lines nt
70nt_SOURCES = nt.c iobuf.h
68AM_CPPFLAGS = \ 71AM_CPPFLAGS = \
69 -I$(top_srcdir)/lib\ 72 -I$(top_srcdir)/lib\
73 -I$(top_srcdir)/gnu\
74 -I$(top_builddir)/gnu\
70 @GRECS_INCLUDES@ 75 @GRECS_INCLUDES@
71 76
72LDADD = \ 77LDADD = \
diff --git a/tests/aux/in.test b/tests/aux/in.test
new file mode 100755
index 0000000..4a98763
--- a/dev/null
+++ b/tests/aux/in.test
@@ -0,0 +1,22 @@
1#! /bin/sh
2
3FILE=${1:?}
4 IFS='
5'
6while read COMMAND ARG
7do
8 echo $COMMAND $ARG >> $FILE
9 case $COMMAND in
10 stop) if [ -n "$STOPCMD" ]; then
11 echo "STOP"
12 $STOPCMD
13 else
14 echo "OK $COMMAND $ARG"
15 fi
16 ;;
17 quit) exit $ARG;;
18 *) echo "OK $COMMAND $ARG"
19 ;;
20 esac
21done
22
diff --git a/tests/inet.at b/tests/inet.at
new file mode 100644
index 0000000..41cae6a
--- a/dev/null
+++ b/tests/inet.at
@@ -0,0 +1,38 @@
1AT_SETUP([inet component])
2AT_CHECK([
3PIES_XFAIL_CHECK
4PIES_CONTROL_INIT
5AT_DATA([input],
6[line 1
7line 2
8stop
9])
10: ${PIES_TEST_INET_SOCKET:=unix://$PWD/in.sock}
11cat > pies.conf <<_EOT
12component in {
13 command "$auxdir/in.test $PWD/inlog";
14 env {
15 set "STOPCMD=piesctl --url unix:///$PWD/pies.ctl --no-netrc shutdown";
16 }
17 mode inetd;
18 socket "$PIES_TEST_INET_SOCKET";
19 stderr file "$PWD/log.err";
20}
21component controller {
22 command "nt $PIES_TEST_INET_SOCKET -i input";
23}
24_EOT
25set -e
26to 10 \
27 pies --foreground --stderr \
28 --config-file control.conf --config-file pies.conf --debug 1 2>errlog
29
30cat inlog
31cat log.err >&2
32],
33[0],
34[line 1
35line 2
36stop
37])
38AT_CLEANUP
diff --git a/tests/iobuf.h b/tests/iobuf.h
new file mode 100644
index 0000000..4e43338
--- a/dev/null
+++ b/tests/iobuf.h
@@ -0,0 +1,141 @@
1/* This file is part of GNU Pies.
2 Copyright (C) 2019 Sergey Poznyakoff
3
4 GNU Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
16
17#define IO_BUF_SIZE 512
18
19struct iobuf
20{
21 char buf[IO_BUF_SIZE]; /* Initial line buffer */
22 size_t start; /* Start of data */
23 size_t avail; /* Start of available space */
24};
25
26static inline void
27iobuf_reset (struct iobuf *bp)
28{
29 bp->start = bp->avail = 0;
30}
31
32/* Return the count of data bytes in the buffer */
33static inline size_t
34iobuf_data_size (struct iobuf *bp)
35{
36 return bp->avail - bp->start;
37}
38
39static inline char *
40iobuf_data_ptr (struct iobuf *bp)
41{
42 return bp->buf + bp->start;
43}
44
45static inline void
46iobuf_data_advance (struct iobuf *bp, size_t n)
47{
48 bp->start += n;
49 if (bp->start == bp->avail)
50 iobuf_reset (bp);
51}
52
53static inline int
54iobuf_putback (struct iobuf *bp)
55{
56 return bp->buf[--bp->start-1];
57}
58
59static inline int
60iobuf_getc (struct iobuf *bp)
61{
62 int c = -1;
63 if (iobuf_data_size (bp) > 0)
64 {
65 c = *iobuf_data_ptr (bp);
66 iobuf_data_advance(bp, 1);
67 }
68 return c;
69}
70
71/* Return the count of available bytes in the buffer */
72static inline size_t
73iobuf_avail_size (struct iobuf *bp)
74{
75 return sizeof (bp->buf) - bp->avail;
76}
77
78static inline char *
79iobuf_avail_ptr (struct iobuf *bp)
80{
81 return bp->buf + bp->avail;
82}
83
84static inline void
85iobuf_avail_advance (struct iobuf *bp, size_t n)
86{
87 bp->avail += n;
88 if (iobuf_avail_size (bp) == 0 && iobuf_data_size (bp) == 0)
89 iobuf_reset (bp);
90}
91
92static inline int
93iobuf_putc (struct iobuf *bp, int c)
94{
95 if (iobuf_avail_size (bp) > 0)
96 {
97 *iobuf_avail_ptr (bp) = c;
98 iobuf_avail_advance (bp, 1);
99 return c;
100 }
101 return -1;
102}
103
104static inline ssize_t
105iobuf_fill (struct iobuf *bp, int fd)
106{
107 ssize_t n = read (fd, iobuf_avail_ptr (bp), iobuf_avail_size (bp));
108 if (n >= 0)
109 iobuf_avail_advance (bp, n);
110 return n;
111}
112
113static inline ssize_t
114iobuf_flush (struct iobuf *bp, int fd)
115{
116 ssize_t n = write (fd, iobuf_data_ptr (bp), iobuf_data_size (bp));
117 if (n >= 0)
118 iobuf_data_advance (bp, n);
119 return n;
120}
121
122static inline ssize_t
123iobuf_copy (struct iobuf *dst, struct iobuf *src)
124{
125 ssize_t n = iobuf_data_size (src);
126 if (n > 0)
127 {
128 ssize_t avail = iobuf_avail_size (dst);
129 if (avail < n)
130 n = avail;
131 if (n)
132 {
133 memcpy (iobuf_avail_ptr (dst), iobuf_data_ptr (src), n);
134 iobuf_avail_advance (dst, n);
135 iobuf_data_advance (src, n);
136 }
137 }
138 return 0;
139}
140
141
diff --git a/tests/nt.c b/tests/nt.c
new file mode 100644
index 0000000..6ee18f8
--- a/dev/null
+++ b/tests/nt.c
@@ -0,0 +1,339 @@
1/* This file is part of GNU Pies.
2 Copyright (C) 2019 Sergey Poznyakoff
3
4 GNU Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
16
17#include <config.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <fcntl.h>
23#include <unistd.h>
24#include <poll.h>
25#include <errno.h>
26#include <libpies.h>
27#include <iobuf.h>
28
29typedef struct netcat_server netcat_server_t;
30typedef struct netcat_stream netcat_stream_t;
31typedef ssize_t (*netcat_stream_io_t) (netcat_server_t *srv);
32typedef int (*netcat_stream_disconnect_t) (netcat_server_t *srv);
33
34enum { IN, OUT };
35
36struct netcat_server
37{
38 char const *id;
39 netcat_server_t *next, *prev;
40 struct pollfd *pollfd;
41 int state;
42 netcat_stream_disconnect_t disconnect;
43 netcat_server_t *peer;
44 struct iobuf buf[2];
45};
46
47static netcat_server_t *server_head, *server_tail;
48
49netcat_server_t *
50netcat_server_create (char const *id, struct pollfd *pfd, int state,
51 netcat_stream_disconnect_t dis, netcat_server_t *peer)
52{
53 netcat_server_t *srv = grecs_zalloc (sizeof (*srv));
54 srv->id = id;
55 srv->pollfd = pfd;
56 srv->state = state;
57 srv->pollfd->events |= srv->state;
58 srv->disconnect = dis;
59 srv->peer = peer;
60 if (peer)
61 srv->peer->peer = srv;
62 iobuf_reset (&srv->buf[IN]);
63 iobuf_reset (&srv->buf[OUT]);
64
65 srv->prev = server_tail;
66 srv->next = NULL;
67 if (server_tail)
68 server_tail->next = srv;
69 else
70 server_head = srv;
71 server_tail = srv;
72
73 return srv;
74}
75
76void
77netcat_server_remove (netcat_server_t *srv)
78{
79 netcat_server_t *p;
80 if ((p = srv->next) != NULL)
81 p->prev = srv->prev;
82 else
83 server_tail = srv->prev;
84 if ((p = srv->prev) != NULL)
85 p->next = srv->next;
86 else
87 server_head = srv->next;
88 if (srv->peer)
89 srv->peer->peer = NULL;
90 free (srv);
91}
92
93/*
94net_reader
951. If there is free space in the IN buffer, fill it with the data read
96from the fd and return
972. Otherwise, clear the POLLIN bit.
98
99stdout_writer (peer -> net_reader)
1001. If OUT buffer is empty
101 1.1 If the peer's IN buffer is not empty, transfer data from it
102 1.2 Else raise the peers POLLIN bit and return.
1032. Write as much as possible from OUT to fd
104
105stdin_reader (same as net_reader)
106
107net_writer (peer -> stdin_reader) same as stdout_writer
108*/
109
110ssize_t
111netcat_stream_read (netcat_server_t *srv)
112{
113 ssize_t n;
114
115 if (iobuf_avail_size (&srv->buf[IN]))
116 {
117 n = iobuf_fill (&srv->buf[IN], srv->pollfd->fd);
118 if (n == -1)
119 {
120 grecs_error (NULL, errno, "%s: read", srv->id);
121 srv->pollfd->events &= ~POLLIN;
122 return -1;
123 }
124 if (n == 0)
125 {
126 /* No more input is expected */
127 srv->disconnect (srv);
128 srv->state &= ~POLLIN;
129 srv->pollfd->events &= ~POLLIN;
130 if (srv->pollfd->events == 0)
131 srv->pollfd->fd = -1;
132 }
133 }
134 else
135 {
136 srv->pollfd->events &= ~POLLIN;
137 n = 0; /* catch timeout? */
138 }
139 return n;
140}
141
142static inline int
143peer_is_state (netcat_server_t *srv, int state)
144{
145 return srv->peer && (srv->peer->state & state);
146}
147
148ssize_t
149netcat_stream_write (netcat_server_t *srv)
150{
151 ssize_t n;
152
153 if (iobuf_data_size (&srv->buf[OUT]) == 0)
154 {
155 if (!peer_is_state (srv, POLLIN))
156 {
157 // shutdown write end
158 srv->disconnect (srv);
159 srv->state &= ~POLLOUT;
160 srv->pollfd->events &= ~POLLOUT;
161 if (srv->pollfd->events == 0)
162 srv->pollfd->fd = -1;
163 return -1;
164 }
165 if (iobuf_copy (&srv->buf[OUT], &srv->peer->buf[IN]) == 0)
166 {
167 srv->peer->pollfd->events |= POLLIN;
168 return 0;
169 }
170 }
171 n = iobuf_flush (&srv->buf[OUT], srv->pollfd->fd);
172 if (n == -1)
173 {
174 grecs_error (NULL, errno, "%s: write", srv->id);
175 return -1;
176 }
177 if (n == 0)
178 {
179 // FIXME: eof
180 return -1;
181 }
182 return 0;
183}
184
185int
186disconnect_in (netcat_server_t *srv)
187{
188 return shutdown (srv->pollfd->fd, SHUT_RD);
189}
190
191int
192disconnect_out (netcat_server_t *srv)
193{
194 return shutdown (srv->pollfd->fd, SHUT_WR);
195}
196
197int
198disconnect_stdin (netcat_server_t *srv)
199{
200 return close (srv->pollfd->fd);
201}
202
203int
204disconnect_stdout (netcat_server_t *srv)
205{
206 close (srv->pollfd->fd);
207 exit (0);
208}
209
210static int
211netcat (char const *urlstr)
212{
213 int fd;
214 struct pies_url *url;
215 struct pollfd pfd[3];
216 int nfd = sizeof (pfd) / sizeof (pfd[0]);
217 netcat_server_t *srvin, *srvout, *srv;
218
219 if (pies_url_create (&url, urlstr))
220 {
221 perror (urlstr);
222 return 64;
223 }
224
225 fd = url_connect (url, NULL);
226 if (fd == -1)
227 return 1;
228
229 pfd[0].fd = 0;
230 pfd[0].events = 0;
231 srvin = netcat_server_create ("stdin", &pfd[0], POLLIN, disconnect_stdin, NULL);
232
233 pfd[1].fd = 1;
234 pfd[1].events = 0;
235 srvout = netcat_server_create ("stdout", &pfd[1], POLLOUT, disconnect_stdout, NULL);
236
237 pfd[2].fd = fd;
238 pfd[2].events = 0;
239
240 netcat_server_create ("netread", &pfd[2], POLLIN, disconnect_in, srvout);
241 netcat_server_create ("netwrite", &pfd[2], POLLOUT, disconnect_out, srvin);
242
243 while (server_head)
244 {
245 ssize_t n = poll (pfd, nfd, -1);
246 if (n == -1)
247 {
248 if (errno != EINTR)
249 grecs_error (NULL, errno, "poll");
250 continue;
251 }
252 for (srv = server_head; srv; )
253 {
254 netcat_server_t *next = srv->next;
255 int events;
256
257 events = (srv->pollfd->events|POLLHUP)
258 & (srv->pollfd->revents & (srv->state|POLLHUP));
259 if (events)
260 {
261 if (events & POLLHUP)
262 {
263 //grecs_error (NULL, 0, "HUP on %s", srv->id);
264 srv->disconnect (srv);
265 srv->pollfd->events &= ~srv->state;
266 if (srv->pollfd->events == 0)
267 srv->pollfd->fd = -1;
268 srv->state = 0;
269 }
270 else if (events & POLLIN)
271 netcat_stream_read (srv);
272 else if (events & POLLOUT)
273 netcat_stream_write (srv);
274 }
275 if (srv->state == 0 || srv->pollfd->fd == -1)
276 netcat_server_remove (srv);
277 srv = next;
278 }
279 }
280 return 0;
281}
282
283static void
284redirect (int sfd, char const *name)
285{
286 int fd;
287
288 fd = open (name, sfd ? (O_WRONLY | O_TRUNC) : O_RDONLY);
289 if (!fd)
290 {
291 perror (name);
292 exit (1);
293 }
294 if (dup2 (fd, sfd))
295 {
296 perror ("dup2");
297 exit (1);
298 }
299}
300
301static void
302usage (FILE *fp)
303{
304 fprintf (fp, "usage: nt [-i FILE] [-o FILE] URL\n");
305}
306
307int
308main (int argc, char **argv)
309{
310 int c;
311
312 while ((c = getopt (argc, argv, "i:o:")) != EOF)
313 {
314 switch (c)
315 {
316 case 'i':
317 redirect (0, optarg);
318 break;
319
320 case 'o':
321 redirect (1, optarg);
322 break;
323
324 default:
325 exit (64);
326 }
327 }
328
329 argc -= optind;
330 argv += optind;
331
332 if (argc != 1)
333 {
334 usage (stderr);
335 exit (64);
336 }
337
338 return netcat (argv[0]);
339}
diff --git a/tests/testsuite.at b/tests/testsuite.at
index e340a2b..822ac7b 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -68,6 +68,7 @@ m4_include([ret-notify.at])
68m4_include([startup.at]) 68m4_include([startup.at])
69m4_include([shutdown.at]) 69m4_include([shutdown.at])
70m4_include([shell.at]) 70m4_include([shell.at])
71m4_include([inet.at])
71 72
72m4_include([envop.at]) 73m4_include([envop.at])
73m4_include([env.at]) \ No newline at end of file 74m4_include([env.at]) \ No newline at end of file
diff --git a/tests/to.c b/tests/to.c
index 6511a54..6874bfd 100644
--- a/tests/to.c
+++ b/tests/to.c
@@ -1,9 +1,28 @@
1#include <config.h>
1#include <stdlib.h> 2#include <stdlib.h>
2#include <stdio.h> 3#include <stdio.h>
3#include <errno.h> 4#include <errno.h>
4#include <unistd.h> 5#include <unistd.h>
5#include <sys/types.h> 6#include <sys/types.h>
6#include <sys/wait.h> 7#include <sys/wait.h>
8#include <signal.h>
9
10int volatile got_sigchld, got_sigalrm;
11
12void
13sighan (int sig)
14{
15 switch (sig)
16 {
17 case SIGCHLD:
18 got_sigchld = 1;
19 break;
20
21 case SIGALRM:
22 got_sigalrm = 1;
23 break;
24 }
25}
7 26
8int 27int
9main (int argc, char **argv) 28main (int argc, char **argv)
@@ -13,7 +32,7 @@ main (int argc, char **argv)
13 char *p; 32 char *p;
14 pid_t pid, ret; 33 pid_t pid, ret;
15 int status; 34 int status;
16 35
17 if (argc < 3) 36 if (argc < 3)
18 { 37 {
19 fprintf (stderr, "usage: %s TIMEOUT COMMAND ...\n", progname); 38 fprintf (stderr, "usage: %s TIMEOUT COMMAND ...\n", progname);
@@ -30,13 +49,16 @@ main (int argc, char **argv)
30 argc -= 2; 49 argc -= 2;
31 argv += 2; 50 argv += 2;
32 51
52 signal (SIGALRM, sighan);
53 signal (SIGCHLD, sighan);
54
33 pid = fork (); 55 pid = fork ();
34 if (pid == -1) 56 if (pid == -1)
35 { 57 {
36 perror ("fork"); 58 perror ("fork");
37 exit (127); 59 exit (127);
38 } 60 }
39 61
40 if (pid == 0) 62 if (pid == 0)
41 { 63 {
42 execvp (argv[0], argv); 64 execvp (argv[0], argv);
@@ -45,8 +67,23 @@ main (int argc, char **argv)
45 } 67 }
46 68
47 alarm (n); 69 alarm (n);
70 while (1)
71 {
72 pause ();
73 if (got_sigchld)
74 {
75 alarm (0);
76 break;
77 }
78 if (got_sigalrm)
79 {
80 fprintf (stderr, "%s: timed out\n", progname);
81 kill (pid, SIGKILL);
82 exit (127);
83 }
84 }
85
48 ret = wait (&status); 86 ret = wait (&status);
49 alarm (0);
50 87
51 if (ret != pid) 88 if (ret != pid)
52 { 89 {
@@ -56,7 +93,7 @@ main (int argc, char **argv)
56 93
57 if (WIFEXITED (status)) 94 if (WIFEXITED (status))
58 return WEXITSTATUS (status); 95 return WEXITSTATUS (status);
59 96
60 if (WIFSIGNALED (status)) 97 if (WIFSIGNALED (status))
61 fprintf (stderr, "%s: %s terminated on signal %d\n", progname, argv[0], 98 fprintf (stderr, "%s: %s terminated on signal %d\n", progname, argv[0],
62 WTERMSIG (status)); 99 WTERMSIG (status));
@@ -67,8 +104,3 @@ main (int argc, char **argv)
67 progname, argv[0], status); 104 progname, argv[0], status);
68 return 127; 105 return 127;
69} 106}
70
71
72
73
74

Return to:

Send suggestions and report system problems to the System administrator.