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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Miscellaneous Utilities
32 * slp_err: Error and information message dispatch, i18n'd
33 * slp_start_call: Marks a SLP handle as in-use
34 * slp_end_call: Marks a SLP handle as available
35 * slp_map_err: protocol to API error mapping
36 * slp_onlist: determines if a token is on a list
37 * slp_add2list: adds a token to a list
38 * slp_list_subtract: removes a token from a list
39 * slp_add_header: creates a SLP message header
40 * slp_get_length: gets the length field from a SLP header
41 * slp_set_length: sets the length field in a SLP header
42 * slp_header_get_sht: gets a 16 bit integer from a SLP header
43 * slp_header_set_sht: sets a 16 bit interger in a SLP header
44 * slp_header_length: calculates the length of a header, including the
46 * slp_get_errcode: returns the error code from a SLP message
47 * slp_add_byte: encodes a byte into the given buffer
48 * slp_add_sht: encodes a 16-bit integer into the given buffer
49 * slp_add_string: encodes the given string into the given buffer
50 * slp_get_byte: decodes a byte from the given buffer
51 * slp_get_sht: decodes a 16-bit integer from the given buffer
52 * slp_get_string: decodes a string from the given buffer
65 #include <arpa/inet.h>
67 #include <slp-internal.h>
69 #define SLP_ERR_BUF_LEN 1024UL
72 * Outputs an error message. priority is a syslog(3) priority.
76 void slp_err(int priority
, int id
, char *func
, char *inmsg
, ...) {
77 static char buf
[SLP_ERR_BUF_LEN
];
81 static mutex_t loglock
= DEFAULTMUTEX
;
84 (void) mutex_lock(&loglock
);
87 msg
= dgettext("libslp", inmsg
);
89 (void) snprintf(buf
, sizeof (buf
), "libslp: %s: ", func
);
92 (void) vsnprintf(p
, SLP_ERR_BUF_LEN
- len
, msg
, ap
);
94 syslog(priority
, buf
);
95 (void) mutex_unlock(&loglock
);
99 * Start and end slp calls
100 * slp_start_call returns SLP_HANDLE_IN_USE if the handle is already
101 * being used, otherwise SLP_OK.
103 SLPError
slp_start_call(slp_handle_impl_t
*hp
) {
104 (void) mutex_lock(&(hp
->outcall_lock
));
105 if (hp
->pending_outcall
) {
106 (void) mutex_unlock(&(hp
->outcall_lock
));
107 return (SLP_HANDLE_IN_USE
);
109 hp
->pending_outcall
= SLP_TRUE
;
110 (void) mutex_unlock(&(hp
->outcall_lock
));
116 void slp_end_call(slp_handle_impl_t
*hp
) {
117 (void) mutex_lock(&(hp
->outcall_lock
));
118 if (hp
->close_on_end
) {
119 /* SLPClose() called from callback */
120 (void) mutex_unlock(&(hp
->outcall_lock
));
121 slp_cleanup_handle(hp
);
125 hp
->pending_outcall
= SLP_FALSE
;
126 (void) cond_signal(&(hp
->outcall_cv
));
127 (void) mutex_unlock(&(hp
->outcall_lock
));
131 * Map a protocol error code to an API error code.
133 SLPError
slp_map_err(unsigned short proto_err
) {
135 case 0: return (SLP_OK
);
136 case 1: return (SLP_LANGUAGE_NOT_SUPPORTED
);
137 case 2: return (SLP_PARSE_ERROR
);
138 case 3: return (SLP_INVALID_REGISTRATION
);
139 case 4: return (SLP_SCOPE_NOT_SUPPORTED
);
140 case 6: return (SLP_AUTHENTICATION_ABSENT
);
141 case 7: return (SLP_AUTHENTICATION_FAILED
);
142 case 13: return (SLP_INVALID_UPDATE
);
144 * 9 (VER_NOT_SUPPORTED), 10 (INTERNAL_ERROR),
145 * 11 (DA_BUSY_NOW), 12 (OPTION_NOT_UNDERSTOOD),
146 * and 14 (RQST_NOT_SUPPORTED)
147 * should be handled internally by the API.
149 default: return (SLP_INTERNAL_SYSTEM_ERROR
);
154 * SLP List Management:
155 * SLP lists are comma separated lists of tokens. The following routines
156 * manage SLP lists, ensuring proper UTF-8 parsing.
160 * If 'item' is on 'list', returns 1, otherwise 0.
162 int slp_onlist(const char *item
, const char *list
) {
164 for (p
= (char *)list
; p
; p
++) {
169 p
= slp_utf_strchr(p
, ',');
170 span
= (p
? (size_t)(p
- s
): strlen(s
));
172 if (strlen(item
) != span
) {
179 if (strncasecmp(item
, s
, span
) == 0)
188 * Adds item to *list if it is not already on it. If *list == NULL,
189 * creates a new list. When it grows the list, it will free *list,
190 * so *list must not be on the caller's stack. 'check_onlist' specifies
191 * whether to look to item on the current list. This is a small
192 * optimization for callers which are that item is not on *list, or
193 * which don't care about duplicates.
195 void slp_add2list(const char *item
, char **list
, SLPBoolean check_onlist
) {
197 if (!(*list
= strdup(item
)))
198 slp_err(LOG_CRIT
, 0, "slp_add2list", "out of memory");
204 if (slp_onlist(item
, *list
))
207 if (!(*list
= realloc(*list
, strlen(*list
) + strlen(item
) + 2))) {
208 slp_err(LOG_CRIT
, 0, "slp_add2list", "out of memory");
211 (void) strcat(*list
, ",");
212 (void) strcat(*list
, item
);
216 * Removes the first instance of item from *list.
217 * When it shrinks the list, it may free *list, so *list must not be on
218 * the caller's stack.
220 void slp_list_subtract(const char *item
, char **list
) {
223 if (!*list
|| !slp_onlist(item
, *list
))
225 /* find item's location on the list */
226 for (p
= *list
; p
; p
++) {
230 p
= slp_utf_strchr(p
, ',');
231 span
= (p
? (size_t)(p
- s
) : strlen(s
));
232 if (strlen(item
) != span
)
234 if (strncasecmp(item
, s
, span
) == 0)
239 if (!p
&& s
== *list
) {
240 /* item is only one on list */
246 /* last one on list; just chop it off */
251 /* either first on list, or somewhere in the middle */
252 (void) strcpy(s
, p
+ 1);
255 /* SLPv2 header management */
258 * Lays a SLP header into pcSendBuf, performing byte-ordering and bounds
259 * checking where necessary.
260 * pcLangTag: Language tag
261 * pcSendBuf: a buffer into which to write the composed header
262 * iSendBufSz: the size of pcSendBuf in bytes
263 * iFun: SLP V2 function number
264 * iLen: The length of the whole SLP message, in bytes
265 * piLen: a pointer to an int into which will be written the size of the
266 * header + the language tag (i.e. the offset at which the rest of
267 * the message should be written into pcSendBuf).
269 SLPError
slp_add_header(const char *pcLangTag
, char *pcSendBuf
,
270 size_t iSendBufSz
, int iFun
,
271 size_t iLen
, size_t *piLen
) {
272 unsigned short us
, xid
;
273 static unsigned short xid_seeded
= 0;
276 static mutex_t lock
= DEFAULTMUTEX
;
277 (void) mutex_lock(&lock
);
279 /* generate a seed based on our PID */
280 long long pid
= getpid();
282 (void) seed48((unsigned short *) &pid
);
285 (void) mutex_unlock(&lock
);
287 /* squish the random value into an unsigned short */
288 xid
= (unsigned short) (lrand48() % USHRT_MAX
);
289 xid
= xid
? xid
: 1; /* 0 is for DAs only */
291 us
= (unsigned short) strlen(pcLangTag
);
292 if ((SLP_HDRLEN
+ us
) > iSendBufSz
)
293 return (SLP_PARAMETER_BAD
);
295 (void) memset(pcSendBuf
, 0, SLP_HDRLEN
);
297 slp_set_version(pcSendBuf
, SLP_VERSION
);
298 slp_set_function(pcSendBuf
, (char)iFun
);
299 slp_set_length(pcSendBuf
, iLen
);
300 slp_set_xid(pcSendBuf
, xid
);
301 slp_set_langlen(pcSendBuf
, us
);
302 (void) memcpy(&pcSendBuf
[SLP_HDRLEN
], pcLangTag
, us
);
304 *piLen
= SLP_HDRLEN
+ us
;
309 * Retrieves the 24 bit int stored at 'off' offset into 'header'.
310 * Assumes 'header' is a valid SLP message header.
312 unsigned int slp_header_get_int24(const char *header
, size_t off
) {
315 len
= ((unsigned int)(header
[off
] & 0xff)) << 16;
316 len
+= ((unsigned int)(header
[off
+ 1] & 0xff)) << 8;
317 len
+= ((unsigned int)(header
[off
+ 2] & 0xff));
323 * Sets a 24 bit int at the location in 'header' 'off' bytes
324 * offset into the header.
325 * Assumes 'header' is a valid SLP message header.
327 void slp_header_set_int24(char *header
, unsigned int len
, size_t off
) {
328 header
[off
] = (unsigned char) ((len
& 0xff0000) >> 16);
329 header
[off
+ 1] = (unsigned char) ((len
& 0xff00) >> 8);
330 header
[off
+ 2] = (unsigned char) (len
& 0xff);
334 * Retrieves the 16 bit integer stored at 'off' offset into 'header'.
335 * Assumes 'header' is a valid SLP message header.
337 unsigned short slp_header_get_sht(const char *header
, size_t off
) {
338 unsigned short answer
= 0;
339 (void) slp_get_sht(header
, SLP_HDRLEN
, &off
, &answer
);
344 * Sets a 16 bit interger at the location in 'header' 'off' bytes
345 * offset into the header.
346 * Assumes 'header' is a valid SLP message header.
348 void slp_header_set_sht(char *header
, unsigned short len
, size_t off
) {
349 (void) slp_add_sht(header
, SLP_HDRLEN
, len
, &off
);
353 * Returns the total length of a SLP header associated with the SLP
354 * handle 'hp', including the language tag.
356 size_t slp_header_length(slp_handle_impl_t
*hp
) {
357 return (SLP_HDRLEN
+ strlen(hp
->locale
));
361 * Retrieves the error code for UA replies -- the errcode is always
362 * the first short after the header for these functions. 'msg' points to
363 * the beginning of a SLP header.
365 slp_proto_err
slp_get_errcode(char *msg
) {
366 unsigned short langlen
, errcode
;
369 /* make sure the reply is long enough */
370 msglen
= slp_get_length(msg
);
371 if (msglen
< (SLP_LANGLEN
+ 2))
372 return (SLP_MSG_PARSE_ERROR
);
373 langlen
= slp_get_langlen(msg
);
374 off
= SLP_HDRLEN
+ langlen
;
376 if (slp_get_sht(msg
, msglen
, &off
, &errcode
) != SLP_OK
)
377 return (SLP_MSG_PARSE_ERROR
);
383 * Primitive Encoding and Decoding Routines.
384 * All perform byte-ordering coversions and bounds checking.
387 SLPError
slp_add_byte(char *pcBuf
, size_t iBufSz
, int iVal
,
389 if ((*piLen
+ 1) > iBufSz
)
390 return (SLP_PARAMETER_BAD
);
392 pcBuf
[(*piLen
)++] = (unsigned char) iVal
;
396 SLPError
slp_add_sht(char *pcBuf
, size_t iBufSz
, unsigned short iVal
,
398 if ((*piLen
+ 2) > iBufSz
)
399 return (SLP_PARAMETER_BAD
);
401 pcBuf
[(*piLen
)++] = (unsigned char) ((iVal
& 0xFF00) >> 8);
402 pcBuf
[(*piLen
)++] = (unsigned char) (iVal
& 0xFF);
406 SLPError
slp_add_int32(char *pcBuf
, size_t iBufSz
, unsigned int iVal
,
408 if ((*piLen
+ 4) > iBufSz
)
409 return (SLP_PARAMETER_BAD
);
411 pcBuf
[(*piLen
)++] = (unsigned char) ((iVal
& 0xFF000000) >> 24);
412 pcBuf
[(*piLen
)++] = (unsigned char) ((iVal
& 0xFF0000) >> 16);
413 pcBuf
[(*piLen
)++] = (unsigned char) ((iVal
& 0xFF00) >> 8);
414 pcBuf
[(*piLen
)++] = (unsigned char) (iVal
& 0xFF);
419 SLPError
slp_add_string(char *pcBuf
, size_t iBufSz
, const char *pcStr
,
421 size_t iStrLen
= strlen(pcStr
);
424 if (iStrLen
> USHRT_MAX
)
425 /* SLP strings are limited to 16-bit len */
426 return (SLP_PARAMETER_BAD
);
427 if ((iStrLen
+ *piLen
+ 2) > iBufSz
)
428 return (SLP_PARAMETER_BAD
);
430 if ((err
= slp_add_sht(pcBuf
, iBufSz
, (unsigned short)iStrLen
, piLen
))
434 (void) memcpy(&(pcBuf
[*piLen
]), pcStr
, iStrLen
);
439 SLPError
slp_get_byte(const char *pcBuf
, size_t maxlen
,
440 size_t *piOffset
, int *piByte
) {
443 if (piOffset
!= NULL
) {
444 if ((*piOffset
+1) > maxlen
)
445 return (SLP_PARSE_ERROR
);
450 *piByte
= (int)pcBuf
[offset
];
454 SLPError
slp_get_sht(const char *pcBuf
, size_t maxlen
,
455 size_t *piOffset
, unsigned short *piSht
) {
458 if (piOffset
!= NULL
) {
459 if ((*piOffset
+2) > maxlen
)
460 return (SLP_PARSE_ERROR
);
465 *piSht
= (unsigned short)
466 ((unsigned char)pcBuf
[offset
] & (unsigned char)0xFF);
468 *piSht
+= (unsigned short)
469 ((unsigned char)pcBuf
[offset
+1] & (unsigned char)0xFF);
474 SLPError
slp_get_int32(const char *pcBuf
, size_t maxlen
,
475 size_t *piOffset
, unsigned int *piInt
) {
478 if (piOffset
!= NULL
) {
479 if ((*piOffset
+4) > maxlen
)
480 return (SLP_PARSE_ERROR
);
485 *piInt
= ((unsigned int)(pcBuf
[offset
] & 0xff)) << 24;
486 *piInt
+= ((unsigned int)(pcBuf
[offset
+1] & 0xff)) << 16;
487 *piInt
+= ((unsigned int)(pcBuf
[offset
+2] & 0xff)) << 8;
488 *piInt
+= ((unsigned int)(pcBuf
[offset
+3] & 0xff));
493 SLPError
slp_get_string(const char *pcBuf
, size_t iMaxLen
,
494 size_t *piOffset
, char **ppcString
) {
499 err
= slp_get_sht(pcBuf
, iMaxLen
, piOffset
, &iLen
);
502 if ((iLen
+*piOffset
) > iMaxLen
)
503 return (SLP_PARSE_ERROR
);
505 if (!(*ppcString
= malloc(iLen
+ 1))) {
506 slp_err(LOG_CRIT
, 0, "slp_get_string", "out of memory");
507 return (SLP_MEMORY_ALLOC_FAILED
);
509 (void) memcpy(*ppcString
, pcBuf
+ *piOffset
, iLen
);
510 (*ppcString
)[iLen
] = 0;