summaryrefslogtreecommitdiff
path: root/usr/src/lib/libslp/clib/slp_utils.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libslp/clib/slp_utils.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libslp/clib/slp_utils.c')
-rw-r--r--usr/src/lib/libslp/clib/slp_utils.c513
1 files changed, 513 insertions, 0 deletions
diff --git a/usr/src/lib/libslp/clib/slp_utils.c b/usr/src/lib/libslp/clib/slp_utils.c
new file mode 100644
index 0000000000..04a4f1a00b
--- /dev/null
+++ b/usr/src/lib/libslp/clib/slp_utils.c
@@ -0,0 +1,513 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Miscellaneous Utilities
+ *
+ * slp_err: Error and information message dispatch, i18n'd
+ * slp_start_call: Marks a SLP handle as in-use
+ * slp_end_call: Marks a SLP handle as available
+ * slp_map_err: protocol to API error mapping
+ * slp_onlist: determines if a token is on a list
+ * slp_add2list: adds a token to a list
+ * slp_list_subtract: removes a token from a list
+ * slp_add_header: creates a SLP message header
+ * slp_get_length: gets the length field from a SLP header
+ * slp_set_length: sets the length field in a SLP header
+ * slp_header_get_sht: gets a 16 bit integer from a SLP header
+ * slp_header_set_sht: sets a 16 bit interger in a SLP header
+ * slp_header_length: calculates the length of a header, including the
+ * language tag
+ * slp_get_errcode: returns the error code from a SLP message
+ * slp_add_byte: encodes a byte into the given buffer
+ * slp_add_sht: encodes a 16-bit integer into the given buffer
+ * slp_add_string: encodes the given string into the given buffer
+ * slp_get_byte: decodes a byte from the given buffer
+ * slp_get_sht: decodes a 16-bit integer from the given buffer
+ * slp_get_string: decodes a string from the given buffer
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <string.h>
+#include <thread.h>
+#include <synch.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <arpa/inet.h>
+#include <libintl.h>
+#include <slp-internal.h>
+
+#define SLP_ERR_BUF_LEN 1024UL
+
+/*
+ * Outputs an error message. priority is a syslog(3) priority.
+ */
+/*ARGSUSED1*/
+/* PRINTFLIKE4 */
+void slp_err(int priority, int id, char *func, char *inmsg, ...) {
+ static char buf[SLP_ERR_BUF_LEN];
+ char *p, *msg;
+ size_t len;
+ va_list ap;
+ static mutex_t loglock = DEFAULTMUTEX;
+ va_start(ap, inmsg);
+
+ (void) mutex_lock(&loglock);
+
+ /* i18n mapping */
+ msg = dgettext("libslp", inmsg);
+
+ (void) snprintf(buf, sizeof (buf), "libslp: %s: ", func);
+ len = strlen(buf);
+ p = &(buf[len]);
+ (void) vsnprintf(p, SLP_ERR_BUF_LEN - len, msg, ap);
+ va_end(ap);
+ syslog(priority, buf);
+ (void) mutex_unlock(&loglock);
+}
+
+/*
+ * Start and end slp calls
+ * slp_start_call returns SLP_HANDLE_IN_USE if the handle is already
+ * being used, otherwise SLP_OK.
+ */
+SLPError slp_start_call(slp_handle_impl_t *hp) {
+ (void) mutex_lock(&(hp->outcall_lock));
+ if (hp->pending_outcall) {
+ (void) mutex_unlock(&(hp->outcall_lock));
+ return (SLP_HANDLE_IN_USE);
+ }
+ hp->pending_outcall = SLP_TRUE;
+ (void) mutex_unlock(&(hp->outcall_lock));
+
+ hp->cancel = 0;
+ return (SLP_OK);
+}
+
+void slp_end_call(slp_handle_impl_t *hp) {
+ (void) mutex_lock(&(hp->outcall_lock));
+ if (hp->close_on_end) {
+ /* SLPClose() called from callback */
+ (void) mutex_unlock(&(hp->outcall_lock));
+ slp_cleanup_handle(hp);
+ return;
+ }
+
+ hp->pending_outcall = SLP_FALSE;
+ (void) cond_signal(&(hp->outcall_cv));
+ (void) mutex_unlock(&(hp->outcall_lock));
+}
+
+/*
+ * Map a protocol error code to an API error code.
+ */
+SLPError slp_map_err(unsigned short proto_err) {
+ switch (proto_err) {
+ case 0: return (SLP_OK);
+ case 1: return (SLP_LANGUAGE_NOT_SUPPORTED);
+ case 2: return (SLP_PARSE_ERROR);
+ case 3: return (SLP_INVALID_REGISTRATION);
+ case 4: return (SLP_SCOPE_NOT_SUPPORTED);
+ case 6: return (SLP_AUTHENTICATION_ABSENT);
+ case 7: return (SLP_AUTHENTICATION_FAILED);
+ case 13: return (SLP_INVALID_UPDATE);
+ /*
+ * 9 (VER_NOT_SUPPORTED), 10 (INTERNAL_ERROR),
+ * 11 (DA_BUSY_NOW), 12 (OPTION_NOT_UNDERSTOOD),
+ * and 14 (RQST_NOT_SUPPORTED)
+ * should be handled internally by the API.
+ */
+ default: return (SLP_INTERNAL_SYSTEM_ERROR);
+ }
+}
+
+/*
+ * SLP List Management:
+ * SLP lists are comma separated lists of tokens. The following routines
+ * manage SLP lists, ensuring proper UTF-8 parsing.
+ */
+
+/*
+ * If 'item' is on 'list', returns 1, otherwise 0.
+ */
+int slp_onlist(const char *item, const char *list) {
+ char *p;
+ for (p = (char *)list; p; p++) {
+ char *s;
+ size_t span;
+
+ s = p;
+ p = slp_utf_strchr(p, ',');
+ span = (p ? (size_t)(p - s): strlen(s));
+
+ if (strlen(item) != span) {
+ if (!p)
+ break;
+ else
+ continue;
+ }
+
+ if (strncasecmp(item, s, span) == 0)
+ return (1);
+ if (!p)
+ break;
+ }
+ return (0);
+}
+
+/*
+ * Adds item to *list if it is not already on it. If *list == NULL,
+ * creates a new list. When it grows the list, it will free *list,
+ * so *list must not be on the caller's stack. 'check_onlist' specifies
+ * whether to look to item on the current list. This is a small
+ * optimization for callers which are that item is not on *list, or
+ * which don't care about duplicates.
+ */
+void slp_add2list(const char *item, char **list, SLPBoolean check_onlist) {
+ if (!(*list)) {
+ if (!(*list = strdup(item)))
+ slp_err(LOG_CRIT, 0, "slp_add2list", "out of memory");
+ return;
+ }
+
+ if (check_onlist)
+ /* no duplicates */
+ if (slp_onlist(item, *list))
+ return;
+
+ if (!(*list = realloc(*list, strlen(*list) + strlen(item) + 2))) {
+ slp_err(LOG_CRIT, 0, "slp_add2list", "out of memory");
+ return;
+ }
+ (void) strcat(*list, ",");
+ (void) strcat(*list, item);
+}
+
+/*
+ * Removes the first instance of item from *list.
+ * When it shrinks the list, it may free *list, so *list must not be on
+ * the caller's stack.
+ */
+void slp_list_subtract(const char *item, char **list) {
+ char *p, *s;
+
+ if (!*list || !slp_onlist(item, *list))
+ return;
+ /* find item's location on the list */
+ for (p = *list; p; p++) {
+ size_t span;
+
+ s = p;
+ p = slp_utf_strchr(p, ',');
+ span = (p ? (size_t)(p - s) : strlen(s));
+ if (strlen(item) != span)
+ continue;
+ if (strncasecmp(item, s, span) == 0)
+ break;
+ if (!p)
+ break;
+ }
+ if (!p && s == *list) {
+ /* item is only one on list */
+ free(*list);
+ *list = NULL;
+ return;
+ }
+ if (!p) {
+ /* last one on list; just chop it off */
+ s--;
+ *s = 0;
+ return;
+ }
+ /* either first on list, or somewhere in the middle */
+ (void) strcpy(s, p + 1);
+}
+
+/* SLPv2 header management */
+
+/*
+ * Lays a SLP header into pcSendBuf, performing byte-ordering and bounds
+ * checking where necessary.
+ * pcLangTag: Language tag
+ * pcSendBuf: a buffer into which to write the composed header
+ * iSendBufSz: the size of pcSendBuf in bytes
+ * iFun: SLP V2 function number
+ * iLen: The length of the whole SLP message, in bytes
+ * piLen: a pointer to an int into which will be written the size of the
+ * header + the language tag (i.e. the offset at which the rest of
+ * the message should be written into pcSendBuf).
+ */
+SLPError slp_add_header(const char *pcLangTag, char *pcSendBuf,
+ size_t iSendBufSz, int iFun,
+ size_t iLen, size_t *piLen) {
+ unsigned short us, xid;
+ static unsigned short xid_seeded = 0;
+
+ if (!xid_seeded) {
+ static mutex_t lock = DEFAULTMUTEX;
+ (void) mutex_lock(&lock);
+ if (!xid_seeded) {
+ /* generate a seed based on our PID */
+ long long pid = getpid();
+ pid *= UINT_MAX;
+ (void) seed48((unsigned short *) &pid);
+ xid_seeded = 1;
+ }
+ (void) mutex_unlock(&lock);
+ }
+ /* squish the random value into an unsigned short */
+ xid = (unsigned short) (lrand48() % USHRT_MAX);
+ xid = xid ? xid : 1; /* 0 is for DAs only */
+
+ us = (unsigned short) strlen(pcLangTag);
+ if ((SLP_HDRLEN + us) > iSendBufSz)
+ return (SLP_PARAMETER_BAD);
+
+ (void) memset(pcSendBuf, 0, SLP_HDRLEN);
+
+ slp_set_version(pcSendBuf, SLP_VERSION);
+ slp_set_function(pcSendBuf, (char)iFun);
+ slp_set_length(pcSendBuf, iLen);
+ slp_set_xid(pcSendBuf, xid);
+ slp_set_langlen(pcSendBuf, us);
+ (void) memcpy(&pcSendBuf[SLP_HDRLEN], pcLangTag, us);
+
+ *piLen = SLP_HDRLEN + us;
+ return (SLP_OK);
+}
+
+/*
+ * Retrieves the 24 bit int stored at 'off' offset into 'header'.
+ * Assumes 'header' is a valid SLP message header.
+ */
+unsigned int slp_header_get_int24(const char *header, size_t off) {
+ unsigned int len;
+
+ len = ((unsigned int)(header[off] & 0xff)) << 16;
+ len += ((unsigned int)(header[off + 1] & 0xff)) << 8;
+ len += ((unsigned int)(header[off + 2] & 0xff));
+
+ return (len);
+}
+
+/*
+ * Sets a 24 bit int at the location in 'header' 'off' bytes
+ * offset into the header.
+ * Assumes 'header' is a valid SLP message header.
+ */
+void slp_header_set_int24(char *header, unsigned int len, size_t off) {
+ header[off] = (unsigned char) ((len & 0xff0000) >> 16);
+ header[off + 1] = (unsigned char) ((len & 0xff00) >> 8);
+ header[off + 2] = (unsigned char) (len & 0xff);
+}
+
+/*
+ * Retrieves the 16 bit integer stored at 'off' offset into 'header'.
+ * Assumes 'header' is a valid SLP message header.
+ */
+unsigned short slp_header_get_sht(const char *header, size_t off) {
+ unsigned short answer = 0;
+ (void) slp_get_sht(header, SLP_HDRLEN, &off, &answer);
+ return (answer);
+}
+
+/*
+ * Sets a 16 bit interger at the location in 'header' 'off' bytes
+ * offset into the header.
+ * Assumes 'header' is a valid SLP message header.
+ */
+void slp_header_set_sht(char *header, unsigned short len, size_t off) {
+ (void) slp_add_sht(header, SLP_HDRLEN, len, &off);
+}
+
+/*
+ * Returns the total length of a SLP header associated with the SLP
+ * handle 'hp', including the language tag.
+ */
+size_t slp_header_length(slp_handle_impl_t *hp) {
+ return (SLP_HDRLEN + strlen(hp->locale));
+}
+
+/*
+ * Retrieves the error code for UA replies -- the errcode is always
+ * the first short after the header for these functions. 'msg' points to
+ * the beginning of a SLP header.
+ */
+slp_proto_err slp_get_errcode(char *msg) {
+ unsigned short langlen, errcode;
+ size_t off, msglen;
+
+ /* make sure the reply is long enough */
+ msglen = slp_get_length(msg);
+ if (msglen < (SLP_LANGLEN + 2))
+ return (SLP_MSG_PARSE_ERROR);
+ langlen = slp_get_langlen(msg);
+ off = SLP_HDRLEN + langlen;
+
+ if (slp_get_sht(msg, msglen, &off, &errcode) != SLP_OK)
+ return (SLP_MSG_PARSE_ERROR);
+
+ return (errcode);
+}
+
+/*
+ * Primitive Encoding and Decoding Routines.
+ * All perform byte-ordering coversions and bounds checking.
+ */
+
+SLPError slp_add_byte(char *pcBuf, size_t iBufSz, int iVal,
+ size_t *piLen) {
+ if ((*piLen + 1) > iBufSz)
+ return (SLP_PARAMETER_BAD);
+
+ pcBuf[(*piLen)++] = (unsigned char) iVal;
+ return (SLP_OK);
+}
+
+SLPError slp_add_sht(char *pcBuf, size_t iBufSz, unsigned short iVal,
+ size_t *piLen) {
+ if ((*piLen + 2) > iBufSz)
+ return (SLP_PARAMETER_BAD);
+
+ pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF00) >> 8);
+ pcBuf[(*piLen)++] = (unsigned char) (iVal & 0xFF);
+ return (SLP_OK);
+}
+
+SLPError slp_add_int32(char *pcBuf, size_t iBufSz, unsigned int iVal,
+ size_t *piLen) {
+ if ((*piLen + 4) > iBufSz)
+ return (SLP_PARAMETER_BAD);
+
+ pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF000000) >> 24);
+ pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF0000) >> 16);
+ pcBuf[(*piLen)++] = (unsigned char) ((iVal & 0xFF00) >> 8);
+ pcBuf[(*piLen)++] = (unsigned char) (iVal & 0xFF);
+
+ return (SLP_OK);
+}
+
+SLPError slp_add_string(char *pcBuf, size_t iBufSz, const char *pcStr,
+ size_t *piLen) {
+ size_t iStrLen = strlen(pcStr);
+ SLPError err = 0;
+
+ if (iStrLen > USHRT_MAX)
+ /* SLP strings are limited to 16-bit len */
+ return (SLP_PARAMETER_BAD);
+ if ((iStrLen + *piLen + 2) > iBufSz)
+ return (SLP_PARAMETER_BAD);
+
+ if ((err = slp_add_sht(pcBuf, iBufSz, (unsigned short)iStrLen, piLen))
+ != SLP_OK)
+ return (err);
+
+ (void) memcpy(&(pcBuf[*piLen]), pcStr, iStrLen);
+ *piLen += iStrLen;
+ return (SLP_OK);
+}
+
+SLPError slp_get_byte(const char *pcBuf, size_t maxlen,
+ size_t *piOffset, int *piByte) {
+ size_t offset = 0;
+
+ if (piOffset != NULL) {
+ if ((*piOffset+1) > maxlen)
+ return (SLP_PARSE_ERROR);
+ offset = *piOffset;
+ *piOffset += 1;
+ }
+
+ *piByte = (int)pcBuf[offset];
+ return (SLP_OK);
+}
+
+SLPError slp_get_sht(const char *pcBuf, size_t maxlen,
+ size_t *piOffset, unsigned short *piSht) {
+ size_t offset = 0;
+
+ if (piOffset != NULL) {
+ if ((*piOffset+2) > maxlen)
+ return (SLP_PARSE_ERROR);
+ offset = *piOffset;
+ *piOffset += 2;
+ }
+
+ *piSht = (unsigned short)
+ ((unsigned char)pcBuf[offset] & (unsigned char)0xFF);
+ *piSht <<= 8;
+ *piSht += (unsigned short)
+ ((unsigned char)pcBuf[offset+1] & (unsigned char)0xFF);
+
+ return (SLP_OK);
+}
+
+SLPError slp_get_int32(const char *pcBuf, size_t maxlen,
+ size_t *piOffset, unsigned int *piInt) {
+ size_t offset = 0;
+
+ if (piOffset != NULL) {
+ if ((*piOffset+4) > maxlen)
+ return (SLP_PARSE_ERROR);
+ offset = *piOffset;
+ *piOffset += 4;
+ }
+
+ *piInt = ((unsigned int)(pcBuf[offset] & 0xff)) << 24;
+ *piInt += ((unsigned int)(pcBuf[offset+1] & 0xff)) << 16;
+ *piInt += ((unsigned int)(pcBuf[offset+2] & 0xff)) << 8;
+ *piInt += ((unsigned int)(pcBuf[offset+3] & 0xff));
+
+ return (SLP_OK);
+}
+
+SLPError slp_get_string(const char *pcBuf, size_t iMaxLen,
+ size_t *piOffset, char **ppcString) {
+ SLPError err;
+ unsigned short iLen;
+
+ *ppcString = NULL;
+ err = slp_get_sht(pcBuf, iMaxLen, piOffset, &iLen);
+ if (err)
+ return (err);
+ if ((iLen+*piOffset) > iMaxLen)
+ return (SLP_PARSE_ERROR);
+
+ if (!(*ppcString = malloc(iLen + 1))) {
+ slp_err(LOG_CRIT, 0, "slp_get_string", "out of memory");
+ return (SLP_MEMORY_ALLOC_FAILED);
+ }
+ (void) memcpy(*ppcString, pcBuf + *piOffset, iLen);
+ (*ppcString)[iLen] = 0;
+ *piOffset += iLen;
+ return (SLP_OK);
+}