| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- /** BEGIN COPYRIGHT BLOCK
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /* Connection Table */
- #include "fe.h"
- Connection_Table *
- connection_table_new(int table_size)
- {
- Connection_Table *ct;
- int i = 0;
- ct= (Connection_Table*)slapi_ch_calloc( 1, sizeof(Connection_Table) );
- ct->size= table_size;
- ct->c = (Connection *)slapi_ch_calloc( 1, table_size * sizeof(Connection) );
- ct->fd = (struct POLL_STRUCT *)slapi_ch_calloc(1, table_size * sizeof(struct POLL_STRUCT));
- ct->table_mutex = PR_NewLock();
- /* We rely on the fact that we called calloc, which zeros the block, so we don't
- * init any structure element unless a zero value is troublesome later
- */
- for ( i = 0; i < table_size; i++ )
- {
- LBER_SOCKET invalid_socket;
- ber_len_t maxbersize = config_get_maxbersize();
- /* DBDB---move this out of here once everything works */
- ct->c[i].c_sb = ber_sockbuf_alloc();
- invalid_socket = SLAPD_INVALID_SOCKET;
- ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_DESC, &invalid_socket );
- ct->c[i].c_sd = SLAPD_INVALID_SOCKET;
- ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_NO_READ_AHEAD, LBER_OPT_ON );
- ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE, &maxbersize );
- #ifndef _WIN32
- /* all connections start out invalid */
- ct->fd[i].fd = SLAPD_INVALID_SOCKET;
- #endif
- /* The connection table has a double linked list running through it.
- * This is used to find out which connections should be looked at
- * in the poll loop. Slot 0 in the table is always the head of
- * the linked list. Each slot has a c_next and c_prev which are
- * pointers back into the array of connection slots. */
- ct->c[i].c_next = NULL;
- ct->c[i].c_prev = NULL;
- ct->c[i].c_ci= i;
- ct->c[i].c_fdi= SLAPD_INVALID_SOCKET_INDEX;
- }
- return ct;
- }
- void connection_table_free(Connection_Table *ct)
- {
- int i;
- for (i = 0; i < ct->size; i++)
- {
- /* Free the contents of the connection structure */
- Connection *c= &(ct->c[i]);
- connection_done(c);
- }
- slapi_ch_free((void**)&ct->c);
- slapi_ch_free((void**)&ct->fd);
- PR_DestroyLock(ct->table_mutex);
- slapi_ch_free((void**)&ct);
- }
- #ifdef _WIN32
- /*
- * This function looks up connection by nspr fd. It is
- * slow because it iterrates through the entire connection
- * array. Currently, it is only used on NT in secure_read_function
- * to handle I/O timeout on SSL socket we should almost never
- * happen.
- */
- Connection*
- connection_table_get_connection_from_fd(Connection_Table *ct,PRFileDesc *prfd)
- {
- int i;
- for (i = 0; i < ct->size; i++)
- {
- if (ct->c[i].c_prfd == prfd)
- {
- return (&(ct->c[i]));
- }
- }
- return NULL;
- }
- #endif
- void
- connection_table_abandon_all_operations(Connection_Table *ct)
- {
- int i;
- for ( i = 0; i < ct->size; i++ )
- {
- if ( ct->c[i].c_mutex != NULL )
- {
- PR_Lock( ct->c[i].c_mutex );
- connection_abandon_operations( &ct->c[i] );
- PR_Unlock( ct->c[i].c_mutex );
- }
- }
- }
- /* Given a file descriptor for a socket, this function will return
- * a slot in the connection table to use.
- *
- * Note: this function is only called from the slapd_daemon (listener)
- * thread, which means it will never be called by two threads at
- * the same time.
- *
- * Returns a Connection on success
- * Returns NULL on failure
- */
- Connection *
- connection_table_get_connection(Connection_Table *ct, int sd)
- {
- Connection *c= NULL;
- int index, count;
- index = sd % ct->size;
- for( count = 0; count < ct->size; count++, index = (index + 1) % ct->size)
- {
- /* Do not use slot 0, slot 0 is head of the list of active connections */
- if ( index == 0 )
- {
- continue;
- }
- else if( ct->c[index].c_mutex == NULL )
- {
- break;
- }
-
- if( connection_is_free (&(ct->c[index])))
- {
- break;
- }
- }
-
- if ( count < ct->size )
- {
- /* Found an available Connection */
- c= &(ct->c[index]);
- PR_ASSERT(c->c_next==NULL);
- PR_ASSERT(c->c_prev==NULL);
- PR_ASSERT(c->c_extension==NULL);
- if ( c->c_mutex == NULL )
- {
- PR_Lock( ct->table_mutex );
- c->c_mutex = PR_NewLock();
- c->c_pdumutex = PR_NewLock();
- PR_Unlock( ct->table_mutex );
- if ( c->c_mutex == NULL || c->c_pdumutex == NULL )
- {
- c->c_mutex = NULL;
- c->c_pdumutex = NULL;
- LDAPDebug( LDAP_DEBUG_ANY,"PR_NewLock failed\n",0, 0, 0 );
- c= NULL;
- }
- }
- /* Let's make sure there's no cruft left on there from the last time this connection was used. */
- /* Note: no need to lock c->c_mutex because this function is only
- * called by one thread (the slapd_daemon thread), and if we got this
- * far then `c' is not being used by any operation threads, etc.
- */
- connection_cleanup(c);
- }
- else
- {
- /* couldn't find a Connection */
- LDAPDebug( LDAP_DEBUG_CONNS, "max open connections reached\n", 0, 0, 0);
- }
- return c;
- }
- /* active connection iteration functions */
- Connection*
- connection_table_get_first_active_connection (Connection_Table *ct)
- {
- return ct->c[0].c_next;
- }
- Connection*
- connection_table_get_next_active_connection (Connection_Table *ct, Connection *c)
- {
- return c->c_next;
- }
- int connection_table_iterate_active_connections(Connection_Table *ct, void* arg, Connection_Table_Iterate_Function f)
- {
- /* Locking in this area seems rather undeveloped, I think because typically only one
- * thread accesses the connection table (daemon thread). But now we allow other threads
- * to iterate over the table. So we use the "new mutex mutex" to lock the table.
- */
- Connection *current_conn = NULL;
- int ret = 0;
- PR_Lock(ct->table_mutex);
- current_conn = connection_table_get_first_active_connection (ct);
- while (current_conn) {
- ret = f(current_conn, arg);
- if (ret) {
- break;
- }
- current_conn = connection_table_get_next_active_connection (ct, current_conn);
- }
- PR_Unlock(ct->table_mutex);
- return ret;
- }
- #ifdef FOR_DEBUGGING
- static void
- connection_table_dump_active_connection (Connection *c)
- {
- slapi_log_error(SLAPI_LOG_FATAL, "connection", "conn=%p fd=%d refcnt=%d c_flags=%d\n"
- "mutex=%p next=%p prev=%p\n\n", c, c->c_sd, c->c_refcnt, c->c_flags,
- c->c_mutex, c->c_next, c->c_prev);
- }
- static void
- connection_table_dump_active_connections (Connection_Table *ct)
- {
- Connection* c;
- PR_Lock(ct->table_mutex);
- slapi_log_error(SLAPI_LOG_FATAL, "connection", "********** BEGIN DUMP ************\n");
- c = connection_table_get_first_active_connection (ct);
- while (c)
- {
- connection_table_dump_active_connection (c);
- c = connection_table_get_next_active_connection (ct, c);
- }
- slapi_log_error(SLAPI_LOG_FATAL, "connection", "********** END DUMP ************\n");
- PR_Unlock(ct->table_mutex);
- }
- #endif
- /*
- * There's a double linked list of active connections running through the array
- * of connections. This function removes a connection (by index) from that
- * list. This list is used to find the connections that should be used in the
- * poll call.
- */
- void
- connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connection *c)
- {
- /* we always have previous element because list contains a dummy header */;
- PR_ASSERT (c->c_prev);
- #ifdef FOR_DEBUGGING
- slapi_log_error(SLAPI_LOG_FATAL, "connection", "Moving connection out of active list\n");
- connection_table_dump_active_connection (c);
- #endif
- /*
- * Note: the connection will NOT be moved off the active list if any other threads still hold
- * a reference to the connection (that is, its reference count must be 1 or less).
- */
- if(c->c_refcnt > 1) return;
-
- /* We need to lock here because we're modifying the linked list */
- PR_Lock(ct->table_mutex);
- c->c_prev->c_next = c->c_next;
- if (c->c_next)
- {
- c->c_next->c_prev = c->c_prev;
- }
- connection_release_nolock (c);
- connection_cleanup (c);
- PR_Unlock(ct->table_mutex);
-
- #ifdef FOR_DEBUGGING
- connection_table_dump_active_connections (ct);
- #endif
- }
- /*
- * There's a double linked list of active connections running through the array
- * of connections. This function adds a connection (by index) to the head of
- * that list. This list is used to find the connections that should be used in the
- * poll call.
- */
- void
- connection_table_move_connection_on_to_active_list(Connection_Table *ct,Connection *c)
- {
- PR_ASSERT(c->c_next==NULL);
- PR_ASSERT(c->c_prev==NULL);
- PR_Lock(ct->table_mutex);
- connection_acquire_nolock (c);
- #ifdef FOR_DEBUGGING
- slapi_log_error(SLAPI_LOG_FATAL, "connection", "Moving connection into active list\n");
- connection_table_dump_active_connection (c);
- #endif
- c->c_next = ct->c[0].c_next;
- if ( c->c_next != NULL )
- {
- c->c_next->c_prev = c;
- }
- c->c_prev = &(ct->c[0]);
- ct->c[0].c_next = c;
- PR_Unlock(ct->table_mutex);
- #ifdef FOR_DEBUGGING
- connection_table_dump_active_connections (ct);
- #endif
- }
- /*
- * Replace the following attributes within the entry 'e' with
- * information about the connection table:
- * connection // multivalued; one value for each active connection
- * currentconnections // single valued; an integer count
- * totalconnections // single valued; an integer count
- * dtablesize // single valued; an integer size
- * readwaiters // single valued; an integer count
- */
- void
- connection_table_as_entry(Connection_Table *ct, Slapi_Entry *e)
- {
- char buf[BUFSIZ];
- struct berval val;
- struct berval *vals[2];
- int i, nconns, nreadwaiters;
- struct tm utm;
- vals[0] = &val;
- vals[1] = NULL;
- attrlist_delete( &e->e_attrs, "connection");
- nconns = 0;
- nreadwaiters = 0;
- for ( i = 0; i < (ct!=NULL?ct->size:0); i++ )
- {
- PR_Lock( ct->table_mutex );
- if ( (ct->c[i].c_mutex == NULL) || (ct->c[i].c_mutex == (PRLock*)-1) )
- {
- PR_Unlock( ct->table_mutex );
- continue;
- }
- /* Can't take c_mutex if holding table_mutex; temporarily unlock */
- PR_Unlock( ct->table_mutex );
- PR_Lock( ct->c[i].c_mutex );
- if ( ct->c[i].c_sd != SLAPD_INVALID_SOCKET )
- {
- char buf2[20];
- int lendn = ct->c[i].c_dn ? strlen(ct->c[i].c_dn) : 6; /* "NULLDN" */
- char *bufptr = &buf[0];
- char *newbuf = NULL;
- nconns++;
- if ( ct->c[i].c_gettingber )
- {
- nreadwaiters++;
- }
- #ifdef _WIN32
- {
- struct tm *pt;
- pt = gmtime( &ct->c[i].c_starttime );
- memcpy(&utm, pt, sizeof(struct tm) );
- }
- #else
- gmtime_r( &ct->c[i].c_starttime, &utm );
- #endif
- strftime( buf2, sizeof(buf2), "%Y%m%d%H%M%SZ", &utm );
- if (lendn > (BUFSIZ - 46)) {
- /*
- * 46 = 4 for the "i" couter + 20 for buf2 +
- * 10 for c_opsinitiated + 10 for c_opscompleted +
- * 1 for c_gettingber + 1
- */
- newbuf = (char *) slapi_ch_malloc(lendn + 46);
- bufptr = newbuf;
- }
- sprintf( bufptr, "%d:%s:%d:%d:%s%s:%s", i,
- buf2,
- ct->c[i].c_opsinitiated,
- ct->c[i].c_opscompleted,
- ct->c[i].c_gettingber ? "r" : "",
- "",
- ct->c[i].c_dn ? ct->c[i].c_dn : "NULLDN" );
- val.bv_val = bufptr;
- val.bv_len = strlen( bufptr );
- attrlist_merge( &e->e_attrs, "connection", vals );
- if (newbuf) {
- slapi_ch_free_string(&newbuf);
- }
- }
- PR_Unlock( ct->c[i].c_mutex );
- }
- sprintf( buf, "%d", nconns );
- val.bv_val = buf;
- val.bv_len = strlen( buf );
- attrlist_replace( &e->e_attrs, "currentconnections", vals );
- PR_Lock( num_conns_mutex );
- sprintf( buf, "%d", num_conns );
- PR_Unlock( num_conns_mutex );
- val.bv_val = buf;
- val.bv_len = strlen( buf );
- attrlist_replace( &e->e_attrs, "totalconnections", vals );
- sprintf( buf, "%d", (ct!=NULL?ct->size:0) );
- val.bv_val = buf;
- val.bv_len = strlen( buf );
- attrlist_replace( &e->e_attrs, "dtablesize", vals );
- sprintf( buf, "%d", nreadwaiters );
- val.bv_val = buf;
- val.bv_len = strlen( buf );
- attrlist_replace( &e->e_attrs, "readwaiters", vals );
- }
- void
- connection_table_dump_activity_to_errors_log(Connection_Table *ct)
- {
- int i;
- for ( i = 0; i < ct->size; i++ )
- {
- Connection *c= &(ct->c[i]);
- if ( c->c_mutex != NULL )
- {
- /* Find the connection we are referring to */
- int j= c->c_fdi;
- PR_Lock( c->c_mutex );
- if ( c->c_sd != SLAPD_INVALID_SOCKET && c->c_prfd == ct->fd[j].fd )
- {
- int r = ct->fd[j].out_flags & SLAPD_POLL_FLAGS;
- if ( r )
- {
- LDAPDebug( LDAP_DEBUG_CONNS,"activity on %d%s\n", i, r ? "r" : "",0 );
- }
- }
- PR_Unlock( c->c_mutex );
- }
- }
- }
- #if 0
- void dump_op_list(FILE *file, Operation *op);
- void
- connection_table_dump(Connection_Table *ct)
- {
- FILE *file;
-
- file = fopen("/tmp/slapd.conn", "a+");
- if (file != NULL)
- {
- int i;
- fprintf(file, "=============pid=%d==================\n", getpid());
- for ( i = 0; i < ct->size; i++ )
- {
- if ( (ct->c[i].c_sd == SLAPD_INVALID_SOCKET) && (ct->c[i].c_connid == 0) )
- {
- continue;
- }
- fprintf(file, "c[%d].c_dn=0x%x\n", i, ct->c[i].c_dn);
- dump_op_list(file, ct->c[i].c_ops);
- fprintf(file, "c[%d].c_sb.sb_sd=%d\n", i, ct->c[i].c_sd);
- fprintf(file, "c[%d].c_connid=%d\n", i, ct->c[i].c_connid);
- fprintf(file, "c[%d].c_opsinitiated=%d\n", i, ct->c[i].c_opsinitiated);
- fprintf(file, "c[%d].c_opscompleted=%d\n", i, ct->c[i].c_opscompleted);
- }
- fclose(file);
- }
- }
- static const char *
- op_status2str( int o_status )
- {
- const char *s = "unknown";
- switch( o_status ) {
- case SLAPI_OP_STATUS_PROCESSING:
- s = "processing";
- break;
- case SLAPI_OP_STATUS_ABANDONED:
- s = "abandoned";
- break;
- case SLAPI_OP_STATUS_WILL_COMPLETE:
- s = "will_complete";
- break;
- case SLAPI_OP_STATUS_RESULT_SENT:
- s = "result_sent";
- break;
- }
- return s;
- }
- void
- dump_op_list(FILE *file, Operation *op)
- {
- Operation *tmp;
- for ( tmp = op; tmp != NULL; tmp = tmp->o_next )
- {
- fprintf(file,
- "(o_msgid=%d, o_tag=%d, o_sdn=0x%x, o_opid=%d, o_connid=%d, o_status=%s)\n",
- tmp->o_msgid, tmp->o_tag, slapi_sdn_get_dn(&tmp->o_sdn), tmp->o_connid,
- *tmp->o_tid, op_status2str( tmp->o_status ));
- }
- }
- #endif /* 0 */
|