Skip to content
Snippets Groups Projects
Select Git revision
20 results Searching

Makefile.in

Blame
  • Forked from Nettle / nettle
    Source project has a limited visibility.
    async.c 9.96 KiB
    /*
     * $Id: async.c,v 1.2 1996/08/03 01:29:29 ceder Exp $
     * Copyright (C) 1991, 1993  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. 
     */
    /*
     * async.c -- Receive asynchronous messages and call a handler.
     *
     * Written by Per Cederqvist 1990-07-24
     */
    
    static char *rcsid = "$Id: async.c,v 1.2 1996/08/03 01:29:29 ceder Exp $";
    
    #include <stdio.h>
    #include <ctype.h>
    #include <sys/types.h>
    #include <sys/ioctl.h>
    /* #include <sys/time.h> is included from kom-types.h */
    #include <sys/types.h>
    #if defined(__svr4__) && defined(__sparc__)
    /* Solaris */
    #include <stropts.h>
    #include <sys/conf.h>
    #define POLLINGREAD	I_NREAD
    #else
    #define POLLINGREAD	FIONREAD
    #endif
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <unistd.h>
    
    #include <kom-types.h>
    #include <kom-errno.h>
    #include <services.h>
    
    #include "async.h"
    #include "client-malloc.h"
    #include "parse.h"
    #include "client.h"
    #include "services.h"
    
    /*
     * The handlers.
     */
    static void (*new_text_handler)(Text_no    text_no, 
    				Text_stat  text_s) = NULL;
    static void (*i_am_on_handler)(Who_info info) = NULL;
    static void (*i_am_off_handler)(Pers_no pers_no) = NULL;
    static void (*new_name_handler)(Conf_no  conf_no,
    				String   old_name,
    				String   new_name) = NULL;
    static void (*directed_message_handler)(Conf_no	to,
    					Conf_no from,
    					String message) = NULL;
    static void (*saving_handler)(void) = NULL;
    
    /* Forward declarators for this file. */
        
    static Success skip_one_token(FILE *fp);
    
    /*
     * Functions that skip tokens. A token is:
     *	a number,
     *	a string or
     *	an array
     *
     * An array is
     *	the character '*' or
     *	the character '{' followed by any number of tokens followed by '}'
     */
    
    /*
     * skip_array is used when the first '{' of an array has been detected.
     * It skips all tokens to the closing '}'.
     */
    static Success
    skip_array(FILE *fp)
    {
        int c;
    
        while ( skipwhite(fp), (c=getc(fp)) != '}' )
        {
    	ungetc(c, fp);
    	if ( skip_one_token(fp) != OK )
    	    return FAILURE;
        }
        return OK;
    }
    
    
    /*
     * Skips the next token. Returns FAILURE if it isn't a token.
     */
    static Success
    skip_one_token(FILE *fp)
    {
        int c;
        u_long strlen;
    
        skipwhite(fp);
        
        switch(c=getc(fp))
        {
        case '{':
    	if ( skip_array(fp) != OK )
    	    return FAILURE;
    	    
    	break;
    
        case '*':
    	break;
    
        default:
    	if ( !isdigit(c) )
    	{
    	    kom_errno = KOM_SERVER_IS_CRAZY;
    	    return FAILURE;
    	}
    
    	ungetc(c, fp);
    	strlen = parse_long(fp);
    
    	if ( (c = getc(fp)) == 'H' )
    	{
    	    /* It was a string. Read it. */
    	    while ( strlen-- > 0 )
    		getc(fp);
    	}
    	else
    	{
    	    /* It was a number. Ignore it. */
    	    if ( ! isspace(c) )
    	    {
    		kom_errno = KOM_SERVER_IS_CRAZY;
    		return FAILURE;
    	    }
    	}	    
        }
        return OK;
    }
    
    
    
    /*
     * Skip no_of_tokens token.
     */
    static Success			/* FIXME+++ - should this be exported? */
    skip_token(FILE *fp,
    	   int   no_of_tokens)
    {
        while ( no_of_tokens-- > 0 )
        {
    	if ( skip_one_token(fp) != OK )
    	    return FAILURE;
        }
    
        return OK;
    }
    
    
    
    /*
     * Functions which gather the arguments for a handler and
     * calls that handler.
     *
     * A handler is always responsible for free:ing everything
     * which is given to it as a pointer. If no handler is registered
     * these functions of course free everything they have malloced.
     */
    static Success
    call_new_text(FILE *fp)
    {
        Text_no   text_no;
        Text_stat text = EMPTY_TEXT_STAT;
    
        text_no = parse_long(fp);
        if ( parse_text_stat(fp, &text) != OK )
    	return FAILURE;
    
        if ( new_text_handler == NULL )
        {
    	if ( text.misc_items != NULL )
    	    isc_free(text.misc_items);
        }
        else
    	new_text_handler(text_no, text);
    
        return OK;
    }
    
    
    static Success
    call_i_am_on(FILE *fp)
    {
        Who_info info = EMPTY_WHO_INFO;
    
        if ( parse_who_info(fp, &info) != OK )
    	return FAILURE;
    
        if ( i_am_on_handler == NULL )
        {
    	s_clear (&info.what_am_i_doing);
    	s_clear (&info.username);
        }
        else
    	i_am_on_handler(info);
    
        return OK;    
    }
    
    static Success
    call_i_am_off(FILE *fp)
    {
        Pers_no pers_no;
    
        pers_no = parse_long(fp);
    
        if ( i_am_off_handler != NULL )
    	i_am_off_handler(pers_no);
    
        return OK;
    }
    
    static Success
    call_new_name(FILE *fp)
    {
        Conf_no  conf_no;
        String   old_name = EMPTY_STRING;
        String   new_name = EMPTY_STRING;
    
        conf_no = parse_long(fp);
        
        if ( parse_string(fp, &old_name) != OK
    	|| parse_string(fp, &new_name) != OK )
        {
    	return FAILURE;
        }
    
        if ( new_name_handler == NULL )
        {
    	s_clear (&old_name);
    	s_clear (&new_name);
        }
        else
    	new_name_handler(conf_no, old_name, new_name);
    
        return OK;
    }
    
    
    static Success
    call_directed_message(FILE *fp)
    {
        Conf_no  to, from;
        String   message = EMPTY_STRING;
    
        to = parse_long(fp);
        from = parse_long(fp);
    
        if ( parse_string(fp, &message) != OK )
        {
    	return FAILURE;
        }
    
        if ( directed_message_handler == NULL )
        {
    	s_clear (&message);
        }
        else
            directed_message_handler(to, from, message);
    
        return OK;
    }
    
    /*
     * Call function telling that the server is syncing.
     */
    static Success
    call_saving(FILE *fp)
    {
        if (saving_handler == NULL)
        {
    	/* Do nothing */
        }
        else
        {
    	saving_handler();
        }
    
        return OK;
    }
    
    /*
     * Parse an asynchronous message and call the appropriate function.
     */
    Success
    async(FILE *fp)
    {
        int tokens_to_skip;
        Async fnc;
    
        tokens_to_skip = parse_long(fp);
        fnc = parse_long(fp);
    
        switch(fnc)
        {
        case ay_new_text:
    	return call_new_text(fp);
    
        case ay_i_am_on:
    	return call_i_am_on(fp);
    
        case ay_i_am_off:
    	return call_i_am_off(fp);
    
        case ay_new_name:
    	return call_new_name(fp);
    
        case ay_directed_message:
    	return call_directed_message(fp);
    
        case ay_saving:
    	return call_saving(fp);
    
        default:
    	/*
    	 * Messages that are not implemented. Since the server
    	 * tells how long the message is it is possible to skip it.
    	 */
    	return skip_token(fp, tokens_to_skip);
        }
    }
    
    
    /*
     * Use the following functions to say that you want to catch a
     * certain type of message. The default action is to ignore all
     * messages.
     */
    void
    register_new_text(void (*async_new_text)(Text_no    text_no, 
    					 Text_stat  text_s))
    {
        new_text_handler = async_new_text;
    }
    
    void
    register_i_am_on(void (*async_i_am_on)(Who_info info))
    {
        i_am_on_handler = async_i_am_on;
    }
    
    
    void
    register_i_am_off (void (*async_i_am_off)(Pers_no pers_no))
    {
        i_am_off_handler = async_i_am_off;
    }
    
    
    void
    register_new_name(void (*async_new_name)(Conf_no  conf_no,
    					 String   old_name,
    					 String   new_name))
    {
        new_name_handler = async_new_name;
    }
    
    
    void
    register_directed_message(void (*async_message)(Conf_no	to,
    						Conf_no	from,
    						String		message))
    {
        directed_message_handler = async_message;
    }
    
    
    void
    register_saving(void (*saving_fun)(void))
    {
        saving_handler = saving_fun;
    }
    
    
    static enum { poll_err, poll_got_msg, poll_no_msg }
    poll_server(void)
    {
        int c;
        long nread;
        
        while ( 1 )
        {    
    	if ( ioctl(kom_server->fd, POLLINGREAD, (caddr_t) &nread) != 0)
    	{
    	    kom_errno = KOM_NO_CONNECT;
    	    return poll_err;
    	}
    
    	if ( nread == 0 )
    	    return poll_no_msg;
    
    	if ( (c=getc(kom_server->in)) == ':' )
    	    return (async(kom_server->in) == OK) ? poll_got_msg : poll_err;
    
    	if ( !isspace(c) )
    	{
    	    kom_errno = KOM_SERVER_IS_CRAZY;
    	    return poll_err;
    	}
        }
    }
    
    	
    /*
     *  Wait for asynchronous message from client, or input on any of
     *  the file-descriptors in opt_set. Returns FAILURE if nothing
     *  happened in msec milliseconds or an error occurs. (kom_errno ==
     *  KOM_NO_ERR if the return was due to a timeout). Returns OK if
     *  there was an asynchronous message or input on any of the fd's in
     *  opt_set.
     *
     *  Set opt_set to NULL if you don't want to wait on any other input
     *  than a message.
     *
     *  To wait for a message or input on stdin the following code can be used:
     *
     *  fd_set read_set;
     *
     *  FD_ZERO(&read_set);
     *  FD_SET(fileno(stdin), &read_set);
     *  if ( kom_wait(read_set, 1000) == OK )
     *  {
     *	if ( FD_ISSET(fileno(stdio), &read_set) )
     *	    handle_stdin_input();
     *	else
     *	    handle_asynchronous_message();
     *  }
     *  else
     *	time_out();
     *
     *  (The handler is called from kom_wait and not handle_asynchronous_message,
     *   but there might be more to do afterwards since a handler cannot call
     *   functions that communicate with the server.)
     */
    extern  Success
    kom_wait (fd_set *opt_set,
    	  int     msec)
    {
        struct timeval wait;
        fd_set read_set;
        int    nfds;
        
        kom_errno = KOM_NO_ERROR;
        
        switch(poll_server())
        {
        case poll_err:
    	FD_ZERO(opt_set);
    	return FAILURE;
    
        case poll_got_msg:
    	FD_ZERO(opt_set);
    	return OK;
    
        case poll_no_msg:
    	break;
        }	
    
        /* No waiting message, so wait a while or two. */
        
        /* Setup timeout structure */
        wait.tv_sec  = msec / 1000;
        wait.tv_usec = (msec % 1000) * 1000;
    
        /* Setup file descriptor set */
        if ( opt_set == NULL )
        {
    	FD_ZERO(&read_set);
    	opt_set = &read_set;
        }
        FD_SET(kom_server->fd, opt_set);
    
      
        nfds = select(FD_SETSIZE,
    		  opt_set,
    		  (fd_set *) NULL,
    		  (fd_set *) NULL,
    		  &wait);
    
        if ( nfds < 0 )
        {
    	kom_errno = KOM_NO_CONNECT;
    	return FAILURE;
        }
    
        if ( FD_ISSET(kom_server->fd, opt_set) 
    	&& poll_server() == poll_err )
        {
    	return FAILURE;
        }
    
        return nfds == 0 ? FAILURE : OK;
    }