RCPT TO:<stik@ON-Luebeck.DE>
Received: from spodden.zetnet.co.uk (majordom@spodden.zetnet.co.uk [194.247.47.34])
	by maskin.oden.se (8.8.7/8.8.7) with ESMTP id XAA18145
	for <dlanor@oden.se>; Wed, 25 Feb 1998 23:46:58 +0100 (MET)
Received: (from majordom@localhost)
	by spodden.zetnet.co.uk (8.8.5/8.8.5) id WAA09725
	for stik-beta-testers-outgoing; Wed, 25 Feb 1998 22:49:46 GMT
Received: from mgate.uni-hannover.de (mgate.uni-hannover.de [130.75.2.3])
	by spodden.zetnet.co.uk (8.8.5/8.8.5) with ESMTP id WAA09718
	for <stik-beta-testers@spodden.zetnet.co.uk>; Wed, 25 Feb 1998 22:49:41 GMT
Received: from mgate2-sn7.rrzn.uni-hannover.de (actually mgate2-sn7) 
          by mgate.uni-hannover.de with LocalSMTP (PP);
          Wed, 25 Feb 1998 23:49:19 +0100
Received: from pallas.amp.uni-hannover.de by mgate2-sn7 with LocalSMTP (PP);
          Wed, 25 Feb 1998 23:47:11 +0100
Received: from juno.amp.uni-hannover.de (juno.amp.uni-hannover.de [130.75.75.17]) 
          by pallas.amp.uni-hannover.de (AIX4.2/UCB 8.7/8.7) with SMTP 
          id XAA11354; Wed, 25 Feb 1998 23:49:14 +0100 (MET)
Date: Wed, 25 Feb 1998 23:49:14 +0100 (NFT)
From: Peter Rottengatter <perot@pallas.amp.uni-hannover.de>
X-Sender: perot@juno.amp.uni-hannover.de
To: STiK Development <stik@ON-Luebeck.DE>,
        STiK Beta Testers <stik-beta-testers@spodden.zetnet.co.uk>
Subject: Background Resolver
Message-ID: <Pine.A41.3.96.980225231425.10946A-100000@juno.amp.uni-hannover.de>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Sender: owner-stik-beta-testers@spodden.zetnet.co.uk
Precedence: bulk
Reply-To: stik-beta-testers@spodden.zetnet.co.uk
X-UIDL: b583329cca44aee68dbfc12d1456ec1a


As promised in Usenet, I've put background resolve into TelStar. You can
download TelStar V1.0 from my web page.

Background resolve is useful for all clients, although by a varying
degree. An IRC client does not gain much, as it would do only one 
resolve action when it connects to the IRC server, which usually is 
the same all the time. A Telnet or FTP client gains more, those will 
do a resolve whenever they connect to any server. Usually the servers
will vary. Definitely a web client (CAB.OVL) gains most, as every third
page or so is another server which will need another resolve, and very
often it's a server never visited before (so that the DNS info cannot
be in the resolver cache). Consequently first people complained about
a frozen CAB while doing the resolve.

It is not difficult to spawn another thread or process doing the resolve
on OSs which support this. This puts the resolver into the background,
while in the foreground people can work the windows, sliders, menue etc
of their clients, they are not frozen anymore by the resolver. All the 
programmer has to do is include the piece of code that I appended to this
message. Actually it's two pieces, the first is a straight snapshot of the
corresponding stuff in TelStar (which has a session structure for each
window with a telnet session and which therefore must deal with reen-
trency issues), the second is a simplified version for clients that
never will need to worry about reentrancy as it cannot do any more but 
a single session.

The code provides a init_misc(); call which is called once at the startup
of the client. It determines whether processes or threads are available,
and therefore decides how the resolve is gonna be carried out. Then each
time a resolve is to be done, open_resolver(); is called. The first code
example requires that timer_func(); is called regularly, one probably
would employ a MU_TIMER event in evnt_multi(); to call func_timer();
regularly. The second is just a linear subroutine that does all the
resolve, and which calls the call_our_event_handler(); to handle AES
events like menue or window actions.

Take the code, and work it into your client. I do not want any credits 
for it, so revamp it to fit your needs. I'd love to see it in CAB.OVL,
this was actually what prompted me to do this stuff. So please, Dan,
have a look into it.


Cheers  Peter

PS.: I'm posting this to both lists as I know there are client programmers
      subscribing to only one of the lists.

PPS.: There are probably better methods of accessing the own commandline,
      than checking p_run to find out the own basepage. If you have any
      better idea, please let me know.

---------------------------------------------------------------------
   Peter Rottengatter       perot@pallas.amp.uni-hannover.de
                            http://www.stud.uni-hannover.de/~perot
---------------------------------------------------------------------


--------8<----------8<----------8<----------8<----------8<----------8<--------


#define  SHW_THR_CREATE   20


typedef struct thread {
     void cdecl  (*procedure) (SESSION *session);
     void         *user_stack; 
     uint32       stack_size;
     uint16       mode;
     uint32       reserved;
 } THREAD;


int          open_resolver (char host[], char port[]);
void  cdecl  resolve_thread (SESSION *session);
long         get_process_id (void);


