daemon.c 91.1 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"

Howard Chu's avatar
Howard Chu committed
44
45
46
47
#ifdef HAVE_POLL
#include <poll.h>
#endif

48
#ifdef HAVE_KQUEUE
49
50
51
52
# 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
53
# include <sys/epoll.h>
54
55
56
57
58
#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>
59
#endif /* ! kqueue && ! epoll && ! /dev/poll */
Howard Chu's avatar
Howard Chu committed
60

Kurt Zeilenga's avatar
Kurt Zeilenga committed
61
#ifdef HAVE_TCPD
62
63
int allow_severity = LOG_INFO;
int deny_severity = LOG_NOTICE;
64
#endif /* TCP Wrappers */
65

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

72
#ifdef LDAP_PF_INET6
73
int slap_inet4or6 = AF_UNSPEC;
74
#else /* ! INETv6 */
75
int slap_inet4or6 = AF_INET;
76
#endif /* ! INETv6 */
77

78
/* globals */
79
80
81
time_t starttime;
ber_socket_t dtblsize;
slap_ssf_t local_ssf = LDAP_PVT_SASL_LOCAL_SSF;
82
struct runqueue_s slapd_rq;
83

84
85
86
#ifndef SLAPD_MAX_DAEMON_THREADS
#define SLAPD_MAX_DAEMON_THREADS	16
#endif
87
88
89
int slapd_daemon_threads = 1;
int slapd_daemon_mask;

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
95
Listener **slap_listeners = NULL;
96
static volatile sig_atomic_t listening = 1; /* 0 when slap_listeners closed */
97
static ldap_pvt_thread_t *listener_tid;
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
static ber_socket_t wake_sds[SLAPD_MAX_DAEMON_THREADS][2];
106
static ldap_pvt_thread_mutex_t emfile_mutex;
107
static int emfile;
108

109
static volatile int waking;
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
} while (0)
115

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

120
121
122
123
124
125
126
127
128
#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

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

133
134
135
typedef struct slap_daemon_st {
	ldap_pvt_thread_mutex_t	sd_mutex;

136
137
	ber_socket_t		sd_nactives;
	int			sd_nwriters;
138
	int			sd_nfds;
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#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)

155
156
157
	struct epoll_event	*sd_epolls;
	int			*sd_index;
	int			sd_epfd;
158
159
160
161
162
163
#elif defined(SLAP_X_DEVPOLL) && defined(HAVE_DEVPOLL)
	/* eXperimental */
	struct pollfd		*sd_pollfd;
	int			*sd_index;
	Listener		**sd_l;
	int			sd_dpfd;
164
#else /* ! kqueue && ! epoll && ! /dev/poll */
165
166
167
168
#ifdef HAVE_WINSOCK
	char	*sd_flags;
	char	*sd_rflags;
#else /* ! HAVE_WINSOCK */
169
170
171
	fd_set			sd_actives;
	fd_set			sd_readers;
	fd_set			sd_writers;
172
#endif /* ! HAVE_WINSOCK */
173
#endif /* ! kqueue && ! epoll && ! /dev/poll */
174
175
} slap_daemon_st;

176
static slap_daemon_st slap_daemon[SLAPD_MAX_DAEMON_THREADS];
177

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

# define SLAP_EVENT_DECL \
     static struct kevent* events = NULL

197
# define SLAP_EVENT_INIT(t) do {\
198
    if (!events) { \
199
        events = ch_malloc(sizeof(*events) * SLAP_EVENT_MAX(t)); \
200
201
202
        if (!events) { \
            Debug(LDAP_DEBUG_ANY, \
                "daemon: SLAP_EVENT_INIT: ch_malloc of events failed, wanted %d bytes\n", \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
203
                sizeof(*events) * SLAP_EVENT_MAX(t)); \
204
205
206
207
208
                slapd_shutdown = 2; \
        } \
    } \
} while (0)

209
# define SLAP_SOCK_INIT(t) do { \
210
211
    int kq_i; \
    size_t kq_nbytes; \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
212
    Debug(LDAP_DEBUG_ANY, "daemon: SLAP_SOCK_INIT: dtblsize=%d\n", dtblsize); \
213
214
    slap_daemon[t].sd_nfds       = 0; \
    slap_daemon[t].sd_changeidx  = 0; \
