daemon.c 81.2 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 1998-2020 The OpenLDAP Foundation.
5
 * Portions Copyright 2007 by Howard Chu, Symas Corporation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* Portions Copyright (c) 1995 Regents of the University of Michigan.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that this notice is preserved and that due credit is given
 * to the University of Michigan at Ann Arbor. The name of the University
 * may not be used to endorse or promote products derived from this
 * software without specific prior written permission. This software
 * is provided ``as is'' without express or implied warranty.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
25
26
 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
28
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
29
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
30
31
32
33
34
35
36
37

#include <ac/ctype.h>
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>

38
#include "slap.h"
Howard Chu's avatar
Howard Chu committed
39
#include "ldap_pvt_thread.h"
40
#include "lutil.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
41

42
43
#include "ldap_rq.h"

44
#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL)
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
45
# include <sys/epoll.h>
46
47
48
49
50
51
#elif defined(SLAP_X_DEVPOLL) && defined(HAVE_SYS_DEVPOLL_H) && defined(HAVE_DEVPOLL)
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <sys/devpoll.h>
#endif /* ! epoll && ! /dev/poll */
Howard Chu's avatar
Howard Chu committed
52

Kurt Zeilenga's avatar
Kurt Zeilenga committed
53
#ifdef HAVE_TCPD
54
55
int allow_severity = LOG_INFO;
int deny_severity = LOG_NOTICE;
56
#endif /* TCP Wrappers */
57

Kurt Zeilenga's avatar
Kurt Zeilenga committed
58
#ifdef LDAP_PF_LOCAL
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
59
# include <sys/stat.h>
60
/* this should go in <ldap.h> as soon as it is accepted */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
61
# define LDAPI_MOD_URLEXT		"x-mod"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
#endif /* LDAP_PF_LOCAL */
63

64
#ifdef LDAP_PF_INET6
65
int slap_inet4or6 = AF_UNSPEC;
66
#else /* ! INETv6 */
67
int slap_inet4or6 = AF_INET;
68
#endif /* ! INETv6 */
69

70
/* globals */
71
72
73
time_t starttime;
ber_socket_t dtblsize;
slap_ssf_t local_ssf = LDAP_PVT_SASL_LOCAL_SSF;
74
struct runqueue_s slapd_rq;
75

76
77
78
#ifndef SLAPD_MAX_DAEMON_THREADS
#define SLAPD_MAX_DAEMON_THREADS	16
#endif
79
80
81
int slapd_daemon_threads = 1;
int slapd_daemon_mask;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
82
83
84
85
86
#ifdef LDAP_TCP_BUFFER
int slapd_tcp_rmem;
int slapd_tcp_wmem;
#endif /* LDAP_TCP_BUFFER */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
87
Listener **slap_listeners = NULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
88
static volatile sig_atomic_t listening = 1; /* 0 when slap_listeners closed */
89
static ldap_pvt_thread_t *listener_tid;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90

91
92
#ifndef SLAPD_LISTEN_BACKLOG
#define SLAPD_LISTEN_BACKLOG 1024
93
#endif /* ! SLAPD_LISTEN_BACKLOG */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
94

95
96
#define	DAEMON_ID(fd)	(fd & slapd_daemon_mask)

97
static ber_socket_t wake_sds[SLAPD_MAX_DAEMON_THREADS][2];
98
static int emfile;
99

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
100
101
static time_t chk_writetime;

102
static volatile int waking;
Howard Chu's avatar
Howard Chu committed
103
#ifdef NO_THREADS
104
#define WAKE_LISTENER(l,w)	do { \
105
	if ((w) && ++waking < 5) { \
106
		tcp_write( SLAP_FD2SOCK(wake_sds[l][1]), "0", 1 ); \
107
	} \
108
109
} while (0)
#else /* ! NO_THREADS */
110
#define WAKE_LISTENER(l,w)	do { \
Howard Chu's avatar
Howard Chu committed
111
	if (w) { \
112
		tcp_write( SLAP_FD2SOCK(wake_sds[l][1]), "0", 1 ); \
Howard Chu's avatar
Howard Chu committed
113
	} \
114
115
} while (0)
#endif /* ! NO_THREADS */
116

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
117
118
volatile sig_atomic_t slapd_shutdown = 0;
volatile sig_atomic_t slapd_gentle_shutdown = 0;
119
120
volatile sig_atomic_t slapd_abrupt_shutdown = 0;

121
122
123
124
125
126
127
128
129
#ifdef HAVE_WINSOCK
ldap_pvt_thread_mutex_t slapd_ws_mutex;
SOCKET *slapd_ws_sockets;
#define	SD_READ 1
#define	SD_WRITE	2
#define	SD_ACTIVE	4
#define	SD_LISTENER	8
#endif

130
#ifdef HAVE_TCPD
131
static ldap_pvt_thread_mutex_t	sd_tcpd_mutex;
132
133
#endif /* TCP Wrappers */

134
135
136
typedef struct slap_daemon_st {
	ldap_pvt_thread_mutex_t	sd_mutex;

137
138
	ber_socket_t		sd_nactives;
	int			sd_nwriters;
139
	int			sd_nfds;
140
141
142
143
144

#if defined(HAVE_EPOLL)
	struct epoll_event	*sd_epolls;
	int			*sd_index;
	int			sd_epfd;
145
146
147
148
149
150
151
#elif defined(SLAP_X_DEVPOLL) && defined(HAVE_DEVPOLL)
	/* eXperimental */
	struct pollfd		*sd_pollfd;
	int			*sd_index;
	Listener		**sd_l;
	int			sd_dpfd;
#else /* ! epoll && ! /dev/poll */
152
153
154
155
#ifdef HAVE_WINSOCK
	char	*sd_flags;
	char	*sd_rflags;
#else /* ! HAVE_WINSOCK */
156
157
158
	fd_set			sd_actives;
	fd_set			sd_readers;
	fd_set			sd_writers;
159
#endif /* ! HAVE_WINSOCK */
160
#endif /* ! epoll && ! /dev/poll */
161
162
} slap_daemon_st;

163
static slap_daemon_st slap_daemon[SLAPD_MAX_DAEMON_THREADS];
164

165
166
167
168
169
170
171
/*
 * NOTE: naming convention for macros:
 *
 * - SLAP_SOCK_* and SLAP_EVENT_* for public interface that deals
 *   with file descriptors and events respectively
 *
 * - SLAP_<type>_* for private interface; type by now is one of
172
 *   EPOLL, DEVPOLL, SELECT
173
174
175
176
177
178
179
180
 *
 * private interface should not be used in the code.
 */
