void ccp_tr_close( ccp_action_record *rec)
{
	ccp_db_header	*db;
	uint4	status;


	db = ccp_get_reg(&rec->v.file_id);

	if (db != NULL  &&  db->segment->nl->ccp_state != CCST_OPNREQ)
	{
		status = ccp_enqw(EFN$C_ENF, LCK$K_EXMODE, &db->refcnt_iosb, LCK$M_CONVERT | LCK$M_NOQUEUE, NULL, 0,
				  NULL, 0, NULL, PSL$C_USER, 0);
		/***** Check error status here? *****/

		if (status == SS$_NORMAL  ||  ccp_stop)
			if (db->segment->nl->ccp_state == CCST_RDMODE)
				ccp_close1(db);
			else
			{
				db->close_region = TRUE;
				if (db->wmexit_requested)
					status = sys$dclast(ccp_exitwm_attempt, db, PSL$C_USER);
				else
					status = sys$dclast(ccp_exitwm_blkast, &db->exitwm_timer_id, PSL$C_USER);
				if (status != SS$_NORMAL)
					ccp_signal_cont(status);	/***** Is this reasonable? *****/
			}

		/* NOTE:  The following `else' clause is a temporary kludge.  There appears to be a scenario in which
			  the CCP loses track of a request to relinquish write mode, causing GT.M processes to hang.
			  We piggyback on the checkdb timer processing here to guarantee that the hang doesn't persist,
			  by simulating the receipt of the blocking AST that initiates write mode exit processing. */
		else
			if (db->quantum_expired  &&  CCP_SEGMENT_STATE(db->segment->nl, CCST_MASK_WRITE_MODE))
			{
				status = sys$dclast(ccp_exitwm_blkast, &db->exitwm_timer_id, PSL$C_USER);
				if (status != SS$_NORMAL)
					ccp_signal_cont(status);	/***** Is this reasonable? *****/
			}
	}

	if (rec->pid == 0  &&  !checkdb_timer)
	{
		/* Request was from ccp_tr_checkdb */
		status = sys$setimr(0, delta_30_sec, ccp_tr_checkdb, 0, 0);
		if (status == SS$_NORMAL)
			checkdb_timer = TRUE;
		else
			ccp_signal_cont(status);	/***** Is this reasonable? *****/
	}

	return;
}
Exemple #2
0
static	void	jnl_oper_krnl_ast(gd_region *reg)
{
	jnl_private_control	*jpc;

	if (!GTM_PROBE(SIZEOF(gd_region), reg, READ)  ||  !reg->open)
		return;
	if (!GTM_PROBE(SIZEOF(gd_segment), reg->dyn.addr, READ))
		return;
	if (dba_bg != reg->dyn.addr->acc_meth  &&  dba_mm != reg->dyn.addr->acc_meth)
		return;
	if (!GTM_PROBE(SIZEOF(file_control), reg->dyn.addr->file_cntl, READ))
		return;
	if (!GTM_PROBE(SIZEOF(vms_gd_info), reg->dyn.addr->file_cntl->file_info, READ))
		return;

	jpc = FILE_INFO(reg)->s_addrs.jnl;	/* since *cs_addrs is a part of vms_gds_info, no additional probe
							for sgmnt_addrs is needed */
	if (!GTM_PROBE(SIZEOF(jnl_private_control), jpc, WRITE))
		return;
	if ((FALSE == jpc->qio_active)  &&  (NOJNL != jpc->channel))
	{
		jpc->old_channel = jpc->channel;
		jpc->channel = NOJNL;
		if (!GTM_PROBE(SIZEOF(vms_lock_sb), jpc->jnllsb, WRITE))
			return;
		jpc->status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
		sys$dclast(jnl_oper_user_ast, reg, PSL$C_USER);		/* if it fails, jnl_ensure_open should cleanup */
	}
}
Exemple #3
0
/*
**++
**  ROUTINE:	netlib_write
**
**  FUNCTIONAL DESCRIPTION:
**
**  	tbs
**
**  RETURNS:	cond_value, longword (unsigned), write only, by value
**
**  PROTOTYPE:
**
**  	tbs
**
**  IMPLICIT INPUTS:	None.
**
**  IMPLICIT OUTPUTS:	None.
**
**  COMPLETION CODES:
**
**
**  SIDE EFFECTS:   	None.
**
**--
*/
unsigned int netlib_write (struct CTX **xctx, struct dsc$descriptor *dsc,
    	    	    	    struct SINDEF *sa, unsigned int *salen,
    	    	    	    struct NETLIBIOSBDEF *iosb,
    	    	    	    void (*astadr)(), void *astprm) {
    struct CTX *ctx;
    void *bufptr;
    unsigned int status;
    unsigned short buflen;
    ITMLST2 sname, *snaddr;
    int argc;

    VERIFY_CTX(xctx, ctx);
    SETARGCOUNT(argc);

    status = lib$analyze_sdesc(dsc, &buflen, &bufptr);
    if (!OK(status)) return status;

    if (argc > 3 && salen != 0) {
    	ITMLST2_INIT(sname, 0, *salen, sa);
    	snaddr = &sname;
    } else snaddr = 0;

    if (argc > 5 && astadr != 0) {
    	struct IOR *ior;
    	GET_IOR(ior, ctx, iosb, astadr, (argc > 6) ? astprm : 0);
    	if (buflen == 0) {
    	    ior->iosb.iosb_w_status = SS$_NORMAL;
    	    ior->iosb.iosb_w_count = 0;
    	    ior->iosb.iosb_l_unused = 0;
    	    status = sys$dclast(io_completion, ior, 0);
    	} else {
    	    status = sys$qio(netlib_asynch_efn, ctx->chan, IO$_WRITEVBLK,
    	    	    	    &ior->iosb,
    	    	    	    io_completion, ior, bufptr, buflen, snaddr,
    	    	    	    0, 0, 0);
    	    if (!OK(status)) FREE_IOR(ior);
    	}
    } else {
    	struct NETLIBIOSBDEF myiosb;
    	if (buflen == 0) {
    	    status = myiosb.iosb_w_status = SS$_NORMAL;
    	    myiosb.iosb_w_count = 0;
    	    myiosb.iosb_l_unused = 0;
    	} else {
    	    status = sys$qiow(netlib_synch_efn, ctx->chan, IO$_WRITEVBLK,
    	    	    	    &myiosb, 0, 0, bufptr, buflen, snaddr,
    	    	    	    0, 0, 0);
    	    if (OK(status)) status = netlib___cvt_status(&myiosb);
    	}
    	if (argc > 4 && iosb != 0) netlib___cvt_iosb(iosb, &myiosb);
    }

    return status;

} /* netlib_write */
Exemple #4
0
/*
**++
**  ROUTINE:	sp_send
**
**  FUNCTIONAL DESCRIPTION:
**
**  	Queue up some data to be sent to the subprocess.
**
**  RETURNS:	cond_value, longword (unsigned), write only, by value
**
**  PROTOTYPE:
**
**  	sp_send(SPHANDLE *ctxpp, struct dsc$descriptor *cmdstr);
**
**  IMPLICIT INPUTS:	None.
**
**  IMPLICIT OUTPUTS:	None.
**
**  COMPLETION CODES:
**  	    SS$_NORMAL:	    Normal successful completion.
**
**  SIDE EFFECTS:   	None.
**
**--
*/
unsigned int sp_send (SPHANDLE *ctxpp, void *cmdstr) {

    SPHANDLE ctx;
    struct SPD *spd;
    unsigned int status, efstate;
    unsigned short cmdlen;
    char *cmdadr;

    ctx = *ctxpp;
    if (sys$readef(ctx->termefn, &efstate) != SS$_WASCLR) return SS$_NONEXPR;
    status = lib$analyze_sdesc(cmdstr, &cmdlen, &cmdadr);
    if (!OK(status)) return status;
    spd = get_spd(cmdlen);
    if (spd == 0) return SS$_INSFMEM;
    memcpy(spd->buf, cmdadr, cmdlen);
    status = sys$setast(0);
    queue_insert(spd, ctx->sendque.tail);
    if (status == SS$_WASSET) sys$setast(1);
    sys$dclast(try_to_send, ctx, 0);

    return SS$_NORMAL;

} /* sp_send */
void	ccp_tr_writedb1(ccp_action_record *rec)
{
	ccp_action_record	request;
	ccp_db_header		*db;
	jnl_buffer		*jb;
	sgmnt_addrs		*csa;
	int4			curr_time[2];
	uint4		status, *p1, *p2, *top;


	if ((db = rec->v.h) == NULL)
		return;

	csa = db->segment;
	assert(csa->nl->ccp_state == CCST_RDMODE  ||  csa->nl->ccp_state == CCST_CLOSED  ||  csa->nl->ccp_state == CCST_OPNREQ);

	if (JNL_ENABLED(csa->hdr))
	{
		assert(csa->jnl->channel != 0);

		jb = csa->jnl->jnl_buff;

		if (jb->blocked != 0)
		{
			/* jnl writes from a previous write mode are not done yet;  try again later */
			if ((status = sys$setimr(0, delta_100_msec, ccp_writedb5, db, 0)) != SS$_NORMAL)
				ccp_signal_cont(status);	/***** Is this reasonable? *****/
			return;
		}

		jb->epoch_tn = db->wm_iosb.valblk[CCP_VALBLK_EPOCH_TN];
		jb->freeaddr = jb->dskaddr
			     = ROUND_UP(db->wm_iosb.valblk[CCP_VALBLK_JNL_ADDR], DISK_BLOCK_SIZE);
		/* lastaddr is no longer a field in jnl_buff
		 *	jb->lastaddr = db->wm_iosb.valblk[CCP_VALBLK_LST_ADDR];
		 */
		jb->free = jb->dsk
			 = 0;
	}

	/* Note:  We must clear these flags prior to changing state or a set from ccp_exitwm_blkast may be missed */
	db->quantum_expired = FALSE;
	db->tick_in_progress = FALSE;

	if (db->remote_wakeup)
	{
		for (p2 = NULL, p1 = csa->lock_addrs[0], top = p1 + SIZEOF(int4) * NUM_CLST_LCKS;
		     *p1 != 0  &&  p1 <= top;
		     ++p1)
		{
			if ((*p1 & NODENUMBER) == (process_id & NODENUMBER))
			{
				crit_wake(p1);
				if (p2 == NULL)
					p2 = p1;
				*p1 = 0;
			}
			else
				if (p2 != NULL)
				{
					*p2++ = *p1;
					*p1 = 0;
				}
		}

		db->remote_wakeup = FALSE;

		status = ccp_enq(0, LCK$K_CRMODE, &db->lock_iosb, LCK$M_CONVERT | LCK$M_SYNCSTS, NULL, 0,
				 ccp_lkrqwake1, db, ccp_lkdowake_blkast, PSL$C_USER, 0);
		/***** Check error status here? *****/
	}

	db->glob_sec->freeze = 0;
	/* db->glob_sec->wcs_active_lvl = db->glob_sec->n_bts / 2; */
	db->drop_lvl = 0;

	sys$gettim(curr_time);
	lib$add_times(curr_time, db->glob_sec->ccp_quantum_interval, &db->start_wm_time);

	csa->nl->ccp_state = CCST_WRTGNT;

	if (db->blocking_ast_received)
	{
		status = sys$dclast(ccp_exitwm_blkast, &db->exitwm_timer_id, PSL$C_USER);
		if (status != SS$_NORMAL)
			ccp_signal_cont(status);	/***** Is this reasonable? *****/
	}

	csa->nl->ccp_crit_blocked = FALSE;
	++csa->nl->ccp_cycle;

	status = sys$setimr(0, &db->glob_sec->ccp_quantum_interval, ccp_quantum_interrupt, &db->quantum_timer_id, 0);
	if (status != SS$_NORMAL)
		ccp_signal_cont(status);	/***** Is this reasonable? *****/

	db->dirty_buffers_acquired = FALSE;
	ccp_pndg_proc_wake(&db->write_wait);

	status = ccp_enq(0, LCK$K_EXMODE, &db->flush_iosb, LCK$M_CONVERT | LCK$M_SYNCSTS, NULL, 0,
			 ccp_reqdrtbuf_interrupt, db, NULL, PSL$C_USER, 0);
	if (status == SS$_SYNCH)
	{
		request.action = CCTR_GOTDRT;
		request.pid = 0;
		request.v.h = db;
		ccp_act_request(&request);
	}
	/***** Check error status here? *****/

}
Exemple #6
0
static int 
vms_ualarm(int mseconds, int interval)
{
    Alarm *a, abase;
    struct item_list3 {
        word length;
        word code;
        void *bufaddr;
        void *retlenaddr;
    } ;
    static struct item_list3 itmlst[2];
    static int first = 1;
    unsigned long asten;
    int iss, enabled;

    if (first) {
        first = 0;
        itmlst[0].code       = JPI$_ASTEN;
        itmlst[0].length     = sizeof(asten);
        itmlst[0].retlenaddr = NULL;
        itmlst[1].code       = 0;
        itmlst[1].length     = 0;
        itmlst[1].bufaddr    = NULL;
        itmlst[1].retlenaddr = NULL;

        iss = lib$get_ef(&alarm_ef);
        if (VMSERR(iss)) lib$signal(iss);

        a0 = &alarm_base;
        a0->function = UAL_NULL;
    }
    itmlst[0].bufaddr    = &asten;
    
    iss = sys$getjpiw(0,0,0,itmlst,0,0,0);
    if (VMSERR(iss)) lib$signal(iss);
    if (!(asten&0x08)) return -1;

    a = &abase;
    if (mseconds) {
        a->function = UAL_SET;
    } else {
        a->function = UAL_CLEAR;
    }

    us_to_VMS(mseconds, a->delay);
    if (interval) {
        us_to_VMS(interval, a->interval);
        a->repeat = 1;
    } else 
        a->repeat = 0;

    iss = sys$clref(alarm_ef);
    if (VMSERR(iss)) lib$signal(iss);

    iss = sys$dclast(ualarm_AST,a,0);
    if (VMSERR(iss)) lib$signal(iss);

    iss = sys$waitfr(alarm_ef);
    if (VMSERR(iss)) lib$signal(iss);

    if (a->function == UAL_ACTIVE) 
        return VMS_to_us(a->remain);
    else
        return 0;
}
void iott_close(io_desc *v, mval *pp)	/* exception is the only deviceparameter allowed */
{
	unsigned short		iosb[4];
	uint4			dummy_msk, enable_msk, status;
	d_tt_struct		*tt_ptr;
	t_cap			s_mode;
	params			ch;
	int			p_offset;

	assert(v->type == tt);
	if (v->state != dev_open)
		return;

	assert((v->pair.in == v) || (v->pair.out == v));
	tt_ptr = (d_tt_struct *)(v->dev_sp);

	if (v->pair.out == v)
	{
		status = sys$dclast(iott_wtclose, tt_ptr, 0);
		if (status != SS$_NORMAL)
			rts_error(VARLSTCNT(1) status);
	}

	if (v->pair.in == v && tt_ptr->term_chars_twisted)
	{
		status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SENSEMODE,
			iosb, 0, 0, &s_mode, 12, 0, 0, 0, 0);
		if (status == SS$_NORMAL)
			status = iosb[0];
		if (status != SS$_NORMAL)
			rts_error(VARLSTCNT(1) status);
		s_mode.ext_cap &= (~TT2$M_PASTHRU & ~TT2$M_EDITING);
		s_mode.ext_cap |= (tt_ptr->ext_cap & (TT2$M_PASTHRU | TT2$M_EDITING));
		s_mode.term_char &= (~TT$M_ESCAPE);
		s_mode.term_char |= (tt_ptr->term_char & TT$M_ESCAPE);
		status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SETMODE,
			iosb, 0, 0, &s_mode, 12, 0, 0, 0, 0);
		if (status == SS$_NORMAL)
			status = iosb[0];
		if (status != SS$_NORMAL)
			rts_error(VARLSTCNT(1) status);
	}

	if (v->pair.in == io_std_device.in)
	{
		enable_msk = std_dev_outofband_msk & CTRLY_MSK;
		if (enable_msk == CTRLY_MSK)
			status = lib$enable_ctrl(&enable_msk, &dummy_msk);
			if (status != SS$_NORMAL)
				rts_error(VARLSTCNT(1) status);
	}

	status = sys$dassgn(tt_ptr->channel);
	if (status != SS$_NORMAL)
		rts_error(VARLSTCNT(1) status);

	p_offset = 0;
	while (*(pp->str.addr + p_offset) != iop_eol)
	{
		if ((ch = *(pp->str.addr + p_offset++)) == iop_exception)
		{
			v->error_handler.len = *(pp->str.addr + p_offset);
			v->error_handler.addr = pp->str.addr + p_offset + 1;
			s2pool(&v->error_handler);
		}
		p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
			(unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
	}

	v->state = dev_closed;
	astq_dyn_alloc += TERMINAL_STATIC_ASTS;
	astq_dyn_avail += TERMINAL_STATIC_ASTS;
	free(tt_ptr->sb_buffer);
	free(tt_ptr->io_buffer);

	return;
}
Exemple #8
0
/*
**++
**  ROUTINE:	netlib_name_to_address
**
**  FUNCTIONAL DESCRIPTION:
**
**  	Uses the UCX IO$_ACPCONTROL $QIO function to translate a host
**  name into one or more IP addresses.
**
**  RETURNS:	cond_value, longword (unsigned), write only, by value
**
**  PROTOTYPE:
**
**  	NETLIB_NAME_TO_ADDRESS  ctx, which, namdsc, addrlist, listsize [,count] [,iosb] [,astadr] [,astprm]
**
**  IMPLICIT INPUTS:	None.
**
**  IMPLICIT OUTPUTS:	None.
**
**  COMPLETION CODES:
**
**
**  SIDE EFFECTS:   	None.
**
**--
*/
unsigned int netlib_name_to_address (struct CTX **xctx, unsigned int *whichp,
    	    	    	    struct dsc$descriptor *namdsc,
    	    	    	    struct INADDRDEF *addrlist,
    	    	    	    unsigned int *listsize, unsigned int *count,
    	    	    	    struct NETLIBIOSBDEF *iosb,
    	    	    	    void (*astadr)(), void *astprm) {

    struct CTX *ctx;
    struct INADDRDEF addr;
    struct NETLIBIOSBDEF myiosb;
    struct HOSTENT hostent;
    unsigned int status, subfunction;
    ITMLST2 subfdsc;
    ITMLST2 entdsc;
    unsigned short helen;
    int argc;

    VERIFY_CTX(xctx, ctx);
    SETARGCOUNT(argc);

    if (argc < 5) return SS$_INSFARG;

    if (namdsc == 0 || addrlist == 0 || listsize == 0) return SS$_BADPARAM;

    if (OK(netlib_strtoaddr(namdsc, &addr))) {
    	addrlist[0] = addr;
    	if (argc > 5 && count != 0) *count = 1;
    	if (argc > 6 && iosb != 0) {
    	    iosb->iosb_w_status = SS$_NORMAL;
    	    iosb->iosb_w_count = 1;
    	    iosb->iosb_l_unused = 0;
    	}
    	if (argc > 7 && astadr != 0) {
    	    return sys$dclast(astadr, (argc > 8) ? astprm : 0, 0);
    	} else {
    	    return SS$_NORMAL;
    	}
    }

    if (argc > 7 && astadr != 0) {
    	struct IOR *ior;
    	GET_IOR(ior, ctx, iosb, astadr, (argc > 8) ? astprm : 0);
    	status = lib$get_vm(&hostent_size, &ior->spec_hostent);
    	if (!OK(status)) {
    	    FREE_IOR(ior);
    	    return status;
    	}
    	ior->specior.subfunction =
    	    (INETACP$C_HOSTENT_OFFSET << 8) | INETACP_FUNC$C_GETHOSTBYNAME;

    	ITMLST2_INIT(subfdsc, 0, sizeof(ior->specior.subfunction),
    	    	    &ior->specior.subfunction);
    	ITMLST2_INIT(entdsc, 0, hostent_size, ior->spec_hostent);
    	
    	ior->spec_useralist = addrlist;
    	ior->spec_length = *listsize;
    	ior->spec_retlen = count;
    	ior->iorflags = IOR_M_COPY_ADDRS;
    	status = sys$qio(netlib_asynch_efn, ctx->chan, IO$_ACPCONTROL, &ior->iosb,
    	    	    	    io_completion, ior, &subfdsc, namdsc,
    	    	    	    &ior->specior.fromlen, &entdsc, 0, 0);
    	if (!OK(status)) FREE_IOR(ior);
    	return status;
    }

    subfunction =
    	    (INETACP$C_HOSTENT_OFFSET << 8) | INETACP_FUNC$C_GETHOSTBYNAME;

    ITMLST2_INIT(subfdsc, 0, sizeof(subfunction), &subfunction);
    ITMLST2_INIT(entdsc, 0, hostent_size, &hostent);
    status = sys$qiow(netlib_synch_efn, ctx->chan, IO$_ACPCONTROL, &myiosb,
    	    	    	0, 0, &subfdsc, namdsc, &helen, &entdsc, 0, 0);
    if (OK(status)) status = netlib___cvt_status(&myiosb);
    if (argc > 6 && iosb != 0) netlib___cvt_iosb(iosb, &myiosb);
    if (OK(status)) {
    	char *base;
    	unsigned int *offlst;
    	int i;
    	base = (char *) &hostent;
    	i = 0;
    	if (hostent.addrlist_offset != 0) {
    	    offlst = (unsigned int *) (base+hostent.addrlist_offset);
    	    while (i < *listsize && offlst[i] != 0) {
    	    	addrlist[i] = *(struct INADDRDEF *) (base + offlst[i]);
    	    	i++;
    	    }
    	}
    	if (argc > 5 && count != 0) *count = i;
    }

    return status;
    
} /* netlib_name_to_address */
Exemple #9
0
/*
**++
**  ROUTINE:	netlib_connect_by_name
**
**  FUNCTIONAL DESCRIPTION:
**
**  	Connects to a remote host/port by name.  The name is looked up,
**  then a connection is tried to each address until a connection is
**  established, or we run out of addresses.
**
**  RETURNS:	cond_value, longword (unsigned), write only, by value
**
**  PROTOTYPE:
**
**  	NETLIB_CONNECT_BY_NAME  ctxptr, namdsc, port [,iosb] [,astadr] [,astprm]
**
**  ctxptr: 	NETLIB context, longword (unsigned), read only, by reference
**  namdsc: 	char_string, character string, read only, by descriptor
**  port:   	word_unsigned, word (unsigned), read only, by reference
**  iosb:   	io_status_block, quadword (unsigned), write only, by reference
**  astadr: 	ast_procedure, procedure value, call, by reference
**  astprm: 	user_arg, longword (unsigned), read only, by value
**
**  IMPLICIT INPUTS:	None.
**
**  IMPLICIT OUTPUTS:	None.
**
**  COMPLETION CODES:
**  	SS$_NORMAL: 	    normal successful completion
**  	SS$_INSFARG:	    not enough arguments
**  	SS$_BADPARAM:	    invalid argument
**  	Codes from LIB$GET_VM, LIB$ANALYZE_SDESC, and
**  	other NETLIB network status codes.
**
**  SIDE EFFECTS:   	None.
**
**--
*/
unsigned int netlib_connect_by_name (struct CTX **xctx,
    	    	    struct dsc$descriptor *dsc, unsigned short *port,
    	    	    struct NETLIBIOSBDEF *iosb, void (*astadr)(), void *astprm) {

    struct Connect_Context *con;
    struct CTX *ctx;
    struct INADDRDEF addr;
    unsigned int status, size;
    unsigned short namlen;
    char *namp;
    int argc;

/*
**  Verify the arguments
*/
    VERIFY_CTX(xctx, ctx);
    SETARGCOUNT(argc);

    if (argc < 3) return SS$_INSFARG;
    if (dsc == 0 || port == 0) return SS$_BADPARAM;

/*
**  Allocate and fill in the connection context
*/
    status = lib$analyze_sdesc(dsc, &namlen, &namp);
    if (!OK(status)) return status;
    size = namlen + sizeof(struct Connect_Context);
    status = lib$get_vm(&size, &con);
    if (!OK(status)) return status;
    memset(con, 0, size);
    con->name = (char *) (con + 1);
    memcpy(con->name, namp, namlen);
    INIT_SDESC(con->dsc, namlen, con->name);
    con->ctx = ctx;
    con->sin.sin_w_family = NETLIB_K_AF_INET;
    con->sin.sin_w_port = netlib_word_swap(*port);
    con->ctxsize = size;

    size = sizeof(con->htadrlst)/sizeof(con->htadrlst[0]);
    if (argc > 3 && iosb != 0) con->user_iosb = iosb;

    if (argc > 4 && astadr != 0) {
    	con->astadr = astadr;
    	if (argc > 5) con->astprm = astprm;
    }
/*
**  If they provided us with a dotted-decimal IP address, fake
**  out do_connect to make it look like we looked up the address
**  via DNS.
*/
    if (OK(netlib_strtoaddr(&con->dsc, &addr))) {
    	con->iosb.iosb_w_status = SS$_NORMAL;
    	con->nsadrcnt = 1;
    	con->nsadrlst[0] = addr;
    	if (con->astadr != 0) return sys$dclast(do_connect, con, 0);
    	return do_connect(con);
    }

/*
**  Make lookup via host table synchronous and in main-line thread
**  because we can't call it from AST level for all packages
*/
    status = netlib_name_to_address(&con->ctx, &useht, &con->dsc,
    	    	    con->htadrlst, &size, &con->htadrcnt, &con->iosb);
    if (!OK(status)) con->htadrcnt = 0;
    size = sizeof(con->nsadrlst)/sizeof(con->nsadrlst[0]);

/*
**  For an asynch call, do the DNS lookup and have DO_CONNECT invoked
**  as the AST routine
*/
    if (argc > 4 && astadr != 0) {
    	status = netlib_name_to_address(&con->ctx, &usedns, &con->dsc,
    	    	    con->nsadrlst, &size, &con->nsadrcnt, &con->iosb,
    	    	    do_connect, con);
    	if (!OK(status)) lib$free_vm(&con->ctxsize, &con);
    	return status;
    }

/*
**  Synchronous call: do the DNS lookup...
*/
    status = netlib_name_to_address(&con->ctx, &usedns, &con->dsc,
    	    	    con->nsadrlst, &size, &con->nsadrcnt, &con->iosb);

/*
**  ... if it failed, fall back on the host table lookup info we got
*/
    if (!OK(status)) {
    	con->iosb.iosb_w_status = SS$_ENDOFFILE;
    	con->nsadrcnt = 0;
    }

/*
**  Just call DO_CONNECT to complete this for us
*/
    return do_connect(con);

} /* netlib_connect_by_name */
gtcm_server()
{
	static readonly int4	reptim[2] = {-100000, -1};	/* 10ms */
       	static readonly int4	wait[2] =  {-1000000, -1};	/* 100ms */
	void		gtcm_ch(), gtcm_exi_handler(), gtcm_init_ast(), gtcm_int_unpack(), gtcm_mbxread_ast(),
			gtcm_neterr(), gtcm_read_ast(), gtcm_remove_from_action_queue(), gtcm_shutdown_ast(), gtcm_write_ast(),
			la_freedb();
	bool		gtcm_link_accept();
	bool		alid;
	char		buff[512];
	char		*h = NULL;
	char		*la_getdb();
	char		nbuff[256];
	char		*pak = NULL;
	char		reply;
	unsigned short	outlen;
	int4		closewait[2] = {0, -1};
	int4		inid = 0, mdl = 0, nid = 0, days = 0;
	int4		lic_status;
	int4		lic_x;
	int4		lm_mdl_nid();
	uint4		status;
	int		i, receive(), value;
	mstr		name1, name2;
	struct NTD	*cmu_ntdroot();
	connection_struct *prev_curr_entry;
	struct	dsc$descriptor_s	dprd;
	struct	dsc$descriptor_s	dver;
	$DESCRIPTOR(node_name, nbuff);
	$DESCRIPTOR(proc_name, "GTCM_SERVER");
	$DESCRIPTOR(timout, buff);
	DCL_THREADGBL_ACCESS;

	GTM_THREADGBL_INIT;
        assert(0 == EMPTY_QUEUE);       /* check so dont need gdsfhead everywhere */
	common_startup_init(GTCM_GNP_SERVER_IMAGE); /* Side-effect: Sets skip_dbtriggers to TRUE for non-trigger platforms */
	gtm_env_init();	/* read in all environment variables */
	name1.addr = "GTCMSVRNAM";
	name1.len = SIZEOF("GTCMSVRNAM") - 1;
	status = trans_log_name(&name1, &name2, nbuff);
	if (SS$_NORMAL == status)
	{
		proc_name.dsc$a_pointer = nbuff;
		proc_name.dsc$w_length = node_name.dsc$w_length = name2.len;
	} else if (SS$_NOLOGNAM == status)
	{
		MEMCPY_LIT(nbuff, "GTCMSVR");
		node_name.dsc$w_length = SIZEOF("GTCMSVR") - 1;
	} else
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
	sys$setprn(&proc_name);
	status = lib$get_foreign(&timout, 0, &outlen, 0);
	if ((status & 1) && (6 > outlen))
	{
		for (i = 0;  i < outlen;  i++)
		{
			value = value * 10;
			if (buff[i] <= '9' && buff[i] >= '0')
				value += buff[i] - 48;
			else
				break;
		}
		if (outlen && (i == outlen))
		{
			cm_timeout = TRUE;
			closewait[0] = value * -10000000;
		}
	}
	dprd.dsc$w_length = cm_prd_len;
	dprd.dsc$b_dtype  = DSC$K_DTYPE_T;
	dprd.dsc$b_class  = DSC$K_CLASS_S;
	dprd.dsc$a_pointer= cm_prd_name;
	dver.dsc$w_length = cm_ver_len;
	dver.dsc$b_dtype  = DSC$K_DTYPE_T;
	dver.dsc$b_class  = DSC$K_CLASS_S;
	dver.dsc$a_pointer= cm_ver_name;
	ast_init();
	licensed = TRUE;
	lkid = 2;
#	ifdef NOLICENSE
	lid = 1;
#	else
	/* this code used to be scattered to discourage reverse engineering, but since it now disabled, that seems pointless */
	lic_status = ((NULL == (h = la_getdb(LMDB))) ? LP_NOCNFDB : SS$_NORMAL);
	lic_status = ((1 == (lic_status & 1)) ? lm_mdl_nid(&mdl, &nid, &inid) : lic_status);
	lic_status = ((1 == (lic_status & 1)) ? lp_licensed(h, &dprd, &dver, mdl, nid, &lid, &lic_x, &days, pak) : lic_status);
	if (LP_NOCNFDB != lic_status)
		la_freedb(h);
	if (1 == (lic_status & 1))
	{
		licensed = TRUE;
		if (days < 14)
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_WILLEXPIRE);
	} else
	{
		licensed = FALSE;
		sys$exit(lic_status);
	}
