#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
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);
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);
}
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) {
(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));
}
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);
default: return (SLP_INTERNAL_SYSTEM_ERROR);
}
}
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);
}
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)
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);
}
void slp_list_subtract(const char *item, char **list) {
char *p, *s;
if (!*list || !slp_onlist(item, *list))
return;
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) {
free(*list);
*list = NULL;
return;
}
if (!p) {
s--;
*s = 0;
return;
}
(void) strcpy(s, p + 1);
}
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) {
long long pid = getpid();
pid *= UINT_MAX;
(void) seed48((unsigned short *) &pid);
xid_seeded = 1;
}
(void) mutex_unlock(&lock);
}
xid = (unsigned short) (lrand48() % USHRT_MAX);
xid = xid ? xid : 1;
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);
}
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);
}
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);
}
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);
}
void slp_header_set_sht(char *header, unsigned short len, size_t off) {
(void) slp_add_sht(header, SLP_HDRLEN, len, &off);
}
size_t slp_header_length(slp_handle_impl_t *hp) {
return (SLP_HDRLEN + strlen(hp->locale));
}
slp_proto_err slp_get_errcode(char *msg) {
unsigned short langlen, errcode;
size_t off, msglen;
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);
}
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)
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);
}