#if defined(HAVE_EPOLL)
/***************************************
 * Use epoll infrastructure - epoll(4) *
 ***************************************/
# define SLAP_EVENT_FNAME		"epoll"
181
# define SLAP_EVENTS_ARE_INDEXED	0
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# define SLAP_EPOLL_SOCK_IX(t,s)		(slap_daemon[t].sd_index[(s)])
# define SLAP_EPOLL_SOCK_EP(t,s)		(slap_daemon[t].sd_epolls[SLAP_EPOLL_SOCK_IX(t,s)])
# define SLAP_EPOLL_SOCK_EV(t,s)		(SLAP_EPOLL_SOCK_EP(t,s).events)
# define SLAP_SOCK_IS_ACTIVE(t,s)		(SLAP_EPOLL_SOCK_IX(t,s) != -1)
# define SLAP_SOCK_NOT_ACTIVE(t,s)	(SLAP_EPOLL_SOCK_IX(t,s) == -1)
# define SLAP_EPOLL_SOCK_IS_SET(t,s, mode)	(SLAP_EPOLL_SOCK_EV(t,s) & (mode))

# define SLAP_SOCK_IS_READ(t,s)		SLAP_EPOLL_SOCK_IS_SET(t,(s), EPOLLIN)
# define SLAP_SOCK_IS_WRITE(t,s)		SLAP_EPOLL_SOCK_IS_SET(t,(s), EPOLLOUT)

# define SLAP_EPOLL_SOCK_SET(t,s, mode)	do { \
	if ( (SLAP_EPOLL_SOCK_EV(t,s) & (mode)) != (mode) ) {	\
		SLAP_EPOLL_SOCK_EV(t,s) |= (mode); \
		epoll_ctl( slap_daemon[t].sd_epfd, EPOLL_CTL_MOD, (s), \
			&SLAP_EPOLL_SOCK_EP(t,s) ); \
197
	} \
198
} while (0)
199

200
201
202
203
204
# define SLAP_EPOLL_SOCK_CLR(t,s, mode)	do { \
	if ( (SLAP_EPOLL_SOCK_EV(t,s) & (mode)) ) { \
		SLAP_EPOLL_SOCK_EV(t,s) &= ~(mode);	\
		epoll_ctl( slap_daemon[t].sd_epfd, EPOLL_CTL_MOD, s, \
			&SLAP_EPOLL_SOCK_EP(t,s) ); \
205
	} \
206
207
} while (0)

208
209
# define SLAP_SOCK_SET_READ(t,s)		SLAP_EPOLL_SOCK_SET(t,s, EPOLLIN)
# define SLAP_SOCK_SET_WRITE(t,s)		SLAP_EPOLL_SOCK_SET(t,s, EPOLLOUT)
210

211
212
# define SLAP_SOCK_CLR_READ(t,s)		SLAP_EPOLL_SOCK_CLR(t,(s), EPOLLIN)
# define SLAP_SOCK_CLR_WRITE(t,s)		SLAP_EPOLL_SOCK_CLR(t,(s), EPOLLOUT)
213

214
215
216
217
218
219
#  define SLAP_SOCK_SET_SUSPEND(t,s) \
	( slap_daemon[t].sd_suspend[SLAP_EPOLL_SOCK_IX(t,s)] = 1 )
#  define SLAP_SOCK_CLR_SUSPEND(t,s) \
	( slap_daemon[t].sd_suspend[SLAP_EPOLL_SOCK_IX(t,s)] = 0 )
#  define SLAP_SOCK_IS_SUSPEND(t,s) \
	( slap_daemon[t].sd_suspend[SLAP_EPOLL_SOCK_IX(t,s)] == 1 )
220

221
# define SLAP_EPOLL_EVENT_CLR(i, mode)	(revents[(i)].events &= ~(mode))
222

223
# define SLAP_EVENT_MAX(t)			slap_daemon[t].sd_nfds
Howard Chu's avatar
Howard Chu committed
224

Howard Chu's avatar
Howard Chu committed
225
226
/* If a Listener address is provided, store that as the epoll data.
 * Otherwise, store the address of this socket's slot in the
227
228
 * index array. If we can't do this add, the system is out of
 * resources and we need to shutdown.
Howard Chu's avatar
Howard Chu committed
229
 */
230
# define SLAP_SOCK_ADD(t, s, l)		do { \
231
	int rc; \
232
233
234
235
236
	SLAP_EPOLL_SOCK_IX(t,(s)) = slap_daemon[t].sd_nfds; \
	SLAP_EPOLL_SOCK_EP(t,(s)).data.ptr = (l) ? (l) : (void *)(&SLAP_EPOLL_SOCK_IX(t,s)); \
	SLAP_EPOLL_SOCK_EV(t,(s)) = EPOLLIN; \
	rc = epoll_ctl(slap_daemon[t].sd_epfd, EPOLL_CTL_ADD, \
		(s), &SLAP_EPOLL_SOCK_EP(t,(s))); \
237
	if ( rc == 0 ) { \
238
		slap_daemon[t].sd_nfds++; \
239
240
	} else { \
		Debug( LDAP_DEBUG_ANY, \
241
242
			"daemon: epoll_ctl(ADD,fd=%d) failed, errno=%d, shutting down\n", \
			s, errno, 0 ); \
243
244
245
246
		slapd_shutdown = 2; \
	} \
} while (0)

247
248
249
# define SLAP_EPOLL_EV_LISTENER(t,ptr) \
	(((int *)(ptr) >= slap_daemon[t].sd_index && \
	(int *)(ptr) <= &slap_daemon[t].sd_index[dtblsize]) ? 0 : 1 )
250

251
# define SLAP_EPOLL_EV_PTRFD(t,ptr)		(SLAP_EPOLL_EV_LISTENER(t,ptr) ? \
252
	((Listener *)ptr)->sl_sd : \
253
	(ber_socket_t) ((int *)(ptr) - slap_daemon[t].sd_index))
254

255
256
# define SLAP_SOCK_DEL(t,s)		do { \
	int fd, rc, index = SLAP_EPOLL_SOCK_IX(t,(s)); \
257
	if ( index < 0 ) break; \
258
259
260
261
262
263
264
265
	rc = epoll_ctl(slap_daemon[t].sd_epfd, EPOLL_CTL_DEL, \
		(s), &SLAP_EPOLL_SOCK_EP(t,(s))); \
	slap_daemon[t].sd_epolls[index] = \
		slap_daemon[t].sd_epolls[slap_daemon[t].sd_nfds-1]; \
	fd = SLAP_EPOLL_EV_PTRFD(t,slap_daemon[t].sd_epolls[index].data.ptr); \
	slap_daemon[t].sd_index[fd] = index; \
	slap_daemon[t].sd_index[(s)] = -1; \
	slap_daemon[t].sd_nfds--; \
