daemon.c 94 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-2021 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
45
46
47
#ifdef HAVE_SYSTEMD_SD_DAEMON_H
#include <systemd/sd-daemon.h>
#endif

Howard Chu's avatar
Howard Chu committed
48
49
50
51
#ifdef HAVE_POLL
#include <poll.h>
#endif

52
#ifdef HAVE_KQUEUE
53
54
55
56
# include <sys/types.h>
# include <sys/event.h>
# include <sys/time.h>
#elif defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL)
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
57
# include <sys/epoll.h>
58
59
60
61
62
#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>
63
#endif /* ! kqueue && ! epoll && ! /dev/poll */
Howard Chu's avatar
Howard Chu committed
64

Kurt Zeilenga's avatar
Kurt Zeilenga committed
65
#ifdef HAVE_TCPD
66
67
int allow_severity = LOG_INFO;
int deny_severity = LOG_NOTICE;
68
#endif /* TCP Wrappers */
69

Kurt Zeilenga's avatar
Kurt Zeilenga committed
70
#ifdef LDAP_PF_LOCAL
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
71
# include <sys/stat.h>
72
/* this should go in <ldap.h> as soon as it is accepted */
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
73
# define LDAPI_MOD_URLEXT		"x-mod"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
74
#endif /* LDAP_PF_LOCAL */
75

76
#ifdef LDAP_PF_INET6
77
int slap_inet4or6 = AF_UNSPEC;
78
#else /* ! INETv6 */
79
int slap_inet4or6 = AF_INET;
80
#endif /* ! INETv6 */
81

82
/* globals */
83
84
85
time_t starttime;
ber_socket_t dtblsize;
slap_ssf_t local_ssf = LDAP_PVT_SASL_LOCAL_SSF;
86
struct runqueue_s slapd_rq;
87

88
89
90
int slapd_daemon_threads = 1;
int slapd_daemon_mask;

91
92
93
94
95
#ifdef LDAP_TCP_BUFFER
int slapd_tcp_rmem;
int slapd_tcp_wmem;
#endif /* LDAP_TCP_BUFFER */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
96
Listener **slap_listeners = NULL;
97
static volatile sig_atomic_t listening = 1; /* 0 when slap_listeners closed */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
98

99
#ifndef SLAPD_LISTEN_BACKLOG
100
#define SLAPD_LISTEN_BACKLOG 2048
101
#endif /* ! SLAPD_LISTEN_BACKLOG */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
102

103
104
#define	DAEMON_ID(fd)	(fd & slapd_daemon_mask)

105
106
107
typedef ber_socket_t sdpair[2];

static sdpair *wake_sds;
108
static ldap_pvt_thread_mutex_t emfile_mutex;
109
static int emfile;
110

111
static volatile int waking;
112
#define WAKE_LISTENER(l,w)	do { \
Howard Chu's avatar
Howard Chu committed
113
	if (w) { \
Howard Chu's avatar
Howard Chu committed
114
		(void)!tcp_write( SLAP_FD2SOCK(wake_sds[l][1]), "0", 1 ); \
Howard Chu's avatar
Howard Chu committed
115
	} \
116
} while (0)
117

118
119
120
121
ldap_pvt_thread_mutex_t slapd_init_mutex;
ldap_pvt_thread_cond_t slapd_init_cond;
int slapd_ready = 0;

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
122
123
volatile sig_atomic_t slapd_shutdown = 0;
volatile sig_atomic_t slapd_gentle_shutdown = 0;
124
125
volatile sig_atomic_t slapd_abrupt_shutdown = 0;

126
127
128
129
130
131
132
133
134
#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

135
#ifdef HAVE_TCPD
136
static ldap_pvt_thread_mutex_t	sd_tcpd_mutex;
137
138
#endif /* TCP Wrappers */

139
140
141
typedef struct slap_daemon_st {
	ldap_pvt_thread_mutex_t	sd_mutex;

142
143
	ber_socket_t		sd_nactives;
	int			sd_nwriters;
144
	int			sd_nfds;
145
	ldap_pvt_thread_t	sd_tid;
146

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#if defined(HAVE_KQUEUE)
	uint8_t*        sd_fdmodes; /* indexed by fd */
	Listener**      sd_l;       /* indexed by fd */
	/* Double buffer the kqueue changes to avoid holding the sd_mutex \
	 * during a kevent() call. \
	 */
	struct kq_change {
	    struct kevent*  sd_changes;
	    int             sd_nchanges;
	    int             sd_maxchanges;
	}               sd_kqc[2];
	int             sd_changeidx; /* index to current change buffer */
	int             sd_kq;
#elif defined(HAVE_EPOLL)

162
163
164
	struct epoll_event	*sd_epolls;
	int			*sd_index;
	int			sd_epfd;
165
166
167
168
169
170
#elif defined(SLAP_X_DEVPOLL) && defined(HAVE_DEVPOLL)
	/* eXperimental */
	struct pollfd		*sd_pollfd;
	int			*sd_index;
	Listener		**sd_l;
	int			sd_dpfd;
171
#else /* ! kqueue && ! epoll && ! /dev/poll */
172
173
174
175
#ifdef HAVE_WINSOCK
	char	*sd_flags;
	char	*sd_rflags;
#else /* ! HAVE_WINSOCK */
176
177
178
	fd_set			sd_actives;
	fd_set			sd_readers;
	fd_set			sd_writers;
179
#endif /* ! HAVE_WINSOCK */
180
#endif /* ! kqueue && ! epoll && ! /dev/poll */
181
182
} slap_daemon_st;