215
    for (kq_i = 0;  kq_i < 2;  kq_i++) { \
216
        struct kq_change* kqc = &slap_daemon[t].sd_kqc[kq_i]; \
217
218
219
220
221
222
223
        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); \
        if (!kqc->sd_changes) { \
            Debug(LDAP_DEBUG_ANY, \
                  "daemon: SLAP_SOCK_INIT: ch_calloc of slap_daemon.sd_changes[%d] failed, wanted %d bytes, shutting down\n", \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
224
                  kq_i, kq_nbytes); \
225
226
227
                  slapd_shutdown = 2; \
        } \
    } \
228
229
230
    kq_nbytes = sizeof(*slap_daemon[t].sd_fdmodes) * dtblsize; \
    slap_daemon[t].sd_fdmodes = ch_calloc(1, kq_nbytes); \
    if (!slap_daemon[t].sd_fdmodes) { \
231
232
        Debug(LDAP_DEBUG_ANY, \
            "daemon: SLAP_SOCK_INIT: ch_calloc of slap_daemon.sd_fdmodes failed, wanted %d bytes, shutting down\n", \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
233
            kq_nbytes); \
234
235
        slapd_shutdown = 2; \
    } \
236
237
238
    kq_nbytes = sizeof(*slap_daemon[t].sd_l) * dtblsize; \
    slap_daemon[t].sd_l = ch_calloc(1, kq_nbytes); \
    if (!slap_daemon[t].sd_l) { \
239
240
        Debug(LDAP_DEBUG_ANY, \
            "daemon: SLAP_SOCK_INIT: ch_calloc of slap_daemon.sd_l failed, wanted %d bytes, shutting down\n", \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
241
            kq_nbytes); \
242
243
        slapd_shutdown = 2; \
    } \
244
245
    slap_daemon[t].sd_kq = kqueue(); \
    if (slap_daemon[t].sd_kq < 0) { \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
246
        Debug(LDAP_DEBUG_ANY, "daemon: SLAP_SOCK_INIT: kqueue() failed, errno=%d, shutting down\n", errno); \
247
248
249
250
        slapd_shutdown = 2; \
    } \
} while (0)

251
252
253
254
255
256
257
258
/* 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)

259
# define SLAP_SOCK_DESTROY(t) do { \
260
	int kq_i; \
261
262
263
    if (slap_daemon[t].sd_kq > 0) { \
        close(slap_daemon[t].sd_kq); \
        slap_daemon[t].sd_kq = -1; \
264
265
    } \
    for (kq_i = 0;  kq_i < 2;  kq_i++) { \
266
267
268
        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; \
269
        } \
270
271
        slap_daemon[t].sd_kqc[kq_i].sd_nchanges = 0; \
        slap_daemon[t].sd_kqc[kq_i].sd_maxchanges = 0; \
272
    } \
273
274
275
    if (slap_daemon[t].sd_l != NULL) { \
        ch_free(slap_daemon[t].sd_l); \
        slap_daemon[t].sd_l = NULL; \
276
    } \
277
278
279
    if (slap_daemon[t].sd_fdmodes != NULL) { \
        ch_free(slap_daemon[t].sd_fdmodes); \
        slap_daemon[t].sd_fdmodes = NULL; \
280
    } \
281
    slap_daemon[t].sd_nfds = 0; \
282
283
284
285
286
287
} while (0)

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

288
289
290
291
# 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)
292
293
294
295
296
297
298

/*
 * 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.
 */

299
# define SLAP_KQUEUE_CHANGE(t, s, filter, flag) do { \
300
301
302
303
    /* 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. \
     */ \
304
    struct kq_change* kqc = &slap_daemon[t].sd_kqc[slap_daemon[t].sd_changeidx]; \
305
306
307
308
309
    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", \
310
              slap_daemon[t].sd_changeidx, kqc->sd_maxchanges, 2*kqc->sd_maxchanges); \
311
312
313
314
315
316
        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); \
        if (!kqc->sd_changes) { \
            Debug(LDAP_DEBUG_ANY, \
                "daemon: SLAP_KQUEUE_CHANGE: ch_realloc of slap_daemon.sd_kqc[%d].sd_changes failed, wanted %d bytes, shutting down\n", \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
317
                slap_daemon[t].sd_changeidx, kq_nbytes); \
318
319
320
321
322
            slapd_shutdown = 2; \
            break; /* Don't want to do the EV_SET if sd_changes is NULL */ \
        } \
    } \
    EV_SET(&kqc->sd_changes[kqc->sd_nchanges++], \
323
           (s), (filter), (flag), 0, 0, slap_daemon[t].sd_l[(s)]); \
