/* * $Id: internal-connections.c,v 0.31 1998/07/08 13:41:46 ceder Exp $ * Copyright (C) 1991, 1992, 1993, 1994, 1996 Lysator Academic Computer Association. * * This file is part of the LysKOM server. * * LysKOM 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; either version 1, or (at your option) * any later version. * * LysKOM 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 LysKOM; see the file COPYING. If not, write to * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN, * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, * MA 02139, USA. * * Please mail bug reports to bug-lyskom@lysator.liu.se. */ /* * internal-connections.c * * Abstract routines on the data type Connection. */ static const char * rcsid = "$Id: internal-connections.c,v 0.31 1998/07/08 13:41:46 ceder Exp $"; #include "rcs.h" USE(rcsid); #include #include #include #include #ifdef HAVE_STDARG_H # include #endif #include "exp.h" #include "s-string.h" #include "kom-types.h" #include "com.h" #include "async.h" #include "connections.h" #include "internal-connections.h" #include "config.h" #include "server/smalloc.h" #include "lyskomd.h" #include "log.h" #include "async.h" #include "kom-memory.h" INTERNAL Connection *all_connections = NULL; INTERNAL Session_no no_of_connection_attempts = 0; /* Used in get_conn_by_number to speed things up. */ INTERNAL Connection *last_conn = NULL; static int no_of_allocated_connections = 0; static void init_connection(Connection *conn) { Async default_want_async[] = ASYNC_DEFAULT_MESSAGES; int i; conn->magic = 0; conn->prev = NULL; conn->next = NULL; conn->pers_no = 0; conn->person = NULL; conn->session_start = NO_TIME; conn->cwc = 0; conn->what_am_i_doing = EMPTY_STRING; conn->ena_level = 0; conn->username = EMPTY_STRING; conn->hostname = EMPTY_STRING; conn->ident_user = EMPTY_STRING; conn->client_name = EMPTY_STRING; conn->client_version = EMPTY_STRING; conn->flags.invisible = FALSE; conn->flags.user_active_used = FALSE; conn->flags.user_absent = FALSE; conn->flags.reserved3 = FALSE; conn->flags.reserved4 = FALSE; conn->flags.reserved5 = FALSE; conn->flags.reserved6 = FALSE; conn->flags.reserved7 = FALSE; conn->username_valid = FALSE; conn->mux = NULL; conn->protocol = '\0'; conn->parse_pos = 0; conn->fnc_parse_pos = 0; conn->array_parse_pos = 0; conn->array_parse_index = 0; conn->struct_parse_pos = 0; conn->string_parse_pos = 0; conn->ref_no = 0; conn->function = call_fnc_login_old; conn->num0 = 0; conn->num1 = 0; conn->num2 = 0; conn->num3 = 0; conn->c_string0 = EMPTY_STRING; conn->c_string1 = EMPTY_STRING; conn->string0 = EMPTY_STRING; conn->c_misc_info_p = NULL; conn->aux_item.data = EMPTY_STRING; conn->aux_item_list.items = NULL; conn->aux_item_list.length = 0; conn->c_local_text_no_p = NULL; conn->unparsed = EMPTY_STRING; conn->first_to_parse = 0; conn->more_to_parse = FALSE; conn->active_time = time(NULL); conn->session_no = 0; conn->info.pers_pres_conf = 0; conn->info.conf_pres_conf = 0; conn->info.motd_conf = 0; conn->info.kom_news_conf = 0; conn->info.motd_of_lyskom = 0; conn->info.version = 0; conn->info.highest_aux_no = 0; conn->info.aux_item_list.length = 0; conn->info.aux_item_list.items = NULL; conn->num_list.length = 0; conn->num_list.data = NULL; for (i = 0; i < ay_dummy_last; i++) conn->want_async[i] = FALSE; for (i = 0; i < sizeof(default_want_async)/sizeof(*default_want_async); i++) conn->want_async[default_want_async[i]] = TRUE; init_priv_bits(&conn->priv_bits); init_conf_type(&conn->conf_type); init_struct_tm(&conn->time); } static Connection * alloc_connection(void) { Connection *res; res = smalloc ( sizeof(Connection) ); init_connection(res); ++no_of_allocated_connections; return res; } EXPORT Connection * new_client(void) { Connection *c; c = alloc_connection(); c->magic = CONN_MAGIC_ALLOC; if (all_connections != NULL) { all_connections->prev->next = c; c->prev = all_connections->prev; all_connections->prev = c; c->next = all_connections; } else { c->prev = c; c->next = c; } all_connections = c; c->session_no = ++no_of_connection_attempts; c->protocol = '\0'; /* Reserved to mean 'no protocol specified yet' */ c->unparsed = EMPTY_STRING; c->first_to_parse = 0; c->more_to_parse = TRUE; c->active_time = time(NULL); c->pers_no = 0; c->person = NULL; time( & c->session_start ); c->cwc = 0; c->what_am_i_doing = EMPTY_STRING; c->ena_level = 0; c->username = EMPTY_STRING; c->ident_user = EMPTY_STRING; c->client_name = EMPTY_STRING; c->client_version = EMPTY_STRING; c->flags.invisible = FALSE; c->flags.user_active_used = FALSE; c->flags.user_absent = FALSE; c->flags.reserved3 = FALSE; c->flags.reserved4 = FALSE; c->flags.reserved5 = FALSE; c->flags.reserved6 = FALSE; c->flags.reserved7 = FALSE; c->username_valid = FALSE; return c; } /* * Only used from logout_client */ EXPORT void kill_client(Connection *cp) { if ( all_connections == NULL ) restart_kom("kill_client(): No clients in all_connections list\n"); if (all_connections == all_connections->next) { if (all_connections->prev != all_connections) restart_kom("kill_client(): all_connections corrupt (LINK)\n"); if (all_connections != cp) restart_kom("kill_client(): all_connections corrupt (SINGLE)\n"); all_connections = NULL; } else { if (cp->prev == NULL || cp->next == NULL) restart_kom("kill_client(): all_connections corrupt (NULL)\n"); cp->prev->next = cp->next; cp->next->prev = cp->prev; if (all_connections == cp) all_connections = cp->next; } if ( last_conn == cp ) last_conn = NULL; cp->magic = CONN_MAGIC_FREE; s_clear(&cp->unparsed); s_clear(&cp->what_am_i_doing); s_clear(&cp->username); s_clear(&cp->hostname); s_clear(&cp->ident_user); s_clear(&cp->client_name); s_clear(&cp->client_version); if ( cp->mux != NULL ) { log("kill_client(): client %ld has mux != NULL.\n", cp->session_no); } if ( !s_empty(cp->c_string0) || !s_empty(cp->c_string1) || !s_empty(cp->string0) ) { log("kill_client(): unexpected string remains.\n"); } if ( cp->c_misc_info_p != NULL || cp->c_local_text_no_p != NULL ) log("kill_client(): unexpected remaining data.\n"); sfree(cp); --no_of_allocated_connections; } #ifndef NDEFENSIVE_CHECKS INTERNAL void check_conn_exists(Connection *foo) { /* Check that foo really is active. */ Connection *c = all_connections; Bool found = FALSE; do { if ( c == foo ) found = TRUE; c = c->next; } while ( c != all_connections && found == FALSE ); if ( found == FALSE ) restart_kom("%s: foo == %ld not found in all_connections.\n", "get_conn_by_number", last_conn->session_no); } #endif /* * Session_nos must NOT be recycled, or this code might break! */ EXPORT Connection * get_conn_by_number (Session_no session_no) { Connection *end; if ( last_conn == NULL ) last_conn = all_connections; else if ( all_connections == NULL ) { restart_kom("get_conn_by_number(%ld): last_conn = %ld %s", session_no, last_conn->session_no, "and all_connections == NULL"); } #ifndef NDEFENSIVE_CHECKS else check_conn_exists(last_conn); #endif end = last_conn; do { if ( last_conn->session_no == session_no ) return last_conn; last_conn = last_conn->next; } while ( last_conn != end); return NULL; } EXPORT Session_no traverse_connections (Session_no session_no) { Connection *prev = NULL; if ( all_connections == NULL ) return 0; prev = get_conn_by_number ( session_no ); /* prev is NULL if session_no is 0, or if session_no was logged out. */ if ( prev == NULL ) return all_connections->session_no; else if ( prev->next == all_connections ) return 0; /* Full circle. */ else return prev->next->session_no; } void dump_allocated_connections(FILE *fp) { fprintf(fp, "---%s:\n\tConnections: %d\n", __FILE__, no_of_allocated_connections); fprintf(fp, "\tConnection attempts: %lu\n", (unsigned long)no_of_connection_attempts); }