183
static slap_daemon_st *slap_daemon;
184

185
186
187
188
189
190
191
/*
 * 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
192
 *   EPOLL, DEVPOLL, SELECT, KQUEUE
193
194
195
 *
 * private interface should not be used in the code.
 */
196
#ifdef HAVE_KQUEUE
197
198
# define SLAP_EVENT_FNAME		    "kqueue"
# define SLAP_EVENTS_ARE_INDEXED	0
199
# define SLAP_EVENT_MAX(t)             (2 * dtblsize)  /* each fd can have a read & a write event */
200
201
202
203

# define SLAP_EVENT_DECL \
     static struct kevent* events = NULL

204
# define SLAP_EVENT_INIT(t) do {\
205
    if (!events) { \
206
        events = ch_malloc(sizeof(*events) * SLAP_EVENT_MAX(t)); \
207
208
209
    } \
} while (0)

210
# define SLAP_SOCK_INIT(t) do { \
211
212
    int kq_i; \
    size_t kq_nbytes; \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
213
    Debug(LDAP_DEBUG_ANY, "daemon: SLAP_SOCK_INIT: dtblsize=%d\n", dtblsize); \
214
215
    slap_daemon[t].sd_nfds       = 0; \
    slap_daemon[t].sd_changeidx  = 0; \
216
    for (kq_i = 0;  kq_i < 2;  kq_i++) { \
217
        struct kq_change* kqc = &slap_daemon[t].sd_kqc[kq_i]; \
218
219
220
221
222
        kqc->sd_nchanges   = 0; \
        kqc->sd_maxchanges = 256; /* will grow as needed */ \
        kq_nbytes = sizeof(*kqc->sd_changes) * kqc->sd_maxchanges; \
        kqc->sd_changes = ch_calloc(1, kq_nbytes); \
    } \
223
224
225
226
227
    kq_nbytes = sizeof(*slap_daemon[t].sd_fdmodes) * dtblsize; \
    slap_daemon[t].sd_fdmodes = ch_calloc(1, kq_nbytes); \
    kq_nbytes = sizeof(*slap_daemon[t].sd_l) * dtblsize; \
    slap_daemon[t].sd_l = ch_calloc(1, kq_nbytes); \
    slap_daemon[t].sd_kq = kqueue(); \
228
229
} while (0)

230
231
232
233
234
235
236
237
/* a kqueue fd obtained before a fork can't be used in child process.
 * close it and reacquire it.
 */
# define SLAP_SOCK_INIT2() do { \
	close(slap_daemon[0].sd_kq); \
	slap_daemon[0].sd_kq = kqueue(); \
} while (0)

238
# define SLAP_SOCK_DESTROY(t) do { \
239
	int kq_i; \
240
241
242
    if (slap_daemon[t].sd_kq > 0) { \
        close(slap_daemon[t].sd_kq); \
        slap_daemon[t].sd_kq = -1; \
243
244
    } \
    for (kq_i = 0;  kq_i < 2;  kq_i++) { \
245
246
247
        if (slap_daemon[t].sd_kqc[kq_i].sd_changes != NULL) { \
            ch_free(slap_daemon[t].sd_kqc[kq_i].sd_changes); \
            slap_daemon[t].sd_kqc[kq_i].sd_changes = NULL; \
248
        } \
249
250
        slap_daemon[t].sd_kqc[kq_i].sd_nchanges = 0; \
        slap_daemon[t].sd_kqc[kq_i].sd_maxchanges = 0; \
251
    } \
252
253
254
    if (slap_daemon[t].sd_l != NULL) { \
        ch_free(slap_daemon[t].sd_l); \
        slap_daemon[t].sd_l = NULL; \
255
    } \
256
257
258
    if (slap_daemon[t].sd_fdmodes != NULL) { \
        ch_free(slap_daemon[t].sd_fdmodes); \
        slap_daemon[t].sd_fdmodes = NULL; \
259
    } \
260
    slap_daemon[t].sd_nfds = 0; \
261
262
263
264
265
266
} while (0)

# define SLAP_KQUEUE_SOCK_ACTIVE        0x01
# define SLAP_KQUEUE_SOCK_READ_ENABLED  0x02
# define SLAP_KQUEUE_SOCK_WRITE_ENABLED 0x04