324
325
} while (0)

326
327
328
329
# 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); \
330
331
332
    } \
} while (0)

333
334
335
336
# 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); \
337
338
339
    } \
} while (0)

340
341
342
343
# 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)
344
345
346
347
348

/* 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)

349
# define SLAP_SOCK_ADD(t, s, l) do { \
350
    assert( s < dtblsize ); \
351
352
353
354
355
    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); \
356
357
} while (0)

358
359
360
361
362
363
# 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; \
364
365
} while (0)

366
# define SLAP_EVENT_FD(t, i)          (events[(i)].ident)
367

368
369
# define SLAP_EVENT_IS_READ(t, i) \
    (events[(i)].filter == EVFILT_READ && SLAP_SOCK_IS_READ(t, SLAP_EVENT_FD(0, i)))
370

371
372
# define SLAP_EVENT_IS_WRITE(t, i) \
    (events[(i)].filter == EVFILT_WRITE && SLAP_SOCK_IS_WRITE(t, SLAP_EVENT_FD(0, i)))
373

374
375
# define SLAP_EVENT_IS_LISTENER(t, i) \
    (events[(i)].udata && SLAP_SOCK_IS_READ(t, SLAP_EVENT_FD(t, i)))
376

377
378
379
# define SLAP_EVENT_LISTENER(t, i)    ((Listener*)(events[(i)].udata))

# define SLAP_EVENT_WAIT(t, tvp, nsp) do { \
380
381
382
383
384
385
386
387
388
389
390
391
    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. \
     */ \
392
393
394
395
396
397
398
399
400
401
    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; \
402
403
404
405
406
} while(0)

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

#elif defined(HAVE_EPOLL)
407
408
409
410
/***************************************
 * Use epoll infrastructure - epoll(4) *
 ***************************************/
# define SLAP_EVENT_FNAME		"epoll"
411
# define SLAP_EVENTS_ARE_INDEXED	0
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
# 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) ); \
427
	} \
428
} while (0)
429

430
431
432
433
434
# 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) ); \
435
	} \
436
437
} while (0)

438
439
# 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)
440

441
442
# 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)
443

444
445
446
447
448
449
#  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 )
450

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

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

Howard Chu's avatar
Howard Chu committed
455
456
/* If a Listener address is provided, store that as the epoll data.
 * Otherwise, store the address of this socket's slot in the
457
458
 * 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
459
 */
460
# define SLAP_SOCK_ADD(t, s, l)		do { \
461
	int rc; \
462
463
464
465
466
	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))); \
467
	if ( rc == 0 ) { \
468
		slap_daemon[t].sd_nfds++; \
469
470
	} else { \
		Debug( LDAP_DEBUG_ANY, \
471
			"daemon: epoll_ctl(ADD,fd=%d) failed, errno=%d, shutting down\n", \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
472
			s, errno ); \
473
474
475
476
		slapd_shutdown = 2; \
	} \
} while (0)

477
478
479
# define SLAP_EPOLL_EV_LISTENER(t,ptr) \
	(((int *)(ptr) >= slap_daemon[t].sd_index && \
	(int *)(ptr) <= &slap_daemon[t].sd_index[dtblsize]) ? 0 : 1 )
480

481
# define SLAP_EPOLL_EV_PTRFD(t,ptr)		(SLAP_EPOLL_EV_LISTENER(t,ptr) ? \
482
	((Listener *)ptr)->sl_sd : \
483
	(ber_socket_t) ((int *)(ptr) - slap_daemon[t].sd_index))
484

485
486
# define SLAP_SOCK_DEL(t,s)		do { \
	int fd, rc, index = SLAP_EPOLL_SOCK_IX(t,(s)); \
487
	if ( index < 0 ) break; \
488
489
490
491
492
493
494
495
	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--; \
496
497
} while (0)

498
499
# define SLAP_EVENT_CLR_READ(i)		SLAP_EPOLL_EVENT_CLR((i), EPOLLIN)
# define SLAP_EVENT_CLR_WRITE(i)	SLAP_EPOLL_EVENT_CLR((i), EPOLLOUT)
500

501
# define SLAP_EPOLL_EVENT_CHK(i, mode)	(revents[(i)].events & mode)
502