266
267
} while (0)

268
269
# define SLAP_EVENT_CLR_READ(i)		SLAP_EPOLL_EVENT_CLR((i), EPOLLIN)
# define SLAP_EVENT_CLR_WRITE(i)	SLAP_EPOLL_EVENT_CLR((i), EPOLLOUT)
270

271
# define SLAP_EPOLL_EVENT_CHK(i, mode)	(revents[(i)].events & mode)
272

273
274
# define SLAP_EVENT_IS_READ(i)		SLAP_EPOLL_EVENT_CHK((i), EPOLLIN)
# define SLAP_EVENT_IS_WRITE(i)		SLAP_EPOLL_EVENT_CHK((i), EPOLLOUT)
275
276
# define SLAP_EVENT_IS_LISTENER(t,i)	SLAP_EPOLL_EV_LISTENER(t,revents[(i)].data.ptr)
# define SLAP_EVENT_LISTENER(t,i)		((Listener *)(revents[(i)].data.ptr))
277

278
# define SLAP_EVENT_FD(t,i)		SLAP_EPOLL_EV_PTRFD(t,revents[(i)].data.ptr)
279

280
281
282
# define SLAP_SOCK_INIT(t)		do { \
	int j; \
	slap_daemon[t].sd_epolls = ch_calloc(1, \
283
284
		( sizeof(struct epoll_event) * 2 \
			+ sizeof(int) ) * dtblsize * 2); \
285
286
287
	slap_daemon[t].sd_index = (int *)&slap_daemon[t].sd_epolls[ 2 * dtblsize ]; \
	slap_daemon[t].sd_epfd = epoll_create( dtblsize / slapd_daemon_threads ); \
	for ( j = 0; j < dtblsize; j++ ) slap_daemon[t].sd_index[j] = -1; \
288
289
} while (0)

290
291
292
293
294
295
# define SLAP_SOCK_DESTROY(t)		do { \
	if ( slap_daemon[t].sd_epolls != NULL ) { \
		ch_free( slap_daemon[t].sd_epolls ); \
		slap_daemon[t].sd_epolls = NULL; \
		slap_daemon[t].sd_index = NULL; \
		close( slap_daemon[t].sd_epfd ); \
296
297
298
	} \
} while ( 0 )

299
# define SLAP_EVENT_DECL		struct epoll_event *revents
300

301
302
# define SLAP_EVENT_INIT(t)		do { \
	revents = slap_daemon[t].sd_epolls + dtblsize; \
303
304
} while (0)

305
306
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
	*(nsp) = epoll_wait( slap_daemon[t].sd_epfd, revents, \
307
		dtblsize, (tvp) ? ((tvp)->tv_sec * 1000 + (tvp)->tv_usec / 1000) : -1 ); \
308
} while (0)
309

310
#elif defined(SLAP_X_DEVPOLL) && defined(HAVE_DEVPOLL)
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
311

312
313
314
315
316
317
318
319
320
321
322
323
/*************************************************************
 * Use Solaris' (>= 2.7) /dev/poll infrastructure - poll(7d) *
 *************************************************************/
# define SLAP_EVENT_FNAME		"/dev/poll"
# define SLAP_EVENTS_ARE_INDEXED	0
/*
 * - sd_index	is used much like with epoll()
 * - sd_l	is maintained as an array containing the address
 *		of the listener; the index is the fd itself
 * - sd_pollfd	is used to keep track of what data has been
 *		registered in /dev/poll
 */
324
325
326
327
328
329
330
331
332
333
334
# define SLAP_DEVPOLL_SOCK_IX(t,s)	(slap_daemon[t].sd_index[(s)])
# define SLAP_DEVPOLL_SOCK_LX(t,s)	(slap_daemon[t].sd_l[(s)])
# define SLAP_DEVPOLL_SOCK_EP(t,s)	(slap_daemon[t].sd_pollfd[SLAP_DEVPOLL_SOCK_IX(t,(s))])
# define SLAP_DEVPOLL_SOCK_FD(t,s)	(SLAP_DEVPOLL_SOCK_EP(t,(s)).fd)
# define SLAP_DEVPOLL_SOCK_EV(t,s)	(SLAP_DEVPOLL_SOCK_EP(t,(s)).events)
# define SLAP_SOCK_IS_ACTIVE(t,s)		(SLAP_DEVPOLL_SOCK_IX(t,(s)) != -1)
# define SLAP_SOCK_NOT_ACTIVE(t,s)	(SLAP_DEVPOLL_SOCK_IX(t,(s)) == -1)
# define SLAP_SOCK_IS_SET(t,s, mode)	(SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode))

# define SLAP_SOCK_IS_READ(t,s)		SLAP_SOCK_IS_SET(t,(s), POLLIN)
# define SLAP_SOCK_IS_WRITE(t,s)		SLAP_SOCK_IS_SET(t,(s), POLLOUT)
335
336
337
338

/* as far as I understand, any time we need to communicate with the kernel
 * about the number and/or properties of a file descriptor we need it to
 * wait for, we have to rewrite the whole set */
339
# define SLAP_DEVPOLL_WRITE_POLLFD(t,s, pfd, n, what, shdn)	do { \
340
341
342
	int rc; \
	size_t size = (n) * sizeof( struct pollfd ); \
	/* FIXME: use pwrite? */ \
343
	rc = write( slap_daemon[t].sd_dpfd, (pfd), size ); \
344
345
346
347
348
349
350
351
352
353
	if ( rc != size ) { \
		Debug( LDAP_DEBUG_ANY, "daemon: " SLAP_EVENT_FNAME ": " \
			"%s fd=%d failed errno=%d\n", \
			(what), (s), errno ); \
		if ( (shdn) ) { \
			slapd_shutdown = 2; \
		} \
	} \
} while (0)

354
# define SLAP_DEVPOLL_SOCK_SET(t,s, mode) 	do { \
355
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_SET_%s(%d)=%d\n", \
356
		(mode) == POLLIN ? "READ" : "WRITE", (s), \
357
358
		( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) != (mode) ) ); \
	if ( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) != (mode) ) { \
359
		struct pollfd pfd; \
360
361
362
363
		SLAP_DEVPOLL_SOCK_EV(t,(s)) |= (mode); \
		pfd.fd = SLAP_DEVPOLL_SOCK_FD(t,(s)); \
		pfd.events = /* (mode) */ SLAP_DEVPOLL_SOCK_EV(t,(s)); \
		SLAP_DEVPOLL_WRITE_POLLFD(t,(s), &pfd, 1, "SET", 0); \
364
365
366
	} \
} while (0)

