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 */ }
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 */ }
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; } } }
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; }
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 ); }
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 ); }
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 */ }
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 ); } }
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 ); }
/* ** 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; }
/* ** 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; }
/* ** 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); }
/* ** 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; }
/* ** 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; }
/* ** 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; }