503
504
# define SLAP_EVENT_IS_READ(i)		SLAP_EPOLL_EVENT_CHK((i), EPOLLIN)
# define SLAP_EVENT_IS_WRITE(i)		SLAP_EPOLL_EVENT_CHK((i), EPOLLOUT)
505
506
# 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))
507

508
# define SLAP_EVENT_FD(t,i)		SLAP_EPOLL_EV_PTRFD(t,revents[(i)].data.ptr)
509

510
511
512
# define SLAP_SOCK_INIT(t)		do { \
	int j; \
	slap_daemon[t].sd_epolls = ch_calloc(1, \
513
514
		( sizeof(struct epoll_event) * 2 \
			+ sizeof(int) ) * dtblsize * 2); \
515
516
517
	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; \
518
519
} while (0)

520
521
# define SLAP_SOCK_INIT2()

522
523
524
525
526
527
# 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 ); \
528
529
530
	} \
} while ( 0 )

531
# define SLAP_EVENT_DECL		struct epoll_event *revents
532

533
534
# define SLAP_EVENT_INIT(t)		do { \
	revents = slap_daemon[t].sd_epolls + dtblsize; \
535
536
} while (0)

537
538
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
	*(nsp) = epoll_wait( slap_daemon[t].sd_epfd, revents, \
539
		dtblsize, (tvp) ? ((tvp)->tv_sec * 1000 + (tvp)->tv_usec / 1000) : -1 ); \
540
} while (0)
541

542
#elif defined(SLAP_X_DEVPOLL) && defined(HAVE_DEVPOLL)
Howard Chu's avatar
Howard Chu committed
543

544
545
546
547
548
549
550
551
552
553
554
555
/*************************************************************
 * 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
 */
556
557
558
559
560
561
562
563
564
565
566
# 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)
567
568
569
570

/* 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 */
571
# define SLAP_DEVPOLL_WRITE_POLLFD(t,s, pfd, n, what, shdn)	do { \
572
573
574
	int rc; \
	size_t size = (n) * sizeof( struct pollfd ); \
	/* FIXME: use pwrite? */ \
575
	rc = write( slap_daemon[t].sd_dpfd, (pfd), size ); \
576
577
578
579
580
581
582
583
584
585
	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)

586
# define SLAP_DEVPOLL_SOCK_SET(t,s, mode) 	do { \
587
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_SET_%s(%d)=%d\n", \
588
		(mode) == POLLIN ? "READ" : "WRITE", (s), \
589
590
		( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) != (mode) ) ); \
	if ( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) != (mode) ) { \
591
		struct pollfd pfd; \
592
593
594
595
		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); \
596
597
598
	} \
} while (0)

599
# define SLAP_DEVPOLL_SOCK_CLR(t,s, mode)		do { \
600
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_CLR_%s(%d)=%d\n", \
601
		(mode) == POLLIN ? "READ" : "WRITE", (s), \
602
603
		( (SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) == (mode) ) ); \
	if ((SLAP_DEVPOLL_SOCK_EV(t,(s)) & (mode)) == (mode) ) { \
604
		struct pollfd pfd[2]; \
605
606
		SLAP_DEVPOLL_SOCK_EV(t,(s)) &= ~(mode); \
		pfd[0].fd = SLAP_DEVPOLL_SOCK_FD(t,(s)); \
607
		pfd[0].events = POLLREMOVE; \
608
609
		pfd[1] = SLAP_DEVPOLL_SOCK_EP(t,(s)); \
		SLAP_DEVPOLL_WRITE_POLLFD(t,(s), &pfd[0], 2, "CLR", 0); \
610
611
612
	} \
} while (0)

613
614
# 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)
615

616
617
# 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)
618

619
620
621
622
623
624
#  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 )
625
626
627

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

628
# define SLAP_EVENT_MAX(t)			slap_daemon[t].sd_nfds
629
630
631
632
633

/* 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.
 */
634
# define SLAP_SOCK_ADD(t, s, l)		do { \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
635
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_ADD(%d, %p)\n", (s), (l) ); \
636
637
638
639
	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; \
640
	SLAP_DEVPOLL_WRITE_POLLFD(t,(s), &SLAP_DEVPOLL_SOCK_EP(t, (s)), 1, "ADD", 1); \
641
	slap_daemon[t].sd_nfds++; \
642
643
644
645
} while (0)

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

646
647
# 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
648
	Debug( LDAP_DEBUG_CONNS, "SLAP_SOCK_DEL(%d)\n", (s) ); \
