]> git.sur5r.net Git - openldap/blob - servers/slapd/connection.c
bbfdd4344e5cef97d2feee0230c33b908f7136df
[openldap] / servers / slapd / connection.c
1 #include "portable.h"
2
3 #include <stdio.h>
4 #include <ac/string.h>
5 #include <ac/time.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include "slap.h"
11
12 extern Operation        *op_add();
13 extern int              active_threads;
14 extern pthread_mutex_t  active_threads_mutex;
15 extern pthread_mutex_t  new_conn_mutex;
16 extern long             ops_initiated;
17 extern long             ops_completed;
18 extern pthread_mutex_t  ops_mutex;
19 extern pthread_t        listener_tid;
20
21 #ifdef DECL_SYS_ERRLIST
22 extern int              sys_nerr;
23 extern char             *sys_errlist[];
24 #endif
25
26 struct co_arg {
27         Connection      *co_conn;
28         Operation       *co_op;
29 };
30
31 /*
32  * connection_activity - handle the request operation op on connection
33  * conn.  This routine figures out what kind of operation it is and
34  * calls the appropriate stub to handle it.
35  */
36
37 static void
38 connection_operation( struct co_arg *arg )
39 {
40         unsigned long   len;
41
42         pthread_mutex_lock( &arg->co_conn->c_opsmutex );
43         arg->co_conn->c_opsinitiated++;
44         pthread_mutex_unlock( &arg->co_conn->c_opsmutex );
45
46         pthread_mutex_lock( &ops_mutex );
47         ops_initiated++;
48         pthread_mutex_unlock( &ops_mutex );
49
50         switch ( arg->co_op->o_tag ) {
51         case LDAP_REQ_BIND:
52                 do_bind( arg->co_conn, arg->co_op );
53                 break;
54
55 #ifdef COMPAT30
56         case LDAP_REQ_UNBIND_30:
57 #endif
58         case LDAP_REQ_UNBIND:
59                 do_unbind( arg->co_conn, arg->co_op );
60                 break;
61
62         case LDAP_REQ_ADD:
63                 do_add( arg->co_conn, arg->co_op );
64                 break;
65
66 #ifdef COMPAT30
67         case LDAP_REQ_DELETE_30:
68 #endif
69         case LDAP_REQ_DELETE:
70                 do_delete( arg->co_conn, arg->co_op );
71                 break;
72
73         case LDAP_REQ_MODRDN:
74                 do_modrdn( arg->co_conn, arg->co_op );
75                 break;
76
77         case LDAP_REQ_MODIFY:
78                 do_modify( arg->co_conn, arg->co_op );
79                 break;
80
81         case LDAP_REQ_COMPARE:
82                 do_compare( arg->co_conn, arg->co_op );
83                 break;
84
85         case LDAP_REQ_SEARCH:
86                 do_search( arg->co_conn, arg->co_op );
87                 break;
88
89 #ifdef COMPAT30
90         case LDAP_REQ_ABANDON_30:
91 #endif
92         case LDAP_REQ_ABANDON:
93                 do_abandon( arg->co_conn, arg->co_op );
94                 break;
95
96         default:
97                 Debug( LDAP_DEBUG_ANY, "unknown request 0x%x\n",
98                     arg->co_op->o_tag, 0, 0 );
99                 break;
100         }
101
102         pthread_mutex_lock( &arg->co_conn->c_opsmutex );
103         arg->co_conn->c_opscompleted++;
104         op_delete( &arg->co_conn->c_ops, arg->co_op );
105         pthread_mutex_unlock( &arg->co_conn->c_opsmutex );
106
107         free( (char *) arg );
108
109         pthread_mutex_lock( &ops_mutex );
110         ops_completed++;
111         pthread_mutex_unlock( &ops_mutex );
112
113         pthread_mutex_lock( &active_threads_mutex );
114         active_threads--;
115         pthread_mutex_unlock( &active_threads_mutex );
116 }
117
118 void
119 connection_activity(
120     Connection *conn
121 )
122 {
123         pthread_attr_t  attr;
124         struct co_arg   *arg;
125         unsigned long   tag, len;
126         long            msgid;
127         BerElement      *ber;
128         char            *tmpdn;
129
130         if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
131             == NULL ) {
132                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
133                 return;
134         }
135
136         errno = 0;
137         if ( (tag = ber_get_next( &conn->c_sb, &len, conn->c_currentber ))
138             != LDAP_TAG_MESSAGE ) {
139                 Debug( LDAP_DEBUG_TRACE,
140                     "ber_get_next on fd %d failed errno %d (%s)\n",
141                     conn->c_sb.sb_sd, errno, errno > -1 && errno < sys_nerr ?
142                     sys_errlist[errno] : "unknown" );
143                 Debug( LDAP_DEBUG_TRACE, "*** got %d of %d so far\n",
144                     conn->c_currentber->ber_rwptr - conn->c_currentber->ber_buf,
145                     conn->c_currentber->ber_len, 0 );
146
147                 if ( errno != EWOULDBLOCK && errno != EAGAIN ) {
148                         /* log, close and send error */
149                         ber_free( conn->c_currentber, 1 );
150                         conn->c_currentber = NULL;
151
152                         close_connection( conn, conn->c_connid, -1 );
153                 }
154
155                 return;
156         }
157         ber = conn->c_currentber;
158         conn->c_currentber = NULL;
159
160         if ( (tag = ber_get_int( ber, &msgid )) != LDAP_TAG_MSGID ) {
161                 /* log, close and send error */
162                 Debug( LDAP_DEBUG_ANY, "ber_get_int returns 0x%x\n", tag, 0,
163                     0 );
164                 ber_free( ber, 1 );
165
166                 close_connection( conn, conn->c_connid, -1 );
167                 return;
168         }
169
170         if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
171                 /* log, close and send error */
172                 Debug( LDAP_DEBUG_ANY, "ber_peek_tag returns 0x%x\n", tag, 0,
173                     0 );
174                 ber_free( ber, 1 );
175
176                 close_connection( conn, conn->c_connid, -1 );
177                 return;
178         }
179
180 #ifdef COMPAT30
181         if ( conn->c_version == 30 ) {
182                 (void) ber_skip_tag( ber, &len );
183         }
184 #endif
185
186         arg = (struct co_arg *) ch_malloc( sizeof(struct co_arg) );
187         arg->co_conn = conn;
188
189         pthread_mutex_lock( &conn->c_dnmutex );
190         if ( conn->c_dn != NULL ) {
191                 tmpdn = strdup( conn->c_dn );
192         } else {
193                 tmpdn = NULL;
194         }
195         pthread_mutex_unlock( &conn->c_dnmutex );
196
197         pthread_mutex_lock( &conn->c_opsmutex );
198         arg->co_op = op_add( &conn->c_ops, ber, msgid, tag, tmpdn,
199             conn->c_opsinitiated, conn->c_connid );
200         pthread_mutex_unlock( &conn->c_opsmutex );
201
202         if ( tmpdn != NULL ) {
203                 free( tmpdn );
204         }
205
206         pthread_attr_init( &attr );
207         pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
208 #ifndef THREAD_MIT_PTHREADS
209         /* POSIX_THREADS or compatible
210          * This is a draft 10 or standard pthreads implementation
211          */
212         if ( pthread_create( &arg->co_op->o_tid, &attr,
213             (void *) connection_operation, (void *) arg ) != 0 ) {
214                 Debug( LDAP_DEBUG_ANY, "pthread_create failed\n", 0, 0, 0 );
215         } else {
216                 pthread_mutex_lock( &active_threads_mutex );
217                 active_threads++;
218                 pthread_mutex_unlock( &active_threads_mutex );
219         }
220 #else   /* !THREAD_MIT_PTHREAD */
221         /*
222          * This is a draft 4 or earlier pthreads implementation
223          */
224         if ( pthread_create( &arg->co_op->o_tid, attr,
225             (void *) connection_operation, (void *) arg ) != 0 ) {
226                 Debug( LDAP_DEBUG_ANY, "pthread_create failed\n", 0, 0, 0 );
227         } else {
228                 pthread_mutex_lock( &active_threads_mutex );
229                 active_threads++;
230                 pthread_mutex_unlock( &active_threads_mutex );
231         }
232 #endif  /* !THREAD_MIT_PTHREAD */
233         pthread_attr_destroy( &attr );
234 }