/* This module creates a mailbox (logical name HTTP_PEEK) and an AST thread 
 * to read and respond to commands.  The unit number of the created mailbox
 * is stored in the global integer peek_mailbox_unit.
 *
 * Command format (read by server):
 *     . . .   . . .   . . .   .   (600 bytes)
 *   | code  | size  | addr  | data  |
 *      0       --      --      --	Null, operation, ignored.
 *      1       n       a       --      Return 'n' bytes from address 'a'
 *      2       --      --     name     Return address of symbol 'name'
 *      3       n       a       --      Return asciz string at 'a' (max 'n').
 *
 * The return message has the same format, code is always zero, addresses
 * (code 2) are returned in the addr field, other data in the data field.
 *
 * Author:	David Jones
 * Date:	18-MAY-1997
 * Revised:	10-DEC-1997		added peek_mailbox_unit global.
 * Revised:	13-DEC-1997		Fixed bug in code 2 symbol lookup.
 * Revised:	23-SEP-1999		Support alternate global symbol for
 *					tserver_tcpshr shareable images.
 */
#include <stdio.h>
#include <iodef.h>
#include <dvidef.h>
#include <descrip.h>

static $DESCRIPTOR(mbx_name,"HTTP_PEEK");

static struct { int code; 		/* 1-return, 2-evaluate */
	int size;
	void *ptr;
	char data[600];
} message;

struct { char *name; void *addr; } http_mst_data[1];
extern void *tserver_tcp_port_list;
extern void *ts_tcp_port_list;
extern int peek_mailbox_unit;

static struct { char *name; void *addr; } sym_table[] = {
   {"peek_symbol_table", sym_table },
   {"http_mst_data", http_mst_data },
   {"tserver_tcp_port_list", &tserver_tcp_port_list },
   { "", (void *) 0 }
};

static int mbx_chan, ef, header_size;
static struct { unsigned short status, count; long pid; } iosb;

static void peek_ast ( int dummy )
{
    int status, SYS$QIO(), LIB$MOVC3(), i, j, match;
    char *str;
#ifdef DEBUG
    printf("ast iosb: %d %d %x, code: %d, %d %x\n", iosb.status,
	iosb.count, iosb.pid, message.code, message.size, message.ptr );
#endif
    if ( ((iosb.status&1) == 1) && (iosb.count >= header_size) ) {
	switch ( message.code ) {
	  case 0:
	    break;
	  case 3:
	    /*
	     * Determine length of data to copy and fixup size field.
	     */
	    str = (char *) message.ptr;
	    for ( i = 0; i < message.size; i++ ) if ( !str[i] ) break;
	    message.size = i;

	  case 1:
	    /*
	     * ptr is address of data to fetch.
	     */
	    if ( message.size > sizeof(message.data) ) 
		message.size = sizeof(message.data);
	    LIB$MOVC3 ( &message.size, message.ptr, message.data );
	    message.code = 0;
	    status = SYS$QIO ( ef, mbx_chan, IO$_WRITEVBLK, &iosb,
		peek_ast, 0, &message, header_size+message.size, 0, 0, 0, 0 );
	    return;

	  case 2:
	    /*
	     * Return address of global symbol.
	     */
	    message.ptr = (void *) 0;
	    for ( i = 0; sym_table[i].addr; i++ ) {
		char *p = sym_table[i].name;
		match = 1;
		for(j=0; j < iosb.count-header_size; j++) {
		    if ( p[j] != message.data[j] ) { match=0; break; }
		    if ( !p[j] ) { match=0; break; }
		}
		if ( match && (p[j] == '\0') ) {
		    message.ptr = sym_table[i].addr;
		    break;
		}
	    }
	    message.code = 0;
	    status = SYS$QIO ( ef, mbx_chan, IO$_WRITEVBLK, &iosb,
		peek_ast, 0, &message, header_size, 0, 0, 0, 0 );
	    return;
	  default:
	    break;
	}
    }
    /*
     * do next read.
     */
    status = SYS$QIO ( ef, mbx_chan, IO$_READVBLK, &iosb, peek_ast,
	0, &message, sizeof(message), 0, 0, 0, 0 );
}
#ifdef VAXC
#define http_base_mst_globals http_base_mst_globals_p
globalref
#endif
struct global_share {
	   int log_level;
	   int (*log_callback)(int,char*,...); 
	   int reentrant_c, reentrant_vms;
	   void *mst_data;
    } *http_base_mst_globals;
int peek_init ( int pflag )
{
    int status, code, SYS$CREMBX(), SYS$DELMBX(), SYS$QIO(), LIB$GET_EF();
    int i, LIB$GETDVI();

    mbx_chan = 0;
    peek_mailbox_unit = 0;
    header_size = sizeof(message) - sizeof(message.data);

    if ( !&tserver_tcp_port_list  ) {
	/*
	 * Using shareable image.
	 */
	for ( i = 0; sym_table[i].name[0]; i++ ) {
	    if ( sym_table[i].addr == &tserver_tcp_port_list ) {
		printf("Reset peek table symbol\n");
		sym_table[i].addr = &ts_tcp_port_list;
	    }
	}
    }

#ifdef DEBUG
    for(i=0; i< 3;i++ ) printf("sym_table[%d] = %s, %x\n", i, sym_table[i].name,
    sym_table[i].addr );
    printf("mst_globals: %x\n", http_base_mst_globals );
#endif
#ifndef __ALPHA
    sym_table[1].addr = http_base_mst_globals->mst_data;
    printf("modified sym_table[1] value to %x\n", sym_table[1].addr );
#endif
    status = SYS$CREMBX ( pflag, &mbx_chan, sizeof(message),
	sizeof(message), 0x0FF00, 0, &mbx_name, 0 );
    if ( (status&1) == 0 ) return status;
    if ( pflag ) SYS$DELMBX ( mbx_chan );

    code = DVI$_UNIT;
    status = LIB$GETDVI ( &code, &mbx_chan, 0, &peek_mailbox_unit );

    LIB$GET_EF ( &ef );
    status = SYS$QIO ( ef, mbx_chan, IO$_READVBLK, &iosb, peek_ast,
	0, &message, sizeof(message), 0, 0, 0, 0 );

    return status;
}