649
	if ( index < 0 ) break; \
650
651
652
653
654
655
	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; \
656
	} \
657
658
659
660
661
	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--; \
662
663
664
665
666
667
668
} 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))

669
# define SLAP_EVENT_FD(t,i)		(revents[(i)].fd)
670
671
672

# define SLAP_EVENT_IS_READ(i)		SLAP_DEVPOLL_EVENT_CHK((i), POLLIN)
# define SLAP_EVENT_IS_WRITE(i)		SLAP_DEVPOLL_EVENT_CHK((i), POLLOUT)
673
674
# 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)))
675

676
677
678
679
680
681
682
683
684
685
# 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 )

686
687
# define SLAP_SOCK_INIT(t)		do { \
	slap_daemon[t].sd_pollfd = ch_calloc( 1, \
688
689
690
		( sizeof(struct pollfd) * 2 \
			+ sizeof( int ) \
			+ sizeof( Listener * ) ) * dtblsize ); \
691
692
693
694
	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 ) { \
695
696
		Debug( LDAP_DEBUG_ANY, "daemon: " SLAP_EVENT_FNAME ": " \
			"open(\"" SLAP_EVENT_FNAME "\") failed errno=%d\n", \
Ondřej Kuzník's avatar
Ondřej Kuzník committed
697
			errno ); \
698
		SLAP_SOCK_DESTROY(t); \
699
700
701
		return -1; \
	} \
	for ( i = 0; i < dtblsize; i++ ) { \
702
703
		slap_daemon[t].sd_pollfd[i].fd = -1; \
		slap_daemon[t].sd_index[i] = -1; \
704
705
706
	} \
} while (0)

707
708
# define SLAP_SOCK_INIT2()

709
710
# define SLAP_EVENT_DECL		struct pollfd *revents

711
712
# define SLAP_EVENT_INIT(t)		do { \
	revents = &slap_daemon[t].sd_pollfd[ dtblsize ]; \
713
714
} while (0)

715
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
716
	struct dvpoll		sd_dvpoll; \
717
	sd_dvpoll.dp_timeout = (tvp) ? ((tvp)->tv_sec * 1000 + (tvp)->tv_usec / 1000) : -1; \
718
719
	sd_dvpoll.dp_nfds = dtblsize; \
	sd_dvpoll.dp_fds = revents; \
720
	*(nsp) = ioctl( slap_daemon[t].sd_dpfd, DP_POLL, &sd_dvpoll ); \
721
722
} while (0)

723
#else /* ! kqueue && ! epoll && ! /dev/poll */
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
# 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
744
745
# define SLAP_EVENT_DECL		fd_set readfds, writefds; char *rflags
# define SLAP_EVENT_INIT(t)	do { \
746
747
748
	int i; \
	FD_ZERO( &readfds ); \
	FD_ZERO( &writefds ); \
749
750
751
752
	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 ) \
753
			FD_SET( slapd_ws_sockets[i], &readfds );\
754
		if ( slap_daemon[t].sd_flags[i] & SD_WRITE ) \
755
756
757
			FD_SET( slapd_ws_sockets[i], &writefds ); \
	} } while ( 0 )

758
# define SLAP_EVENT_MAX(t)		slap_daemon[t].sd_nfds
759

760
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
761
	int i; \
Pierangelo Masarati's avatar
Pierangelo Masarati committed
762
	*(nsp) = select( SLAP_EVENT_MAX(t), &readfds, \
763
764
765
766
		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 ) { \
767
			slap_daemon[t].sd_rflags[fd] = SD_READ; \
768
769
770
771
772
773
			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 ) { \
774
			slap_daemon[t].sd_rflags[fd] = SD_WRITE; \
775
776
777
778
779
			if ( fd >= *(nsp)) *(nsp) = fd+1; \
		} \
	} \
} while (0)

780
781
# define SLAP_EVENT_IS_READ(fd)		(rflags[fd] & SD_READ)
# define SLAP_EVENT_IS_WRITE(fd)	(rflags[fd] & SD_WRITE)
782

783
784
# define SLAP_EVENT_CLR_READ(fd) 	rflags[fd] &= ~SD_READ
# define SLAP_EVENT_CLR_WRITE(fd)	rflags[fd] &= ~SD_WRITE
785

786
787
# define SLAP_SOCK_INIT(t)		do { \
	if (!t) { \
788
789
790
	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) ); \
