Пример #1
0
VOID
GCsend( SVC_PARMS *svc_parms )
{
	GCA_GCB		*gcb = (GCA_GCB *)svc_parms->gc_cb;
	struct subchan	*subchan = &gcb->send_chan
				[ svc_parms->flags.flow_indicator ];

	GCTRACE(1)( "%sGCsend %d: send %d%s\n",
		gc_trace > 2 ? "===\n" : "",
		gcb->id, svc_parms->svc_send_length,
		gc_chan[ svc_parms->flags.flow_indicator ] );

	svc_parms->status = OK;

	/* Sanity check for duplicate request. */

	if( subchan->state != GC_CHAN_QUIET )
	{
		GCTRACE(1)( "GCsend: duplicate request\n" );
		GC_abort_sends( gcb, GC_ASSOC_FAIL );
		GC_drive_complete( gcb );
		return;
	}

	/* Note request on subchannel.  */

	subchan->svc_parms = svc_parms;
	subchan->buf = svc_parms->svc_buffer;
	subchan->len = svc_parms->svc_send_length;
	subchan->state = GC_CHAN_ACTIVE;

	if ( gcb->ccb.flags & GC_PEER_SEND )
	{
	    /*
	    ** Our partner sent an old style peer info packet to us
	    ** and is expecting one in return.  We must combine the 
	    ** GCA info with ours.
	    */
	    MEcopy( (PTR)svc_parms->svc_buffer,
		    min( svc_parms->svc_send_length, 
			 sizeof( gcb->ccb.assoc_info.orig_info.gca_info ) ),
		    (PTR)&gcb->ccb.assoc_info.orig_info.gca_info );
	    subchan->len = sizeof( gcb->ccb.assoc_info.orig_info );
	    subchan->buf = (char *)&gcb->ccb.assoc_info.orig_info;
	    gcb->ccb.flags &= ~GC_PEER_SEND;
	    GCTRACE(1)( "GCsend %d: sending GCA and CL peer info\n", gcb->id );
	}

	/* Start the writer state machine, if not already running.  */

	if( !gcb->send.running )
	{
		gcb->send.running = TRUE;
		GC_send_sm( gcb );
	}
# ifdef OS_THREADS_USED
	if ( iisynclisten && svc_parms->flags.flow_indicator == 0 )
		GC_send_sm( gcb );
# endif /* OS_THREADS_USED */
}
Пример #2
0
VOID
GCpurge( SVC_PARMS *svc_parms )
{
	GCA_GCB 	*gcb = (GCA_GCB *)svc_parms->gc_cb;

	GCTRACE(1)( "%sGCpurge %d\n", gc_trace > 2 ? "===\n" : "", gcb->id );

	svc_parms->status = OK;

	/* No queueing purges. */

	if( gcb->sendchops.state == GC_CHAN_ACTIVE )
		return;

	/* Note request. */

	gcb->sendchops.state = GC_CHAN_ACTIVE;

	/* Start the sender state machine, if not already running.  */

	if( !gcb->send.running )
	{
		gcb->send.running = TRUE;
		GC_send_sm( gcb );
	}
# ifdef OS_THREADS_USED
	if ( iisynclisten && svc_parms->flags.flow_indicator == 0 )
		GC_send_sm( gcb );
# endif /* OS_THREADS_USED */
}
Пример #3
0
static VOID
GC_abort_recvs( GCA_GCB *gcb, STATUS status )
{
	i4 i;

	/*
	** Look for active RECV requests.
	** For each, copy the status around and set the request up
	** for callback.
	*/

	for( i = GC_SUB; i--; )
	{
	    struct subchan *chan = &gcb->recv_chan[i];

  	    if( status == GC_TIME_OUT &&
		chan->svc_parms != NULL &&
	        chan->svc_parms->time_out == -1 )
	    {
		GCTRACE(2)( "GC_abort_recvs %d:%d status %x\n", gcb->id,
	           gc_chan[ chan->svc_parms->flags.flow_indicator ], status );
		continue;
	    }

	    if( chan->state == GC_CHAN_ACTIVE )
	    {
		chan->svc_parms->status = status;
		*(chan->svc_parms->sys_err) = gcb->recv.syserr; 
		chan->state = GC_CHAN_DONE;
	    }
	}
}
Пример #4
0
VOID
GCdisconn( SVC_PARMS *svc_parms )
{
    GCA_GCB	*gcb = (GCA_GCB *)svc_parms->gc_cb;
    BS_PARMS	bsp;

    svc_parms->status = OK;

    /* 
    ** Not connected? 
    */
    if ( ! gcb )
    {
	(*svc_parms->gca_cl_completion)( svc_parms->closure );
	return;
    }

    GCTRACE(1)( "%sGCdisconn %d\n", gc_trace > 2 ? "===\n" : "", gcb->id );

    /*
    ** Fail any outstanding requests: calling GCdisconn with 
    ** incomplete requests aborts those reqests.
    */
    GC_abort_recvs( gcb, GC_ASSN_RLSED );
    GC_abort_sends( gcb, GC_ASSN_RLSED );

    /*
    ** Start up disconnect state machine.
    */
    gcb->sendclose.svc_parms = svc_parms;
    gcb->sendclose.state = GC_CHAN_ACTIVE;
    GC_disc_sm( gcb );

    return;
}
Пример #5
0
static void
GC_send_sm( GCA_GCB *gcb )
{
	register int 	n;

	/* Copy some parameters */

	gcb->send.bsp.func = GC_send_sm;
	gcb->send.bsp.closure = (PTR)gcb;
	gcb->send.bsp.syserr = &gcb->send.syserr;
	gcb->send.bsp.bcb = gcb->bcb;
	gcb->send.bsp.lbcb = listenbcb;
	gcb->send.bsp.timeout = -1;
# ifdef OS_THREADS_USED
	if ( iisynclisten )
	    gcb->send.bsp.regop = BS_POLL_INVALID; /* force blocking IO */
	else
	    gcb->send.bsp.regop = BS_POLL_SEND;
# else /* OS_THREADS_USED */
	gcb->send.bsp.regop = BS_POLL_SEND;
# endif /* OS_THREADS_USED */
	gcb->send.bsp.status = OK;

top:
	GCTRACE(3)( "GC_send_sm %d: state %s\n", 
		gcb->id, gc_trs[ gcb->send.state ] );

	switch( gcb->send.state )
	{
	case GC_W_LOOK:
	    /* Look for something to send. */

	    if( gcb->send_chan[ n = 1 ].state == GC_CHAN_ACTIVE || 
		gcb->send_chan[ n = 0 ].state == GC_CHAN_ACTIVE )
	    {
		    /* Sending data.  Setup MTYP. */

		    char	*buf = gcb->send_chan[ n ].buf;
		    i4		len = gcb->send_chan[ n ].len;

		    buf -= sizeof( GC_MTYP );

		    ((GC_MTYP *)buf)->len = len;
		    ((GC_MTYP *)buf)->chan = n;

		    gcb->send.bsp.buf = buf;
		    gcb->send.bsp.len = len + sizeof( GC_MTYP );
		    gcb->sending = &gcb->send_chan[ n ];

		    gcb->send.state = GC_W_DATA;
		    goto writereg;
	    }
	    else if( gcb->sendchops.state == GC_CHAN_ACTIVE )
	    {
		    /* Sending 2 chop marks.  Set up first.  */

		    gcb->send.bsp.buf = (char *)GC_chopmarks;
		    gcb->send.bsp.len = sizeof( GC_chopmarks );
		    gcb->sending = &gcb->sendchops;

		    gcb->send.state = GC_W_CHOP;
		    goto writereg;
	    } 
	    else
	    {
		    /* No outstanding requests - suspend state machine */

		    GCTRACE(3)( "GC_send_sm %d: suspend\n", gcb->id );
		    gcb->send.running = FALSE;
		    break;
	    }

	case GC_W_CHOP:
	case GC_W_DATA:

	    /* Issue BS write to write chop mark or data. */

	    (*GCdriver->send)( &gcb->send.bsp );

            if( gcb->send.bsp.status != OK )
	    {
		GCTRACE(1)( "GC_send_sm %d: BSsend failed %x\n", 
			    gcb->id, gcb->send.bsp.status );

		/*
		** An error of EPIPE is a special case, usually
		** meaning that the connection is not valid.
		** The connection was probably not valid to begin with.
		*/
		if ( gcb->send.bsp.syserr->errnum == EPIPE )
		    gcb->send.bsp.status = GC_ASSOC_FAIL;

		GC_abort_sends( gcb, gcb->send.bsp.status );
		gcb->send.running = FALSE;
		break;
	    }

            /* More to send? */

            if( gcb->send.bsp.len )
                goto writereg;

	    /* Write done. */

	    gcb->sending->state = GC_CHAN_DONE;
	    gcb->send.state = GC_W_LOOK;
	    goto top;

	writereg:
	    /* Register for a send op */

	    GCTRACE(3)( "GC_send_sm %d: polling to send %d bytes\n", 
		    gcb->id, gcb->send.bsp.len );

	    if( gcb->send.bsp.len 
		&& (*GCdriver->regfd)( &gcb->send.bsp, n ) )
		break;

	    goto top;
        }

	GC_drive_complete( gcb );
}
Пример #6
0
static void
GC_recv_sm( GCA_GCB *gcb, STATUS timeout_status )
{
	i4		len;
	int		n;
	struct subchan *subchan;

	/* Copy some parameters */

	gcb->recv.bsp.func = GC_recv_sm;
	gcb->recv.bsp.closure = (PTR)gcb;
	gcb->recv.bsp.syserr = &gcb->recv.syserr;
	gcb->recv.bsp.bcb = gcb->bcb;
	gcb->recv.bsp.lbcb = listenbcb;
# ifdef OS_THREADS_USED
	if ( iisynclisten )
	    gcb->recv.bsp.regop = BS_POLL_INVALID; /* force blocking IO */
	else
	    gcb->recv.bsp.regop = BS_POLL_RECEIVE;
# else /* OS_THREADS_USED */
	gcb->recv.bsp.regop = BS_POLL_RECEIVE;
# endif /* OS_THREADS_USED */
	gcb->recv.bsp.status = OK;

	GCTRACE(3)( "GC_recv_sm %d: state %s\n", 
		gcb->id, gc_trr[ gcb->recv.state ] );

	/* Loop while requests outstanding. */

	while( gcb->recv_chan[ n = 0 ].state == GC_CHAN_ACTIVE ||
	       ( !iisynclisten && 
                 gcb->recv_chan[ n = 1 ].state == GC_CHAN_ACTIVE ) )
	    switch( gcb->recv.state )
	{
	case GC_R_IDLE:
	    /* 
	    ** Setup to fill buffer.  To avoid copying, read directly 
	    ** into the NORMAL flow buffer, if there is a NORMAL request
	    ** posted.
	    */

	    subchan = &gcb->recv_chan[ 0 ];

	    if( subchan->state == GC_CHAN_ACTIVE &&
		subchan->len >= sizeof( gcb->buffer ) - sizeof( GC_MTYP ) )
	    {
		/* Use NORMAL flow receive buffer */
		gcb->recv.bsp.buf = subchan->buf - sizeof( GC_MTYP );
		gcb->recv.bsp.len = sizeof( gcb->buffer );
	    }
	    else
	    {
		/* Use our private buffer */
		gcb->recv.bsp.buf = gcb->buffer;
		gcb->recv.bsp.len = sizeof( gcb->buffer );
	    }

	    gcb->mtyp = (GC_MTYP *)gcb->recv.bsp.buf;

	    /* Go to register for read */

	    gcb->recv.state = GC_R_CHECK;
	    continue;

	case GC_R_FILL:
	    /* Check for timeout */

	    if( timeout_status != OK )
	    {
		gcb->recv.state = GC_R_IDLE;
		gcb->recv.bsp.status = GC_TIME_OUT;
		goto abort;
	    }

	    /* Issue BS read. */

	    (*GCdriver->receive)( &gcb->recv.bsp );

	    if( gcb->recv.bsp.status != OK )
		goto abort;

	    gcb->recv.state = GC_R_CHECK;

	    /* fall through */
		
	case GC_R_CHECK:
	    /* Get at least the mtyp and its data, or fill the buffer. */

	    len = gcb->recv.bsp.buf - (char *)gcb->mtyp;

	    if( len < sizeof( GC_MTYP ) ||
		len < sizeof( GC_MTYP ) + gcb->mtyp->len &&
		gcb->recv.bsp.len )
	    {
		/* Use timeout for first read */

		gcb->recv.bsp.timeout = len ? -1 : gcb->recv.timeout;
		gcb->recv.state = GC_R_FILL;

		/* Register for a read op */

		GCTRACE(3)( "GC_recv_sm %d: polling to read %d bytes\n", 
			gcb->id, gcb->recv.bsp.len );

		if( (*GCdriver->regfd)( &gcb->recv.bsp ) )
		    goto complete;

		timeout_status = OK;
		continue;
	    }

	    /* Got MTYP.  Check subchannel. */

	    if( gcb->mtyp->chan < 0 || gcb->mtyp->chan >= GC_SUB )
	    {
		GCTRACE(1)( "GCreceive %d: bad MTYP %d/%d\n", 
			gcb->id, 
			gcb->mtyp->chan, 
			gcb->mtyp->len );
		gcb->recv.bsp.status = GC_ASSOC_FAIL;
		goto abort;
	    }

	    GCTRACE(3)( "GC_recv_sm %d: recv MTYP %s len %d (%d read)\n", 
		    gcb->id, 
		    gc_chan[ gcb->mtyp->chan ],
		    gcb->mtyp->len,
		    len );

	    gcb->recv.state = GC_R_LOOK;

	    /* fall through */

	case GC_R_LOOK:
	    /* A request waiting on this subchannel? */

	    subchan = &gcb->recv_chan[ gcb->mtyp->chan ];

	    if( subchan->state != GC_CHAN_ACTIVE )
	    {
		/* 
		** Data on wrong channel. 
		** If polling on other channel, time it out.
		*/

		subchan = &gcb->recv_chan[ gcb->mtyp->chan ? 0 : 1];

		if( subchan->state == GC_CHAN_ACTIVE && 
		    subchan->svc_parms->time_out != -1 )
		{
		    subchan->svc_parms->status = GC_TIME_OUT;
		    *(subchan->svc_parms->sys_err) = gcb->recv.syserr; 
		    subchan->state = GC_CHAN_DONE;
		}

		if ( gcb->mtyp->chan == GC_EXPEDITED &&
		     subchan->state == GC_CHAN_ACTIVE &&
		     subchan->svc_parms->time_out == -1 )
		{
		    /* 
		    ** data detected on expedited channel and
		    ** read is blocking on the normal channel
		    */
		    subchan->svc_parms->status = GC_NOTIMEOUT_DLOCK;
		    *(subchan->svc_parms->sys_err) = gcb->recv.syserr;
		    subchan->state = GC_CHAN_DONE;
		}

		goto suspend;
	    }
	    else
	    {
		/*
		** Satisfy request by copying data.
		*/

		char	*src = (char *)gcb->mtyp + sizeof(GC_MTYP);

		/* 
		** Compute the minimum of what's in the buffer,
		** what's in the mtyp, and what the user asked for.
		*/

		len = gcb->recv.bsp.buf - src;

		if( gcb->mtyp->len < len )
		    len = gcb->mtyp->len;

		if( subchan->len < len )
		    len = subchan->len;

		/* Copy buffer and update request counters */

		GCTRACE(3)( "GC_recv_sm %d: using %d bytes\n", gcb->id, len );

		if( src != subchan->buf )
                {
                    /* Close security vulnerabilty hole */
                    if( len < 0 )
                    {
                        subchan->svc_parms->status = GC_INVALID_ARGS;
                        goto abort;
                    }
		    MEcopy( src, len, subchan->buf );
                }

		subchan->buf += len;
		subchan->len -= len;
		subchan->state = GC_CHAN_DONE;

		/*
		** Adjust mtyp for the used data.
		** Set src to point to the unused data, and
		** set len to amount of unused data.
		*/

		gcb->mtyp->len -= len;
		src += len;
		len = gcb->recv.bsp.buf - src;

		/*
		** If both the mtyp and buffer were depleted, go to idle.
		*/

		if( !gcb->mtyp->len && !len )
		{
		    gcb->recv.state = GC_R_IDLE;
		    continue;
		}
	
		/*
		** Normally, GCreceive requests are large enough to
		** use all the data in the MTYP and buffer.  In two
		** cases, they are not: if an older program sends us
		** a jumbo MTYP too big for our buffer; or if a short
		** MTYP (such as expedited data) is immediately 
		** followed by another MTYP.
		*/

		/*
		** Copy pieces back to the beginning of the buffer.
		*/

		GCTRACE(3)( "GC_recv_sm %d: excess %d mtyp %d buffer\n", 
			gcb->id, gcb->mtyp->len, len );

		gcb->recv.bsp.buf = gcb->buffer;
		gcb->recv.bsp.len = sizeof( gcb->buffer );

		/* If any data left in mtyp, copy mtyp over */

		if( gcb->mtyp->len )
		{
		    MEcopy( (PTR)gcb->mtyp, sizeof( GC_MTYP ), 
			gcb->recv.bsp.buf );
		    gcb->recv.bsp.buf += sizeof( GC_MTYP );
		    gcb->recv.bsp.len -= sizeof( GC_MTYP );
		}

		/* Copy remaining user data data */

		if( len )
		{
		    MEcopy( (PTR)src, len, gcb->recv.bsp.buf );
		    gcb->recv.bsp.buf += len;
		    gcb->recv.bsp.len -= len;
		}

		/* Point base back to our buffer. */

		gcb->mtyp = (GC_MTYP *)gcb->buffer;
		gcb->recv.state = GC_R_CHECK;
		continue;
	    }

    abort:
	    GCTRACE(1)( "GC_recv_sm %d: BSread failed %x\n", 
		    gcb->id, gcb->recv.bsp.status );

	    GC_abort_recvs( gcb, gcb->recv.bsp.status );
	}

suspend:
	/* No outstanding requests - suspend state machine */

	GCTRACE(3)( "GC_recv_sm %d: suspend\n", gcb->id );

	gcb->recv.running = FALSE;

complete:
	GC_drive_complete( gcb );
}
Пример #7
0
VOID
GCreceive( SVC_PARMS *svc_parms )
{
	GCA_GCB		*gcb = (GCA_GCB *)svc_parms->gc_cb;
	register struct subchan	*subchan = &gcb->recv_chan 
				[ svc_parms->flags.flow_indicator ];
	 
	GCTRACE(1)( "%sGCreceive %d: want %d%s\n",
		gc_trace > 1 ? "===\n" : "",
		gcb->id, svc_parms->reqd_amount,
		gc_chan[ svc_parms->flags.flow_indicator ] );

	svc_parms->status = OK;

	/* Sanity check for duplicate request. */

	if( subchan->state != GC_CHAN_QUIET )
	{
		GCTRACE(1)( "GCreceive %d: duplicate request\n", gcb->id );
		GC_abort_recvs( gcb, GC_ASSOC_FAIL );
		GC_drive_complete( gcb );
		return;
	}

	if( !svc_parms->svc_buffer )
	{
		GCTRACE(1)( "GCreceive %d: null request\n", gcb->id );
		GC_abort_recvs( gcb, GC_ASSOC_FAIL );
		GC_drive_complete( gcb );
		return;
	}

	/* Note request on subchannel.  */

	subchan->svc_parms = svc_parms;
	subchan->buf = svc_parms->svc_buffer;
	subchan->len = svc_parms->reqd_amount;
	subchan->state = GC_CHAN_ACTIVE;
	gcb->recv.timeout = svc_parms->time_out;

	if ( gcb->ccb.flags & GC_PEER_RECV )
	{
	    /*
	    ** We have already received an old style peer info
	    ** packet.  We return the GCA portion of the packet
	    ** on the first receive request.  GCA must provide 
	    ** enough room to retrieve all the info.
	    */
	    u_i2 len = min( sizeof( gcb->ccb.assoc_info.orig_info.gca_info ),
			    subchan->len );

	    MEcopy( (PTR)&gcb->ccb.assoc_info.orig_info.gca_info,
		    len, (PTR)subchan->buf );

	    subchan->buf += len;
	    subchan->state = GC_CHAN_DONE;
	    gcb->ccb.flags &= ~GC_PEER_RECV;

	    GCTRACE(1)( "GCreceive %d: returning peer info\n", gcb->id );
	    GC_drive_complete( gcb );
	    return;
	}

	/* If nothing (more) to read, complete.  */

	if( !subchan->len )
	{
		subchan->state = GC_CHAN_DONE;
		GC_drive_complete( gcb );
	}

	/* Start the reader state machine, if not already running. */

	if( !gcb->recv.running )
	{
		gcb->recv.running = TRUE;
		GC_recv_sm( gcb, OK );
	}
# ifdef OS_THREADS_USED
	if ( iisynclisten && svc_parms->flags.flow_indicator == 0 )
		GC_recv_sm( gcb, OK );
# endif /* OS_THREADS_USED */

}
Пример #8
0
static void
GC_drive_complete( GCA_GCB *gcb )
{
	register struct subchan	*chan;
	register SVC_PARMS	*svc_parms;
	i4 			i;

	if( gcb->completing++ )
		return;

	/*
	** Look for active RECV, SEND, requests.
	*/

    again:
	for( i = GC_SUB; i--; )
	{
	    chan = &gcb->recv_chan[i];

	    if( chan->state == GC_CHAN_DONE )
	    {
		svc_parms = chan->svc_parms;

		svc_parms->rcv_data_length = 
		    chan->buf - svc_parms->svc_buffer;
		svc_parms->flags.new_chop = !svc_parms->rcv_data_length;

		chan->state = GC_CHAN_QUIET;

		GCTRACE(2)( "GC_recv_comp %d: recv %d%s stat=%x%s\n",
		    gcb->id, svc_parms->rcv_data_length,
		    gc_chan[ svc_parms->flags.flow_indicator ],
		    svc_parms->status, 
		    gc_chop[ svc_parms->flags.new_chop ] );

		(*( svc_parms->gca_cl_completion ) )( svc_parms->closure );

	    }

	    chan = &gcb->send_chan[i];

	    if( chan->state == GC_CHAN_DONE )
	    {
		svc_parms = chan->svc_parms;

		chan->state = GC_CHAN_QUIET;

		GCTRACE(2)( "GC_send_comp %d: sent %d%s status %x\n",
		    gcb->id, svc_parms->svc_send_length, 
		    gc_chan[ svc_parms->flags.flow_indicator ],
		    svc_parms->status );

		(*( svc_parms->gca_cl_completion ) )( svc_parms->closure );

	    }
	}

# ifdef OS_THREADS_USED
	if ( gcb->completing > 0 )
	{
		--gcb->completing;
		goto again;
	}
# else /* OS_THREADS_USED */
	if( --gcb->completing )
		goto again;
# endif /* OS_THREADS_USED */

	/*
	** Check close request.
	*/

	chan = &gcb->sendclose;

	if( chan->state == GC_CHAN_DONE )
	{
		svc_parms = chan->svc_parms;

		chan->state = GC_CHAN_QUIET;

		GCTRACE(2)( "GC_close_comp %d: status %x\n",
		    gcb->id, svc_parms->status );

		(*( svc_parms->gca_cl_completion ) )( svc_parms->closure );
	}
}
Пример #9
0
static void
GC_disc_sm( GCA_GCB *gcb )
{
	BS_PARMS	*bsp = &gcb->close.bsp;

	bsp->func = GC_disc_sm;
	bsp->closure = (PTR)gcb;
	bsp->syserr = &gcb->close.syserr;
	bsp->bcb = gcb->bcb;
	bsp->lbcb = listenbcb;
	bsp->status = OK;

	GCTRACE(3)( "GC_disc_sm %d: <<<entered>>>\n", gcb->id );

top:

	GCTRACE(3)( "GC_disc_sm %d: state %s\n", 
		gcb->id, gc_trd[ gcb->close.state ] );

	switch( gcb->close.state )
	{
	case GC_D_REL_WAIT:
	    /*
	    ** If orderly release is supported, poll to send the indication.
	    ** Otherwise, just go right to the close.
	    */

	    if ( !GCdriver->release )
	    {
	        gcb->close.state = GC_D_CLOSE;
		goto top;
	    }
	
	    gcb->close.state = GC_D_RELEASE;
# ifdef OS_THREADS_USED
	    if ( iisynclisten )
	        bsp->regop = BS_POLL_INVALID; /* force blocking IO */
	    else
	        bsp->regop = BS_POLL_SNDREL;
# else /* OS_THREADS_USED */
	    bsp->regop = BS_POLL_SNDREL;
# endif /* OS_THREADS_USED */
	    if( (*GCdriver->regfd)( bsp ) )
		return;

	    gcb->close.state = GC_D_CLOSE;
	    goto top;

	case GC_D_RELEASE:
	    /* Send orderly release indication */

	    (*GCdriver->release)( bsp );
	
	    gcb->close.state = GC_D_CLOSE_WAIT;
	    goto top;

	case GC_D_CLOSE_WAIT:
	    /* Poll for the release confirmation */

	    gcb->close.state = GC_D_CLOSE;
# ifdef OS_THREADS_USED
	    if ( iisynclisten )
	        bsp->regop = BS_POLL_INVALID; /* force blocking IO */
	    else
	        bsp->regop = BS_POLL_RCVREL;
# else /* OS_THREADS_USED */
	    bsp->regop = BS_POLL_RCVREL;
# endif /* OS_THREADS_USED */
	    if( (*GCdriver->regfd)( bsp ) )
		return;

	    goto top;

	case GC_D_CLOSE:
	    /* Close connection with BS close */

	    (*GCdriver->close)( bsp );

	    if( bsp->status == BS_INCOMPLETE )
	    {
	        gcb->close.state = GC_D_CLOSE_WAIT;
	        goto top;
	    }

	    gcb->sendclose.state = GC_CHAN_DONE;
	    break;
        }

	/* 
	**  Drive completion events.
	*/

	GC_drive_complete( gcb );
}
Пример #10
0
/*
** Name: GClanman_async_thread
** Description:
**	This thread handles all the asynchronous I/O for a protocol driver.
** 	It will be woken up when GClanman() places a request on it's input
**	Q.  Then, this thread will move the request from the input Q to its
**	processing Q and continue to process the request until complete.
**	When complete, the request is finally moved to the completion
**	Q.
** History:
**	04-Nov-93 (edg)
**	    Written.
**	29-jun-2000 (somsa01)
**	    Use GCc_listen_port for the server ncb_name. Also, make sure
**	    that we update GCc_client_name if we need a unique one.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**	    Since _beginthreadex() is now used to start this thread,
**	    use _endthreadex() to end it.
*/
VOID
GClanman_async_thread( VOID * parms)
{
	int             status = OK;
	char            callname[NCBNAMSZ+1];
	DWORD		wait_stat;
	HANDLE		hSave;
	int		processing_requests = 0;
	int		pending_requests = 0;
	QUEUE		*q;
	SECURITY_ATTRIBUTES sa;

	iimksec (&sa);

	GCTRACE(4)("LMAN THREAD: started.\n");
top:
	/*
	** Wait for a request to come in from the primary gcc thread....
	*/

	GCTRACE(4)("LMAN THREAD: waiting for event ... \n");

	wait_stat = WaitForSingleObject( hEventThreadInQ, INFINITE );

	GCTRACE(3)("LMAN THREAD: wait returned %d, handle = %d\n", 
		    wait_stat, hEventThreadInQ );

	/*
	** If wait failed, chances are it's a major hosure.  Continue on any
	** way -- there's a possibility that something useful may get done.
	*/
	if (wait_stat == WAIT_FAILED)
	{
	    GCTRACE(1)("LMAN THREAD: wait failed %d\n", 
	    		GetLastError() );
	}

	/*
	** Now get get the incoming requests and add up how many requests
	** we're processing.
	*/
	processing_requests = GCget_incoming_reqs( Tptr, hMutexThreadInQ );

	GCTRACE(2)("LMAN THREAD: Got %d new requests to process\n",
		    processing_requests);

	/*
	** Loop until there's no more requests being processed.
	*/
	while( processing_requests )
	{
            pending_requests = 0;
	    /*
	    ** Now loop thru the inprocess request list.
	    */
	    for ( q = Tptr->process_head.q_next;
	    	  q != &Tptr->process_head;
		  q = q->q_next )
	    {
	        REQUEST_Q *rq = (REQUEST_Q *)q;
		GCC_P_PLIST *parm_list = rq->plist;
		PCB *pcb = (PCB *)parm_list->pcb;

		parm_list->generic_status = OK;
		CLEAR_ERR(&parm_list->system_status);

		switch (parm_list->function_invoked) 
		{

		    /******************************************************
		    ** Handle CONNECT
		    *******************************************************/
		    case GCC_CONNECT:

		    GCTRACE(4)("LMAN THREAD: process CONNECT\n");
		    if ( pcb == NULL || pcb->state.conn == INITIAL )
		    {
		        GCTRACE(3)("LMAN THREAD: initial CONNECT\n");
		        /*
			** Allocate the protocol control block.
			*/
		  	pcb = (PCB *) malloc( sizeof(PCB) );
		    	parm_list->pcb = (char *)pcb;
			if (pcb == NULL) 
			{
			    status = errno;
			    SETWIN32ERR(&parm_list->system_status, status, ER_alloc);
			    pcb->state.conn = COMPLETED;
			    parm_list->generic_status = GC_CONNECT_FAIL;
			    break;
		   	}
			memset( pcb, 0, sizeof( *pcb ) );
		        GCTRACE(3)("LMAN THREAD: CONNECT allocated pcb\n");
			/*
			** Create send/recv event handles for ncb.
			*/
    			if ((pcb->s_ncb.ncb_event = 
				CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    			{
        		    status = GetLastError();
			    pcb->state.conn = COMPLETED;
			    SETWIN32ERR(&parm_list->system_status, status, ER_create);
			    parm_list->generic_status = GC_CONNECT_FAIL;
			    break;
    		        }
       		 	if ((pcb->r_ncb.ncb_event = 
				CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    			{
        		    status = GetLastError();
			    CloseHandle( pcb->s_ncb.ncb_event );
			    pcb->state.conn = COMPLETED;
			    SETWIN32ERR(&parm_list->system_status, status, ER_create);
			    parm_list->generic_status = GC_CONNECT_FAIL;
			    break;
    			}
		        GCTRACE(3)("LMAN THREAD: CONNECT created events\n");

			pcb->state.conn = INITIAL;

		    } /* end if pcb NULL */

		    /*
		    ** If the PCB state is not INITIAL, just break because
		    ** we're just waiting for connect to complete.
		    */
		    if ( pcb->state.conn != INITIAL )
		        break;

		    /*
		    ** Use the send ncb in pcb for the connect -- add name.
		    */
		    pcb->s_ncb.ncb_command = NCBADDNAME;
		    pcb->s_ncb.ncb_buffer = Dummy_Buf;
		    pcb->s_ncb.ncb_length = sizeof(Dummy_Buf);
		    pcb->s_ncb.ncb_lana_num = lana_num;

		    for (;;)
		    {
			STprintf( GCc_client_name, "%s%-d", 
				  MyName, GCc_client_count++ );
			STcopy( GCc_client_name, pcb->s_ncb.ncb_name );

			GCTRACE(3)("LMAN THREAD: CONNECT doing ADDNAME %s\n",
				   pcb->s_ncb.ncb_name );

			/*
			** Copy to local NCB struct -- Netbios seems to fark
			** up if we don't.
			*/
			memcpy( &Name_Ncb, &pcb->s_ncb, sizeof( Name_Ncb ) );

			Netbios( &Name_Ncb );

			if (Name_Ncb.ncb_retcode == NRC_GOODRET)
			    break;
			else if (Name_Ncb.ncb_retcode == NRC_DUPNAME)
			    continue;
			else
			{
			    status = (STATUS)Name_Ncb.ncb_retcode;
			    CloseHandle( Name_Ncb.ncb_event );
			    pcb->s_ncb.ncb_event = NULL;
			    CloseHandle( pcb->r_ncb.ncb_event );
			    pcb->r_ncb.ncb_event = NULL;
			    pcb->state.conn = COMPLETED;
			    SETWIN32ERR(&parm_list->system_status, status,
					ER_netbios);
			    parm_list->generic_status = GC_CONNECT_FAIL;
			    break;
			}
		    }

		    if (parm_list->generic_status == GC_CONNECT_FAIL)
			break;

		    /*
		    ** just in case ...
		    */
		    ResetEvent( pcb->s_ncb.ncb_event );

		    /*
		    ** OK, now make the call
		    */
		    hSave = pcb->s_ncb.ncb_event;    /* save handle */
		    memset( &pcb->s_ncb, 0, sizeof(NCB) );
		    pcb->s_ncb.ncb_event = hSave;    /* restore handle */
		    pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr;    
		    pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng;    
		    pcb->s_ncb.ncb_command = NCBCALL | ASYNCH;
		    pcb->s_ncb.ncb_lana_num = lana_num;
		    STcopy( GCc_client_name, pcb->s_ncb.ncb_name );
		    STpolycat( 3, parm_list->function_parms.connect.node_id,
		    	       "_", parm_list->function_parms.connect.port_id,
			       callname );
		    CVupper( callname );

		    
		    /*
		    ** Loopback check to prevent mangling the name (?)
		    */
		    if ( STcompare( parm_list->function_parms.connect.port_id,
		    		    GCc_listen_port ) == 0 )
		    {
		        STcopy( GCc_listen_port, pcb->s_ncb.ncb_callname );
		    }
		    else
		    {
		        STcopy( callname, pcb->s_ncb.ncb_callname );
		    }

		    GCTRACE(3)("LMAN THREAD: CONNECT doing CALL to %s\n",
		    		pcb->s_ncb.ncb_callname );

		    if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET )
		    {
		        status = (STATUS)pcb->s_ncb.ncb_retcode;
			CloseHandle( pcb->s_ncb.ncb_event );
			pcb->s_ncb.ncb_event = NULL;
			CloseHandle( pcb->r_ncb.ncb_event );
			pcb->r_ncb.ncb_event = NULL;
			pcb->state.conn = COMPLETED;
			SETWIN32ERR(&parm_list->system_status, status, ER_netbios);
			parm_list->generic_status = GC_CONNECT_FAIL;
			break;
		    }

		    GCTRACE(3)("LMAN THREAD: Async CALL OK\n" );

		    pcb->state.conn = COMPLETING;

		    break;


		    /*******************************************************
		    ** Handle SEND
		    *******************************************************/
		    case GCC_SEND:

		    GCTRACE(4)("LMAN THREAD: process SEND\n");

		    if ( pcb->state.send != INITIAL )
		    {
		        break;
		    }
		    pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr;    
		    pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng;    
		    pcb->s_ncb.ncb_lana_num = lana_num;
		    pcb->s_ncb.ncb_command = NCBSEND | ASYNCH;
		    if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET )
		    {
		        status = (STATUS)pcb->s_ncb.ncb_retcode;
			pcb->state.send = COMPLETED;
			SETWIN32ERR(&parm_list->system_status, status, ER_netbios);
			parm_list->generic_status = GC_SEND_FAIL;
		    }

		    pcb->state.send = COMPLETING;

		    break;


		    /*******************************************************
		    ** Handle RECEIVE
		    *******************************************************/
		    case GCC_RECEIVE:

		    GCTRACE(4)("LMAN THREAD: process RECEIVE\n");

		    if ( pcb->state.recv != INITIAL )
		    {
                        pending_requests++;
		        break;
		    }
		    pcb->r_ncb.ncb_buffer = parm_list->buffer_ptr;    
		    pcb->r_ncb.ncb_length = (WORD)parm_list->buffer_lng;    
		    pcb->r_ncb.ncb_lana_num = lana_num;
		    pcb->r_ncb.ncb_command = NCBRECV | ASYNCH;

		    if ( Netbios( &pcb->r_ncb ) != NRC_GOODRET )
		    {
		        status = (STATUS)pcb->r_ncb.ncb_retcode;
			pcb->state.recv = COMPLETED;
			SETWIN32ERR(&parm_list->system_status, status, ER_netbios);
			parm_list->generic_status = GC_RECEIVE_FAIL;
		    }

		    pcb->state.recv = COMPLETING;

		    break;

		    /*******************************************************
		    ** Handle DISCONNECT
		    *******************************************************/
		    case GCC_DISCONNECT:

		    GCTRACE(4)("LMAN THREAD: process DISCONNECT\n");

		    if ( pcb && pcb->state.disc == INITIAL ) 
		    {
		        pcb->s_ncb.ncb_buffer = parm_list->buffer_ptr;    
		        pcb->s_ncb.ncb_length = (WORD)parm_list->buffer_lng;    
		        pcb->s_ncb.ncb_command = NCBHANGUP | ASYNCH;
		    	pcb->s_ncb.ncb_lana_num = lana_num;
			if ( pcb->s_ncb.ncb_lsn == 0 )
			    pcb->s_ncb.ncb_lsn = pcb->r_ncb.ncb_lsn;
		        if ( Netbios( &pcb->s_ncb ) != NRC_GOODRET )
		        {
		            status = (STATUS)pcb->s_ncb.ncb_retcode;
		    	    pcb->state.disc = COMPLETED;
			    SETWIN32ERR(&parm_list->system_status, status, ER_netbios);
			    parm_list->generic_status = GC_DISCONNECT_FAIL;
			    break;
		        }
		        pcb->state.disc = COMPLETING;
		    }

		    break;

		} /* end switch */

	    } /* end for process q loop */

	    /*
	    ** Now go thru the inprocess Q and look for any requests that
	    ** have been completed.  This will be indicated by one of:
	    ** parm_list->pcb == NULL (bad connect or after disconnect) or
	    ** pcb->state == COMPLETED, or WaitForSingleObject indicates
	    ** completion.
	    */

	    GCTRACE(4)("LMAN THREAD: processing completed. . . \n");

	    q = Tptr->process_head.q_next;
	    while( q != &Tptr->process_head )
	    {
	        REQUEST_Q *rq = (REQUEST_Q *)q;
	        GCC_P_PLIST *pl = rq->plist;
		PCB *pcb = (PCB *)pl->pcb;
		bool completed = FALSE;

		switch ( pl->function_invoked )
		{
		    case GCC_CONNECT:
		        if ( pcb == NULL || pcb->state.conn == COMPLETED || 
			     WaitForSingleObject( pcb->s_ncb.ncb_event, 0) ==
			         WAIT_OBJECT_0 )
			{
			    if (pcb) 
			    {
			        ResetEvent( pcb->s_ncb.ncb_event );
			        pcb->r_ncb.ncb_lsn = pcb->s_ncb.ncb_lsn;
				if ( pcb->s_ncb.ncb_lsn == 0 ||
				     pcb->s_ncb.ncb_retcode != NRC_GOODRET )
				{
				    pl->generic_status = GC_CONNECT_FAIL;
				    status = (STATUS)pcb->s_ncb.ncb_retcode;
				    SETWIN32ERR( &pl->system_status, status , ER_revent);
				    CloseHandle( pcb->s_ncb.ncb_event );
				    CloseHandle( pcb->r_ncb.ncb_event );
				    free( pcb );
				    pl->pcb = NULL;
				}
			    }

			    completed = TRUE;
			}
		        break;
		    case GCC_SEND:
		        if ( pcb == NULL || pcb->state.send == COMPLETED || 
			     WaitForSingleObject( pcb->s_ncb.ncb_event, 0) ==
			         WAIT_OBJECT_0 )
			{
			    ResetEvent( pcb->s_ncb.ncb_event );
			    if ( pcb->s_ncb.ncb_lsn == 0 ||
			         pcb->s_ncb.ncb_retcode != NRC_GOODRET )
			    {
				    pl->generic_status = GC_SEND_FAIL;
				    status = (STATUS)pcb->s_ncb.ncb_retcode;
				    SETWIN32ERR( &pl->system_status, status , ER_revent);
			    }
			    else
			    {
			        GCTRACE(2)(
				"LMAN THREAD: Send COMP pl len %d pcb len %d\n",
			            pl->buffer_lng, pcb->s_ncb.ncb_length);
					
			        pl->buffer_lng = pcb->s_ncb.ncb_length;
			    }
			    completed = TRUE;
			}
		        break;
		    case GCC_RECEIVE:
		        if ( pcb == NULL || pcb->state.recv == COMPLETED || 
			     WaitForSingleObject( pcb->r_ncb.ncb_event, 0) ==
			         WAIT_OBJECT_0 )
			{
			    ResetEvent( pcb->r_ncb.ncb_event );
			    if ( pcb->s_ncb.ncb_lsn == 0 ||
			         pcb->r_ncb.ncb_retcode != NRC_GOODRET )
			    {
				    pl->generic_status = GC_RECEIVE_FAIL;
				    status = (STATUS)pcb->r_ncb.ncb_retcode;
				    SETWIN32ERR( &pl->system_status, status , ER_revent);
			    }
			    else
			    {
			        pl->buffer_lng = pcb->r_ncb.ncb_length;
			    }
			    completed = TRUE;
			}
		        break;
		    case GCC_DISCONNECT:
		        if ( pcb == NULL || pcb->state.disc == COMPLETED || 
			     WaitForSingleObject( pcb->s_ncb.ncb_event, 0) ==
			         WAIT_OBJECT_0 )
			{
			    if (pcb) 
			    {
				if ( pcb->s_ncb.ncb_lsn == 0 ||
				     pcb->s_ncb.ncb_retcode != NRC_GOODRET )
				{
				    pl->generic_status = GC_DISCONNECT_FAIL;
				    status = (STATUS)pcb->s_ncb.ncb_retcode;
				    SETWIN32ERR( &pl->system_status, status , ER_revent);
				}
				pcb->s_ncb.ncb_command = NCBDELNAME;
				Netbios( &pcb->s_ncb );
				CloseHandle( pcb->s_ncb.ncb_event );
				CloseHandle( pcb->r_ncb.ncb_event );
				free( pcb );
				pl->pcb = NULL;
			    }
			    completed = TRUE;
			}
		        break;
		} /* end switch */

		if ( completed )
		{
		    QUEUE *nq = q->q_next;

	    	    GCTRACE(3)("LMAN THREAD:  Complete! PCB = %x PARM = %x \n",
		    		pcb, pl);

		    GCcomplete_request( q );

		    q = nq;
		    processing_requests--;

	    	    GCTRACE(3)("LMAN THREAD: processed completed \n");
	    	    GCTRACE(3)("                 : total now = %d \n",
		    		processing_requests);

		} /* end if req completed */
		else
		{
		    q = q->q_next;
		}

	    } /* end for -- look for complete req */

	    /*
	    ** Do a quick, non-blocking check to see if any new requests
	    ** came in during processing.
	    */
	    GCTRACE(4)("LMAN THREAD: quick look for new reqs \n");
	    if ( WaitForSingleObject( hEventThreadInQ, 0 ) == WAIT_OBJECT_0 )
	    {
		processing_requests += GCget_incoming_reqs( Tptr, 
					   hMutexThreadInQ );
	    }
	    GCTRACE(4)("LMAN THREAD: process reqs now = %d\n",
	    		processing_requests);

            if (processing_requests && pending_requests == processing_requests)
            {
                i4 Sleeptime = 1;
                Sleep(Sleeptime);
            }

	} /* end while processing requests */

	if (In_Shutdown)
	{
		_endthreadex(0);
		return;
	}

	/*
	** we're done for now, go back to the top and sleep.
	*/
	GCTRACE(3)("LMAN THREAD: No more reqs, going back to top\n" );
	goto top;
}
Пример #11
0
/*
** Name: GClanman_open
** Description:
**	Open the listen channel for LANMAN.   Called from GClanman().  This
**	routine should only be called once at server startup.
** History:
**	11-nov-93 (edg)
**	    created.
**	03-may-1996 (canor01)
**	    Allow for more than the default number of sessions.
**	29-jun-2000 (somsa01)
**	    Use GCc_listen_port for the ncb_name, making sure that we
**	    update GCc_listen_port if we need a unique one.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**          Remove mutexing around calls to GCA service completion routine
**          as it is no longer necessary, since GCA is thread-safe...removes
**          calls to GCwaitCompletion + GCrestart. Should improve peformance.
*/
STATUS
GClanman_open( GCC_P_PLIST *parm_list )
{
	STATUS	status;
	LANA_ENUM	lanas;
	i4		subport = 0;

	/*
	** Find available adapters
	*/
	memset( &Listen_Ncb, 0, sizeof(NCB) );
	Listen_Ncb.ncb_buffer = &lanas;
	Listen_Ncb.ncb_length = sizeof(LANA_ENUM);
	Listen_Ncb.ncb_command = NCBENUM;
	Netbios( &Listen_Ncb );
	if ( lanas.length == 0 )
	{
		status = (STATUS)Listen_Ncb.ncb_retcode;
		GCTRACE(1)("GClanman_open: No LANA adapters %d\n",
			    status );
		parm_list->generic_status = GC_OPEN_FAIL;
		SETWIN32ERR(&parm_list->system_status, status, ER_listen);
		goto err_exit;
	}
	/* use first available LANA */
	lana_num = lanas.lana[0];

	/*
	** Use Listen_Ncb to 1st do a reset to start things out ...
	*/
	memset( &Listen_Ncb, 0, sizeof(NCB) );
	Listen_Ncb.ncb_buffer = Dummy_Buf;
	Listen_Ncb.ncb_length = sizeof(Dummy_Buf);
	Listen_Ncb.ncb_lana_num = lana_num;
	Listen_Ncb.ncb_callname[0] = 255; /* max number of sessions */
	Listen_Ncb.ncb_callname[2] = 255; /* max number of names */
	Listen_Ncb.ncb_command = NCBRESET;
	Netbios( &Listen_Ncb );

	/*
	** Add Name we'll be listening on.
	*/
	memset( &Listen_Ncb, 0, sizeof(NCB) );
	Listen_Ncb.ncb_buffer = Dummy_Buf;
	Listen_Ncb.ncb_length = sizeof(Dummy_Buf);
	Listen_Ncb.ncb_lana_num = lana_num;
	Listen_Ncb.ncb_command = NCBADDNAME;

	for (;;)
	{
	    if (subport)
		STprintf(Listen_Ncb.ncb_name, "%s%d", GCc_listen_port, subport);
	    else
		STcopy( GCc_listen_port, Listen_Ncb.ncb_name );

	    Netbios( &Listen_Ncb );

	    if (Listen_Ncb.ncb_retcode == NRC_GOODRET)
		break;
	    else if (Listen_Ncb.ncb_retcode == NRC_DUPNAME && (++subport) < 8)
		continue;
	    else
	    {
		status = (STATUS)Listen_Ncb.ncb_retcode;
		GCTRACE(1)("GClanman_open: Error ADDNAME returned %d\n",
			    status );
		parm_list->generic_status = GC_OPEN_FAIL;
		SETWIN32ERR(&parm_list->system_status, status, ER_listen);
		goto err_exit;
	    }
	}

	/*
	** Set listen port in parm list.
	*/
	STcopy(Listen_Ncb.ncb_name, GCc_listen_port);
	if (subport)
	{
	    STprintf(parm_list->pce->pce_port, "%s%d",
		     parm_list->function_parms.open.port_id, subport);
	}
	parm_list->function_parms.open.lsn_port = GCc_listen_port;

err_exit:
	/*
	** Should completion be driven here?
	*/
	(*parm_list->compl_exit) (parm_list->compl_id);
	return OK;
}
Пример #12
0
/*
** Name: GClanman_listen
** Description:
**	This is the listen thread for lanman.  It runs a syncronous accept()
**	on the listen socket.  When complete it Q's the completetion to
**	the completed event Q.  When accept completes, this thread returns.
**	A new one will be created when GClanman() gets the request to
**	repost the listen.
** History:
**	11-nov-93 (edg)
**	    created.
**	29-jun-2000 (somsa01)
**	    Use GCc_listen_port for the ncb_name.
**	16-mar-2001 (somsa01)
**	    Set node_id to ncb_callname.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**          Convert GCC completion queue mutex to a critical section
**          to improve performance (less overhead).
**	    Since _beginthreadex() is now used to start this thread,
**	    use _endthreadex() to end it.
*/
VOID
GClanman_listen( VOID *parms )
{
    GCC_P_PLIST		*parm_list = (GCC_P_PLIST *)parms;
    PCB			*pcb;
    STATUS		status = OK;
    REQUEST_Q		*rq;
    SECURITY_ATTRIBUTES	sa;

    iimksec (&sa);

    /*
    ** Initialize the listen node_id to NULL.
    */
    parm_list->function_parms.listen.node_id = NULL;

    /*
    ** Initialize fields of the Listen_Ncb
    */
    memset( &Listen_Ncb, 0, sizeof(NCB) );
    Listen_Ncb.ncb_buffer = parm_list->buffer_ptr;
    Listen_Ncb.ncb_length = (USHORT)parm_list->buffer_lng;
    Listen_Ncb.ncb_command = NCBLISTEN;
    Listen_Ncb.ncb_lana_num = lana_num;
    *Listen_Ncb.ncb_callname = (unsigned char)NULL;
    STmove( "*", ' ', NCBNAMSZ, Listen_Ncb.ncb_callname );
    *Listen_Ncb.ncb_name = (unsigned char)NULL;
    STcopy( GCc_listen_port, Listen_Ncb.ncb_name );


    /*
    ** Now we can do the NCBLISTEN request.  Block until it completes.
    */
    Netbios( &Listen_Ncb );
    if ( Listen_Ncb.ncb_retcode != NRC_GOODRET )
    {
	status = (int)Listen_Ncb.ncb_retcode;
	goto sys_err;
    }

    /*
    ** Allocate Protcol Control Block specific to this driver and put into
    ** parm list
    */
    pcb = (PCB *) malloc( sizeof(PCB) );
    if (pcb == NULL) 
    {
	status = errno;
	goto sys_err;
    }
    memset( pcb, 0, sizeof( *pcb ) );
    parm_list->pcb = (char *)pcb;

    /*
    ** Set node_id to the node name of the partner.
    */
    parm_list->function_parms.listen.node_id = STalloc(Listen_Ncb.ncb_callname);

    /*
    ** Now assign the pcb's send and receive NCB's the local session number
    ** returned by listen for further communications.
    */
    pcb->s_ncb.ncb_lsn = pcb->r_ncb.ncb_lsn = Listen_Ncb.ncb_lsn;

    /*
    ** Now create handles for the read and write event handles in the
    ** NCB.  These are created with manual reset as cautioned by the 
    ** programmer's guide so a ResetEvent MUST be done on them.
    */
    if ((pcb->s_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    {
        status = GetLastError();
	goto sys_err;
    }
    if ((pcb->r_ncb.ncb_event = CreateEvent( &sa, TRUE, FALSE, NULL ))== NULL)
    {
        status = GetLastError();
	CloseHandle( pcb->s_ncb.ncb_event );
	pcb->s_ncb.ncb_event = NULL;
	goto sys_err;
    }

sys_err:
    if (status != OK) 
    {
        SETWIN32ERR(&parm_list->system_status, status, ER_create);
	parm_list->generic_status = GC_LISTEN_FAIL;
    }

    /*
    ** Now allocate a request q structure, stick it into complete q, and
    ** raise the GCC_COMPLETE event.
    */
    if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL )
    {
        rq->plist = parm_list;
	/*
	** Get critical section for completion Q.
	*/
	EnterCriticalSection( &GccCompleteQCritSect );

	/*
	** Now insert the completed request into the completed Q.
	*/
	QUinsert( &rq->req_q, &IIGCc_proto_threads.completed_head );

	/*
	** Exit/leave critical section for completion Q
	*/
	LeaveCriticalSection( &GccCompleteQCritSect );

	/*
	** raise the completion event to wake up GCexec.
	*/
	if ( !SetEvent( hAsyncEvents[GCC_COMPLETE] ) )
	{
	   /*
	   ** ruh roh.  We're screwed if this event can't be signaled.
	   */
	   status = GetLastError();
	   GCTRACE(1)("GClanman_listen, SetEvent error = %d\n", status );
	}

    }
    else
    {
        /*
	** ruh-roh.  MEreqmem failed.  Selious tlouble.  Not sure what to
	** do about it at this point since if it failed we can't notify
	** the completion routine.  For now, just return (exit thread)
	** which will probably have the effect of blocking all incoming
	** connections.
	*/
    }
    _endthreadex(0);
}
Пример #13
0
/*
** Name: GClanman
** Description:
**	Main entry point for the window's NT lan manager protocol driver.  This
** 	driver is essentially just a dispatcher -- it runs in the primary
**	GCC thread and mostly just Q's things to do to the constantly running
**	aynchronous request thread.  It may also start a listen thread if
**	it is a LISTEN request.
**
**	The following functions are handled:
**	    GCC_OPEN	- call GClanman_open
**	    GCC_LISTEN  - start listen thread
**	    GCC_SEND    - Q request for asynch thread
**	    GCC_RECEIVE - Q request for asynch thread
**	    GCC_CONNECT - Q request for asynch thread
**	    GCC_DISCONN - Q request for asynch thread
** History:
**	11-Nov-93 (edg)
**	    Original.
**      06-Aug-2009 (Bruce Lunsford) Sir 122426
**          Remove mutexing around calls to GCA service completion routine
**          as it is no longer necessary, since GCA is thread-safe...removes
**          calls to GCwaitCompletion + GCrestart. Should improve peformance.
**	    Convert CreateThread() to _beginthreadex() which is recommended
**	    when using C runtime.
*/
STATUS
GClanman( i4 function_code, GCC_P_PLIST * parm_list)
{
	STATUS          generror = 0;
	int             status = 0;
	int             tid;
	HANDLE          hThread;
    	REQUEST_Q 	*rq;
	SECURITY_ATTRIBUTES sa;

	iimksec (&sa);

	CLEAR_ERR(&parm_list->system_status);

	/*
	** set error based on function code and determine whether we got a
	** valid function.
	*/
	switch (function_code) {
	case GCC_OPEN:
		is_comm_svr = TRUE;
		GCTRACE(2) ("GClanman: Function = OPEN\n" );
		return GClanman_open( parm_list );

	case GCC_LISTEN:
		GCTRACE(2) ("GClanman: Function = LISTEN\n" );
		generror = GC_LISTEN_FAIL;
                /*
                ** For Lanman, the peer is always remote.
                */
                parm_list->options = 0;

		/*
		** Spawn off a thread to handle the listen request
		*/
		hThread = (HANDLE)_beginthreadex(&sa,
			       GC_STACK_SIZE,
			       (LPTHREAD_START_ROUTINE) GClanman_listen,
			       parm_list,
			       (unsigned long)NULL,
			       &tid);
		if (hThread) 
		{
			CloseHandle(hThread);
			return (OK);
		}
		status = errno;
		SETWIN32ERR(&parm_list->system_status, status, ER_create);
		goto err_exit;
		break;

	case GCC_CONNECT:
	    GCTRACE(2) ("GClanman: Function = CONNECT\n" );
	    generror = GC_CONNECT_FAIL;
	    break;
	case GCC_SEND:
	    GCTRACE(2) ("GClanman: Function = SEND\n" );
	    generror = GC_SEND_FAIL;
	    break;
	case GCC_RECEIVE:
	    GCTRACE(2) ("GClanman: Function = RECEIVE\n" );
	    generror = GC_RECEIVE_FAIL;
	    break;
	case GCC_DISCONNECT:
	    GCTRACE(2) ("GClanman: Function = DISCONNECT\n" );
	    generror = GC_DISCONNECT_FAIL;
	    break;

	default:
	    return FAIL;
	}			/* end switch */
	/*
	** CONNECT, SEND, RECEIVE and DISCONNECT are all dispatched
	** to the asynch thread.
   	** Now allocate a request q structure, stick it into incoming q,
   	** and raise the INCOMING REQUEST event.
   	*/
	GCTRACE(2)("GClanman: Q'ing request ...\n");

    	if ( (rq = (REQUEST_Q *)MEreqmem(0, sizeof(*rq), TRUE, NULL ) ) != NULL )
    	{
            rq->plist = parm_list;
	    /*
	    ** get mutex for completion Q
	    */
	    GCTRACE(2)("GClanman: wait for input mutex ...\n");
	    WaitForSingleObject( hMutexThreadInQ, INFINITE );

	    /*
	    ** Now insert the completed request into the inconming Q.
	    */
	    GCTRACE(2)("GClanman: inserting incoming req ...\n");
	    QUinsert( &rq->req_q, &Tptr->incoming_head );

	    /*
	    ** release mutex for completion Q
	    */
	    GCTRACE(2)("GClanman: releasing Mutex incoming req ...\n");
	    ReleaseMutex( hMutexThreadInQ );

	    /*
	    ** raise the incoming event to wake up the thread.
	    */
	    GCTRACE(2)("GClanman: Setting event ...\n");
	    if ( !SetEvent( hEventThreadInQ ) )
	    {
	   	    status = GetLastError();
		    SETWIN32ERR(&parm_list->system_status, status, ER_sevent);
	   	    GCTRACE(1)("GClanman, SetEvent error = %d\n", 
		    		status );
	    }

	    return OK;

   	}
    	else
    	{
	        /*
		** MEreqmem failed
		*/
		SETWIN32ERR(&parm_list->system_status, errno, ER_alloc);
    	}

	/*
	 * * Drive the completion routine on error
	 */
err_exit:
	parm_list->generic_status = generror;
	(*parm_list->compl_exit) (parm_list->compl_id);
	return OK;
}
Пример #14
0
/*
** Name: GClanman_init
** Description:
**	LANMAN inititialization function.  This routine is called from
**	GCpinit() -- the routine GCC calls to initialize protocol drivers.
**
**	This function does initialization specific to the protocol:
**	    Creates Events and Mutex's for the protocol
**	    Finds and saves a pointer to it's input event Q.
**	    Fires up the thread which will do asynch I/O
** History:
**	11-Nov-93 (edg)
**	    created.
**      15-jul-95 (emmag)
**          Use a NULL Discretionary Access Control List (DACL) for
**          security, to give implicit access to everyone.
**	23-Feb-1998 (thaal01)
**	    Make space for port_id, stops gcc crashing on startup, sometimes.
**	13-may-2004 (somsa01)
**	    Updated config.dat string used to retrieve port information such
**	    that we do not rely specifically on the GCC port.
**	06-Aug-2009 (Bruce Lunsford)  Sir 122426
**	    Change arglist pointer in _beginthreadex for async_thread from
**	    uninitialized "dummy" to NULL to eliminate compiler warning
**	    and possible startup problem.
*/
STATUS
GClanman_init(GCC_PCE * pptr)
{

	char            *ptr, *host, *server_id, *port_id;
	char		config_string[256];
	char            buffer[MAX_COMPUTERNAME_LENGTH + 1];
	int 		real_name_size = MAX_COMPUTERNAME_LENGTH + 1;
	i4		i;
	int		tid;
	HANDLE		hThread;
	int		status;
	SECURITY_ATTRIBUTES sa;
	char		port_id_buf[8];

	port_id = port_id_buf;

	iimksec (&sa);

	/*
	** Look for trace variable.
	*/
	NMgtAt( "II_LANMAN_TRACE", &ptr );
	if ( !(ptr && *ptr) && PMget("!.lanman_trace_level", &ptr) != OK )
	{
	    GCLANMAN_trace = 0;
	}
	else
	{
	    GCLANMAN_trace = atoi( ptr );
	}

	/*
	** Create MUTEX and EVENT for the input queue of this protocol
	** driver.
	*/
	if ( ( hMutexThreadInQ = CreateMutex(&sa, FALSE, NULL) ) == NULL )
	{
	    return FAIL;
	}

	GCTRACE(3)( "GClanman_init: MutexInQ Handle = %d\n", hMutexThreadInQ );

	if ( ( hEventThreadInQ = CreateEvent(&sa, FALSE, FALSE, NULL)) == NULL )
	{
	    CloseHandle( hMutexThreadInQ );
	    return FAIL;
	}

	GCTRACE(3)( "GClanman_init: EventInQ Handle = %d\n", hEventThreadInQ );
	

	GCTRACE(4)( "Start GClanman_init\n" );

        /*
        ** Get set up for the PMget call.
        */
        PMinit();
        if( PMload( NULL, (PM_ERR_FUNC *)NULL ) != OK )
                PCexit( FAIL );

	/*
	** Construct the network port identifier. 
	*/

        host = PMhost();
	server_id = PMgetDefault(3);
 	if (!server_id)
 		server_id = "*" ;
        STprintf( config_string, ERx("!.lanman.port"),
                  SystemCfgPrefix, host, server_id);

	/*
	** Search config.dat for a match on the string we just built.
	** If we don't find it, then use the value for II_INSTALLATION 
	** failing that, default to II.
	*/
        PMget( config_string, &port_id );
	if (port_id == NULL )
	{
		NMgtAt("II_INSTALLATION", &ptr);
		if (ptr != NULL && *ptr != '\0')
		{
			STcopy(ptr, port_id);
		}
		else 
		{ 
			STcopy(SystemVarPrefix, port_id);
		}
	}

	NMgtAt( "II_NETBIOS_NODE", &ptr );
	if ( !ptr || !*ptr  )
	{
	    /*
	    ** Get Computer Name into buffer.
	    */
	    *buffer = (char)NULL;
	    GetComputerName( buffer, &real_name_size );
	    if ( !*buffer )
	        STcopy( "NONAME", buffer );
	    ptr = buffer;
	}
	/*
	** MyName holds ID for outgoing connections.
	*/
	STpolycat( 2, ptr, "_", MyName );
	/*
	** Create listen port ID.
	*/
	STpolycat( 3, ptr, "_", port_id, GCc_listen_port );
	CVupper( MyName );
	CVupper( GCc_listen_port );
	STcopy( GCc_listen_port, pptr->pce_port );

	GCTRACE(2)("GClanman_init: port = %s\n", pptr->pce_port );

	/*
	** Go thru the the protocol threads event list and find the index
	** of the lanman thread.  Set the Global Tptr for easy reference
	** to the event q's for this protocols thread.
	*/
	for ( i = 0; i < IIGCc_proto_threads.no_threads; i++ )
	{
	     THREAD_EVENTS *p = &IIGCc_proto_threads.thread[i];

	     if ( !STcompare( LANMAN_ID, p->thread_name ) )
	     {
	         Tptr = p;
	         break;
	     }
	}
	if ( Tptr == NULL )
	{
	    CloseHandle( hEventThreadInQ );
	    CloseHandle( hMutexThreadInQ );
	    return FAIL;
	}

	/*
	** Finally we start the asynchronous I/O thread
	*/

	hThread = (HANDLE)_beginthreadex(&sa,
		       GC_STACK_SIZE,
		       (LPTHREAD_START_ROUTINE) GClanman_async_thread,
		       NULL,
		       (unsigned long)NULL,
		       &tid);
	if (hThread) 
	{
		CloseHandle(hThread);
	}
	else
	{
	    status = errno;
	    GCTRACE(1)("GClanman_init: Couldn't create thread errno = %d '%s'\n",
	    		status, strerror(status) );
	    return FAIL;
	}

	return OK;
}
Пример #15
0
/*
** Name: GCwintcp_init
** Description:
**	WINTCP inititialization function.  This routine is called from
**	GCwinsock_init() -- the routine GCC calls to initialize protocol 
**	drivers.
**
**	This function does initialization specific to the protocol:
**	   Reads any protocol-specific env vars.
**	   Sets up the winsock protocol-specific control info.
** History:
**	05-Nov-93 (edg)
**	    created.
**	23-Feb-1998 (thaal01)
**	    Allow space for port_id, stops GCC crashing on startup sometimes.
**	07-Jul-1998 (macbr01)
**	    Bug 91972 - jasgcc not receiving incoming communications. This is 
**	    due to incorrect usage of PMget() in function GCwintcp_init(). 
**	    Changed to test return code of PMget() instead of testing passed 
**	    in parameter for not equal to NULL.
**	15-jul-1998 (canor01)
**	    Move assignment of port_id to port_id_buf to prevent possible
**	    access violation. Clean up comments.
**	09-feb-2004 (somsa01)
**	    When working with instance identifiers as port IDs, make sure
**	    we initialize sbprt with the trailing number, if set.
**	13-may-2004 (somsa01)
**	    Updated config.dat string used to retrieve port information such
**	    that we do not rely specifically on the GCC port. Also, corrected
**	    function used to convert subport into a number.
**      26-Jan-2006 (loera01) Bug 115671
**          Added GCWINTCP_log_rem_host to allow of gethostbyaddr() to be
**          disabled.
**      06-Feb-2007 (Ralph Loen) SIR 117590
**          Removed GCWINTCP_log_rem_host, since gethostbyaddr() is no
**          longer invoked for network listens.
**      22-Feb-2008 (rajus01) Bug 119987, SD issue 125582
**          Bridge server configuration requires listening on a specified
**          three character listen address. During protocol initialization
**          the bridge server fails to start when three character listen
**          address is specified. For example,
**          the following configuration entries in config.dat
**               ii.<host>.gcb.*.wintcp.port: <xxn>,
**               ii.<host>.gcb.*.wintcp.status:<prot_stat>
**          are for command line configuration. When these entries are
**          present in addition to the CBF VNODE configuration (shown below )
**                ii.rajus01.gcb.*.wintcp.port.v1:<xxn>
**                ii.rajus01.gcb.*.wintcp.status.v1:<prot_stat>
**          the bridge server fails even though the port is available for use.
**          It has been found that the global 'sbprt' variable gets set
**          by the bridge server during protocol initialization to 'n' in the
**          three charater listen address 'xxn'. Later, while resolving the
**          three character portname into port number by GCwintcp_port routine
**          it assumes that this port is already in use even though it is not
**          the case.
**	    Added server_type to determine the GCF server type.
**          The error messages from errlog.log are the following:
**          rajus01 ::[R3\BRIDGE\12c4    , 4804      , ffffffff]: Tue Feb 19
**          19:49:27 2008 E_GC2808_NTWK_OPEN_FAIL  Network open failed for
**          protocol TCP_IP, port R3; status follows.
**          rajus01 ::[R3\BRIDGE\12c4    , 4804      , ffffffff]: Tue Feb 19
**          19:49:27 2008 E_CL2787_GC_OPEN_FAIL    An attempted network open
**          failed.
**	    Change description:
**		The code that clears the third character in the listen address
**		specified in the config.dat has been removed. This
**		appears to be a wrong assumption in the protocol driver based
**	        on the documentation in "Appendix A:TCP/IP protocol, Listen
**		Address Format seciton of Connectivity Guide". With these
**		changes the protocol driver will behave the way UNIX does.
**
**		WARNING: This DOES introduce the behavioural changes in the
**		following cases when starting one or more servers by increa-
**		sing the startup count in config.dat.
**		
**		Case 1: 
**		   Both tcp_ip and win_tcp status are set to ON with Listen
**		   Addresses II5 and II5 for example.
**		   New behaviour: The GCF server will come up and listen on 
**	           one protocol using port II5, but will fail on the other 
**		   protocol. 
**		   Original behaviour:
**		   The GCF server will listen on port II5 on the first
**		   protocol and the second one will listen on II6.
**		   This seems to be a bug in the driver as this is not the 
**		   behaviour documented in the connectivity guide. 
**		Case 2:
**		   Both tcp_ip and win_tcp status are set to ON with Listen
**		   Addresses (win_tcp=II, tcp_ip = II1).
**		   Original behaviour:
**		   First GCF server will come up OK (II0, II1). The second
**		   GCF server will come up fine too ( II2, II3 ).
**		   New Behaviour:
**		   First GCF server will come up fine. The second GCF server
**		   will fail for tcp_ip protocol, but will come up on win_tcp
**		   protocol. This doesn't seem to be much of an issue because
**		   the second GCF server will still come up using win_tcp. 
**	13-Apr-2010 (Bruce Lunsford)  SIR 122679
**	    Set wsd->pce_driver from GCC PCT rather than from ex-global
**	    WS_wintcp.
*/
STATUS
GCwintcp_init(GCC_PCE * pptr, GCC_WINSOCK_DRIVER *wsd)
{

	char           *ptr = NULL;
	char            real_name_size[] = "100";
	char           *host, *server_id, *port_id;
	char            config_string[256];
	char            install[32]; //II_INSTALLATION code

        /*
        ** Get set up for the PMget call.
        */
        PMinit();
        if( PMload( NULL, (PM_ERR_FUNC *)NULL ) != OK )
                PCexit( FAIL );

        /*
        ** Construct the network port identifier.
        */

        host = PMhost();
        server_id = PMgetDefault(3);
        if (!server_id)
                server_id = "*" ;
        STprintf( config_string, ERx("!.wintcp.port"),
                  SystemCfgPrefix, host, server_id);

        /*
        ** Search config.dat for a match on the string we just built.
        ** If we don't find it, then use the value for II_INSTALLATION
        ** failing that, default to II.
        */
        if ((PMget( config_string, &port_id ) != OK) ||
            (port_id == NULL ))
        {
                NMgtAt("II_INSTALLATION", &ptr);
		port_id = install; 
                if (ptr != NULL && *ptr != '\0')
                {
                        STcopy(ptr, port_id);
                }
                else
                {
                        STcopy(SystemVarPrefix, port_id);
                }
        }

	STcopy(port_id, pptr->pce_port);
	GCTRACE(1)("GCwintcp_init: port = %s\n", pptr->pce_port );


	/*
	** Fill in protocol-specific info
	*/
	wsd->addr_len = sizeof( struct sockaddr_in );
	wsd->sock_fam = AF_INET;
	wsd->sock_type = SOCK_STREAM;
	wsd->sock_proto = 0;
	wsd->block_mode = FALSE;
	wsd->pce_driver = pptr->pce_driver;

	/*
	** Get trace variable
	*/
        ptr = NULL;
	NMgtAt( "II_WINTCP_TRACE", &ptr );
	if ( !(ptr && *ptr) && PMget("!.wintcp_trace_level", &ptr) != OK )
	{
	    GCWINTCP_trace = 0;
	}
	else
	{
	    GCWINTCP_trace = atoi( ptr );
	}

	return OK;
}