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(void *); 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, 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 * 590 reg_thread(void *arg __unused) 591 { 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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