791
792
793
794
	} \
	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
795
796
	slapd_ws_sockets[t*2] = wake_sds[t][0]; \
	slapd_ws_sockets[t*2+1] = wake_sds[t][1]; \
797
798
	wake_sds[t][0] = t*2; \
	wake_sds[t][1] = t*2+1; \
Howard Chu's avatar
Howard Chu committed
799
	slap_daemon[t].sd_nfds = t*2 + 2; \
800
801
	} while ( 0 )

802
803
# define SLAP_SOCK_INIT2()

804
# define SLAP_SOCK_DESTROY(t)	do { \
805
	ch_free( slapd_ws_sockets ); slapd_ws_sockets = NULL; \
806
807
	slap_daemon[t].sd_flags = NULL; \
	slap_daemon[t].sd_rflags = NULL; \
808
809
810
	ldap_pvt_thread_mutex_destroy( &slapd_ws_mutex ); \
	} while ( 0 )

811
812
813
814
# 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])
815

816
817
# 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 )
818

819
820
# define SLAP_SELECT_ADDTEST(t,s)	do { \
	if ((s) >= slap_daemon[t].sd_nfds) slap_daemon[t].sd_nfds = (s)+1; \
821
822
} while (0)

823
824
# 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 )
825

826
827
828
# define SLAP_SOCK_ADD(t,s, l)	do { \
	SLAP_SELECT_ADDTEST(t,(s)); \
	slap_daemon[t].sd_flags[s] = SD_ACTIVE|SD_READ; \
829
830
} while ( 0 )

831
832
# define SLAP_SOCK_DEL(t,s) do { \
	slap_daemon[t].sd_flags[s] = 0; \
833
834
835
836
	slapd_sockdel( s ); \
} while ( 0 )

# else /* !HAVE_WINSOCK */
837
838
839
840
841

/**************************************
 * Use select system call - select(2) *
 **************************************/
# define SLAP_EVENT_FNAME		"select"
842
/* select */
843
844
# define SLAP_EVENTS_ARE_INDEXED	1
# define SLAP_EVENT_DECL		fd_set readfds, writefds
845

846
847
# define SLAP_EVENT_INIT(t)		do { \
	AC_MEMCPY( &readfds, &slap_daemon[t].sd_readers, sizeof(fd_set) );	\
848
	if ( nwriters )	{ \
849
		AC_MEMCPY( &writefds, &slap_daemon[t].sd_writers, sizeof(fd_set) ); \
850
851
852
853
854
855
	} else { \
		FD_ZERO( &writefds ); \
	} \
} while (0)

# ifdef FD_SETSIZE
856
#  define SLAP_SELECT_CHK_SETSIZE	do { \
857
858
	if (dtblsize > FD_SETSIZE) dtblsize = FD_SETSIZE; \
} while (0)
859
860
861
# else /* ! FD_SETSIZE */
#  define SLAP_SELECT_CHK_SETSIZE	do { ; } while (0)
# endif /* ! FD_SETSIZE */
862

863
# define SLAP_SOCK_INIT(t)			do { \
864
	SLAP_SELECT_CHK_SETSIZE; \
865
866
867
	FD_ZERO(&slap_daemon[t].sd_actives); \
	FD_ZERO(&slap_daemon[t].sd_readers); \
	FD_ZERO(&slap_daemon[t].sd_writers); \
868
869
} while (0)

870
871
# define SLAP_SOCK_INIT2()

872
# define SLAP_SOCK_DESTROY(t)
873

874
875
876
# 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)
877

878
879
# 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))
880

881
882
# 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)
883

884
885
886
# 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; \
887
888
} while (0)

889
890
# 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)
891

892
893
894
895
# 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); \
896
} while (0)
897

898
899
900
901
# 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); \
902
} while (0)
903

904
905
# define SLAP_EVENT_IS_READ(fd)		FD_ISSET((fd), &readfds)
# define SLAP_EVENT_IS_WRITE(fd)	FD_ISSET((fd), &writefds)
906

907
908
# define SLAP_EVENT_CLR_READ(fd) 	FD_CLR((fd), &readfds)
# define SLAP_EVENT_CLR_WRITE(fd)	FD_CLR((fd), &writefds)
909

