1 /*-------------------------------------------------------------------------
2 * Copyright (C) 2000 Caldera Systems, Inc
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of Caldera Systems nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA
24 * SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *-------------------------------------------------------------------------*/
32
33 /** Find server types.
34 *
35 * Implementation for SLPFindSrvType() call.
36 *
37 * @file libslp_findsrvtypes.c
38 * @author Matthew Peterson, John Calcote (jcalcote@novell.com)
39 * @attention Please submit patches to http://www.openslp.org
40 * @ingroup LibSLPCode
41 */
42
43 #include "slp.h"
44 #include "libslp.h"
45 #include "slp_net.h"
46 #include "slp_property.h"
47 #include "slp_xmalloc.h"
48 #include "slp_compare.h"
49 #include "slp_message.h"
50
51 /** Collates response data to user callback for SLPFindSrvType requests.
52 *
53 * @param[in] hSLP - The SLP handle object associated with the request.
54 * @param[in] pcSrvTypes - The service type for this pass.
55 * @param[in] errorcode - The error code received on this pass.
56 *
57 * @return An SLP boolean value; SLP_TRUE indicates we are finished;
58 * SLP_FALSE indicates we should continue.
59 *
60 * @todo Trace the logic of CollateToSLPSrvTypeCallback to ensure that
61 * it works.
62 *
63 * @internal
64 */
CollateToSLPSrvTypeCallback(SLPHandle hSLP,const char * pcSrvTypes,SLPError errorcode)65 static SLPBoolean CollateToSLPSrvTypeCallback(SLPHandle hSLP,
66 const char * pcSrvTypes, SLPError errorcode)
67 {
68 int maxResults;
69 char * srvtypes;
70 size_t srvtypeslen;
71 SLPHandleInfo * handle = hSLP;
72
73 handle->callbackcount++;
74
75 #ifdef ENABLE_ASYNC_API
76 /* Do not collate for async calls. */
77 if (handle->isAsync)
78 return handle->params.findsrvtypes.callback(hSLP, pcSrvTypes,
79 errorcode, handle->params.findsrvtypes.cookie);
80 #endif
81
82 /* Configure behaviour for desired max results. */
83 maxResults = SLPPropertyAsInteger("net.slp.maxResults");
84 if (maxResults == -1)
85 maxResults = INT_MAX;
86
87 if (errorcode == SLP_LAST_CALL || handle->callbackcount > maxResults)
88 {
89 /* We're done. Send back the collated srvtype string. */
90 if (handle->collatedsrvtypes)
91 if (handle->params.findsrvtypes.callback(handle,
92 handle->collatedsrvtypes, SLP_OK,
93 handle->params.findsrvtypes.cookie) == SLP_TRUE)
94 handle->params.findsrvtypes.callback(handle, 0,
95 SLP_LAST_CALL, handle->params.findsrvtypes.cookie);
96
97 /* Free the collatedsrvtype string. */
98 if (handle->collatedsrvtypes)
99 {
100 xfree(handle->collatedsrvtypes);
101 handle->collatedsrvtypes = 0;
102 }
103 handle->callbackcount = 0;
104 return SLP_FALSE;
105 }
106 else if (errorcode != SLP_OK)
107 return SLP_TRUE;
108
109 /* Add the service types to the colation. */
110 srvtypeslen = strlen(pcSrvTypes) + 1; /* +1 - terminator */
111 if (handle->collatedsrvtypes)
112 srvtypeslen += strlen(handle->collatedsrvtypes) + 1; /* +1 - comma */
113
114 srvtypes = xmalloc(srvtypeslen);
115 if (srvtypes)
116 {
117 if (handle->collatedsrvtypes)
118 {
119 if (SLPUnionStringList(strlen(handle->collatedsrvtypes),
120 handle->collatedsrvtypes, strlen(pcSrvTypes), pcSrvTypes,
121 &srvtypeslen, srvtypes) != (int)srvtypeslen)
122 {
123 xfree(handle->collatedsrvtypes);
124 handle->collatedsrvtypes = srvtypes;
125 }
126 else
127 {
128 #ifndef COLLATION_CHANGES
129 xfree(handle->collatedsrvtypes);
130 handle->collatedsrvtypes = srvtypes;
131 handle->collatedsrvtypes[srvtypeslen] = 0;
132 #else
133 xfree(srvtypes);
134 #endif
135 }
136 }
137 else
138 {
139 strcpy(srvtypes, pcSrvTypes);
140 handle->collatedsrvtypes = srvtypes;
141 }
142 }
143 return SLP_TRUE;
144 }
145
146 /** SLPFindSrvTypes callback routine for NetworkRqstRply.
147 *
148 * @param[in] errorcode - The network operation error code.
149 * @param[in] peerinfo - The network address of the responder.
150 * @param[in] replybuf - The response buffer from the network request.
151 * @param[in] cookie - Callback context data from ProcessSrvReg.
152 *
153 * @return SLP_FALSE (to stop any iterative callbacks).
154 *
155 * @internal
156 */
ProcessSrvTypeRplyCallback(SLPError errorcode,void * peerinfo,SLPBuffer replybuf,void * cookie)157 static SLPBoolean ProcessSrvTypeRplyCallback(SLPError errorcode,
158 void * peerinfo, SLPBuffer replybuf, void * cookie)
159 {
160 SLPMessage * replymsg;
161 SLPBoolean result = SLP_TRUE;
162 SLPHandleInfo * handle = (SLPHandleInfo *)cookie;
163
164 /* Check the errorcode and bail if it is set. */
165 if (errorcode)
166 return CollateToSLPSrvTypeCallback(handle, 0, errorcode);
167
168 /* Parse the replybuf. */
169 replymsg = SLPMessageAlloc();
170 if (replymsg)
171 {
172 if (!SLPMessageParseBuffer(peerinfo, 0, replybuf, replymsg)
173 && replymsg->header.functionid == SLP_FUNCT_SRVTYPERPLY
174 && !replymsg->body.srvtyperply.errorcode)
175 {
176 SLPSrvTypeRply * srvtyperply = &replymsg->body.srvtyperply;
177 if (srvtyperply->srvtypelistlen)
178 result = CollateToSLPSrvTypeCallback((SLPHandle)handle,
179 srvtyperply->srvtypelist, srvtyperply->errorcode * -1);
180 }
181 SLPMessageFree(replymsg);
182 }
183 return result;
184 }
185
186 /** Formats and sends an SLPFindSrvTypes wire buffer request.
187 *
188 * @param handle - The OpenSLP session handle, containing request
189 * parameters. See docs for SLPFindSrvTypes.
190 *
191 * @return Zero on success, or an SLP API error code.
192 *
193 * @internal
194 */
ProcessSrvTypeRqst(SLPHandleInfo * handle)195 static SLPError ProcessSrvTypeRqst(SLPHandleInfo * handle)
196 {
197 sockfd_t sock;
198 uint8_t * buf;
199 uint8_t * curpos;
200 SLPError serr = SLP_OK;
201 struct sockaddr_storage peeraddr;
202 struct sockaddr_in* destaddrs = 0;
203
204 /* 0 1 2 3
205 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
206 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
207 | length of Naming Authority | <Naming Authority String> \
208 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
209 | length of <scope-list> | <scope-list> String \
210 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
211
212 /** @todo Ensure that we don't exceed the MTU. */
213
214 buf = curpos = xmalloc(
215 + 2 + handle->params.findsrvtypes.namingauthlen
216 + 2 + handle->params.findsrvtypes.scopelistlen);
217 if (buf == 0)
218 return SLP_MEMORY_ALLOC_FAILED;
219
220 /* Naming Authority */
221 if (strcmp(handle->params.findsrvtypes.namingauth, "*") == 0)
222 PutUINT16(&curpos, 0xffff); /* 0xffff is wildcard */
223 else
224 PutL16String(&curpos, handle->params.findsrvtypes.namingauth,
225 handle->params.findsrvtypes.namingauthlen);
226
227 /* <scope-list> */
228 PutL16String(&curpos, handle->params.findsrvtypes.scopelist,
229 handle->params.findsrvtypes.scopelistlen);
230
231 /* Send request, receive reply. */
232 do
233 {
234 #ifndef UNICAST_NOT_SUPPORTED
235 if (handle->dounicast == 1)
236 {
237 serr = NetworkUcastRqstRply(handle, buf, SLP_FUNCT_SRVTYPERQST,
238 curpos - buf, ProcessSrvTypeRplyCallback, handle, false);
239 break;
240 }
241 if (SLPNetIsIPV4())
242 {
243 if (KnownDASpanningListFromCache(handle,
244 (int)handle->params.findsrvs.scopelistlen,
245 handle->params.findsrvs.scopelist,
246 &destaddrs) > 0)
247 {
248 serr = NetworkMultiUcastRqstRply(destaddrs,
249 handle->langtag,
250 (char*)buf,
251 SLP_FUNCT_SRVTYPERQST,
252 curpos - buf,
253 ProcessSrvTypeRplyCallback,
254 handle, false);
255 xfree(destaddrs);
256 break;
257 }
258 }
259 #endif
260 sock = NetworkConnectToDA(handle,
261 handle->params.findsrvtypes.scopelist,
262 handle->params.findsrvtypes.scopelistlen,
263 &peeraddr);
264
265 if (sock == SLP_INVALID_SOCKET)
266 {
267 serr = NetworkMcastRqstRply(handle, buf, SLP_FUNCT_SRVTYPERQST,
268 curpos - buf, ProcessSrvTypeRplyCallback, 0, false);
269 break;
270 }
271 serr = NetworkRqstRply(sock, &peeraddr, handle->langtag, 0, buf,
272 SLP_FUNCT_SRVTYPERQST, curpos - buf, ProcessSrvTypeRplyCallback,
273 handle, false);
274
275 if (serr)
276 NetworkDisconnectDA(handle);
277
278 } while (serr == SLP_NETWORK_ERROR);
279
280 xfree(buf);
281 return serr;
282 }
283
284 #ifdef ENABLE_ASYNC_API
285 /** Thread start procedure for asynchronous service type request.
286 *
287 * @param[in,out] handle - Contains the request parameters, returns the
288 * request result.
289 *
290 * @return An SLPError code.
291 *
292 * @internal
293 */
AsyncProcessSrvTypeRqst(SLPHandleInfo * handle)294 static SLPError AsyncProcessSrvTypeRqst(SLPHandleInfo * handle)
295 {
296 SLPError result = ProcessSrvTypeRqst(handle);
297 xfree((void *)handle->params.findsrvtypes.namingauth);
298 xfree((void *)handle->params.findsrvtypes.scopelist);
299 handle->inUse = SLP_FALSE;
300 return result;
301 }
302 #endif
303
304 /** Return a list of service types available on the network.
305 *
306 * The SLPFindSrvType function issues an SLP service type request for
307 * service types in the scopes indicated by the @p pcScopeList. The
308 * results are returned through the @p callback parameter. The service
309 * types are independent of language locale, but only for services
310 * registered in one of scopes and for the indicated naming authority.
311 *
312 * @par
313 * If the naming authority is "*", then results are returned for all
314 * naming authorities. If the naming authority is the empty string,
315 * i.e. "", then the default naming authority, "IANA", is used. "IANA"
316 * is not a valid naming authority name, and it is a PARAMETER_BAD error
317 * to include it explicitly.
318 *
319 * @par
320 * The service type names are returned with the naming authority intact.
321 * If the naming authority is the default (i.e. empty string) then it
322 * is omitted, as is the separating ".". Service type names from URLs
323 * of the service: scheme are returned with the "service:" prefix
324 * intact. [RFC 2608] See [RFC 2609] for more information on the
325 * syntax of service type names.
326 *
327 * @param[in] hSLP - The SLPHandle on which to search for types.
328 * @param[in] pcNamingAuthority - The naming authority to search. Use "*"
329 * for all naming authorities and the empty string, "", for the default
330 * naming authority.
331 * @param[in] pcScopeList - A pointer to a char containing comma separated
332 * list of scope names to search for service types. May not be the empty
333 * string, "".
334 * @param[in] callback - A callback function through which the results of
335 * the operation are reported.
336 * @param[in] pvCookie - Memory passed to the @p callback code from the
337 * client. May be NULL.
338 *
339 * @return If an error occurs in starting the operation, one of the
340 * SLPError codes is returned.
341 */
SLPFindSrvTypes(SLPHandle hSLP,const char * pcNamingAuthority,const char * pcScopeList,SLPSrvTypeCallback callback,void * pvCookie)342 SLPError SLPAPI SLPFindSrvTypes(
343 SLPHandle hSLP,
344 const char * pcNamingAuthority,
345 const char * pcScopeList,
346 SLPSrvTypeCallback callback,
347 void * pvCookie)
348 {
349 bool inuse;
350 SLPError serr = 0;
351 SLPHandleInfo * handle = hSLP;
352
353 /* Check for invalid parameters. */
354 SLP_ASSERT(handle != 0);
355 SLP_ASSERT(handle->sig == SLP_HANDLE_SIG);
356 SLP_ASSERT(pcNamingAuthority != 0);
357 SLP_ASSERT(strcmp(pcNamingAuthority, "IANA") != 0);
358 SLP_ASSERT(callback != 0);
359
360 if (handle == 0 || handle->sig != SLP_HANDLE_SIG
361 || pcNamingAuthority == 0
362 || strcmp(pcNamingAuthority, "IANA") == 0
363 || callback == 0)
364 return SLP_PARAMETER_BAD;
365
366 /* Check to see if the handle is in use. */
367 inuse = SLPSpinLockTryAcquire(&handle->inUse);
368 SLP_ASSERT(!inuse);
369 if (inuse)
370 return SLP_HANDLE_IN_USE;
371
372 /* Get a scope list if none was specified. */
373 if (pcScopeList == 0 || *pcScopeList == 0)
374 pcScopeList = SLPPropertyGet("net.slp.useScopes", 0, 0);
375
376 /* Set the handle up to reference parameters. */
377 handle->params.findsrvtypes.namingauthlen = strlen(pcNamingAuthority);
378 handle->params.findsrvtypes.namingauth = pcNamingAuthority;
379 handle->params.findsrvtypes.scopelistlen = strlen(pcScopeList);
380 handle->params.findsrvtypes.scopelist = pcScopeList;
381 handle->params.findsrvtypes.callback = callback;
382 handle->params.findsrvtypes.cookie = pvCookie;
383
384 /* Check to see if we should be async or sync. */
385 #ifdef ENABLE_ASYNC_API
386 if (handle->isAsync)
387 {
388 /* Copy all the referenced parameters. */
389 handle->params.findsrvtypes.namingauth =
390 xstrdup(handle->params.findsrvtypes.namingauth);
391 handle->params.findsrvtypes.scopelist =
392 xstrdup(handle->params.findsrvtypes.scopelist);
393
394 /* Ensure strdups and thread create succeed. */
395 if (handle->params.findsrvtypes.namingauth == 0
396 || handle->params.findsrvtypes.scopelist == 0
397 || (handle->th = SLPThreadCreate((SLPThreadStartProc)
398 AsyncProcessSrvTypeRqst, handle)) == 0)
399 {
400 serr = SLP_MEMORY_ALLOC_FAILED;
401 xfree((void *)handle->params.findsrvtypes.namingauth);
402 xfree((void *)handle->params.findsrvtypes.scopelist);
403 SLPSpinLockRelease(&handle->inUse);
404 }
405 return serr;
406 }
407 #endif
408
409 /* Reference all parameters. */
410 serr = ProcessSrvTypeRqst(handle);
411 SLPSpinLockRelease(&handle->inUse);
412 return serr;
413 }
414
415 /*=========================================================================*/
416