267
268
269
270
# define SLAP_SOCK_IS_ACTIVE(t,s)  (slap_daemon[t].sd_fdmodes[(s)] != 0)
# define SLAP_SOCK_NOT_ACTIVE(t,s) (slap_daemon[t].sd_fdmodes[(s)] == 0)
# define SLAP_SOCK_IS_READ(t,s)    (slap_daemon[t].sd_fdmodes[(s)] & SLAP_KQUEUE_SOCK_READ_ENABLED)
# define SLAP_SOCK_IS_WRITE(t,s)   (slap_daemon[t].sd_fdmodes[(s)] & SLAP_KQUEUE_SOCK_WRITE_ENABLED)
271
272
273
274
275
276
277

/*
 * SLAP_SOCK_SET_* & SLAP_SOCK_CLR_* get called a _lot_.  Since kevent()
 * processes changes before it looks for events, batch up the changes which
 * will get submitted the next time kevent() is called for events.
 */

278
# define SLAP_KQUEUE_CHANGE(t, s, filter, flag) do { \
279
280
281
282
    /* If maxchanges is reached, have to realloc to make room for more. \
     * Ideally we'd call kevent(), but the daemon thread could be sitting \
     * in kevent() waiting for events. \
     */ \
283
    struct kq_change* kqc = &slap_daemon[t].sd_kqc[slap_daemon[t].sd_changeidx]; \
284
285
286
287
288
    if (kqc->sd_nchanges == kqc->sd_maxchanges) { \
        /* Don't want to do this very often.  Double the size. */ \
        size_t kq_nbytes; \
        Debug(LDAP_DEBUG_CONNS, \
              "daemon: SLAP_KQUEUE_CHANGE: increasing slap_daemon.sd_kqc[%d].maxchanges from %d to %d\n", \
289
              slap_daemon[t].sd_changeidx, kqc->sd_maxchanges, 2*kqc->sd_maxchanges); \
290
291
292
293
294
        kqc->sd_maxchanges += kqc->sd_maxchanges; \
        kq_nbytes = sizeof(*kqc->sd_changes) * kqc->sd_maxchanges; \
        kqc->sd_changes = ch_realloc(kqc->sd_changes, kq_nbytes); \
    } \
    EV_SET(&kqc->sd_changes[kqc->sd_nchanges++], \
295
           (s), (filter), (flag), 0, 0, slap_daemon[t].sd_l[(s)]); \
296
297
} while (0)

298
299
300
301
# define SLAP_KQUEUE_SOCK_SET(t, s, filter, mode) do { \
    if ((slap_daemon[t].sd_fdmodes[(s)] & (mode)) != (mode)) { \
        slap_daemon[t].sd_fdmodes[(s)] |= (mode); \
        SLAP_KQUEUE_CHANGE(t, (s), (filter), EV_ENABLE); \
302
303
304
    } \
} while (0)

305
306
307
308
# define SLAP_KQUEUE_SOCK_CLR(t, s, filter, mode) do { \
    if (slap_daemon[t].sd_fdmodes[(s)] & (mode)) { \
        slap_daemon[t].sd_fdmodes[(s)] &= ~(mode); \
        SLAP_KQUEUE_CHANGE(t, (s), (filter), EV_DISABLE); \
309
310
311
    } \
} while (0)

312
313
314
315
# define SLAP_SOCK_SET_READ(t, s)  SLAP_KQUEUE_SOCK_SET(t, (s), EVFILT_READ,  SLAP_KQUEUE_SOCK_READ_ENABLED)
# define SLAP_SOCK_SET_WRITE(t, s) SLAP_KQUEUE_SOCK_SET(t, (s), EVFILT_WRITE, SLAP_KQUEUE_SOCK_WRITE_ENABLED)
# define SLAP_SOCK_CLR_READ(t, s)  SLAP_KQUEUE_SOCK_CLR(t, (s), EVFILT_READ,  SLAP_KQUEUE_SOCK_READ_ENABLED)
# define SLAP_SOCK_CLR_WRITE(t, s) SLAP_KQUEUE_SOCK_CLR(t, (s), EVFILT_WRITE, SLAP_KQUEUE_SOCK_WRITE_ENABLED)
316
317
318
319
320

/* kqueue doesn't need to do anything to clear the event. */
# define SLAP_EVENT_CLR_READ(i)     do {} while (0)
# define SLAP_EVENT_CLR_WRITE(i)    do {} while (0)

321
# define SLAP_SOCK_ADD(t, s, l) do { \
322
    assert( s < dtblsize ); \
323
324
325
326
327
    slap_daemon[t].sd_l[(s)] = (l); \
    slap_daemon[t].sd_fdmodes[(s)] = SLAP_KQUEUE_SOCK_ACTIVE | SLAP_KQUEUE_SOCK_READ_ENABLED; \
    ++slap_daemon[t].sd_nfds; \
    SLAP_KQUEUE_CHANGE(t, (s), EVFILT_READ, EV_ADD); \
    SLAP_KQUEUE_CHANGE(t, (s), EVFILT_WRITE, EV_ADD | EV_DISABLE); \