367
# define SLAP_DEVPOLL_SOCK_CLR(t,s, mode)		do { \
368
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_CLR_%s(%d)=%d\n", \
369
		(mode) == POLLIN ? "READ" : "WRITE", (s), \
370
371
		( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) == (mode) ) ); \
	if ((SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) == (mode) ) { \
372
		struct pollfd pfd[2]; \
373
374
		SLAP_DEVPOLL_SOCK_EV(t,(s)) &= ~(mode); \
		pfd[0].fd = SLAP_DEVPOLL_SOCK_FD(t,(s)); \
375
		pfd[0].events = POLLREMOVE; \
376
377
		pfd[1] = SLAP_DEVPOLL_SOCK_EP(t,(s)); \
		SLAP_DEVPOLL_WRITE_POLLFD(t,(s), &pfd[0], 2, "CLR", 0); \
378
379
380
	} \
} while (0)

381
382
# define SLAP_SOCK_SET_READ(t,s)		SLAP_DEVPOLL_SOCK_SET(t,s, POLLIN)
# define SLAP_SOCK_SET_WRITE(t,s)		SLAP_DEVPOLL_SOCK_SET(t,s, POLLOUT)
383

384
385
# define SLAP_SOCK_CLR_READ(t,s)		SLAP_DEVPOLL_SOCK_CLR(t,(s), POLLIN)
# define SLAP_SOCK_CLR_WRITE(t,s)		SLAP_DEVPOLL_SOCK_CLR(t,(s), POLLOUT)
386

387
388
389
390
391
392
#  define SLAP_SOCK_SET_SUSPEND(t,s) \
	( slap_daemon[t].sd_suspend[SLAP_DEVPOLL_SOCK_IX(t,(s))] = 1 )
#  define SLAP_SOCK_CLR_SUSPEND(t,s) \
	( slap_daemon[t].sd_suspend[SLAP_DEVPOLL_SOCK_IX(t,(s))] = 0 )
#  define SLAP_SOCK_IS_SUSPEND(t,s) \
	( slap_daemon[t].sd_suspend[SLAP_DEVPOLL_SOCK_IX(t,(s))] == 1 )
393
394
395

# define SLAP_DEVPOLL_EVENT_CLR(i, mode)	(revents[(i)].events &= ~(mode))

396
# define SLAP_EVENT_MAX(t)			slap_daemon[t].sd_nfds
397
398
399
400
401

/* If a Listener address is provided, store that in the sd_l array.
 * If we can't do this add, the system is out of resources and we 
 * need to shutdown.
 */
402
# define SLAP_SOCK_ADD(t, s, l)		do { \
403
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_ADD(%d, %p)\n", (s), (l), 0 ); \
404
405
406
407
408
409
	SLAP_DEVPOLL_SOCK_IX(t,(s)) = slap_daemon[t].sd_nfds; \
	SLAP_DEVPOLL_SOCK_LX(t,(s)) = (l); \
	SLAP_DEVPOLL_SOCK_FD(t,(s)) = (s); \
	SLAP_DEVPOLL_SOCK_EV(t,(s)) = POLLIN; \
	SLAP_DEVPOLL_WRITE_POLLFD(t,(s), &SLAP_DEVPOLL_SOCK_EP((s)), 1, "ADD", 1); \
	slap_daemon[t].sd_nfds++; \
410
411
412
413
} while (0)

# define SLAP_DEVPOLL_EV_LISTENER(ptr)	((ptr) != NULL)

414
415
# define SLAP_SOCK_DEL(t,s)		do { \
	int fd, index = SLAP_DEVPOLL_SOCK_IX(t,(s)); \
416
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_DEL(%d)\n", (s), 0, 0 ); \
417
	if ( index < 0 ) break; \
418
419
420
421
422
423
	if ( index < slap_daemon[t].sd_nfds - 1 ) { \
		struct pollfd pfd = slap_daemon[t].sd_pollfd[index]; \
		fd = slap_daemon[t].sd_pollfd[slap_daemon[t].sd_nfds - 1].fd; \
		slap_daemon[t].sd_pollfd[index] = slap_daemon[t].sd_pollfd[slap_daemon[t].sd_nfds - 1]; \
		slap_daemon[t].sd_pollfd[slap_daemon[t].sd_nfds - 1] = pfd; \
		slap_daemon[t].sd_index[fd] = index; \
424
	} \
425
426
427
428
429
	slap_daemon[t].sd_index[(s)] = -1; \
	slap_daemon[t].sd_pollfd[slap_daemon[t].sd_nfds - 1].events = POLLREMOVE; \
	SLAP_DEVPOLL_WRITE_POLLFD(t,(s), &slap_daemon[t].sd_pollfd[slap_daemon[t].sd_nfds - 1], 1, "DEL", 0); \
	slap_daemon[t].sd_pollfd[slap_daemon[t].sd_nfds - 1].events = 0; \
	slap_daemon[t].sd_nfds--; \
430
431
432
433
434
435
436
} while (0)

# define SLAP_EVENT_CLR_READ(i)		SLAP_DEVPOLL_EVENT_CLR((i), POLLIN)
# define SLAP_EVENT_CLR_WRITE(i)	SLAP_DEVPOLL_EVENT_CLR((i), POLLOUT)

# define SLAP_DEVPOLL_EVENT_CHK(i, mode)	(revents[(i)].events & (mode))

437
# define SLAP_EVENT_FD(t,i)		(revents[(i)].fd)
438
439
440

# define SLAP_EVENT_IS_READ(i)		SLAP_DEVPOLL_EVENT_CHK((i), POLLIN)
# define SLAP_EVENT_IS_WRITE(i)		SLAP_DEVPOLL_EVENT_CHK((i), POLLOUT)
441
442
# define SLAP_EVENT_IS_LISTENER(t,i)	SLAP_DEVPOLL_EV_LISTENER(SLAP_DEVPOLL_SOCK_LX(SLAP_EVENT_FD(t,(i))))
# define SLAP_EVENT_LISTENER(t,i)		SLAP_DEVPOLL_SOCK_LX(SLAP_EVENT_FD(t,(i)))
443

444
445
# define SLAP_SOCK_INIT(t)		do { \
	slap_daemon[t].sd_pollfd = ch_calloc( 1, \
446
447
448
		( sizeof(struct pollfd) * 2 \
			+ sizeof( int ) \
			+ sizeof( Listener * ) ) * dtblsize ); \
