connection.c 6.3 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
4
5
6
7
8
9
10

#include <stdio.h>

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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
12
#include "slap.h"

13
14
15
static int connection_op_activate( Connection *conn, Operation *op );
static int connection_resched( Connection *conn );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
16
17
18
19
20
21
22
23
24
25
26
struct co_arg {
	Connection	*co_conn;
	Operation	*co_op;
};

/*
 * connection_activity - handle the request operation op on connection
 * conn.  This routine figures out what kind of operation it is and
 * calls the appropriate stub to handle it.
 */

27
28
static void *
connection_operation( void *arg_v )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
29
{
30
	struct co_arg	*arg = arg_v;
31
32
	int tag = arg->co_op->o_tag;
	Connection *conn = arg->co_conn;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
33

34
35
36
	ldap_pvt_thread_mutex_lock( &conn->c_opsmutex );
	conn->c_ops_received++;
	ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
37

38
	ldap_pvt_thread_mutex_lock( &ops_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
39
	ops_initiated++;
40
	ldap_pvt_thread_mutex_unlock( &ops_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
41

42
	switch ( tag ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
43
	case LDAP_REQ_BIND:
44
		do_bind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
45
46
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
47
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
48
49
50
	case LDAP_REQ_UNBIND_30:
#endif
	case LDAP_REQ_UNBIND:
51
		do_unbind( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
52
53
54
		break;

	case LDAP_REQ_ADD:
55
		do_add( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
56
57
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
58
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
60
61
	case LDAP_REQ_DELETE_30:
#endif
	case LDAP_REQ_DELETE:
62
		do_delete( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
63
64
65
		break;

	case LDAP_REQ_MODRDN:
66
		do_modrdn( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
67
68
69
		break;

	case LDAP_REQ_MODIFY:
70
		do_modify( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
71
72
73
		break;

	case LDAP_REQ_COMPARE:
74
		do_compare( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
75
76
77
		break;

	case LDAP_REQ_SEARCH:
78
		do_search( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
79
80
		break;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
81
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
82
83
84
	case LDAP_REQ_ABANDON_30:
#endif
	case LDAP_REQ_ABANDON:
85
		do_abandon( conn, arg->co_op );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
86
87
88
		break;

	default:
89
		Debug( LDAP_DEBUG_ANY, "unknown request 0x%lx\n",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
90
91
92
93
		    arg->co_op->o_tag, 0, 0 );
		break;
	}

94
95
96
	ldap_pvt_thread_mutex_lock( &ops_mutex );
	ops_completed++;
	ldap_pvt_thread_mutex_unlock( &ops_mutex );
97

98
99
	ldap_pvt_thread_mutex_lock( &conn->c_opsmutex );
	conn->c_ops_completed++;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
100

101
102
103
	slap_op_remove( &conn->c_ops, arg->co_op );
	slap_op_free( arg->co_op );
	arg->co_op = NULL;
104
	arg->co_conn = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
105
	free( (char *) arg );
106
	arg = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
107

108
109
110
111
112
	if((tag == LDAP_REQ_BIND) && (conn->c_state == SLAP_C_BINDING)) {
		conn->c_state = SLAP_C_ACTIVE;
	}

	ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
113

114
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
115
	active_threads--;
116
	if( active_threads < 1 ) {
117
		ldap_pvt_thread_cond_signal(&active_threads_cond);
118
	}
119
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );
120
121
122

	connection_resched( conn );

123
	return NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
124
125
126
127
128
129
130
}

void
connection_activity(
    Connection *conn
)
{
131
	Operation *op;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
	unsigned long	tag, len;
	long		msgid;
	BerElement	*ber;

	if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
	    == NULL ) {
		Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
		return;
	}

	errno = 0;
	if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
	    != LDAP_TAG_MESSAGE ) {
		Debug( LDAP_DEBUG_TRACE,
		    "ber_get_next on fd %d failed errno %d (%s)\n",
147
		    lber_pvt_sb_get_desc(&conn->c_sb), errno, errno > -1 && errno < sys_nerr ?
Kurt Zeilenga's avatar
Kurt Zeilenga committed
148
		    sys_errlist[errno] : "unknown" );
Hallvard Furuseth's avatar
Hallvard Furuseth committed
149
150
		Debug( LDAP_DEBUG_TRACE, "*** got %ld of %lu so far\n",
		    (long)(conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf),
Kurt Zeilenga's avatar
Kurt Zeilenga committed
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
		    conn->c_currentber->ber_len, 0 );

		if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
			/* log, close and send error */
			ber_free( conn->c_currentber, 1 );
			conn->c_currentber = NULL;

			close_connection( conn, conn->c_connid, -1 );
		}

		return;
	}
	ber = conn->c_currentber;
	conn->c_currentber = NULL;

	if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
		/* log, close and send error */
168
		Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%lx\n", tag, 0,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
169
170
171
172
173
174
175
176
177
		    0 );
		ber_free( ber, 1 );

		close_connection( conn, conn->c_connid, -1 );
		return;
	}

	if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
		/* log, close and send error */
178
		Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%lx\n", tag, 0,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
179
180
181
182
183
184
185
		    0 );
		ber_free( ber, 1 );

		close_connection( conn, conn->c_connid, -1 );
		return;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
186
#ifdef LDAP_COMPAT30
Kurt Zeilenga's avatar
Kurt Zeilenga committed
187
188
189
190
191
	if ( conn->c_version == 30 ) {
		(void) ber_skip_tag( ber, &len );
	}
#endif

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
	op = slap_op_alloc( ber, msgid, tag,
	   	conn->c_ops_received, conn->c_connid );

	if ( conn->c_state == SLAP_C_BINDING ) {
		/* connection is binding to a dn, make 'em wait */
		ldap_pvt_thread_mutex_lock( &conn->c_opsmutex );
		slap_op_add( &conn->c_pending_ops, op );

		Debug( LDAP_DEBUG_ANY, "deferring operation\n", 0, 0, 0 );

		ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex );

		return;
	}

	connection_op_activate( conn, op );
}

static int
connection_resched( Connection *conn )
{
	Operation *op;

	if( conn->c_state != SLAP_C_ACTIVE ) {
		/* other states need different handling */
		return;
	}

	ldap_pvt_thread_mutex_lock( &conn->c_opsmutex );

	for( op = slap_op_pop( &conn->c_pending_ops );
		op != NULL;
		op = slap_op_pop( &conn->c_pending_ops ) )
	{
		ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex );

		connection_op_activate( conn, op );

		ldap_pvt_thread_mutex_lock( &conn->c_opsmutex );

		if ( conn->c_state == SLAP_C_BINDING ) {
			break;
		}
	}

	ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex );
}

