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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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