Windows NT 4.0 source code leak
 
 
 
 
 
 

1251 lines
33 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:
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 <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 <rpcutil.h> // NetpStartRpcServer
#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 "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
//
// Defines
//
// The following is the size of the first offset area in the shared buffer.
// The size of this area is dependent on a runtime variable - the number
// of nets. The BOOKKEEPING_SIZE is calculated from the SD offsets
// described in msrv.h.
//
#define BOOKKEEPING_SIZE(n) (SDNAMEFLAGS + \
(n * NCBMAX) + \
(n * NCBMAX) + \
(n * NCBMAX * (NCBNAMSZ+4)) + \
(n * NCBMAX * (NCBNAMSZ+4)) + \
(n * NCBMAX * sizeof(DWORD)))
#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
//
STATIC VOID
MsgBufferInit(
IN USHORT buflen
);
NET_API_STATUS
MsgInitSharedData(
DWORD NumNets
);
STATIC BOOL
MsgSetComputerName(
DWORD NumNets
);
STATIC DWORD
MsgGetNumNets(VOID);
NET_API_STATUS
MsgGetBufSize (
IN DWORD argc,
IN LPTSTR *argv,
OUT LPDWORD bufferSize,
OUT LPTSTR *lastarg
);
DWORD
MsgSetUpMessageFile(VOID);
STATIC VOID
MsgInitMessageBoxTitle(
VOID
);
NET_API_STATUS
MsgInitializeMsgr(
DWORD argc,
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;
LPTSTR lastarg;
DWORD NumNets;
DWORD hint_count = 0;
DWORD msgrState;
DWORD bufLen;
//
// Initialize the Time format. Since no users are logged on, we use
// the information for the default user.
//
InitializeCriticalSection(&TimeFormatCritSec);
NetpGetTimeFormat(&GlobalTimeFormat);
//
// Initialize the Thread Manager. This initializes some locks used
// on the Thread and Status databases.
//
MsgThreadManagerInit();
//
// 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 NetServiceRegisterCtrlHandler\n",0);
if ((MsgrStatusHandle = RegisterServiceCtrlHandler(
SERVICE_MESSENGER,
MsgrCtrlHandler
)) == (SERVICE_STATUS_HANDLE) NULL) {
status = GetLastError();
MSG_LOG(ERROR,
"FAILURE: RegisterServiceCtrlHandler 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);
}
//
// 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);
}
//
// Check command line for buffer size. If none given,
// use the default buffer size.
// lastarg is a pointer to the argument string that was found
// to be bad.
//
status = MsgGetBufSize ( argc, argv, &bufferSize, &lastarg );
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));
MSG_LOG(TRACE, "Calling MsgGetNumNets\n",0);
NumNets = MsgGetNumNets();
if ( NumNets == 0 ) {
MSG_LOG(ERROR, "No nets to connect to\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
NERR_NoNetworkResource));
}
// ***** INSTALLATION HINT *****
msgrState = MsgStatusUpdate(STARTING);
if (msgrState != STARTING) {
return(msgrState);
}
//
// Initialize shared memory areas.
//
MSG_LOG(TRACE, "Calling MsgInitSharedData\n",0);
status = MsgInitSharedData(NumNets);
if (status != NERR_Success) {
MSG_LOG(ERROR, "InitSharedData Failure\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
NERR_NoRoom));
}
// ***** INSTALLATION HINT *****
msgrState = MsgStatusUpdate(STARTING);
if (msgrState != STARTING) {
return(msgrState);
}
//*****************************************
//
// 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);
if ( MsgInitSupportSeg() )
{
LocalFree (dataPtr); // Free shared data
MSG_LOG(ERROR, "InitSupportSeg Failed\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
NERR_NoRoom));
}
//
// Now initialize global net bios handles & lana nums.
//
MSG_LOG(TRACE, "Calling MsgInit_NetBios\n",0);
if (!MsgInit_NetBios())
{
MsgFreeSupportSeg();
LocalFree (dataPtr); // Free shared data
MSG_LOG(ERROR, "Init_NetBios Failed\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
ERROR_OPEN_FAILED));
}
//
// Get the wake up semaphore handles.
//
MSG_LOG(TRACE, "Calling MsgCreateWakeupSems\n",0);
if (!MsgCreateWakeupSems(SD_NUMNETS())) {
MsgCloseWakeupSems(); // Close the ones that have been created
MsgFreeSupportSeg();
LocalFree (dataPtr); // Free shared data
MSG_LOG(ERROR, "CreateWakeupSems Failed\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
NERR_NoRoom));
}
//
// 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
//
MsgCloseWakeupSems();
MsgFreeSupportSeg();
LocalFree (dataPtr); // Free shared data
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);
//
// 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);
if(MsgSetComputerName(SD_NUMNETS()) != 0) {
MsgCloseWakeupSems();
MsgFreeSupportSeg();
LocalFree (dataPtr); // Free shared data
MSG_LOG(ERROR, "SetComputerName Failed\n",0);
return (MsgBeginForcedShutdown(
IMMEDIATE,
NERR_NoComputerName));
}
//
// Change from IMMEDIATE Shutdowns to PENDING shutdowns.
// This is because at this point we have names on the adapters
// to clean up.
//
//
// The NCBs and NCB buffers belong in a seperate segment so
// DosAlloc the segment here.
//
MSG_LOG(TRACE, "Calling MsgInitNCBSeg\n",0);
if( MsgInitNCBSeg() )
{
MSG_LOG(ERROR, "InitNCBSeg Failed\n",0);
return (MsgBeginForcedShutdown(
PENDING,
NERR_NoRoom));
}
//
// Allocate the the Service segment.
//
MSG_LOG(TRACE, "Calling MsgInitServiceSeg\n",0);
if ( MsgInitServiceSeg() )
{
MSG_LOG(ERROR, "InitServiceSeg Failed\n",0);
return (MsgBeginForcedShutdown(
PENDING,
NERR_NoRoom));
}
//
// 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
// SD_NUMNETS() is the position in the wakeupSem array for the
// mailslot event.
//
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
//
if (!MsgDisplayInit()) {
MSG_LOG(ERROR, "Could not initialize the display functions\n",0);
return (MsgBeginForcedShutdown(
PENDING,
NERR_NoRoom)); // BUGBUG: Make this meaningful!
}
//
// 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();
//
// 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)
//
MsgAddUserNames();
//
// 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(
MsgsvcGlobalData->SvcsRpcPipeName,
msgsvc_ServerIfHandle);
if (status != RPC_S_OK) {
MSG_LOG(ERROR, "RPC Initialization 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));
}
STATIC VOID
MsgBufferInit(
IN USHORT buflen // Buffer length
)
/*++
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:
buflen - buffer length
Return Value:
none
--*/
{
LPHEAPHDR hp; // Heap block pointer
hp = (LPHEAPHDR) SD_BUFFER(); // Get the address of buffer
HP_SIZE(*hp) = buflen; // Set the size of the first block
HP_FLAG(*hp) = 0; // Unallocated
SD_BUFLEN() = buflen; // 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;
//
// Create and initialize shared data area.
//
size = bufferSize + BOOKKEEPING_SIZE(NumNets);
dataPtr = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, size);
if (dataPtr == NULL) {
MSG_LOG(ERROR,"[MSG]InitSharedData:LocalAlloc Failure "
FORMAT_API_STATUS "\n", GetLastError());
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Initialize the shared data lock. The shared data is shared between
// the API threads and the worker threads.
//
MsgDatabaseLock(MSG_INITIALIZE,"InitSharedData");
//
// 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; ++i) {
//
// Mark entries as free
//
SD_NAMEFLAGS(j,i) = NFDEL;
}
}
//
// Initialize the message buffer
//
MsgBufferInit((USHORT)bufferSize);
//
// NT NOTE:
// Skip Initializing the Support Set and Wakeup sems.
// Init_msrv will end up doing that.
//
return(NERR_Success);
}
STATIC BOOL
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;
NCB ncb; /* Network Control Block */
// ASTAT adapterStatus; /* Adapter status buffer */
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",net_lana_num[i]);
status = MsgsvcGlobalData->NetBiosReset(net_lana_num[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_LOG(ERROR,"SetComputerName: Format name failed!",0);
return ((BOOL)1);
}
ncb.ncb_command = NCBADDNAME; // Add name (wait)
ncb.ncb_lana_num = net_lana_num[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);
MSG_LOG1(TRACE,"MsgSetComputerName: Adding ComputerName to lana #%d\n",
net_lana_num[i]);
if( (res = Msgsendncb( &ncb, i)) != 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
//
//Close_NetBios();
MSG_LOG1(ERROR, "SetComputerName:sendncb (ASTAT) failed 0x%x\n",res);
return((BOOL)1);
}
//
// 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
//
//Close_NetBios();
MSG_LOG(ERROR,
"SetComputerName:DupName-failed to find NameNum\n",0);
return((BOOL)1);
}
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
//
// Close_NetBios();
MSG_LOG(ERROR, "SetComputerName:Name Not on Card. netbios rc = 0x%x\n",res);
return((BOOL)1);
}
}
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
// Close_NetBios();
return((BOOL)0); /* Success */
}
STATIC 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 (
IN DWORD argc,
IN LPTSTR *argv,
OUT LPDWORD bufferSize,
OUT LPTSTR *lastarg
)
/*++
Routine Description:
This routine parses through the command line arguments in search of
the buffer size. This is the only valid argument and is of the
following form:
/sizmessbuf:[bytes]
Where bytes is the number of bytes for the message buffer defining
the size of messages the messenger can receive. The range is
512-62000. The default is 4096.
If a passed in sizmessbuf is an illegal value, an error will be returned.
Arguments that are not switches (prefixed by "/") are ignored. Invalid
switches cause a failure, and the text of the bad switch is passed back
in lastarg.
Arguments:
argc - This is the count of the number of arguments that is passed in.
argv - This is a pointer to an array of pointers to arguments.
bufferSize - This is a pointer to where the buffer size is to be stored.
If a bufferSize was not found on the command line, the default
is placed in here.
lastarg - This is a pointer to a location where a pointer to a
switch argument that was in error is to be placed.
Return Value:
NERR_Success - No errors, the returned bufferSize is valid and
lastarg does not contain any error information.
ERROR_INVALID_PARAMETER - The command line switch is not a valid one for
this service.
--*/
{
DWORD switchNameSize;
BOOL fromCmdLine = FALSE;
DWORD i;
LPTSTR pSizeString;
//
// Check the passed in command args.
//
*lastarg = NULL;
*bufferSize = 0;
for (i=0; i<argc; i++) {
if ( *argv[i] == '/') {
switchNameSize = STRLEN(LMI_PARM_M_SIZMESSBUF);
if (STRNICMP (argv[i], LMI_PARM_M_SIZMESSBUF, switchNameSize) == 0) {
//
// We received a valid command line switch - see if it is
// a duplicate of one we already have.
//
if (fromCmdLine = TRUE) {
*lastarg = argv[i];
return( ERROR_INVALID_PARAMETER );
}
pSizeString = argv[i] + switchNameSize;
*bufferSize = ATOL(pSizeString);
fromCmdLine = TRUE;
}
else {
//
// We received an invalid command line switch
//
MSG_LOG(ERROR,"MsgGetBufSize:Invalid command line switch\n",0);
*lastarg = argv[i];
return( ERROR_INVALID_PARAMETER );
}
}
else {
//
// do nothing - skip things that don't look like switches
//
}
}
if (!fromCmdLine) {
//
// Attempt to get the buffer size from the configuration database.
// BUGBUG! do this sometime.
// Actually, it would be nice to do away with this config
// baggage. Leave it fixed size.
//
//
// If it isn't in the database, use the default.
//
*bufferSize = 8192;
}
if ((*bufferSize < 512) || (*bufferSize > 62000)) {
MSG_LOG(ERROR,"MsgGetBufSize:BufferSize out of range\n",0);
return( ERROR_INVALID_PARAMETER);
}
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, and is constructed using the following
template.
lanroot\netprog\net.msg
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);
}
//
// BUGBUG: The following function finds the LAN root directory and
// builds a filename with that. What will we do in NT?
//
#ifdef later
result = NetIMakeLMFileName ( MESSAGE_FILE, MessageFileName,
PATHLEN+1);
if ( result ) {
MessageFileName[0] = '\0';
}
#endif
//
// Temporary fix. Use a fixed filename and use the temporary
// DosGetMessage (until we get a win32 equivalent).
// This message filename 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;
}
FreeLibrary(hModule);
return;
}