📄 sdpdb.cpp
字号:
status = SdpTreeFromStream(pStream, streamSize, NULL, &tree, TRUE);
if (!NT_SUCCESS(status)) {
return status;
}
ASSERT(tree != NULL);
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
// WinCE has added ability to update record handle (pRecord != NULL)
ULONG recordHandle = GetNextRecordHandle();
#else
ULONG recordHandle = pRecordOriginal ? pRecordOriginal->recordHandle : GetNextRecordHandle();
#endif
uint32 = SdpCreateNodeUInt32(recordHandle);
if (uint32 == NULL) {
//
// see if we can roll back the increment. This will not recover the
// "acquired" recordHandle if another caller has tried to add a record in
// between our call for GetNextRecordHandle and here
//
status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
SdpAddAttributeToTree(tree, SDP_ATTRIB_RECORD_HANDLE, uint32);
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
//
// Only automatically add the public browse group list if the user does NOT
// disable this feature.
//
if ((fOptions & SERVICE_OPTION_NO_PUBLIC_BROWSE) == 0 &&
(fOptions & SERVICE_OPTION_DO_NOT_PUBLISH) == 0) {
pCont = NULL;
status = SdpFindAttributeInTree(tree,
SDP_ATTRIB_BROWSE_GROUP_LIST,
&pCont);
if (NT_SUCCESS(status)) {
//
// Group was present
//
/* do nothing */;
}
else {
PSDP_NODE pSeq, pUuid16;
ASSERT(pCont == NULL);
//
// Group was not present, add it
//
// Keep status as a failure code until we successfully add the
// attribute
//
pSeq = SdpCreateNodeSequence();
if (pSeq) {
pUuid16 =
SdpCreateNodeUUID16(PublicBrowseGroupServiceClassID_UUID16);
if (pUuid16) {
//
// Add in the node and set our status to success
//
SdpAppendNodeToContainerNode(pSeq, pUuid16);
SdpAddAttributeToTree(tree,
SDP_ATTRIB_BROWSE_GROUP_LIST,
pSeq);
status = STATUS_SUCCESS;
}
else {
SdpFreeOrphanedNode(pSeq);
}
}
}
}
if (!NT_SUCCESS(status)) {
goto Done;
}
#endif // UNDER_CE
//
// See if there is a protocol list. Some records, such as the BrowseGroupInfo
// will not have any protocols associated with them
//
status = SdpFindAttributeInTree(tree, SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST, &pCont);
if (NT_SUCCESS(status)) {
ASSERT(pCont != NULL);
if (pCont->hdr.Type == SDP_TYPE_ALTERNATIVE) {
count = 0;
PLIST_ENTRY entry = pCont->u.alternative.Link.Flink;
for ( ; entry != &pCont->u.alternative.Link; entry = entry->Flink, count++)
;
ASSERT(count != 0);
}
else {
ASSERT(pCont->hdr.Type == SDP_TYPE_SEQUENCE);
count = 1;
}
}
else {
status = STATUS_SUCCESS;
count = 0;
}
size = sizeof(ServiceRecord);
if (count > 1) {
size += sizeof(PSM_PROTOCOL_PAIR) * (count - 1);
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
pv = ExAllocatePoolWithTag(NonPagedPool, size, SDP_TAG);
if (pv) {
pRecord = new(pv) ServiceRecord;
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
if (count && pCont) {
//
// This will also initialize the psmList
//
status = SdpValidateProtocolContainer(pCont, &pRecord->psmList);
if (!NT_SUCCESS(status)) {
goto Done;
}
}
#else
pRecord = new ServiceRecord();
if (!pRecord) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto Done;
}
#endif
//
// Get the service class ID. This is a sequence of UUIDs, where the 1st
// item in the list is the most specific. SdpVerifyServiceRecord has made
// sure that this attrib exists
//
SdpFindAttributeInTree(tree, SDP_ATTRIB_CLASS_ID_LIST, &pCont);
ASSERT(pCont != NULL);
ASSERT(pCont->hdr.Type == SDP_TYPE_SEQUENCE);
ASSERT(!IsListEmpty(&pCont->u.sequence.Link));
//
// Store the UUID as a 128 bit UUID to make comparison easier
//
SdpNormalizeUuid(
CONTAINING_RECORD(pCont->u.sequence.Link.Flink, SDP_NODE, hdr.Link),
&pRecord->serviceClass);
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
serviceClass = pRecord->serviceClass;
//
// Allow each validator to validate stream
//
status = ValidateRecordExternal(pStream,
streamSize,
tree,
&pRecord->psmList,
RVF_ADD_RECORD,
&pRecord->serviceClass
);
#endif // UNDER_CE
if (!NT_SUCCESS(status)) {
goto Done;
}
status = SdpStreamFromTree(tree, &pNewStream, &newStreamSize);
if (!NT_SUCCESS(status)) {
goto Done;
}
//
// don't know if this chunk of code is necessary or not
//
#if 0
//
// Revalidate in case one of the validators failed
//
status = SdpIsStreamRecord(pNewStream, newStreamSize);
if (!NT_SUCCESS(status)) {
goto Done;
}
//
// Make sure all of the universal attributes have the correct syntax and
// that all of the attributes we require locally are present
//
err = 0xFFFF;
status = SdpVerifyServiceRecord(pNewStream,
newStreamSize,
VERIFY_CHECK_MANDATORY_LOCAL,
&err);
if (!NT_SUCCESS(status)) {
goto Done;
}
#endif
m_ServiceRecordList.Lock();
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
ProtMux *ppm;
ULONG i; // ,j
protIsMux = FALSE;
for (i = 0; i < pRecord->psmList.count; i++) {
if ((protIsMux = IsProtocolMuxed(pRecord->psmList.list[i].protocol))) {
break;
}
}
if (protIsMux == FALSE) {
//
// Make sure the protocol isn't duplicated across any other record
//
ServiceRecord *psr;
for (psr = m_ServiceRecordList.GetHead();
psr != NULL;
psr = m_ServiceRecordList.GetNext(psr)) {
for (i = 0; i < psr->psmList.count; i++) {
for (j = 0; j < pRecord->psmList.count; j++) {
//
// We only care about potential conflicts on the PSM
//
if (psr->psmList.list[i].psm == pRecord->psmList.list[j].psm) {
if (IsEqualUuid(&psr->psmList.list[i].protocol,
&pRecord->psmList.list[j].protocol)) {
//
// protocol is being muxed w/out a registered mux handler
//
status = STATUS_DEVICE_PROTOCOL_ERROR;
}
else {
//
// different protocols on top of the same PSM
//
status = STATUS_NO_MATCH;
}
break;
}
}
if (!NT_SUCCESS(status)) {
break;
}
}
if (!NT_SUCCESS(status)) {
break;
}
}
}
#endif // UNDER_CE
if (NT_SUCCESS(status)) {
//
// Make sure the psmList in this record is either unique, or we have a
// registered multiplexor for it
//
#if defined (UNDER_CE) || defined (WINCE_EMULATION)
if (pRecordOriginal) {
if (pRecordOriginal->pStream)
SdpFreePool(pRecordOriginal->pStream);
memcpy(&pRecordOriginal->serviceClass,&pRecord->serviceClass,sizeof(GUID));
ASSERT(pRecordOriginal == pRecordOriginal->handle);
ASSERT(pRecordOriginal->recordHandle == recordHandle);
delete pRecord;
pRecord = pRecordOriginal;
}
pRecord->recordHandle = recordHandle;
pRecord->streamSize = newStreamSize;
pRecord->pStream = pNewStream;
pRecord->psmList.count = 0;
AlterDatabaseState();
if (!pRecordOriginal)
m_ServiceRecordList.AddTail(pRecord);
#if defined (UNDER_CE)
*pHandle = pRecord->handle = (HANDLE) pRecord;
#endif
#else // UNDER_CE
pRecord->recordHandle = recordHandle;
pRecord->streamSize = newStreamSize;
pRecord->fService = fService;
pRecord->fOptions = fOptions;
pRecord->pFileObject = stack->FileObject;
pRecord->pStream = pNewStream;
pRecord->handle = (HANDLE) pRecord;
AlterDatabaseState();
m_ServiceRecordList.AddTail(pRecord);
#endif // UNDER_CE
}
m_ServiceRecordList.Unlock();
Done:
if (tree) {
SdpFreeTree(tree);
}
if (NT_SUCCESS(status)) {
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
FireWmiEvent(*pHandle, SdpDatabaseEventNewRecord);
Globals.pSecDB->AddService(serviceClass, fSecurity);
*pfService = fService;
#endif
}
else {
if (pRecord) {
delete pRecord;
}
if (pNewStream) {
SdpFreePool(pNewStream);
}
//
// this will revert the next record handle count if there have been
// no new records in between the increment and here. Otherwise, it will
// be a gap
//
#if defined (UNDER_CE)
InterlockedCompareExchange(&m_nextRecordHandle,
(LONG)(recordHandle-1),
(LONG) recordHandle);
#else
InterlockedCompareExchange((void **)&m_nextRecordHandle,
(void *)(recordHandle-1),
(void *) recordHandle);
#endif
}
return status;
}
NTSTATUS SdpDatabase::UpdateRecord(UCHAR *pStream, ULONG stremaSize, HANDLE handle)
{
#if (defined (UNDER_CE) || defined (WINCE_EMULATION))
ServiceRecord *pRecordOriginal;
NTSTATUS status;
if (handle == 0) {
ASSERT(0); // handle == 0 only for SDP specific database entry. Should never get in this state
return STATUS_NOT_FOUND;
}
// make sure record is in the data base.
m_ServiceRecordList.Lock();
for (pRecordOriginal = m_ServiceRecordList.GetHead();
pRecordOriginal != NULL;
pRecordOriginal = m_ServiceRecordList.GetNext(pRecordOriginal)) {
if (pRecordOriginal->handle == handle) {
break;
}
}
if (!pRecordOriginal) {
m_ServiceRecordList.Unlock();
return STATUS_NOT_FOUND;
}
status = AddRecord(pStream,stremaSize,&handle,pRecordOriginal);
m_ServiceRecordList.Unlock();
return status;
#else // UNDER_CE
// This code isn't fully implemented on NT yet.
if (handle == INVALID_ID) {
return STATUS_INVALID_PARAMETER;
}
//
// Find the record in the list, then remove it. If the update
// goes well, it will be reinserted into the list. I remove it so
// I can make calls outside the driver without holding onto a lock
//
ServiceRecord *pRecord;
NTSTATUS status = STATUS_NOT_FOUND;
#if 0
m_ServiceRecordList.Lock();
for (pRecord = m_ServiceRecordList.GetHead();
pRecord != NULL;
pRecord = m_ServiceRecordList.GetNext(pRecord)) {
if (pRecord->handle == handle) {
m_ServiceRecordList.RemoveAt(pRecord);
status = STATUS_SUCCESS;
break;
}
}
m_ServiceRecordList.Unlock();
#endif
if (!NT_SUCCESS(status)) {
return status;
}
//
// TBD: of the core attributes, what do we allow to change?
// o RecordHandle ? defnitely not
// o ServiceClass ? if so, then the record is more "new" than updated
// o
//
FireWmiEvent(handle, SdpDatabaseEventUpdateRecord);
return status;
#endif
}
NTSTATUS
SdpDatabase::RemoveRecord(
HANDLE handle,
ULONG *pfService
)
{
if ((handle == INVALID_ID) || (handle == 0)) {
return STATUS_INVALID_PARAMETER;
}
ServiceRecord *pRecord;
NTSTATUS status = STATUS_NOT_FOUND;
m_ServiceRecordList.Lock();
for (pRecord = m_ServiceRecordList.GetHead();
pRecord != NULL;
pRecord = m_ServiceRecordList.GetNext(pRecord)) {
if (pRecord->handle == handle) {
m_ServiceRecordList.RemoveAt(pRecord);
AlterDatabaseState();
status = STATUS_SUCCESS;
break;
}
}
m_ServiceRecordList.Unlock();
if (NT_SUCCESS(status)) {
FireWmiEvent(handle, SdpDatabaseEventRemoveRecord);
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
*pfService = pRecord->fService;
#endif
delete pRecord;
}
return status;
}
#if ! (defined (UNDER_CE) || defined (WINCE_EMULATION))
void SdpDatabase::Cleanup(PFILE_OBJECT pFileObject)
{
ServiceRecordList sdl;
ServiceRecord *pRecord;
m_ServiceRecordList.Lock();
pRecord = m_ServiceRecordList.GetHead();
while (pRecord != NULL) {
if (pRecord->pFileObject == pFileObject) {
//
// Retrieve the next record in the list b/c we will lose the link
// once it pRecord is removed from the list
//
ServiceRecord *pNext = m_ServiceRecordList.GetNext(pRecord);
m_ServiceRecordList.RemoveAt(pRecord);
sdl.AddTail(pRecord);
pRecord = pNext;
}
else {
pRecord = m_ServiceRecordList.GetNext(pRecord);
}
}
if (!sdl.IsEmpty()) {
AlterDatabaseState();
}
m_ServiceRecordList.Unlock();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -