487 lines
12 KiB
C
487 lines
12 KiB
C
//****************************************************************************
|
|
//
|
|
// Module: UNIMDM
|
|
// File: SLOT.C
|
|
//
|
|
// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved
|
|
//
|
|
// Revision History
|
|
//
|
|
//
|
|
// 3/25/96 JosephJ Created
|
|
//
|
|
//
|
|
// Description: Implements the unimodem TSP notification mechanism:
|
|
// The lower level (notifXXXX) APIs
|
|
//
|
|
//****************************************************************************
|
|
|
|
#define UNICODE
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include "slot.h"
|
|
#include "sec.h"
|
|
|
|
#define T(_str) TEXT(_str)
|
|
|
|
#define ASSERT(_c) \
|
|
((_c) ? 0: DPRINTF2("Assertion failed in %s:%d\n", __FILE__, __LINE__))
|
|
#define DPRINTF(_fmt) printf(_fmt)
|
|
#define DPRINTF1(_fmt,_arg) printf(_fmt,_arg)
|
|
#define DPRINTF2(_fmt,_arg,_arg2) printf(_fmt,_arg,_arg2)
|
|
#define DPRINTF3(_fmt,_arg,_arg2,_arg3) printf(_fmt,_arg,_arg2,_arg3)
|
|
|
|
#define fNOTIF_STATE_DEINIT 0
|
|
#define fNOTIF_STATE_INIT_SERVER 1
|
|
#define fNOTIF_STATE_INIT_CLIENT 2
|
|
|
|
#define IS_SERVER(_pns) ((_pns)->dwState==fNOTIF_STATE_INIT_SERVER)
|
|
#define IS_CLIENT(_pns) ((_pns)->dwState==fNOTIF_STATE_INIT_CLIENT)
|
|
|
|
|
|
// The following help define the fully-qualified mailslot and semaphore names.
|
|
#define dwNOTIFSTATE_SIG (0x53CB31A0L)
|
|
#define FULLNAME_TEMPLATE T("--.-mailslot-%08lx-%s")
|
|
|
|
// Keeps the state of a notification (either client or server).
|
|
// It is cast to a DWORD to form the handle returned by notifCreate()
|
|
typedef struct
|
|
{
|
|
DWORD dwSig; // should be dwNOTIFSTATE_SIG when inited
|
|
HANDLE hSem;
|
|
HANDLE hSlot;
|
|
DWORD dwState;
|
|
DWORD dwcbMax;
|
|
|
|
} NOTIFICATION_STATE, *PNOTIFICATION_STATE;
|
|
|
|
DWORD inotif_server_create(PNOTIFICATION_STATE pns, LPTSTR lptsz,
|
|
DWORD dwMaxSize,
|
|
DWORD dwMaxPending);
|
|
DWORD inotif_client_open(PNOTIFICATION_STATE pns, LPTSTR lptsz);
|
|
PNOTIFICATION_STATE inotif_getstate(HNOTIFICATION hn);
|
|
|
|
|
|
//****************************************************************************
|
|
// Function: Creates a notification object -- either as server or client.
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
HNOTIFICATION notifCreate(
|
|
BOOL fServer, // TRUE ==> Server
|
|
LPCTSTR lptszName, // Name to associate with this object
|
|
DWORD dwMaxSize, // Max size of frames written/read
|
|
// (Ignored if (!fServer))
|
|
DWORD dwMaxPending // Max number of notification frames allowed
|
|
// to be pending. (Ignored if (!fServer))
|
|
)
|
|
{
|
|
PNOTIFICATION_STATE pns=NULL;
|
|
HNOTIFICATION hn=0;
|
|
TCHAR rgtchTmp[MAX_NOTIFICATION_NAME_SIZE+23];
|
|
UINT u = lstrlen(lptszName);
|
|
DWORD dwErr=0;
|
|
|
|
// Format of semaphore name is --.-mailslot-sig-name
|
|
// Example: "--.-mailslot-8cb45651-unimodem"
|
|
// To create the equivalent mailslot, we run through and change
|
|
// all '-' to '\'s (if the name containts '-', they will get converted --
|
|
// big deal.)
|
|
if ((u+23)>(sizeof(rgtchTmp)/sizeof(TCHAR))) // 13(prefix)+ 9(sig-) +1(null)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto end;
|
|
}
|
|
|
|
pns=LocalAlloc(LPTR, sizeof(*pns));
|
|
if (!pns) goto end;
|
|
|
|
wsprintf(rgtchTmp,FULLNAME_TEMPLATE,
|
|
(unsigned long) dwNOTIFSTATE_SIG,
|
|
lptszName);
|
|
|
|
DPRINTF1("Semaphore name = [%s]\n", rgtchTmp);
|
|
|
|
if (fServer) dwErr = inotif_server_create(pns, rgtchTmp,
|
|
dwMaxSize, dwMaxPending);
|
|
else dwErr = inotif_client_open(pns, rgtchTmp);
|
|
|
|
if (dwErr) goto end;
|
|
pns->dwSig=dwNOTIFSTATE_SIG;
|
|
hn = (HNOTIFICATION)pns;
|
|
|
|
end:
|
|
if (!hn)
|
|
{
|
|
if (!dwErr) dwErr=GetLastError();
|
|
if (pns) LocalFree(pns);
|
|
SetLastError(dwErr);
|
|
}
|
|
return hn;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// Function: Free a notification object
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
void notifFree(HNOTIFICATION hn)
|
|
{
|
|
PNOTIFICATION_STATE pns = inotif_getstate(hn);
|
|
if (hn)
|
|
{
|
|
pns->dwSig=0;
|
|
CloseHandle(pns->hSem); pns->hSem=0;
|
|
CloseHandle(pns->hSlot); pns->hSlot=0;
|
|
LocalFree(pns);
|
|
}
|
|
}
|
|
|
|
//****************************************************************************
|
|
// Function: Retrieve the synchronization object handle accociated with
|
|
// the notiication object. NOTE: This handle is valid until
|
|
// the notification object is alive. It must NOT be deleted
|
|
// externally. Must be a server object.
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
HANDLE notifGetObj(HNOTIFICATION hn)
|
|
{
|
|
PNOTIFICATION_STATE pns = inotif_getstate(hn);
|
|
if (pns && IS_SERVER(pns))
|
|
{
|
|
return pns->hSem;
|
|
}
|
|
else if (pns)
|
|
{
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//****************************************************************************
|
|
// Function: Retrieves the max allowable size of the frame (server only)
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
DWORD notifGetMaxSize(HNOTIFICATION hn)
|
|
{
|
|
PNOTIFICATION_STATE pns = inotif_getstate(hn);
|
|
if (pns && IS_SERVER(pns))
|
|
{
|
|
return pns->dwcbMax;
|
|
}
|
|
else
|
|
{
|
|
if (pns)
|
|
{
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// Function: (Server only) Reads a notification msg, if any. Does not block.
|
|
// A return value of FALSE and a GetLastError value of ERROR_NO_DATA
|
|
// indicates that no frame was available..
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
BOOL notifReadMsg(HNOTIFICATION hn,
|
|
LPBYTE lpb,
|
|
DWORD dwcbMax,
|
|
LPDWORD lpdwRead)
|
|
{
|
|
PNOTIFICATION_STATE pns = inotif_getstate(hn);
|
|
BOOL fRet=FALSE;
|
|
*lpdwRead=0;
|
|
|
|
if (pns)
|
|
{
|
|
DWORD dwRead=0;
|
|
|
|
if(!IS_SERVER(pns))
|
|
{
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
goto end;
|
|
}
|
|
|
|
fRet = ReadFile(pns->hSlot, lpb, dwcbMax, lpdwRead, NULL);
|
|
|
|
if (!fRet)
|
|
{
|
|
DPRINTF("ReadFile failed!\n");
|
|
goto end;
|
|
}
|
|
|
|
DPRINTF("Success!\n");
|
|
fRet=TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
end:
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// Function: Returns the size of the next frame in the queue. Returns TRUE
|
|
// even if there is no data in the queue -- in this case, *lpdwcb
|
|
// is set to 0. Returns FALSE if there is some other error.
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
BOOL notifGetNextMsgSize(HNOTIFICATION hn, LPDWORD lpdwcb)
|
|
{
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// Function: (Client side). Write a notification msg.
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
BOOL notifWriteMsg(HNOTIFICATION hn, LPBYTE lpb, DWORD dwcb)
|
|
{
|
|
PNOTIFICATION_STATE pns = inotif_getstate(hn);
|
|
BOOL fRet=FALSE;
|
|
|
|
if (pns)
|
|
{
|
|
DWORD dwWritten=0;
|
|
|
|
if(!IS_CLIENT(pns))
|
|
{
|
|
SetLastError(ERROR_NOT_SUPPORTED);
|
|
goto end;
|
|
}
|
|
|
|
fRet = WriteFile(pns->hSlot, lpb, dwcb, &dwWritten, NULL);
|
|
if (fRet)
|
|
{
|
|
fRet=ReleaseSemaphore(pns->hSem,1,NULL);
|
|
if (!fRet)
|
|
{
|
|
DPRINTF("ReleaseSemaphore failed!\n");
|
|
goto end;
|
|
}
|
|
}
|
|
if (!fRet || dwWritten!=dwcb)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
DPRINTF3("WriteFile failed. fRet=%lu; dwWritten=%lu; Err=%lu\n",
|
|
fRet, dwcb, dwErr);
|
|
SetLastError(dwErr);
|
|
goto end;
|
|
}
|
|
DPRINTF("notifWriteFrame: success!\n");
|
|
fRet=TRUE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
end:
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// Function: (internal) create the notif object -- server side.
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
DWORD inotif_server_create(PNOTIFICATION_STATE pns, LPTSTR lptsz, DWORD dwMaxSize,
|
|
DWORD dwMaxPending)
|
|
{
|
|
DWORD dwErr=ERROR_INVALID_PARAMETER;
|
|
TCHAR c, *pc = lptsz;
|
|
SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
|
|
SECURITY_ATTRIBUTES sa, *psa=NULL;
|
|
|
|
PSECURITY_DESCRIPTOR pSD = AllocateSecurityDescriptor (
|
|
&siaWorld,
|
|
SECURITY_WORLD_RID,
|
|
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL
|
|
| SEMAPHORE_ALL_ACCESS
|
|
| SEMAPHORE_MODIFY_STATE
|
|
| GENERIC_READ
|
|
| GENERIC_WRITE
|
|
,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (!pSD)
|
|
{
|
|
DPRINTF1("WARNING:AllocateSecurityDescriptor(-) returns error 0x%lx\n",
|
|
GetLastError());
|
|
}
|
|
else
|
|
{
|
|
DPRINTF("AllocateSecurityDescriptor(-) returns SUCCESS\n");
|
|
sa.nLength = sizeof(sa);
|
|
sa.bInheritHandle=FALSE;
|
|
sa.lpSecurityDescriptor = pSD;
|
|
psa = &sa;
|
|
|
|
}
|
|
|
|
|
|
// Create mailslot name -- make sure there are no '\'s
|
|
while(c=*pc++) {if (c=='\\') pc[-1]='-';}
|
|
DPRINTF1("Semaphore name = [%s]\n", lptsz);
|
|
|
|
// Create Semaphore
|
|
{
|
|
pns->hSem=CreateSemaphore(psa, 0, dwMaxPending, lptsz);
|
|
if (pns->hSem && (dwErr=(GetLastError()==ERROR_ALREADY_EXISTS)))
|
|
{
|
|
DPRINTF1("Semaphore %s already exists!\n", lptsz);
|
|
CloseHandle(pns->hSem);
|
|
pns->hSem=NULL;
|
|
}
|
|
if (!pns->hSem) goto end_fail;
|
|
}
|
|
|
|
// Create mailslot name
|
|
pc = lptsz;
|
|
while(c=*pc++) {if (c=='-') pc[-1]='\\';}
|
|
|
|
DPRINTF1("Mailslot name = [%s]\n", lptsz);
|
|
|
|
// CreateMailSlot -- specify size, zero-delay
|
|
pns->hSlot=CreateMailslot(lptsz, dwMaxSize, 0, psa);
|
|
if (!pns->hSlot)
|
|
{
|
|
dwErr = GetLastError();
|
|
CloseHandle(pns->hSem); pns->hSem=0;
|
|
goto end_fail;
|
|
}
|
|
|
|
DPRINTF("Mailslot created!\n");
|
|
|
|
// set state and maxsize
|
|
pns->dwState=fNOTIF_STATE_INIT_SERVER;
|
|
pns->dwcbMax=dwMaxSize;
|
|
dwErr=0;
|
|
goto end;
|
|
|
|
end_fail:
|
|
if (!dwErr) dwErr=GetLastError();
|
|
if (!dwErr) dwErr=ERROR_INVALID_PARAMETER;
|
|
|
|
end:
|
|
if (pSD) {FreeSecurityDescriptor(pSD);}
|
|
return dwErr;
|
|
}
|
|
|
|
|
|
//****************************************************************************
|
|
// Function: (internal) create the notif object -- client side.
|
|
// The server must be already up and running, or we will
|
|
// fail.
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
DWORD inotif_client_open(PNOTIFICATION_STATE pns, LPTSTR lptsz)
|
|
{
|
|
DWORD dwErr=ERROR_INVALID_PARAMETER;
|
|
TCHAR c, *pc = lptsz;
|
|
|
|
// Create mailslot name -- convert '-' to '\';
|
|
while(c=*pc++) {if (c=='-') pc[-1]='\\';}
|
|
DPRINTF1("Mailslot name = [%s]\n", lptsz);
|
|
|
|
// Open mailslot ...
|
|
pns->hSlot=CreateFile(
|
|
lptsz,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if (!pns->hSlot)
|
|
{
|
|
DPRINTF("Couldn't open mailslot for writing\n");
|
|
goto end_fail;
|
|
}
|
|
|
|
// Create Semaphore name -- convert '\' to '-';
|
|
pc=lptsz;
|
|
while(c=*pc++) {if (c=='\\') pc[-1]='-';}
|
|
DPRINTF1("Sempahore name = [%s]\n", lptsz);
|
|
|
|
pns->hSem=OpenSemaphore(SEMAPHORE_MODIFY_STATE, FALSE, lptsz);
|
|
//pns->hSem=OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, lptsz);
|
|
if (!pns->hSem) {
|
|
DPRINTF("Could not open semaphore\n");
|
|
dwErr=GetLastError();
|
|
CloseHandle(pns->hSlot); pns->hSlot=0;
|
|
goto end_fail;
|
|
}
|
|
|
|
// set state and maxsize
|
|
pns->dwState=fNOTIF_STATE_INIT_CLIENT;
|
|
pns->dwcbMax=0; // Apparently you can't get the max size of the mailslot.
|
|
dwErr=0;
|
|
goto end;
|
|
|
|
end_fail:
|
|
if (!dwErr) dwErr=GetLastError();
|
|
if (!dwErr) dwErr=ERROR_INVALID_PARAMETER;
|
|
|
|
end:
|
|
return dwErr;
|
|
}
|
|
|
|
//****************************************************************************
|
|
// Function: (internal) validates and converts a handle to a ptr to state.
|
|
//
|
|
// History:
|
|
// 3/25/96 JosephJ Created
|
|
//****************************************************************************/
|
|
PNOTIFICATION_STATE inotif_getstate(HNOTIFICATION hn)
|
|
{
|
|
if (hn)
|
|
{
|
|
PNOTIFICATION_STATE pns= (PNOTIFICATION_STATE) hn;
|
|
if (pns->dwSig!=dwNOTIFSTATE_SIG)
|
|
{
|
|
DPRINTF1("Bad hotification handle 0x%lu\n", hn);
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
return pns;
|
|
}
|
|
return NULL;
|
|
}
|