extern  BASPAG  *_BasPag;

SESSION   session[8];
int       resolver;



int  init_misc()

/* This function determines which kind of resolving we're going to carry out.
 * It sets 'resolver' to 0 for normal, unblocking resolve. Resolve in a MiNT 
 * process is done if 'resolver' is 1, MagiC threads are used if 'resolver'
 * is 2. */

{
   int   version;
   long  date;
   char  *struc;

/* default : blocking resolve */
   resolver = 0;

/* Are we running under MiNT ? Then use MiNT processes */
   if (get_cookie ('MiNT', (long *) & struc))
        resolver = 1;

/* Are we running under MagiC ? */
   if (get_cookie ('MagX', (long *) & struc)) {
        struc += 8;
        if (* (long *) struc != 0L) {
             version = * ( int *) (* (long *) struc + 48) >> 8;
             date    = * (long *) (* (long *) struc + 16);
/* Is this a MagiC version that supports threads ? It must be a MagiC V5 at least,
 * and the MagiC must be of Apr. 1st 1996, or later */
             if (version >= 5 && ((date<<16) | ((date>>8) & 0xff00L) | (date>>24)) >= 0x19960401L)
                  resolver = 2;
           }
      }

   return (TRUE);
 }


int  open_resolver (host, port)

char  host[], port[];

{
   BASPAG  *process;
   THREAD  thread;
   int     index;
   char    *work = NULL;

/* Let's find a session structure that's not used so far */
   for (index = 0; index < 8; index++) {
        if (session[index].state == FALSE)
             break;
      }
/* None left ? Return error */
   if (index == 8)   return (-1);

/* Copy host name and port into session structure */
   strcpy (session[index].host,    host);
   strcpy (session[index].portstr, port);
   session[index].port = atoi (port);

   switch (resolver) {
      case 1 :
/* Ok, we're running under MiNT, so we try to spawn a MiNT process */

/* Create a basepage */
        if ((long) (process = (BASPAG *) Pexec (5, NULL, "", NULL)) > 0) {

/* Then shrink memory to basepage plus some space for the stack. */
             Mshrink (0, process, 512L);

/* This memory is gonna be the process' TPA */
             process->p_hitpa = (uint8 *) (process->p_lowtpa = process) + 512;

/* Inherit global data (DATA and BSS) from parent (that's us) */
             process->p_dbase = _BasPag->p_dbase;   process->p_dlen = _BasPag->p_dlen;
             process->p_bbase = _BasPag->p_bbase;   process->p_blen = _BasPag->p_blen;

/* Process is supposed to execute our function 'resolve_thread'. 1024 is just
 * a very rough guess of the size. Doesn't really matter. */
             process->p_tbase = (void *) resolve_thread;
             process->p_tlen  = 1024;

/* Pass the address of our session structure as parameter in the commandline */
             sprintf (& process->p_cmdlin[1], "%ld", (long) & session[index]);
             session[index].state = RESOLVE;

/* Give birth to child process */
             if (Pexec (104, "TS_RSLV", process, NULL) < 0)
                  break;
                  
/* Successful ? Then return, and check later (timer_func()) if resolve is
 * finished. */
             return (-2);
           }
        break;
      case 2 :
/* Ok, we're running under MagiC, so we try to spawn a MagiC thread */
        session[index].state = RESOLVE;

/* That's the resolve code */
        thread.procedure  = resolve_thread;
        
/* Let MagiC create the stack */
        thread.user_stack = NULL;
        thread.stack_size = 512;
        
/* Reserved values */
        thread.mode       = 0;
        thread.reserved   = 0L;

/* Launch thread */
        if (shel_write (SHW_THR_CREATE, 1, 0, (char *) & thread, (char *) & session[index]))
             return (-2);

/* No success ? Then fall through and do old-fashioned method */
        break;
      }

/* Old fashioned method : */

   if (resolve (host, & work, & session[index].ip_address, 1) != 1) {
        form_alert (1, "[1][ |  Can't resolve hostname !   ][ Hmm ]");
        return (-1);
      }

   if (work) {
/* get canonical name returned by resolve() */
        strncpy (session[index].host, work, 64);
        KRfree (work);
      }

/* Done, now start new session */
   if (open_telnet (& session[index]) < 0)
        return (-1);
     else
        return (index);
 }


void  cdecl  resolve_thread (sess_arg)

SESSION  *sess_arg;

{
   SESSION  *session;
   char     *canon;

   switch (resolver) {
      case 1 :
/* MiNT, so get address of session structure from command line */
        session = (SESSION *) atol (& ((BASPAG *) Supexec (get_process_id))->p_cmdlin[1]);
        break;
      case 2 :
/* MagiC, so get address of session structure from stack parameter */
        session = sess_arg;
        break;
      }

   if (resolve (session->host, & canon, & session->ip_address, 1) != 1) {
        session->ip_address = 0L;
      }
     else {
        if (canon) {
             strncpy (session->host, canon, 64);
             KRfree (canon);
           }
      }
   session->state = DONE;

/* MiNT process must terminate with Ptermxxx() */
   if (resolver == 1)   Pterm0();
 }


