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