#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <slp-internal.h>
struct surl_node {
char *surl;
unsigned short lifetime;
};
struct caller_bundle {
SLPSrvURLCallback *cb;
void *cookie;
SLPHandle handle;
};
static int compare_surls(struct surl_node *, struct surl_node *);
static char *collate_surls(char *, unsigned short, void **);
static void traverse_surls(SLPHandle, SLPSrvURLCallback, void *, void *);
static void process_surl_node(void *, VISIT, int, void *);
static SLPBoolean unpackDAAdvert_srv(slp_handle_impl_t *, char *,
SLPSrvURLCallback, void *,
void **, int *);
static SLPBoolean unpackSAAdvert_srv(slp_handle_impl_t *, char *,
SLPSrvURLCallback, void *,
void **, int *);
SLPError SLPFindSrvs(SLPHandle hSLP, const char *pcServiceType,
const char *pcScope, const char *pcSearchFilter,
SLPSrvURLCallback callback, void *pvUser) {
SLPError err;
slp_handle_impl_t *hp = (slp_handle_impl_t *)hSLP;
int wantSAAdvert =
strcasecmp(pcServiceType, "service:service-agent") == 0;
int wantDAAdvert =
strcasecmp(pcServiceType, "service:directory-agent") == 0;
int isSpecial = wantSAAdvert || wantDAAdvert;
SLPMsgReplyCB *unpack_cb;
if (!hSLP || !pcServiceType || !pcScope || (!*pcScope && !isSpecial) ||
!pcSearchFilter || !callback) {
return (SLP_PARAMETER_BAD);
}
if ((strlen(pcServiceType) > SLP_MAX_STRINGLEN) ||
(strlen(pcScope) > SLP_MAX_STRINGLEN) ||
(strlen(pcSearchFilter) > SLP_MAX_STRINGLEN)) {
return (SLP_PARAMETER_BAD);
}
if ((err = slp_start_call(hSLP)) != SLP_OK)
return (err);
if (wantDAAdvert) {
unpack_cb = (SLPMsgReplyCB *)unpackDAAdvert_srv;
hp->force_multicast = SLP_TRUE;
} else if (wantSAAdvert) {
unpack_cb = (SLPMsgReplyCB *)unpackSAAdvert_srv;
hp->force_multicast = SLP_TRUE;
} else {
unpack_cb = (SLPMsgReplyCB *)slp_unpackSrvReply;
}
err = slp_packSrvRqst(pcServiceType, pcSearchFilter, hp);
if (err == SLP_OK)
err = slp_ua_common(hSLP, pcScope,
(SLPGenericAppCB *)(uintptr_t)callback, pvUser, unpack_cb);
if (err != SLP_OK)
slp_end_call(hSLP);
return (err);
}
SLPBoolean slp_unpackSrvReply(slp_handle_impl_t *hp, char *reply,
SLPSrvURLCallback cb, void *cookie,
void **collator, int *numResults) {
SLPError errCode;
unsigned short urlCount, protoErrCode;
size_t len, off;
int i;
int maxResults = slp_get_maxResults();
SLPBoolean cont = SLP_TRUE;
if (!reply) {
if (!hp->async) {
traverse_surls(hp, cb, cookie, *collator);
}
cb(hp, NULL, 0, SLP_LAST_CALL, cookie);
return (SLP_FALSE);
}
len = slp_get_length(reply);
off = SLP_HDRLEN + slp_get_langlen(reply);
if (slp_get_sht(reply, len, &off, &protoErrCode) != SLP_OK)
return (SLP_TRUE);
if ((errCode = slp_map_err(protoErrCode)) != SLP_OK) {
return (cb(hp, NULL, 0, errCode, cookie));
}
if (slp_get_sht(reply, len, &off, &urlCount) != SLP_OK)
return (SLP_TRUE);
for (i = 0; i < urlCount && !hp->cancel; i++) {
char *pcSrvURL;
unsigned short sLifetime;
int nURLAuthBlocks;
size_t tbv_len;
char *url_tbv;
off++;
if (slp_get_sht(reply, len, &off, &sLifetime) != SLP_OK)
return (SLP_TRUE);
url_tbv = reply + off;
tbv_len = off;
if (slp_get_string(reply, len, &off, &pcSrvURL) != SLP_OK)
return (SLP_TRUE);
tbv_len = off - tbv_len;
if (slp_get_byte(reply, len, &off, &nURLAuthBlocks) != SLP_OK)
goto cleanup;
if ((!hp->internal_call && slp_get_security_on()) ||
nURLAuthBlocks > 0) {
struct iovec iov[1];
size_t abLen = 0;
iov[0].iov_base = url_tbv;
iov[0].iov_len = tbv_len;
if (slp_verify(iov, 1,
reply + off,
len - off,
nURLAuthBlocks,
&abLen) != SLP_OK) {
goto cleanup;
}
off += abLen;
}
if (!hp->async) {
pcSrvURL = collate_surls(pcSrvURL, sLifetime, collator);
if (!pcSrvURL)
continue;
}
(*numResults)++;
if (hp->async)
cont = cb(
(SLPHandle) hp,
pcSrvURL,
sLifetime,
errCode,
cookie);
cleanup:
free(pcSrvURL);
if (!hp->internal_call && *numResults == maxResults) {
cont = SLP_FALSE;
}
if (!cont) break;
}
return (cont);
}
static SLPBoolean unpackDAAdvert_srv(slp_handle_impl_t *hp, char *reply,
SLPSrvURLCallback cb, void *cookie,
void **collator, int *numResults) {
char *surl, *scopes, *attrs, *spis;
SLPBoolean cont = SLP_TRUE;
SLPError errCode;
int maxResults = slp_get_maxResults();
if (!reply) {
if (!hp->async) {
traverse_surls(hp, cb, cookie, *collator);
}
cb(hp, NULL, 0, SLP_LAST_CALL, cookie);
return (SLP_FALSE);
}
if (slp_unpackDAAdvert(reply, &surl, &scopes, &attrs, &spis, &errCode)
!= SLP_OK) {
return (SLP_TRUE);
}
if (errCode != SLP_OK) {
return (cb(hp, NULL, 0, errCode, cookie));
}
surl = collate_surls(surl, 0, collator);
if (!surl) {
return (SLP_TRUE);
}
(*numResults)++;
if (hp->async) {
cont = cb((SLPHandle)hp, surl, 0, errCode, cookie);
}
free(surl);
free(scopes);
free(attrs);
free(spis);
if (!hp->internal_call && *numResults == maxResults) {
return (SLP_FALSE);
}
return (cont);
}
static SLPBoolean unpackSAAdvert_srv(slp_handle_impl_t *hp, char *reply,
SLPSrvURLCallback cb, void *cookie,
void **collator, int *numResults) {
char *surl, *scopes, *attrs;
SLPBoolean cont = SLP_TRUE;
int maxResults = slp_get_maxResults();
if (!reply) {
if (!hp->async) {
traverse_surls(hp, cb, cookie, *collator);
}
cb(hp, NULL, 0, SLP_LAST_CALL, cookie);
return (SLP_FALSE);
}
if (slp_unpackSAAdvert(reply, &surl, &scopes, &attrs) != SLP_OK) {
return (SLP_TRUE);
}
surl = collate_surls(surl, 0, collator);
if (!surl) {
return (SLP_TRUE);
}
(*numResults)++;
if (hp->async) {
cont = cb((SLPHandle)hp, surl, 0, SLP_OK, cookie);
}
free(surl);
free(scopes);
free(attrs);
if (!hp->internal_call && *numResults == maxResults) {
return (SLP_FALSE);
}
return (cont);
}
SLPError slp_packSrvRqst(const char *type,
const char *filter,
slp_handle_impl_t *hp) {
SLPError err;
size_t len, msgLen, tmplen;
slp_msg_t *msg = &(hp->msg);
char *spi = NULL;
if (slp_get_security_on()) {
spi = (char *)SLPGetProperty(SLP_CONFIG_SPI);
}
if (!spi || !*spi) {
spi = "";
}
if (!(msg->iov = calloc(7, sizeof (*(msg->iov))))) {
slp_err(LOG_CRIT, 0, "slp_packSrvRqst", "out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
msg->iovlen = 7;
msgLen = 2 +
2 + strlen(type) +
2 +
2 + strlen(filter) +
2 + strlen(spi);
if (!(msg->msg = calloc(1, msgLen))) {
free(msg->iov);
slp_err(LOG_CRIT, 0, "slp_packSrvRqst", "out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
msg->prlistlen.iov_base = msg->msg;
msg->prlistlen.iov_len = 2;
msg->iov[1].iov_base = msg->msg;
msg->iov[1].iov_len = 2;
msg->scopeslen.iov_base = msg->msg + 2;
msg->scopeslen.iov_len = 2;
msg->iov[4].iov_base = msg->msg + 2;
msg->iov[4].iov_len = 2;
msg->prlist = &(msg->iov[2]);
msg->scopes = &(msg->iov[5]);
len = 4;
msg->iov[3].iov_base = msg->msg + len;
tmplen = len;
err = slp_add_string(msg->msg, msgLen, type, &len);
msg->iov[3].iov_len = len - tmplen;
if (err != SLP_OK)
goto error;
msg->iov[6].iov_base = msg->msg + len;
tmplen = len;
err = slp_add_string(msg->msg, msgLen, filter, &len);
if (err != SLP_OK)
goto error;
err = slp_add_string(msg->msg, msgLen, spi, &len);
msg->iov[6].iov_len = len - tmplen;
hp->fid = SRVRQST;
if (err == SLP_OK) {
return (err);
}
error:
free(msg->iov);
free(msg->msg);
return (err);
}
SLPError slp_packSrvRqst_single(const char *type,
const char *scopes,
const char *filter,
char **msg,
const char *lang) {
SLPError err;
size_t len, msgLen;
msgLen =
SLP_HDRLEN + strlen(lang) + 2 +
2 + strlen(type) +
2 + strlen(scopes) +
2 + strlen(filter) +
2;
if (!(*msg = calloc(msgLen, 1))) {
slp_err(LOG_CRIT, 0, "slp_packSrvRqst_single",
"out of memory");
return (SLP_MEMORY_ALLOC_FAILED);
}
len = 0;
err = slp_add_header(lang, *msg, msgLen, SRVRQST, msgLen, &len);
len += 2;
if (err == SLP_OK)
err = slp_add_string(*msg, msgLen, type, &len);
if (err == SLP_OK)
err = slp_add_string(*msg, msgLen, scopes, &len);
if (err == SLP_OK)
err = slp_add_string(*msg, msgLen, filter, &len);
if (err == SLP_OK)
err = slp_add_string(*msg, msgLen, "", &len);
return (err);
}
static int compare_surls(struct surl_node *s1, struct surl_node *s2) {
if (s1->lifetime != s2->lifetime)
return (s1->lifetime - s2->lifetime);
return (slp_strcasecmp(s1->surl, s2->surl));
}
static char *collate_surls(char *surl, unsigned short life, void **collator) {
struct surl_node *n, **res;
if (!(n = malloc(sizeof (*n)))) {
slp_err(LOG_CRIT, 0, "collate_surls", "out of memory");
return (NULL);
}
if (!(n->surl = strdup(surl))) {
free(n);
slp_err(LOG_CRIT, 0, "collate_surls", "out of memory");
return (NULL);
}
n->lifetime = life;
res = slp_tsearch((void *) n, collator,
(int (*)(const void *, const void *)) compare_surls);
if (*res == n) {
return (surl);
}
free(n->surl);
free(n);
free(surl);
return (NULL);
}
static void traverse_surls(SLPHandle h, SLPSrvURLCallback cb,
void *cookie, void *collator) {
struct caller_bundle caller[1];
if (!collator)
return;
caller->cb = cb;
caller->cookie = cookie;
caller->handle = h;
slp_twalk(collator, process_surl_node, 0, caller);
}
static void process_surl_node(void *node, VISIT order, int level, void *c) {
struct surl_node *n;
SLPSrvURLCallback *cb;
slp_handle_impl_t *h;
struct caller_bundle *caller = (struct caller_bundle *)c;
if (order == endorder || order == leaf) {
SLPBoolean cont = SLP_TRUE;
cb = caller->cb;
h = (slp_handle_impl_t *)caller->handle;
n = *(struct surl_node **)node;
if (cont && (!h || !h->async))
cont = cb(
h, n->surl,
n->lifetime,
SLP_OK,
caller->cookie);
free(n->surl);
free(n);
free(node);
}
}