449
450
451
452
	slap_daemon[t].sd_index = (int *)&slap_daemon[t].sd_pollfd[ 2 * dtblsize ]; \
	slap_daemon[t].sd_l = (Listener **)&slap_daemon[t].sd_index[ dtblsize ]; \
	slap_daemon[t].sd_dpfd = open( SLAP_EVENT_FNAME, O_RDWR ); \
	if ( slap_daemon[t].sd_dpfd == -1 ) { \
453
454
455
456
457
458
459
		Debug( LDAP_DEBUG_ANY, "daemon: " SLAP_EVENT_FNAME ": " \
			"open(\"" SLAP_EVENT_FNAME "\") failed errno=%d\n", \
			errno, 0, 0 ); \
		SLAP_SOCK_DESTROY; \
		return -1; \
	} \
	for ( i = 0; i < dtblsize; i++ ) { \
460
461
		slap_daemon[t].sd_pollfd[i].fd = -1; \
		slap_daemon[t].sd_index[i] = -1; \
462
463
464
	} \
} while (0)

465
466
467
468
469
470
471
# define SLAP_SOCK_DESTROY(t)		do { \
	if ( slap_daemon[t].sd_pollfd != NULL ) { \
		ch_free( slap_daemon[t].sd_pollfd ); \
		slap_daemon[t].sd_pollfd = NULL; \
		slap_daemon[t].sd_index = NULL; \
		slap_daemon[t].sd_l = NULL; \
		close( slap_daemon[t].sd_dpfd ); \
472
473
474
475
476
	} \
} while ( 0 )

# define SLAP_EVENT_DECL		struct pollfd *revents

477
478
# define SLAP_EVENT_INIT(t)		do { \
	revents = &slap_daemon[t].sd_pollfd[ dtblsize ]; \
479
480
} while (0)

481
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
482
	struct dvpoll		sd_dvpoll; \
483
	sd_dvpoll.dp_timeout = (tvp) ? ((tvp)->tv_sec * 1000 + (tvp)->tv_usec / 1000) : -1; \
484
485
	sd_dvpoll.dp_nfds = dtblsize; \
	sd_dvpoll.dp_fds = revents; \
486
	*(nsp) = ioctl( slap_daemon[t].sd_dpfd, DP_POLL, &sd_dvpoll ); \
487
488
489
} while (0)

#else /* ! epoll && ! /dev/poll */
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
# ifdef HAVE_WINSOCK
# define SLAP_EVENT_FNAME		"WSselect"
/* Winsock provides a "select" function but its fd_sets are
 * actually arrays of sockets. Since these sockets are handles
 * and not a contiguous range of small integers, we manage our
 * own "fd" table of socket handles and use their indices as
 * descriptors.
 *
 * All of our listener/connection structures use fds; the actual
 * I/O functions use sockets. The SLAP_FD2SOCK macro in proto-slap.h
 * handles the mapping.
 *
 * Despite the mapping overhead, this is about 45% more efficient
 * than just using Winsock's select and FD_ISSET directly.
 *
 * Unfortunately Winsock's select implementation doesn't scale well
 * as the number of connections increases. This probably needs to be
 * rewritten to use the Winsock overlapped/asynchronous I/O functions.
 */
# define SLAP_EVENTS_ARE_INDEXED	1
510
511
# define SLAP_EVENT_DECL		fd_set readfds, writefds; char *rflags
# define SLAP_EVENT_INIT(t)	do { \
512
513
514
	int i; \
	FD_ZERO( &readfds ); \
	FD_ZERO( &writefds ); \
515
516
517
518
	rflags = slap_daemon[t].sd_rflags; \
	memset( rflags, 0, slap_daemon[t].sd_nfds ); \
	for ( i=0; i<slap_daemon[t].sd_nfds; i++ ) { \
		if ( slap_daemon[t].sd_flags[i] & SD_READ ) \
519
			FD_SET( slapd_ws_sockets[i], &readfds );\
520
		if ( slap_daemon[t].sd_flags[i] & SD_WRITE ) \
521
522
523
			FD_SET( slapd_ws_sockets[i], &writefds ); \
	} } while ( 0 )

524
# define SLAP_EVENT_MAX(t)		slap_daemon[t].sd_nfds
525

526
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
527
	int i; \
528
	*(nsp) = select( SLAP_EVENT_MAX(t), &readfds, \
529
530
531
532
		nwriters > 0 ? &writefds : NULL, NULL, (tvp) ); \
	for ( i=0; i<readfds.fd_count; i++) { \
		int fd = slapd_sock2fd(readfds.fd_array[i]); \
		if ( fd >= 0 ) { \
533
			slap_daemon[t].sd_rflags[fd] = SD_READ; \
534
535
536
537
538
539
			if ( fd >= *(nsp)) *(nsp) = fd+1; \
		} \
	} \
	for ( i=0; i<writefds.fd_count; i++) { \
		int fd = slapd_sock2fd(writefds.fd_array[i]); \
		if ( fd >= 0 ) { \
540
			slap_daemon[t].sd_rflags[fd] = SD_WRITE; \
541
542
543
544
545
			if ( fd >= *(nsp)) *(nsp) = fd+1; \
		} \
	} \
} while (0)

546
547
# define SLAP_EVENT_IS_READ(fd)		(rflags[fd] & SD_READ)
# define SLAP_EVENT_IS_WRITE(fd)	(rflags[fd] & SD_WRITE)
548

549
550
# define SLAP_EVENT_CLR_READ(fd) 	rflags[fd] &= ~SD_READ
# define SLAP_EVENT_CLR_WRITE(fd)	rflags[fd] &= ~SD_WRITE
551

552
553
# define SLAP_SOCK_INIT(t)		do { \
	if (!t) { \
554
555
556
	ldap_pvt_thread_mutex_init( &slapd_ws_mutex ); \
	slapd_ws_sockets = ch_malloc( dtblsize * ( sizeof(SOCKET) + 2)); \
	memset( slapd_ws_sockets, -1, dtblsize * sizeof(SOCKET) ); \
557
558
559
560
561
562
	} \
	slap_daemon[t].sd_flags = (char *)(slapd_ws_sockets + dtblsize); \
	slap_daemon[t].sd_rflags = slap_daemon[t].sd_flags + dtblsize; \
	memset( slap_daemon[t].sd_flags, 0, dtblsize ); \
	slapd_ws_sockets[t*2] = wake_sds[t][0]; \
	slapd_ws_sockets[t*2+1] = wake_sds[t][1]; \
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
563
564
	wake_sds[t][0] = t*2; \
	wake_sds[t][1] = t*2+1; \