static int connection_op_activate( Connection *conn, Operation *op )
{
	struct co_arg *arg;
	char *tmpdn;
	int status;
	unsigned long tag = op->o_tag;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
246

247
	ldap_pvt_thread_mutex_lock( &conn->c_dnmutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
248
	if ( conn->c_dn != NULL ) {
249
		tmpdn = ch_strdup( conn->c_dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
250
251
252
	} else {
		tmpdn = NULL;
	}
253
	ldap_pvt_thread_mutex_unlock( &conn->c_dnmutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
254

255
256
257
258
259
260
261
	arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
	arg->co_conn = conn;
	arg->co_op = op;

	arg->co_op->o_dn = ch_strdup( tmpdn != NULL ? tmpdn : "" );
	arg->co_op->o_ndn = dn_normalize_case( ch_strdup( arg->co_op->o_dn ) );

262
	ldap_pvt_thread_mutex_lock( &conn->c_opsmutex );
263
264
265
266
267
268
269

	slap_op_add( &conn->c_ops, arg->co_op );

	if(tag == LDAP_REQ_BIND) {
		conn->c_state = SLAP_C_BINDING;
	}

270
	ldap_pvt_thread_mutex_unlock( &conn->c_opsmutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
271
272
273
274
275

	if ( tmpdn != NULL ) {
		free( tmpdn );
	}

276
277
278
279
	ldap_pvt_thread_mutex_lock( &active_threads_mutex );
	active_threads++;
	ldap_pvt_thread_mutex_unlock( &active_threads_mutex );

280
281
	status = ldap_pvt_thread_create( &arg->co_op->o_tid, 1,
					 connection_operation, (void *) arg );
282

283
	if ( status != 0 ) {
284
		Debug( LDAP_DEBUG_ANY, "ldap_pvt_thread_create failed (%d)\n", status, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
285
	}
286
287

	return status;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
288
}