328
329
} while (0)

330
331
332
333
334
335
# define SLAP_SOCK_DEL(t, s) do { \
    SLAP_KQUEUE_CHANGE(t, (s), EVFILT_READ, EV_DELETE); \
    SLAP_KQUEUE_CHANGE(t, (s), EVFILT_WRITE, EV_DELETE); \
    slap_daemon[t].sd_l[(s)] = NULL; \
    slap_daemon[t].sd_fdmodes[(s)] = 0; \
    --slap_daemon[t].sd_nfds; \
336
337
} while (0)

338
# define SLAP_EVENT_FD(t, i)          (events[(i)].ident)
339

340
341
# define SLAP_EVENT_IS_READ(t, i) \
    (events[(i)].filter == EVFILT_READ && SLAP_SOCK_IS_READ(t, SLAP_EVENT_FD(0, i)))
342

343
344
# define SLAP_EVENT_IS_WRITE(t, i) \
    (events[(i)].filter == EVFILT_WRITE && SLAP_SOCK_IS_WRITE(t, SLAP_EVENT_FD(0, i)))
345

346
347
# define SLAP_EVENT_IS_LISTENER(t, i) \
    (events[(i)].udata && SLAP_SOCK_IS_READ(t, SLAP_EVENT_FD(t, i)))
348

349
350
351
# define SLAP_EVENT_LISTENER(t, i)    ((Listener*)(events[(i)].udata))

# define SLAP_EVENT_WAIT(t, tvp, nsp) do { \
352
353
354
355
356
357
358
359
360
361
362
363
    struct timespec  kq_ts; \
    struct timespec* kq_tsp; \
    int kq_idx; \
    if (tvp) { \
        TIMEVAL_TO_TIMESPEC((tvp), &kq_ts); \
        kq_tsp = &kq_ts; \
    } else { \
        kq_tsp = NULL; \
    } \
    /* Save the change buffer index for use when the mutex is unlocked, \
     * then switch the index so new changes go to the other buffer. \
     */ \
364
365
366
367
368
369
370
371
372
373
    ldap_pvt_thread_mutex_lock( &slap_daemon[t].sd_mutex ); \
    kq_idx = slap_daemon[t].sd_changeidx; \
    slap_daemon[t].sd_changeidx ^= 1; \
    ldap_pvt_thread_mutex_unlock( &slap_daemon[t].sd_mutex ); \
    *(nsp) = kevent(slap_daemon[t].sd_kq, \
                    slap_daemon[t].sd_kqc[kq_idx].sd_nchanges \
                        ? slap_daemon[t].sd_kqc[kq_idx].sd_changes : NULL, \
                    slap_daemon[t].sd_kqc[kq_idx].sd_nchanges, \
                    events, SLAP_EVENT_MAX(t), kq_tsp); \
    slap_daemon[t].sd_kqc[kq_idx].sd_nchanges = 0; \
374
375
376
377
378
} while(0)

/*-------------------------------------------------------------------------------*/

#elif defined(HAVE_EPOLL)
379
380
381
382
/***************************************
 * Use epoll infrastructure - epoll(4) *
 ***************************************/
# define SLAP_EVENT_FNAME		"epoll"
383
# define SLAP_EVENTS_ARE_INDEXED	0
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# 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) ); \
399
	} \
400
} while (0)
401

402
403
404
405
406
# 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) ); \
407
	} \
408
409
} while (0)

410
411
# 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)
412

413
414
# 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)
415

416
417
418
419
420
421
#  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 )
422

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

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

Howard Chu's avatar
Howard Chu committed
427
428
/* If a Listener address is provided, store that as the epoll data.
 * Otherwise, store the address of this socket's slot in the
429
430
 * 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
431
 */
432
# define SLAP_SOCK_ADD(t, s, l)		do { \
433
	int rc; \
434
435
436
437
438
	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))); \
439
	if ( rc == 0 ) { \
440
		slap_daemon[t].sd_nfds++; \
441
	} else { \
442
		int saved_errno = errno; \
443
		Debug( LDAP_DEBUG_ANY, \
444
			"daemon: epoll_ctl(ADD,fd=%d) failed, errno=%d, shutting down\n", \
445
			s, saved_errno ); \
446
447
448
449
		slapd_shutdown = 2; \
	} \
} while (0)

450
451
452
# define SLAP_EPOLL_EV_LISTENER(t,ptr) \
	(((int *)(ptr) >= slap_daemon[t].sd_index && \
	(int *)(ptr) <= &slap_daemon[t].sd_index[dtblsize]) ? 0 : 1 )
453

454
# define SLAP_EPOLL_EV_PTRFD(t,ptr)		(SLAP_EPOLL_EV_LISTENER(t,ptr) ? \
455
	((Listener *)ptr)->sl_sd : \
