You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1613 lines
41 KiB
1613 lines
41 KiB
/*++
|
|
|
|
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))
|
|
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
MSG_LOG(TRACE, "Calling MsgSetUpMessageFile\n",0);
|
|
|
|
status = MsgSetUpMessageFile();
|
|
|
|
if (status != NO_ERROR)
|
|
{
|
|
MSG_LOG1(ERROR, "MsgSetUpMessageFile Failure\n", status);
|
|
|
|
return (MsgBeginForcedShutdown(
|
|
PENDING,
|
|
status));
|
|
}
|
|
|
|
//
|
|
// 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_MESLOG() = 0; // Message logging disabled
|
|
|
|
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;
|
|
}
|