565
	slap_daemon[t].sd_nfds = t*2 + 2; \
566
567
	} while ( 0 )

568
# define SLAP_SOCK_DESTROY(t)	do { \
569
	ch_free( slapd_ws_sockets ); slapd_ws_sockets = NULL; \
570
571
	slap_daemon[t].sd_flags = NULL; \
	slap_daemon[t].sd_rflags = NULL; \
572
573
574
	ldap_pvt_thread_mutex_destroy( &slapd_ws_mutex ); \
	} while ( 0 )

575
576
577
578
# define SLAP_SOCK_IS_ACTIVE(t,fd) ( slap_daemon[t].sd_flags[fd] & SD_ACTIVE )
# define SLAP_SOCK_IS_READ(t,fd) ( slap_daemon[t].sd_flags[fd] & SD_READ )
# define SLAP_SOCK_IS_WRITE(t,fd) ( slap_daemon[t].sd_flags[fd] & SD_WRITE )
# define SLAP_SOCK_NOT_ACTIVE(t,fd)	(!slap_daemon[t].sd_flags[fd])
579

580
581
# define SLAP_SOCK_SET_READ(t,fd)		( slap_daemon[t].sd_flags[fd] |= SD_READ )
# define SLAP_SOCK_SET_WRITE(t,fd)		( slap_daemon[t].sd_flags[fd] |= SD_WRITE )
582

583
584
# define SLAP_SELECT_ADDTEST(t,s)	do { \
	if ((s) >= slap_daemon[t].sd_nfds) slap_daemon[t].sd_nfds = (s)+1; \
585
586
} while (0)

587
588
# define SLAP_SOCK_CLR_READ(t,fd)		( slap_daemon[t].sd_flags[fd] &= ~SD_READ )
# define SLAP_SOCK_CLR_WRITE(t,fd)		( slap_daemon[t].sd_flags[fd] &= ~SD_WRITE )
589

590
591
592
# define SLAP_SOCK_ADD(t,s, l)	do { \
	SLAP_SELECT_ADDTEST(t,(s)); \
	slap_daemon[t].sd_flags[s] = SD_ACTIVE|SD_READ; \
593
594
} while ( 0 )

595
596
# define SLAP_SOCK_DEL(t,s) do { \
	slap_daemon[t].sd_flags[s] = 0; \
597
598
599
600
	slapd_sockdel( s ); \
} while ( 0 )

# else /* !HAVE_WINSOCK */
601
602
603
604
605

/**************************************
 * Use select system call - select(2) *
 **************************************/
# define SLAP_EVENT_FNAME		"select"
606
/* select */
607
608
# define SLAP_EVENTS_ARE_INDEXED	1
# define SLAP_EVENT_DECL		fd_set readfds, writefds
609

610
611
# define SLAP_EVENT_INIT(t)		do { \
	AC_MEMCPY( &readfds, &slap_daemon[t].sd_readers, sizeof(fd_set) );	\
612
	if ( nwriters )	{ \
613
		AC_MEMCPY( &writefds, &slap_daemon[t].sd_writers, sizeof(fd_set) ); \
614
615
616
617
618
619
	} else { \
		FD_ZERO( &writefds ); \
	} \
} while (0)

# ifdef FD_SETSIZE
620
#  define SLAP_SELECT_CHK_SETSIZE	do { \
621
622
	if (dtblsize > FD_SETSIZE) dtblsize = FD_SETSIZE; \
} while (0)
623
624
625
# else /* ! FD_SETSIZE */
#  define SLAP_SELECT_CHK_SETSIZE	do { ; } while (0)
# endif /* ! FD_SETSIZE */
626

627
# define SLAP_SOCK_INIT(t)			do { \
628
	SLAP_SELECT_CHK_SETSIZE; \
629
630
631
	FD_ZERO(&slap_daemon[t].sd_actives); \
	FD_ZERO(&slap_daemon[t].sd_readers); \
	FD_ZERO(&slap_daemon[t].sd_writers); \
632
633
} while (0)

634
# define SLAP_SOCK_DESTROY(t)
635

636
637
638
# define SLAP_SOCK_IS_ACTIVE(t,fd)	FD_ISSET((fd), &slap_daemon[t].sd_actives)
# define SLAP_SOCK_IS_READ(t,fd)		FD_ISSET((fd), &slap_daemon[t].sd_readers)
# define SLAP_SOCK_IS_WRITE(t,fd)		FD_ISSET((fd), &slap_daemon[t].sd_writers)
639

640
641
# define SLAP_SOCK_NOT_ACTIVE(t,fd)	(!SLAP_SOCK_IS_ACTIVE(t,fd) && \
	 !SLAP_SOCK_IS_READ(t,fd) && !SLAP_SOCK_IS_WRITE(t,fd))
642

643
644
# define SLAP_SOCK_SET_READ(t,fd)	FD_SET((fd), &slap_daemon[t].sd_readers)
# define SLAP_SOCK_SET_WRITE(t,fd)	FD_SET((fd), &slap_daemon[t].sd_writers)
645

646
647
648
# define SLAP_EVENT_MAX(t)		slap_daemon[t].sd_nfds
# define SLAP_SELECT_ADDTEST(t,s)	do { \
	if ((s) >= slap_daemon[t].sd_nfds) slap_daemon[t].sd_nfds = (s)+1; \
649
650
} while (0)

651
652
# define SLAP_SOCK_CLR_READ(t,fd)		FD_CLR((fd), &slap_daemon[t].sd_readers)
# define SLAP_SOCK_CLR_WRITE(t,fd)	FD_CLR((fd), &slap_daemon[t].sd_writers)
653

654
655
656
657
# define SLAP_SOCK_ADD(t,s, l)		do { \
	SLAP_SELECT_ADDTEST(t,(s)); \
	FD_SET((s), &slap_daemon[t].sd_actives); \
	FD_SET((s), &slap_daemon[t].sd_readers); \
658
} while (0)
659

660
661
662
663
# define SLAP_SOCK_DEL(t,s)		do { \
	FD_CLR((s), &slap_daemon[t].sd_actives); \
	FD_CLR((s), &slap_daemon[t].sd_readers); \
	FD_CLR((s), &slap_daemon[t].sd_writers); \
664
} while (0)
665

666
667
# define SLAP_EVENT_IS_READ(fd)		FD_ISSET((fd), &readfds)
# define SLAP_EVENT_IS_WRITE(fd)	FD_ISSET((fd), &writefds)
668

669
670
# define SLAP_EVENT_CLR_READ(fd) 	FD_CLR((fd), &readfds)
# define SLAP_EVENT_CLR_WRITE(fd)	FD_CLR((fd), &writefds)
671