456
	(ber_socket_t) ((int *)(ptr) - slap_daemon[t].sd_index))
457

458
459
# define SLAP_SOCK_DEL(t,s)		do { \
	int fd, rc, index = SLAP_EPOLL_SOCK_IX(t,(s)); \
460
	if ( index < 0 ) break; \
461
462
463
464
465
466
467
468
	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--; \
469
470
} while (0)

471
472
# define SLAP_EVENT_CLR_READ(i)		SLAP_EPOLL_EVENT_CLR((i), EPOLLIN)
# define SLAP_EVENT_CLR_WRITE(i)	SLAP_EPOLL_EVENT_CLR((i), EPOLLOUT)
473

474
# define SLAP_EPOLL_EVENT_CHK(i, mode)	(revents[(i)].events & mode)
475

476
477
# define SLAP_EVENT_IS_READ(i)		SLAP_EPOLL_EVENT_CHK((i), EPOLLIN)
# define SLAP_EVENT_IS_WRITE(i)		SLAP_EPOLL_EVENT_CHK((i), EPOLLOUT)
478
479
# 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))
480

481
# define SLAP_EVENT_FD(t,i)		SLAP_EPOLL_EV_PTRFD(t,revents[(i)].data.ptr)
482

483
484
485
# define SLAP_SOCK_INIT(t)		do { \
	int j; \
	slap_daemon[t].sd_epolls = ch_calloc(1, \
486
487
		( sizeof(struct epoll_event) * 2 \
			+ sizeof(int) ) * dtblsize * 2); \
488
489
490
	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; \
491
492
} while (0)

493
494
# define SLAP_SOCK_INIT2()

495
496
497
498
499
500
# 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 ); \
501
502
503
	} \
} while ( 0 )

504
# define SLAP_EVENT_DECL		struct epoll_event *revents
505

506
507
# define SLAP_EVENT_INIT(t)		do { \
	revents = slap_daemon[t].sd_epolls + dtblsize; \
508
509
} while (0)

510
511
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
	*(nsp) = epoll_wait( slap_daemon[t].sd_epfd, revents, \
512
		dtblsize, (tvp) ? ((tvp)->tv_sec * 1000 + (tvp)->tv_usec / 1000) : -1 ); \
513
} while (0)
514

515
#elif defined(SLAP_X_DEVPOLL) && defined(HAVE_DEVPOLL)
Howard Chu's avatar
Howard Chu committed
516

517
518
519
520
521
522
523
524
525
526
527
528
/*************************************************************
 * 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
 */
529
530
531
532
533
534
535
536
537
538
539
# 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)
540
541
542
543

/* 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 */
544
# define SLAP_DEVPOLL_WRITE_POLLFD(t,s, pfd, n, what, shdn)	do { \
545
546
547
	int rc; \
	size_t size = (n) * sizeof( struct pollfd ); \
	/* FIXME: use pwrite? */ \
548
	rc = write( slap_daemon[t].sd_dpfd, (pfd), size ); \
549
	if ( rc != size ) { \
550
		int saved_errno = errno; \
551
552
		Debug( LDAP_DEBUG_ANY, "daemon: " SLAP_EVENT_FNAME ": " \
			"%s fd=%d failed errno=%d\n", \
553
			(what), (s), saved_errno ); \
554
555
556
557
558
559
		if ( (shdn) ) { \
			slapd_shutdown = 2; \
		} \
	} \
} while (0)

560
# define SLAP_DEVPOLL_SOCK_SET(t,s, mode) 	do { \
561
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_SET_%s(%d)=%d\n", \
562
		(mode) == POLLIN ? "READ" : "WRITE", (s), \
563
564
		( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) != (mode) ) ); \
	if ( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) != (mode) ) { \
565
		struct pollfd pfd; \
566
567
568
569
		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); \
570
571
572
	} \
} while (0)

573
# define SLAP_DEVPOLL_SOCK_CLR(t,s, mode)		do { \
574
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_CLR_%s(%d)=%d\n", \
575
		(mode) == POLLIN ? "READ" : "WRITE", (s), \
576
577
		( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) == (mode) ) ); \
	if ((SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) == (mode) ) { \
578
		struct pollfd pfd[2]; \
579
580
		SLAP_DEVPOLL_SOCK_EV(t,(s)) &= ~(mode); \
		pfd[0].fd = SLAP_DEVPOLL_SOCK_FD(t,(s)); \
581
		pfd[0].events = POLLREMOVE; \
582
583
		pfd[1] = SLAP_DEVPOLL_SOCK_EP(t,(s)); \
		SLAP_DEVPOLL_WRITE_POLLFD(t,(s), &pfd[0], 2, "CLR", 0); \
584
585
586
	} \
} while (0)

587
588
# 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)
589

590
591
# 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)
592

593
594
595
596
597
598
#  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 )
599
600
601

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

