1614 lines
39 KiB
C
1614 lines
39 KiB
C
/*++
|
||
|
||
Copyright (c) 1991-92 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
msginit.c
|
||
|
||
Abstract:
|
||
|
||
Messenger Service Initialization Routines.
|
||
The following is a list of functions in this file:
|
||
|
||
MsgInitializeMsgr
|
||
BufferInit
|
||
InitSharedData
|
||
SetComputerName
|
||
GetNumNets
|
||
MsgGetBufSize
|
||
SetUpMessageFile
|
||
|
||
Author:
|
||
|
||
Dan Lafferty (danl) 18-Jul-1991
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Notes:
|
||
|
||
optional-notes
|
||
|
||
Revision History:
|
||
|
||
19-Aug-1997 wlees
|
||
PNP support. Retry if lana's not present yet.
|
||
|
||
27-Jun-1995 AnirudhS
|
||
LocalFree(dataPtr) must be called AFTER MsgFreeSupportSeg, because
|
||
the latter tries to _close a handle stored in dataPtr.
|
||
|
||
08-Feb-1994 Danl
|
||
Removed the restriction that the memory allocated had to be
|
||
restricted to less than a 64K segment. We don't worry about
|
||
segments anymore.
|
||
|
||
12-Jan-1993 Danl
|
||
In error paths where we call MsgCloseWakeupSems, I need to do the
|
||
LocalFree(dataPtr) after the call to MsgCloseWakeupSems. Otherwise,
|
||
it access violates because MsgCloseWakeupSems uses the shared date
|
||
in the block pointed to by the dataPtr.
|
||
|
||
21-Apr-1992 JohnRo
|
||
Fixed bug printing a status when message name add fails.
|
||
Changed to use FORMAT_ equates throughout.
|
||
|
||
18-Feb-1992 ritaw
|
||
Convert to Win32 service control APIs.
|
||
|
||
18-Jul-1991 danl
|
||
Created as a composite of the original LM2,0 routines.
|
||
|
||
|
||
--*/
|
||
//
|
||
// Includes
|
||
//
|
||
|
||
#include <stdlib.h> // atol
|
||
#include "msrv.h" // Messenger prototypes and constants
|
||
#include <winsvc.h> // Service control APIs
|
||
#include <winsock2.h> // Windows sockets
|
||
|
||
#include <netdebug.h> // NetpAssert, FORMAT_ equates.
|
||
#include <rpc.h> // DataTypes and runtime APIs
|
||
#include <msgsvc.h> // generated by the MIDL complier
|
||
|
||
#include <netlibnt.h> // NetpNtStatusToApiStatus prototypes
|
||
|
||
#include <tstring.h> // Unicode string macros
|
||
#include <string.h> // memcpy
|
||
#include <lmwksta.h> // NetWrkstaTransportEnum
|
||
#include <lmapibuf.h> // NetApiBufferFree
|
||
#include <netlib.h> // UNUSED macro
|
||
#include <msgrutil.h> // NetpNetBiosReset
|
||
#include <apperr2.h> // APE2_ALERTER_PRINTING_SUCCESS
|
||
|
||
#include "msgdbg.h" // MSG_LOG
|
||
#include "heap.h" // heap management routines and macros.
|
||
#include "msgdata.h" // Global data
|
||
#include "msgsec.h" // Messenger security information
|
||
|
||
#include "msgnames.h" // MSGR_INTERFACE_NAME
|
||
#include "msgtext.h" // MTXT_MsgsvcTitle
|
||
|
||
#include "msgsvcsend.h" // Broadcast message send interface
|
||
|
||
#include "apiutil.h" // for MsgAddSessionInList
|
||
|
||
// The per net data and heap buffer are allocated once. Later on we may
|
||
// wish to keep them separate.
|
||
#define BOOKKEEPING_SIZE(n) (n * sizeof(NET_DATA))
|
||
|
||
#define MAXSEG (0xffff)
|
||
|
||
#define LMI_PARM_M_SIZMESSBUF TEXT("/sizmessbuf")
|
||
|
||
|
||
//
|
||
// Global Data
|
||
//
|
||
|
||
static DWORD bufferSize; // Message buffer size
|
||
static DWORD msrv_pid; // pid of message server
|
||
|
||
extern LPTSTR MessageFileName;
|
||
|
||
//
|
||
// Local Function Prototypes
|
||
//
|
||
|
||
VOID
|
||
MsgBufferInit(
|
||
IN DWORD dwBufLen
|
||
);
|
||
|
||
NET_API_STATUS
|
||
MsgInitSharedData(
|
||
DWORD NumNets
|
||
);
|
||
|
||
NET_API_STATUS
|
||
MsgSetComputerName(
|
||
DWORD NumNets
|
||
);
|
||
|
||
DWORD
|
||
MsgGetNumNets(VOID);
|
||
|
||
NET_API_STATUS
|
||
MsgGetBufSize (
|
||
OUT LPDWORD bufferSize
|
||
);
|
||
|
||
DWORD
|
||
MsgSetUpMessageFile(VOID);
|
||
|
||
|
||
STATIC VOID
|
||
MsgInitMessageBoxTitle(
|
||
VOID
|
||
);
|
||
|
||
NET_API_STATUS
|
||
MsgrInitializeMsgrInternal1(
|
||
void
|
||
);
|
||
|
||
NET_API_STATUS
|
||
MsgrInitializeMsgrInternal2(
|
||
void
|
||
);
|
||
|
||
VOID
|
||
MsgInitEndpoint(
|
||
PVOID Context // This passed in as context
|
||
);
|
||
|
||
|
||
NET_API_STATUS
|
||
MsgInitializeMsgr(
|
||
IN DWORD argc,
|
||
IN LPTSTR *argv
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Registers the control handler with the dispatcher thread. Then it
|
||
performs all initialization including the starting of the RPC server.
|
||
If any of the initialization fails, MsgStatusUpdate is called so that the
|
||
status is updated and the thread is terminated.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS status;
|
||
DWORD msgrState;
|
||
DWORD bufLen;
|
||
WSADATA wsaData;
|
||
NTSTATUS ntStatus;
|
||
|
||
//
|
||
// Initialize the Thread Manager. This initializes some locks used
|
||
// on the Thread and Status databases.
|
||
//
|
||
status = MsgThreadManagerInit();
|
||
|
||
if (status != NO_ERROR)
|
||
{
|
||
MSG_LOG1(ERROR,
|
||
"MsgInitializeMsgr: Thread manager init failed %d\n",
|
||
status);
|
||
|
||
return MsgBeginForcedShutdown(IMMEDIATE, status);
|
||
}
|
||
|
||
//
|
||
// Initialize the status structure
|
||
//
|
||
MsgStatusInit();
|
||
|
||
//
|
||
// Register this service with the ControlHandler.
|
||
// Now we can accept control requests and be requested to UNINSTALL.
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Calling RegisterServiceCtrlHandlerEx\n",0);
|
||
if ((MsgrStatusHandle = RegisterServiceCtrlHandlerEx(
|
||
SERVICE_MESSENGER,
|
||
MsgrCtrlHandler,
|
||
NULL
|
||
)) == (SERVICE_STATUS_HANDLE) NULL) {
|
||
|
||
status = GetLastError();
|
||
|
||
MSG_LOG(ERROR,
|
||
"FAILURE: RegisterServiceCtrlHandlerEx status = " FORMAT_API_STATUS
|
||
"\n", status);
|
||
|
||
return( MsgBeginForcedShutdown (
|
||
IMMEDIATE,
|
||
status));
|
||
}
|
||
|
||
//
|
||
// Notify that installation is pending
|
||
//
|
||
|
||
msgrState = MsgStatusUpdate(STARTING);
|
||
|
||
if (msgrState != STARTING) {
|
||
//
|
||
// An UNINSTALL control request must have been received
|
||
//
|
||
return(msgrState);
|
||
}
|
||
|
||
//
|
||
// Init the _HYDRA_ WinStation message support
|
||
//
|
||
status = MultiUserInitMessage();
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR, "MultiUser Initialization Failed " FORMAT_RPC_STATUS "\n",
|
||
status);
|
||
|
||
return (MsgBeginForcedShutdown(
|
||
IMMEDIATE,
|
||
status));
|
||
}
|
||
|
||
//
|
||
// Check that the workstation is started
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Calling NetServiceControl\n",0);
|
||
|
||
if (! NetpIsServiceStarted(SERVICE_WORKSTATION)) {
|
||
|
||
MSG_LOG(ERROR, "WorkStation Service is not started\n",0);
|
||
|
||
return (MsgBeginForcedShutdown(
|
||
IMMEDIATE,
|
||
NERR_WkstaNotStarted));
|
||
}
|
||
|
||
// *** INSTALLATION HINT ***
|
||
msgrState = MsgStatusUpdate(STARTING);
|
||
if (msgrState != STARTING) {
|
||
return(msgrState);
|
||
}
|
||
|
||
//
|
||
// Get the default buffer size.
|
||
//
|
||
|
||
status = MsgGetBufSize(&bufferSize);
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR, "MsgGetBufSize Failed\n",0);
|
||
return (MsgBeginForcedShutdown(
|
||
IMMEDIATE,
|
||
status));
|
||
}
|
||
|
||
// *** INSTALLATION HINT ***
|
||
msgrState = MsgStatusUpdate(STARTING);
|
||
if (msgrState != STARTING) {
|
||
return(msgrState);
|
||
}
|
||
|
||
|
||
if (bufferSize > MAX_SIZMESSBUF || bufferSize < MIN_SIZMESSBUF) {
|
||
MSG_LOG(ERROR, "Message Buffer Size is illegal\n",0);
|
||
return (MsgBeginForcedShutdown(
|
||
IMMEDIATE,
|
||
ERROR_INVALID_PARAMETER));
|
||
}
|
||
|
||
//
|
||
// This is the size of the buffer (that SDBUFFER points to) in the
|
||
// shared data area. This is calculated as:
|
||
//
|
||
// The size of a message buffer (bufferSize)
|
||
// plus
|
||
// space for 4 Multi-block message headers and names,
|
||
// plus
|
||
// space for one Multi-block text header for each text block that
|
||
// fits into the message buffer. (bufferSize/TXTMAX).
|
||
//
|
||
// The number of headers is rounded up by one.
|
||
// (bufferSize+TXTMAX-1)/TXTMAX
|
||
//
|
||
bufferSize += (4 * (sizeof(MBB) + (2 * NCBNAMSZ))) +
|
||
((( (bufferSize+TXTMAX-1)/TXTMAX) + 1) * sizeof(MBT));
|
||
|
||
|
||
|
||
// ***** INSTALLATION HINT *****
|
||
msgrState = MsgStatusUpdate(STARTING);
|
||
if (msgrState != STARTING) {
|
||
return(msgrState);
|
||
}
|
||
|
||
//
|
||
// Ask the Worksta for the computer name. If the computer
|
||
// has no name, then abort.
|
||
//
|
||
// The computername and the username are in unicode format.
|
||
//
|
||
// NOTE: the username that is returned is a name we may want to add
|
||
// to the table.
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Getting the ComputerName\n",0);
|
||
|
||
bufLen = sizeof(machineName);
|
||
|
||
*machineName = TEXT('\0');
|
||
|
||
if (!GetComputerName(machineName,&bufLen)) {
|
||
MSG_LOG(ERROR,"GetComputerName failed \n",0);
|
||
status = GetLastError();
|
||
}
|
||
|
||
if ( (status != NERR_Success) ||
|
||
(*machineName == TEXT('\0')) || (*machineName == TEXT(' ')))
|
||
{
|
||
//
|
||
// fatal error if no name
|
||
//
|
||
MSG_LOG(ERROR, "GetWkstaNames Failed\n",0);
|
||
return (MsgBeginForcedShutdown(
|
||
IMMEDIATE,
|
||
NERR_NoComputerName));
|
||
}
|
||
|
||
machineName[NCBNAMSZ] = TEXT('\0'); // make sure it's terminated
|
||
MachineNameLen = (SHORT) STRLEN(machineName);
|
||
|
||
|
||
// ***** INSTALLATION HINT *****
|
||
msgrState = MsgStatusUpdate(STARTING);
|
||
|
||
if (msgrState != STARTING)
|
||
{
|
||
return(msgrState);
|
||
}
|
||
|
||
//
|
||
// Initialize the configuration lock. This lock covers the allocation and deallocation
|
||
// of the data structures related to lan adapters.
|
||
//
|
||
if (MsgConfigurationLock(MSG_INITIALIZE,"MsgInitializeMsgr"))
|
||
{
|
||
//
|
||
// Do first phase of lan adapter related configuration
|
||
//
|
||
status = MsgrInitializeMsgrInternal1();
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG1(ERROR, "MsgrInitializeMsgrInternal1 Failure %d\n", status);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
MSG_LOG0(ERROR, "MsgConfigurationLock -- MSG_INITIALIZE failed\n");
|
||
|
||
status = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MsgFreeSharedData();
|
||
|
||
if (wakeupSem != NULL)
|
||
{
|
||
MsgFreeSupportSeg();
|
||
}
|
||
|
||
MsgCloseWakeupSems(); // Close the ones that have been created
|
||
|
||
return (MsgBeginForcedShutdown(
|
||
IMMEDIATE,
|
||
status));
|
||
}
|
||
|
||
|
||
// ***** INSTALLATION HINT *****
|
||
msgrState = MsgStatusUpdate(STARTING);
|
||
|
||
if (msgrState != STARTING)
|
||
{
|
||
return(msgrState);
|
||
}
|
||
|
||
//
|
||
// Change from IMMEDIATE Shutdowns to PENDING shutdowns.
|
||
// This is because at this point we have names on the adapters
|
||
// to clean up.
|
||
//
|
||
|
||
status = MsgrInitializeMsgrInternal2();
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG1(ERROR, "MsgrInitializeMsgrInternal2 Failure\n", status);
|
||
|
||
return (MsgBeginForcedShutdown(
|
||
PENDING,
|
||
status));
|
||
}
|
||
|
||
//
|
||
// Build the name of the file that is to be used to get the
|
||
// message header and tail. Don't care about errors, since
|
||
// any error will result in the file not being used and is
|
||
// resorting to the old standby strings.
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Calling MsgSetUpMessageFile\n",0);
|
||
MsgSetUpMessageFile();
|
||
|
||
//
|
||
// Start the Group messenger thread to handle all domain messaging
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Calling MsgInitGroupSupport\n",0);
|
||
|
||
if ( status = MsgInitGroupSupport( SD_NUMNETS() ) )
|
||
{
|
||
MSG_LOG(ERROR, "InitGroupSupport Failed\n",0);
|
||
return (MsgBeginForcedShutdown(
|
||
PENDING,
|
||
NERR_GrpMsgProcessor));
|
||
}
|
||
|
||
//
|
||
// Initialize the Display Code
|
||
//
|
||
status = MsgDisplayInit();
|
||
|
||
if (status != NO_ERROR)
|
||
{
|
||
MSG_LOG1(ERROR, "Could not initialize the display functions %d\n", status);
|
||
return (MsgBeginForcedShutdown(
|
||
PENDING,
|
||
status));
|
||
}
|
||
|
||
|
||
//
|
||
// Create the security descriptor that is to be used in access
|
||
// checks on the API interface.
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Calling MsgCreateMessageNameObject\n",0);
|
||
status = MsgCreateMessageNameObject();
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR, "MsgCreateMessageNameObject (security descriptor) "
|
||
"Failed\n", 0);
|
||
|
||
return (MsgBeginForcedShutdown(
|
||
PENDING,
|
||
status));
|
||
}
|
||
|
||
//
|
||
// Initialize the text for the message box title.
|
||
//
|
||
MsgInitMessageBoxTitle();
|
||
|
||
//
|
||
// Start the Messengers RPC server.
|
||
//
|
||
// NOTE: Now all RPC servers in services.exe share the same pipe name.
|
||
// However, in order to support communication with version 1.0 of WinNt,
|
||
// it is necessary for the Client Pipe name to remain the same as
|
||
// it was in version 1.0. Mapping to the new name is performed in
|
||
// the Named Pipe File System code.
|
||
//
|
||
|
||
MSG_LOG(TRACE,
|
||
"MsgInitializeMsgr:Getting ready to start RPC server\n",0);
|
||
|
||
status = MsgsvcGlobalData->StartRpcServer(
|
||
MSGR_INTERFACE_NAME,
|
||
msgsvc_ServerIfHandle);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
MSG_LOG(ERROR, "RPC Initialization Failed " FORMAT_RPC_STATUS "\n",
|
||
status);
|
||
|
||
return (MsgBeginForcedShutdown(
|
||
PENDING,
|
||
status));
|
||
}
|
||
|
||
//
|
||
// Start thread to register with endpoint mapper (may take a while)
|
||
//
|
||
ntStatus = RtlQueueWorkItem(MsgInitEndpoint, // Callback
|
||
NULL, // pContext
|
||
WT_EXECUTEONLYONCE | // Long one-shot callback
|
||
WT_EXECUTELONGFUNCTION);
|
||
|
||
if (!NT_SUCCESS(ntStatus)) {
|
||
MSG_LOG(ERROR, "MsgInit: failed to start endpoint registration thread: %#x\n",
|
||
ntStatus);
|
||
|
||
return (MsgBeginForcedShutdown(
|
||
PENDING,
|
||
status));
|
||
}
|
||
|
||
// Initialize winsock (needed for name resolution)
|
||
//
|
||
|
||
status = WSAStartup(MAKEWORD(2,1),&wsaData);
|
||
if (status != ERROR_SUCCESS) {
|
||
MSG_LOG(ERROR, "Initialization of Winsock DLL failed " FORMAT_RPC_STATUS "\n",
|
||
status);
|
||
|
||
return (MsgBeginForcedShutdown(
|
||
PENDING,
|
||
status));
|
||
}
|
||
|
||
//
|
||
// Update the status to indicate that installation is complete.
|
||
// Get the current state back in case the ControlHandling thread has
|
||
// told us to shutdown.
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Exiting MsgInitializeMsgr - Init Done!\n",0);
|
||
|
||
return (MsgStatusUpdate(RUNNING));
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
MsgrInitializeMsgrInternal1(
|
||
void
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize volatile state related to lanas.
|
||
These initializations can be undone immediately if there is an error.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD NumNets;
|
||
NET_API_STATUS status;
|
||
|
||
MSG_LOG(TRACE, "Calling MsgGetNumNets\n",0);
|
||
NumNets = MsgGetNumNets();
|
||
|
||
if (NumNets == 0)
|
||
{
|
||
MSG_LOG(TRACE, "FYI: No lana's enabled at this time\n",0);
|
||
// Not having any networks is no longer an error, ie Numnets == 0 is ok
|
||
}
|
||
|
||
//
|
||
// Initialize shared memory areas.
|
||
//
|
||
MSG_LOG(TRACE, "Calling MsgInitSharedData\n",0);
|
||
status = MsgInitSharedData(NumNets);
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
return status;
|
||
}
|
||
|
||
//*****************************************
|
||
//
|
||
// STUFF FROM Init_msrv() in MSRV.C
|
||
//
|
||
//*****************************************
|
||
|
||
heap = SD_BUFFER(); // Initialize data heap pointer
|
||
heapln = SD_BUFLEN(); // Initialize data heap length
|
||
|
||
//
|
||
// Set up the segement to hold the net bios handles, lana-nums
|
||
// and wakeup Semaphores.
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Calling MsgInitSupportSeg\n",0);
|
||
|
||
status = MsgInitSupportSeg();
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR, "InitSupportSeg Failed\n",0);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Now initialize global net bios handles & lana nums. Initializes net_lana_num[]
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Calling MsgInit_NetBios\n",0);
|
||
|
||
status = MsgInit_NetBios();
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG1(ERROR, "MsgInit_NetBios failed %d\n", status);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Get the wake up semaphore handles. Initializes wakeupSem[]
|
||
//
|
||
|
||
MSG_LOG(TRACE, "Calling MsgCreateWakeupSems\n",0);
|
||
|
||
//
|
||
// This always returns TRUE
|
||
//
|
||
MsgCreateWakeupSems(SD_NUMNETS());
|
||
|
||
//
|
||
// Open NETBIOS for use by messenger.
|
||
// If any failures occur beyond this we must remember to close.
|
||
//
|
||
MsgsvcGlobalData->NetBiosOpen();
|
||
|
||
//
|
||
// Set computer name on adapters - if any
|
||
//
|
||
MSG_LOG(TRACE, "Calling MsgSetComputerName\n",0);
|
||
|
||
status = MsgSetComputerName(SD_NUMNETS());
|
||
|
||
if(status != NERR_Success)
|
||
{
|
||
MSG_LOG1(ERROR, "SetComputerName failed %d\n", status);
|
||
MsgsvcGlobalData->NetBiosClose();
|
||
return status;
|
||
}
|
||
|
||
return NERR_Success;
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
MsgrInitializeMsgrInternal2(
|
||
void
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize volatile lana state. These initializations cannot be undone easily. If this routine
|
||
fails we must go through a full shutdown in order to clean up.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Installation is successful and complete. If there is a
|
||
// user logged on then an attempt is made to add the user name
|
||
// to this message server. No attempt is made at error reporting
|
||
// if this fails, there may not be a user logged on, and if there is,
|
||
// the user name may already exist as a message name on another
|
||
// station.
|
||
//
|
||
// This is when we add usernames to the message table if we can.
|
||
// Sometime this needs to handle multiple users??? (not in version 1)
|
||
//
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
MsgAddAlreadyLoggedOnUserNames();
|
||
}
|
||
else
|
||
{
|
||
MsgAddUserNames();
|
||
}
|
||
|
||
return NERR_Success;
|
||
}
|
||
|
||
|
||
VOID
|
||
MsgBufferInit(
|
||
IN DWORD dwBufLen
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called during initialization to set up
|
||
the message buffer in the shared data area.
|
||
|
||
This function assumes that the shared data area is locked
|
||
in memory, that the access semaphore for the shared data
|
||
area is set, and that the global far pointer, dataPtr, is
|
||
valid. BufferInit() initializes the heap structure of the
|
||
buffer.
|
||
|
||
SIDE EFFECTS
|
||
|
||
The buffer in shared memory is initialized.
|
||
|
||
Arguments:
|
||
|
||
dwBuflen - buffer length
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
|
||
{
|
||
LPHEAPHDR hp; // Heap block pointer
|
||
|
||
hp = (LPHEAPHDR) SD_BUFFER(); // Get the address of buffer
|
||
HP_SIZE(*hp) = dwBufLen; // Set the size of the first block
|
||
HP_FLAG(*hp) = 0; // Unallocated
|
||
SD_BUFLEN() = dwBufLen; // Save the length of the buffer
|
||
}
|
||
|
||
DWORD
|
||
MsgInitSharedData(
|
||
DWORD NumNets
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function creates and initializes the shared data area.
|
||
It sets up the computer name and initializes the message
|
||
buffer.
|
||
|
||
SIDE EFFECTS
|
||
|
||
Calls MsgBufferInit().
|
||
|
||
|
||
Arguments:
|
||
|
||
NumNets - Number of network adapters to support.
|
||
|
||
Return Value:
|
||
|
||
RETURN
|
||
NERR_Success if the operation was successful
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - If the memory alloc for the shared
|
||
memory segment fails.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD i,j; // Index
|
||
ULONG size;
|
||
PNCB_DATA pNcbData;
|
||
DWORD MinimumNumNets = ((NumNets == 0)? 1 : NumNets); // 1 is the minimum
|
||
|
||
//
|
||
// Create and initialize shared data area.
|
||
//
|
||
size = bufferSize + BOOKKEEPING_SIZE(MinimumNumNets);
|
||
|
||
if ((GlobalData.NetData = (PNET_DATA)LocalAlloc(LMEM_ZEROINIT, size)) == NULL) {
|
||
goto NoMemory;
|
||
}
|
||
//
|
||
// In case NumNets = 0, keep 1 dummy NetData.
|
||
// This is not very pretty but should avoid any trouble, without having to modify
|
||
// too much code.
|
||
//
|
||
GlobalData.Buffer = (PCHAR) (&GlobalData.NetData[MinimumNumNets]);
|
||
|
||
for (i = 0; i < NumNets ; i++ )
|
||
{
|
||
// Allocate the list array at the maximum size, but only allocate
|
||
// a small initial number of NCBs.
|
||
if ((GlobalData.NetData[i].NcbList =
|
||
LocalAlloc(LMEM_ZEROINIT,
|
||
sizeof(PNCB_DATA) * NCB_MAX_ENTRIES)) == NULL)
|
||
{
|
||
goto NoMemory;
|
||
}
|
||
GlobalData.NetData[i].NumNcbs = NCB_INIT_ENTRIES;
|
||
|
||
for (j=0; j < NCB_INIT_ENTRIES; j++)
|
||
{
|
||
if ((GlobalData.NetData[i].NcbList[j] = pNcbData =
|
||
(PNCB_DATA) LocalAlloc(LMEM_ZEROINIT,
|
||
sizeof(NCB_DATA))) == NULL)
|
||
{
|
||
goto NoMemory;
|
||
}
|
||
|
||
pNcbData->Ncb.ncb_cmd_cplt = 0xff;
|
||
pNcbData->Ncb.ncb_retcode = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Initialize the shared data lock. The shared data is shared between
|
||
// the API threads and the worker threads.
|
||
//
|
||
if (!MsgDatabaseLock(MSG_INITIALIZE,"InitSharedData"))
|
||
{
|
||
MSG_LOG0(ERROR,
|
||
"MsgInitSharedData: MsgDatabaseLock failed\n");
|
||
|
||
goto NoMemory;
|
||
}
|
||
|
||
//
|
||
// Initialize the "used-to-be shared" data
|
||
//
|
||
SD_NUMNETS() = NumNets;
|
||
SD_MSRV() = 0; // No message server active
|
||
SD_LOGNAM()[0] = '\0'; // No log file yet
|
||
SD_MESLOG() = 0; // Message logging disabled
|
||
SD_MESQF() = INULL; // Message queue is empty
|
||
SD_MESQB() = INULL;
|
||
|
||
for ( j = 0; j < SD_NUMNETS(); j++ )
|
||
{
|
||
for(i = 0; i < NCBMAX(j); ++i)
|
||
{
|
||
//
|
||
// Mark entries as free
|
||
//
|
||
SD_NAMEFLAGS(j,i) = NFDEL;
|
||
|
||
//create empty session lists
|
||
InitializeListHead(&(SD_SIDLIST(j,i)));
|
||
}
|
||
}
|
||
|
||
//
|
||
// Initialize the message buffer
|
||
//
|
||
MsgBufferInit(bufferSize);
|
||
|
||
//
|
||
// NT NOTE:
|
||
// Skip Initializing the Support Set and Wakeup sems.
|
||
// Init_msrv will end up doing that.
|
||
//
|
||
|
||
return(NERR_Success);
|
||
|
||
NoMemory:
|
||
MSG_LOG(ERROR,"[MSG]InitSharedData:LocalAlloc Failure "
|
||
FORMAT_API_STATUS "\n", GetLastError());
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
|
||
}
|
||
|
||
VOID
|
||
MsgFreeSharedData(VOID)
|
||
{
|
||
PNET_DATA pNetData;
|
||
PNCB_DATA pNcbData;
|
||
DWORD i,j;
|
||
|
||
if (pNetData = GlobalData.NetData) {
|
||
for (i = 0; i < SD_NUMNETS() ; i++, pNetData++ ) {
|
||
if (pNetData->NcbList) {
|
||
for (j = 0; j < NCBMAX(i) ; j++ ) {
|
||
if (pNcbData = GETNCBDATA(i,j)) {
|
||
LocalFree(pNcbData);
|
||
}
|
||
}
|
||
LocalFree(pNetData->NcbList);
|
||
}
|
||
}
|
||
LocalFree(GlobalData.NetData);
|
||
GlobalData.NetData = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
MsgSetComputerName(
|
||
IN DWORD NumNets
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets up the shared data area for the computer name
|
||
so that it can receive messages.
|
||
|
||
This function sets things up so that the computer name will be able
|
||
to receive messages. First, it adds the user name form of the computer
|
||
name to the local adapter. If successful, it then initializes one slot
|
||
in the name table in the shared data area: a computer name
|
||
receiving messages
|
||
|
||
SIDE EFFECTS
|
||
|
||
Locks the init data segment around net bios usage.
|
||
Calls the net bios. Makes entries in the shared data area.
|
||
|
||
|
||
Arguments:
|
||
|
||
NumNets - The number of network adapters that is supported
|
||
|
||
Return Value:
|
||
|
||
0 = success
|
||
non-zero = failure
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS status = NERR_Success;
|
||
NCB ncb;
|
||
UCHAR res;
|
||
DWORD i;
|
||
unsigned short j;
|
||
|
||
struct {
|
||
ADAPTER_STATUS AdapterStatus;
|
||
NAME_BUFFER NameBuffer[16];
|
||
} Astat;
|
||
|
||
|
||
//
|
||
// Loop for each net.
|
||
//
|
||
|
||
for ( i = 0; i < NumNets; i++ )
|
||
{
|
||
// NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW
|
||
//
|
||
// Reset the adapter
|
||
//
|
||
MSG_LOG1(TRACE,"Calling NetBiosReset for lana #%d\n",GETNETLANANUM(i));
|
||
|
||
status = MsgsvcGlobalData->NetBiosReset(GETNETLANANUM(i));
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG(ERROR,"MsgSetComputerName: NetBiosReset failed "
|
||
FORMAT_API_STATUS "\n", status);
|
||
MSG_LOG(ERROR,"MsgSetComputerName: AdapterNum " FORMAT_DWORD
|
||
"\n",i);
|
||
//
|
||
// If it fails, skip to the Next Net.
|
||
//
|
||
continue;
|
||
}
|
||
|
||
//
|
||
//
|
||
// NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW-NEW
|
||
|
||
//
|
||
// Set call name for local adapter
|
||
//
|
||
clearncb(&ncb);
|
||
status = MsgFmtNcbName(ncb.ncb_name, machineName, 3);
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG1(ERROR, "SetComputerName: Format name failed!", status);
|
||
return status;
|
||
}
|
||
|
||
ncb.ncb_command = NCBADDNAME; // Add name (wait)
|
||
ncb.ncb_lana_num = GETNETLANANUM(i); // Use the LANMAN adapter
|
||
|
||
//
|
||
// Copy the name
|
||
// (At this point the name is ansi - not unicode)
|
||
//
|
||
memcpy(SD_NAMES(i,0), ncb.ncb_name, NCBNAMSZ);
|
||
|
||
if (g_IsTerminalServer)
|
||
{
|
||
MSG_LOG(TRACE,"SetComputerName: Adding session EVERYBODY_SESSION_ID in the list\n",0);
|
||
MsgAddSessionInList(&(SD_SIDLIST(i,0)),(ULONG)EVERYBODY_SESSION_ID);
|
||
}
|
||
|
||
MSG_LOG1(TRACE,"MsgSetComputerName: Adding ComputerName to lana #%d\n",
|
||
GETNETLANANUM(i));
|
||
|
||
res = Msgsendncb( &ncb, i);
|
||
|
||
//
|
||
// If the lana is being reinitialized we need to force a reset
|
||
//
|
||
if ((res & 0xff) == NRC_ENVNOTDEF)
|
||
{
|
||
MSG_LOG1(TRACE,"SetComputerName: NetBios ADDNAME failed 0x%x - doing reset\n",res);
|
||
status = NetpNetBiosReset(GETNETLANANUM(i));
|
||
|
||
if (status == NERR_Success)
|
||
{
|
||
//
|
||
// rebuild the add name request
|
||
//
|
||
clearncb(&ncb);
|
||
status = MsgFmtNcbName(ncb.ncb_name, machineName, 3);
|
||
|
||
if (status != NERR_Success)
|
||
{
|
||
MSG_LOG1(ERROR, "SetComputerName: Format name failed %d!", status);
|
||
return status;
|
||
}
|
||
|
||
ncb.ncb_command = NCBADDNAME; // Add name (wait)
|
||
ncb.ncb_lana_num = GETNETLANANUM(i); // Use the LANMAN adapter
|
||
|
||
MSG_LOG1(TRACE,"MsgSetComputerName: Adding ComputerName<03> to lana #%d\n",
|
||
GETNETLANANUM(i));
|
||
|
||
res = Msgsendncb(&ncb, i); // reissue the ncb
|
||
}
|
||
}
|
||
|
||
if(res != 0)
|
||
{
|
||
MSG_LOG1(TRACE,"SetComputerName: NetBios ADDNAME failed 0x%x\n",res);
|
||
|
||
if((res & 0xff) == NRC_DUPNAME)
|
||
{
|
||
//
|
||
// If the name already exists on the adapter card (the
|
||
// workstation may have added it), we want to get the
|
||
// name number and pretend that we just added it.
|
||
//
|
||
// Name already exists. Issue an ASTAT to find the name
|
||
// number.
|
||
//
|
||
clearncb(&ncb);
|
||
ncb.ncb_buffer = (char FAR *) &Astat; // Set buffer address
|
||
ncb.ncb_length = sizeof(Astat); // Set buffer length
|
||
ncb.ncb_callname[0] = '*'; // local adapter status
|
||
ncb.ncb_command = NCBASTAT; // Adapter status (wait)
|
||
|
||
res = Msgsendncb(&ncb,i);
|
||
if( res != NRC_GOODRET)
|
||
{
|
||
//
|
||
// Failed to add name
|
||
//
|
||
MSG_LOG1(ERROR, "SetComputerName:sendncb (ASTAT) failed 0x%x\n", res);
|
||
return MsgMapNetError(res);
|
||
}
|
||
|
||
//
|
||
// Loop to name number
|
||
//
|
||
for(j = 0; j< Astat.AdapterStatus.name_count; ++j)
|
||
{
|
||
if (((Astat.NameBuffer[j].name_flags & 7) == 4)
|
||
&&
|
||
(memcmp( Astat.NameBuffer[j].name,
|
||
SD_NAMES(i,0),
|
||
NCBNAMSZ) == 0))
|
||
{
|
||
break; // Found the name
|
||
}
|
||
}
|
||
|
||
if (j == Astat.AdapterStatus.name_count)
|
||
{
|
||
//
|
||
// Failed to find
|
||
//
|
||
|
||
MSG_LOG(ERROR,
|
||
"SetComputerName:DupName-failed to find NameNum\n",0);
|
||
|
||
return NERR_NoComputerName;
|
||
}
|
||
|
||
SD_NAMENUMS(i,0) = Astat.NameBuffer[j].name_num; // Save num
|
||
MSG_LOG1(TRACE,"SetComputerName: use existing name num (%d) instead\n",
|
||
Astat.NameBuffer[j].name_num);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Fail if name not on the card after the call
|
||
//
|
||
MSG_LOG(ERROR, "SetComputerName:Name Not on Card. netbios rc = 0x%x\n",res);
|
||
return NERR_NoComputerName;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SD_NAMENUMS(i,0) = ncb.ncb_num; // Save the name number
|
||
}
|
||
|
||
|
||
SD_NAMEFLAGS(i,0) = NFNEW | NFMACHNAME; // Name is new
|
||
|
||
|
||
} // End for all nets
|
||
|
||
return NERR_Success;
|
||
}
|
||
|
||
|
||
DWORD
|
||
MsgGetNumNets(VOID)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
NCB ncb;
|
||
LANA_ENUM lanaBuffer;
|
||
unsigned char nbStatus;
|
||
|
||
//
|
||
// Find the number of networks by sending an enum request via Netbios.
|
||
//
|
||
|
||
clearncb(&ncb);
|
||
ncb.ncb_command = NCBENUM; // Enumerate LANA nums (wait)
|
||
ncb.ncb_buffer = (char FAR *)&lanaBuffer;
|
||
ncb.ncb_length = sizeof(LANA_ENUM);
|
||
|
||
nbStatus = Netbios (&ncb);
|
||
if (nbStatus != NRC_GOODRET) {
|
||
MSG_LOG(ERROR, "GetNumNets:Netbios LanaEnum failed rc="
|
||
FORMAT_DWORD "\n", (DWORD) nbStatus);
|
||
return(FALSE);
|
||
}
|
||
|
||
return((DWORD)lanaBuffer.length);
|
||
|
||
#ifdef replaced
|
||
|
||
LPBYTE transportInfo;
|
||
int count=0;
|
||
USHORT loopback_found = 0;
|
||
NET_API_STATUS status;
|
||
DWORD entriesRead;
|
||
DWORD totalEntries;
|
||
|
||
//
|
||
// First try and find the networks mananged by the LAN manager
|
||
//
|
||
// NOTE: This call will fail if there are more than MSNGR_MAX_NETS
|
||
// in the machine. This is not a problem unless there are fewer
|
||
// than MSNGR_MAX_NETS that would qualify for messaging service.
|
||
// In this case, it might be argued that the messenger should start.
|
||
// For now, this is not the case. - ERICPE
|
||
//
|
||
|
||
status = NetWkstaTransportEnum (
|
||
NULL, // server name (local)
|
||
0, // level
|
||
&transportInfo, // bufptr
|
||
-1, // preferred maximum length
|
||
&entriesRead, // entries read
|
||
&totalEntries, // total entries
|
||
NULL); // resumeHandle
|
||
|
||
//
|
||
// Free up the buffer that RPC allocated for us.
|
||
//
|
||
NetApiBufferFree(transportInfo);
|
||
|
||
if (status != NERR_Success) {
|
||
MSG_LOG(ERROR,"GetNumNets:NetWkstaTransportEnum failed "
|
||
FORMAT_API_STATUS "\n", status);
|
||
return(0);
|
||
}
|
||
MSG_LOG(TRACE,"GetNumNets: numnets = " FORMAT_DWORD "\n", totalEntries);
|
||
|
||
return(totalEntries);
|
||
#endif
|
||
}
|
||
|
||
NET_API_STATUS
|
||
MsgGetBufSize (
|
||
OUT LPDWORD bufferSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine fills in the default buffer size
|
||
|
||
Arguments:
|
||
|
||
bufferSize - This is a pointer to where the buffer size is to be stored.
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - No errors, the returned bufferSize is valid.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Use the default.
|
||
//
|
||
|
||
*bufferSize = 8192;
|
||
|
||
return NERR_Success;
|
||
}
|
||
|
||
|
||
DWORD
|
||
MsgSetUpMessageFile (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Builds the name of the message file that is to be used in any
|
||
subsequent DosGetMessage calls. The name is built in the Global
|
||
variable MessageFileName.
|
||
|
||
Arguments:
|
||
|
||
none
|
||
|
||
Return Value:
|
||
|
||
NERR_Success - The operation was successful
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - Couldn't allocate memory for MessageFileName.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// allocate some space for the message file name to be built.
|
||
//
|
||
MessageFileName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, (MSGFILENAMLEN+sizeof(TCHAR)));
|
||
|
||
if (MessageFileName == NULL) {
|
||
MSG_LOG(ERROR,"[MSG]SetUpMessageFile:LocalAlloc Failure "
|
||
FORMAT_API_STATUS "\n", GetLastError());
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
|
||
//
|
||
// This message filename (netmsg.dll) is defined in lmcons.h
|
||
//
|
||
|
||
STRCPY(MessageFileName,MESSAGE_FILENAME);
|
||
|
||
return (NERR_Success);
|
||
|
||
}
|
||
|
||
STATIC VOID
|
||
MsgInitMessageBoxTitle(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Obtains the title text for the message box used to display messages.
|
||
If the title is successfully obtained from the message file, then
|
||
that title is pointed to by GlobalAllocatedMsgTitle and
|
||
GlobalMessageBoxTitle. If unsuccessful, then GlobalMessageBoxTitle
|
||
left pointing to the DefaultMessageBoxTitle.
|
||
|
||
NOTE: If successful, a buffer is allocated by this function. The
|
||
pointer stored in GlobalAllocatedMsgTitle and it should be freed when
|
||
done with this buffer.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
none
|
||
|
||
--*/
|
||
{
|
||
LPVOID hModule;
|
||
DWORD msgSize;
|
||
DWORD status=NO_ERROR;
|
||
|
||
GlobalAllocatedMsgTitle = NULL;
|
||
|
||
hModule = LoadLibrary( L"netmsg.dll");
|
||
if ( hModule == NULL) {
|
||
status = GetLastError();
|
||
MSG_LOG1(ERROR, "LoadLibrary() fails with winError = %d\n", GetLastError());
|
||
return;
|
||
}
|
||
|
||
msgSize = FormatMessageW(
|
||
FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
|
||
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||
hModule,
|
||
MTXT_MsgsvcTitle, // MessageId
|
||
0, // dwLanguageId
|
||
(LPWSTR)&GlobalAllocatedMsgTitle, // lpBuffer
|
||
0, // nSize
|
||
NULL);
|
||
|
||
if (msgSize == 0) {
|
||
status = GetLastError();
|
||
MSG_LOG1(ERROR,"Could not find MessageBox title in a message file %d\n",
|
||
status);
|
||
}
|
||
else {
|
||
GlobalMessageBoxTitle = GlobalAllocatedMsgTitle;
|
||
}
|
||
|
||
//
|
||
// Get the messages as Ansi since we'll be comparing them to an
|
||
// Ansi message that comes in from a remote Alerter service.
|
||
//
|
||
|
||
msgSize = FormatMessageA(
|
||
FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
|
||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||
hModule,
|
||
APE2_ALERTER_PRINTING_SUCCESS, // MessageId
|
||
0, // dwLanguageId
|
||
(LPSTR) &g_lpAlertSuccessMessage, // lpBuffer
|
||
0, // nSize
|
||
NULL);
|
||
|
||
if (msgSize == 0)
|
||
{
|
||
// No loss -- we just won't be able to filter print success alerts
|
||
|
||
status = GetLastError();
|
||
MSG_LOG1(ERROR,
|
||
"Could not find Alerter print success message %d\n",
|
||
status);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Trim the message to end after the "Printing Complete" line.
|
||
//
|
||
|
||
LPSTR lpTemp = g_lpAlertSuccessMessage;
|
||
|
||
g_dwAlertSuccessLen = 0;
|
||
|
||
while (*lpTemp && *lpTemp != '\r')
|
||
{
|
||
lpTemp++;
|
||
g_dwAlertSuccessLen++;
|
||
}
|
||
|
||
*lpTemp = '\0';
|
||
}
|
||
|
||
msgSize = FormatMessageA(
|
||
FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
|
||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
||
FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||
hModule,
|
||
APE2_ALERTER_PRINTING_FAILURE, // MessageId
|
||
0, // dwLanguageId
|
||
(LPSTR) &g_lpAlertFailureMessage, // lpBuffer
|
||
0, // nSize
|
||
NULL);
|
||
|
||
if (msgSize == 0)
|
||
{
|
||
// No loss -- we just won't be able to filter print success alerts
|
||
|
||
status = GetLastError();
|
||
MSG_LOG1(ERROR,
|
||
"Could not find Alerter print failure message %d\n",
|
||
status);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Trim the message to end after the "Printing Complete" line.
|
||
//
|
||
|
||
LPSTR lpTemp = g_lpAlertFailureMessage;
|
||
|
||
g_dwAlertFailureLen = 0;
|
||
|
||
while (*lpTemp && *lpTemp != '\r')
|
||
{
|
||
lpTemp++;
|
||
g_dwAlertFailureLen++;
|
||
}
|
||
|
||
*lpTemp = '\0';
|
||
}
|
||
|
||
FreeLibrary(hModule);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
MsgInitEndpoint(
|
||
PVOID Context // This passed in as context.
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to initialize our RPC server entry point. We
|
||
do this in a separate thread because we may have to wait because
|
||
RpcSS is not ready yet.
|
||
|
||
Arguments:
|
||
|
||
Context - Context parameter
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
RPC_BINDING_VECTOR *bindingVector = NULL;
|
||
DWORD status, tries;
|
||
|
||
MSG_LOG(TRACE, "MsgInitEndpoint starting in separate thread\n",0);
|
||
|
||
//
|
||
// Create endpoint for receiving RPC calls
|
||
// This is for netbiosless notifications
|
||
//
|
||
|
||
for( tries = 0; tries < 3; tries++ ) {
|
||
|
||
status = RpcServerUseProtseq(
|
||
TEXT("ncadg_ip_udp"),
|
||
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
|
||
NULL // Do we need an empty SD here?
|
||
);
|
||
|
||
if ( (status == RPC_S_OK) || (status == RPC_S_DUPLICATE_ENDPOINT) ) {
|
||
break;
|
||
}
|
||
|
||
MSG_LOG(ERROR, "RPC Init (UseProt Udp) Failed "
|
||
FORMAT_RPC_STATUS " - trying again\n", status);
|
||
Sleep( 30 * 1000 );
|
||
}
|
||
|
||
if ( (status != RPC_S_OK) && (status != RPC_S_DUPLICATE_ENDPOINT) ) {
|
||
if (status == RPC_S_SERVER_UNAVAILABLE) {
|
||
MSG_LOG( ERROR, "Failed to use UDP, check RPCSS service\n",0 );
|
||
} else {
|
||
MSG_LOG( ERROR, "Failed to use UDP, check TCP/IP\n",0 );
|
||
}
|
||
// give up
|
||
return;
|
||
}
|
||
|
||
status = RpcServerInqBindings(
|
||
&bindingVector
|
||
);
|
||
if (status != ERROR_SUCCESS) {
|
||
MSG_LOG( ERROR, "RpcServerInqBindings failed with %d\n",status );
|
||
return;
|
||
}
|
||
|
||
// Try to register in a loop in case RPCSS is not running yet
|
||
|
||
for( tries = 0; tries < 3; tries++ ) {
|
||
|
||
status = RpcEpRegister(
|
||
msgsvcsend_ServerIfHandle,
|
||
bindingVector,
|
||
NULL,
|
||
TEXT("Messenger Service")
|
||
);
|
||
|
||
if (status == RPC_S_OK) {
|
||
break;
|
||
}
|
||
|
||
MSG_LOG( ERROR, "Msgr: RpcEpRegister failed with %d - trying again\n", status );
|
||
|
||
RpcEpUnregister( msgsvcsend_ServerIfHandle,
|
||
bindingVector,
|
||
NULL );
|
||
// ignore error
|
||
|
||
Sleep( 10 * 1000 );
|
||
}
|
||
|
||
RpcBindingVectorFree( &bindingVector );
|
||
|
||
if (status != RPC_S_OK) {
|
||
// give up
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Register RPC interface
|
||
//
|
||
|
||
status = RpcServerRegisterIf(
|
||
msgsvcsend_ServerIfHandle, // interface to register
|
||
NULL, // MgrTypeUuid
|
||
NULL); // MgrEpv; null means use default
|
||
|
||
if (status != RPC_S_OK) {
|
||
MSG_LOG(ERROR, "RPC Init (RegIf MsgSvcSend) Failed "
|
||
FORMAT_RPC_STATUS "\n", status);
|
||
return;
|
||
}
|
||
|
||
MSG_LOG(TRACE, "MsgInitEndpoint final status %d\n", status);
|
||
|
||
return;
|
||
}
|