don't free(page_rand) when we don't have a sockaddr generator.
[trinity.git] / sockets.c
blob2ca404e3bbefa096552eb42b0253ceda422f3b4d
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 "constants.h"
12 #include "log.h"
13 #include "net.h"
14 #include "maps.h"
15 #include "params.h" // verbose, do_specific_proto
16 #include "protocols.h"
17 #include "random.h"
18 #include "shm.h"
19 #include "trinity.h"
20 #include "utils.h"
22 unsigned int nr_sockets = 0;
24 static const char *cachefilename="trinity.socketcache";
26 #define MAX_PER_DOMAIN 5
27 #define MAX_TRIES_PER_DOMAIN 10
29 static int open_socket(unsigned int domain, unsigned int type, unsigned int protocol)
31 int fd;
32 __unused__ int ret;
33 struct sockaddr *sa = NULL;
34 socklen_t salen;
35 struct sockopt so = { 0, 0, 0, 0 };
37 fd = socket(domain, type, protocol);
38 if (fd == -1)
39 return fd;
41 shm->sockets[nr_sockets].fd = fd;
42 shm->sockets[nr_sockets].triplet.family = domain;
43 shm->sockets[nr_sockets].triplet.type = type;
44 shm->sockets[nr_sockets].triplet.protocol = protocol;
46 output(2, "fd[%i] = domain:%i (%s) type:0x%x protocol:%i\n",
47 fd, domain, get_proto_name(domain), type, protocol);
49 /* Set some random socket options. */
50 sso_socket(&shm->sockets[nr_sockets].triplet, &so, fd);
52 nr_sockets++;
54 /* Sometimes, listen on created sockets. */
55 if (rand_bool()) {
56 /* fake a sockaddr. */
57 generate_sockaddr((struct sockaddr **) &sa, (socklen_t *) &salen, domain);
59 ret = bind(fd, sa, salen);
60 /* if (ret == -1)
61 debugf("bind: %s\n", strerror(errno));
62 else
63 debugf("bind: success!\n");
65 ret = listen(fd, (rand() % 2) + 1);
66 /* if (ret == -1)
67 debugf("listen: %s\n", strerror(errno));
68 else
69 debugf("listen: success!\n");
73 /* If we didn't have a function for this sockaddr type, we would
74 * have returned page_rand, so don't free() it or we segv. */
75 if (sa == (struct sockaddr *) page_rand)
76 return fd;
78 if (sa != NULL)
79 free(sa);
81 return fd;
84 static void lock_cachefile(int cachefile, int type)
86 struct flock fl = {
87 .l_len = 0,
88 .l_start = 0,
89 .l_whence = SEEK_SET,
92 fl.l_pid = getpid();
93 fl.l_type = type;
95 if (verbose)
96 output(2, "waiting on lock for cachefile\n");
98 if (fcntl(cachefile, F_SETLKW, &fl) == -1) {
99 perror("fcntl F_SETLKW");
100 exit(1);
103 if (verbose)
104 output(2, "took lock for cachefile\n");
107 static void unlock_cachefile(int cachefile)
109 struct flock fl = {
110 .l_len = 0,
111 .l_start = 0,
112 .l_whence = SEEK_SET,
115 fl.l_pid = getpid();
116 fl.l_type = F_UNLCK;
118 if (fcntl(cachefile, F_SETLK, &fl) == -1) {
119 perror("fcntl F_UNLCK F_SETLK ");
120 exit(1);
123 if (verbose)
124 output(2, "dropped lock for cachefile\n");
127 static void generate_sockets(void)
129 int fd, n;
130 int cachefile;
131 unsigned int nr_to_create = NR_SOCKET_FDS;
132 unsigned int buffer[3];
134 cachefile = creat(cachefilename, S_IWUSR|S_IRUSR);
135 if (cachefile < 0) {
136 outputerr("Couldn't open cachefile for writing! (%s)\n",
137 strerror(errno));
138 exit(EXIT_FAILURE);
141 lock_cachefile(cachefile, F_WRLCK);
144 * Don't loop forever if all protos all are disabled.
146 if (!do_specific_proto) {
147 for (n = 0; n < (int)ARRAY_SIZE(no_protos); n++) {
148 if (!no_protos[n])
149 break;
152 if (n >= (int)ARRAY_SIZE(no_protos))
153 nr_to_create = 0;
156 while (nr_to_create > 0) {
158 struct socket_triplet st;
160 if (shm->exit_reason != STILL_RUNNING) {
161 close(cachefile);
162 return;
165 for (st.family = 0; st.family < TRINITY_PF_MAX; st.family++) {
167 if (do_specific_proto == TRUE)
168 st.family = specific_proto;
170 if (get_proto_name(st.family) == NULL)
171 goto skip;
173 BUG_ON(st.family >= ARRAY_SIZE(no_protos));
174 if (no_protos[st.family])
175 goto skip;
177 if (sanitise_socket_triplet(&st) == -1)
178 rand_proto_type(&st);
180 fd = open_socket(st.family, st.type, st.protocol);
181 if (fd > -1) {
182 nr_to_create--;
184 buffer[0] = st.family;
185 buffer[1] = st.type;
186 buffer[2] = st.protocol;
187 n = write(cachefile, &buffer, sizeof(int) * 3);
188 if (n == -1) {
189 outputerr("something went wrong writing the cachefile!\n");
190 exit(EXIT_FAILURE);
193 if (nr_to_create == 0)
194 goto done;
195 } else {
196 //outputerr("Couldn't open family:%d (%s)\n", st.family, get_proto_name(st.family));
198 skip:
200 /* check for ctrl-c */
201 if (shm->exit_reason != STILL_RUNNING)
202 return;
204 //FIXME: If we've passed -P and we're spinning here without making progress
205 // then we should abort after a few hundred loops.
209 done:
210 unlock_cachefile(cachefile);
212 output(1, "created %d sockets\n", nr_sockets);
214 close(cachefile);
218 void close_sockets(void)
220 unsigned int i;
221 int fd;
222 int r = 0;
223 struct linger ling = { .l_onoff = FALSE, .l_linger = 0 };
225 for (i = 0; i < nr_sockets; i++) {
227 //FIXME: This is a workaround for a weird bug where we hang forevre
228 // waiting for bluetooth sockets when we setsockopt.
229 // Hopefully at some point we can remove this when someone figures out what's going on.
230 if (shm->sockets[i].triplet.family == PF_BLUETOOTH)
231 continue;
233 /* Grab an fd, and nuke it before someone else uses it. */
234 fd = shm->sockets[i].fd;
235 shm->sockets[i].fd = 0;
237 /* disable linger */
238 r = setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger));
239 if (r)
240 perror("setsockopt");
242 r = shutdown(fd, SHUT_RDWR);
243 if (r)
244 perror("shutdown");
246 if (close(fd) != 0)
247 output(1, "failed to close socket [%d:%d:%d].(%s)\n",
248 shm->sockets[i].triplet.family,
249 shm->sockets[i].triplet.type,
250 shm->sockets[i].triplet.protocol,
251 strerror(errno));
254 nr_sockets = 0;
257 void open_sockets(void)
259 int cachefile;
260 unsigned int domain, type, protocol;
261 unsigned int buffer[3];
262 int bytesread=-1;
263 int fd;
265 cachefile = open(cachefilename, O_RDONLY);
266 if (cachefile < 0) {
267 output(1, "Couldn't find socket cachefile. Regenerating.\n");
268 generate_sockets();
269 return;
272 lock_cachefile(cachefile, F_RDLCK);
274 while (bytesread != 0) {
275 bytesread = read(cachefile, buffer, sizeof(int) * 3);
276 if (bytesread == 0)
277 break;
279 domain = buffer[0];
280 type = buffer[1];
281 protocol = buffer[2];
283 if ((do_specific_proto == TRUE && domain != specific_proto) ||
284 (domain < ARRAY_SIZE(no_protos) && no_protos[domain] == TRUE)) {
285 output(1, "ignoring socket cachefile due to specific "
286 "protocol request (or protocol disabled), "
287 "and stale data in cachefile.\n");
288 regenerate:
289 unlock_cachefile(cachefile); /* drop the reader lock. */
290 close(cachefile);
291 unlink(cachefilename);
292 generate_sockets();
293 return;
296 fd = open_socket(domain, type, protocol);
297 if (fd < 0) {
298 output(1, "Cachefile is stale. Need to regenerate.\n");
299 close_sockets();
300 goto regenerate;
303 /* check for ctrl-c */
304 if (shm->exit_reason != STILL_RUNNING) {
305 close(cachefile);
306 return;
310 if (nr_sockets < NR_SOCKET_FDS) {
311 output(1, "Insufficient sockets in cachefile (%d). Regenerating.\n", nr_sockets);
312 goto regenerate;
315 output(1, "%d sockets created based on info from socket cachefile.\n", nr_sockets);
317 unlock_cachefile(cachefile);
318 close(cachefile);