Method for updating LSP Protocol chains (Code included)

June 22nd, 2004 - 10:42 am ET by Chet Simpson | Report spam
As I've gotten closer and closer to finishing my LSP I've been doing some
tests concerning the installation and removal of the provider when other
LSP's have been installed onto the system. During the testing I noticed that
several products being used to test compatibility failed miserably during the
removal stage of their own provider. Under Windows XP updating the protocol
chains is a snap as you have the WSCUpdateProvider call. Under Win9x variants
it's not as easy since you have to manage reinstalling the providers while
making sure all of the protocol chains are fixed for the new configuration. I
*think* I've found an easier method of updating the protocol chains for
instances such as this but I wanted to get some additional input.

I examined the protocol catalogs on both Windows XP and Windows 98se and was
somewhat surprised that with the exception of the contents the data layout was
the same for both platforms. From what I can tell each catalog entry contains
256 bytes containing the pathname of the dll, followed by 4 unknown bytes
(possibly unused), followed by the contents of the WSAPROTOCOL_INFOW
structure. Since the WSAPROTOCOL_INFOW data seems to be stored verbatim in the
registry I decided to run a few tests and came up with the code below for
updating only the protocol chains in a catalog entry.

Although this is only a proof of concept implementation I'm betting that if I
stepped into the WSCUpdateProvider call it would look very similar to the code
below. If WSCUpdateProvider does work in a similar fashion and the structure
of the catalog data remains the same across all Win32 platforms I see no
reason why this code (with a bit of additional error checking) couldn't be
used in a production environment.


Anyone have some thoughts on this approach?




[ SNIP CODE HERE ]



struct CATITEM {
char Path[256];
DWORD Unknown;
WSAPROTOCOL_INFOW ProtocolInfo;
};


#define KEY_PACKED_CATALOG_ITEM "PackedCatalogItem"
#define KEY_PROTOCOL_CATALOG \

"System\\CurrentControlSet\\Services\\Winsock2\\Parameters\\Protocol_Catalog9\\Catalog_Entries"
#define KEY_NAME_LENGTH 256
int UpdateProviderChain(const DWORD providerID,
const WSAPROTOCOLCHAIN *chain,
DWORD *lpErrno)
{
LONG retVal;
LONG result;
HKEY hkey;
DWORD index;

// Open the proto catalog in the registry
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
KEY_PROTOCOL_CATALOG,
0,
KEY_READ,
&hkey);
if(ERROR_SUCCESS != result) {
*lpErrno = result;
return SOCKET_ERROR;
}

// Set up the default error
retVal = SOCKET_ERROR;
*lpErrno = WSAEINVAL;

// Go do it
index = 0;
while(ERROR_SUCCESS == result) {
char subKeyName[KEY_NAME_LENGTH + 1];
DWORD subKeyLen;
FILETIME lastReadTime;
HKEY subKey;
DWORD type;
DWORD size;
CATITEM item;
LONG status;

subKeyLen = KEY_NAME_LENGTH;

// Enumerate the key index
result = RegEnumKeyEx(hkey,
index,
subKeyName,
&subKeyLen,
0,
NULL,
NULL,
&lastReadTime);
// If there are no more items then assume the catalog ID is incorrect
if(ERROR_NO_MORE_ITEMS == result) {
*lpErrno = WSAEINVAL;
break;
}

// Check for misc other errors
if(ERROR_SUCCESS != result) {
*lpErrno = result;
break;
}

// Open the sub key
subKey = NULL;
result = RegOpenKeyEx(hkey,
subKeyName,
0,
KEY_READ | KEY_WRITE,
&subKey);
if(ERROR_SUCCESS != result) {
*lpErrno = result;
break;
}

/*
** NOTE **

The query of the value does not currently initiate an overall
failure of the update to the catalog chain

*/
// Get the key data
size = sizeof(item);
status = RegQueryValueEx(subKey,
KEY_PACKED_CATALOG_ITEM,
0,
&type,
(BYTE*)&item,
&size);

// Make sure we got the data
if(ERROR_SUCCESS == status && sizeof(CATITEM) == size && REG_BINARY =type) {
// Check the provider ID
if(providerID == item.ProtocolInfo.dwCatalogEntryId) {
// Update the new chain
item.ProtocolInfo.ProtocolChain = *chain;

// Save the data
*lpErrno = RegSetValueEx(subKey,
KEY_PACKED_CATALOG_ITEM,
0,
REG_BINARY,
(BYTE*)&item,
sizeof(item));
if(ERROR_SUCCESS != result) {
retVal = ERROR_SUCCESS;
}

RegCloseKey(subKey);

break;
}
}

// Close the subkey if it was opened
if(ERROR_SUCCESS == status && NULL != subKey) {
RegCloseKey(subKey);
}

index++;
}

RegCloseKey(hkey);

return retVal;
}





-
Chet Simpson
MSDN in one hand. Prozac in the other.
email Follow the discussionReplies 1 replyReplies Make a reply

Similar topics

Replies

