8 #include <sys/socket.h>
11 #include "constants.h"
15 #include "params.h" // verbose, do_specific_proto
16 #include "protocols.h"
23 unsigned int nr_sockets
= 0;
25 static const char *cachefilename
="trinity.socketcache";
27 #define MAX_PER_DOMAIN 5
28 #define MAX_TRIES_PER_DOMAIN 10
30 static int open_socket(unsigned int domain
, unsigned int type
, unsigned int protocol
)
34 struct sockaddr
*sa
= NULL
;
36 struct sockopt so
= { 0, 0, 0, 0 };
38 fd
= socket(domain
, type
, protocol
);
42 shm
->sockets
[nr_sockets
].fd
= fd
;
43 shm
->sockets
[nr_sockets
].triplet
.family
= domain
;
44 shm
->sockets
[nr_sockets
].triplet
.type
= type
;
45 shm
->sockets
[nr_sockets
].triplet
.protocol
= protocol
;
47 output(2, "fd[%i] = domain:%i (%s) type:0x%x protocol:%i\n",
48 fd
, domain
, get_proto_name(domain
), type
, protocol
);
50 /* Set some random socket options. */
51 sso_socket(&shm
->sockets
[nr_sockets
].triplet
, &so
, fd
);
55 /* Sometimes, listen on created sockets. */
57 /* fake a sockaddr. */
58 generate_sockaddr((struct sockaddr
**) &sa
, (socklen_t
*) &salen
, domain
);
60 ret
= bind(fd
, sa
, salen
);
62 debugf("bind: %s\n", strerror(errno));
64 debugf("bind: success!\n");
66 ret
= listen(fd
, (rand() % 2) + 1);
68 debugf("listen: %s\n", strerror(errno));
70 debugf("listen: success!\n");
74 /* If we didn't have a function for this sockaddr type, we would
75 * have returned page_rand, so don't free() it or we segv. */
76 if (sa
== (struct sockaddr
*) page_rand
)
85 static void lock_cachefile(int cachefile
, int type
)
97 output(2, "waiting on lock for cachefile\n");
99 if (fcntl(cachefile
, F_SETLKW
, &fl
) == -1) {
100 perror("fcntl F_SETLKW");
105 output(2, "took lock for cachefile\n");
108 static void unlock_cachefile(int cachefile
)
113 .l_whence
= SEEK_SET
,
119 if (fcntl(cachefile
, F_SETLK
, &fl
) == -1) {
120 perror("fcntl F_UNLCK F_SETLK ");
125 output(2, "dropped lock for cachefile\n");
128 static unsigned int valid_proto(unsigned int family
)
132 famstr
= get_proto_name(family
);
134 /* Not used for creating sockets. */
135 if (strncmp(famstr
, "PF_UNSPEC", 9) == 0)
137 if (strncmp(famstr
, "PF_BRIDGE", 9) == 0)
139 if (strncmp(famstr
, "PF_SECURITY", 11) == 0)
142 /* Not actually implemented (or now removed). */
143 if (strncmp(famstr
, "PF_NETBEUI", 10) == 0)
145 if (strncmp(famstr
, "PF_ASH", 6) == 0)
147 if (strncmp(famstr
, "PF_ECONET", 9) == 0)
149 if (strncmp(famstr
, "PF_SNA", 6) == 0)
151 if (strncmp(famstr
, "PF_WANPIPE", 10) == 0)
156 if (strncmp(famstr
, "PF_KEY", 6) == 0)
158 if (strncmp(famstr
, "PF_PACKET", 9) == 0)
160 if (strncmp(famstr
, "PF_LLC", 6) == 0)
167 static int generate_sockets(void)
169 int fd
, n
, ret
= FALSE
;
171 unsigned int nr_to_create
= NR_SOCKET_FDS
;
172 unsigned int buffer
[3];
174 cachefile
= creat(cachefilename
, S_IWUSR
|S_IRUSR
);
176 outputerr("Couldn't open cachefile for writing! (%s)\n", strerror(errno
));
178 lock_cachefile(cachefile
, F_WRLCK
);
181 * Don't loop forever if all protos all are disabled.
183 if (!do_specific_proto
) {
184 for (n
= 0; n
< (int)ARRAY_SIZE(no_protos
); n
++) {
189 if (n
>= (int)ARRAY_SIZE(no_protos
))
193 while (nr_to_create
> 0) {
195 struct socket_triplet st
;
197 for (st
.family
= 0; st
.family
< TRINITY_PF_MAX
; st
.family
++) {
199 /* check for ctrl-c again. */
200 if (shm
->exit_reason
!= STILL_RUNNING
)
203 if (do_specific_proto
== TRUE
) {
204 st
.family
= specific_proto
;
205 //FIXME: If we've passed -P and we're spinning here without making progress
206 // then we should abort after a few hundred loops.
209 if (get_proto_name(st
.family
) == NULL
)
212 if (valid_proto(st
.family
) == FALSE
) {
213 if (do_specific_proto
== TRUE
) {
214 outputerr("Can't do protocol %s\n", get_proto_name(st
.family
));
221 BUG_ON(st
.family
>= ARRAY_SIZE(no_protos
));
222 if (no_protos
[st
.family
])
225 if (sanitise_socket_triplet(&st
) == -1)
226 rand_proto_type(&st
);
228 fd
= open_socket(st
.family
, st
.type
, st
.protocol
);
232 if (cachefile
!= -1) {
233 buffer
[0] = st
.family
;
235 buffer
[2] = st
.protocol
;
236 n
= write(cachefile
, &buffer
, sizeof(int) * 3);
238 outputerr("something went wrong writing the cachefile!\n");
243 if (nr_to_create
== 0)
246 //outputerr("Couldn't open family:%d (%s)\n", st.family, get_proto_name(st.family));
254 output(1, "created %d sockets\n", nr_sockets
);
257 if (cachefile
!= -1) {
258 unlock_cachefile(cachefile
);
266 void close_sockets(void)
271 struct linger ling
= { .l_onoff
= FALSE
, .l_linger
= 0 };
273 for (i
= 0; i
< nr_sockets
; i
++) {
275 //FIXME: This is a workaround for a weird bug where we hang forevre
276 // waiting for bluetooth sockets when we setsockopt.
277 // Hopefully at some point we can remove this when someone figures out what's going on.
278 if (shm
->sockets
[i
].triplet
.family
== PF_BLUETOOTH
)
281 /* Grab an fd, and nuke it before someone else uses it. */
282 fd
= shm
->sockets
[i
].fd
;
283 shm
->sockets
[i
].fd
= 0;
286 r
= setsockopt(fd
, SOL_SOCKET
, SO_LINGER
, &ling
, sizeof(struct linger
));
288 perror("setsockopt");
290 r
= shutdown(fd
, SHUT_RDWR
);
295 output(1, "failed to close socket [%d:%d:%d].(%s)\n",
296 shm
->sockets
[i
].triplet
.family
,
297 shm
->sockets
[i
].triplet
.type
,
298 shm
->sockets
[i
].triplet
.protocol
,
305 unsigned int open_sockets(void)
308 unsigned int domain
, type
, protocol
;
309 unsigned int buffer
[3];
314 cachefile
= open(cachefilename
, O_RDONLY
);
316 output(1, "Couldn't find socket cachefile. Regenerating.\n");
317 ret
= generate_sockets();
321 lock_cachefile(cachefile
, F_RDLCK
);
323 while (bytesread
!= 0) {
324 bytesread
= read(cachefile
, buffer
, sizeof(int) * 3);
330 protocol
= buffer
[2];
332 if ((do_specific_proto
== TRUE
&& domain
!= specific_proto
) ||
333 (domain
< ARRAY_SIZE(no_protos
) && no_protos
[domain
] == TRUE
)) {
334 output(1, "ignoring socket cachefile due to specific "
335 "protocol request (or protocol disabled), "
336 "and stale data in cachefile.\n");
338 unlock_cachefile(cachefile
); /* drop the reader lock. */
340 unlink(cachefilename
);
341 ret
= generate_sockets();
345 fd
= open_socket(domain
, type
, protocol
);
347 output(1, "Cachefile is stale. Need to regenerate.\n");
352 /* check for ctrl-c */
353 if (shm
->exit_reason
!= STILL_RUNNING
) {
359 if (nr_sockets
< NR_SOCKET_FDS
) {
360 output(1, "Insufficient sockets in cachefile (%d). Regenerating.\n", nr_sockets
);
364 output(1, "%d sockets created based on info from socket cachefile.\n", nr_sockets
);
366 unlock_cachefile(cachefile
);