672
673
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
	*(nsp) = select( SLAP_EVENT_MAX(t), &readfds, \
674
675
		nwriters > 0 ? &writefds : NULL, NULL, (tvp) ); \
} while (0)
676
# endif /* !HAVE_WINSOCK */
677
#endif /* ! epoll && ! /dev/poll */
678
679
680
681
682
683
684
685

#ifdef HAVE_SLP
/*
 * SLP related functions
 */
#include <slp.h>

#define LDAP_SRVTYPE_PREFIX "service:ldap://"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
686
687
#define LDAPS_SRVTYPE_PREFIX "service:ldaps://"
static char** slapd_srvurls = NULL;
688
static SLPHandle slapd_hslp = 0;
689
int slapd_register_slp = 0;
690
const char *slapd_slp_attrs = NULL;
691
692

static SLPError slapd_slp_cookie;
693

694
695
696
static void
slapd_slp_init( const char* urls )
{
697
	int i;
698
	SLPError err;
699

700
	slapd_srvurls = ldap_str2charray( urls, " " );
701

702
	if ( slapd_srvurls == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
703
704

	/* find and expand INADDR_ANY URLs */
705
706
	for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
		if ( strcmp( slapd_srvurls[i], "ldap:///" ) == 0 ) {
Howard Chu's avatar
Howard Chu committed
707
			slapd_srvurls[i] = (char *) ch_realloc( slapd_srvurls[i],
708
				global_host_bv.bv_len +
Howard Chu's avatar
Howard Chu committed
709
710
				sizeof( LDAP_SRVTYPE_PREFIX ) );
			strcpy( lutil_strcopy(slapd_srvurls[i],
711
				LDAP_SRVTYPE_PREFIX ), global_host_bv.bv_val );
712
		} else if ( strcmp( slapd_srvurls[i], "ldaps:///" ) == 0 ) {
Howard Chu's avatar
Howard Chu committed
713
			slapd_srvurls[i] = (char *) ch_realloc( slapd_srvurls[i],
714
				global_host_bv.bv_len +
Howard Chu's avatar
Howard Chu committed
715
716
				sizeof( LDAPS_SRVTYPE_PREFIX ) );
			strcpy( lutil_strcopy(slapd_srvurls[i],
717
				LDAPS_SRVTYPE_PREFIX ), global_host_bv.bv_val );
718
719
720
721
		}
	}

	/* open the SLP handle */
722
723
	err = SLPOpen( "en", 0, &slapd_hslp );

724
	if ( err != SLP_OK ) {
725
726
727
		Debug( LDAP_DEBUG_CONNS, "daemon: SLPOpen() failed with %ld\n",
			(long)err, 0, 0 );
	}
728
729
}

730
731
732
733
static void
slapd_slp_deinit( void )
{
	if ( slapd_srvurls == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
734

735
	ldap_charray_free( slapd_srvurls );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
736
	slapd_srvurls = NULL;
737
738
739
740
741

	/* close the SLP handle */
	SLPClose( slapd_hslp );
}

742
743
744
745
746
static void
slapd_slp_regreport(
	SLPHandle	hslp,
	SLPError	errcode,
	void		*cookie )
747
{
748
749
	/* return the error code in the cookie */
	*(SLPError*)cookie = errcode; 
750
751
}

752
753
754
static void
slapd_slp_reg()
{
755
	int i;
756
	SLPError err;
757

758
	if ( slapd_srvurls == NULL ) return;
759

760
761
	for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
		if ( strncmp( slapd_srvurls[i], LDAP_SRVTYPE_PREFIX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
762
				sizeof( LDAP_SRVTYPE_PREFIX ) - 1 ) == 0 ||
763
			strncmp( slapd_srvurls[i], LDAPS_SRVTYPE_PREFIX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
764
765
				sizeof( LDAPS_SRVTYPE_PREFIX ) - 1 ) == 0 )
		{
766
			err = SLPReg( slapd_hslp,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
767
768
769
				slapd_srvurls[i],
				SLP_LIFETIME_MAXIMUM,
				"ldap",
770
771
				(slapd_slp_attrs) ? slapd_slp_attrs : "",
				SLP_TRUE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
772
				slapd_slp_regreport,
773
				&slapd_slp_cookie );
774

775
			if ( err != SLP_OK || slapd_slp_cookie != SLP_OK ) {
776
777
778
779
				Debug( LDAP_DEBUG_CONNS,
					"daemon: SLPReg(%s) failed with %ld, cookie = %ld\n",
					slapd_srvurls[i], (long)err, (long)slapd_slp_cookie );
			}	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
780
		}
781
782
783
	}
}

784
785
786
static void
slapd_slp_dereg( void )
{
787
	int i;
788
	SLPError err;
789

790
	if ( slapd_srvurls == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
791

792
	for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
793
		err = SLPDereg( slapd_hslp,
794
795
			slapd_srvurls[i],
			slapd_slp_regreport,
796
			&slapd_slp_cookie );
797
		
798
		if ( err != SLP_OK || slapd_slp_cookie != SLP_OK ) {
799
800
801
802
			Debug( LDAP_DEBUG_CONNS,
				"daemon: SLPDereg(%s) failed with %ld, cookie = %ld\n",
				slapd_srvurls[i], (long)err, (long)slapd_slp_cookie );
		}
803
804
805
	}
}
#endif /* HAVE_SLP */
806

807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
#ifdef HAVE_WINSOCK
/* Manage the descriptor to socket table */
ber_socket_t
slapd_socknew( ber_socket_t s )
{
	ber_socket_t i;
	ldap_pvt_thread_mutex_lock( &slapd_ws_mutex );
	for ( i = 0; i < dtblsize && slapd_ws_sockets[i] != INVALID_SOCKET; i++ );
	if ( i == dtblsize ) {
		WSASetLastError( WSAEMFILE );
	} else {
		slapd_ws_sockets[i] = s;
	}
	ldap_pvt_thread_mutex_unlock( &slapd_ws_mutex );
	return i;
}

void
slapd_sockdel( ber_socket_t s )
{
	ldap_pvt_thread_mutex_lock( &slapd_ws_mutex );
	slapd_ws_sockets[s] = INVALID_SOCKET;
	ldap_pvt_thread_mutex_unlock( &slapd_ws_mutex );
}

ber_socket_t
slapd_sock2fd( ber_socket_t s )
{
	ber_socket_t i;
	for ( i=0; i<dtblsize && slapd_ws_sockets[i] != s; i++);
	if ( i == dtblsize )
		i = -1;
	return i;
}
#endif

