factor out the stuck syscall info to own function
[trinity.git] / sockets.c
blobc2037c94879127c4b9ac8ecd8e85e0bd3f9b2a8f
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/stat.h>
11 #include "trinity.h"
12 #include "constants.h"
13 #include "shm.h"
14 #include "net.h"
15 #include "log.h"
16 #include "params.h" // victim_path, verbose, do_specific_proto
17 #include "random.h"
19 unsigned int nr_sockets = 0;
21 static const char *cachefilename="trinity.socketcache";
23 #define MAX_PER_DOMAIN 5
24 #define MAX_TRIES_PER_DOMAIN 10
26 static int open_socket(unsigned int domain, unsigned int type, unsigned int protocol)
28 int fd;
29 struct sockaddr sa;
30 socklen_t salen;
32 fd = socket(domain, type, protocol);
33 if (fd == -1)
34 return fd;
36 shm->socket_fds[nr_sockets] = fd;
38 output(2, "fd[%i] = domain:%i (%s) type:0x%x protocol:%i\n",
39 fd, domain, get_proto_name(domain), type, protocol);
41 nr_sockets++;
43 /* Sometimes, listen on created sockets. */
44 if (rand_bool()) {
45 __unused__ int ret;
47 /* fake a sockaddr. */
48 generate_sockaddr((unsigned long *) &sa, (unsigned long *) &salen, domain);
50 ret = bind(fd, &sa, salen);
51 /* if (ret == -1)
52 printf("bind: %s\n", strerror(errno));
53 else
54 printf("bind: success!\n");
56 ret = listen(fd, (rand() % 2) + 1);
57 /* if (ret == -1)
58 printf("listen: %s\n", strerror(errno));
59 else
60 printf("listen: success!\n");
64 return fd;
67 static void lock_cachefile(int cachefile, int type)
69 struct flock fl = {
70 .l_len = 0,
71 .l_start = 0,
72 .l_whence = SEEK_SET,
75 fl.l_pid = getpid();
76 fl.l_type = type;
78 if (verbose)
79 output(2, "waiting on lock for cachefile\n");
81 if (fcntl(cachefile, F_SETLKW, &fl) == -1) {
82 perror("fcntl F_SETLKW");
83 exit(1);
86 if (verbose)
87 output(2, "took lock for cachefile\n");
90 static void unlock_cachefile(int cachefile)
92 struct flock fl = {
93 .l_len = 0,
94 .l_start = 0,
95 .l_whence = SEEK_SET,
98 fl.l_pid = getpid();
99 fl.l_type = F_UNLCK;
101 if (fcntl(cachefile, F_SETLK, &fl) == -1) {
102 perror("fcntl F_UNLCK F_SETLK ");
103 exit(1);
106 if (verbose)
107 output(2, "dropped lock for cachefile\n");
110 static void generate_sockets(void)
112 int fd, n;
113 int cachefile;
114 unsigned int nr_to_create = NR_SOCKET_FDS;
115 unsigned int buffer[3];
117 cachefile = creat(cachefilename, S_IWUSR|S_IRUSR);
118 if (cachefile < 0) {
119 printf("Couldn't open cachefile for writing! (%s)\n",
120 strerror(errno));
121 exit(EXIT_FAILURE);
124 lock_cachefile(cachefile, F_WRLCK);
126 while (nr_to_create > 0) {
128 struct socket_triplet st;
130 if (shm->exit_reason != STILL_RUNNING) {
131 close(cachefile);
132 return;
135 for (st.family = 0; st.family < TRINITY_PF_MAX; st.family++) {
137 if (do_specific_proto == TRUE)
138 st.family = specific_proto;
140 if (get_proto_name(st.family) == NULL)
141 goto skip;
143 if (sanitise_socket_triplet(&st) == -1)
144 rand_proto_type(&st);
146 fd = open_socket(st.family, st.type, st.protocol);
147 if (fd > -1) {
148 nr_to_create--;
150 buffer[0] = st.family;
151 buffer[1] = st.type;
152 buffer[2] = st.protocol;
153 n = write(cachefile, &buffer, sizeof(int) * 3);
154 if (n == -1) {
155 printf("something went wrong writing the cachefile!\n");
156 exit(EXIT_FAILURE);
159 if (nr_to_create == 0)
160 goto done;
161 } else {
162 //printf("Couldn't open family:%d (%s)\n", st.family, get_proto_name(st.family));
164 skip:
166 /* check for ctrl-c */
167 if (shm->exit_reason != STILL_RUNNING)
168 return;
170 //FIXME: If we've passed -P and we're spinning here without making progress
171 // then we should abort after a few hundred loops.
175 done:
176 unlock_cachefile(cachefile);
178 output(1, "created %d sockets\n", nr_sockets);
180 close(cachefile);
184 static void close_sockets(void)
186 unsigned int i;
187 int fd;
189 for (i = 0; i < nr_sockets; i++) {
190 fd = shm->socket_fds[i];
191 shm->socket_fds[i] = 0;
192 if (close(fd) != 0) {
193 printf("failed to close socket.(%s)\n", strerror(errno));
197 nr_sockets = 0;
200 void open_sockets(void)
202 int cachefile;
203 unsigned int domain, type, protocol;
204 unsigned int buffer[3];
205 int bytesread=-1;
206 int fd;
208 /* If we have victim files, don't worry about sockets. */
209 if (victim_path != NULL)
210 return;
212 cachefile = open(cachefilename, O_RDONLY);
213 if (cachefile < 0) {
214 printf("Couldn't find socket cachefile. Regenerating.\n");
215 generate_sockets();
216 return;
219 lock_cachefile(cachefile, F_RDLCK);
221 while (bytesread != 0) {
222 bytesread = read(cachefile, buffer, sizeof(int) * 3);
223 if (bytesread == 0)
224 break;
226 domain = buffer[0];
227 type = buffer[1];
228 protocol = buffer[2];
230 if (do_specific_proto == TRUE) {
231 if (domain != specific_proto) {
232 printf("ignoring socket cachefile due to specific protocol request, and stale data in cachefile.\n");
233 regenerate:
234 unlock_cachefile(cachefile); /* drop the reader lock. */
235 close(cachefile);
236 unlink(cachefilename);
237 generate_sockets();
238 return;
242 fd = open_socket(domain, type, protocol);
243 if (fd < 0) {
244 printf("Cachefile is stale. Need to regenerate.\n");
245 close_sockets();
246 goto regenerate;
249 /* check for ctrl-c */
250 if (shm->exit_reason != STILL_RUNNING) {
251 close(cachefile);
252 return;
256 if (nr_sockets < NR_SOCKET_FDS) {
257 printf("Insufficient sockets in cachefile (%d). Regenerating.\n", nr_sockets);
258 goto regenerate;
261 output(1, "%d sockets created based on info from socket cachefile.\n", nr_sockets);
263 unlock_cachefile(cachefile);
264 close(cachefile);