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