602
# define SLAP_EVENT_MAX(t)			slap_daemon[t].sd_nfds
603
604
605
606
607

/* 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.
 */
608
# define SLAP_SOCK_ADD(t, s, l)		do { \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
609
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_ADD(%d, %p)\n", (s), (l) ); \
610
611
612
613
	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; \
614
	SLAP_DEVPOLL_WRITE_POLLFD(t,(s), &SLAP_DEVPOLL_SOCK_EP(t, (s)), 1, "ADD", 1); \
615
	slap_daemon[t].sd_nfds++; \
616
617
618
619
} while (0)

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

620
621
# define SLAP_SOCK_DEL(t,s)		do { \
	int fd, index = SLAP_DEVPOLL_SOCK_IX(t,(s)); \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
622
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_DEL(%d)\n", (s) ); \
623
	if ( index < 0 ) break; \
624
625
626
627
628
629
	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; \
630
	} \
631
632
633
634
635
	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--; \
636
637
638
639
640
641
642
} 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))

643
# define SLAP_EVENT_FD(t,i)		(revents[(i)].fd)
644
645
646

# define SLAP_EVENT_IS_READ(i)		SLAP_DEVPOLL_EVENT_CHK((i), POLLIN)
# define SLAP_EVENT_IS_WRITE(i)		SLAP_DEVPOLL_EVENT_CHK((i), POLLOUT)
647
648
# define SLAP_EVENT_IS_LISTENER(t,i)	SLAP_DEVPOLL_EV_LISTENER(SLAP_DEVPOLL_SOCK_LX(t, SLAP_EVENT_FD(t,(i))))
# define SLAP_EVENT_LISTENER(t,i)		SLAP_DEVPOLL_SOCK_LX(t, SLAP_EVENT_FD(t,(i)))
649

650
651
652
653
654
655
656
657
658
659
# 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 ); \
	} \
} while ( 0 )

660
661
# define SLAP_SOCK_INIT(t)		do { \
	slap_daemon[t].sd_pollfd = ch_calloc( 1, \
662
663
664
		( sizeof(struct pollfd) * 2 \
			+ sizeof( int ) \
			+ sizeof( Listener * ) ) * dtblsize ); \
665
666
667
668
	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 ) { \
669
		int saved_errno = errno; \
670
671
		Debug( LDAP_DEBUG_ANY, "daemon: " SLAP_EVENT_FNAME ": " \
			"open(\"" SLAP_EVENT_FNAME "\") failed errno=%d\n", \
672
			saved_errno ); \
673
		SLAP_SOCK_DESTROY(t); \
674
675
676
		return -1; \
	} \
	for ( i = 0; i < dtblsize; i++ ) { \
677
678
		slap_daemon[t].sd_pollfd[i].fd = -1; \
		slap_daemon[t].sd_index[i] = -1; \
679
680
681
	} \
} while (0)

682
683
# define SLAP_SOCK_INIT2()

684
685
# define SLAP_EVENT_DECL		struct pollfd *revents

686
687
# define SLAP_EVENT_INIT(t)		do { \
	revents = &slap_daemon[t].sd_pollfd[ dtblsize ]; \
688
689
} while (0)

690
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
691
	struct dvpoll		sd_dvpoll; \
692
	sd_dvpoll.dp_timeout = (tvp) ? ((tvp)->tv_sec * 1000 + (tvp)->tv_usec / 1000) : -1; \
693
694
	sd_dvpoll.dp_nfds = dtblsize; \
	sd_dvpoll.dp_fds = revents; \
695
	*(nsp) = ioctl( slap_daemon[t].sd_dpfd, DP_POLL, &sd_dvpoll ); \
696
697
} while (0)

698
#else /* ! kqueue && ! epoll && ! /dev/poll */
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
# 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
719
720
# define SLAP_EVENT_DECL		fd_set readfds, writefds; char *rflags
# define SLAP_EVENT_INIT(t)	do { \
721
722
723
	int i; \
	FD_ZERO( &readfds ); \
	FD_ZERO( &writefds ); \
724
725
726
727
	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 ) \
728
			FD_SET( slapd_ws_sockets[i], &readfds );\
729
		if ( slap_daemon[t].sd_flags[i] & SD_WRITE ) \
730
731
732
			FD_SET( slapd_ws_sockets[i], &writefds ); \
	} } while ( 0 )

733
# define SLAP_EVENT_MAX(t)		slap_daemon[t].sd_nfds
734

735
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
736
	int i; \
Pierangelo Masarati's avatar
Pierangelo Masarati committed
737
	*(nsp) = select( SLAP_EVENT_MAX(t), &readfds, \
738
739
740
741
		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 ) { \
742
			slap_daemon[t].sd_rflags[fd] = SD_READ; \
743
744
745
746
747
748
			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 ) { \
749
			slap_daemon[t].sd_rflags[fd] = SD_WRITE; \
750
751
752
753
754
			if ( fd >= *(nsp)) *(nsp) = fd+1; \
		} \
	} \
} while (0)