long  get_process_id()

{
   OSHEADER  *oshdr = * (OSHEADER **) 0x4f2L;
   BASPAG    **process;
/* Find address of our basepage in order to be able to access command line */
   if (oshdr->os_version >= 0x0102)
        process = oshdr->p_run;
     else
        process = (BASPAG **) (((oshdr->os_conf >> 1) == 4) ? 0x873cL : 0x602cL);

   return ((long) *process);
 }


int  timer_func()

{
   SESSION  *sess;

/* Check all 8 sessions */
   for (index = 0; index < 8; index++) {
        sess = & session[index];
        switch (sess->state) {
           case TELNET :
             /* ... */
             break;
           case REPLAY :
             /* ... */
             break;
           case DONE :
/* Ooops, a process or thread terminated ! */
             if (resolver == 1) {
/* MiNT processes become zombies after termination, redeem them */
                  Pwait3 (3, NULL);
                }
             if (sess->ip_address) {
/* Oh, resolve was successful, got the IP address */
                  /* Initiate session */
                }
               else {
                  form_alert (1, "[1][ |  Can't resolve hostname !   ][ Hmm ]");
                  sess->state = FALSE;
                }
             break;
           }
      }

   return (0);
 }

--------8<----------8<----------8<----------8<----------8<----------8<--------


#define  SHW_THR_CREATE   20


typedef struct thread {
     void cdecl  (*procedure) (void);
     void         *user_stack; 
     uint32       stack_size;
     uint16       mode;
     uint32       reserved;
 } THREAD;


int          resolver (char host[]);
void  cdecl  resolve_thread (void);
long         get_process_id (void);


extern  BASPAG  *_BasPag;

uint32  IP_address;
int16   resolver, state;
char    glob_host[128];



int  init_misc()

{
   int   version;
   long  date;
   char  *struc;

   resolver = 0;

   if (get_cookie ('MiNT', (long *) & struc))
        resolver = 1;

   if (get_cookie ('MagX', (long *) & struc)) {
        struc += 8;
        if (* (long *) struc != 0L) {
             version = * ( int *) (* (long *) struc + 48) >> 8;
             date    = * (long *) (* (long *) struc + 16);
             if (version >= 5 && ((date<<16) | ((date>>8) & 0xff00L) | (date>>24)) >= 0x19960401L)
                  resolver = 2;
           }
      }

   return (TRUE);
 }


int  open_resolver (host)

char  host[];

{
   BASPAG  *process;
   THREAD  thread;
   char    *work = NULL;

   strcpy (glob_host, host);

   switch (resolver) {
      case 1 :
        if ((long) (process = (BASPAG *) Pexec (5, NULL, "", NULL)) > 0) {
             Mshrink (0, process, 512L);
             process->p_hitpa = (uint8 *) (process->p_lowtpa = process) + 512;
             process->p_dbase = _BasPag->p_dbase;   process->p_dlen = _BasPag->p_dlen;
             process->p_bbase = _BasPag->p_bbase;   process->p_blen = _BasPag->p_blen;
             process->p_tbase = (void *) resolve_thread;
             process->p_tlen  = 1024;
             state = RESOLVE;
             if (Pexec (104, "RSLV", process, NULL) < 0)
                  break;
             while (state != DONE)
                  call_our_event_handler();
             strncpy (host, work, 64);
             if (resolver == 1) {
                  Pwait3 (3, NULL);
                }
             if (ip_address == 0L) {
                  form_alert (1, "[1][ |  Can't resolve hostname !   ][ Hmm ]");
                  state = 0;
                }
             return;
           }
        break;
      case 2 :
        thread.procedure  = resolve_thread;
        thread.user_stack = NULL;
        thread.stack_size = 512;
        thread.mode       = 0;
        thread.reserved   = 0L;
        state = RESOLVE;
        if (shel_write (SHW_THR_CREATE, 1, 0, (char *) & thread, NULL) {
             while (state != DONE)
                  call_our_event_handler();
             strncpy (host, work, 64);
             if (ip_address == 0L) {
                  form_alert (1, "[1][ |  Can't resolve hostname !   ][ Hmm ]");
                  state = 0;
                }
             return;
           }
        break;
      }

   if (resolve (host, & work, ip_address, 1) != 1) {
        form_alert (1, "[1][ |  Can't resolve hostname !   ][ Hmm ]");
        return (-1);
      }
   if (work) {
        strncpy (host, work, 64);
        KRfree (work);
      }
 }


void  cdecl  resolve_thread()

{
   char  *canon;

   if (resolve (glob_host, & canon, & ip_address, 1) != 1) {
        ip_address = 0L;
      }
     else {
        if (canon) {
             strncpy (glob_host, canon, 128);
             KRfree (canon);
           }
      }
   state = DONE;

   if (resolver == 1)   Pterm0();
 }

--------8<----------8<----------8<----------8<----------8<----------8<--------


---------------------------------------------------------------------------
To unsubscribe from this list, e-mail Majordomo@spodden.zetnet.co.uk
with the body of the message containing "unsubscribe Stik-Beta-Testers"
---------------------------------------------------------------------------

.
