*Excellent* patch from Michael Steffens <michael_steffens@hp.com> to limit
authorJeremy Allison <jra@samba.org>
Fri, 28 Feb 2003 00:26:20 +0000 (00:26 +0000)
committerJeremy Allison <jra@samba.org>
Fri, 28 Feb 2003 00:26:20 +0000 (00:26 +0000)
the unix domain sockets used by winbindd (also solves FD_SETSIZE problem
in winbindd to boot !). Adds a "last_access" field to winbindd connections,
and will close the oldest idle connection once the number of open connections
goes over WINBINDD_MAX_SIMULTANEOUS_CLIENTS (defined in local.h as 200
currently).
Jeremy.
(This used to be commit a82caefda49396641e8650db8a7ef51752ba6c41)

source3/include/local.h
source3/nsswitch/winbindd.c
source3/nsswitch/winbindd.h

index e16cdbbc5dcdb5c9fcf63bd76e4e2afa6ef9af1e..29b0641119de060e2dfffbf44a8147a55c1290f5 100644 (file)
 /* Number in seconds for winbindd to wait for the mutex. Make this 2 * smbd wait time. */
 #define WINBIND_SERVER_MUTEX_WAIT_TIME (( ((NUM_CLI_AUTH_CONNECT_RETRIES) * ((CLI_AUTH_TIMEOUT)/1000)) + 5)*2)
 
+/* Max number of simultaneous winbindd socket connections. */
+#define WINBINDD_MAX_SIMULTANEOUS_CLIENTS 200
 #endif
index 09b89462ecdb5f585bae408debe295313dc21039..ad37768c09097f36a32c2df1bea0012ab17175ba 100644 (file)
@@ -339,7 +339,9 @@ static void new_connection(int listen_sock)
        
        ZERO_STRUCTP(state);
        state->sock = sock;
-       
+
+       state->last_access = time(NULL);        
+
        /* Add to connection list */
        
        winbindd_add_client(state);
@@ -375,6 +377,35 @@ static void remove_client(struct winbindd_cli_state *state)
 }
 
 
+/* Shutdown client connection which has been idle for the longest time */
+
+static BOOL remove_idle_client(void)
+{
+       struct winbindd_cli_state *state, *remove_state = NULL;
+       time_t last_access = 0;
+       int nidle = 0;
+
+       for (state = winbindd_client_list(); state; state = state->next) {
+               if (state->read_buf_len == 0 && state->write_buf_len == 0 &&
+                               !state->getpwent_state && !state->getgrent_state) {
+                       nidle++;
+                       if (!last_access || state->last_access < last_access) {
+                               last_access = state->last_access;
+                               remove_state = state;
+                       }
+               }
+       }
+
+       if (remove_state) {
+               DEBUG(5,("Found %d idle client connections, shutting down sock %d, pid %u\n",
+                       nidle, remove_state->sock, (unsigned int)remove_state->pid));
+               remove_client(remove_state);
+               return True;
+       }
+
+       return False;
+}
+
 /* Process a complete received packet from a client */
 
 void winbind_process_packet(struct winbindd_cli_state *state)
@@ -427,6 +458,7 @@ void winbind_client_read(struct winbindd_cli_state *state)
        /* Update client state */
        
        state->read_buf_len += n;
+       state->last_access = time(NULL);
 }
 
 /* Write some data to a client connection */
@@ -477,7 +509,8 @@ static void client_write(struct winbindd_cli_state *state)
        /* Update client state */
        
        state->write_buf_len -= num_written;
-       
+       state->last_access = time(NULL);
+
        /* Have we written all data? */
        
        if (state->write_buf_len == 0) {
@@ -508,7 +541,7 @@ static void client_write(struct winbindd_cli_state *state)
        }
 }
 
-/* Process incoming clients on accept_sock.  We use a tricky non-blocking,
+/* Process incoming clients on listen_sock.  We use a tricky non-blocking,
    non-forking, non-threaded model which allows us to handle many
    simultaneous connections while remaining impervious to many denial of
    service attacks. */
@@ -608,7 +641,7 @@ static void process_loop(void)
                        exit(1);
                }
 
-               /* Create a new connection if accept_sock readable */
+               /* Create a new connection if listen_sock readable */
 
                if (selret > 0) {
 
@@ -616,8 +649,18 @@ static void process_loop(void)
                                dual_select(&w_fds);
                        }
 
-                       if (FD_ISSET(listen_sock, &r_fds))
+                       if (FD_ISSET(listen_sock, &r_fds)) {
+                               while (winbindd_num_clients() > WINBINDD_MAX_SIMULTANEOUS_CLIENTS - 1) {
+                                       DEBUG(5,("winbindd: Exceeding %d client connections, removing idle connection.\n",
+                                               WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+                                       if (!remove_idle_client()) {
+                                               DEBUG(0,("winbindd: Exceeding %d client connections, no idle connection found\n",
+                                                       WINBINDD_MAX_SIMULTANEOUS_CLIENTS));
+                                               break;
+                                       }
+                               }
                                new_connection(listen_sock);
+                       }
             
                        /* Process activity on client connections */
             
index 8bd8a837481616c07b40e26374b910459e0230be..42ef209fafa972917e5a3e83782eacf183cc1591 100644 (file)
 /* Client state structure */
 
 struct winbindd_cli_state {
-    struct winbindd_cli_state *prev, *next;   /* Linked list pointers */
-    int sock;                                 /* Open socket from client */
-    pid_t pid;                                /* pid of client */
-    int read_buf_len, write_buf_len;          /* Indexes in request/response */
-    BOOL finished;                            /* Can delete from list */
-    BOOL write_extra_data;                    /* Write extra_data field */
-    struct winbindd_request request;          /* Request from client */
-    struct winbindd_response response;        /* Respose to client */
-    struct getent_state *getpwent_state;      /* State for getpwent() */
-    struct getent_state *getgrent_state;      /* State for getgrent() */
+       struct winbindd_cli_state *prev, *next;   /* Linked list pointers */
+       int sock;                                 /* Open socket from client */
+       pid_t pid;                                /* pid of client */
+       int read_buf_len, write_buf_len;          /* Indexes in request/response */
+       BOOL finished;                            /* Can delete from list */
+       BOOL write_extra_data;                    /* Write extra_data field */
+       time_t last_access;                       /* Time of last access (read or write) */
+       struct winbindd_request request;          /* Request from client */
+       struct winbindd_response response;        /* Respose to client */
+       struct getent_state *getpwent_state;      /* State for getpwent() */
+       struct getent_state *getgrent_state;      /* State for getgrent() */
 };
 
 /* State between get{pw,gr}ent() calls */