xref: /illumos-gate/usr/src/lib/libslp/clib/SLPReg.c (revision 0daffde0)
1 /*
2  * CDDL HEADER START
3  *
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
7  * with the License.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * This file contains all functions pertaining to registrations:
29  *	SLPReg
30  *	SLPDereg
31  *	SLPDelAttrs
32  *
33  * Each function talks only to the local slpd, and receives a SrvAck
34  * reply.
35  *
36  * These calls can operate in sync or async mode. Sync mode operates
37  * as follows:
38  *	format params into a char *msg
39  *	send this msg to slpd
40  *	invoke the SLPRegReport callback with the error code found in the
41  *		reply from slpd
42  *	return
43  *
44  * Async mode operates as follows:
45  *	format the params into a char *msg
46  *	there is one thread per process which handles async regs
47  *	make sure this thread is running
48  *	the reg_thread monitors the global static reg_q for messages
49  *	a queue message is represented as a struct reg_q_msg
50  *	caller thread places the reg msg on the reg_q, and returns
51  *	the reg_thread reads the message from the reg_q, and sends the
52  *		msg to slpd
53  *	the reg_thread then invokes the SLPRegReport callback with the error
54  *		code found in the reply from slpd
55  *	once started, the reg_thread manages registration refreshing.
56  *		If there are no registrations to refresh, the thread exits.
57  */
58 
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <thread.h>
62 #include <synch.h>
63 #include <syslog.h>
64 #include <slp-internal.h>
65 #include <sys/time.h>
66 #include <time.h>
67 
68 /* Indices into a reg_msg iovec for auth blocks */
69 #define	SLP_URL_AUTH	1
70 #define	SLP_ATTR_AUTH	3
71 
72 /* A registration / de-registration message */
73 struct reg_msg {
74 	struct iovec *msgiov;	/* msg contents */
75 	int msgiov_len;		/* number of iovec components in msgiov */
76 	struct iovec urlbytes;
77 	struct iovec attrbytes;
78 	int urlauth;		/* index into authiov for URL auth blocks */
79 	int attrauth;		/* index into authiov for attr auth blocks */
80 };
81 
82 /*
83  * This is the message bundle passed to the reg thread via a queue.
84  */
85 struct reg_q_msg {
86 	struct reg_msg *msg;
87 	slp_handle_impl_t *hp;
88 	SLPRegReport *cb;
89 	void *cookie;
90 };
91 
92 /*
93  * These structures and vars are used for automatic re-registering.
94  */
95 static struct rereg_entry {
96 	char *url;
97 	struct reg_msg *msg;
98 	time_t wake_time;
99 	unsigned short lifetime;
100 	struct rereg_entry *next;
101 } *reregs;
102 
103 static time_t next_wake_time;
104 static unsigned short granularity = 3600;
105 static mutex_t rereg_lock = DEFAULTMUTEX;	/* protects the rereg struct */
106 static mutex_t start_lock = DEFAULTMUTEX;	/* protects reg_thr creation */
107 
108 static slp_queue_t *reg_q;	/* the global registration queue */
109 static int slp_reg_thr_running;	/* positive if reg_thread is running */
110 
111 /* Private Utility Routines */
112 
113 static SLPBoolean check_reregs();
114 static SLPError add_rereg(const char *, struct reg_msg *, unsigned short);
115 static unsigned short dereg_rereg(const char *);
116 
117 static SLPError enqueue_reg(slp_handle_impl_t *, struct reg_msg *,
118 			    void *, SLPRegReport *);
119 static SLPError reg_impl(slp_handle_impl_t *, struct reg_msg *,
120 				void *, SLPRegReport *);
121 static void reg_thread();
122 static SLPError start_reg_thr();
123 static SLPError reg_common(slp_handle_impl_t *, struct reg_msg *,
124 				void *, SLPRegReport *);
125 static SLPError UnpackSrvAck(char *, SLPError *);
126 static SLPError packSrvReg(slp_handle_impl_t *, const char *,
127 				unsigned short, const char *, const char *,
128 				const char *, SLPBoolean, struct reg_msg **);
129 static SLPError packSrvDereg(slp_handle_impl_t *, const char *,
130 				const char *, const char *, struct reg_msg **);
131 static SLPError find_SAscopes(char **scopes);
132 static void free_msgiov(struct iovec *, int);
133 
134 /* Public API SA functionality */
135 
136 SLPError SLPReg(SLPHandle   hSLP, const char  *pcSrvURL,
137 		const unsigned short usLifetime,
138 		const char  *pcSrvType,
139 		const char  *pcAttrs, SLPBoolean  fresh,
140 		SLPRegReport callback, void *pvUser) {
141 	SLPError err;
142 	char *pcScopeList;
143 	struct reg_msg *msg;
144 
145 	if (!hSLP || !pcSrvURL || !*pcSrvURL || !pcSrvType ||
146 	    !pcAttrs || !callback) {
147 		return (SLP_PARAMETER_BAD);
148 	}
149 
150 	if ((strlen(pcSrvURL) > SLP_MAX_STRINGLEN) ||
151 	    (strlen(pcSrvType) > SLP_MAX_STRINGLEN) ||
152 	    (strlen(pcAttrs) > SLP_MAX_STRINGLEN)) {
153 	    return (SLP_PARAMETER_BAD);
154 	}
155 
156 	if ((err = find_SAscopes(&pcScopeList)) != SLP_OK) {
157 		return (err);
158 	}
159 
160 	if ((err = slp_start_call(hSLP)) != SLP_OK)
161 		return (err);
162 
163 	/* format params into msg */
164 	if ((err = packSrvReg(
165 		hSLP, pcSrvURL, usLifetime, pcSrvType,
166 		pcScopeList, pcAttrs, fresh, &msg)) != SLP_OK) {
167 		free(pcScopeList);
168 		slp_end_call(hSLP);
169 		return (err);
170 	}
171 
172 	if ((err = reg_common(hSLP, msg, pvUser, callback)) == SLP_OK &&
173 	    usLifetime == SLP_LIFETIME_MAXIMUM) {
174 		struct reg_msg *rereg_msg;
175 
176 		/* create a rereg message, with no attrs */
177 		err = packSrvReg(
178 			hSLP, pcSrvURL, usLifetime,
179 			pcSrvType, pcScopeList, "", SLP_TRUE, &rereg_msg);
180 		if (err == SLP_OK) {
181 			err = add_rereg(pcSrvURL, rereg_msg, usLifetime);
182 		}
183 	}
184 
185 	free(pcScopeList);
186 	return (err);
187 }
188 
189 static SLPError packSrvReg(slp_handle_impl_t *hp, const char *url,
190 				unsigned short lifetime, const char *type,
191 				const char *scope, const char *attrs,
192 				SLPBoolean fresh, struct reg_msg **msg) {
193 	char *m = NULL;
194 	SLPError err;
195 	size_t msgLen, tmplen, len = 0;
196 	time_t ts;
197 	struct timeval tp[1];
198 
199 	/* calculate the timestamp */
200 	(void) gettimeofday(tp, NULL);
201 	ts = tp->tv_sec + lifetime;
202 
203 	/* create the reg_msg */
204 	*msg = NULL;
205 	if (!(*msg = calloc(1, sizeof (**msg)))) {
206 		slp_err(LOG_CRIT, 0, "packSrvReg", "out of memory");
207 		return (SLP_MEMORY_ALLOC_FAILED);
208 	}
209 
210 	/* compute the total messge length */
211 	msgLen =
212 		slp_hdrlang_length(hp) +
213 		/* URL entry */
214 		5 + strlen(url) +
215 		/* srv reg msg */
216 		2 + strlen(type) +
217 		2 + strlen(scope) +
218 		2 + strlen(attrs);
219 
220 	/*
221 	 * Allocate memory for all the message except the auth blocks.
222 	 * The iovec msgiov actually contains only pointers into this
223 	 * memory.
224 	 */
225 	if (!(m = calloc(msgLen, 1))) {
226 		slp_err(LOG_CRIT, 0, "packSrvReg", "out of memory");
227 		err = SLP_MEMORY_ALLOC_FAILED;
228 		goto error;
229 	}
230 
231 	/*
232 	 * Create iovec for the msg. The iovec components are layed out thus:
233 	 *   0: header + URL
234 	 *   1: URL auth block count, URL auth block
235 	 *   2: attrs
236 	 *   3: attrs auth block count, attr auth block
237 	 */
238 	if (!((*msg)->msgiov = calloc(4, sizeof (*((*msg)->msgiov))))) {
239 		slp_err(LOG_CRIT, 0, "packSrvReg", "out of memory");
240 		err = SLP_MEMORY_ALLOC_FAILED;
241 		goto error;
242 	}
243 	(*msg)->msgiov_len = 4;
244 
245 	if ((err = slp_add_header(hp->locale, m, msgLen, SRVREG, 0, &len))
246 	    != SLP_OK)
247 		goto error;
248 	/* set fresh flag */
249 	if (fresh)
250 		slp_set_fresh(m);
251 
252 	/* URL entry */
253 	len++;	/* skip reserved byte in URL entry */
254 	if ((err = slp_add_sht(m, msgLen, lifetime, &len)) != SLP_OK)
255 		goto error;
256 
257 	/* save pointer to URL for signing */
258 	tmplen = len;
259 	(*msg)->urlbytes.iov_base = m + len;
260 
261 	if ((err = slp_add_string(m, msgLen, url, &len)) != SLP_OK)
262 		goto error;
263 
264 	(*msg)->urlbytes.iov_len = len - tmplen;
265 
266 	(*msg)->msgiov[0].iov_base = m;
267 	(*msg)->msgiov[0].iov_len = len;
268 
269 	/* add auth blocks for URL */
270 	err = slp_sign(&((*msg)->urlbytes), 1, ts,
271 			(*msg)->msgiov, SLP_URL_AUTH);
272 	if (err != SLP_OK) {
273 		goto error;
274 	}
275 
276 	(*msg)->msgiov[2].iov_base = m + len;
277 
278 	/* type, scopes, and attrs */
279 	if ((err = slp_add_string(m, msgLen, type, &len)) != SLP_OK)
280 		goto error;
281 	if ((err = slp_add_string(m, msgLen, scope, &len)) != SLP_OK)
282 		goto error;
283 
284 	/* save pointer to attr for signing */
285 	tmplen = len;
286 	(*msg)->attrbytes.iov_base = m + len;
287 
288 	if ((err = slp_add_string(m, msgLen, attrs, &len)) != SLP_OK)
289 		goto error;
290 
291 	(*msg)->attrbytes.iov_len = len - tmplen;
292 
293 	/* length of 2nd portion is len - length of 1st portion */
294 	(*msg)->msgiov[2].iov_len = len - (*msg)->msgiov[0].iov_len;
295 
296 	/* add auth blocks for attrs */
297 	err = slp_sign(&((*msg)->attrbytes), 1, ts,
298 			(*msg)->msgiov, SLP_ATTR_AUTH);
299 	if (err != SLP_OK) {
300 		goto error;
301 	}
302 
303 	/* adjust msgLen with authblocks, and set header length */
304 	msgLen += (*msg)->msgiov[SLP_URL_AUTH].iov_len;
305 	msgLen += (*msg)->msgiov[SLP_ATTR_AUTH].iov_len;
306 
307 	/* make sure msgLen is valid */
308 	if (msgLen > SLP_MAX_MSGLEN) {
309 		err = SLP_PARAMETER_BAD;
310 		goto error;
311 	}
312 	slp_set_length(m, msgLen);
313 
314 	return (SLP_OK);
315 error:
316 	if (m) free(m);
317 	if (*msg) {
318 		if ((*msg)->msgiov) free_msgiov((*msg)->msgiov, 4);
319 		free(*msg);
320 	}
321 	*msg = NULL;
322 	return (err);
323 }
324 
325 SLPError SLPDereg(SLPHandle hSLP, const char *pURL,
326 			SLPRegReport callback, void *pvUser) {
327 	char *pcScopeList;
328 	struct reg_msg *msg;
329 	SLPError err;
330 
331 	if (!hSLP || !pURL || !*pURL || !callback) {
332 		return (SLP_PARAMETER_BAD);
333 	}
334 
335 	if (strlen(pURL) > SLP_MAX_STRINGLEN) {
336 	    return (SLP_PARAMETER_BAD);
337 	}
338 
339 	if ((err = find_SAscopes(&pcScopeList))
340 	    != SLP_OK) {
341 		return (err);
342 	}
343 
344 	if ((err = slp_start_call(hSLP)) != SLP_OK)
345 		return (err);
346 
347 	/* format params into msg */
348 	if ((err = packSrvDereg(hSLP, pURL, pcScopeList, NULL, &msg))
349 	    != SLP_OK) {
350 		free(pcScopeList);
351 		slp_end_call(hSLP);
352 		return (err);
353 	}
354 
355 	if ((err = reg_common(hSLP, msg, pvUser, callback)) == SLP_OK) {
356 		(void) dereg_rereg(pURL);
357 	}
358 
359 	free(pcScopeList);
360 	return (err);
361 }
362 
363 SLPError SLPDelAttrs(SLPHandle hSLP, const char *pURL,
364 			const char *pcAttrs,
365 			SLPRegReport callback, void *pvUser) {
366 	SLPError err;
367 	char *pcScopeList;
368 	struct reg_msg *msg;
369 
370 	if (!hSLP || !pURL || !*pURL || !pcAttrs || !callback) {
371 		return (SLP_PARAMETER_BAD);
372 	}
373 
374 	if ((strlen(pURL) > SLP_MAX_STRINGLEN) ||
375 	    (strlen(pcAttrs) > SLP_MAX_STRINGLEN)) {
376 	    return (SLP_PARAMETER_BAD);
377 	}
378 
379 	if ((err = find_SAscopes(&pcScopeList))
380 	    != SLP_OK) {
381 		return (err);
382 	}
383 
384 	if ((err = slp_start_call(hSLP)) != SLP_OK)
385 		return (err);
386 
387 	/* format params into msg */
388 	if ((err = packSrvDereg(hSLP, pURL, pcScopeList, pcAttrs, &msg))
389 	    != SLP_OK) {
390 		free(pcScopeList);
391 		slp_end_call(hSLP);
392 		return (err);
393 	}
394 
395 	free(pcScopeList);
396 	return (reg_common(hSLP, msg, pvUser, callback));
397 }
398 
399 static SLPError packSrvDereg(slp_handle_impl_t *hp, const char *url,
400 				const char *scopes, const char *attrs,
401 				struct reg_msg  **msg) {
402 	char *m = NULL;
403 	SLPError err;
404 	size_t msgLen, tmplen, len = 0;
405 
406 	/* create the reg_msg */
407 	*msg = NULL;
408 	if (!(*msg = calloc(1, sizeof (**msg)))) {
409 		slp_err(LOG_CRIT, 0, "packSrvReg", "out of memory");
410 		return (SLP_MEMORY_ALLOC_FAILED);
411 	}
412 
413 	/* compute the total message length */
414 	attrs = (attrs ? attrs : "");
415 	msgLen =
416 		slp_hdrlang_length(hp) +
417 		2 + strlen(scopes) +
418 		/* URL entry */
419 		5 + strlen(url) +
420 		2 + strlen(attrs);
421 
422 	if (!(m = calloc(msgLen, 1))) {
423 		slp_err(LOG_CRIT, 0, "packSrvDereg", "out of memory");
424 		return (SLP_MEMORY_ALLOC_FAILED);
425 	}
426 
427 	/*
428 	 * Create iovec for the msg. The iovec components are layed out thus:
429 	 *   0: header + URL
430 	 *   1: URL auth block count, URL auth block
431 	 *   2: attrs
432 	 */
433 	if (!((*msg)->msgiov = calloc(3, sizeof (*((*msg)->msgiov))))) {
434 		slp_err(LOG_CRIT, 0, "packSrvDereg", "out of memory");
435 		err = SLP_MEMORY_ALLOC_FAILED;
436 		goto error;
437 	}
438 	(*msg)->msgiov_len = 3;
439 
440 	if ((err = slp_add_header(
441 		hp->locale, m, msgLen, SRVDEREG, 0, &len)) != SLP_OK)
442 		goto error;
443 
444 	/* scopes */
445 	if ((err = slp_add_string(m, msgLen, scopes, &len)) != SLP_OK)
446 		goto error;
447 
448 	/* URL Entry */
449 	len++;	/* skip reserved byte in URL entry */
450 	if ((err = slp_add_sht(m, msgLen, 0, &len)) != SLP_OK)
451 		goto error;
452 
453 	/* save pointer to URL for signing */
454 	tmplen = len;
455 	(*msg)->urlbytes.iov_base = m + len;
456 
457 	if ((err = slp_add_string(m, msgLen, url, &len)) != SLP_OK)
458 		goto error;
459 
460 	(*msg)->urlbytes.iov_len = len - tmplen;
461 
462 	(*msg)->msgiov[0].iov_base = m;
463 	(*msg)->msgiov[0].iov_len = len;
464 
465 	/* add auth blocks for URL */
466 	err = slp_sign(&((*msg)->urlbytes), 1, 0,
467 			(*msg)->msgiov, SLP_URL_AUTH);
468 	if (err != SLP_OK) {
469 		goto error;
470 	}
471 
472 	(*msg)->msgiov[2].iov_base = m + len;
473 
474 	/* tag list */
475 	if ((err = slp_add_string(m, msgLen, attrs, &len)) != SLP_OK)
476 		goto error;
477 
478 	/* length of 2nd portion is len - length of 1st portion */
479 	(*msg)->msgiov[2].iov_len = len - (*msg)->msgiov[0].iov_len;
480 
481 	/* adjust msgLen with authblocks, and set header length */
482 	msgLen += (*msg)->msgiov[SLP_URL_AUTH].iov_len;
483 
484 	/* make sure msgLen is valid */
485 	if (msgLen > SLP_MAX_MSGLEN) {
486 		err = SLP_PARAMETER_BAD;
487 		goto error;
488 	}
489 	slp_set_length(m, msgLen);
490 
491 	return (SLP_OK);
492 error:
493 	if (m) free(m);
494 	if (*msg) {
495 		if ((*msg)->msgiov) free_msgiov((*msg)->msgiov, 3);
496 		free(*msg);
497 	}
498 	*msg = NULL;
499 	return (err);
500 }
501 
502 /*
503  * Passes the packed message to the routines which talk to slpd.
504  */
505 static SLPError reg_common(slp_handle_impl_t *hp, struct reg_msg *msg,
506 				void *cookie, SLPRegReport callback) {
507 	SLPError err;
508 
509 	if (!slp_reg_thr_running)
510 		if ((err = start_reg_thr()) != SLP_OK)
511 			goto reg_done;
512 
513 	if (hp->async)
514 		err = enqueue_reg(hp, msg, cookie, callback);
515 	else
516 		err = reg_impl(hp, msg, cookie, callback);
517 
518 reg_done:
519 	/* If an error occurred, end_call() will not have happened */
520 	if (err != SLP_OK)
521 		slp_end_call(hp);
522 	return (err);
523 }
524 
525 /*
526  * Put a reg message on the queue. Assumes reg_thread is running.
527  */
528 static SLPError enqueue_reg(slp_handle_impl_t *hp, struct reg_msg *msg,
529 			    void *cookie, SLPRegReport cb) {
530 	struct reg_q_msg *rmsg;
531 
532 	if (!(rmsg = malloc(sizeof (*rmsg)))) {
533 		slp_err(LOG_CRIT, 0, "enqueue_reg", "out of memory");
534 		return (SLP_MEMORY_ALLOC_FAILED);
535 	}
536 
537 	rmsg->msg = msg;
538 	rmsg->hp = hp;
539 	rmsg->cb = cb;
540 	rmsg->cookie = cookie;
541 
542 	return (slp_enqueue(reg_q, rmsg));
543 }
544 
545 /*
546  * Create a new reg_q and start the reg thread.
547  */
548 static SLPError start_reg_thr() {
549 	SLPError err = SLP_OK;
550 	int terr;
551 
552 	(void) mutex_lock(&start_lock);
553 	/* make sure someone else hasn't already intialized the thread */
554 	if (slp_reg_thr_running) {
555 		goto start_done;
556 	}
557 
558 	/* create the reg queue */
559 	reg_q = slp_new_queue(&err);
560 	if (err != SLP_OK) {
561 		goto start_done;
562 	}
563 
564 	/* start the reg thread */
565 	if ((terr = thr_create(
566 		0, 0, (void *(*)(void *)) reg_thread,
567 		NULL, 0, NULL)) != 0) {
568 		slp_err(LOG_CRIT, 0, "start_reg_thr",
569 			"could not start thread: %s",
570 			strerror(terr));
571 		slp_destroy_queue(reg_q);
572 		err = SLP_INTERNAL_SYSTEM_ERROR;
573 		goto start_done;
574 	}
575 	slp_reg_thr_running = 1;
576 
577 start_done:
578 	(void) mutex_unlock(&start_lock);
579 	return (err);
580 }
581 
582 /*
583  * This is what the permanent reg thread runs; it just sits in a loop
584  * monitoring the reg_q for new reg messages.
585  *
586  * To conserve resources,
587  * if there are no more registrations to refresh, it will exit.
588  */
589 static void reg_thread() {
590 	timestruc_t timeout;
591 	timeout.tv_nsec = 0;
592 
593 	for (;;) {
594 		SLPBoolean etimed;
595 		struct reg_q_msg *rmsg;
596 
597 		/* get the next message from the queue */
598 		timeout.tv_sec =
599 			next_wake_time ? next_wake_time : time(NULL) + 5;
600 		rmsg = slp_dequeue_timed(reg_q, &timeout, &etimed);
601 		if (!rmsg && etimed == SLP_TRUE) {
602 			/* timed out */
603 			if (!check_reregs()) {
604 				/* no more reregs; shut down this thread */
605 				(void) mutex_lock(&start_lock);
606 				slp_destroy_queue(reg_q);
607 				slp_reg_thr_running = 0;
608 				(void) mutex_unlock(&start_lock);
609 				thr_exit(NULL);
610 			}
611 			continue;
612 		}
613 		if (!rmsg)
614 			continue;
615 
616 		/* got a new message */
617 		(void) reg_impl(rmsg->hp, rmsg->msg, rmsg->cookie, rmsg->cb);
618 		free(rmsg);
619 		(void) check_reregs();
620 	}
621 }
622 
623 /*
624  * Unpacks a SrvAck.
625  * 'reply' should point to the beginning of the header.
626  */
627 static SLPError UnpackSrvAck(char *reply, SLPError *ans) {
628 	SLPError err;
629 	unsigned short langlen, call_err;
630 	char *p = reply + SLP_HDRLEN;
631 
632 	langlen = slp_get_langlen(reply);
633 	p += langlen;
634 	if ((err = slp_get_sht(p, 0, NULL, &call_err)) != SLP_OK)
635 		return (err);
636 
637 	*ans = slp_map_err(call_err);
638 
639 	return (SLP_OK);
640 }
641 
642 /*
643  * The dispatcher for SA messages. Sends a message to slpd, unpacks and
644  * dispatches the reply to the user callback.
645  */
646 static SLPError reg_impl(slp_handle_impl_t *hp, struct reg_msg *msg,
647 				void *cookie, SLPRegReport cb) {
648 	char *reply = NULL;
649 	SLPError err, call_err;
650 
651 	if (hp->cancel)
652 		goto transaction_complete;
653 
654 	if ((err = slp_send2slpd_iov(msg->msgiov, msg->msgiov_len, &reply))
655 	    != SLP_OK)
656 		goto transaction_complete;
657 
658 	/* through with msg, so free it now */
659 	free_msgiov(msg->msgiov, msg->msgiov_len);
660 	free(msg);
661 
662 	if ((err = UnpackSrvAck(reply, &call_err)) != SLP_OK)
663 		goto transaction_complete;
664 
665 	/* the reg thread doubles as the consumer thread for SA calls */
666 	hp->consumer_tid = thr_self();
667 
668 	cb(hp, call_err, cookie);
669 
670 transaction_complete:
671 	if (reply) {
672 		free(reply);
673 	}
674 	slp_end_call(hp);
675 	return (err);
676 }
677 
678 /*
679  * Re-registration routines
680  */
681 
682 /*
683  * Adds the registration contained in 'msg' to the refresh registration
684  * list managed by reg_thread.
685  * Only registrations which are meant to be permanent are refreshed,
686  * so we only allow reg's with lifetime == SLP_LIFETIME_PERMANENT into
687  * the rereg table.
688  */
689 static SLPError add_rereg(const char *url, struct reg_msg *msg,
690 				unsigned short lifetime) {
691 	struct rereg_entry *reg;
692 	SLPError err = SLP_OK;
693 
694 	if (lifetime != SLP_LIFETIME_MAXIMUM) {
695 		return (SLP_OK);
696 	}
697 
698 	(void) mutex_lock(&rereg_lock);
699 	/* alloc a new rereg entry */
700 	if (!(reg = malloc(sizeof (*reg)))) {
701 		slp_err(LOG_CRIT, 0, "add_rereg", "out of memory");
702 		err = SLP_MEMORY_ALLOC_FAILED;
703 		goto done;
704 	}
705 
706 	if (!(reg->url = strdup(url))) {
707 		free(reg);
708 		slp_err(LOG_CRIT, 0, "add_rereg", "out of memory");
709 		err = SLP_MEMORY_ALLOC_FAILED;
710 		goto done;
711 	}
712 
713 	reg->msg = msg;
714 	reg->lifetime = lifetime;
715 	reg->wake_time = (time(NULL) + lifetime) - 60;
716 	reg->next = NULL;
717 
718 	/* adjust the next wake time if necessary */
719 	next_wake_time =
720 		reg->wake_time < next_wake_time ?
721 		reg->wake_time : next_wake_time;
722 
723 	/* add the rereg to the list */
724 	if (!reregs) {
725 		/* first one */
726 		reregs = reg;
727 		goto done;
728 	}
729 
730 	/* else add it to the beginning of the list */
731 	reg->next = reregs;
732 	reregs = reg;
733 
734 done:
735 	(void) mutex_unlock(&rereg_lock);
736 	return (err);
737 }
738 
739 /*
740  * Walks through the rereg list and re-registers any which will expire
741  * before the reg thread wakes up and checks again.
742  * Returns true if there are more reregs on the list, false if none.
743  */
744 static SLPBoolean check_reregs() {
745 	struct rereg_entry *p;
746 	time_t now, shortest_wait;
747 	SLPBoolean more = SLP_TRUE;
748 
749 	(void) mutex_lock(&rereg_lock);
750 
751 	if (!reregs) {
752 		more = SLP_FALSE;
753 		goto done;
754 	}
755 
756 	now = time(NULL);
757 	shortest_wait = now + reregs->lifetime;
758 
759 	for (p = reregs; p; p = p->next) {
760 		if (now > (p->wake_time - granularity)) {
761 		    char *reply;
762 
763 		    /* rereg it, first recalculating signature */
764 		    (void) slp_sign(&(p->msg->urlbytes), 1, now + p->lifetime,
765 				    p->msg->msgiov, 1);
766 		    (void) slp_sign(&(p->msg->attrbytes), 1, now + p->lifetime,
767 				    p->msg->msgiov, 3);
768 
769 		    (void) slp_send2slpd_iov(
770 				p->msg->msgiov, p->msg->msgiov_len, &reply);
771 		    if (reply)
772 			    free(reply);
773 
774 		    p->wake_time = now + p->lifetime;
775 		}
776 
777 		if (p->wake_time < shortest_wait)
778 			shortest_wait = p->wake_time;
779 	}
780 	next_wake_time = shortest_wait;
781 
782 done:
783 	(void) mutex_unlock(&rereg_lock);
784 	return (more);
785 }
786 
787 /*
788  * Removes the refresh registration for 'url'.
789  */
790 static unsigned short dereg_rereg(const char *url) {
791 	struct rereg_entry *p, *q;
792 	unsigned short lifetime = 0;
793 
794 	(void) mutex_lock(&rereg_lock);
795 	for (p = q = reregs; p; p = p->next) {
796 		if (slp_strcasecmp(p->url, url) == 0) {
797 			/* found it; remove it from the list */
798 			if (p == q) {
799 				/* first one on list */
800 				reregs = p->next;
801 			} else {
802 				q->next = p->next;
803 			}
804 
805 			/* free the entry */
806 			lifetime = p->lifetime;
807 			free(p->url);
808 			/* free the message memory */
809 			free(p->msg->msgiov[0].iov_base);
810 			/* free the URL auth block */
811 			free(p->msg->msgiov[SLP_URL_AUTH].iov_base);
812 			/* free the attr auth block */
813 			free(p->msg->msgiov[SLP_ATTR_AUTH].iov_base);
814 			/* free the message iovec */
815 			free(p->msg->msgiov);
816 			/* finally, free the message structure */
817 			free(p->msg);
818 			free(p);
819 
820 			goto done;
821 		}
822 
823 		q = p;
824 	}
825 
826 done:
827 	(void) mutex_unlock(&rereg_lock);
828 	return (lifetime);
829 }
830 
831 /*
832  * Returns configured scopes in scopes. Caller should free *scopes
833  * when done. If the scope string is too long for an SLP string, the
834  * string is truncated.
835  */
836 static SLPError find_SAscopes(char **scopes) {
837 	SLPError err;
838 
839 	if ((err = slp_administrative_scopes(scopes, SLP_TRUE))
840 	    != SLP_OK) {
841 		return (err);
842 	}
843 
844 	/* Ensure string is not too long */
845 	if (strlen(*scopes) > SLP_MAX_STRINGLEN) {
846 		/* truncate the string */
847 		if ((*scopes)[SLP_MAX_STRINGLEN - 1] == ',') {
848 			/* scopes can't end with ',' */
849 			(*scopes)[SLP_MAX_STRINGLEN - 1] = 0;
850 		} else {
851 			(*scopes)[SLP_MAX_STRINGLEN] = 0;
852 		}
853 	}
854 
855 	return (SLP_OK);
856 }
857 
858 /*
859  * Does all the dirty work of freeing a msgiov.
860  */
861 static void free_msgiov(struct iovec *msgiov, int iovlen) {
862 	/* free the message memory */
863 	free(msgiov[0].iov_base);
864 	/* free the URL auth block */
865 	free(msgiov[SLP_URL_AUTH].iov_base);
866 	if (iovlen == 4) {
867 		/* free the attr auth block */
868 		free(msgiov[SLP_ATTR_AUTH].iov_base);
869 	}
870 	/* free the message iovec */
871 	free(msgiov);
872 }
873