910
# define SLAP_EVENT_WAIT(t, tvp, nsp)	do { \
Pierangelo Masarati's avatar
Pierangelo Masarati committed
911
	*(nsp) = select( SLAP_EVENT_MAX(t), &readfds, \
912
913
		nwriters > 0 ? &writefds : NULL, NULL, (tvp) ); \
} while (0)
914
# endif /* !HAVE_WINSOCK */
915
#endif /* ! kqueue && ! epoll && ! /dev/poll */
916
917
918
919
920
921
922
923

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

#define LDAP_SRVTYPE_PREFIX "service:ldap://"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
924
925
#define LDAPS_SRVTYPE_PREFIX "service:ldaps://"
static char** slapd_srvurls = NULL;
926
static SLPHandle slapd_hslp = 0;
927
int slapd_register_slp = 0;
928
const char *slapd_slp_attrs = NULL;
929
930

static SLPError slapd_slp_cookie;
931

932
933
934
static void
slapd_slp_init( const char* urls )
{
935
	int i;
936
	SLPError err;
937

938
	slapd_srvurls = ldap_str2charray( urls, " " );
939

940
	if ( slapd_srvurls == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
941
942

	/* find and expand INADDR_ANY URLs */
943
944
	for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
		if ( strcmp( slapd_srvurls[i], "ldap:///" ) == 0 ) {
Howard Chu's avatar
Howard Chu committed
945
			slapd_srvurls[i] = (char *) ch_realloc( slapd_srvurls[i],
946
				global_host_bv.bv_len +
Howard Chu's avatar
Howard Chu committed
947
948
				sizeof( LDAP_SRVTYPE_PREFIX ) );
			strcpy( lutil_strcopy(slapd_srvurls[i],
949
				LDAP_SRVTYPE_PREFIX ), global_host_bv.bv_val );
950
		} else if ( strcmp( slapd_srvurls[i], "ldaps:///" ) == 0 ) {
Howard Chu's avatar
Howard Chu committed
951
			slapd_srvurls[i] = (char *) ch_realloc( slapd_srvurls[i],
952
				global_host_bv.bv_len +
Howard Chu's avatar
Howard Chu committed
953
954
				sizeof( LDAPS_SRVTYPE_PREFIX ) );
			strcpy( lutil_strcopy(slapd_srvurls[i],
955
				LDAPS_SRVTYPE_PREFIX ), global_host_bv.bv_val );
956
957
958
959
		}
	}

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

962
	if ( err != SLP_OK ) {
963
		Debug( LDAP_DEBUG_CONNS, "daemon: SLPOpen() failed with %ld\n",
964
			(long)err );
965
	}
966
967
}

968
969
970
971
static void
slapd_slp_deinit( void )
{
	if ( slapd_srvurls == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
972

973
	ldap_charray_free( slapd_srvurls );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
974
	slapd_srvurls = NULL;
975
976
977
978
979

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

980
981
982
983
984
static void
slapd_slp_regreport(
	SLPHandle	hslp,
	SLPError	errcode,
	void		*cookie )
985
{
986
987
	/* return the error code in the cookie */
	*(SLPError*)cookie = errcode; 
988
989
}

990
991
992
static void
slapd_slp_reg()
{
993
	int i;
994
	SLPError err;
995

996
	if ( slapd_srvurls == NULL ) return;
997

998
999
	for ( i = 0; slapd_srvurls[i] != NULL; i++ ) {
		if ( strncmp( slapd_srvurls[i], LDAP_SRVTYPE_PREFIX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1000
				sizeof( LDAP_SRVTYPE_PREFIX ) - 1 ) == 0 ||
1001
			strncmp( slapd_srvurls[i], LDAPS_SRVTYPE_PREFIX,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1002
1003
				sizeof( LDAPS_SRVTYPE_PREFIX ) - 1 ) == 0 )
		{
1004
			err = SLPReg( slapd_hslp,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1005
1006
1007
				slapd_srvurls[i],
				SLP_LIFETIME_MAXIMUM,
				"ldap",
1008
1009
				(slapd_slp_attrs) ? slapd_slp_attrs : "",
				SLP_TRUE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1010
				slapd_slp_regreport,
1011
				&slapd_slp_cookie );
1012

1013
			if ( err != SLP_OK || slapd_slp_cookie != SLP_OK ) {
1014
1015
1016
1017
				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
1018
		}
1019
1020
1021
	}
}

1022
1023
1024
static void
slapd_slp_dereg( void )
{
1025
	int i;
1026
	SLPError err;
1027

1028
	if (