STATUS ME_alloc_shared(i4 flag, SIZE_TYPE pages, char *key, PTR *memory, SIZE_TYPE *allocated_pages, CL_ERR_DESC *err_code) { STATUS status; SIZE_TYPE memsize; #ifdef LP64 LARGE_INTEGER numbytes; #endif HANDLE name; HANDLE map; PTR temp; char map_key[MAX_LOC+1]; char *install_code; char *ObjectPrefix; SECURITY_ATTRIBUTES sa; CLEAR_ERR(err_code); GVshobj(&ObjectPrefix); if (key == NULL || *key == '\0') { return (ME_BAD_PARAM); } memsize = pages * ME_MPAGESIZE; /* ** Moved ME_makekey to be called each time ME_alloc_shared is called ** as this obtains a handle to the file which will be required later ** if this is an attach to shared memory. ** This file handle is closed during an MEshared_free. */ if ((name = ME_makekey(key)) == (HANDLE) -1) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); return (FAIL); } /* ** The file mapping key used to be the name of the file. ** This caused problems when Jasmine and Ingres were installed ** on the same machine. Create a unique key name, and use ** that for File Mapping instead. */ NMgtAt("II_INSTALLATION", &install_code); STpolycat(4, ObjectPrefix, SystemVarPrefix, install_code, key, map_key); if (flag & ME_CREATE_MASK) { iimksecdacl( &sa ); FlushFileBuffers(name); #ifdef LP64 numbytes.QuadPart = Int32x32To64(pages, ME_MPAGESIZE); map = CreateFileMapping(name, &sa, PAGE_READWRITE, numbytes.HighPart, numbytes.LowPart, map_key); #else map = CreateFileMapping(name, &sa, PAGE_READWRITE, 0, memsize, map_key); #endif /* LP64 */ if (map == NULL) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); FlushFileBuffers(name); CloseHandle(name); switch (status) { case ERROR_ALREADY_EXISTS: return ME_ALREADY_EXISTS; case ERROR_NOT_ENOUGH_MEMORY: return ME_OUT_OF_MEM; default: return FAIL; } } if (map != NULL && GetLastError() == ERROR_ALREADY_EXISTS) { FlushFileBuffers(name); CloseHandle(map); CloseHandle(name); return (ME_ALREADY_EXISTS); } } else { map = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, map_key); if (map == NULL) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); FlushFileBuffers(name); CloseHandle(name); switch (status) { case ERROR_FILE_NOT_FOUND: return ME_NO_SUCH_SEGMENT; case ERROR_NOT_ENOUGH_MEMORY: return ME_OUT_OF_MEM; default: return FAIL; } } } /* * Finally. Now get a memory address for the sucker. * * If ME_ADDR_SPEC is set, we'll attempt to hardwire the address; else * we'll take whatever the system gives us. */ if (flag & ME_ADDR_SPEC) { temp = MapViewOfFileEx(map, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0, *memory); if ((temp == NULL) || (temp != *memory)) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); return (FAIL); } } else { *memory = MapViewOfFile(map, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0); if (*memory == NULL) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); return (FAIL); } } /* ** If this is not an attach to shared memory assume that pages value ** is valid. */ if ((flag & ME_CREATE_MASK) || !(flag & (ME_SSHARED_MASK | ME_MSHARED_MASK))) { pages = (SIZE_TYPE)(memsize / ME_MPAGESIZE); } else { BY_HANDLE_FILE_INFORMATION sFileInfo; /* ** If attaching to shared memory ignore the page argument and ** calculate size of shared segment in pages from file size. ** Assume that a single shared memory file will not exceed 4G. */ if (GetFileInformationByHandle (name, &sFileInfo) == 0) { status = GetLastError(); SETWIN32ERR(err_code, status, ER_alloc); return (FAIL); } else { pages = sFileInfo.nFileSizeLow / ME_MPAGESIZE; } } if (allocated_pages) *allocated_pages = pages; /* ** if this is an attach where pages is 0 ME_reg_seg will register ** pages calculated from the size of the file. */ if (ME_reg_seg(*memory, pages, map, name) != OK) { UnmapViewOfFile(memory); *memory = (PTR) NULL; return (FAIL); } return (OK); }
/* ** 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: DI_list - Use WIN32 NT directory listing interface to list files ** ** Description: ** List all files/directories in a given directory depending on ** list_type argument. ** ** Inputs: ** path Pointer to the path name. ** pathlength Length of path name. ** list_type type of object to list (DIRECTORY or FILE) ** func function to call for each object found. ** arg_list arguments to call the function with. ** ** Outputs: ** err_code Pointer to a variable used ** to return operating system ** errors. ** ** Returns: ** DI_BADDIR Path specification error. ** DI_ENDFILE Error returned from client handler or ** all files listed. ** DI_BADPARAM Parameter(s) in error. ** DI_DIRNOTFOUND Path not found. ** DI_BADLIST Error trying to list objects. ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 07-jul-1995 (canor01) ** convert filename returned from FindFirstFile() to lowercase, since ** other DI functions (via unix) expect lowercase. ** 18-jul-1995 (reijo01) ** Changed SETWIN32ERR so that it will populate the CL_ERR_DESC with ** the proper values. ** 08-dec-1997 (canor01) ** Implement LRU for open files (initial copy from Unix). ** 28-jan-1998 (canor01) ** Correct a problem with previous implementation. If closing ** files succeeds, retry, else bail out with error. ** 04-mar-1998 (canor01) ** Parameters to DIlru_flush were changed on Unix side. Change ** them here too. ** ******************************************************************************/ static STATUS DI_list(char *path, u_i4 pathlength, i4 list_type, STATUS (*func) (), PTR arg_list, CL_SYS_ERR *err_code) { STATUS ret_val = OK; STATUS dos_call; char input_path[DI_PATH_MAX]; HANDLE handle; ULONG count = 1; WIN32_FIND_DATA findbuf; /* default returns */ CLEAR_ERR(err_code); /* Check input parameters */ if ((pathlength > DI_PATH_MAX) || (pathlength == 0)) return DI_BADPARAM; /* get null terminated path to the directory */ memcpy(input_path, path, pathlength); memcpy(input_path + pathlength, "\\*.*", 5); /* break out on errors */ while ( (handle = FindFirstFile(input_path, &findbuf)) == INVALID_HANDLE_VALUE ) { switch (dos_call = GetLastError()) { case ERROR_NO_SYSTEM_RESOURCES: case ERROR_TOO_MANY_OPEN_FILES: case ERROR_NO_MORE_FILES: case ERROR_NOT_ENOUGH_MEMORY: case ERROR_OUTOFMEMORY: case ERROR_HANDLE_DISK_FULL: case ERROR_OUT_OF_STRUCTURES: case ERROR_NONPAGED_SYSTEM_RESOURCES: case ERROR_PAGED_SYSTEM_RESOURCES: if (DIlru_flush( err_code ) != OK) { ret_val = DI_BADLIST; } else { continue; } break; case ERROR_PATH_NOT_FOUND: SETWIN32ERR(err_code, dos_call, ER_list); ret_val = DI_DIRNOTFOUND; break; default: SETWIN32ERR(err_code, dos_call, ER_list); ret_val = DI_BADLIST; break; } if ( ret_val != OK ) return(ret_val); } /* now loop through all entries in the directory */ ret_val = DI_ENDFILE; do { if (!memcmp(findbuf.cFileName, ".", 2) || !memcmp(findbuf.cFileName, "..", 3)) { continue; } /* * This next check is a leftover from OS/2. Should dump it * at some point, or enlarge the functionality of this * routine. If we're looking for a directory, verify it is * one... */ if (list_type == DIRECTORY) { if (~findbuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { continue; } } /* * other functions expect lowercase name, but DOS * returns uppercase * * bug fix 89213. * Unlike DOS, NT returns upper and lower case * names. */ if ((*func) (arg_list, findbuf.cFileName, STlength(findbuf.cFileName), err_code)) { ret_val = DI_ENDFILE; break; } } while (FindNextFile(handle, &findbuf)); if (!FindClose(handle)) { SETWIN32ERR(err_code, GetLastError(), ER_list); ret_val = DI_BADLIST; } return (ret_val); }