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; }
static void winbindd_status(void) { struct winbindd_cli_state *tmp; DEBUG(0, ("winbindd status:\n")); /* Print client state information */ DEBUG(0, ("\t%d clients currently active\n", winbindd_num_clients())); if (DEBUGLEVEL >= 2 && winbindd_num_clients()) { DEBUG(2, ("\tclient list:\n")); for(tmp = winbindd_client_list(); tmp; tmp = tmp->next) { DEBUGADD(2, ("\t\tpid %lu, sock %d\n", (unsigned long)tmp->pid, tmp->sock)); } } }
static void process_loop(void) { /* We'll be doing this a lot */ while (1) { struct winbindd_cli_state *state; fd_set r_fds, w_fds; int maxfd, listen_sock, listen_priv_sock, selret; struct timeval timeout; /* Handle messages */ message_dispatch(); /* refresh the trusted domain cache */ rescan_trusted_domains(); /* Free up temporary memory */ lp_talloc_free(); main_loop_talloc_free(); /* Initialise fd lists for select() */ listen_sock = open_winbindd_socket(); listen_priv_sock = open_winbindd_priv_socket(); if (listen_sock == -1 || listen_priv_sock == -1) { perror("open_winbind_socket"); exit(1); } maxfd = MAX(listen_sock, listen_priv_sock); FD_ZERO(&r_fds); FD_ZERO(&w_fds); FD_SET(listen_sock, &r_fds); FD_SET(listen_priv_sock, &r_fds); timeout.tv_sec = WINBINDD_ESTABLISH_LOOP; timeout.tv_usec = 0; if (opt_dual_daemon) { maxfd = dual_select_setup(&w_fds, maxfd); } /* Set up client readers and writers */ state = winbindd_client_list(); while (state) { /* Dispose of client connection if it is marked as finished */ if (state->finished) { struct winbindd_cli_state *next = state->next; remove_client(state); state = next; continue; } /* Select requires we know the highest fd used */ if (state->sock > maxfd) maxfd = state->sock; /* Add fd for reading */ if (state->read_buf_len != sizeof(state->request)) FD_SET(state->sock, &r_fds); /* Add fd for writing */ if (state->write_buf_len) FD_SET(state->sock, &w_fds); state = state->next; } /* Call select */ selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout); if (selret == 0) continue; if ((selret == -1 && errno != EINTR) || selret == 0) { /* Select error, something is badly wrong */ perror("select"); exit(1); } /* Create a new connection if listen_sock readable */ if (selret > 0) { if (opt_dual_daemon) { dual_select(&w_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, non-privileged connection */ new_connection(listen_sock, False); } if (FD_ISSET(listen_priv_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, privileged connection */ new_connection(listen_priv_sock, True); } /* Process activity on client connections */ for (state = winbindd_client_list(); state; state = state->next) { /* Data available for reading */ if (FD_ISSET(state->sock, &r_fds)) { /* Read data */ winbind_client_read(state); /* * If we have the start of a * packet, then check the * length field to make sure * the client's not talking * Mock Swedish. */ if (state->read_buf_len >= sizeof(uint32) && *(uint32 *) &state->request != sizeof(state->request)) { DEBUG(0,("process_loop: Invalid request size from pid %lu: %d bytes sent, should be %ld\n", (unsigned long)state->request.pid, *(uint32 *) &state->request, (unsigned long)sizeof(state->request))); DEBUGADD(0, ("This usually means that you are running old wbinfo, pam_winbind or libnss_winbind clients\n")); remove_client(state); break; } /* A request packet might be complete */ if (state->read_buf_len == sizeof(state->request)) { winbind_process_packet(state); } } /* Data available for writing */ if (FD_ISSET(state->sock, &w_fds)) client_write(state); } } #if 0 winbindd_check_cache_size(time(NULL)); #endif /* Check signal handling things */ if (do_sigterm) terminate(); if (do_sighup) { DEBUG(3, ("got SIGHUP\n")); msg_reload_services(MSG_SMB_CONF_UPDATED, (pid_t) 0, NULL, 0); do_sighup = False; } if (do_sigusr2) { print_winbindd_status(); do_sigusr2 = False; } } }