843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
#ifdef DEBUG_CLOSE
/* Was used to find a bug causing slapd's descriptors to be closed
 * out from under it. Tracked it down to a long-standing (from 2009)
 * bug in Heimdal https://github.com/heimdal/heimdal/issues/431 .
 * Leaving this here for future use, if necessary.
 */
#include <dlfcn.h>
#ifndef RTLD_NEXT
#define RTLD_NEXT	(void *)-1L
#endif
static char *newconns;
typedef int (closefunc)(int fd);
static closefunc *close_ptr;
int close( int s )
{
	if (newconns) {
		Debug( LDAP_DEBUG_CONNS,
			"daemon: close(%ld)\n", s, 0, 0 );
		if (s >= 0 && s < dtblsize && newconns[s])
			assert(newconns[s] == 2);
	}
	return close_ptr ? close_ptr(s) : -1;
}

void slapd_debug_close()
{
	if (dtblsize)
		newconns = ch_calloc(1, dtblsize);
	close_ptr = dlsym(RTLD_NEXT, "close");
}

void slapd_set_close(int fd)
{
	newconns[fd] = 3;
}
#define SETUP_CLOSE()	slapd_debug_close()
#define SET_CLOSE(fd)	slapd_set_close(fd)
#define CLR_CLOSE(fd)	if (newconns[fd]) newconns[fd]--
#else
#define SETUP_CLOSE(fd)
#define SET_CLOSE(fd)
#define CLR_CLOSE(fd)
#endif

887
888
/*
 * Add a descriptor to daemon control
889
890
891
892
 *
 * If isactive, the descriptor is a live server session and is subject
 * to idletimeout control. Otherwise, the descriptor is a passive
 * listener or an outbound client session, and not subject to
Howard Chu's avatar
Howard Chu committed
893
894
 * idletimeout. The underlying event handler may record the Listener
 * argument to differentiate Listener's from real sessions.
895
 */
896
static void
897
slapd_add( ber_socket_t s, int isactive, Listener *sl, int id )
898
{
899
900
901
	if (id < 0)
		id = DAEMON_ID(s);
	ldap_pvt_thread_mutex_lock( &slap_daemon[id].sd_mutex );
902

903
	assert( SLAP_SOCK_NOT_ACTIVE(id, s) );
904

905
	if ( isactive ) slap_daemon[id].sd_nactives++;
906

907
	SLAP_SOCK_ADD(id, s, sl);
908

909
910
	Debug( LDAP_DEBUG_CONNS, "daemon: added %ldr%s listener=%p\n",
		(long) s, isactive ? " (active)" : "", (void *)sl );
911

912
	ldap_pvt_thread_mutex_unlock( &slap_daemon[id].sd_mutex );
913

914
	WAKE_LISTENER(id,1);
915
916
}

917
918
919
/*
 * Remove the descriptor from daemon control
 */
920
921
void
slapd_remove(
922
	ber_socket_t s,
923
	Sockbuf *sb,
924
	int wasactive,
925
926
	int wake,
	int locked )
927
{
928
	int waswriter;
929
	int wasreader;
930
	int id = DAEMON_ID(s);
931

932
	if ( !locked )
933
		ldap_pvt_thread_mutex_lock( &slap_daemon[id].sd_mutex );
934

935
	assert( SLAP_SOCK_IS_ACTIVE( id, s ));
936

937
	if ( wasactive ) slap_daemon[id].sd_nactives--;
938

939
940
	waswriter = SLAP_SOCK_IS_WRITE(id, s);
	wasreader = SLAP_SOCK_IS_READ(id, s);
941

942
	Debug( LDAP_DEBUG_CONNS, "daemon: removing %ld%s%s\n",
943
944
		(long) s,
		wasreader ? "r" : "",
945
		waswriter ? "w" : "" );
946

947
	if ( waswriter ) slap_daemon[id].sd_nwriters--;
948

949
	SLAP_SOCK_DEL(id, s);
950
	CLR_CLOSE(s);
951

Howard Chu's avatar
Howard Chu committed
952
953
	if ( sb )
		ber_sockbuf_free(sb);
954

955
956
957
958
	/* If we ran out of file descriptors, we dropped a listener from
	 * the select() loop. Now that we're removing a session from our
	 * control, we can try to resume a dropped listener to use.
	 */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
959
	if ( emfile && listening ) {
960
961
		int i;
		for ( i = 0; slap_listeners[i] != NULL; i++ ) {
962
			Listener *lr = slap_listeners[i];
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
963

964
965
966
967
968
			if ( lr->sl_sd == AC_SOCKET_INVALID ) continue;
			if ( lr->sl_sd == s ) continue;
			if ( lr->sl_mute ) {
				lr->sl_mute = 0;
				emfile--;
969
970
				if ( DAEMON_ID(lr->sl_sd) != id )
					WAKE_LISTENER(DAEMON_ID(lr->sl_sd), wake);
971
				break;
972
973
974
975
976
			}
		}
		/* Walked the entire list without enabling anything; emfile
		 * counter is stale. Reset it.
		 */
977
		if ( slap_listeners[i] == NULL ) emfile = 0;
978
	}
979
980
	ldap_pvt_thread_mutex_unlock( &slap_daemon[id].sd_mutex );
	WAKE_LISTENER(id, wake || slapd_gentle_shutdown == 2);
981
982
}

983
984
985
void
slapd_clr_write( ber_socket_t s, int wake )
{
986
987
	int id = DAEMON_ID(s);
	ldap_pvt_thread_mutex_lock( &slap_daemon[id].sd_mutex );
988

989
990
	if ( SLAP_SOCK_IS_WRITE( id, s )) {
		assert( SLAP_SOCK_IS_ACTIVE( id, s ));
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
991

992
993
		SLAP_SOCK_CLR_WRITE( id, s );
		slap_daemon[id].sd_nwriters--;
994
	}
995

996
997
	ldap_pvt_thread_mutex_unlock( &slap_daemon[id].sd_mutex );
	WAKE_LISTENER(id,wake);
998
999
}

1000
1001
1002
void
slapd_set_write( ber_socket_t s, int wake )
{
1003
1004
	int id = DAEMON_ID(s);
	ldap_pvt_thread_mutex_lock( &slap_daemon[id].sd_mutex );
1005

1006
	assert( SLAP_SOCK_IS_ACTIVE( id, s ));
1007

1008
1009
1010
	if ( !SLAP_SOCK_IS_WRITE( id, s )) {
		SLAP_SOCK_SET_WRITE( id, s );
		slap_daemon[id].sd_nwriters++;
1011
	}