#	endif
	gtcm_ast_avail = astq_dyn_avail - GTCM_AST_OVRHD;
	stp_init(STP_INITSIZE);
	rts_stringpool = stringpool;
	cache_init();
	procnum = 0;
	get_proc_info(0, TADR(login_time), &image_count);
        memset(proc_to_clb, 0, SIZEOF(proc_to_clb));
	status = cmi_init(&node_name, 0, 0, gtcm_init_ast, gtcm_link_accept);
	if (!(status & 1))
	{
		rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ((status ^ 3) | 4));
		sys$exit(status);
	}
	ntd_root = cmu_ntdroot();
	ntd_root->mbx_ast =  gtcm_mbxread_ast;
	ntd_root->err = gtcm_neterr;
	gtcm_connection = FALSE;
	lib$establish(gtcm_ch);
	gtcm_exi_blk.exit_hand = &gtcm_exi_handler;
	gtcm_exi_blk.arg_cnt = 1;
	gtcm_exi_blk.cond_val = &gtcm_exi_condition;
	sys$dclexh(&gtcm_exi_blk);
	INVOKE_INIT_SECSHR_ADDRS;
	initialize_pattern_table();
	assert(run_time); /* Should have been set by common_startup_init */
	while (!cm_shutdown)
	{
		if (blkdlist)
			gtcml_chkreg();

		assert(!lib$ast_in_prog());
		status = sys$dclast(&gtcm_remove_from_action_queue, 0, 0);
		if (SS$_NORMAL != status)
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) CMERR_CMSYSSRV, 0, status, 0);
		if (INTERLOCK_FAIL == curr_entry)
			rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) CMERR_CMINTQUE);
		if (EMPTY_QUEUE != curr_entry)
		{
			switch (*curr_entry->clb_ptr->mbf)
			{
				case CMMS_L_LKCANALL:
					reply = gtcmtr_lkcanall();
					break;
				case CMMS_L_LKCANCEL:
					reply = gtcmtr_lkcancel();
					break;
				case CMMS_L_LKREQIMMED:
					reply = gtcmtr_lkreqimmed();
					break;
				case CMMS_L_LKREQNODE:
					reply = gtcmtr_lkreqnode();
					break;
				case CMMS_L_LKREQUEST:
					reply = gtcmtr_lkrequest();
					break;
				case CMMS_L_LKRESUME:
					reply = gtcmtr_lkresume();
					break;
				case CMMS_L_LKACQUIRE:
					reply = gtcmtr_lkacquire();
					break;
				case CMMS_L_LKSUSPEND:
					reply = gtcmtr_lksuspend();
					break;
				case CMMS_L_LKDELETE:
					reply = gtcmtr_lkdelete();
					break;
				case CMMS_Q_DATA:
					reply = gtcmtr_data();
					break;
				case CMMS_Q_GET:
					reply = gtcmtr_get();
					break;
				case CMMS_Q_KILL:
					reply = gtcmtr_kill();
					break;
				case CMMS_Q_ORDER:
					reply = gtcmtr_order();
					break;
				case CMMS_Q_PREV:
					reply = gtcmtr_zprevious();
					break;
				case CMMS_Q_PUT:
					reply = gtcmtr_put();
					break;
				case CMMS_Q_QUERY:
					reply = gtcmtr_query();
					break;
				case CMMS_Q_ZWITHDRAW:
					reply = gtcmtr_zwithdraw();
					break;
				case CMMS_S_INITPROC:
					reply = gtcmtr_initproc();
					break;
				case CMMS_S_INITREG:
					reply = gtcmtr_initreg();
					break;
				case CMMS_S_TERMINATE:
					reply = gtcmtr_terminate(TRUE);
					break;
				case CMMS_E_TERMINATE:
					reply = gtcmtr_terminate(FALSE);
					break;
				case CMMS_U_LKEDELETE:
					reply = gtcmtr_lke_clearrep(curr_entry->clb_ptr, curr_entry->clb_ptr->mbf);
					break;
				case CMMS_U_LKESHOW:
					reply = gtcmtr_lke_showrep(curr_entry->clb_ptr, curr_entry->clb_ptr->mbf);
					break;
				case CMMS_B_BUFRESIZE:
					reply = CM_WRITE;
					value = *(unsigned short *)(curr_entry->clb_ptr->mbf + 1);
					if (value > curr_entry->clb_ptr->mbl)
					{
						free(curr_entry->clb_ptr->mbf);
						curr_entry->clb_ptr->mbf = malloc(value);
					}
					*curr_entry->clb_ptr->mbf = CMMS_C_BUFRESIZE;
					curr_entry->clb_ptr->mbl = value;
					curr_entry->clb_ptr->cbl = 1;
					break;
				case CMMS_B_BUFFLUSH:
					reply = gtcmtr_bufflush();
					break;
				case CMMS_Q_INCREMENT:
					reply = gtcmtr_increment();
					break;
				default:
					reply = FALSE;
					if (SS$_NORMAL == status)
                                                rts_error_csa(CSA_ARG(NULL)
							VARLSTCNT(3) ERR_BADGTMNETMSG, 1, (int)*curr_entry->clb_ptr->mbf);
					break;
			}
			if (curr_entry)		/* curr_entry can be NULL if went through gtcmtr_terminate */
			{
				status = sys$gettim(&curr_entry->lastact[0]);
				if (SS$_NORMAL != status)
					rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
				/* curr_entry is used by gtcm_mbxread_ast to determine if it needs to defer the interrupt message */
				prev_curr_entry = curr_entry;
				if (CM_WRITE == reply)
				{	/* if ast == gtcm_write_ast, let it worry */
					curr_entry->clb_ptr->ast = gtcm_write_ast;
					curr_entry = EMPTY_QUEUE;
					cmi_write(prev_curr_entry->clb_ptr);
				} else
				{
					curr_entry = EMPTY_QUEUE;
					if (1 == (prev_curr_entry->int_cancel.laflag & 1))
					{  /* valid interrupt cancel msg, handle in gtcm_mbxread_ast */
						status = sys$dclast(gtcm_int_unpack, prev_curr_entry, 0);
						if (SS$_NORMAL != status)
							rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
					} else  if (CM_READ == reply)
					{
						prev_curr_entry->clb_ptr->ast = gtcm_read_ast;
						cmi_read(prev_curr_entry->clb_ptr);
					}
				}
			}
		} else  if (1 < astq_dyn_avail)
		{
#			ifdef GTCM_REPTIM
			/* if reptim is not needed - and smw doesn't know why it would be - remove this	*/
			status = sys$schdwk(0, 0, &wait[0], &reptim[0]);
#			else
			status = sys$schdwk(0, 0, &wait[0], 0);
#			endif
			sys$hiber();
			sys$canwak(0, 0);
		}
		if (cm_timeout && (0 == gtcm_users))
                        sys$setimr(efn_ignore, closewait, gtcm_shutdown_ast, &cm_shutdown, 0);
	}
}