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