1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <syslog.h> 30 #include <slp-internal.h> 31 32 static SLPBoolean UnpackSrvTypesReply(slp_handle_impl_t *, char *, 33 SLPSrvTypeCallback, void *, 34 void **, int *); 35 static SLPError slp_packSrvTypeRqst(slp_handle_impl_t *, const char *); 36 static char *collate_types(char *, void **, int *, int); 37 static char *build_types_list(void *); 38 static void collect_types(void *, VISIT, int, void *); 39 40 SLPError SLPFindSrvTypes(SLPHandle hSLP, const char *pcNamingAuthority, 41 const char *pcScopeList, 42 SLPSrvTypeCallback callback, void *pvUser) { 43 SLPError err; 44 45 if (!hSLP || !pcNamingAuthority || !pcScopeList || 46 !*pcScopeList || !callback) { 47 return (SLP_PARAMETER_BAD); 48 } 49 50 if ((strlen(pcNamingAuthority) > SLP_MAX_STRINGLEN) || 51 (strlen(pcScopeList) > SLP_MAX_STRINGLEN)) { 52 return (SLP_PARAMETER_BAD); 53 } 54 55 if ((err = slp_start_call(hSLP)) != SLP_OK) 56 return (err); 57 58 /* format params into msgBuf */ 59 err = slp_packSrvTypeRqst(hSLP, pcNamingAuthority); 60 61 if (err == SLP_OK) 62 err = slp_ua_common(hSLP, pcScopeList, 63 (SLPGenericAppCB *) callback, pvUser, 64 (SLPMsgReplyCB *) UnpackSrvTypesReply); 65 66 if (err != SLP_OK) 67 slp_end_call(hSLP); 68 69 return (err); 70 } 71 72 static SLPBoolean UnpackSrvTypesReply(slp_handle_impl_t *hp, char *reply, 73 SLPSrvTypeCallback cb, void *cookie, 74 void **collator, int *numResults) { 75 char *pcSrvTypes; 76 SLPError errCode; 77 unsigned short protoErrCode; 78 size_t off, len; 79 int maxResults = slp_get_maxResults(); 80 SLPBoolean cont = SLP_TRUE; 81 82 if (!reply) { 83 /* no more results */ 84 if (!hp->async) { 85 pcSrvTypes = build_types_list(*collator); 86 } 87 88 if (!hp->async && pcSrvTypes) { 89 /* synchronous case */ 90 cb(hp, pcSrvTypes, SLP_OK, cookie); 91 free(pcSrvTypes); 92 } 93 cb(hp, NULL, SLP_LAST_CALL, cookie); 94 return (SLP_FALSE); 95 } 96 97 /* parse reply into params */ 98 len = slp_get_length(reply); 99 off = SLP_HDRLEN + slp_get_langlen(reply); 100 /* error code */ 101 if (slp_get_sht(reply, len, &off, &protoErrCode) != SLP_OK) 102 return (SLP_TRUE); 103 /* internal errors should have been filtered out by the net code */ 104 if ((errCode = slp_map_err(protoErrCode)) != SLP_OK) { 105 return (cb(hp, NULL, errCode, cookie)); 106 } 107 108 /* types string */ 109 if (slp_get_string(reply, len, &off, &pcSrvTypes) != SLP_OK) 110 return (SLP_TRUE); 111 112 /* collate the types for sync behavior */ 113 if (!hp->async) { 114 pcSrvTypes = collate_types(pcSrvTypes, collator, 115 numResults, maxResults); 116 if (!pcSrvTypes) 117 return (SLP_TRUE); 118 } else { 119 /* async; invoke cb */ 120 cont = cb((SLPHandle) hp, pcSrvTypes, errCode, cookie); 121 } 122 123 /* cleanup */ 124 free(pcSrvTypes); 125 126 /* check maxResults */ 127 if (!hp->internal_call && *numResults == maxResults) { 128 return (SLP_FALSE); 129 } 130 131 return (cont); 132 } 133 134 static SLPError slp_packSrvTypeRqst(slp_handle_impl_t *hp, const char *na) { 135 SLPError err; 136 size_t len, nalen, msgLen, tmplen; 137 int all_nas; 138 slp_msg_t *msg = &(hp->msg); 139 140 /* 141 * Allocate iovec for the message. A SrvTypeRqst is layed out thus: 142 * 0: header 143 * 1: prlist length 144 * 2: prlist (filled in later by networking code) 145 * 3: na 146 * 4: scopes length 147 * 5: scopes (filled in later by networking code) 148 */ 149 if (!(msg->iov = calloc(6, sizeof (*(msg->iov))))) { 150 slp_err(LOG_CRIT, 0, "slp_packSrvTypeRqst", "out of memory"); 151 return (SLP_MEMORY_ALLOC_FAILED); 152 } 153 msg->iovlen = 6; 154 155 /* calculate msg length */ 156 all_nas = strcmp(na, "*") == 0 ? 1 : 0; 157 if (all_nas) { 158 nalen = 0; 159 } else { 160 nalen = strlen(na); 161 } 162 nalen += 2; 163 164 msgLen = 2 + /* prlist length */ 165 nalen + /* NA string */ 166 2; /* Scope string length */ 167 168 if (!(msg->msg = calloc(1, msgLen))) { 169 free(msg->iov); 170 slp_err(LOG_CRIT, 0, "slp_packSrvTypeRqst", "out of memory"); 171 return (SLP_MEMORY_ALLOC_FAILED); 172 } 173 174 /* set pointer to PR list and scope list length spaces */ 175 msg->prlistlen.iov_base = msg->msg; 176 msg->prlistlen.iov_len = 2; 177 msg->iov[1].iov_base = msg->msg; 178 msg->iov[1].iov_len = 2; 179 180 msg->scopeslen.iov_base = msg->msg + 2; 181 msg->scopeslen.iov_len = 2; 182 msg->iov[4].iov_base = msg->msg + 2; 183 msg->iov[4].iov_len = 2; 184 185 /* set up the scopes and prlist pointers into iov */ 186 msg->prlist = &(msg->iov[2]); 187 msg->scopes = &(msg->iov[5]); 188 189 len = 4; 190 191 /* set up NA string in iovec */ 192 msg->iov[3].iov_base = msg->msg + len; 193 tmplen = len; 194 195 if (all_nas) { 196 err = slp_add_sht(msg->msg, msgLen, 0xffff, &len); 197 } else { 198 err = slp_add_string(msg->msg, msgLen, na, &len); 199 } 200 msg->iov[3].iov_len = len - tmplen; 201 202 hp->fid = SRVTYPERQST; 203 if (err == SLP_OK) { 204 return (SLP_OK); 205 } 206 207 /* else error */ 208 free(msg->iov); 209 free(msg->msg); 210 211 return (err); 212 } 213 214 /* 215 * Using the collator, determines which types in the types list 216 * have already been recieved, and composes a new list of the remaining 217 * (unique) types. If there are no unique types, returns NULL; 218 * types is destructively modified. 219 */ 220 static char *collate_types(char *types, void **collator, 221 int *numResults, int maxResults) { 222 char *p, *s, **res, *utypes = NULL; 223 224 /* walk through the types list */ 225 p = types; 226 for (s = types; p && *numResults != maxResults; s = p) { 227 p = slp_utf_strchr(s, ','); 228 if (p) 229 *p++ = 0; 230 if (!(s = strdup(s))) { 231 free(types); 232 if (utypes) free(utypes); 233 slp_err(LOG_CRIT, 0, "collate_types", "out of memory"); 234 return (NULL); 235 } 236 /* search the tree for this type */ 237 res = slp_tsearch((void *) s, collator, 238 (int (*)(const void *, const void *)) slp_strcasecmp); 239 if (*res == s) { 240 /* first time we've encountered this type */ 241 slp_add2list(s, &utypes, SLP_FALSE); 242 (*numResults)++; 243 } else { 244 /* else already in tree */ 245 free(s); 246 } 247 } 248 free(types); 249 return (utypes); 250 } 251 252 /* 253 * This is used after all types have been collated into the tree. 254 * It walks through the tree, composing a list from all the types in 255 * the tree, and freeing each node of the tree as it goes. 256 * Returns the list, or NULL if the tree is empty. 257 */ 258 /* the walk action function: */ 259 /*ARGSUSED*/ 260 static void collect_types(void *node, VISIT order, int level, void *cookie) { 261 char **types = (char **)cookie; 262 263 if (order == endorder || order == leaf) { 264 char *t = *(char **)node; 265 slp_add2list(t, types, SLP_FALSE); 266 free(t); 267 free(node); 268 } 269 } 270 271 /* the walk driver: */ 272 static char *build_types_list(void *collator) { 273 char *types = NULL; 274 275 if (!collator) 276 return (NULL); 277 slp_twalk(collator, collect_types, 0, (void *) &types); 278 return (types); 279 } 280