1 /* Inner loops of cache daemon.
2 Copyright (C) 1998 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
27 #include <sys/param.h>
29 #include <sys/socket.h>
37 /* Mapping of request type to database. */
38 static const dbtype serv2db
[LASTDBREQ
+ 1] =
40 [GETPWBYNAME
] = pwddb
,
42 [GETGRBYNAME
] = grpdb
,
44 [GETHOSTBYNAME
] = hstdb
,
45 [GETHOSTBYNAMEv6
] = hstdb
,
46 [GETHOSTBYADDR
] = hstdb
,
47 [GETHOSTBYADDRv6
] = hstdb
,
50 /* Map request type to a string. */
51 const char *serv2str
[LASTREQ
] =
53 [GETPWBYNAME
] = "GETPWBYNAME",
54 [GETPWBYUID
] = "GETPWBYUID",
55 [GETGRBYNAME
] = "GETGRBYNAME",
56 [GETGRBYGID
] = "GETGRBYGID",
57 [GETHOSTBYNAME
] = "GETHOSTBYNAME",
58 [GETHOSTBYNAMEv6
] = "GETHOSTBYNAMEv6",
59 [GETHOSTBYADDR
] = "GETHOSTBYADDR",
60 [GETHOSTBYADDRv6
] = "GETHOSTBYADDRv6",
61 [SHUTDOWN
] = "SHUTDOWN",
65 /* The control data structures for the services. */
66 static struct database dbs
[lastdb
] =
69 lock
: PTHREAD_RWLOCK_INITIALIZER
,
72 filename
: "/etc/passwd",
74 disabled_iov
: &pwd_iov_disabled
77 lock
: PTHREAD_RWLOCK_INITIALIZER
,
80 filename
: "/etc/group",
82 disabled_iov
: &grp_iov_disabled
85 lock
: PTHREAD_RWLOCK_INITIALIZER
,
88 filename
: "/etc/hosts",
90 disabled_iov
: &hst_iov_disabled
94 /* Number of threads to use. */
97 /* Socket for incoming connections. */
101 /* Initialize database information structures. */
103 nscd_init (const char *conffile
)
105 struct sockaddr_un sock_addr
;
108 /* Read the configuration file. */
109 if (nscd_parse_file (conffile
, dbs
) != 0)
111 /* We couldn't read the configuration file. Disable all services
112 by shutting down the srever. */
113 dbg_log (_("cannot read configuration file; this is fatal"));
117 /* No configuration for this value, assume a default. */
118 nthreads
= 2 * lastdb
;
120 for (cnt
= 0; cnt
< lastdb
; ++cnt
)
121 if (dbs
[cnt
].enabled
)
123 pthread_rwlock_init (&dbs
[cnt
].lock
, NULL
);
125 dbs
[cnt
].array
= (struct hashentry
**)
126 calloc (dbs
[cnt
].module
, sizeof (struct hashentry
*));
127 if (dbs
[cnt
].array
== NULL
)
128 error (EXIT_FAILURE
, errno
, "while allocating cache");
130 if (dbs
[cnt
].check_file
)
132 /* We need the modification date of the file. */
135 if (stat (dbs
[cnt
].filename
, &st
) < 0)
138 /* We cannot stat() the file, disable file checking. */
139 dbg_log (_("cannot stat() file `%s': %s"),
141 strerror_r (errno
, buf
, sizeof (buf
)));
142 dbs
[cnt
].check_file
= 0;
145 dbs
[cnt
].file_mtime
= st
.st_mtime
;
149 /* Create the socket. */
150 sock
= socket (AF_UNIX
, SOCK_STREAM
, 0);
153 dbg_log (_("cannot open socket: %s"), strerror (errno
));
156 /* Bind a name to the socket. */
157 sock_addr
.sun_family
= AF_UNIX
;
158 strcpy (sock_addr
.sun_path
, _PATH_NSCDSOCKET
);
159 if (bind (sock
, (struct sockaddr
*) &sock_addr
, sizeof (sock_addr
)) < 0)
161 dbg_log ("%s: %s", _PATH_NSCDSOCKET
, strerror (errno
));
165 /* Set permissions for the socket. */
166 chmod (_PATH_NSCDSOCKET
, 0666);
168 /* Set the socket up to accept connections. */
169 if (listen (sock
, SOMAXCONN
) < 0)
171 dbg_log (_("cannot enable socket to accept connections: %s"),
178 /* Close the connections. */
186 /* Handle new request. */
188 handle_request (int fd
, request_header
*req
, void *key
)
191 dbg_log (_("handle_requests: request received (Version = %d)"),
194 if (req
->version
!= NSCD_VERSION
)
197 cannot handle old request version %d; current version is %d"),
198 req
->version
, NSCD_VERSION
);
202 if (req
->type
>= GETPWBYNAME
&& req
->type
<= LASTDBREQ
)
204 struct hashentry
*cached
;
205 struct database
*db
= &dbs
[serv2db
[req
->type
]];
208 dbg_log ("\t%s (%s)", serv2str
[req
->type
], key
);
210 /* Is this service enabled? */
213 /* No sent the prepared record. */
214 if (TEMP_FAILURE_RETRY (write (fd
, db
->disabled_iov
->iov_base
,
215 db
->disabled_iov
->iov_len
))
216 != db
->disabled_iov
->iov_len
)
218 /* We have problems sending the result. */
220 dbg_log (_("cannot write result: %s"),
221 strerror_r (errno
, buf
, sizeof (buf
)));
227 /* Be sure we can read the data. */
228 pthread_rwlock_rdlock (&db
->lock
);
230 /* See whether we can handle it from the cache. */
231 cached
= (struct hashentry
*) cache_search (req
->type
, key
, req
->key_len
,
235 /* Hurray it's in the cache. */
236 if (TEMP_FAILURE_RETRY (write (fd
, cached
->packet
, cached
->total
))
239 /* We have problems sending the result. */
241 dbg_log (_("cannot write result: %s"),
242 strerror_r (errno
, buf
, sizeof (buf
)));
245 pthread_rwlock_unlock (&db
->lock
);
250 pthread_rwlock_unlock (&db
->lock
);
254 dbg_log ("\t%s", serv2str
[req
->type
]);
256 /* Handle the request. */
260 addpwbyname (&dbs
[serv2db
[req
->type
]], fd
, req
, key
);
264 addpwbyuid (&dbs
[serv2db
[req
->type
]], fd
, req
, key
);
268 addgrbyname (&dbs
[serv2db
[req
->type
]], fd
, req
, key
);
272 addgrbygid (&dbs
[serv2db
[req
->type
]], fd
, req
, key
);
276 addhstbyname (&dbs
[serv2db
[req
->type
]], fd
, req
, key
);
279 case GETHOSTBYNAMEv6
:
280 addhstbynamev6 (&dbs
[serv2db
[req
->type
]], fd
, req
, key
);
284 addhstbyaddr (&dbs
[serv2db
[req
->type
]], fd
, req
, key
);
287 case GETHOSTBYADDRv6
:
288 addhstbyaddrv6 (&dbs
[serv2db
[req
->type
]], fd
, req
, key
);
292 send_stats (fd
, dbs
);
296 termination_handler (0);
305 /* This is the main loop. It is replicated in different threads but the
306 `poll' call makes sure only one thread handles an incoming connection. */
308 __attribute__ ((__noreturn__
))
311 int my_number
= (int) p
;
313 int run_prune
= my_number
< lastdb
&& dbs
[my_number
].enabled
;
314 time_t now
= time (NULL
);
315 time_t next_prune
= now
+ 15;
316 int timeout
= run_prune
? 1000 * (next_prune
- now
) : -1;
319 conn
.events
= POLLRDNORM
;
323 int nr
= poll (&conn
, 1, timeout
);
327 /* The `poll' call timed out. It's time to clean up the cache. */
328 assert (my_number
< lastdb
);
330 prune_cache (&dbs
[my_number
], now
);
331 next_prune
= now
+ 15;
332 timeout
= 1000 * (next_prune
- now
);
336 /* We have a new incoming connection. */
337 if (conn
.revents
& (POLLRDNORM
|POLLERR
|POLLHUP
|POLLNVAL
))
339 /* Accept the connection. */
340 int fd
= accept (conn
.fd
, NULL
, NULL
);
346 dbg_log (_("while accepting connection: %s"),
347 strerror_r (errno
, buf
, sizeof (buf
)));
351 /* Now read the request. */
352 if (TEMP_FAILURE_RETRY (read (fd
, &req
, sizeof (req
)))
355 dbg_log (_("short read while reading request: %s"),
356 strerror_r (errno
, buf
, sizeof (buf
)));
361 /* It should not be possible to crash the nscd with a silly
362 request (i.e., a terribly large key. We limit the size
364 if (req
.key_len
< 0 || req
.key_len
> 1024)
366 dbg_log (_("key length in request to long: %Zd"), req
.key_len
);
373 char keybuf
[req
.key_len
];
375 if (TEMP_FAILURE_RETRY (read (fd
, keybuf
, req
.key_len
))
378 dbg_log (_("short read while reading request key: %s"),
379 strerror_r (errno
, buf
, sizeof (buf
)));
384 /* Phew, we got all the data, now process it. */
385 handle_request (fd
, &req
, keybuf
);
395 timeout
= now
< next_prune
? 1000 * (next_prune
- now
) : 0;
401 /* Start all the threads we want. The initial process is thread no. 1. */
409 pthread_attr_init (&attr
);
410 pthread_attr_setdetachstate (&attr
, PTHREAD_CREATE_DETACHED
);
412 /* We allow less than LASTDB threads only for debugging. */
413 if (debug_level
== 0)
414 nthreads
= MAX (nthreads
, lastdb
);
416 for (i
= 1; i
< nthreads
; ++i
)
417 pthread_create (&th
, &attr
, nscd_run
, (void *) i
);
419 pthread_attr_destroy (&attr
);
421 nscd_run ((void *) 0);