Skip to content
Snippets Groups Projects
Select Git revision
  • a38808d68d3c61de44508f913a3d0daf366eb52c
  • master default protected
  • hpke
  • ppc-chacha-4core
  • delete-internal-name-mangling
  • master-updates
  • ppc-gcm
  • ppc-chacha-2core
  • refactor-ecc-mod
  • ppc-chacha-core
  • use-mpn_cnd-functions
  • optimize-ecc-invert
  • default-m4-quote-char
  • power-asm-wip
  • test-fat
  • chacha-3core-neon
  • x86_64-salsa20-2core
  • salsa20-2core-neon
  • bcrypt
  • arm-salsa20-chacha-vsra
  • test-shlib-dir
  • nettle_3.6_release_20200429
  • nettle_3.6rc3
  • nettle_3.6rc2
  • nettle_3.6rc1
  • nettle_3.5.1_release_20190627
  • nettle_3.5_release_20190626
  • nettle_3.5rc1
  • nettle_3.4.1_release_20181204
  • nettle_3.4.1rc1
  • nettle_3.4_release_20171119
  • nettle_3.4rc2
  • nettle_3.4rc1
  • nettle_3.3_release_20161001
  • nettle_3.2_release_20160128
  • nettle_3.1.1_release_20150424
  • nettle_3.1_release_20150407
  • nettle_3.1rc3
  • nettle_3.1rc2
  • nettle_3.1rc1
  • nettle_3.0_release_20140607
41 results

aes-meta.c