755
756
# define SLAP_EVENT_IS_READ(fd)		(rflags[fd] & SD_READ)
# define SLAP_EVENT_IS_WRITE(fd)	(rflags[fd] & SD_WRITE)
757

758
759
# define SLAP_EVENT_CLR_READ(fd) 	rflags[fd] &= ~SD_READ
# define SLAP_EVENT_CLR_WRITE(fd)	rflags[fd] &= ~SD_WRITE
760

761
762
# define SLAP_SOCK_INIT(t)		do { \
	if (!t) { \
763
764
765
	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) ); \
766
767
768
769
	} \
	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 ); \
Howard Chu's avatar
Howard Chu committed
770
771
	slapd_ws_sockets[t*2] = wake_sds[t][0]; \
	slapd_ws_sockets[t*2+1] = wake_sds[t][1]; \
772
773
	wake_sds[t][0] = t*2; \
	wake_sds[t][1] = t*2+1; \
Howard Chu's avatar
Howard Chu committed
774
	slap_daemon[t].sd_nfds = t*2 + 2; \
775
776
	} while ( 0 )

777
778
# define SLAP_SOCK_INIT2()

779
# define SLAP_SOCK_DESTROY(t)	do { \
780
	ch_free( slapd_ws_sockets ); slapd_ws_sockets = NULL; \
781
782
	slap_daemon[t].sd_flags = NULL; \
	slap_daemon[t].sd_rflags = NULL; \
783
784
785
	ldap_pvt_thread_mutex_destroy( &slapd_ws_mutex ); \
	} while ( 0 )

786
787
788
789
# 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])
790

791
792
# 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 )
793

794
795
# define SLAP_SELECT_ADDTEST(t,s)	do { \
	if ((s) >= slap_daemon[t].sd_nfds) slap_daemon[t].sd_nfds = (s)+1; \
796
797
} while (0)

798
799
# 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 )
800

801
802
803
# define SLAP_SOCK_ADD(t,s, l)	do { \
	SLAP_SELECT_ADDTEST(t,(s)); \
	slap_daemon[t].sd_flags[s] = SD_ACTIVE|SD_READ; \
804
805
} while ( 0 )

806
807
# define SLAP_SOCK_DEL(t,s) do { \
	slap_daemon[t].sd_flags[s] = 0; \
808
809
810
811
	slapd_sockdel( s ); \
} while ( 0 )

# else /* !HAVE_WINSOCK */
812
813
814
815
816

/**************************************
 * Use select system call - select(2) *
 **************************************/
# define SLAP_EVENT_FNAME		"select"
817
/* select */
818
819
# define SLAP_EVENTS_ARE_INDEXED	1
# define SLAP_EVENT_DECL		fd_set readfds, writefds
820

821
822
# define SLAP_EVENT_INIT(t)		do { \
	AC_MEMCPY( &readfds, &slap_daemon[t].sd_readers, sizeof(fd_set) );	\
823
	if ( nwriters )	{ \
824
		AC_MEMCPY( &writefds, &slap_daemon[t].sd_writers, sizeof(fd_set) ); \
825
826
827
828
829
830
	} else { \
		FD_ZERO( &writefds ); \
	} \
} while (0)

# ifdef FD_SETSIZE
831
#  define SLAP_SELECT_CHK_SETSIZE	do { \
832
833
	if (dtblsize > FD_SETSIZE) dtblsize = FD_SETSIZE; \
} while (0)
834
835
836
# else /* ! FD_SETSIZE */
#  define SLAP_SELECT_CHK_SETSIZE	do { ; } while (0)
# endif /* ! FD_SETSIZE */
837

838
# define SLAP_SOCK_INIT(t)			do { \
839
	SLAP_SELECT_CHK_SETSIZE; \
840
841
842
	FD_ZERO(&slap_daemon[t].sd_actives); \
	FD_ZERO(&slap_daemon[t].sd_readers); \
	FD_ZERO(&slap_daemon[t].sd_writers); \
843
844
} while (0)

845
846
# define SLAP_SOCK_INIT2()

847
# define SLAP_SOCK_DESTROY(t)
848

849
850
851
# 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)
852

853
854
# 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))
855

856
857
# 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)
858

859
860
861
# 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; \
862
863
} while (0)

864
865
# 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)
866

867
868
869
870
# 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); \
871
} while (0)
872

873
874
875
876
# 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); \
877
} while (0)
878

879
880
# define SLAP_EVENT_IS_READ(fd)		FD_ISSET((fd), &readfds)
# define SLAP_EVENT_IS_WRITE(fd)	FD_ISSET((fd), &writefds)
881

882
883
# define SLAP_EVENT_CLR_READ(fd) 	FD_CLR((fd), &readfds)
# define SLAP_EVENT_CLR_WRITE(fd)	FD_CLR((fd), &writefds)
884

