2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A/*
2N/A * This file contains all functions pertaining to registrations:
2N/A * SLPReg
2N/A * SLPDereg
2N/A * SLPDelAttrs
2N/A *
2N/A * Each function talks only to the local slpd, and receives a SrvAck
2N/A * reply.
2N/A *
2N/A * These calls can operate in sync or async mode. Sync mode operates
2N/A * as follows:
2N/A * format params into a char *msg
2N/A * send this msg to slpd
2N/A * invoke the SLPRegReport callback with the error code found in the
2N/A * reply from slpd
2N/A * return
2N/A *
2N/A * Async mode operates as follows:
2N/A * format the params into a char *msg
2N/A * there is one thread per process which handles async regs
2N/A * make sure this thread is running
2N/A * the reg_thread monitors the global static reg_q for messages
2N/A * a queue message is represented as a struct reg_q_msg
2N/A * caller thread places the reg msg on the reg_q, and returns
2N/A * the reg_thread reads the message from the reg_q, and sends the
2N/A * msg to slpd
2N/A * the reg_thread then invokes the SLPRegReport callback with the error
2N/A * code found in the reply from slpd
2N/A * once started, the reg_thread manages registration refreshing.
2N/A * If there are no registrations to refresh, the thread exits.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <thread.h>
2N/A#include <synch.h>
2N/A#include <syslog.h>
2N/A#include <slp-internal.h>
2N/A#include <sys/time.h>
2N/A#include <time.h>
2N/A
2N/A/* Indices into a reg_msg iovec for auth blocks */
2N/A#define SLP_URL_AUTH 1
2N/A#define SLP_ATTR_AUTH 3
2N/A
2N/A/* A registration / de-registration message */
2N/Astruct reg_msg {
2N/A struct iovec *msgiov; /* msg contents */
2N/A int msgiov_len; /* number of iovec components in msgiov */
2N/A struct iovec urlbytes;
2N/A struct iovec attrbytes;
2N/A int urlauth; /* index into authiov for URL auth blocks */
2N/A int attrauth; /* index into authiov for attr auth blocks */
2N/A};
2N/A
2N/A/*
2N/A * This is the message bundle passed to the reg thread via a queue.
2N/A */
2N/Astruct reg_q_msg {
2N/A struct reg_msg *msg;
2N/A slp_handle_impl_t *hp;
2N/A SLPRegReport *cb;
2N/A void *cookie;
2N/A};
2N/A
2N/A/*
2N/A * These structures and vars are used for automatic re-registering.
2N/A */
2N/Astatic struct rereg_entry {
2N/A char *url;
2N/A struct reg_msg *msg;
2N/A time_t wake_time;
2N/A unsigned short lifetime;
2N/A struct rereg_entry *next;
2N/A} *reregs;
2N/A
2N/Astatic time_t next_wake_time;
2N/Astatic unsigned short granularity = 3600;
2N/Astatic mutex_t rereg_lock = DEFAULTMUTEX; /* protects the rereg struct */
2N/Astatic mutex_t start_lock = DEFAULTMUTEX; /* protects reg_thr creation */
2N/A
2N/Astatic slp_queue_t *reg_q; /* the global registration queue */
2N/Astatic int slp_reg_thr_running; /* positive if reg_thread is running */
2N/A
2N/A/* Private Utility Routines */
2N/A
2N/Astatic SLPBoolean check_reregs();
2N/Astatic SLPError add_rereg(const char *, struct reg_msg *, unsigned short);
2N/Astatic unsigned short dereg_rereg(const char *);
2N/A
2N/Astatic SLPError enqueue_reg(slp_handle_impl_t *, struct reg_msg *,
2N/A void *, SLPRegReport *);
2N/Astatic SLPError reg_impl(slp_handle_impl_t *, struct reg_msg *,
2N/A void *, SLPRegReport *);
2N/Astatic void reg_thread();
2N/Astatic SLPError start_reg_thr();
2N/Astatic SLPError reg_common(slp_handle_impl_t *, struct reg_msg *,
2N/A void *, SLPRegReport *);
2N/Astatic SLPError UnpackSrvAck(char *, SLPError *);
2N/Astatic SLPError packSrvReg(slp_handle_impl_t *, const char *,
2N/A unsigned short, const char *, const char *,
2N/A const char *, SLPBoolean, struct reg_msg **);
2N/Astatic SLPError packSrvDereg(slp_handle_impl_t *, const char *,
2N/A const char *, const char *, struct reg_msg **);
2N/Astatic SLPError find_SAscopes(char **scopes);
2N/Astatic void free_msgiov(struct iovec *, int);
2N/A
2N/A/* Public API SA functionality */
2N/A
2N/ASLPError SLPReg(SLPHandle hSLP, const char *pcSrvURL,
2N/A const unsigned short usLifetime,
2N/A const char *pcSrvType,
2N/A const char *pcAttrs, SLPBoolean fresh,
2N/A SLPRegReport callback, void *pvUser) {
2N/A SLPError err;
2N/A char *pcScopeList;
2N/A struct reg_msg *msg;
2N/A
2N/A if (!hSLP || !pcSrvURL || !*pcSrvURL || !pcSrvType ||
2N/A !pcAttrs || !callback) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((strlen(pcSrvURL) > SLP_MAX_STRINGLEN) ||
2N/A (strlen(pcSrvType) > SLP_MAX_STRINGLEN) ||
2N/A (strlen(pcAttrs) > SLP_MAX_STRINGLEN)) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((err = find_SAscopes(&pcScopeList)) != SLP_OK) {
2N/A return (err);
2N/A }
2N/A
2N/A if ((err = slp_start_call(hSLP)) != SLP_OK)
2N/A return (err);
2N/A
2N/A /* format params into msg */
2N/A if ((err = packSrvReg(
2N/A hSLP, pcSrvURL, usLifetime, pcSrvType,
2N/A pcScopeList, pcAttrs, fresh, &msg)) != SLP_OK) {
2N/A free(pcScopeList);
2N/A slp_end_call(hSLP);
2N/A return (err);
2N/A }
2N/A
2N/A if ((err = reg_common(hSLP, msg, pvUser, callback)) == SLP_OK &&
2N/A usLifetime == SLP_LIFETIME_MAXIMUM) {
2N/A struct reg_msg *rereg_msg;
2N/A
2N/A /* create a rereg message, with no attrs */
2N/A err = packSrvReg(
2N/A hSLP, pcSrvURL, usLifetime,
2N/A pcSrvType, pcScopeList, "", SLP_TRUE, &rereg_msg);
2N/A if (err == SLP_OK) {
2N/A err = add_rereg(pcSrvURL, rereg_msg, usLifetime);
2N/A }
2N/A }
2N/A
2N/A free(pcScopeList);
2N/A return (err);
2N/A}
2N/A
2N/Astatic SLPError packSrvReg(slp_handle_impl_t *hp, const char *url,
2N/A unsigned short lifetime, const char *type,
2N/A const char *scope, const char *attrs,
2N/A SLPBoolean fresh, struct reg_msg **msg) {
2N/A char *m = NULL;
2N/A SLPError err;
2N/A size_t msgLen, tmplen, len = 0;
2N/A time_t ts;
2N/A struct timeval tp[1];
2N/A
2N/A /* calculate the timestamp */
2N/A (void) gettimeofday(tp, NULL);
2N/A ts = tp->tv_sec + lifetime;
2N/A
2N/A /* create the reg_msg */
2N/A *msg = NULL;
2N/A if (!(*msg = calloc(1, sizeof (**msg)))) {
2N/A slp_err(LOG_CRIT, 0, "packSrvReg", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A
2N/A /* compute the total messge length */
2N/A msgLen =
2N/A slp_hdrlang_length(hp) +
2N/A /* URL entry */
2N/A 5 + strlen(url) +
2N/A /* srv reg msg */
2N/A 2 + strlen(type) +
2N/A 2 + strlen(scope) +
2N/A 2 + strlen(attrs);
2N/A
2N/A /*
2N/A * Allocate memory for all the message except the auth blocks.
2N/A * The iovec msgiov actually contains only pointers into this
2N/A * memory.
2N/A */
2N/A if (!(m = calloc(msgLen, 1))) {
2N/A slp_err(LOG_CRIT, 0, "packSrvReg", "out of memory");
2N/A err = SLP_MEMORY_ALLOC_FAILED;
2N/A goto error;
2N/A }
2N/A
2N/A /*
2N/A * Create iovec for the msg. The iovec components are layed out thus:
2N/A * 0: header + URL
2N/A * 1: URL auth block count, URL auth block
2N/A * 2: attrs
2N/A * 3: attrs auth block count, attr auth block
2N/A */
2N/A if (!((*msg)->msgiov = calloc(4, sizeof (*((*msg)->msgiov))))) {
2N/A slp_err(LOG_CRIT, 0, "packSrvReg", "out of memory");
2N/A err = SLP_MEMORY_ALLOC_FAILED;
2N/A goto error;
2N/A }
2N/A (*msg)->msgiov_len = 4;
2N/A
2N/A if ((err = slp_add_header(hp->locale, m, msgLen, SRVREG, 0, &len))
2N/A != SLP_OK)
2N/A goto error;
2N/A /* set fresh flag */
2N/A if (fresh)
2N/A slp_set_fresh(m);
2N/A
2N/A /* URL entry */
2N/A len++; /* skip reserved byte in URL entry */
2N/A if ((err = slp_add_sht(m, msgLen, lifetime, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A /* save pointer to URL for signing */
2N/A tmplen = len;
2N/A (*msg)->urlbytes.iov_base = m + len;
2N/A
2N/A if ((err = slp_add_string(m, msgLen, url, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A (*msg)->urlbytes.iov_len = len - tmplen;
2N/A
2N/A (*msg)->msgiov[0].iov_base = m;
2N/A (*msg)->msgiov[0].iov_len = len;
2N/A
2N/A /* add auth blocks for URL */
2N/A err = slp_sign(&((*msg)->urlbytes), 1, ts,
2N/A (*msg)->msgiov, SLP_URL_AUTH);
2N/A if (err != SLP_OK) {
2N/A goto error;
2N/A }
2N/A
2N/A (*msg)->msgiov[2].iov_base = m + len;
2N/A
2N/A /* type, scopes, and attrs */
2N/A if ((err = slp_add_string(m, msgLen, type, &len)) != SLP_OK)
2N/A goto error;
2N/A if ((err = slp_add_string(m, msgLen, scope, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A /* save pointer to attr for signing */
2N/A tmplen = len;
2N/A (*msg)->attrbytes.iov_base = m + len;
2N/A
2N/A if ((err = slp_add_string(m, msgLen, attrs, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A (*msg)->attrbytes.iov_len = len - tmplen;
2N/A
2N/A /* length of 2nd portion is len - length of 1st portion */
2N/A (*msg)->msgiov[2].iov_len = len - (*msg)->msgiov[0].iov_len;
2N/A
2N/A /* add auth blocks for attrs */
2N/A err = slp_sign(&((*msg)->attrbytes), 1, ts,
2N/A (*msg)->msgiov, SLP_ATTR_AUTH);
2N/A if (err != SLP_OK) {
2N/A goto error;
2N/A }
2N/A
2N/A /* adjust msgLen with authblocks, and set header length */
2N/A msgLen += (*msg)->msgiov[SLP_URL_AUTH].iov_len;
2N/A msgLen += (*msg)->msgiov[SLP_ATTR_AUTH].iov_len;
2N/A
2N/A /* make sure msgLen is valid */
2N/A if (msgLen > SLP_MAX_MSGLEN) {
2N/A err = SLP_PARAMETER_BAD;
2N/A goto error;
2N/A }
2N/A slp_set_length(m, msgLen);
2N/A
2N/A return (SLP_OK);
2N/Aerror:
2N/A if (m) free(m);
2N/A if (*msg) {
2N/A if ((*msg)->msgiov) free_msgiov((*msg)->msgiov, 4);
2N/A free(*msg);
2N/A }
2N/A *msg = NULL;
2N/A return (err);
2N/A}
2N/A
2N/ASLPError SLPDereg(SLPHandle hSLP, const char *pURL,
2N/A SLPRegReport callback, void *pvUser) {
2N/A char *pcScopeList;
2N/A struct reg_msg *msg;
2N/A SLPError err;
2N/A
2N/A if (!hSLP || !pURL || !*pURL || !callback) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if (strlen(pURL) > SLP_MAX_STRINGLEN) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((err = find_SAscopes(&pcScopeList))
2N/A != SLP_OK) {
2N/A return (err);
2N/A }
2N/A
2N/A if ((err = slp_start_call(hSLP)) != SLP_OK)
2N/A return (err);
2N/A
2N/A /* format params into msg */
2N/A if ((err = packSrvDereg(hSLP, pURL, pcScopeList, NULL, &msg))
2N/A != SLP_OK) {
2N/A free(pcScopeList);
2N/A slp_end_call(hSLP);
2N/A return (err);
2N/A }
2N/A
2N/A if ((err = reg_common(hSLP, msg, pvUser, callback)) == SLP_OK) {
2N/A (void) dereg_rereg(pURL);
2N/A }
2N/A
2N/A free(pcScopeList);
2N/A return (err);
2N/A}
2N/A
2N/ASLPError SLPDelAttrs(SLPHandle hSLP, const char *pURL,
2N/A const char *pcAttrs,
2N/A SLPRegReport callback, void *pvUser) {
2N/A SLPError err;
2N/A char *pcScopeList;
2N/A struct reg_msg *msg;
2N/A
2N/A if (!hSLP || !pURL || !*pURL || !pcAttrs || !callback) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((strlen(pURL) > SLP_MAX_STRINGLEN) ||
2N/A (strlen(pcAttrs) > SLP_MAX_STRINGLEN)) {
2N/A return (SLP_PARAMETER_BAD);
2N/A }
2N/A
2N/A if ((err = find_SAscopes(&pcScopeList))
2N/A != SLP_OK) {
2N/A return (err);
2N/A }
2N/A
2N/A if ((err = slp_start_call(hSLP)) != SLP_OK)
2N/A return (err);
2N/A
2N/A /* format params into msg */
2N/A if ((err = packSrvDereg(hSLP, pURL, pcScopeList, pcAttrs, &msg))
2N/A != SLP_OK) {
2N/A free(pcScopeList);
2N/A slp_end_call(hSLP);
2N/A return (err);
2N/A }
2N/A
2N/A free(pcScopeList);
2N/A return (reg_common(hSLP, msg, pvUser, callback));
2N/A}
2N/A
2N/Astatic SLPError packSrvDereg(slp_handle_impl_t *hp, const char *url,
2N/A const char *scopes, const char *attrs,
2N/A struct reg_msg **msg) {
2N/A char *m = NULL;
2N/A SLPError err;
2N/A size_t msgLen, tmplen, len = 0;
2N/A
2N/A /* create the reg_msg */
2N/A *msg = NULL;
2N/A if (!(*msg = calloc(1, sizeof (**msg)))) {
2N/A slp_err(LOG_CRIT, 0, "packSrvReg", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A
2N/A /* compute the total message length */
2N/A attrs = (attrs ? attrs : "");
2N/A msgLen =
2N/A slp_hdrlang_length(hp) +
2N/A 2 + strlen(scopes) +
2N/A /* URL entry */
2N/A 5 + strlen(url) +
2N/A 2 + strlen(attrs);
2N/A
2N/A if (!(m = calloc(msgLen, 1))) {
2N/A slp_err(LOG_CRIT, 0, "packSrvDereg", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A
2N/A /*
2N/A * Create iovec for the msg. The iovec components are layed out thus:
2N/A * 0: header + URL
2N/A * 1: URL auth block count, URL auth block
2N/A * 2: attrs
2N/A */
2N/A if (!((*msg)->msgiov = calloc(3, sizeof (*((*msg)->msgiov))))) {
2N/A slp_err(LOG_CRIT, 0, "packSrvDereg", "out of memory");
2N/A err = SLP_MEMORY_ALLOC_FAILED;
2N/A goto error;
2N/A }
2N/A (*msg)->msgiov_len = 3;
2N/A
2N/A if ((err = slp_add_header(
2N/A hp->locale, m, msgLen, SRVDEREG, 0, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A /* scopes */
2N/A if ((err = slp_add_string(m, msgLen, scopes, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A /* URL Entry */
2N/A len++; /* skip reserved byte in URL entry */
2N/A if ((err = slp_add_sht(m, msgLen, 0, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A /* save pointer to URL for signing */
2N/A tmplen = len;
2N/A (*msg)->urlbytes.iov_base = m + len;
2N/A
2N/A if ((err = slp_add_string(m, msgLen, url, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A (*msg)->urlbytes.iov_len = len - tmplen;
2N/A
2N/A (*msg)->msgiov[0].iov_base = m;
2N/A (*msg)->msgiov[0].iov_len = len;
2N/A
2N/A /* add auth blocks for URL */
2N/A err = slp_sign(&((*msg)->urlbytes), 1, 0,
2N/A (*msg)->msgiov, SLP_URL_AUTH);
2N/A if (err != SLP_OK) {
2N/A goto error;
2N/A }
2N/A
2N/A (*msg)->msgiov[2].iov_base = m + len;
2N/A
2N/A /* tag list */
2N/A if ((err = slp_add_string(m, msgLen, attrs, &len)) != SLP_OK)
2N/A goto error;
2N/A
2N/A /* length of 2nd portion is len - length of 1st portion */
2N/A (*msg)->msgiov[2].iov_len = len - (*msg)->msgiov[0].iov_len;
2N/A
2N/A /* adjust msgLen with authblocks, and set header length */
2N/A msgLen += (*msg)->msgiov[SLP_URL_AUTH].iov_len;
2N/A
2N/A /* make sure msgLen is valid */
2N/A if (msgLen > SLP_MAX_MSGLEN) {
2N/A err = SLP_PARAMETER_BAD;
2N/A goto error;
2N/A }
2N/A slp_set_length(m, msgLen);
2N/A
2N/A return (SLP_OK);
2N/Aerror:
2N/A if (m) free(m);
2N/A if (*msg) {
2N/A if ((*msg)->msgiov) free_msgiov((*msg)->msgiov, 3);
2N/A free(*msg);
2N/A }
2N/A *msg = NULL;
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Passes the packed message to the routines which talk to slpd.
2N/A */
2N/Astatic SLPError reg_common(slp_handle_impl_t *hp, struct reg_msg *msg,
2N/A void *cookie, SLPRegReport callback) {
2N/A SLPError err;
2N/A
2N/A if (!slp_reg_thr_running)
2N/A if ((err = start_reg_thr()) != SLP_OK)
2N/A goto reg_done;
2N/A
2N/A if (hp->async)
2N/A err = enqueue_reg(hp, msg, cookie, callback);
2N/A else
2N/A err = reg_impl(hp, msg, cookie, callback);
2N/A
2N/Areg_done:
2N/A /* If an error occurred, end_call() will not have happened */
2N/A if (err != SLP_OK)
2N/A slp_end_call(hp);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Put a reg message on the queue. Assumes reg_thread is running.
2N/A */
2N/Astatic SLPError enqueue_reg(slp_handle_impl_t *hp, struct reg_msg *msg,
2N/A void *cookie, SLPRegReport cb) {
2N/A struct reg_q_msg *rmsg;
2N/A
2N/A if (!(rmsg = malloc(sizeof (*rmsg)))) {
2N/A slp_err(LOG_CRIT, 0, "enqueue_reg", "out of memory");
2N/A return (SLP_MEMORY_ALLOC_FAILED);
2N/A }
2N/A
2N/A rmsg->msg = msg;
2N/A rmsg->hp = hp;
2N/A rmsg->cb = cb;
2N/A rmsg->cookie = cookie;
2N/A
2N/A return (slp_enqueue(reg_q, rmsg));
2N/A}
2N/A
2N/A/*
2N/A * Create a new reg_q and start the reg thread.
2N/A */
2N/Astatic SLPError start_reg_thr() {
2N/A SLPError err = SLP_OK;
2N/A int terr;
2N/A
2N/A (void) mutex_lock(&start_lock);
2N/A /* make sure someone else hasn't already intialized the thread */
2N/A if (slp_reg_thr_running) {
2N/A goto start_done;
2N/A }
2N/A
2N/A /* create the reg queue */
2N/A reg_q = slp_new_queue(&err);
2N/A if (err != SLP_OK) {
2N/A goto start_done;
2N/A }
2N/A
2N/A /* start the reg thread */
2N/A if ((terr = thr_create(
2N/A 0, NULL, (void *(*)(void *)) reg_thread,
2N/A NULL, 0, NULL)) != 0) {
2N/A slp_err(LOG_CRIT, 0, "start_reg_thr",
2N/A "could not start thread: %s",
2N/A strerror(terr));
2N/A slp_destroy_queue(reg_q);
2N/A err = SLP_INTERNAL_SYSTEM_ERROR;
2N/A goto start_done;
2N/A }
2N/A slp_reg_thr_running = 1;
2N/A
2N/Astart_done:
2N/A (void) mutex_unlock(&start_lock);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * This is what the permanent reg thread runs; it just sits in a loop
2N/A * monitoring the reg_q for new reg messages.
2N/A *
2N/A * To conserve resources,
2N/A * if there are no more registrations to refresh, it will exit.
2N/A */
2N/Astatic void reg_thread() {
2N/A timestruc_t timeout;
2N/A timeout.tv_nsec = 0;
2N/A
2N/A for (;;) {
2N/A SLPBoolean etimed;
2N/A struct reg_q_msg *rmsg;
2N/A
2N/A /* get the next message from the queue */
2N/A timeout.tv_sec =
2N/A next_wake_time ? next_wake_time : time(NULL) + 5;
2N/A rmsg = slp_dequeue_timed(reg_q, &timeout, &etimed);
2N/A if (!rmsg && etimed == SLP_TRUE) {
2N/A /* timed out */
2N/A if (!check_reregs()) {
2N/A /* no more reregs; shut down this thread */
2N/A (void) mutex_lock(&start_lock);
2N/A slp_destroy_queue(reg_q);
2N/A slp_reg_thr_running = 0;
2N/A (void) mutex_unlock(&start_lock);
2N/A thr_exit(NULL);
2N/A }
2N/A continue;
2N/A }
2N/A if (!rmsg)
2N/A continue;
2N/A
2N/A /* got a new message */
2N/A (void) reg_impl(rmsg->hp, rmsg->msg, rmsg->cookie, rmsg->cb);
2N/A free(rmsg);
2N/A (void) check_reregs();
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Unpacks a SrvAck.
2N/A * 'reply' should point to the beginning of the header.
2N/A */
2N/Astatic SLPError UnpackSrvAck(char *reply, SLPError *ans) {
2N/A SLPError err;
2N/A unsigned short langlen, call_err;
2N/A char *p = reply + SLP_HDRLEN;
2N/A
2N/A langlen = slp_get_langlen(reply);
2N/A p += langlen;
2N/A if ((err = slp_get_sht(p, 0, NULL, &call_err)) != SLP_OK)
2N/A return (err);
2N/A
2N/A *ans = slp_map_err(call_err);
2N/A
2N/A return (SLP_OK);
2N/A}
2N/A
2N/A/*
2N/A * The dispatcher for SA messages. Sends a message to slpd, unpacks and
2N/A * dispatches the reply to the user callback.
2N/A */
2N/Astatic SLPError reg_impl(slp_handle_impl_t *hp, struct reg_msg *msg,
2N/A void *cookie, SLPRegReport cb) {
2N/A char *reply = NULL;
2N/A SLPError err, call_err;
2N/A
2N/A if (hp->cancel)
2N/A goto transaction_complete;
2N/A
2N/A if ((err = slp_send2slpd_iov(msg->msgiov, msg->msgiov_len, &reply))
2N/A != SLP_OK)
2N/A goto transaction_complete;
2N/A
2N/A /* through with msg, so free it now */
2N/A free_msgiov(msg->msgiov, msg->msgiov_len);
2N/A free(msg);
2N/A
2N/A if ((err = UnpackSrvAck(reply, &call_err)) != SLP_OK)
2N/A goto transaction_complete;
2N/A
2N/A /* the reg thread doubles as the consumer thread for SA calls */
2N/A hp->consumer_tid = thr_self();
2N/A
2N/A cb(hp, call_err, cookie);
2N/A
2N/Atransaction_complete:
2N/A if (reply) {
2N/A free(reply);
2N/A }
2N/A slp_end_call(hp);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Re-registration routines
2N/A */
2N/A
2N/A/*
2N/A * Adds the registration contained in 'msg' to the refresh registration
2N/A * list managed by reg_thread.
2N/A * Only registrations which are meant to be permanent are refreshed,
2N/A * so we only allow reg's with lifetime == SLP_LIFETIME_PERMANENT into
2N/A * the rereg table.
2N/A */
2N/Astatic SLPError add_rereg(const char *url, struct reg_msg *msg,
2N/A unsigned short lifetime) {
2N/A struct rereg_entry *reg;
2N/A SLPError err = SLP_OK;
2N/A
2N/A if (lifetime != SLP_LIFETIME_MAXIMUM) {
2N/A return (SLP_OK);
2N/A }
2N/A
2N/A (void) mutex_lock(&rereg_lock);
2N/A /* alloc a new rereg entry */
2N/A if (!(reg = malloc(sizeof (*reg)))) {
2N/A slp_err(LOG_CRIT, 0, "add_rereg", "out of memory");
2N/A err = SLP_MEMORY_ALLOC_FAILED;
2N/A goto done;
2N/A }
2N/A
2N/A if (!(reg->url = strdup(url))) {
2N/A free(reg);
2N/A slp_err(LOG_CRIT, 0, "add_rereg", "out of memory");
2N/A err = SLP_MEMORY_ALLOC_FAILED;
2N/A goto done;
2N/A }
2N/A
2N/A reg->msg = msg;
2N/A reg->lifetime = lifetime;
2N/A reg->wake_time = (time(NULL) + lifetime) - 60;
2N/A reg->next = NULL;
2N/A
2N/A /* adjust the next wake time if necessary */
2N/A next_wake_time =
2N/A reg->wake_time < next_wake_time ?
2N/A reg->wake_time : next_wake_time;
2N/A
2N/A /* add the rereg to the list */
2N/A if (!reregs) {
2N/A /* first one */
2N/A reregs = reg;
2N/A goto done;
2N/A }
2N/A
2N/A /* else add it to the beginning of the list */
2N/A reg->next = reregs;
2N/A reregs = reg;
2N/A
2N/Adone:
2N/A (void) mutex_unlock(&rereg_lock);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Walks through the rereg list and re-registers any which will expire
2N/A * before the reg thread wakes up and checks again.
2N/A * Returns true if there are more reregs on the list, false if none.
2N/A */
2N/Astatic SLPBoolean check_reregs() {
2N/A struct rereg_entry *p;
2N/A time_t now, shortest_wait;
2N/A SLPBoolean more = SLP_TRUE;
2N/A
2N/A (void) mutex_lock(&rereg_lock);
2N/A
2N/A if (!reregs) {
2N/A more = SLP_FALSE;
2N/A goto done;
2N/A }
2N/A
2N/A now = time(NULL);
2N/A shortest_wait = now + reregs->lifetime;
2N/A
2N/A for (p = reregs; p; p = p->next) {
2N/A if (now > (p->wake_time - granularity)) {
2N/A char *reply;
2N/A
2N/A /* rereg it, first recalculating signature */
2N/A (void) slp_sign(&(p->msg->urlbytes), 1, now + p->lifetime,
2N/A p->msg->msgiov, 1);
2N/A (void) slp_sign(&(p->msg->attrbytes), 1, now + p->lifetime,
2N/A p->msg->msgiov, 3);
2N/A
2N/A (void) slp_send2slpd_iov(
2N/A p->msg->msgiov, p->msg->msgiov_len, &reply);
2N/A if (reply)
2N/A free(reply);
2N/A
2N/A p->wake_time = now + p->lifetime;
2N/A }
2N/A
2N/A if (p->wake_time < shortest_wait)
2N/A shortest_wait = p->wake_time;
2N/A }
2N/A next_wake_time = shortest_wait;
2N/A
2N/Adone:
2N/A (void) mutex_unlock(&rereg_lock);
2N/A return (more);
2N/A}
2N/A
2N/A/*
2N/A * Removes the refresh registration for 'url'.
2N/A */
2N/Astatic unsigned short dereg_rereg(const char *url) {
2N/A struct rereg_entry *p, *q;
2N/A unsigned short lifetime = 0;
2N/A
2N/A (void) mutex_lock(&rereg_lock);
2N/A for (p = q = reregs; p; p = p->next) {
2N/A if (slp_strcasecmp(p->url, url) == 0) {
2N/A /* found it; remove it from the list */
2N/A if (p == q) {
2N/A /* first one on list */
2N/A reregs = p->next;
2N/A } else {
2N/A q->next = p->next;
2N/A }
2N/A
2N/A /* free the entry */
2N/A lifetime = p->lifetime;
2N/A free(p->url);
2N/A /* free the message memory */
2N/A free(p->msg->msgiov[0].iov_base);
2N/A /* free the URL auth block */
2N/A free(p->msg->msgiov[SLP_URL_AUTH].iov_base);
2N/A /* free the attr auth block */
2N/A free(p->msg->msgiov[SLP_ATTR_AUTH].iov_base);
2N/A /* free the message iovec */
2N/A free(p->msg->msgiov);
2N/A /* finally, free the message structure */
2N/A free(p->msg);
2N/A free(p);
2N/A
2N/A goto done;
2N/A }
2N/A
2N/A q = p;
2N/A }
2N/A
2N/Adone:
2N/A (void) mutex_unlock(&rereg_lock);
2N/A return (lifetime);
2N/A}
2N/A
2N/A/*
2N/A * Returns configured scopes in scopes. Caller should free *scopes
2N/A * when done. If the scope string is too long for an SLP string, the
2N/A * string is truncated.
2N/A */
2N/Astatic SLPError find_SAscopes(char **scopes) {
2N/A SLPError err;
2N/A
2N/A if ((err = slp_administrative_scopes(scopes, SLP_TRUE))
2N/A != SLP_OK) {
2N/A return (err);
2N/A }
2N/A
2N/A /* Ensure string is not too long */
2N/A if (strlen(*scopes) > SLP_MAX_STRINGLEN) {
2N/A /* truncate the string */
2N/A if ((*scopes)[SLP_MAX_STRINGLEN - 1] == ',') {
2N/A /* scopes can't end with ',' */
2N/A (*scopes)[SLP_MAX_STRINGLEN - 1] = 0;
2N/A } else {
2N/A (*scopes)[SLP_MAX_STRINGLEN] = 0;
2N/A }
2N/A }
2N/A
2N/A return (SLP_OK);
2N/A}
2N/A
2N/A/*
2N/A * Does all the dirty work of freeing a msgiov.
2N/A */
2N/Astatic void free_msgiov(struct iovec *msgiov, int iovlen) {
2N/A /* free the message memory */
2N/A free(msgiov[0].iov_base);
2N/A /* free the URL auth block */
2N/A free(msgiov[SLP_URL_AUTH].iov_base);
2N/A if (iovlen == 4) {
2N/A /* free the attr auth block */
2N/A free(msgiov[SLP_ATTR_AUTH].iov_base);
2N/A }
2N/A /* free the message iovec */
2N/A free(msgiov);
2N/A}