Blame
  • Forked from Nettle / nettle
    Source project has a limited visibility.
    connections.c 20.92 KiB
    /*
     * $Id: connections.c,v 0.19 1992/06/11 14:32:54 ceder Exp $
     * Copyright (C) 1991  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. 
     */
    /*
     * connections.c
     *
     * Denna fil inneh}ller niv}n ovanf|r isc.
     *
     * Created by Willf|r 31/3-90. Mostly written by ceder.
     */
    
    static char *rcsid = "$Id: connections.c,v 0.19 1992/06/11 14:32:54 ceder Exp $";
    
    
    #include <errno.h>
    #include <setjmp.h>
    #include <sys/types.h>
    #include <sys/file.h>
    #include <sys/stat.h>
    #include <time.h>
    #include <sys/time.h>
    #include <string.h>
    
    #include "s-string.h"
    #include <kom-types.h>
    #include "lyskomd.h"
    #include <config.h>
    #include <debug.h>
    #include "end-of-atomic.h"
    #include "log.h"
    #include <services.h>
    #include "isc-interface.h"
    #include <kom-errno.h>
    #include "com.h"
    #include "connections.h"
    #include "prot-a-parse.h"
    #include "prot-a-output.h"
    #include "prot-a.h"
    #include <server/smalloc.h>
    #include "prot-a-parse-arg.h"
    #include "isc-parse.h"
    #include "cache.h"
    #include "send-async.h"
    #include "mux.h"
    #include "mux-parse.h"
    #include "internal-connections.h"
    #include "rfc931.h"
    
    IscMaster      * kom_server_mcb    = NULL;
    Connection     * active_connection = NULL;
    
    /*
     * This is set TRUE when the server should be closed. It is checked
     * each time around the main loop. It is set if someone with enough
     * privileges issues a `shutdown', or of lyskomd receives a SIGHUP.
     * This not an abort: all data is saved before we exit.
     */
    volatile Bool	 go_and_die = FALSE;
    
    /*
     * Once upon a time the entire database was always held in core, and
     * saved to disk when we got a SIGUSR1 signal. Nowadays the server
     * keeps track of the time itself and saves at appropriate intervalls.
     * It does still write some statistics when it get a SIGUSR1 signal.
     * The signal handler sets do_sync_db. The name is retained for
     * historical reasons.
     */
    volatile Bool	 do_sync_db = FALSE;
    
    jmp_buf 	 parse_env;
    
    
    const Fnc_descriptor fnc_defs[]={
    #include "fnc-def-init.incl"
    };
    
    u_long service_statistics[sizeof (fnc_defs) / sizeof (Fnc_descriptor)];
    
    BUGDECL;
    
    
    
    static void
    logout_client(Connection *cp)
    {
        Connection *real_active_connection;
    
        if ( active_connection != NULL )
        {
    	log("BUGCHK: logout_client(%d): connection %d is active.\n",
    	    cp->session_no, active_connection->session_no);
        }
        
        switch (cp->magic)
        {
        case CONN_MAGIC_ALLOC:
            break;
    
        case CONN_MAGIC_FREE:
    	log("LOGOUT_CLIENT: Trying to free freed Connection - ignored!\n");
    	return;
    
        default:
    	restart_kom("LOGOUT_CLIENT: Bad magic number\n");
        }
    
        if ( cp->pers_no != 0 )
        {
    	real_active_connection = active_connection; /* Shouldn't be needed +++ */
    	active_connection = cp;
    	logout();
    	active_connection = real_active_connection;
        }
    
        switch(cp->protocol)
        {
        case 0:			/* Hasn't yet allocated any protocol. */
    	break;
    	
        case 'A':
    	prot_a_destruct(cp);
    	break;
    	
        default:
    	restart_kom("logout_client(): Bad protocol.\n");
        }
    
        mux_close(cp);		/* Close fd's. Clear mux and isc structures. */
    
        kill_client(cp);		/* Free the Connection */
    }
    
    /*
     * This function is part of the shutdown tidy-up sequence.
     */
    void
    logout_all_clients(void)
    {
        Session_no sess = 0;
        Connection *conn;
        
        while ( (sess = traverse_connections (sess)) != 0)
        {
    	conn = get_conn_by_number (sess);
    
    	if ( conn == NULL )
    	    restart_kom("logout_all_clients(): cant get session %d.\n",
    			sess);
    	else
    	    logout_client (conn);
        }
    
        if ( traverse_connections (0) != 0)
    	restart_kom("logout_all_clients(): traverse_connections(0) == %d.\n",
    		    traverse_connections(0));
    }
    
        
        
    
        
    /*
     * Call a function in services.c. A pointer to the result is returned.
     * The pointer points to static data which is overwritten on each call.
     */
    static Success
    call_function (Connection  * client,
    	       Result_holder   * res)     /* This is a union. */
    {
        Success	status=FAILURE;	/* OK if the call was successful. */
    
        if ( active_connection != NULL )
        {
    	log("call_function(%d): active_connection = %d",
    	    client->session_no, active_connection->session_no);
        }
        
        active_connection = client;
    
        service_statistics[client->function]++;
    
    #include "call-switch.incl"
    
        active_connection = NULL;
    
        return status;
    }
    
    
    static void
    parse_packet(Connection *client)
    {
        if ( client->protocol == '\0' ) /* Not known yet. */
        {
    	client->protocol = parse_char(client);
    	switch(client->protocol)
    	{
    	case 'A':
    	    prot_a_init(client);
    	    break;
    
    	default:
    	    client->protocol = '\0';
    	    mux_printf(client,
    		    "%%%%LysKOM unsupported protocol.\n");
    	    mux_flush(client);
    	    BUG(("%%%%Unsupported protocol.\n"));
    	    longjmp(parse_env, ISC_LOGOUT);
    	}
        }
    
        switch(client->protocol)
        {
        case 'A':
    	prot_a_parse_packet(client);
    	break;
    
        default:
    	restart_kom("parse_packet(): Bad protocol.\n");
    	break;
        }
    }
    
    /*
     * Free all parsed areas which are no longer needed. Re-initialize all
     * parse_pos fields so that the parse will expect a new function.
     *
     * This function is called
     *	when a parse error occurs
     *	when a parse is complete and the function has executed.
     */
    static void
    free_parsed(Connection *client)
    {
        s_clear(&client->c_string0);
        s_clear(&client->c_string1);
        client->string0 = EMPTY_STRING; /* So that no one frees it. */
        sfree( client->c_misc_info_p);
        client->c_misc_info_p = NULL;
        sfree( client->c_local_text_no_p);
        client->c_local_text_no_p = NULL;
        client->parse_pos = 0;
        client->fnc_parse_pos = 0;
        client->array_parse_pos = 0;
        client->struct_parse_pos = 0;
        client->string_parse_pos = 0;
    }
    
    /*
     * Send a reply to a call.
     */
    static void
    reply(Connection *client,
          Success	      status,
          Result_holder  *result)
    {
        switch(client->protocol)
        {
        case 'A':
    	prot_a_reply(client, status, result);
    	break;
    
        default:
    	restart_kom("reply(): Bad protocol.\n");
    	break;
        }
    }
    
    
    /*
     * Try to parse enough data from client->unparsed to call a function.
     * If more data is needed set client->more_to_parse to FALSE.
     */
    static void
    parse_unparsed(Connection *client)
    {
        String        tmp_str = EMPTY_STRING;
        Success       status;
        Result_holder result;
            
        switch ( setjmp(parse_env) )
        {
        case 0 :
    	/* Parse message. If message is complete call function and reply. */
    	parse_packet(client);
    	client->last_request = time(NULL);
    	status = call_function(client, &result);
    	reply(client, status, &result);
    	free_parsed(client);
    	end_of_atomic(FALSE);
    	break;
    
        case ISC_PROTOCOL_ERR:
    	s_clear(&client->string0);
    	free_parsed(client);
    	mux_printf(client, "%% LysKOM protocol error.\n");
    	mux_flush(client);
    	BUG(("%%%% Protocol error.\n"));
    	s_clear(&client->unparsed);
    	client->first_to_parse = 0;
    	client->more_to_parse = FALSE;
    	end_of_atomic(FALSE);
    	break;
    
        case ISC_MSG_INCOMPLETE:
    	client->more_to_parse = FALSE;
    	break;
    
        case ISC_LOGOUT:
    	add_to_kill_list(client);
    	break;
        }
        
        /* Delete the parsed part of 'unparsed' */
        
        if ( s_substr(&tmp_str, client->unparsed,
    		  client->first_to_parse, END_OF_STRING) != OK )
    	restart_kom("parse_unparsed: s_substr\n");
    
        s_clear(&client->unparsed);
        client->unparsed = tmp_str;
        client->first_to_parse = 0;
    }
    
    
    /*
     * There is a message in the event. Parse it.
     */
    static void
    parse_message(Connection *cp, String tmp_str)
    {
        VBUGSTR(tmp_str);
    
        cp->more_to_parse = TRUE;
        
        if ( s_strcat(&cp->unparsed, tmp_str) != OK )
    	restart_kom("parse_message(): s_strcat\n");
    
        tmp_str = EMPTY_STRING;
        
        /* Parse this packet, but leave the last token if it isn't complete. */
    
        parse_unparsed(cp);
    
        return;
    }
    
    static void
    mux_handle_packet(Mux *mux)
    {
        Mux_client *mcp = NULL;
        Connection *cp = NULL;
    
        switch(mux->parse.function)
        {
        case 0:			/* ping */
    	isc_printf(mux->scb, "0\n");
    	isc_flush(mux->scb);
    	break;
    
        case 1:			/* login */
    
    	mcp = mux_getclientbyid(mux, mux->parse.num);
    	if (mcp)
    	{			/* ERROR %d: Already logged in\n */
    	    isc_printf(mux->scb, "4\n");
    	    isc_flush(mux->scb);
    	    return;
    	}
        
    	cp = new_client();
    	cp->mux = mux;
    	cp->hostname = mux->parse.string;
    	mux->parse.string = EMPTY_STRING;
    	
    	mux_addclient(mux, mux->parse.num, cp);
    
        
    	BUG(("\n[Client %d from %.*s via MUX %s",
    	     cp->session_no,
    	     (int)cp->hostname.len,
    	     cp->hostname.string,
    	     isc_gethostname(mux->scb->info.tcp.raddr, NULL, 0)));
    	BUG((" is connecting]\n"));
    
    	break;
        
        case 2:			/* logout */
    	mcp = mux_getclientbyid(mux, mux->parse.num);
    	if (!mcp)
    	{			/* ERROR %d: No such mux-session */
    	    isc_printf(mux->scb, "4\n");
    	    isc_flush(mux->scb);
    	    return;
    	}
    
    	cp = mcp->conn;
        
    	BUG(("\n[Client %d via MUX(%s)",
    	     cp->session_no,
    	     isc_gethostname(mux->scb->info.tcp.raddr, NULL, 0)));
    	BUG((" is logging out by request]\n"));
    
    	add_to_kill_list(cp);
    	break;
    
        case 3:			/* msg */
    	mcp = mux_getclientbyid(mux, mux->parse.num);
    	if (!mcp)
    	{			/* ERROR %d: No such mux-session */
    	    isc_printf(mux->scb, "4\n");
    	    isc_flush(mux->scb);
    	    return;
    	}
        
    	cp = mcp->conn;
        
    	VBUG(("\n[Message client %d via MUX #%d]\n",
    	      cp->session_no, (int)mux->scb));
    
    	parse_message(cp, mux->parse.string);
    	break;
    
        default:
    	
    	VBUG(("\nMUX Protocol error from MUX #%d]\n",
    	      (int)mux->scb));
    
    	isc_printf(mux->scb, "5\n");
    	isc_flush(mux->scb);
    	break;
    	
        }
    }
    	
    static void
    mux_logout(Mux *mp)
    {
        int i;
    
        for (i = 0; i < mp->client_c; i++)
    	if (mp->client_v[i].conn)
    	{
    	    BUG(("\n[Client %d via MUX(%s)",
    		 mp->client_v[i].conn->session_no,
    		 isc_gethostname(mp->scb->info.tcp.raddr, NULL, 0)));
    	    BUG((" is logging out by MUX shutdown]\n"));
    	    logout_client(mp->client_v[i].conn);
    	    end_of_atomic(FALSE);
    	}
    	      
        isc_destroy(kom_server_mcb, mp->scb);
        mux_destruct(mp);
    }
    
    
    static void
    mux_parse_unparsed(Mux *mux)
    {
        String        tmp_str;
    
        while ( mux->parse.more_to_parse )
        {
    	switch ( setjmp(mux_parse_env) )
    	{
    	case 0 :
    	    /* Parse message. Take apropriate action if message is complete. */
    	    mux_parse_packet(mux);
    	    mux_handle_packet(mux);
    	    mux_free_parsed(mux);
    	    break;
    
    	case MUX_PROTOCOL_ERR:
    	    s_clear(&mux->parse.string);
    	    mux_free_parsed(mux);
    	    isc_printf(mux->scb, "5\n");
    	    isc_flush(mux->scb);
    	    BUG(("%%%% Mux protocol error.\n"));
    	    s_clear(&mux->parse.unparsed);
    	    mux->parse.first_to_parse = 0;
    	    mux->parse.more_to_parse = FALSE;
    	    break;
    
    	case MUX_MSG_INCOMPLETE:
    	    mux->parse.more_to_parse = FALSE;
    	    break;
    
    	case MUX_LOGOUT:
    	    mux_logout(mux);
    	    return;
    	}
        
    	/* Delete the parsed part of 'unparsed' */
    
    	tmp_str = EMPTY_STRING;
    
    	if ( s_substr(&tmp_str, mux->parse.unparsed,
    		      mux->parse.first_to_parse, END_OF_STRING) != OK )
    	    restart_kom("mux_parse_unparsed: s_substr\n");
    
    	s_clear(&mux->parse.unparsed);
    	mux->parse.unparsed = tmp_str;
    	mux->parse.first_to_parse = 0;
        }
    }
    
    
    static void
    mux_parse_message(Mux *mp, String tmp_str)
    {
        VBUGSTR(tmp_str);
    
        BUG(("mux_parse_message(): mp->parse.unparsed = { len = %d, "
    	 "string = %p }\n", mp->parse.unparsed.len,
    	 (void *)mp->parse.unparsed.string));
        
        if ( s_strcat(&mp->parse.unparsed, tmp_str) != OK )
    	restart_kom("mux_parse_message(): s_strcat\n");
    
        tmp_str = EMPTY_STRING;
        
        /* Parse this packet, but leave the last token if it isn't complete. */
    
        mux_parse_unparsed(mp);
    
        return;
    }
    
    /*
     * parse data in client->unparsed and mux->unparsed if there
     * is data that has not yet been taken care of. Return TRUE
     * if there was no data to take care of.
     */
    static Bool
    parse_forgotten(void)
    {
        Bool flg = FALSE;			/* Was there anything? */
        Connection *ci;
        Session_no session_no = 0;
    
        if ( traverse_connections(0) == 0 )
    	return TRUE;
    
        while ( ( session_no = traverse_connections( session_no ) ) != 0 )
        {
    	ci = get_conn_by_number (session_no);
    
    	if ( ci->more_to_parse )
    	{
    	    parse_unparsed(ci);
    	    flg = TRUE;
    	}
        }
    
        return !flg;
    }
    
    
    /* Return 1 if the named file exists, 0 otherwise */
    static int
    fexists(const char *filename)
    {
        struct stat buf;
        int code;
      
        code = !stat(filename, &buf);
        errno = 0;
    
        return code;
    }
    
    
    void
    dump_statistics(void)
    {
        static time_t last_dump = NO_TIME;
        int i;
        time_t now;
        FILE *fp;
        extern char statisticfile[1024]; /* Defined in ramkomd.c */
    
        if ( (fp = fopen(statisticfile, "a")) == NULL )
        {
    	log(__FILE__ ": dump_statistics(): can't open file %s\n",
    	    statisticfile);
    	return;
        }
    
        time(&now);
    
        if (last_dump == NO_TIME)
        {
    	fprintf(fp, "RESTART\n");
    	last_dump = now;
        }
        
        fprintf(fp, "TIME: %s", ctime(&now));
        fprintf(fp, "SECONDS: %d\n", (int)difftime(now, last_dump));
        fprintf(fp, "STATISTICS:");
        for ( i = 0; i < sizeof(service_statistics) / sizeof(u_long); i++)
        {
    	fprintf(fp, " %lu", service_statistics[i]);
    	service_statistics[i]=0;
        }
    
        fprintf(fp, "\n");
        fclose(fp);
    
        last_dump = now;
    }
    
    /* List of connections to kill. */
    
    Session_no *kill_list = NULL;
    int kill_list_size = 0;
    
    /* Schedule this client for termination. */
    void
    add_to_kill_list(Connection *conn)
    {
        int i;
    
        for (i = 0; i < kill_list_size; i++)
    	if (kill_list[kill_list_size] == conn->session_no)
    	{
    	    log("add_to_kill_list(%d): already present as %d of %d.\n",
    		conn->session_no, i, kill_list_size);
    	    return;
    	}
    
        if (kill_list == NULL)
        {
    	if (kill_list_size != 0)
    	    restart_kom("add_to_kill_list(): size = %d\n", kill_list_size);
    
    	kill_list_size = 1;
    	kill_list = smalloc(sizeof(Session_no));
        }
        else
        {
    	kill_list_size++;
    	kill_list = srealloc(kill_list, kill_list_size * sizeof(Session_no));
        }
    
        kill_list[kill_list_size-1] = conn->session_no;
    }
    
    /*
     * check_kill_flg must NEVER be called inside an atomic call!
     */
    static void
    check_kill_flg(void)
    {
        Connection *conn;
    
        if ( active_connection != NULL )
        {
    	restart_kom("check_kill_flg: active_connection == %d",
    		    active_connection->session_no);
        }
    
        while (kill_list_size > 0)
        {
    	--kill_list_size;
    	conn = get_conn_by_number (kill_list[kill_list_size]);
    	if (conn == NULL)
    	{
    	    log("check_kill_flg(): Connection %d doesn't exist.\n",
    		kill_list[kill_list_size]);
    	}
    	else
    	{
    	    logout_client (conn);
    	    end_of_atomic (FALSE);
    	}
        }
    
        if (kill_list != NULL)
        {
    	sfree (kill_list);
    	kill_list = NULL;
        }
    }
    
    static void
    login_request(IscEvent  *event)
    {
        Connection  * cp;
        char *realuser;
        int localport;
        IscAddress *isc_adr;
        char *hostname = NULL;
    
        if (isc_sessions(kom_server_mcb) >= MAX_NO_OF_CONNECTIONS)
        {
    	BUG(("Connection attempt rejected.\n"));
    	isc_printf(event->session, "%s", "%% No connections left.\n");
    	isc_flush(event->session);
    	isc_destroy(kom_server_mcb, event->session);
    	      
    	async_rejected_connection();
    	return;
        }
    
        /* Supress logins if /etc/nologin exists */
        if (fexists("/etc/nologin"))
        {
    	isc_printf(event->session, "%s", "%% No logins allowed.\n");
    	isc_flush(event->session);
     	isc_destroy(kom_server_mcb, event->session);
    	return;
        }
    
        /* Find out if it is a mux or a client that tries to connect to
           us.  Do it by getting the local port number. */
    
        isc_adr = isc_getladdress (event->session);
        if (isc_adr == NULL)
    	restart_kom("login_request(): can't isc_getladdress (%lu)\n",
    		    event->session);
    
        localport = isc_getportnum (isc_adr);
        isc_freeaddress (isc_adr);
        
        if (localport == num_ip_mux_port)
        {
    	/* Multiplexer requesting connection */
    
    	/*
    	 ** Create, and setup the MUX for the MUX case
    	 */
    	event->session->udg = mux_create(MUX_TYPE_MUX, event->session);
    	      
    	BUG(("MUX #%d at %s connecting.\n",
    	     (int)event->session,
    	     isc_gethostname(event->session->info.tcp.raddr, NULL, 0)));
        }
        else if (localport == num_ip_client_port)
        {
    	/* Client requesting connection */
    	      
    	/*
    	 ** Create, and setup the MUX for the CLIENT case
    	 */
    	event->session->udg = mux_create(MUX_TYPE_CLIENT,
    					 event->session);
    	      
    	cp = new_client();
    	cp->mux = event->session->udg;
    	hostname = isc_gethostname(event->session->info.tcp.raddr, NULL, 0);
    	if (hostname == NULL)
    	    hostname = isc_getipnum(event->session->info.tcp.raddr, NULL, 0);
    	if (hostname == NULL)
    	{
    	    log("WNG: login_request(): unknown hostid.\n");
    	    s_crea_str(&cp->hostname, "unknown");
    	}
    	else
    	    s_crea_str(&cp->hostname, hostname);
    
    	/* Get the real user name, as returned by the Ident protocol
    	   (rfc 931). */
    	realuser = get_real_username(event->session);
    	if (realuser != NULL)
    	    s_crea_str(&cp->ident_user, realuser);
    
    	mux_addclient(event->session->udg, 0, cp);
    	      
    	BUG(("\n[Client %d from %s", cp->session_no,
    	     isc_gethostname(event->session->info.tcp.raddr, NULL, 0)));
    	BUG((" is connecting]\n"));
        }
        else
        {
    	/* Help! It was neither a client, nor a mux. */
    	restart_kom("login_request(): Neither client, nor mux.\n");
        }
    }
    
    static void
    logout_request(IscEvent *event)
    {
        Connection  * cp;
        
        if (event->session->udg->type == MUX_TYPE_MUX)
        {
    	BUG(("\n[MUX #%d at %s", (int)event->session,
    	     isc_gethostname(event->session->info.tcp.raddr, NULL, 0)));
    	BUG((" is logging out]\n"));
    
    	/*
    	 ** Logout any remaining clients
    	 */
    	mux_logout(event->session->udg);
        }
        else
        {
    	cp = event->session->udg->client_v[0].conn;
    	      
    	BUG(("\n[Client %d from %s", cp->session_no,
    	     isc_gethostname(event->session->info.tcp.raddr, NULL, 0)));
    	BUG((" is logging out]\n"));
    	      
    	add_to_kill_list(cp);
        }
    }
    
    
    static void
    message_request(IscEvent *event)
    {
        Connection *cp;
        String      tmp_str;
    
        if (event->session->udg->type == MUX_TYPE_MUX)
        {
    	event->session->udg->parse.more_to_parse = TRUE;
    	tmp_str.string = (unsigned char *)event->msg->buffer;
    	tmp_str.len    = event->msg->length;
    	mux_parse_message(event->session->udg, tmp_str);
        }
        else
        {
    	cp = event->session->udg->client_v[0].conn;
    	VBUG(("\n[Message from client %d]\n",
    	      cp->session_no));
    	/*
    	 ** Pass the message on to the parser
    	 */
    	tmp_str.string = (unsigned char *)event->msg->buffer;
    	tmp_str.len    = event->msg->length;
    	parse_message(cp, tmp_str);
        }
    }
    
    static long
    timevaldiff(struct timeval a,
    	    struct timeval b)
    {
        return 1000000 * (a.tv_sec - b.tv_sec) + a.tv_usec - b.tv_usec;
    }
    
    void
    toploop(void)
    {
        IscEvent      * event;
        Bool	pending_input = TRUE; /* Should be TRUE whenever there
    				         is or might be pending input
    					 from any client in the unparsed
    					 buffer. */
        long	timeout = 0;        /* In milliseconds. Start with a
    				       small value since we should
    				       start garbing right away. */
        struct timeval before, after;
        
        while ( !go_and_die )
        {
            if (do_sync_db)
    	{
    	    /*
    	     * do_sync_db used to save the entire database. Nowadays
    	     * all it does is to print some statistics.
    	     */
    	    cache_sync();	/* A noop in lyskomd. Actually
    				   stops the server and dumps
    				   everything in ramkomd. */
    	    dump_statistics();
    	    do_sync_db = FALSE;
    	}
    
    	gettimeofday(&before, NULL);
    	event = isc_getnextevent(kom_server_mcb,
    				 pending_input ? 0 : timeout );
    	gettimeofday(&after, NULL);
    
    	timeout -= timevaldiff(after, before) / 1000;
    
    	if ( timeout < 0 )
    	    timeout = 0;
    	
    	if ( event == NULL )
    	    restart_kom("toploop(): Got NULL event - shouldn't happen...\n");
    
    	switch ( event->event )
    	{
    	case ISC_EVENT_ERROR:
    	    if (errno != EINTR)
    	    {
    		log("toploop: ISC_EVENT_ERROR (error = '%s'):\n   '%s'\n",
    		    strerror(errno), event->msg ? event->msg->buffer
    		    : "(unknown)");
    	    }
    	    break;
    	    
    	case ISC_EVENT_TIMEOUT:
    	    BUG((">"));
    #ifdef DEBUG
    	    fflush(stdout);
    #endif
    	    if ( pending_input == FALSE )
    		timeout = end_of_atomic(TRUE); /* Idle. Do some cleaning up. */
    	    else
    	    {
    		if ( timeout == 0 )
    		    end_of_atomic(FALSE);
    		pending_input = !parse_forgotten();
    	    }
    	    
    	    	    
    	    break;
    	    
    	case ISC_EVENT_LOGIN:
    	    pending_input = TRUE;
    	    login_request(event);
    	    break;
    
    	case ISC_EVENT_LOGOUT:
    	    pending_input = TRUE;
    	    logout_request(event);
    	    break;
    
     	case ISC_EVENT_MESSAGE:
    	    pending_input = TRUE;
    	    message_request(event);
    	    break;
    
    	default:
    	    pending_input = TRUE;
    	    log("ERROR: toploop(): Unknown ISC_EVENT\n");
    	    break;
    	}
    
            isc_dispose(event);
    
    	check_kill_flg();
        }
    }