885
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
Pierangelo Masarati's avatar
Pierangelo Masarati committed
886
	*(nsp) = select( SLAP_EVENT_MAX(t), &readfds, \
887
888
		nwriters > 0 ? &writefds : NULL, NULL, (tvp) ); \
} while (0)
889
# endif /* !HAVE_WINSOCK */
890
#endif /* ! kqueue && ! epoll && ! /dev/poll */
891
892
893
894
895
896
897
898

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

#define LDAP_SRVTYPE_PREFIX "service:ldap://"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
899
900
#define LDAPS_SRVTYPE_PREFIX "service:ldaps://"
static char** slapd_srvurls = NULL;
901
static SLPHandle slapd_hslp = 0;
902
int slapd_register_slp = 0;
903
const char *slapd_slp_attrs = NULL;
904
905

static SLPError slapd_slp_cookie;
906

907
908
909
static void
slapd_slp_init( const char* urls )
{
910
	int i;
911
	SLPError err;
912

913
	slapd_srvurls = ldap_str2charray( urls, " " );
914

915
	if ( slapd_srvurls == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
916
917

	/* find and expand INADDR_ANY URLs */
918
919
	for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
		if ( strcmp( slapd_srvurls[i], "ldap:///" ) == 0 ) {
Howard Chu's avatar
Howard Chu committed
920
			slapd_srvurls[i] = (char *) ch_realloc( slapd_srvurls[i],
921
				global_host_bv.bv_len +
Howard Chu's avatar
Howard Chu committed
922
923
				sizeof( LDAP_SRVTYPE_PREFIX ) );
			strcpy( lutil_strcopy(slapd_srvurls[i],
924
				LDAP_SRVTYPE_PREFIX ), global_host_bv.bv_val );
925
		} else if ( strcmp( slapd_srvurls[i], "ldaps:///" ) == 0 ) {
Howard Chu's avatar
Howard Chu committed
926
			slapd_srvurls[i] = (char *) ch_realloc( slapd_srvurls[i],
927
				global_host_bv.bv_len +
Howard Chu's avatar
Howard Chu committed
928
929
				sizeof( LDAPS_SRVTYPE_PREFIX ) );
			strcpy( lutil_strcopy(slapd_srvurls[i],
930
				LDAPS_SRVTYPE_PREFIX ), global_host_bv.bv_val );
931
932
933
934
		}
	}

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

937
	if ( err != SLP_OK ) {
938
		Debug( LDAP_DEBUG_CONNS, "daemon: SLPOpen() failed with %ld\n",
939
			(long)err );
940
	}
941
942
}

943
944
945
946
static void
slapd_slp_deinit( void )
{
	if ( slapd_srvurls == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
947

948
	ldap_charray_free( slapd_srvurls );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
949
	slapd_srvurls = NULL;
950
951
952
953
954

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

955
956
957
958
959
static void
slapd_slp_regreport(
	SLPHandle	hslp,
	SLPError	errcode,
	void		*cookie )
960
{
961
962
	/* return the error code in the cookie */
	*(SLPError*)cookie = errcode; 
963
964
}

965
966
967
static void
slapd_slp_reg()
{
968
	int i;
969
	SLPError err;
970

971
	if ( slapd_srvurls == NULL ) return;
972

973
974
	for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
		if ( strncmp( slapd_srvurls[i], LDAP_SRVTYPE_PREFIX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
975
				sizeof( LDAP_SRVTYPE_PREFIX ) - 1 ) == 0 ||
976
			strncmp( slapd_srvurls[i], LDAPS_SRVTYPE_PREFIX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
977
978
				sizeof( LDAPS_SRVTYPE_PREFIX ) - 1 ) == 0 )
		{
979
			err = SLPReg( slapd_hslp,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
980
981
982
				slapd_srvurls[i],
				SLP_LIFETIME_MAXIMUM,
				"ldap",
983
984
				(slapd_slp_attrs) ? slapd_slp_attrs : "",
				SLP_TRUE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
985
				slapd_slp_regreport,
986
				&slapd_slp_cookie );
987

988
			if ( err != SLP_OK || slapd_slp_cookie != SLP_OK ) {
989
990
991
992
				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
993
		}
994
995
996
	}
}

997
998
999
static void
slapd_slp_dereg( void )
{
1000
	int i;
1001
	SLPError err;
1002

1003
	if ( slapd_srvurls == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1004

1005
	for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
1006
		err = SLPDereg( slapd_hslp,
1007
1008
			slapd_srvurls[i],
			slapd_slp_regreport,
1009
			&slapd_slp_cookie );
1010
		
1011
		if ( err != SLP_OK || slapd_slp_cookie != SLP_OK ) {
1012
1013
1014
1015
			Debug( LDAP_DEBUG_CONNS,
				"daemon: SLPDereg(%s) failed with %ld, cookie = %ld\n",
				slapd_srvurls[i], (long)err, (long)slapd_slp_cookie );
		}
Kurt Zeilenga's avatar