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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains all functions pertaining to registrations:
35 * Each function talks only to the local slpd, and receives a SrvAck
38 * These calls can operate in sync or async mode. Sync mode operates
40 * format params into a char *msg
41 * send this msg to slpd
42 * invoke the SLPRegReport callback with the error code found in the
46 * Async mode operates as follows:
47 * format the params into a char *msg
48 * there is one thread per process which handles async regs
49 * make sure this thread is running
50 * the reg_thread monitors the global static reg_q for messages
51 * a queue message is represented as a struct reg_q_msg
52 * caller thread places the reg msg on the reg_q, and returns
53 * the reg_thread reads the message from the reg_q, and sends the
55 * the reg_thread then invokes the SLPRegReport callback with the error
56 * code found in the reply from slpd
57 * once started, the reg_thread manages registration refreshing.
58 * If there are no registrations to refresh, the thread exits.
66 #include <slp-internal.h>
70 /* Indices into a reg_msg iovec for auth blocks */
71 #define SLP_URL_AUTH 1
72 #define SLP_ATTR_AUTH 3
74 /* A registration / de-registration message */
76 struct iovec
*msgiov
; /* msg contents */
77 int msgiov_len
; /* number of iovec components in msgiov */
78 struct iovec urlbytes
;
79 struct iovec attrbytes
;
80 int urlauth
; /* index into authiov for URL auth blocks */
81 int attrauth
; /* index into authiov for attr auth blocks */
85 * This is the message bundle passed to the reg thread via a queue.
89 slp_handle_impl_t
*hp
;
95 * These structures and vars are used for automatic re-registering.
97 static struct rereg_entry
{
101 unsigned short lifetime
;
102 struct rereg_entry
*next
;
105 static time_t next_wake_time
;
106 static unsigned short granularity
= 3600;
107 static mutex_t rereg_lock
= DEFAULTMUTEX
; /* protects the rereg struct */
108 static mutex_t start_lock
= DEFAULTMUTEX
; /* protects reg_thr creation */
110 static slp_queue_t
*reg_q
; /* the global registration queue */
111 static int slp_reg_thr_running
; /* positive if reg_thread is running */
113 /* Private Utility Routines */
115 static SLPBoolean
check_reregs();
116 static SLPError
add_rereg(const char *, struct reg_msg
*, unsigned short);
117 static unsigned short dereg_rereg(const char *);
119 static SLPError
enqueue_reg(slp_handle_impl_t
*, struct reg_msg
*,
120 void *, SLPRegReport
*);
121 static SLPError
reg_impl(slp_handle_impl_t
*, struct reg_msg
*,
122 void *, SLPRegReport
*);
123 static void reg_thread();
124 static SLPError
start_reg_thr();
125 static SLPError
reg_common(slp_handle_impl_t
*, struct reg_msg
*,
126 void *, SLPRegReport
*);
127 static SLPError
UnpackSrvAck(char *, SLPError
*);
128 static SLPError
packSrvReg(slp_handle_impl_t
*, const char *,
129 unsigned short, const char *, const char *,
130 const char *, SLPBoolean
, struct reg_msg
**);
131 static SLPError
packSrvDereg(slp_handle_impl_t
*, const char *,
132 const char *, const char *, struct reg_msg
**);
133 static SLPError
find_SAscopes(char **scopes
);
134 static void free_msgiov(struct iovec
*, int);
136 /* Public API SA functionality */
138 SLPError
SLPReg(SLPHandle hSLP
, const char *pcSrvURL
,
139 const unsigned short usLifetime
,
140 const char *pcSrvType
,
141 const char *pcAttrs
, SLPBoolean fresh
,
142 SLPRegReport callback
, void *pvUser
) {
147 if (!hSLP
|| !pcSrvURL
|| !*pcSrvURL
|| !pcSrvType
||
148 !pcAttrs
|| !callback
) {
149 return (SLP_PARAMETER_BAD
);
152 if ((strlen(pcSrvURL
) > SLP_MAX_STRINGLEN
) ||
153 (strlen(pcSrvType
) > SLP_MAX_STRINGLEN
) ||
154 (strlen(pcAttrs
) > SLP_MAX_STRINGLEN
)) {
155 return (SLP_PARAMETER_BAD
);
158 if ((err
= find_SAscopes(&pcScopeList
)) != SLP_OK
) {
162 if ((err
= slp_start_call(hSLP
)) != SLP_OK
)
165 /* format params into msg */
166 if ((err
= packSrvReg(
167 hSLP
, pcSrvURL
, usLifetime
, pcSrvType
,
168 pcScopeList
, pcAttrs
, fresh
, &msg
)) != SLP_OK
) {
174 if ((err
= reg_common(hSLP
, msg
, pvUser
, callback
)) == SLP_OK
&&
175 usLifetime
== SLP_LIFETIME_MAXIMUM
) {
176 struct reg_msg
*rereg_msg
;
178 /* create a rereg message, with no attrs */
180 hSLP
, pcSrvURL
, usLifetime
,
181 pcSrvType
, pcScopeList
, "", SLP_TRUE
, &rereg_msg
);
183 err
= add_rereg(pcSrvURL
, rereg_msg
, usLifetime
);
191 static SLPError
packSrvReg(slp_handle_impl_t
*hp
, const char *url
,
192 unsigned short lifetime
, const char *type
,
193 const char *scope
, const char *attrs
,
194 SLPBoolean fresh
, struct reg_msg
**msg
) {
197 size_t msgLen
, tmplen
, len
= 0;
199 struct timeval tp
[1];
201 /* calculate the timestamp */
202 (void) gettimeofday(tp
, NULL
);
203 ts
= tp
->tv_sec
+ lifetime
;
205 /* create the reg_msg */
207 if (!(*msg
= calloc(1, sizeof (**msg
)))) {
208 slp_err(LOG_CRIT
, 0, "packSrvReg", "out of memory");
209 return (SLP_MEMORY_ALLOC_FAILED
);
212 /* compute the total messge length */
214 slp_hdrlang_length(hp
) +
223 * Allocate memory for all the message except the auth blocks.
224 * The iovec msgiov actually contains only pointers into this
227 if (!(m
= calloc(msgLen
, 1))) {
228 slp_err(LOG_CRIT
, 0, "packSrvReg", "out of memory");
229 err
= SLP_MEMORY_ALLOC_FAILED
;
234 * Create iovec for the msg. The iovec components are layed out thus:
236 * 1: URL auth block count, URL auth block
238 * 3: attrs auth block count, attr auth block
240 if (!((*msg
)->msgiov
= calloc(4, sizeof (*((*msg
)->msgiov
))))) {
241 slp_err(LOG_CRIT
, 0, "packSrvReg", "out of memory");
242 err
= SLP_MEMORY_ALLOC_FAILED
;
245 (*msg
)->msgiov_len
= 4;
247 if ((err
= slp_add_header(hp
->locale
, m
, msgLen
, SRVREG
, 0, &len
))
255 len
++; /* skip reserved byte in URL entry */
256 if ((err
= slp_add_sht(m
, msgLen
, lifetime
, &len
)) != SLP_OK
)
259 /* save pointer to URL for signing */
261 (*msg
)->urlbytes
.iov_base
= m
+ len
;
263 if ((err
= slp_add_string(m
, msgLen
, url
, &len
)) != SLP_OK
)
266 (*msg
)->urlbytes
.iov_len
= len
- tmplen
;
268 (*msg
)->msgiov
[0].iov_base
= m
;
269 (*msg
)->msgiov
[0].iov_len
= len
;
271 /* add auth blocks for URL */
272 err
= slp_sign(&((*msg
)->urlbytes
), 1, ts
,
273 (*msg
)->msgiov
, SLP_URL_AUTH
);
278 (*msg
)->msgiov
[2].iov_base
= m
+ len
;
280 /* type, scopes, and attrs */
281 if ((err
= slp_add_string(m
, msgLen
, type
, &len
)) != SLP_OK
)
283 if ((err
= slp_add_string(m
, msgLen
, scope
, &len
)) != SLP_OK
)
286 /* save pointer to attr for signing */
288 (*msg
)->attrbytes
.iov_base
= m
+ len
;
290 if ((err
= slp_add_string(m
, msgLen
, attrs
, &len
)) != SLP_OK
)
293 (*msg
)->attrbytes
.iov_len
= len
- tmplen
;
295 /* length of 2nd portion is len - length of 1st portion */
296 (*msg
)->msgiov
[2].iov_len
= len
- (*msg
)->msgiov
[0].iov_len
;
298 /* add auth blocks for attrs */
299 err
= slp_sign(&((*msg
)->attrbytes
), 1, ts
,
300 (*msg
)->msgiov
, SLP_ATTR_AUTH
);
305 /* adjust msgLen with authblocks, and set header length */
306 msgLen
+= (*msg
)->msgiov
[SLP_URL_AUTH
].iov_len
;
307 msgLen
+= (*msg
)->msgiov
[SLP_ATTR_AUTH
].iov_len
;
309 /* make sure msgLen is valid */
310 if (msgLen
> SLP_MAX_MSGLEN
) {
311 err
= SLP_PARAMETER_BAD
;
314 slp_set_length(m
, msgLen
);
320 if ((*msg
)->msgiov
) free_msgiov((*msg
)->msgiov
, 4);
327 SLPError
SLPDereg(SLPHandle hSLP
, const char *pURL
,
328 SLPRegReport callback
, void *pvUser
) {
333 if (!hSLP
|| !pURL
|| !*pURL
|| !callback
) {
334 return (SLP_PARAMETER_BAD
);
337 if (strlen(pURL
) > SLP_MAX_STRINGLEN
) {
338 return (SLP_PARAMETER_BAD
);
341 if ((err
= find_SAscopes(&pcScopeList
))
346 if ((err
= slp_start_call(hSLP
)) != SLP_OK
)
349 /* format params into msg */
350 if ((err
= packSrvDereg(hSLP
, pURL
, pcScopeList
, NULL
, &msg
))
357 if ((err
= reg_common(hSLP
, msg
, pvUser
, callback
)) == SLP_OK
) {
358 (void) dereg_rereg(pURL
);
365 SLPError
SLPDelAttrs(SLPHandle hSLP
, const char *pURL
,
367 SLPRegReport callback
, void *pvUser
) {
372 if (!hSLP
|| !pURL
|| !*pURL
|| !pcAttrs
|| !callback
) {
373 return (SLP_PARAMETER_BAD
);
376 if ((strlen(pURL
) > SLP_MAX_STRINGLEN
) ||
377 (strlen(pcAttrs
) > SLP_MAX_STRINGLEN
)) {
378 return (SLP_PARAMETER_BAD
);
381 if ((err
= find_SAscopes(&pcScopeList
))
386 if ((err
= slp_start_call(hSLP
)) != SLP_OK
)
389 /* format params into msg */
390 if ((err
= packSrvDereg(hSLP
, pURL
, pcScopeList
, pcAttrs
, &msg
))
398 return (reg_common(hSLP
, msg
, pvUser
, callback
));
401 static SLPError
packSrvDereg(slp_handle_impl_t
*hp
, const char *url
,
402 const char *scopes
, const char *attrs
,
403 struct reg_msg
**msg
) {
406 size_t msgLen
, tmplen
, len
= 0;
408 /* create the reg_msg */
410 if (!(*msg
= calloc(1, sizeof (**msg
)))) {
411 slp_err(LOG_CRIT
, 0, "packSrvReg", "out of memory");
412 return (SLP_MEMORY_ALLOC_FAILED
);
415 /* compute the total message length */
416 attrs
= (attrs
? attrs
: "");
418 slp_hdrlang_length(hp
) +
424 if (!(m
= calloc(msgLen
, 1))) {
425 slp_err(LOG_CRIT
, 0, "packSrvDereg", "out of memory");
426 return (SLP_MEMORY_ALLOC_FAILED
);
430 * Create iovec for the msg. The iovec components are layed out thus:
432 * 1: URL auth block count, URL auth block
435 if (!((*msg
)->msgiov
= calloc(3, sizeof (*((*msg
)->msgiov
))))) {
436 slp_err(LOG_CRIT
, 0, "packSrvDereg", "out of memory");
437 err
= SLP_MEMORY_ALLOC_FAILED
;
440 (*msg
)->msgiov_len
= 3;
442 if ((err
= slp_add_header(
443 hp
->locale
, m
, msgLen
, SRVDEREG
, 0, &len
)) != SLP_OK
)
447 if ((err
= slp_add_string(m
, msgLen
, scopes
, &len
)) != SLP_OK
)
451 len
++; /* skip reserved byte in URL entry */
452 if ((err
= slp_add_sht(m
, msgLen
, 0, &len
)) != SLP_OK
)
455 /* save pointer to URL for signing */
457 (*msg
)->urlbytes
.iov_base
= m
+ len
;
459 if ((err
= slp_add_string(m
, msgLen
, url
, &len
)) != SLP_OK
)
462 (*msg
)->urlbytes
.iov_len
= len
- tmplen
;
464 (*msg
)->msgiov
[0].iov_base
= m
;
465 (*msg
)->msgiov
[0].iov_len
= len
;
467 /* add auth blocks for URL */
468 err
= slp_sign(&((*msg
)->urlbytes
), 1, 0,
469 (*msg
)->msgiov
, SLP_URL_AUTH
);
474 (*msg
)->msgiov
[2].iov_base
= m
+ len
;
477 if ((err
= slp_add_string(m
, msgLen
, attrs
, &len
)) != SLP_OK
)
480 /* length of 2nd portion is len - length of 1st portion */
481 (*msg
)->msgiov
[2].iov_len
= len
- (*msg
)->msgiov
[0].iov_len
;
483 /* adjust msgLen with authblocks, and set header length */
484 msgLen
+= (*msg
)->msgiov
[SLP_URL_AUTH
].iov_len
;
486 /* make sure msgLen is valid */
487 if (msgLen
> SLP_MAX_MSGLEN
) {
488 err
= SLP_PARAMETER_BAD
;
491 slp_set_length(m
, msgLen
);
497 if ((*msg
)->msgiov
) free_msgiov((*msg
)->msgiov
, 3);
505 * Passes the packed message to the routines which talk to slpd.
507 static SLPError
reg_common(slp_handle_impl_t
*hp
, struct reg_msg
*msg
,
508 void *cookie
, SLPRegReport callback
) {
511 if (!slp_reg_thr_running
)
512 if ((err
= start_reg_thr()) != SLP_OK
)
516 err
= enqueue_reg(hp
, msg
, cookie
, callback
);
518 err
= reg_impl(hp
, msg
, cookie
, callback
);
521 /* If an error occurred, end_call() will not have happened */
528 * Put a reg message on the queue. Assumes reg_thread is running.
530 static SLPError
enqueue_reg(slp_handle_impl_t
*hp
, struct reg_msg
*msg
,
531 void *cookie
, SLPRegReport cb
) {
532 struct reg_q_msg
*rmsg
;
534 if (!(rmsg
= malloc(sizeof (*rmsg
)))) {
535 slp_err(LOG_CRIT
, 0, "enqueue_reg", "out of memory");
536 return (SLP_MEMORY_ALLOC_FAILED
);
542 rmsg
->cookie
= cookie
;
544 return (slp_enqueue(reg_q
, rmsg
));
548 * Create a new reg_q and start the reg thread.
550 static SLPError
start_reg_thr() {
551 SLPError err
= SLP_OK
;
554 (void) mutex_lock(&start_lock
);
555 /* make sure someone else hasn't already intialized the thread */
556 if (slp_reg_thr_running
) {
560 /* create the reg queue */
561 reg_q
= slp_new_queue(&err
);
566 /* start the reg thread */
567 if ((terr
= thr_create(
568 0, NULL
, (void *(*)(void *)) reg_thread
,
569 NULL
, 0, NULL
)) != 0) {
570 slp_err(LOG_CRIT
, 0, "start_reg_thr",
571 "could not start thread: %s",
573 slp_destroy_queue(reg_q
);
574 err
= SLP_INTERNAL_SYSTEM_ERROR
;
577 slp_reg_thr_running
= 1;
580 (void) mutex_unlock(&start_lock
);
585 * This is what the permanent reg thread runs; it just sits in a loop
586 * monitoring the reg_q for new reg messages.
588 * To conserve resources,
589 * if there are no more registrations to refresh, it will exit.
591 static void reg_thread() {
597 struct reg_q_msg
*rmsg
;
599 /* get the next message from the queue */
601 next_wake_time
? next_wake_time
: time(NULL
) + 5;
602 rmsg
= slp_dequeue_timed(reg_q
, &timeout
, &etimed
);
603 if (!rmsg
&& etimed
== SLP_TRUE
) {
605 if (!check_reregs()) {
606 /* no more reregs; shut down this thread */
607 (void) mutex_lock(&start_lock
);
608 slp_destroy_queue(reg_q
);
609 slp_reg_thr_running
= 0;
610 (void) mutex_unlock(&start_lock
);
618 /* got a new message */
619 (void) reg_impl(rmsg
->hp
, rmsg
->msg
, rmsg
->cookie
, rmsg
->cb
);
621 (void) check_reregs();
627 * 'reply' should point to the beginning of the header.
629 static SLPError
UnpackSrvAck(char *reply
, SLPError
*ans
) {
631 unsigned short langlen
, call_err
;
632 char *p
= reply
+ SLP_HDRLEN
;
634 langlen
= slp_get_langlen(reply
);
636 if ((err
= slp_get_sht(p
, 0, NULL
, &call_err
)) != SLP_OK
)
639 *ans
= slp_map_err(call_err
);
645 * The dispatcher for SA messages. Sends a message to slpd, unpacks and
646 * dispatches the reply to the user callback.
648 static SLPError
reg_impl(slp_handle_impl_t
*hp
, struct reg_msg
*msg
,
649 void *cookie
, SLPRegReport cb
) {
651 SLPError err
, call_err
;
654 goto transaction_complete
;
656 if ((err
= slp_send2slpd_iov(msg
->msgiov
, msg
->msgiov_len
, &reply
))
658 goto transaction_complete
;
660 /* through with msg, so free it now */
661 free_msgiov(msg
->msgiov
, msg
->msgiov_len
);
664 if ((err
= UnpackSrvAck(reply
, &call_err
)) != SLP_OK
)
665 goto transaction_complete
;
667 /* the reg thread doubles as the consumer thread for SA calls */
668 hp
->consumer_tid
= thr_self();
670 cb(hp
, call_err
, cookie
);
672 transaction_complete
:
681 * Re-registration routines
685 * Adds the registration contained in 'msg' to the refresh registration
686 * list managed by reg_thread.
687 * Only registrations which are meant to be permanent are refreshed,
688 * so we only allow reg's with lifetime == SLP_LIFETIME_PERMANENT into
691 static SLPError
add_rereg(const char *url
, struct reg_msg
*msg
,
692 unsigned short lifetime
) {
693 struct rereg_entry
*reg
;
694 SLPError err
= SLP_OK
;
696 if (lifetime
!= SLP_LIFETIME_MAXIMUM
) {
700 (void) mutex_lock(&rereg_lock
);
701 /* alloc a new rereg entry */
702 if (!(reg
= malloc(sizeof (*reg
)))) {
703 slp_err(LOG_CRIT
, 0, "add_rereg", "out of memory");
704 err
= SLP_MEMORY_ALLOC_FAILED
;
708 if (!(reg
->url
= strdup(url
))) {
710 slp_err(LOG_CRIT
, 0, "add_rereg", "out of memory");
711 err
= SLP_MEMORY_ALLOC_FAILED
;
716 reg
->lifetime
= lifetime
;
717 reg
->wake_time
= (time(NULL
) + lifetime
) - 60;
720 /* adjust the next wake time if necessary */
722 reg
->wake_time
< next_wake_time
?
723 reg
->wake_time
: next_wake_time
;
725 /* add the rereg to the list */
732 /* else add it to the beginning of the list */
737 (void) mutex_unlock(&rereg_lock
);
742 * Walks through the rereg list and re-registers any which will expire
743 * before the reg thread wakes up and checks again.
744 * Returns true if there are more reregs on the list, false if none.
746 static SLPBoolean
check_reregs() {
747 struct rereg_entry
*p
;
748 time_t now
, shortest_wait
;
749 SLPBoolean more
= SLP_TRUE
;
751 (void) mutex_lock(&rereg_lock
);
759 shortest_wait
= now
+ reregs
->lifetime
;
761 for (p
= reregs
; p
; p
= p
->next
) {
762 if (now
> (p
->wake_time
- granularity
)) {
765 /* rereg it, first recalculating signature */
766 (void) slp_sign(&(p
->msg
->urlbytes
), 1, now
+ p
->lifetime
,
768 (void) slp_sign(&(p
->msg
->attrbytes
), 1, now
+ p
->lifetime
,
771 (void) slp_send2slpd_iov(
772 p
->msg
->msgiov
, p
->msg
->msgiov_len
, &reply
);
776 p
->wake_time
= now
+ p
->lifetime
;
779 if (p
->wake_time
< shortest_wait
)
780 shortest_wait
= p
->wake_time
;
782 next_wake_time
= shortest_wait
;
785 (void) mutex_unlock(&rereg_lock
);
790 * Removes the refresh registration for 'url'.
792 static unsigned short dereg_rereg(const char *url
) {
793 struct rereg_entry
*p
, *q
;
794 unsigned short lifetime
= 0;
796 (void) mutex_lock(&rereg_lock
);
797 for (p
= q
= reregs
; p
; p
= p
->next
) {
798 if (slp_strcasecmp(p
->url
, url
) == 0) {
799 /* found it; remove it from the list */
801 /* first one on list */
808 lifetime
= p
->lifetime
;
810 /* free the message memory */
811 free(p
->msg
->msgiov
[0].iov_base
);
812 /* free the URL auth block */
813 free(p
->msg
->msgiov
[SLP_URL_AUTH
].iov_base
);
814 /* free the attr auth block */
815 free(p
->msg
->msgiov
[SLP_ATTR_AUTH
].iov_base
);
816 /* free the message iovec */
817 free(p
->msg
->msgiov
);
818 /* finally, free the message structure */
829 (void) mutex_unlock(&rereg_lock
);
834 * Returns configured scopes in scopes. Caller should free *scopes
835 * when done. If the scope string is too long for an SLP string, the
836 * string is truncated.
838 static SLPError
find_SAscopes(char **scopes
) {
841 if ((err
= slp_administrative_scopes(scopes
, SLP_TRUE
))
846 /* Ensure string is not too long */
847 if (strlen(*scopes
) > SLP_MAX_STRINGLEN
) {
848 /* truncate the string */
849 if ((*scopes
)[SLP_MAX_STRINGLEN
- 1] == ',') {
850 /* scopes can't end with ',' */
851 (*scopes
)[SLP_MAX_STRINGLEN
- 1] = 0;
853 (*scopes
)[SLP_MAX_STRINGLEN
] = 0;
861 * Does all the dirty work of freeing a msgiov.
863 static void free_msgiov(struct iovec
*msgiov
, int iovlen
) {
864 /* free the message memory */
865 free(msgiov
[0].iov_base
);
866 /* free the URL auth block */
867 free(msgiov
[SLP_URL_AUTH
].iov_base
);
869 /* free the attr auth block */
870 free(msgiov
[SLP_ATTR_AUTH
].iov_base
);
872 /* free the message iovec */