#1 Arkady Frenkel
June 23rd, 2004 - 04:06 am ET | Report spam
Just a question , do you mean that WSCUpdateProvider doesn't work under W9x
?
Arkady

"Chet Simpson" wrote in message
news:

As I've gotten closer and closer to finishing my LSP I've been doing some
tests concerning the installation and removal of the provider when other
LSP's have been installed onto the system. During the testing I noticed


that
several products being used to test compatibility failed miserably during


the
removal stage of their own provider. Under Windows XP updating the


protocol
chains is a snap as you have the WSCUpdateProvider call. Under Win9x


variants
it's not as easy since you have to manage reinstalling the providers while
making sure all of the protocol chains are fixed for the new


configuration. I
*think* I've found an easier method of updating the protocol chains for
instances such as this but I wanted to get some additional input.

I examined the protocol catalogs on both Windows XP and Windows 98se and


was
somewhat surprised that with the exception of the contents the data layout


was
the same for both platforms. From what I can tell each catalog entry


contains
256 bytes containing the pathname of the dll, followed by 4 unknown bytes
(possibly unused), followed by the contents of the WSAPROTOCOL_INFOW
structure. Since the WSAPROTOCOL_INFOW data seems to be stored verbatim in


the
registry I decided to run a few tests and came up with the code below for
updating only the protocol chains in a catalog entry.

Although this is only a proof of concept implementation I'm betting that


if I
stepped into the WSCUpdateProvider call it would look very similar to the


code
below. If WSCUpdateProvider does work in a similar fashion and the


structure
of the catalog data remains the same across all Win32 platforms I see no
reason why this code (with a bit of additional error checking) couldn't be
used in a production environment.


Anyone have some thoughts on this approach?




[ SNIP CODE HERE ]



struct CATITEM {
char Path[256];
DWORD Unknown;
WSAPROTOCOL_INFOW ProtocolInfo;
};


#define KEY_PACKED_CATALOG_ITEM "PackedCatalogItem"
#define KEY_PROTOCOL_CATALOG \




"System\\CurrentControlSet\\Services\\Winsock2\\Parameters\\Protocol_Catalog
9\\Catalog_Entries"
#define KEY_NAME_LENGTH 256
int UpdateProviderChain(const DWORD providerID,
const WSAPROTOCOLCHAIN *chain,
DWORD *lpErrno)
{
LONG retVal;
LONG result;
HKEY hkey;
DWORD index;

// Open the proto catalog in the registry
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
KEY_PROTOCOL_CATALOG,
0,
KEY_READ,
&hkey);
if(ERROR_SUCCESS != result) {
*lpErrno = result;
return SOCKET_ERROR;
}

// Set up the default error
retVal = SOCKET_ERROR;
*lpErrno = WSAEINVAL;

// Go do it
index = 0;
while(ERROR_SUCCESS == result) {
char subKeyName[KEY_NAME_LENGTH + 1];
DWORD subKeyLen;
FILETIME lastReadTime;
HKEY subKey;
DWORD type;
DWORD size;
CATITEM item;
LONG status;

subKeyLen = KEY_NAME_LENGTH;

// Enumerate the key index
result = RegEnumKeyEx(hkey,
index,
subKeyName,
&subKeyLen,
0,
NULL,
NULL,
&lastReadTime);
// If there are no more items then assume the catalog ID is


incorrect
if(ERROR_NO_MORE_ITEMS == result) {
*lpErrno = WSAEINVAL;
break;
}

// Check for misc other errors
if(ERROR_SUCCESS != result) {
*lpErrno = result;
break;
}

// Open the sub key
subKey = NULL;
result = RegOpenKeyEx(hkey,
subKeyName,
0,
KEY_READ | KEY_WRITE,
&subKey);
if(ERROR_SUCCESS != result) {
*lpErrno = result;
break;
}

/*
** NOTE **

The query of the value does not currently initiate an overall
failure of the update to the catalog chain

*/
// Get the key data
size = sizeof(item);
status = RegQueryValueEx(subKey,
KEY_PACKED_CATALOG_ITEM,
0,
&type,
(BYTE*)&item,
&size);

// Make sure we got the data
if(ERROR_SUCCESS == status && sizeof(CATITEM) == size &&


REG_BINARY => type) {
// Check the provider ID
if(providerID == item.ProtocolInfo.dwCatalogEntryId) {
// Update the new chain
item.ProtocolInfo.ProtocolChain = *chain;

// Save the data
*lpErrno = RegSetValueEx(subKey,
KEY_PACKED_CATALOG_ITEM,
0,
REG_BINARY,
(BYTE*)&item,
sizeof(item));
if(ERROR_SUCCESS != result) {
retVal = ERROR_SUCCESS;
}

RegCloseKey(subKey);

break;
}
}

// Close the subkey if it was opened
if(ERROR_SUCCESS == status && NULL != subKey) {
RegCloseKey(subKey);
}

index++;
}

RegCloseKey(hkey);

return retVal;
}





-
Chet Simpson
MSDN in one hand. Prozac in the other.


email Follow the discussion Replies Reply to this message
Help Create a new topicReplies Make a reply
Search Make your own search