Bump version to 1.2.5
[socket_wrapper.git] / tests / torture.c
1 /*
2  * Copyright (C) Andreas Schneider 2013 <asn@samba.org>
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the author nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "config.h"
35
36 #include "torture.h"
37
38 #include <errno.h>
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/socket.h>
43 #include <signal.h>
44 #include <fcntl.h>
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <time.h>
51 #include <stdbool.h>
52
53 #define TORTURE_ECHO_SRV_IPV4 "127.0.0.10"
54 /* socket wrapper IPv6 prefix  fd00::5357:5fxx */
55 #define TORTURE_ECHO_SRV_IPV6 "fd00::5357:5f0a"
56 #define TORTURE_ECHO_SRV_PORT 7
57
58 #define TORTURE_SOCKET_DIR "/tmp/w_XXXXXX"
59 #define TORTURE_ECHO_SRV_PIDFILE "echo_srv.pid"
60 #define TORTURE_PCAP_FILE "socket_trace.pcap"
61
62 const char *torture_server_address(int family)
63 {
64         switch (family) {
65         case AF_INET: {
66                 const char *ip4 = getenv("TORTURE_SERVER_ADDRESS_IPV4");
67
68                 if (ip4 != NULL && ip4[0] != '\0') {
69                         return ip4;
70                 }
71
72                 return TORTURE_ECHO_SRV_IPV4;
73         }
74 #ifdef HAVE_IPV6
75         case AF_INET6: {
76                 const char *ip6 = getenv("TORTURE_SERVER_ADDRESS_IPV6");
77
78                 if (ip6 != NULL && ip6[0] != '\0') {
79                         return ip6;
80                 }
81
82                 return TORTURE_ECHO_SRV_IPV6;
83         }
84 #endif
85         default:
86                 return NULL;
87         }
88
89         return NULL;
90 }
91
92 int torture_server_port(void)
93 {
94         char *env = getenv("TORTURE_SERVER_PORT");
95
96         if (env != NULL && env[0] != '\0' && strlen(env) < 6) {
97                 int port = atoi(env);
98
99                 if (port > 0 && port < 65536) {
100                         return port;
101                 }
102         }
103
104         return TORTURE_ECHO_SRV_PORT;
105 }
106
107 void torture_setup_socket_dir(void **state)
108 {
109         struct torture_state *s;
110         const char *p;
111         size_t len;
112
113         s = malloc(sizeof(struct torture_state));
114         assert_non_null(s);
115
116         s->socket_dir = strdup(TORTURE_SOCKET_DIR);
117         assert_non_null(s->socket_dir);
118
119         p = mkdtemp(s->socket_dir);
120         assert_non_null(p);
121
122         /* pcap file */
123         len = strlen(p) + 1 + strlen(TORTURE_PCAP_FILE) + 1;
124
125         s->pcap_file = malloc(len);
126         assert_non_null(s->pcap_file);
127
128         snprintf(s->pcap_file, len, "%s/%s", p, TORTURE_PCAP_FILE);
129
130         /* pid file */
131         len = strlen(p) + 1 + strlen(TORTURE_ECHO_SRV_PIDFILE) + 1;
132
133         s->srv_pidfile = malloc(len);
134         assert_non_null(s->srv_pidfile);
135
136         snprintf(s->srv_pidfile, len, "%s/%s", p, TORTURE_ECHO_SRV_PIDFILE);
137
138         setenv("SOCKET_WRAPPER_DIR", p, 1);
139         setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1);
140         setenv("SOCKET_WRAPPER_PCAP_FILE", s->pcap_file, 1);
141
142         *state = s;
143 }
144
145 static void torture_setup_echo_srv_ip(void **state,
146                                       const char *ip,
147                                       int port,
148                                       int type)
149 {
150         struct torture_state *s;
151         char start_echo_srv[1024] = {0};
152         const char *t;
153         int count = 0;
154         int rc;
155
156         torture_setup_socket_dir(state);
157
158         s = *state;
159
160         switch (type) {
161         case SOCK_STREAM:
162                 t = "-t";
163                 break;
164         case SOCK_DGRAM:
165                 t = "-u";
166                 break;
167         default:
168                 t = "";
169                 break;
170         }
171
172         /* set default iface for the server */
173         setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
174
175         snprintf(start_echo_srv, sizeof(start_echo_srv),
176                  "%s/tests/echo_srv -b %s -p %d -D %s --pid %s",
177                  BINARYDIR, ip, port, t, s->srv_pidfile);
178
179         rc = system(start_echo_srv);
180         assert_int_equal(rc, 0);
181
182         do {
183                 struct stat sb;
184
185                 count++;
186                 if (count > 20) {
187                         break;
188                 }
189
190                 rc = stat(s->srv_pidfile, &sb);
191                 usleep(50000L); /* 0.05s * 20 */
192         } while (rc != 0);
193         assert_int_equal(rc, 0);
194
195         /* set default iface for the client */
196         setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1);
197 }
198
199 void torture_setup_echo_srv_udp_ipv4(void **state)
200 {
201         torture_setup_echo_srv_ip(state,
202                                   "0.0.0.0",
203                                   torture_server_port(),
204                                   SOCK_DGRAM);
205 }
206
207 void torture_setup_echo_srv_udp_ipv6(void **state)
208 {
209         torture_setup_echo_srv_ip(state,
210                                   "::",
211                                   torture_server_port(),
212                                   SOCK_DGRAM);
213 }
214
215 void torture_setup_echo_srv_tcp_ipv4(void **state)
216 {
217         torture_setup_echo_srv_ip(state,
218                                   "0.0.0.0",
219                                   torture_server_port(),
220                                   SOCK_STREAM);
221 }
222
223 void torture_setup_echo_srv_tcp_ipv6(void **state)
224 {
225         torture_setup_echo_srv_ip(state,
226                                   "::",
227                                   torture_server_port(),
228                                   SOCK_STREAM);
229 }
230
231 void torture_teardown_socket_dir(void **state)
232 {
233         struct torture_state *s = *state;
234         char *env = getenv("TORTURE_SKIP_CLEANUP");
235         char remove_cmd[1024] = {0};
236         int rc;
237
238         if (env != NULL && env[0] == '1') {
239                 fprintf(stderr, ">>> Skipping cleanup of %s", s->socket_dir);
240         } else {
241                 snprintf(remove_cmd, sizeof(remove_cmd), "rm -rf %s", s->socket_dir);
242
243                 rc = system(remove_cmd);
244                 if (rc < 0) {
245                         fprintf(stderr, "%s failed: %s", remove_cmd, strerror(errno));
246                 }
247         }
248
249         free(s->socket_dir);
250         free(s->pcap_file);
251         free(s->srv_pidfile);
252         free(s);
253 }
254
255 void torture_teardown_echo_srv(void **state)
256 {
257         struct torture_state *s = *state;
258         char buf[12] = {0}; /* -2147483648 + null byte */
259         ssize_t rc;
260         pid_t pid;
261         int fd;
262         bool is_running = true;
263         int count;
264
265         /* read the pidfile */
266         fd = open(s->srv_pidfile, O_RDONLY);
267         if (fd < 0) {
268                 goto done;
269         }
270
271         rc = read(fd, buf, sizeof(buf));
272         close(fd);
273         if (rc <= 0) {
274                 goto done;
275         }
276
277         buf[sizeof(buf) - 1] = '\0';
278
279         errno = 0;
280         pid = strtol(buf, NULL, 10);
281         if (pid == 0 || errno != 0) {
282                 goto done;
283         }
284
285         for (count = 0; count < 10; count++) {
286                 /* Make sure the daemon goes away! */
287                 kill(pid, SIGTERM);
288
289                 usleep(5000);
290
291                 rc = kill(pid, 0);
292                 if (rc != 0) {
293                         is_running = false;
294                         break;
295                 }
296         }
297
298         if (is_running) {
299                 fprintf(stderr,
300                         "WARNING the echo server is still running!\n");
301         }
302
303 done:
304         torture_teardown_socket_dir(state);
305 }
306
307 void torture_generate_random_buffer(uint8_t *out, int len)
308 {
309         int i;
310
311         srand(time(NULL));
312
313         for (i = 0; i < len; i++) {
314                 out[i] = (uint8_t)rand();
315         }
316 }