/***************************************************************************/ /* */ /* Project: OpenSLP - OpenSource implementation of Service Location */ /* Protocol */ /* */ /* File: libslp_knownda.c */ /* */ /* Abstract: Internal implementation for generating unique XIDs. */ /* Provides functions that are supposed to generate 16-bit */ /* values that won't be generated for a long time in this */ /* process and hopefully won't be generated by other process */ /* for a long time. */ /* */ /*-------------------------------------------------------------------------*/ /* */ /* Please submit patches to http://www.openslp.org */ /* */ /*-------------------------------------------------------------------------*/ /* */ /* Copyright (C) 2000 Caldera Systems, Inc */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following conditions are */ /* met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the */ /* distribution. */ /* */ /* Neither the name of Caldera Systems nor the names of its */ /* contributors may be used to endorse or promote products derived */ /* from this software without specific prior written permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA */ /* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /***************************************************************************/ #include "slp.h" #include "libslp.h" #include "slp_dhcp.h" #ifndef _WIN32 #define closesocket close #endif #include /*=========================================================================*/ SLPDatabase G_KnownDACache ={0,0,0}; /* The cache DAAdvert messages from known DAs. */ /*=========================================================================*/ /*=========================================================================*/ int G_KnownDAScopesLen = 0; char* G_KnownDAScopes = 0; /* Cached known scope list */ /*=========================================================================*/ /*=========================================================================*/ time_t G_KnownDALastCacheRefresh = 0; /* The time of the last Multicast for known DAs */ /*=========================================================================*/ /*-------------------------------------------------------------------------*/ SLPBoolean KnownDAListFind(int scopelistlen, const char* scopelist, int spistrlen, const char* spistr, struct in_addr* daaddr) /* Returns: non-zero on success, zero if DA can not be found */ /*-------------------------------------------------------------------------*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; int result = SLP_FALSE; dh = SLPDatabaseOpen(&G_KnownDACache); if(dh) { /*----------------------------------------*/ /* Check to see if there a matching entry */ /*----------------------------------------*/ while(1) { entry = SLPDatabaseEnum(dh); if(entry == NULL) break; /* Check scopes */ if(SLPSubsetStringList(entry->msg->body.daadvert.scopelistlen, entry->msg->body.daadvert.scopelist, scopelistlen, scopelist)) { #ifdef ENABLE_SLPv2_SECURITY if(SLPCompareString(entry->msg->body.daadvert.spilistlen, entry->msg->body.daadvert.spilist, spistrlen, spistr) == 0) #endif { memcpy(daaddr, &(entry->msg->peer.sin_addr), sizeof(struct in_addr)); result = SLP_TRUE; } } } SLPDatabaseClose(dh); } return result; } /*-------------------------------------------------------------------------*/ int KnownDAAdd(SLPMessage msg, SLPBuffer buf) /* Add an entry to the KnownDA cache */ /* */ /* Returns: zero on success, non-zero on error */ /*-------------------------------------------------------------------------*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; SLPDAAdvert* entrydaadvert; SLPDAAdvert* daadvert; int result; result = 0; dh = SLPDatabaseOpen(&G_KnownDACache); if(dh) { /* daadvert is the DAAdvert message being added */ daadvert = &(msg->body.daadvert); /*-----------------------------------------------------*/ /* Check to see if there is already an identical entry */ /*-----------------------------------------------------*/ while(1) { entry = SLPDatabaseEnum(dh); if(entry == NULL) break; /* entrydaadvert is the DAAdvert message from the database */ entrydaadvert = &(entry->msg->body.daadvert); /* Assume DAs are identical if their URLs match */ if(SLPCompareString(entrydaadvert->urllen, entrydaadvert->url, daadvert->urllen, daadvert->url) == 0) { SLPDatabaseRemove(dh,entry); break; } } /* Create and link in a new entry */ entry = SLPDatabaseEntryCreate(msg,buf); if(entry) { SLPDatabaseAdd(dh, entry); } else { result = SLP_MEMORY_ALLOC_FAILED; } SLPDatabaseClose(dh); } return result; } /*-------------------------------------------------------------------------*/ SLPBoolean KnownDADiscoveryCallback(SLPError errorcode, struct sockaddr_in* peerinfo, SLPBuffer rplybuf, void* cookie) /*-------------------------------------------------------------------------*/ { SLPMessage replymsg; SLPBuffer dupbuf; struct hostent* he; SLPSrvURL* srvurl; int* count; SLPBoolean result = SLP_TRUE; count = (int*)cookie; if(errorcode == 0) { dupbuf = SLPBufferDup(rplybuf); if(dupbuf) { replymsg = SLPMessageAlloc(); if(replymsg) { if(SLPMessageParseBuffer(peerinfo,dupbuf,replymsg) == 0 && replymsg->header.functionid == SLP_FUNCT_DAADVERT) { if(replymsg->body.daadvert.errorcode == 0) { /* TRICKY: NULL terminate the DA url */ ((char*)(replymsg->body.daadvert.url))[replymsg->body.daadvert.urllen] = 0; if(SLPParseSrvURL(replymsg->body.daadvert.url, &srvurl) == 0) { replymsg->peer.sin_addr.s_addr = 0; if(inet_aton(srvurl->s_pcHost, &(replymsg->peer.sin_addr)) == 0) { he = gethostbyname(srvurl->s_pcHost); if(he) { /* Reset the peer to the one in the URL */ replymsg->peer.sin_addr.s_addr = *((unsigned int*)(he->h_addr_list[0])); } } SLPFree(srvurl); if(replymsg->peer.sin_addr.s_addr) { (*count) += 1; KnownDAAdd(replymsg,dupbuf); if(replymsg->header.flags & SLP_FLAG_MCAST) { return SLP_FALSE; } return SLP_TRUE; } } } else if(replymsg->body.daadvert.errorcode == SLP_ERROR_INTERNAL_ERROR) { /* SLP_ERROR_INTERNAL_ERROR is a "end of stream" */ /* marker for looppack IPC */ result = SLP_FALSE; } } SLPMessageFree(replymsg); } SLPBufferFree(dupbuf); } } return result; } /*-------------------------------------------------------------------------*/ int KnownDADiscoveryRqstRply(int sock, struct sockaddr_in* peeraddr, int scopelistlen, #ifndef MI_NOT_SUPPORTED const char* scopelist, PSLPHandleInfo handle) #else const char* scopelist) #endif /* MI_NOT_SUPPORTED */ /* Returns: number of *new* DAEntries found */ /*-------------------------------------------------------------------------*/ { char* buf; char* curpos; int bufsize; int result = 0; /*-------------------------------------------------------------------*/ /* determine the size of the fixed portion of the SRVRQST */ /*-------------------------------------------------------------------*/ bufsize = 31; /* 2 bytes for the srvtype length */ /* 23 bytes for "service:directory-agent" srvtype */ /* 2 bytes for scopelistlen */ /* 2 bytes for predicatelen */ /* 2 bytes for sprstrlen */ bufsize += scopelistlen; /* TODO: make sure that we don't exceed the MTU */ buf = curpos = (char*)xmalloc(bufsize); if(buf == 0) { return 0; } memset(buf,0,bufsize); /*------------------------------------------------------------*/ /* Build a buffer containing the fixed portion of the SRVRQST */ /*------------------------------------------------------------*/ /* service type */ ToUINT16(curpos,23); curpos = curpos + 2; /* 23 is the length of SLP_DA_SERVICE_TYPE */ memcpy(curpos,SLP_DA_SERVICE_TYPE,23); curpos += 23; /* scope list */ ToUINT16(curpos,scopelistlen); curpos = curpos + 2; memcpy(curpos,scopelist,scopelistlen); /* predicate zero length */ /* spi list zero length */ if(sock == -1) { #ifndef MI_NOT_SUPPORTED NetworkMcastRqstRply(handle, #else NetworkMcastRqstRply("en", #endif /* MI_NOT_SUPPORTED */ buf, SLP_FUNCT_DASRVRQST, bufsize, KnownDADiscoveryCallback, &result); } else { NetworkRqstRply(sock, peeraddr, "en", 0, buf, SLP_FUNCT_DASRVRQST, bufsize, KnownDADiscoveryCallback, &result); } xfree(buf); return result; } /*-------------------------------------------------------------------------*/ #ifndef MI_NOT_SUPPORTED int KnownDADiscoverFromMulticast(int scopelistlen, const char* scopelist, PSLPHandleInfo handle) #else int KnownDADiscoverFromMulticast(int scopelistlen, const char* scopelist) #endif /* MI_NOT_SUPPORTED */ /* Locates DAs via multicast convergence */ /* */ /* Returns: number of *new* DAs found */ /*-------------------------------------------------------------------------*/ { int result = 0; if(SLPPropertyAsBoolean(SLPGetProperty("net.slp.activeDADetection")) && SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait"))) { result = KnownDADiscoveryRqstRply(-1, NULL, scopelistlen, #ifndef MI_NOT_SUPPORTED scopelist, handle); #else scopelist); #endif /* MI_NOT_SUPPORTED */ } return result; } /*-------------------------------------------------------------------------*/ #ifndef MI_NOT_SUPPORTED int KnownDADiscoverFromDHCP(PSLPHandleInfo handle) #else int KnownDADiscoverFromDHCP() #endif /* MI_NOT_SUPPORTED */ /* Locates DAs via DHCP */ /* */ /* Returns: number of *new* DAs found via DHCP. */ /*-------------------------------------------------------------------------*/ { int count = 0; int scopelistlen; DHCPContext ctx; unsigned char *alp; struct timeval timeout; struct sockaddr_in peeraddr; unsigned char dhcpOpts[] = {TAG_SLP_SCOPE, TAG_SLP_DA}; *ctx.scopelist = 0; ctx.addrlistlen = 0; DHCPGetOptionInfo(dhcpOpts, sizeof(dhcpOpts), DHCPParseSLPTags, &ctx); if(!*ctx.scopelist) { const char *slp = SLPGetProperty("net.slp.useScopes"); if(slp) strcpy(ctx.scopelist, slp); } scopelistlen = strlen(ctx.scopelist); memset(&peeraddr,0,sizeof(peeraddr)); peeraddr.sin_family = AF_INET; peeraddr.sin_port = htons(SLP_RESERVED_PORT); timeout.tv_sec = SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait")); timeout.tv_usec = (timeout.tv_sec % 1000) * 1000; timeout.tv_sec = timeout.tv_sec / 1000; alp = ctx.addrlist; while(ctx.addrlistlen >= 4) { memcpy(&peeraddr.sin_addr.s_addr, alp, 4); if(peeraddr.sin_addr.s_addr) { int sockfd; if((sockfd = SLPNetworkConnectStream(&peeraddr, &timeout)) >= 0) { count = KnownDADiscoveryRqstRply(sockfd, &peeraddr, scopelistlen, #ifndef MI_NOT_SUPPORTED ctx.scopelist, handle); #else ctx.scopelist); #endif /* MI_NOT_SUPPORTED */ closesocket(sockfd); if(scopelistlen && count) break; /* stop after the first set found */ } } ctx.addrlistlen -= 4; alp += 4; } return count; } /*-------------------------------------------------------------------------*/ int KnownDADiscoverFromProperties(int scopelistlen, #ifndef MI_NOT_SUPPORTED const char* scopelist, PSLPHandleInfo handle) #else const char* scopelist) #endif /* MI_NOT_SUPPORTED */ /* Locates DAs from the property list of DA hostnames */ /* */ /* Returns: number of *new* DAs found */ /*-------------------------------------------------------------------------*/ { char* temp; char* tempend; char* slider1; char* slider2; int sockfd; struct hostent* he; struct sockaddr_in peeraddr; struct timeval timeout; int result = 0; memset(&peeraddr,0,sizeof(peeraddr)); peeraddr.sin_family = AF_INET; peeraddr.sin_port = htons(SLP_RESERVED_PORT); slider1 = slider2 = temp = xstrdup(SLPGetProperty("net.slp.DAAddresses")); if(temp) { tempend = temp + strlen(temp); while(slider1 != tempend) { timeout.tv_sec = SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait")); timeout.tv_usec = (timeout.tv_sec % 1000) * 1000; timeout.tv_sec = timeout.tv_sec / 1000; while(*slider2 && *slider2 != ',') slider2++; *slider2 = 0; peeraddr.sin_addr.s_addr = 0; if(inet_aton(slider1, &(peeraddr.sin_addr)) == 0) { he = gethostbyname(slider1); if(he) { peeraddr.sin_addr.s_addr = *((unsigned int*)(he->h_addr_list[0])); } } if (peeraddr.sin_addr.s_addr) { sockfd = SLPNetworkConnectStream(&peeraddr,&timeout); if(sockfd >= 0) { result = KnownDADiscoveryRqstRply(sockfd, &peeraddr, scopelistlen, #ifndef MI_NOT_SUPPORTED scopelist, handle); #else scopelist); #endif closesocket(sockfd); if(scopelistlen && result) { /* return if we found at least one DA */ break; } } } slider1 = slider2; slider2++; } xfree(temp); } return result; } /*-------------------------------------------------------------------------*/ #ifndef MI_NOT_SUPPORTED int KnownDADiscoverFromIPC(PSLPHandleInfo handle) #else int KnownDADiscoverFromIPC() #endif /* Ask Slpd if it knows about a DA */ /* */ /* Returns: number of *new* DAs found */ /*-------------------------------------------------------------------------*/ { struct sockaddr_in peeraddr; int sockfd; int result = 0; sockfd = NetworkConnectToSlpd(&peeraddr); if(sockfd >= 0) { #ifndef MI_NOT_SUPPORTED result = KnownDADiscoveryRqstRply(sockfd, &peeraddr, 0, "", handle); #else result = KnownDADiscoveryRqstRply(sockfd, &peeraddr, 0, ""); #endif closesocket(sockfd); } return result; } /*-------------------------------------------------------------------------*/ SLPBoolean KnownDAFromCache(int scopelistlen, const char* scopelist, int spistrlen, const char* spistr, #ifndef MI_NOT_SUPPORTED struct in_addr* daaddr, PSLPHandleInfo handle) #else struct in_addr* daaddr) #endif /* MI_NOT_SUPPORTED */ /* Ask Slpd if it knows about a DA */ /* */ /* Returns: non-zero on success, zero if DA can not be found */ /*-------------------------------------------------------------------------*/ { time_t curtime; if(KnownDAListFind(scopelistlen, scopelist, spistrlen, spistr, daaddr) == SLP_FALSE) { curtime = time(&curtime); if(G_KnownDALastCacheRefresh == 0 || curtime - G_KnownDALastCacheRefresh > MINIMUM_DISCOVERY_INTERVAL) { G_KnownDALastCacheRefresh = curtime; /* discover DAs */ #ifndef MI_NOT_SUPPORTED if(KnownDADiscoverFromIPC(handle) == 0) if(KnownDADiscoverFromProperties(scopelistlen, scopelist, handle) == 0) if(KnownDADiscoverFromDHCP(handle) == 0) KnownDADiscoverFromMulticast(scopelistlen, scopelist, handle); #else if(KnownDADiscoverFromIPC() == 0) if(KnownDADiscoverFromProperties(scopelistlen, scopelist) == 0) if(KnownDADiscoverFromDHCP() == 0) KnownDADiscoverFromMulticast(scopelistlen, scopelist); #endif } return KnownDAListFind(scopelistlen, scopelist, spistrlen, spistr, daaddr); } return SLP_TRUE; } /*=========================================================================*/ int KnownDAConnect(PSLPHandleInfo handle, int scopelistlen, const char* scopelist, struct sockaddr_in* peeraddr) /* Get a connected socket to a DA that supports the specified scope */ /* */ /* scopelistlen (IN) stringlen of the scopelist */ /* */ /* scopelist (IN) DA must support this scope */ /* */ /* peeraddr (OUT) the peer that was connected to */ /* */ /* */ /* returns: valid socket file descriptor or -1 if no DA is found */ /*=========================================================================*/ { struct timeval timeout; int sock = -1; int spistrlen = 0; char* spistr = 0; #ifdef ENABLE_SLPv2_SECURITY if(SLPPropertyAsBoolean(SLPGetProperty("net.slp.securityEnabled"))) { SLPSpiGetDefaultSPI(handle->hspi, SLPSPI_KEY_TYPE_PUBLIC, &spistrlen, &spistr); } #endif /* Set up connect timeout */ timeout.tv_sec = SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait")); timeout.tv_usec = (timeout.tv_sec % 1000) * 1000; timeout.tv_sec = timeout.tv_sec / 1000; while(1) { memset(peeraddr,0,sizeof(peeraddr)); if(KnownDAFromCache(scopelistlen, scopelist, spistrlen, spistr, #ifndef MI_NOT_SUPPORTED &(peeraddr->sin_addr), handle) == 0) #else &(peeraddr->sin_addr)) == 0) #endif /* MI_NOT_SUPPORTED */ { break; } peeraddr->sin_family = PF_INET; peeraddr->sin_port = htons(SLP_RESERVED_PORT); sock = SLPNetworkConnectStream(peeraddr,&timeout); if(sock >= 0) { break; } KnownDABadDA(&(peeraddr->sin_addr)); } #ifdef ENABLE_SLPv2_SECURITY if(spistr) xfree(spistr); #endif return sock; } /*=========================================================================*/ void KnownDABadDA(struct in_addr* daaddr) /* Mark a KnownDA as a Bad DA. */ /* */ /* daaddr (IN) address of the bad DA */ /* */ /* Returns: none */ /*=========================================================================*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; dh = SLPDatabaseOpen(&G_KnownDACache); if(dh) { /*-----------------------------------*/ /* Check to find the requested entry */ /*-----------------------------------*/ while(1) { entry = SLPDatabaseEnum(dh); if(entry == NULL) break; /* Assume DAs are identical if their in_addrs match */ if(memcmp(daaddr,&(entry->msg->peer.sin_addr),sizeof(struct in_addr)) == 0) { SLPDatabaseRemove(dh,entry); break; } } SLPDatabaseClose(dh); } } /*=========================================================================*/ int KnownDAGetScopes(int* scopelistlen, #ifndef MI_NOT_SUPPORTED char** scopelist, PSLPHandleInfo handle) #else char** scopelist) #endif /* Gets a list of scopes from the known DA list */ /* */ /* scopelistlen (OUT) stringlen of the scopelist */ /* */ /* scopelist (OUT) NULL terminated list of scopes */ /* */ /* returns: zero on success, non-zero on failure */ /*=========================================================================*/ { int newlen; SLPDatabaseHandle dh; SLPDatabaseEntry* entry; /* discover all DAs */ #ifndef MI_NOT_SUPPORTED if(KnownDADiscoverFromIPC(handle) == 0) #else if(KnownDADiscoverFromIPC() == 0) #endif { #ifndef MI_NOT_SUPPORTED KnownDADiscoverFromDHCP(handle); KnownDADiscoverFromProperties(0,"", handle); KnownDADiscoverFromMulticast(0,"", handle); #else KnownDADiscoverFromDHCP(); KnownDADiscoverFromProperties(0,""); KnownDADiscoverFromMulticast(0,""); #endif } /* enumerate through all the knownda entries and generate a */ /* scopelist */ dh = SLPDatabaseOpen(&G_KnownDACache); if(dh) { /*-----------------------------------*/ /* Check to find the requested entry */ /*-----------------------------------*/ while(1) { entry = SLPDatabaseEnum(dh); if(entry == NULL) break; newlen = G_KnownDAScopesLen; while(SLPUnionStringList(G_KnownDAScopesLen, G_KnownDAScopes, entry->msg->body.daadvert.scopelistlen, entry->msg->body.daadvert.scopelist, &newlen, G_KnownDAScopes) < 0) { G_KnownDAScopes = xrealloc(G_KnownDAScopes,newlen); if(G_KnownDAScopes == 0) { G_KnownDAScopesLen = 0; break; } } G_KnownDAScopesLen = newlen; } SLPDatabaseClose(dh); } /* Explicitly add in the useScopes property */ newlen = G_KnownDAScopesLen; while(SLPUnionStringList(G_KnownDAScopesLen, G_KnownDAScopes, strlen(SLPPropertyGet("net.slp.useScopes")), SLPPropertyGet("net.slp.useScopes"), &newlen, G_KnownDAScopes) < 0) { G_KnownDAScopes = xrealloc(G_KnownDAScopes,newlen); if(G_KnownDAScopes == 0) { G_KnownDAScopesLen = 0; break; } } G_KnownDAScopesLen = newlen; if(G_KnownDAScopesLen) { *scopelist = xmalloc(G_KnownDAScopesLen + 1); if(*scopelist == 0) { return -1; } memcpy(*scopelist,G_KnownDAScopes, G_KnownDAScopesLen); (*scopelist)[G_KnownDAScopesLen] = 0; *scopelistlen = G_KnownDAScopesLen; } else { *scopelist = xstrdup(""); if(*scopelist == 0) { return -1; } *scopelistlen = 0; } return 0; } /*=========================================================================*/ void KnownDAProcessSrvRqst(PSLPHandleInfo handle) /* Process a SrvRqst for service:directory-agent */ /* */ /* handle (IN) the handle used to make the SrvRqst */ /* */ /* returns: none */ /*=========================================================================*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; SLPBoolean cb_result; char tmp; /* discover all DAs */ #ifndef MI_NOT_SUPPORTED if(KnownDADiscoverFromIPC(handle) == 0) #else if(KnownDADiscoverFromIPC() == 0) #endif { #ifndef MI_NOT_SUPPORTED KnownDADiscoverFromDHCP(handle); KnownDADiscoverFromProperties(0,"", handle); KnownDADiscoverFromMulticast(0,"", handle); #else KnownDADiscoverFromDHCP(); KnownDADiscoverFromProperties(0,""); KnownDADiscoverFromMulticast(0,""); #endif } /* Enumerate through knownDA database */ dh = SLPDatabaseOpen(&G_KnownDACache); if(dh) { /* Check to see if there a matching entry */ while(1) { entry = SLPDatabaseEnum(dh); /* is there anything left? */ if(entry == NULL) break; /* TRICKY temporary null termination of DA url */ tmp = entry->msg->body.daadvert.url[entry->msg->body.daadvert.urllen]; ((char*)(entry->msg->body.daadvert.url))[entry->msg->body.daadvert.urllen] = 0; /* Call the SrvURLCallback */ cb_result = handle->params.findsrvs.callback((SLPHandle)handle, entry->msg->body.daadvert.url, SLP_LIFETIME_MAXIMUM, SLP_OK, handle->params.findsrvs.cookie); /* TRICKY: undo temporary null termination of DA url */ ((char*)(entry->msg->body.daadvert.url))[entry->msg->body.daadvert.urllen] = tmp; /* does the caller want more? */ if(cb_result == SLP_FALSE) { break; } } SLPDatabaseClose(dh); } /* Make SLP_LAST_CALL */ handle->params.findsrvs.callback((SLPHandle)handle, NULL, 0, SLP_LAST_CALL, handle->params.findsrvs.cookie); } #ifdef DEBUG /*=========================================================================*/ void KnownDAFreeAll() /* Frees all (cached) resources associated with known DAs */ /* */ /* returns: none */ /*=========================================================================*/ { SLPDatabaseHandle dh; SLPDatabaseEntry* entry; dh = SLPDatabaseOpen(&G_KnownDACache); if(dh) { while(1) { entry = SLPDatabaseEnum(dh); if(entry == NULL) break; SLPDatabaseRemove(dh,entry); } SLPDatabaseClose(dh); } if(G_KnownDAScopes) xfree(G_KnownDAScopes); G_KnownDAScopesLen = 0; G_KnownDALastCacheRefresh = 0; } #endif