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