/*++ Copyright (c) 1994 Microsoft Corporation Module Name: gtsadrnr.c Abstract: This module contains the code to support the new RnR APIs. Some support code is in getaddr.c, but the interface routines and routines specific to RnR2 are herein. Author: ArnoldM 4-Dec-1995 Revision History: ArnoldM Created --*/ #include #include #include #include #include "ncp.h" #include #include #include #include #include #include #include //-------------------------------------------------------------------// // // // Globals in getaddr.c and provider .c // // // //-------------------------------------------------------------------// GUID HostAddrByInetStringGuid = SVCID_INET_HOSTADDRBYINETSTRING; GUID ServiceByNameGuid = SVCID_INET_SERVICEBYNAME; GUID HostAddrByNameGuid = SVCID_INET_HOSTADDRBYNAME; GUID HostNameGuid = SVCID_HOSTNAME; DWORD NwpGetAddressByName( IN LPWSTR Reserved, IN WORD nServiceType, IN LPWSTR lpServiceName, IN OUT LPSOCKADDR_IPX lpsockaddr ); DWORD NwpGetAddressViaSap( IN WORD nServiceType, IN LPWSTR lpServiceName, IN DWORD nProt, IN OUT LPVOID lpCsAddrBuffer, IN OUT LPDWORD lpdwBufferLength, IN HANDLE hCancellationEvent, OUT LPDWORD lpcAddress ); DWORD NwpRnR2AddServiceType( IN LPWSTR lpServiceTypeName, IN LPGUID lpClassType, IN WORD wSapId, IN WORD wPort ); BOOL NwpRnR2RemoveServiceType( IN LPGUID lpServiceType ); DWORD SapFreeSapSocket( SOCKET s ); PSAP_RNR_CONTEXT SapMakeContext ( IN HANDLE Handle, DWORD dwExcess ); BOOL NwpLookupSapInRegistry( IN LPGUID lpServiceType, OUT PWORD pnSapType, OUT PWORD pwPort, IN OUT PDWORD pfConnectionOriented ); PSAP_RNR_CONTEXT SapGetContext( HANDLE h ); DWORD DoASap( IN PSAP_RNR_CONTEXT psrcContext, IN WORD QueryType, IN PBYTE * ppData, IN LPWSAQUERYSETW lpqsResults, IN PLONG pl, IN PDWORD pdw ); VOID SapReleaseContext( IN PSAP_RNR_CONTEXT psrcContext ); DWORD SapGetSapSocket( SOCKET * ps ); DWORD PrepareForSap( IN PSAP_RNR_CONTEXT psrc ); DWORD SapGetSapForType( PSAP_BCAST_CONTROL psbc, WORD nServiceType ); DWORD FillBufferWithCsAddr( IN LPBYTE pAddress, IN DWORD nProt, IN OUT LPVOID lpCsAddrBuffer, IN OUT LPDWORD lpdwBufferLength, OUT LPDWORD pcAddress ); DWORD pSapSetService2( IN DWORD dwOperation, IN LPWSTR lpszServiceInstanceName, IN PBYTE pbAddress, IN LPGUID pServiceType, IN WORD nServiceType ); DWORD NwpGetRnRAddress( PHANDLE phServer, PWCHAR pwszContext, PLONG plIndex, LPWSTR lpServiceName, WORD nServiceType, PDWORD pdwVersion, DWORD dwInSize, LPWSTR OutName, SOCKADDR_IPX * pSockAddr ); DWORD NwpSetClassInfo( IN LPWSTR lpwszClassName, IN LPGUID lpClassId, IN PCHAR lpbProp ); VOID pFreeAllContexts(); extern DWORD oldRnRServiceRegister, oldRnRServiceDeRegister; //-------------------------------------------------------------------// // // // Local Function Prototypes // // // //-------------------------------------------------------------------// INT WINAPI pGetServiceClassInfo( IN LPGUID lpProviderId, IN OUT LPDWORD lpdwBufSize, IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo, IN PBOOL pfAdvert ); DWORD NwpSetClassInfoAdvertise( IN LPGUID lpClassType, IN WORD wSapId ); BOOL NSPpCheckCancel( PVOID pvArg ); DWORD NSPpGotSap( PSAP_BCAST_CONTROL psbc, PSAP_IDENT_HEADER pSap, PDWORD pdwErr ); INT WINAPI NSPLookupServiceBegin( IN LPGUID lpProviderId, IN LPWSAQUERYSETW lpqsRestrictions, IN LPWSASERVICECLASSINFOW lpServiceClassInfo, IN DWORD dwControlFlags, OUT LPHANDLE lphLookup ); INT WINAPI NSPLookupServiceNext( IN HANDLE hLookup, IN DWORD dwControlFlags, IN OUT LPDWORD lpdwBufferLength, OUT LPWSAQUERYSETW lpqsResults ); INT WINAPI NSPUnInstallNameSpace( IN LPGUID lpProviderId ); INT WINAPI NSPCleanup( IN LPGUID lpProviderId ); INT WINAPI NSPLookupServiceEnd( IN HANDLE hLookup ); INT WINAPI NSPSetService( IN LPGUID lpProviderId, IN LPWSASERVICECLASSINFOW lpServiceClassInfo, IN LPWSAQUERYSETW lpqsRegInfo, IN WSAESETSERVICEOP essOperation, IN DWORD dwControlFlags ); INT WINAPI NSPInstallServiceClass( IN LPGUID lpProviderId, IN LPWSASERVICECLASSINFOW lpServiceClassInfo ); INT WINAPI NSPRemoveServiceClass( IN LPGUID lpProviderId, IN LPGUID lpServiceCallId ); INT WINAPI NSPGetServiceClassInfo( IN LPGUID lpProviderId, IN OUT LPDWORD lpdwBufSize, IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo ); //-------------------------------------------------------------------// // // // Data definitions // // // //-------------------------------------------------------------------// NSP_ROUTINE nsrVector = { FIELD_OFFSET(NSP_ROUTINE, NSPIoctl), 1, // major version 1, // minor version NSPCleanup, NSPLookupServiceBegin, NSPLookupServiceNext, NSPLookupServiceEnd, NSPSetService, NSPInstallServiceClass, NSPRemoveServiceClass, NSPGetServiceClassInfo }; static GUID HostnameGuid = SVCID_HOSTNAME; static GUID InetHostname = SVCID_INET_HOSTADDRBYNAME; static GUID AddressGuid = SVCID_INET_HOSTADDRBYINETSTRING; static GUID IANAGuid = SVCID_INET_SERVICEBYNAME; #define GuidEqual(x,y) RtlEqualMemory(x, y, sizeof(GUID)) //------------------------------------------------------------------// // // // Function Bodies // // // //------------------------------------------------------------------// DWORD NwpSetClassInfoAdvertise( IN LPGUID lpClassType, IN WORD wSapId ) { /*++ Routine Description: Start a class info advertise. Called upon a SetService call --*/ PWCHAR pwszUuid; SOCKADDR_IPX sock; if (UuidToString(lpClassType, &pwszUuid) != RPC_S_OK) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return SOCKET_ERROR; } memset(&sock, 0, sizeof(sock)); *(PWORD)&sock.sa_netnum = htons(wSapId); // encode the ID here return(pSapSetService2( oldRnRServiceRegister, pwszUuid, (PBYTE)&sock, lpClassType, RNRCLASSSAPTYPE)); } DWORD pRnRReturnString( IN PWCHAR pwszSrc, IN OUT PBYTE *ppData, IN OUT PLONG plBytes ) { /*++ Routine Description: Utility routine to pack a string into the spare buffer space, update pointers and counts. If the string fits, it is copied. If not, the pointer and count are still updated so the caller can compute the additional space needed --*/ PBYTE pSave = *ppData; LONG lLen = (wcslen(pwszSrc) + 1) * sizeof(WCHAR); *ppData = pSave + lLen; // update the buffer pointer *plBytes = *plBytes - lLen; // and the count if(*plBytes >= 0) { // // it fits. // RtlMoveMemory(pSave, pwszSrc, lLen); return(NO_ERROR); } return(WSAEFAULT); } DWORD pLocateSapIdAndProtocls( IN LPGUID lpClassInfoType, IN DWORD dwNumClassInfo, IN LPWSANSCLASSINFOW lpClassInfoBuf, OUT PWORD pwSapId, OUT PDWORD pdwnProt ) /*++ Routine Description: Locate the SAP ID entry and return it. Also return the protocols support. --*/ { DWORD err = NO_ERROR; if(GuidEqual(lpClassInfoType, &HostnameGuid) || GuidEqual(lpClassInfoType, &InetHostname) ) { *pwSapId = 0x4; } else if(IS_SVCID_NETWARE(lpClassInfoType)) { *pwSapId = SAPID_FROM_SVCID_NETWARE(lpClassInfoType); } else { for(; dwNumClassInfo; dwNumClassInfo--, lpClassInfoBuf++) { // // We have some class info data. Rummage through it // looking for what we want // if(!_wcsicmp(SERVICE_TYPE_VALUE_SAPIDW, lpClassInfoBuf->lpszName) && (lpClassInfoBuf->dwValueType == REG_DWORD) && (lpClassInfoBuf->dwValueSize >= sizeof(WORD))) { // // got it // *pwSapId = *(PWORD)lpClassInfoBuf->lpValue; break; } } if(!dwNumClassInfo) { err = WSA_INVALID_PARAMETER; } } *pdwnProt = SPX_BIT | SPXII_BIT | IPX_BIT; return(err); } DWORD pRnRReturnResults( IN PWCHAR pwszString, IN LPGUID pgdServiceClass, IN DWORD dwVersion, IN OUT PBYTE *ppData, IN OUT PLONG plBytes, IN PBYTE lpSockAddr, IN DWORD nProt, IN DWORD dwControlFlags, OUT LPWSAQUERYSETW lpqsResults ) { /*++ Routine Description: Return the requested results --*/ DWORD err; lpqsResults->dwNameSpace = NS_SAP; if(dwControlFlags & LUP_RETURN_TYPE) { lpqsResults->lpServiceClassId = (LPGUID)*ppData; *ppData += sizeof(GUID); *plBytes -= sizeof(GUID); if(*plBytes >= 0) { *lpqsResults->lpServiceClassId = *pgdServiceClass; } } if(dwVersion && (dwControlFlags & LUP_RETURN_VERSION) ) { // // have a verion, and the caller wants it // lpqsResults->lpVersion = (LPWSAVERSION)*ppData; *ppData += sizeof(WSAVERSION); *plBytes -= sizeof(WSAVERSION); if(*plBytes >= 0) { // // and it fits. So return it // lpqsResults->lpVersion->dwVersion = dwVersion; lpqsResults->lpVersion->ecHow = COMP_EQUAL; } } if(dwControlFlags & LUP_RETURN_ADDR) { DWORD dwCsAddrLen; if(*plBytes >= 0) { dwCsAddrLen = (DWORD)*plBytes; // all of it for now } else { dwCsAddrLen = 0; } lpqsResults->lpcsaBuffer = (PVOID)*ppData; err = FillBufferWithCsAddr( lpSockAddr, nProt, (PVOID)lpqsResults->lpcsaBuffer, &dwCsAddrLen, &lpqsResults->dwNumberOfCsAddrs); // // see if it fit. Whether it did or not, compute the space available, // align, and do the rest // if(err == NO_ERROR) { // // if it worked, we have to compute the space taken // dwCsAddrLen = lpqsResults->dwNumberOfCsAddrs * (sizeof(CSADDR_INFO) + 2*sizeof(SOCKADDR_IPX)); } else if(err == ERROR_INSUFFICIENT_BUFFER) { err = WSAEFAULT; } *plBytes = *plBytes - dwCsAddrLen; *ppData = *ppData + dwCsAddrLen; } else { err = NO_ERROR; } // // no padding needed. if((dwControlFlags & LUP_RETURN_NAME)) { lpqsResults->lpszServiceInstanceName = (LPWSTR)*ppData; err = pRnRReturnString( pwszString, ppData, plBytes); } if(pgdServiceClass) { // // Do we really return this? // } return(err); } INT WINAPI NSPLookupServiceBegin( IN LPGUID lpProviderId, IN LPWSAQUERYSETW lpqsRestrictions, IN LPWSASERVICECLASSINFOW lpServiceClassInfo, IN DWORD dwControlFlags, OUT LPHANDLE lphLookup ) /*++ Routine Description: This is the RnR routine that begins a lookup. --*/ { PSAP_RNR_CONTEXT psrc; int err; DWORD nProt, nProt1; OEM_STRING OemServiceName; LPWSTR pwszContext; WORD wSapid; DWORD dwNumClassInfo; LPWSANSCLASSINFOW lpClassInfoBuf; // // Do parameter checking. // if ( lpqsRestrictions == NULL || lpProviderId == NULL ) { SetLastError( WSA_INVALID_PARAMETER ); return( SOCKET_ERROR ); } if ( lpqsRestrictions->dwNameSpace != NS_ALL && lpqsRestrictions->dwNameSpace != NS_SAP ) { SetLastError( WSAEINVAL ); return( SOCKET_ERROR ); } if ( lpqsRestrictions->lpServiceClassId == NULL ) { SetLastError( WSA_INVALID_PARAMETER ); return( SOCKET_ERROR ); } // // Test to see if the ServiceClassId is TCP's, if so // we don't do the lookup. if ( lpqsRestrictions->lpServiceClassId && ( GuidEqual( lpqsRestrictions->lpServiceClassId, &HostAddrByInetStringGuid ) || GuidEqual( lpqsRestrictions->lpServiceClassId, &ServiceByNameGuid ) || GuidEqual( lpqsRestrictions->lpServiceClassId, &HostNameGuid ) || GuidEqual( lpqsRestrictions->lpServiceClassId, &HostAddrByNameGuid ) ) ) { SetLastError( WSASERVICE_NOT_FOUND ); return( SOCKET_ERROR ); } if(lpqsRestrictions->dwSize < sizeof(WSAQUERYSETW)) { SetLastError(WSAEFAULT); return(SOCKET_ERROR); } if(lpqsRestrictions->lpszContext && (lpqsRestrictions->lpszContext[0] != 0) && wcscmp(&lpqsRestrictions->lpszContext[0], L"\\") ) { // // if not the default context, we must copy it. // pwszContext = lpqsRestrictions->lpszContext; } else { // // map all default contexts into "no context". // pwszContext = 0; } // // Compute protocols to return, or return them all // if(lpqsRestrictions->lpafpProtocols) { // // Make certain at least one IPX/SPX protocol is being requested // DWORD i; nProt = 0; for ( i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++ ) { if((lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_IPX) || (lpqsRestrictions->lpafpProtocols[i].iAddressFamily == AF_UNSPEC) ) { switch(lpqsRestrictions->lpafpProtocols[i].iProtocol) { case NSPROTO_IPX: nProt |= IPX_BIT; break; case NSPROTO_SPX: nProt |= SPX_BIT; break; case NSPROTO_SPXII: nProt |= SPXII_BIT; break; default: break; } } } if(!nProt) { // // if the caller doesn't want IPX/SPX addresses, why bother? // SetLastError(WSANO_DATA); return(SOCKET_ERROR); } } else { nProt = IPX_BIT | SPX_BIT | SPXII_BIT; } if(dwControlFlags & LUP_CONTAINERS) { if(pwszContext) { BadGuid: SetLastError(WSANO_DATA); return(SOCKET_ERROR); // can't handle containers in containers } wSapid = 0x4; nProt1 = IPX_BIT; err = NO_ERROR; } else { LPGUID pgClass = lpqsRestrictions->lpServiceClassId; if(!pgClass || GuidEqual(pgClass, &AddressGuid) || GuidEqual(pgClass, &IANAGuid) ) { goto BadGuid; } if(!lpqsRestrictions->lpszServiceInstanceName || !*lpqsRestrictions->lpszServiceInstanceName) { SetLastError(WSA_INVALID_PARAMETER); return(SOCKET_ERROR); } if(!lpServiceClassInfo) { dwNumClassInfo = 0; } else { dwNumClassInfo = lpServiceClassInfo->dwCount; lpClassInfoBuf = lpServiceClassInfo->lpClassInfos; } err = pLocateSapIdAndProtocls(pgClass, dwNumClassInfo, lpClassInfoBuf, &wSapid, &nProt1); if(err) { if(dwNumClassInfo) { SetLastError(err); return(SOCKET_ERROR); } else { nProt1 = nProt; wSapid = 0; err = 0; } } } nProt &= nProt1; // the relevant protocols if(!nProt) { SetLastError(WSANO_DATA); return(SOCKET_ERROR); } // // Make sure a class ID is given since we copy it // if(!lpqsRestrictions->lpServiceClassId) { // // not. So, fail // SetLastError(WSA_INVALID_PARAMETER); return(SOCKET_ERROR); } // // It looks like a query we can handle. Make a context // psrc = SapMakeContext(0, sizeof(WSAVERSION) - sizeof(PVOID)); if(!psrc) { SetLastError(WSA_NOT_ENOUGH_MEMORY); return(SOCKET_ERROR); } // // save things // psrc->gdType = *lpqsRestrictions->lpServiceClassId; psrc->dwControlFlags = dwControlFlags; // save for Next processing psrc->wSapId = wSapid; if(pwszContext) { wcscpy(psrc->wszContext, pwszContext); } // // save the relevant restrictions // if the name is a wild-card, don't copy it. A NULL name // serves as a wild-card to NSPLookupServiceNext // if(lpqsRestrictions->lpszServiceInstanceName && *lpqsRestrictions->lpszServiceInstanceName && wcscmp(lpqsRestrictions->lpszServiceInstanceName, L"*")) { DWORD dwLen = wcslen(lpqsRestrictions->lpszServiceInstanceName); if(dwLen > 48) { err = WSA_INVALID_PARAMETER; goto Done; } else { RtlMoveMemory(psrc->chwName, lpqsRestrictions->lpszServiceInstanceName, dwLen * sizeof(WCHAR)); _wcsupr(psrc->chwName); } } psrc->fConnectionOriented = (DWORD) -1; *lphLookup = (HANDLE)psrc; psrc->nProt = nProt; psrc->gdProvider = *lpProviderId; if(lpqsRestrictions->lpVersion) { *(LPWSAVERSION)&psrc->pvVersion = *lpqsRestrictions->lpVersion; } Done: SapReleaseContext(psrc); if(err != NO_ERROR) { SapReleaseContext(psrc); SetLastError(err); err = SOCKET_ERROR; } return(err); } INT WINAPI NSPLookupServiceNext( IN HANDLE hLookup, IN DWORD dwControlFlags, IN OUT LPDWORD lpdwBufferLength, OUT LPWSAQUERYSETW lpqsResults ) /*++ Routine Description: The continuation of the LookupServiceBegin. Called to fetch a matching item. Arguments: See RnR spec --*/ { DWORD err = NO_ERROR; PSAP_RNR_CONTEXT psrc; SOCKADDR_IPX SockAddr; WCHAR OutName[48]; PBYTE pData = (PBYTE)(lpqsResults + 1); LONG lSpare; LONG lLastIndex; DWORD dwVersion; WSAQUERYSETW wsaqDummy; BOOL fDoStateMachine; if(*lpdwBufferLength < sizeof(WSAQUERYSETW)) { lpqsResults = &wsaqDummy; } lSpare = (LONG)*lpdwBufferLength - sizeof(WSAQUERYSETW); memset(lpqsResults, 0, sizeof(WSAQUERYSETW)); lpqsResults->dwNameSpace = NS_SAP; lpqsResults->dwSize = sizeof(WSAQUERYSETW); psrc = SapGetContext(hLookup); if(!psrc) { SetLastError(WSA_INVALID_HANDLE); return(SOCKET_ERROR); } // // This is a valid context. Determine whether this is the first // call to this. If so, we need to determine whether to // get the information from the bindery or by using SAP. // if ( psrc->u_type.bc.lIndex == 0xffffffff ) { err = WSA_E_NO_MORE; goto DoneNext; } // // make sure we have the class info info // if(!psrc->wSapId) { // // Need to get it // UCHAR Buffer[1000]; LPWSASERVICECLASSINFOW lpcli = (LPWSASERVICECLASSINFOW)Buffer; DWORD dwBufSize; DWORD nProt1; dwBufSize = 1000; lpcli->lpServiceClassId = &psrc->gdType; if( (err = NSPGetServiceClassInfo(&psrc->gdProvider, &dwBufSize, lpcli)) != NO_ERROR) { goto DoneNext; } err = pLocateSapIdAndProtocls(&psrc->gdType, lpcli->dwCount, lpcli->lpClassInfos, &psrc->wSapId, &nProt1); if(err) { SetLastError(err); goto DoneNext; } psrc->nProt &= nProt1; if(!psrc->nProt) { // // no protocols match // err = WSANO_DATA; goto DoneNext; } } // // this is the state machine for querying. It selects the bindery or // SAP as appropriate. // fDoStateMachine = TRUE; // enter the machine do { // // switch on the current machine state. // switch(psrc->dwUnionType) { case LOOKUP_TYPE_NIL: psrc->u_type.bc.lIndex = -1; psrc->dwUnionType = LOOKUP_TYPE_BINDERY; break; // reenter state machine case LOOKUP_TYPE_BINDERY: // // try the bindery // if(psrc->dwControlFlags & LUP_NEAREST) { err = NO_DATA; // skip the bindery } else { // // otherwise, try the bindery // EnterCriticalSection(&psrc->u_type.sbc.csMonitor); lLastIndex = psrc->u_type.bc.lIndex; // save it err = NwpGetRnRAddress( &psrc->hServer, (psrc->wszContext[0] ? &psrc->wszContext[0] : 0), &psrc->u_type.bc.lIndex, (psrc->chwName[0] ? psrc->chwName : 0), psrc->wSapId, &dwVersion, 48 * sizeof(WCHAR), OutName, &SockAddr); LeaveCriticalSection(&psrc->u_type.sbc.csMonitor); } if(err != NO_ERROR) { if((psrc->u_type.bc.lIndex == -1)) { err = PrepareForSap(psrc); if(err) { // // if we can't, exit the state machine // fDoStateMachine = FALSE; } } else { // // no more bindery entries. We will leave the state machine // if(err == ERROR_NO_MORE_ITEMS) { err = WSA_E_NO_MORE; } fDoStateMachine = FALSE; } break; } else { LPWSAVERSION lpVersion = (LPWSAVERSION)&psrc->pvVersion; if(lpVersion->dwVersion && dwVersion) { // // need to checkout for version matching // switch(lpVersion->ecHow) { case COMP_EQUAL: if(lpVersion->dwVersion != dwVersion) { continue; //reenter machine } break; case COMP_NOTLESS: if(lpVersion->dwVersion > dwVersion) { continue; } break; default: continue; // error. If we don't // know how to compare, we // must reject it. } } // // have a suitable item. // return the name and type and all // that err = pRnRReturnResults( OutName, &psrc->gdType, dwVersion, &pData, &lSpare, (PBYTE)SockAddr.sa_netnum, psrc->nProt, psrc->dwControlFlags, lpqsResults); if(err == WSAEFAULT) { // // no room. Return buffer size required and // restore the index // *lpdwBufferLength = (DWORD)((LONG)*lpdwBufferLength - lSpare); psrc->u_type.bc.lIndex = lLastIndex; } fDoStateMachine = FALSE; } break; case LOOKUP_TYPE_SAP: // // Use SAP. // { WORD QueryType; if(psrc->dwControlFlags & LUP_NEAREST) { QueryType = QT_NEAREST_QUERY; } else { QueryType = QT_GENERAL_QUERY; } err = DoASap(psrc, QueryType, &pData, lpqsResults, &lSpare, lpdwBufferLength); if((err == WSA_E_NO_MORE) && !(psrc->fFlags & SAP_F_END_CALLED) && (QueryType == QT_NEAREST_QUERY) && (psrc->dwControlFlags & LUP_DEEP) && !psrc->u_type.sbc.psdHead) { // // didn't find it locally. Turn off LUP_NEAREST // and do this as a general query. This might bring // it back to a SAP query, but this time // without LUP_NEAREST. But starting anew // allows the use of the bindery and that // might find things quickly. // psrc->dwControlFlags &= ~LUP_NEAREST; psrc->dwUnionType = LOOKUP_TYPE_NIL; if(psrc->u_type.sbc.s) { SapFreeSapSocket(psrc->u_type.sbc.s); psrc->u_type.sbc.s = 0; } } else { fDoStateMachine = FALSE; } break; } } // switch } while(fDoStateMachine); DoneNext: SapReleaseContext(psrc); if((err != NO_ERROR) && (err != (DWORD)SOCKET_ERROR)) { SetLastError(err); err = (DWORD)SOCKET_ERROR; } return((INT)err); } BOOL NSPpCheckCancel( PVOID pvArg ) /*++ Routine Description: Coroutine called to check if the SAP lookup has been cancelled. For now, this always returns FALSE as we use the flags word in the control block instead --*/ { return(FALSE); } DWORD NSPpGotSap( PSAP_BCAST_CONTROL psbc, PSAP_IDENT_HEADER pSap, PDWORD pdwErr ) /*++ Routine Description: Coroutine called for each SAP reply received. This decides whether to keep the data or not and returns a code telling the SAP engine whether to proceed Arguments: psbc -- the SAP_BCAST_CONTROL pSap -- the SAP reply pdwErr -- where to put an error code --*/ { PSAP_DATA psdData; LPWSAQUERYSETW Results = (LPWSAQUERYSETW)psbc->pvArg; PSAP_RNR_CONTEXT psrc = psbc->psrc; DWORD dwRet = dwrcNil; PCHAR pServiceName = (PCHAR)psrc->chName; EnterCriticalSection(&psbc->csMonitor); // // First, check if this is a lookup for a particular name. If so, // accept only the name. // if(*pServiceName) { if(strcmp(pServiceName, pSap->ServerName)) { goto nota; } if(!(psrc->dwControlFlags & LUP_NEAREST)) { dwRet = dwrcDone; psbc->fFlags |= SBC_FLAG_NOMORE; } } // // see if we want to keep this guy // We keep it if we don't already have it in the list // for(psdData = psbc->psdHead; psdData; psdData = psdData->sapNext) { if(RtlEqualMemory( psdData->socketAddr, &pSap->Address, IPX_ADDRESS_LENGTH)) { goto nota; // we have it already } } psdData = (PSAP_DATA)LocalAlloc(LPTR, sizeof(SAP_DATA)); if(!psdData) { goto nota; // can't save it } psdData->sapid = pSap->ServerType; RtlMoveMemory(psdData->sapname, pSap->ServerName, 48); RtlMoveMemory(psdData->socketAddr, &pSap->Address, IPX_ADDRESS_LENGTH); if(psbc->psdTail) { psbc->psdTail->sapNext = psdData; } else { psbc->psdHead = psdData; } psbc->psdTail = psdData; if(!psbc->psdNext1) { psbc->psdNext1 = psdData; } nota: LeaveCriticalSection(&psbc->csMonitor); if((dwRet == dwrcNil) && psbc->psdNext1) { dwRet = dwrcNoWait; } return(dwRet); } INT WINAPI NSPUnInstallNameSpace( IN LPGUID lpProviderId ) { return(NO_ERROR); } INT WINAPI NSPCleanup( IN LPGUID lpProviderId ) { // // Make sure all contexts are released // // pFreeAllContexts(); // done in Dll Process detach return(NO_ERROR); } INT WINAPI NSPLookupServiceEnd( IN HANDLE hLookup ) { PSAP_RNR_CONTEXT psrc; psrc = SapGetContext(hLookup); if(!psrc) { SetLastError(WSA_INVALID_HANDLE); return(SOCKET_ERROR); } psrc->fFlags |= SAP_F_END_CALLED; SapReleaseContext(psrc); // get rid of it SapReleaseContext(psrc); // and close it. Context cleanup is // done on the last derefernce. return(NO_ERROR); } INT WINAPI NSPSetService( IN LPGUID lpProviderId, IN LPWSASERVICECLASSINFOW lpServiceClassInfo, IN LPWSAQUERYSETW lpqsRegInfo, IN WSAESETSERVICEOP essOperation, IN DWORD dwControlFlags ) { /*++ Routine Description: The routine that implements the RnR SetService routine. Note that context is ignored. There is no way to direct the registration to a particular server. --*/ PBYTE pbAddress; DWORD dwOperation; PBYTE pbSocket; DWORD dwAddrs; DWORD err = NO_ERROR; WORD wSapId; DWORD nProt, dwAddress; BOOL fAdvert = FALSE; DWORD dwNumClassInfo; LPWSANSCLASSINFOW lpClassInfoBuf; // // Verify all args present // if(!lpqsRegInfo->lpszServiceInstanceName || !lpqsRegInfo->lpServiceClassId) { SetLastError(WSA_INVALID_PARAMETER); return(SOCKET_ERROR); } if(!lpServiceClassInfo && !IS_SVCID_NETWARE(lpqsRegInfo->lpServiceClassId)) { UCHAR Buffer[1000]; LPWSASERVICECLASSINFOW lpcli = (LPWSASERVICECLASSINFOW)Buffer; DWORD dwBufSize; dwBufSize = 1000; lpcli->lpServiceClassId = lpqsRegInfo->lpServiceClassId; if(pGetServiceClassInfo(lpProviderId, &dwBufSize, lpcli, &fAdvert) != NO_ERROR) { return(SOCKET_ERROR); } dwNumClassInfo = lpcli->dwCount; lpClassInfoBuf = lpcli->lpClassInfos; } else if (lpServiceClassInfo) { dwNumClassInfo = lpServiceClassInfo->dwCount; lpClassInfoBuf = lpServiceClassInfo->lpClassInfos; } else { // lpServiceClassId is a GUID which defines the SapId. This means // that pLocateSapIdAndProtocls doesn't need the lpClassInfoBuf. dwNumClassInfo = 0; lpClassInfoBuf = 0; } // // Find the IPX address in the input args // err = pLocateSapIdAndProtocls(lpqsRegInfo->lpServiceClassId, dwNumClassInfo, lpClassInfoBuf, &wSapId, &nProt); if(err == NO_ERROR) { if(essOperation == RNRSERVICE_REGISTER) { PCSADDR_INFO pcsaAddress; pcsaAddress = lpqsRegInfo->lpcsaBuffer; try { for(dwAddrs = lpqsRegInfo->dwNumberOfCsAddrs; dwAddrs; dwAddrs--, pcsaAddress++) { if(pcsaAddress->LocalAddr.lpSockaddr->sa_family == AF_IPX) { pbSocket = (PBYTE)pcsaAddress->LocalAddr.lpSockaddr; break; } } } except(EXCEPTION_EXECUTE_HANDLER) { err = GetExceptionCode(); } if(err || !dwAddrs) { err = ERROR_INCORRECT_ADDRESS; } else if(fAdvert) { NwpSetClassInfoAdvertise(lpqsRegInfo->lpServiceClassId, wSapId); } } else { pbSocket = 0; } if(err == NO_ERROR) { // // map the operation, and call the common worker // switch(essOperation) { case RNRSERVICE_REGISTER: dwOperation = oldRnRServiceRegister; break; case RNRSERVICE_DEREGISTER: case RNRSERVICE_DELETE: dwOperation = oldRnRServiceDeRegister; break; default: err = WSA_INVALID_PARAMETER; break; } if(err == NO_ERROR) { err = pSapSetService2( dwOperation, lpqsRegInfo->lpszServiceInstanceName, pbSocket, lpqsRegInfo->lpServiceClassId, wSapId); } } } if(err != NO_ERROR) { SetLastError(err); err = (DWORD)SOCKET_ERROR; } return(err); } INT WINAPI NSPInstallServiceClass( IN LPGUID lpProviderId, IN LPWSASERVICECLASSINFOW lpServiceClassInfo ) { LPWSANSCLASSINFOW pcli, pcli1 = 0; DWORD dwIndex = lpServiceClassInfo->dwCount; CHAR PropertyBuffer[128]; PBINDERYCLASSES pbc = (PBINDERYCLASSES)PropertyBuffer; BYTE bData = (BYTE)&((PBINDERYCLASSES)0)->cDataArea[0]; PCHAR pszData = &pbc->cDataArea[0]; DWORD err; DWORD iter; WORD port = 0, sap = 0; BOOL fIsSAP = FALSE; // // Check a few parameters . . . // if ( lpServiceClassInfo == NULL ) { SetLastError(WSA_INVALID_PARAMETER); return(SOCKET_ERROR); } if ( !lpServiceClassInfo->lpServiceClassId || !lpServiceClassInfo->lpszServiceClassName || ( lpServiceClassInfo->dwCount && !lpServiceClassInfo->lpClassInfos ) ) { SetLastError(WSA_INVALID_PARAMETER); return(SOCKET_ERROR); } // // Test to see if the ServiceClassId is TCP's, if so we don't allow // the service class installation since these are already present. // if ( GuidEqual( lpServiceClassInfo->lpServiceClassId, &HostAddrByInetStringGuid ) || GuidEqual( lpServiceClassInfo->lpServiceClassId, &ServiceByNameGuid ) || GuidEqual( lpServiceClassInfo->lpServiceClassId, &HostNameGuid ) || GuidEqual( lpServiceClassInfo->lpServiceClassId, &HostAddrByNameGuid ) ) { SetLastError(WSA_INVALID_PARAMETER); return(SOCKET_ERROR); } for( iter = 0; iter < lpServiceClassInfo->dwCount; iter++ ) { if ( lpServiceClassInfo->lpClassInfos[iter].dwNameSpace == NS_SAP || lpServiceClassInfo->lpClassInfos[iter].dwNameSpace == NS_ALL ) fIsSAP = TRUE; } if ( !fIsSAP ) { SetLastError(WSA_INVALID_PARAMETER); return(SOCKET_ERROR); } // // Find the SapId entry // for(pcli = lpServiceClassInfo->lpClassInfos; dwIndex; pcli++, dwIndex--) { WORD wTemp; if ( pcli->dwNameSpace == NS_SAP || pcli->dwNameSpace == NS_ALL ) { if(!_wcsicmp(pcli->lpszName, SERVICE_TYPE_VALUE_IPXPORTW) && (pcli->dwValueSize == sizeof(WORD))) { // // the value may not be aligned // ((PBYTE)&wTemp)[0] = ((PBYTE)pcli->lpValue)[0]; ((PBYTE)&wTemp)[1] = ((PBYTE)pcli->lpValue)[1]; port = wTemp; } else if(!_wcsicmp(pcli->lpszName, SERVICE_TYPE_VALUE_SAPIDW) && (pcli->dwValueSize >= sizeof(WORD))) { ((PBYTE)&wTemp)[0] = ((PBYTE)pcli->lpValue)[0]; ((PBYTE)&wTemp)[1] = ((PBYTE)pcli->lpValue)[1]; sap = wTemp; pcli1 = pcli; } } } if(!(pcli = pcli1)) { SetLastError(WSA_INVALID_PARAMETER); return(SOCKET_ERROR); } #if 0 // old way of doing this // // Found it. Build the property segment // memset(PropertyBuffer, 0, 128); // clear out everyting pbc->bOffset = bData; pbc->bSizeOfString = sizeof("Sapid"); pbc->bType = BT_WORD; // just a word, I assure you pbc->bSizeOfType = 2; pbc->wNameSpace = (WORD)NS_SAP; // it's us *(PWORD)pszData = htons(*(PWORD)pcli->lpValue); pszData += sizeof(WORD); // where the string goes strcpy(pszData, "SapId"); // pbc->bFlags = (BYTE)pcli->dwConnectionFlags; err = NwpSetClassInfo( lpServiceClassInfo->lpszServiceClassName, lpServiceClassInfo->lpServiceClassId, PropertyBuffer); #else err = NwpRnR2AddServiceType( lpServiceClassInfo->lpszServiceClassName, lpServiceClassInfo->lpServiceClassId, sap, port); #endif if(err != NO_ERROR) { SetLastError(err); err = (DWORD)SOCKET_ERROR; } return(err); } INT WINAPI NSPRemoveServiceClass( IN LPGUID lpProviderId, IN LPGUID lpServiceCallId ) { BOOL success; // // Do parameter checking // if ( lpServiceCallId == NULL ) { SetLastError( WSA_INVALID_PARAMETER ); return SOCKET_ERROR; } success = NwpRnR2RemoveServiceType( lpServiceCallId ); if ( success ) return( NO_ERROR ); else SetLastError(WSATYPE_NOT_FOUND); return (DWORD)SOCKET_ERROR; } INT WINAPI NSPGetServiceClassInfo( IN LPGUID lpProviderId, IN OUT LPDWORD lpdwBufSize, IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo ) { /*++ Routine Description: Get the ClassInfo for this type. Class info data may be in the registry, or available via SAP or the bindery. We try all three as appropriate --*/ BOOL fAdvert; return(pGetServiceClassInfo( lpProviderId, lpdwBufSize, lpServiceClassInfo, &fAdvert)); } INT WINAPI pGetServiceClassInfo( IN LPGUID lpProviderId, IN OUT LPDWORD lpdwBufSize, IN OUT LPWSASERVICECLASSINFOW lpServiceClassInfo, IN PBOOL pfAdvert ) { /*++ Routine Description: Get the ClassInfo for this type. Class info data may be in the registry, or available via SAP or the bindery. We try all three as appropriate --*/ DWORD err; LONG lInSize; LONG lSizeNeeded; PBYTE pbBuffer; GUID gdDummy; PWCHAR pwszUuid; LPGUID pType; WORD wSapId; WORD wPort; SOCKADDR_IPX sock; PWCHAR pwszSaveName = lpServiceClassInfo->lpszServiceClassName; #define SIZENEEDED (sizeof(WSASERVICECLASSINFO) + \ sizeof(WSANSCLASSINFO) + \ sizeof(WSANSCLASSINFO) + \ 10 + 2 + \ sizeof(GUID) + 12 + 2) *pfAdvert = FALSE; lInSize = (LONG)*lpdwBufSize - SIZENEEDED; pType = (LPGUID)(lpServiceClassInfo + 1); pbBuffer = (PBYTE)(pType + 1); if(lInSize < 0) { // // it is too small already // pType = &gdDummy; } if (UuidToString(lpServiceClassInfo->lpServiceClassId, &pwszUuid) != RPC_S_OK) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return SOCKET_ERROR; } // // First, try the bindery // err = NwpGetAddressByName(0, RNRCLASSSAPTYPE, pwszUuid, &sock); if(err == NO_ERROR) { wSapId = ntohs(*(PWORD)&sock.sa_netnum); wPort = ntohs(*(PWORD)&sock.sa_socket); } else { UCHAR Buffer[400]; DWORD dwLen = 400; DWORD dwNum; // // try SAP // err = NwpGetAddressViaSap(RNRCLASSSAPTYPE, pwszUuid, IPX_BIT, (PVOID)Buffer, &dwLen, 0, &dwNum); if((err == NO_ERROR) && (dwNum > 0) ) { PCSADDR_INFO psca = (PCSADDR_INFO)Buffer; PSOCKADDR_IPX psock = (PSOCKADDR_IPX)psca->RemoteAddr.lpSockaddr; wSapId = ntohs(*(PWORD)&psock->sa_netnum); wPort = ntohs(*(PWORD)&sock.sa_socket); } else { // // try the local bindery if(!NwpLookupSapInRegistry( lpServiceClassInfo->lpServiceClassId, &wSapId, &wPort, NULL)) { err = WSASERVICE_NOT_FOUND; } else { *pfAdvert = TRUE; err = NO_ERROR; } } } RpcStringFree(&pwszUuid); if(err != NO_ERROR) { SetLastError(err); err = (DWORD)SOCKET_ERROR; } else { // // we return the input structure and the found type. That's it. // The space needed is a constant since we don't return the name // if(lInSize < 0) { SetLastError(WSAEFAULT); *lpdwBufSize += (DWORD)(-lInSize); err = (DWORD)SOCKET_ERROR; } else { LPWSANSCLASSINFOW pci = (LPWSANSCLASSINFOW)pbBuffer; PUCHAR Buff; // // it will fit. SO let's go // if(wPort) { Buff = (PCHAR)(pci + 2); } else { Buff = (PCHAR)(pci + 1); } *pType = *lpServiceClassInfo->lpServiceClassId; lpServiceClassInfo->lpServiceClassId = pType; lpServiceClassInfo->lpszServiceClassName = 0; // not a lpServiceClassInfo->dwCount = 1; lpServiceClassInfo->lpClassInfos = pci; pci->dwNameSpace = NS_SAP; pci->dwValueType = REG_DWORD; pci->dwValueSize = 2; pci->lpszName = (LPWSTR)Buff; wcscpy((PWCHAR)Buff, L"SapId"); Buff += 6 * sizeof(WCHAR); pci->lpValue = (LPVOID)Buff; *(PWORD)Buff = wSapId; Buff += sizeof(WORD); if(wPort) { lpServiceClassInfo->dwCount++; pci++; pci->dwNameSpace = NS_SAP; pci->dwValueType = REG_DWORD; pci->dwValueSize = 2; pci->lpszName = (LPWSTR)Buff; wcscpy((PWCHAR)Buff, L"Port"); Buff += 5 * sizeof(WCHAR); pci->lpValue = (LPVOID)Buff; *(PWORD)Buff = wPort; } } } return(err); } INT WINAPI NSPStartup( IN LPGUID lpProviderId, IN OUT LPNSP_ROUTINE lpsnpRoutines) { // DWORD dwSize = min(sizeof(nsrVector), lpsnpRoutines->cbSize); DWORD dwSize = sizeof(nsrVector); RtlCopyMemory(lpsnpRoutines, &nsrVector, dwSize); return(NO_ERROR); } DWORD DoASap( IN PSAP_RNR_CONTEXT psrc, IN WORD QueryType, IN PBYTE * ppData, IN LPWSAQUERYSETW lpqsResults, IN PLONG plSpare, IN PDWORD lpdwBufferLength ) /*++ Small routine to construcst a SAP_BROADCAST pakcet and issue the SAP --*/ { DWORD err; if(!psrc->u_type.sbc.s) { // // this is the first time. We must init the // structure // err = SapGetSapSocket(&psrc->u_type.sbc.s); if(err) { psrc->u_type.sbc.s = 0; // make sure return(err); } psrc->u_type.sbc.Func = NSPpGotSap; psrc->u_type.sbc.fCheckCancel = NSPpCheckCancel; psrc->u_type.sbc.dwIndex = 0; // just in case. psrc->u_type.sbc.pvArg = (PVOID)lpqsResults; psrc->u_type.sbc.psrc = psrc; psrc->u_type.sbc.fFlags = 0; } psrc->u_type.sbc.wQueryType = QueryType; if(!psrc->u_type.sbc.psdNext1 && !(psrc->u_type.sbc.fFlags & SBC_FLAG_NOMORE)) { err = SapGetSapForType(&psrc->u_type.sbc, psrc->wSapId); } EnterCriticalSection(&psrc->u_type.sbc.csMonitor); if(psrc->u_type.sbc.psdNext1) { // // Got something to return. Let's do it // // // Assume we have to return the name // // // We have to convert the name to UNICODE so // we can return it to the caller. // // OEM_STRING Oem; NTSTATUS status; UNICODE_STRING UString; RtlInitAnsiString(&Oem, psrc->u_type.sbc.psdNext1->sapname); status = RtlOemStringToUnicodeString( &UString, &Oem, TRUE); if(NT_SUCCESS(status)) { if(psrc->wSapId == OT_DIRSERVER) { PWCHAR pwszTemp = &UString.Buffer[31]; while(*pwszTemp == L'_') { *pwszTemp-- = 0; } } err = pRnRReturnResults( UString.Buffer, &psrc->gdType, 0, // never a version ppData, plSpare, psrc->u_type.sbc.psdNext1->socketAddr, psrc->nProt, psrc->dwControlFlags, lpqsResults); RtlFreeUnicodeString(&UString); if(err == WSAEFAULT) { // // no room. Return buffer size required // *lpdwBufferLength = (DWORD)((LONG)*lpdwBufferLength - *plSpare); } } else { err = (DWORD)status; } if(err == NO_ERROR) { // // if we got it, step the item // psrc->u_type.sbc.psdNext1 = psrc->u_type.sbc.psdNext1->sapNext; } } else { err = (DWORD)WSA_E_NO_MORE; } LeaveCriticalSection(&psrc->u_type.sbc.csMonitor); return(err); } DWORD PrepareForSap( IN PSAP_RNR_CONTEXT psrc ) /*++ Called when there is no bindery or the bindery does not have the entry. This initializes the values needed for a SAP search --*/ { OEM_STRING OemServiceName; UNICODE_STRING UString; NTSTATUS status; // // the bindery didn't work. Use SAP. // psrc->u_type.sbc.dwIndex = psrc->u_type.sbc.dwTickCount = 0; if(psrc->wszContext[0]) { return(WSASERVICE_NOT_FOUND); // no contexts in SAP } RtlInitUnicodeString(&UString, psrc->chwName); status = RtlUnicodeStringToOemString(&OemServiceName, &UString, TRUE); if(!NT_SUCCESS(status)) { return( (DWORD)status); } strcpy((PCHAR)&psrc->chName, OemServiceName.Buffer); RtlFreeOemString(&OemServiceName); psrc->dwUnionType = LOOKUP_TYPE_SAP; psrc->u_type.sbc.s = 0; return(NO_ERROR); }