make munmap aware of the mapping lists
[trinity.git] / sockets.c
blob30e36099bec7d9ca009a296dc5ce3de5e37fbdd6
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 "params.h" // verbose, do_specific_proto
15 #include "protocols.h"
16 #include "random.h"
17 #include "shm.h"
18 #include "trinity.h"
19 #include "utils.h"
21 unsigned int nr_sockets = 0;
23 static const char *cachefilename="trinity.socketcache";
25 #define MAX_PER_DOMAIN 5
26 #define MAX_TRIES_PER_DOMAIN 10
28 static int open_socket(unsigned int domain, unsigned int type, unsigned int protocol)
30 int fd;
31 __unused__ int ret;
32 struct sockaddr *sa = NULL;
33 socklen_t salen;
34 struct sockopt so = { 0, 0, 0, 0 };
36 fd = socket(domain, type, protocol);
37 if (fd == -1)
38 return fd;
40 shm->sockets[nr_sockets].fd = fd;
41 shm->sockets[nr_sockets].triplet.family = domain;
42 shm->sockets[nr_sockets].triplet.type = type;
43 shm->sockets[nr_sockets].triplet.protocol = protocol;
45 output(2, "fd[%i] = domain:%i (%s) type:0x%x protocol:%i\n",
46 fd, domain, get_proto_name(domain), type, protocol);
48 nr_sockets++;
50 /* Set some random socket options. */
51 sso_socket(&shm->sockets[nr_sockets].triplet, &so, fd);
53 /* Sometimes, listen on created sockets. */
54 if (rand_bool()) {
55 /* fake a sockaddr. */
56 generate_sockaddr((unsigned long **) &sa, (unsigned long *) &salen, domain);
58 ret = bind(fd, sa, salen);
59 /* if (ret == -1)
60 debugf("bind: %s\n", strerror(errno));
61 else
62 debugf("bind: success!\n");
64 ret = listen(fd, (rand() % 2) + 1);
65 /* if (ret == -1)
66 debugf("listen: %s\n", strerror(errno));
67 else
68 debugf("listen: success!\n");
71 if (sa != NULL)
72 free(sa);
74 return fd;
77 static void lock_cachefile(int cachefile, int type)
79 struct flock fl = {
80 .l_len = 0,
81 .l_start = 0,
82 .l_whence = SEEK_SET,
85 fl.l_pid = getpid();
86 fl.l_type = type;
88 if (verbose)
89 output(2, "waiting on lock for cachefile\n");
91 if (fcntl(cachefile, F_SETLKW, &fl) == -1) {
92 perror("fcntl F_SETLKW");
93 exit(1);
96 if (verbose)
97 output(2, "took lock for cachefile\n");
100 static void unlock_cachefile(int cachefile)
102 struct flock fl = {
103 .l_len = 0,
104 .l_start = 0,
105 .l_whence = SEEK_SET,
108 fl.l_pid = getpid();
109 fl.l_type = F_UNLCK;
111 if (fcntl(cachefile, F_SETLK, &fl) == -1) {
112 perror("fcntl F_UNLCK F_SETLK ");
113 exit(1);
116 if (verbose)
117 output(2, "dropped lock for cachefile\n");
120 static void generate_sockets(void)
122 int fd, n;
123 int cachefile;
124 unsigned int nr_to_create = NR_SOCKET_FDS;
125 unsigned int buffer[3];
127 cachefile = creat(cachefilename, S_IWUSR|S_IRUSR);
128 if (cachefile < 0) {
129 outputerr("Couldn't open cachefile for writing! (%s)\n",
130 strerror(errno));
131 exit(EXIT_FAILURE);
134 lock_cachefile(cachefile, F_WRLCK);
137 * Don't loop forever if all protos all are disabled.
139 if (!do_specific_proto) {
140 for (n = 0; n < (int)ARRAY_SIZE(no_protos); n++) {
141 if (!no_protos[n])
142 break;
145 if (n >= (int)ARRAY_SIZE(no_protos))
146 nr_to_create = 0;
149 while (nr_to_create > 0) {
151 struct socket_triplet st;
153 if (shm->exit_reason != STILL_RUNNING) {
154 close(cachefile);
155 return;
158 for (st.family = 0; st.family < TRINITY_PF_MAX; st.family++) {
160 if (do_specific_proto == TRUE)
161 st.family = specific_proto;
163 if (get_proto_name(st.family) == NULL)
164 goto skip;
166 BUG_ON(st.family >= ARRAY_SIZE(no_protos));
167 if (no_protos[st.family])
168 goto skip;
170 if (sanitise_socket_triplet(&st) == -1)
171 rand_proto_type(&st);
173 fd = open_socket(st.family, st.type, st.protocol);
174 if (fd > -1) {
175 nr_to_create--;
177 buffer[0] = st.family;
178 buffer[1] = st.type;
179 buffer[2] = st.protocol;
180 n = write(cachefile, &buffer, sizeof(int) * 3);
181 if (n == -1) {
182 outputerr("something went wrong writing the cachefile!\n");
183 exit(EXIT_FAILURE);
186 if (nr_to_create == 0)
187 goto done;
188 } else {
189 //outputerr("Couldn't open family:%d (%s)\n", st.family, get_proto_name(st.family));
191 skip:
193 /* check for ctrl-c */
194 if (shm->exit_reason != STILL_RUNNING)
195 return;
197 //FIXME: If we've passed -P and we're spinning here without making progress
198 // then we should abort after a few hundred loops.
202 done:
203 unlock_cachefile(cachefile);
205 output(1, "created %d sockets\n", nr_sockets);
207 close(cachefile);
211 void close_sockets(void)
213 unsigned int i;
214 int fd;
215 int r = 0;
216 struct linger ling = { .l_onoff = FALSE, };
218 for (i = 0; i < nr_sockets; i++) {
220 //FIXME: This is a workaround for a weird bug where we hang forevre
221 // waiting for bluetooth sockets when we setsockopt.
222 // Hopefully at some point we can remove this when someone figures out what's going on.
223 if (shm->sockets[i].triplet.family == PF_BLUETOOTH)
224 continue;
226 /* Grab an fd, and nuke it before someone else uses it. */
227 fd = shm->sockets[i].fd;
228 shm->sockets[i].fd = 0;
230 /* disable linger */
231 r = setsockopt(fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger));
232 if (r)
233 perror("setsockopt");
235 r = shutdown(fd, SHUT_RDWR);
236 if (r)
237 perror("shutdown");
239 if (close(fd) != 0)
240 output(1, "failed to close socket [%d:%d:%d].(%s)\n",
241 shm->sockets[i].triplet.family,
242 shm->sockets[i].triplet.type,
243 shm->sockets[i].triplet.protocol,
244 strerror(errno));
247 nr_sockets = 0;
250 void open_sockets(void)
252 int cachefile;
253 unsigned int domain, type, protocol;
254 unsigned int buffer[3];
255 int bytesread=-1;
256 int fd;
258 cachefile = open(cachefilename, O_RDONLY);
259 if (cachefile < 0) {
260 output(1, "Couldn't find socket cachefile. Regenerating.\n");
261 generate_sockets();
262 return;
265 lock_cachefile(cachefile, F_RDLCK);
267 while (bytesread != 0) {
268 bytesread = read(cachefile, buffer, sizeof(int) * 3);
269 if (bytesread == 0)
270 break;
272 domain = buffer[0];
273 type = buffer[1];
274 protocol = buffer[2];
276 if ((do_specific_proto == TRUE && domain != specific_proto) ||
277 (domain < ARRAY_SIZE(no_protos) && no_protos[domain] == TRUE)) {
278 output(1, "ignoring socket cachefile due to specific "
279 "protocol request (or protocol disabled), "
280 "and stale data in cachefile.\n");
281 regenerate:
282 unlock_cachefile(cachefile); /* drop the reader lock. */
283 close(cachefile);
284 unlink(cachefilename);
285 generate_sockets();
286 return;
289 fd = open_socket(domain, type, protocol);
290 if (fd < 0) {
291 output(1, "Cachefile is stale. Need to regenerate.\n");
292 close_sockets();
293 goto regenerate;
296 /* check for ctrl-c */
297 if (shm->exit_reason != STILL_RUNNING) {
298 close(cachefile);
299 return;
303 if (nr_sockets < NR_SOCKET_FDS) {
304 output(1, "Insufficient sockets in cachefile (%d). Regenerating.\n", nr_sockets);
305 goto regenerate;
308 output(1, "%d sockets created based on info from socket cachefile.\n", nr_sockets);
310 unlock_cachefile(cachefile);
311 close(cachefile);