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 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <sys/sysmacros.h> 33 #include <sys/fm/protocol.h> 34 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 38 #include <strings.h> 39 #include <unistd.h> 40 #include <pthread.h> 41 #include <alloca.h> 42 #include <fcntl.h> 43 #include <errno.h> 44 #include <netdb.h> 45 #include <poll.h> 46 47 #include <fm/fmd_api.h> 48 49 #define IP_MAGIC "\177FMA" /* magic string identifying a packet header */ 50 #define IP_MAGLEN 4 /* length of magic string */ 51 52 typedef struct ip_hdr { 53 char iph_magic[IP_MAGLEN]; /* magic string */ 54 uint32_t iph_size; /* packed size */ 55 } ip_hdr_t; 56 57 typedef struct ip_buf { 58 void *ipb_buf; /* data buffer */ 59 size_t ipb_size; /* size of buffer */ 60 } ip_buf_t; 61 62 typedef struct ip_xprt { 63 fmd_xprt_t *ipx_xprt; /* transport handle */ 64 int ipx_flags; /* transport flags */ 65 int ipx_fd; /* socket file descriptor */ 66 int ipx_done; /* flag indicating connection closed */ 67 pthread_t ipx_tid; /* recv-side auxiliary thread */ 68 ip_buf_t ipx_sndbuf; /* buffer for sending events */ 69 ip_buf_t ipx_rcvbuf; /* buffer for receiving events */ 70 struct ip_xprt *ipx_next; /* next ip_xprt in global list */ 71 } ip_xprt_t; 72 73 typedef struct ip_stat { 74 fmd_stat_t ips_accfail; /* failed accepts */ 75 fmd_stat_t ips_badmagic; /* invalid packet headers */ 76 fmd_stat_t ips_packfail; /* failed packs */ 77 fmd_stat_t ips_unpackfail; /* failed unpacks */ 78 } ip_stat_t; 79 80 static void ip_xprt_create(fmd_xprt_t *, int, int); 81 static void ip_xprt_destroy(ip_xprt_t *); 82 83 static ip_stat_t ip_stat = { 84 { "accfail", FMD_TYPE_UINT64, "failed accepts" }, 85 { "badmagic", FMD_TYPE_UINT64, "invalid packet headers" }, 86 { "packfail", FMD_TYPE_UINT64, "failed packs" }, 87 { "unpackfail", FMD_TYPE_UINT64, "failed unpacks" }, 88 }; 89 90 static fmd_hdl_t *ip_hdl; /* module handle */ 91 static pthread_mutex_t ip_lock; /* lock for ip_xps list */ 92 static ip_xprt_t *ip_xps; /* list of active transports */ 93 static nvlist_t *ip_auth; /* authority to use for transport(s) */ 94 static size_t ip_size; /* default buffer size */ 95 static volatile int ip_quit; /* signal to quit */ 96 static int ip_qlen; /* queue length for listen(3SOCKET) */ 97 static int ip_mtbf; /* mtbf for simulating packet drop */ 98 static hrtime_t ip_burp; /* make mtbf slower by adding this much delay */ 99 static int ip_translate; /* call fmd_xprt_translate() before sending */ 100 static char *ip_host; /* host to connect to (or NULL if server) */ 101 static char *ip_port; /* port to connect to (or bind to if server) */ 102 static struct addrinfo *ip_ail; /* addr info list for ip_host/ip_port */ 103 static uint_t ip_retry; /* retry count for ip_xprt_setup() */ 104 static hrtime_t ip_sleep; /* sleep delay for ip_xprt_setup() */ 105 106 /* 107 * Allocate space in ipx_sndbuf for a header and a packed XDR encoding of 108 * the specified nvlist, and then send the buffer to our remote peer. 109 */ 110 /*ARGSUSED*/ 111 static int 112 ip_xprt_send(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep, nvlist_t *nvl) 113 { 114 ip_xprt_t *ipx = fmd_xprt_getspecific(hdl, xp); 115 116 size_t size, nvsize; 117 char *buf, *nvbuf; 118 ip_hdr_t *iph; 119 ssize_t r, n; 120 int err; 121 122 /* 123 * For testing purposes, if ip_mtbf is non-zero, use this to pseudo- 124 * randomly simulate the need for retries. If ip_burp is also set, 125 * then we also suspend the transport for a bit and wake it up again. 126 */ 127 if (ip_mtbf != 0 && gethrtime() % ip_mtbf == 0) { 128 if (ip_burp != 0) { 129 fmd_hdl_debug(ip_hdl, "burping ipx %p", (void *)ipx); 130 ipx->ipx_flags |= FMD_XPRT_SUSPENDED; 131 (void) fmd_timer_install(ip_hdl, ipx, NULL, ip_burp); 132 fmd_xprt_suspend(ip_hdl, xp); 133 } 134 return (FMD_SEND_RETRY); 135 } 136 137 if (ip_translate && (nvl = fmd_xprt_translate(hdl, xp, ep)) == NULL) { 138 fmd_hdl_error(hdl, "failed to translate event %p", (void *)ep); 139 return (FMD_SEND_FAILED); 140 } 141 142 (void) nvlist_size(nvl, &nvsize, NV_ENCODE_XDR); 143 size = r = sizeof (ip_hdr_t) + nvsize; 144 145 if (ipx->ipx_sndbuf.ipb_size < size) { 146 fmd_hdl_free(hdl, ipx->ipx_sndbuf.ipb_buf, 147 ipx->ipx_sndbuf.ipb_size); 148 ipx->ipx_sndbuf.ipb_size = P2ROUNDUP(size, 16); 149 ipx->ipx_sndbuf.ipb_buf = fmd_hdl_alloc(hdl, 150 ipx->ipx_sndbuf.ipb_size, FMD_SLEEP); 151 } 152 153 buf = ipx->ipx_sndbuf.ipb_buf; 154 iph = (ip_hdr_t *)(uintptr_t)buf; 155 nvbuf = buf + sizeof (ip_hdr_t); 156 157 bcopy(IP_MAGIC, iph->iph_magic, IP_MAGLEN); 158 iph->iph_size = htonl(nvsize); 159 err = nvlist_pack(nvl, &nvbuf, &nvsize, NV_ENCODE_XDR, 0); 160 161 if (ip_translate) 162 nvlist_free(nvl); 163 164 if (err != 0) { 165 fmd_hdl_error(ip_hdl, "failed to pack event for " 166 "transport %p: %s\n", (void *)ipx->ipx_xprt, strerror(err)); 167 ip_stat.ips_packfail.fmds_value.ui64++; 168 return (FMD_SEND_FAILED); 169 } 170 171 while (!ip_quit && r != 0) { 172 if ((n = send(ipx->ipx_fd, buf, r, 0)) < 0) { 173 if (errno != EINTR && errno != EWOULDBLOCK) { 174 fmd_hdl_debug(ip_hdl, 175 "failed to send on ipx %p", (void *)ipx); 176 return (FMD_SEND_FAILED); 177 } 178 continue; 179 } 180 buf += n; 181 r -= n; 182 } 183 184 return (FMD_SEND_SUCCESS); 185 } 186 187 /* 188 * Receive a chunk of data of the specified size from our remote peer. The 189 * data is received into ipx_rcvbuf, and then a pointer to the buffer is 190 * returned. NOTE: The data is only valid until the next call to ip_xprt_recv. 191 * If the connection breaks or ip_quit is set during receive, NULL is returned. 192 */ 193 static void * 194 ip_xprt_recv(ip_xprt_t *ipx, size_t size) 195 { 196 char *buf = ipx->ipx_rcvbuf.ipb_buf; 197 ssize_t n, r = size; 198 199 if (ipx->ipx_rcvbuf.ipb_size < size) { 200 fmd_hdl_free(ip_hdl, ipx->ipx_rcvbuf.ipb_buf, 201 ipx->ipx_rcvbuf.ipb_size); 202 ipx->ipx_rcvbuf.ipb_size = P2ROUNDUP(size, 16); 203 ipx->ipx_rcvbuf.ipb_buf = buf = fmd_hdl_alloc(ip_hdl, 204 ipx->ipx_rcvbuf.ipb_size, FMD_SLEEP); 205 } 206 207 while (!ip_quit && r != 0) { 208 if ((n = recv(ipx->ipx_fd, buf, r, MSG_WAITALL)) == 0) { 209 ipx->ipx_done++; 210 return (NULL); 211 } 212 213 if (n < 0) { 214 if (errno != EINTR && errno != EWOULDBLOCK) { 215 fmd_hdl_debug(ip_hdl, 216 "failed to recv on ipx %p", (void *)ipx); 217 } 218 continue; 219 } 220 221 buf += n; 222 r -= n; 223 } 224 225 return (r ? NULL: ipx->ipx_rcvbuf.ipb_buf); 226 } 227 228 static nvlist_t * 229 ip_xprt_auth(const struct sockaddr *sap) 230 { 231 const struct sockaddr_in6 *sin6 = (const void *)sap; 232 const struct sockaddr_in *sin = (const void *)sap; 233 234 char buf[INET6_ADDRSTRLEN + 16]; 235 struct in_addr v4addr; 236 in_port_t port; 237 238 nvlist_t *nvl; 239 size_t n; 240 int err; 241 242 if (ip_auth != NULL) 243 err = nvlist_dup(ip_auth, &nvl, 0); 244 else 245 err = nvlist_alloc(&nvl, 0, 0); 246 247 if (err != 0) { 248 fmd_hdl_abort(ip_hdl, "failed to create nvlist for " 249 "authority: %s\n", strerror(err)); 250 } 251 252 if (ip_auth != NULL) 253 return (nvl); 254 255 if (sap->sa_family == AF_INET6 && 256 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 257 IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &v4addr); 258 (void) inet_ntop(AF_INET, &v4addr, buf, sizeof (buf)); 259 port = ntohs(sin6->sin6_port); 260 } else if (sap->sa_family == AF_INET6) { 261 (void) inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof (buf)); 262 port = ntohs(sin6->sin6_port); 263 } else { 264 (void) inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof (buf)); 265 port = ntohs(sin->sin_port); 266 } 267 268 n = strlen(buf); 269 (void) snprintf(buf + n, sizeof (buf) - n, ":%u", port); 270 fmd_hdl_debug(ip_hdl, "ip_authority %s=%s\n", FM_FMRI_AUTH_SERVER, buf); 271 272 (void) nvlist_add_uint8(nvl, FM_VERSION, FM_FMRI_AUTH_VERSION); 273 (void) nvlist_add_string(nvl, FM_FMRI_AUTH_SERVER, buf); 274 275 return (nvl); 276 } 277 278 static void 279 ip_xprt_accept(ip_xprt_t *ipx) 280 { 281 struct sockaddr sa; 282 socklen_t salen = sizeof (sa); 283 fmd_xprt_t *xp; 284 int fd; 285 286 if ((fd = accept(ipx->ipx_fd, &sa, &salen)) == -1) { 287 fmd_hdl_error(ip_hdl, "failed to accept connection"); 288 ip_stat.ips_accfail.fmds_value.ui64++; 289 return; 290 } 291 292 (void) getpeername(fd, &sa, &salen); 293 xp = fmd_xprt_open(ip_hdl, ipx->ipx_flags, ip_xprt_auth(&sa), NULL); 294 ip_xprt_create(xp, fd, ipx->ipx_flags); 295 } 296 297 static void 298 ip_xprt_recv_event(ip_xprt_t *ipx) 299 { 300 ip_hdr_t *iph; 301 nvlist_t *nvl; 302 size_t size; 303 void *buf; 304 int err; 305 306 if ((iph = ip_xprt_recv(ipx, sizeof (ip_hdr_t))) == NULL) 307 return; /* connection broken */ 308 309 if (bcmp(iph->iph_magic, IP_MAGIC, IP_MAGLEN) != 0) { 310 fmd_hdl_error(ip_hdl, 311 "invalid hdr magic %x.%x.%x.%x from transport %p\n", 312 iph->iph_magic[0], iph->iph_magic[1], iph->iph_magic[2], 313 iph->iph_magic[3], (void *)ipx->ipx_xprt); 314 ip_stat.ips_badmagic.fmds_value.ui64++; 315 return; 316 } 317 318 size = ntohl(iph->iph_size); 319 320 if ((buf = ip_xprt_recv(ipx, size)) == NULL) 321 return; /* connection broken */ 322 323 if ((err = nvlist_unpack(buf, size, &nvl, 0)) != 0) { 324 fmd_hdl_error(ip_hdl, "failed to unpack event from " 325 "transport %p: %s\n", (void *)ipx->ipx_xprt, strerror(err)); 326 ip_stat.ips_unpackfail.fmds_value.ui64++; 327 } else 328 fmd_xprt_post(ip_hdl, ipx->ipx_xprt, nvl, 0); 329 330 if (fmd_xprt_error(ip_hdl, ipx->ipx_xprt)) { 331 fmd_hdl_error(ip_hdl, "protocol error on transport %p", 332 (void *)ipx->ipx_xprt); 333 ipx->ipx_done++; 334 } 335 } 336 337 static void 338 ip_xprt_thread(void *arg) 339 { 340 ip_xprt_t *ipx = arg; 341 struct sockaddr sa; 342 socklen_t salen = sizeof (sa); 343 struct pollfd pfd; 344 id_t id; 345 346 while (!ip_quit && !ipx->ipx_done) { 347 if (ipx->ipx_xprt != NULL || (ipx->ipx_flags & FMD_XPRT_ACCEPT)) 348 pfd.events = POLLIN; 349 else 350 pfd.events = POLLOUT; 351 352 pfd.fd = ipx->ipx_fd; 353 pfd.revents = 0; 354 355 if (poll(&pfd, 1, -1) <= 0) 356 continue; /* loop around and check ip_quit */ 357 358 if (pfd.revents & (POLLHUP | POLLERR)) { 359 fmd_hdl_debug(ip_hdl, "hangup fd %d\n", ipx->ipx_fd); 360 break; 361 } 362 363 if (pfd.revents & POLLOUT) { 364 /* 365 * Once we're connected, there's no reason to have our 366 * calls to recv() and send() be non-blocking since we 367 * we have separate threads for each: clear O_NONBLOCK. 368 */ 369 (void) fcntl(ipx->ipx_fd, F_SETFL, 370 fcntl(ipx->ipx_fd, F_GETFL, 0) & ~O_NONBLOCK); 371 372 if (getpeername(ipx->ipx_fd, &sa, &salen) != 0) { 373 fmd_hdl_error(ip_hdl, "failed to get peer name " 374 "for fd %d", ipx->ipx_fd); 375 bzero(&sa, sizeof (sa)); 376 } 377 378 ipx->ipx_xprt = fmd_xprt_open(ip_hdl, 379 ipx->ipx_flags, ip_xprt_auth(&sa), ipx); 380 381 fmd_hdl_debug(ip_hdl, "connect fd %d\n", ipx->ipx_fd); 382 continue; 383 } 384 385 if (pfd.revents & POLLIN) { 386 if (ipx->ipx_xprt == NULL) 387 ip_xprt_accept(ipx); 388 else 389 ip_xprt_recv_event(ipx); 390 } 391 } 392 393 id = fmd_timer_install(ip_hdl, ipx, NULL, 0); 394 fmd_hdl_debug(ip_hdl, "close fd %d (timer %d)\n", ipx->ipx_fd, (int)id); 395 } 396 397 static void 398 ip_xprt_create(fmd_xprt_t *xp, int fd, int flags) 399 { 400 ip_xprt_t *ipx = fmd_hdl_zalloc(ip_hdl, sizeof (ip_xprt_t), FMD_SLEEP); 401 402 ipx->ipx_xprt = xp; 403 ipx->ipx_flags = flags; 404 ipx->ipx_fd = fd; 405 ipx->ipx_tid = fmd_thr_create(ip_hdl, ip_xprt_thread, ipx); 406 407 if (ipx->ipx_xprt != NULL) 408 fmd_xprt_setspecific(ip_hdl, ipx->ipx_xprt, ipx); 409 410 (void) pthread_mutex_lock(&ip_lock); 411 412 ipx->ipx_next = ip_xps; 413 ip_xps = ipx; 414 415 (void) pthread_mutex_unlock(&ip_lock); 416 } 417 418 static void 419 ip_xprt_destroy(ip_xprt_t *ipx) 420 { 421 ip_xprt_t *ipp, **ppx = &ip_xps; 422 423 (void) pthread_mutex_lock(&ip_lock); 424 425 for (ipp = *ppx; ipp != NULL; ipp = ipp->ipx_next) { 426 if (ipp != ipx) 427 ppx = &ipp->ipx_next; 428 else 429 break; 430 } 431 432 if (ipp != ipx) { 433 (void) pthread_mutex_unlock(&ip_lock); 434 fmd_hdl_abort(ip_hdl, "ipx %p not on xps list\n", (void *)ipx); 435 } 436 437 *ppx = ipx->ipx_next; 438 ipx->ipx_next = NULL; 439 440 (void) pthread_mutex_unlock(&ip_lock); 441 442 fmd_thr_signal(ip_hdl, ipx->ipx_tid); 443 fmd_thr_destroy(ip_hdl, ipx->ipx_tid); 444 445 if (ipx->ipx_xprt != NULL) 446 fmd_xprt_close(ip_hdl, ipx->ipx_xprt); 447 448 fmd_hdl_free(ip_hdl, ipx->ipx_sndbuf.ipb_buf, ipx->ipx_sndbuf.ipb_size); 449 fmd_hdl_free(ip_hdl, ipx->ipx_rcvbuf.ipb_buf, ipx->ipx_rcvbuf.ipb_size); 450 451 (void) close(ipx->ipx_fd); 452 fmd_hdl_free(ip_hdl, ipx, sizeof (ip_xprt_t)); 453 } 454 455 /* 456 * Loop through the addresses that were returned by getaddrinfo() in _fmd_init 457 * and for each one attempt to create a socket and initialize it. If we are 458 * successful, return zero. If we fail, we check ip_retry: if it is non-zero 459 * we return the last errno and let our caller retry ip_xprt_setup() later. If 460 * ip_retry reaches zero, we call fmd_hdl_abort() with an appropriate message. 461 */ 462 static int 463 ip_xprt_setup(fmd_hdl_t *hdl) 464 { 465 int err, fd, oflags, xflags, optval = 1; 466 struct addrinfo *aip; 467 const char *s1, *s2; 468 469 if (ip_host != NULL) 470 xflags = FMD_XPRT_RDWR; 471 else 472 xflags = FMD_XPRT_RDWR | FMD_XPRT_ACCEPT; 473 474 for (aip = ip_ail; aip != NULL; aip = aip->ai_next) { 475 if (aip->ai_family != AF_INET && aip->ai_family != AF_INET6) 476 continue; /* ignore anything that isn't IPv4 or IPv6 */ 477 478 if ((fd = socket(aip->ai_family, 479 aip->ai_socktype, aip->ai_protocol)) == -1) { 480 err = errno; 481 continue; 482 } 483 484 oflags = fcntl(fd, F_GETFL, 0); 485 (void) fcntl(fd, F_SETFL, oflags | O_NONBLOCK); 486 487 if (xflags & FMD_XPRT_ACCEPT) { 488 err = setsockopt(fd, SOL_SOCKET, 489 SO_REUSEADDR, &optval, sizeof (optval)) != 0 || 490 bind(fd, aip->ai_addr, aip->ai_addrlen) != 0 || 491 listen(fd, ip_qlen) != 0; 492 } else { 493 err = connect(fd, aip->ai_addr, 494 aip->ai_addrlen) != 0 && errno != EINPROGRESS; 495 } 496 497 if (err == 0) { 498 ip_xprt_create(NULL, fd, xflags); 499 freeaddrinfo(ip_ail); 500 ip_ail = NULL; 501 return (0); 502 } 503 504 err = errno; 505 (void) close(fd); 506 } 507 508 if (ip_host != NULL) { 509 s1 = "failed to connect to"; 510 s2 = ip_host; 511 } else { 512 s1 = "failed to listen on"; 513 s2 = ip_port; 514 } 515 516 if (err == EACCES || ip_retry-- == 0) 517 fmd_hdl_abort(hdl, "%s %s: %s\n", s1, s2, strerror(err)); 518 519 fmd_hdl_debug(hdl, "%s %s: %s (will retry)\n", s1, s2, strerror(err)); 520 return (err); 521 } 522 523 /* 524 * Timeout handler for the transport module. We use three types of timeouts: 525 * 526 * (a) arg is NULL: attempt ip_xprt_setup(), re-install timeout to retry 527 * (b) arg is non-NULL, FMD_XPRT_SUSPENDED: call fmd_xprt_resume() on arg 528 * (c) arg is non-NULL, !FMD_XPRT_SUSPENDED: call ip_xprt_destroy() on arg 529 * 530 * Case (c) is required as we need to cause the module's main thread, which 531 * runs this timeout handler, to join with the transport's auxiliary thread. 532 */ 533 static void 534 ip_timeout(fmd_hdl_t *hdl, id_t id, void *arg) 535 { 536 ip_xprt_t *ipx = arg; 537 538 if (ipx == NULL) { 539 if (ip_xprt_setup(hdl) != 0) 540 (void) fmd_timer_install(hdl, NULL, NULL, ip_sleep); 541 } else if (ipx->ipx_flags & FMD_XPRT_SUSPENDED) { 542 fmd_hdl_debug(hdl, "timer %d waking ipx %p\n", (int)id, arg); 543 ipx->ipx_flags &= ~FMD_XPRT_SUSPENDED; 544 fmd_xprt_resume(hdl, ipx->ipx_xprt); 545 } else { 546 fmd_hdl_debug(hdl, "timer %d closing ipx %p\n", (int)id, arg); 547 ip_xprt_destroy(ipx); 548 } 549 } 550 551 static const fmd_prop_t fmd_props[] = { 552 { "ip_authority", FMD_TYPE_STRING, NULL }, 553 { "ip_bufsize", FMD_TYPE_SIZE, "4k" }, 554 { "ip_burp", FMD_TYPE_TIME, "0" }, 555 { "ip_enable", FMD_TYPE_BOOL, "false" }, 556 { "ip_mtbf", FMD_TYPE_INT32, "0" }, 557 { "ip_port", FMD_TYPE_STRING, "664" }, 558 { "ip_qlen", FMD_TYPE_INT32, "32" }, 559 { "ip_retry", FMD_TYPE_UINT32, "50" }, 560 { "ip_server", FMD_TYPE_STRING, NULL }, 561 { "ip_sleep", FMD_TYPE_TIME, "10s" }, 562 { "ip_translate", FMD_TYPE_BOOL, "false" }, 563 { NULL, 0, NULL } 564 }; 565 566 static const fmd_hdl_ops_t fmd_ops = { 567 NULL, /* fmdo_recv */ 568 ip_timeout, /* fmdo_timeout */ 569 NULL, /* fmdo_close */ 570 NULL, /* fmdo_stats */ 571 NULL, /* fmdo_gc */ 572 ip_xprt_send, /* fmdo_send */ 573 }; 574 575 static const fmd_hdl_info_t fmd_info = { 576 "IP Transport Agent", "1.0", &fmd_ops, fmd_props 577 }; 578 579 /* 580 * Initialize the ip-transport module as either a server or a client. Note 581 * that the ip-transport module is not enabled by default under Solaris: 582 * at present we require a developer or tool to setprop ip_enable=true. 583 * If ip-transport is needed in the future out-of-the-box on one or more Sun 584 * platforms, the code to check 'ip_enable' should be replaced with: 585 * 586 * (a) configuring ip-transport to operate in client mode by default, 587 * (b) a platform-specific configuration mechanism, or 588 * (c) a means to assure security and prevent denial-of-service attacks. 589 * 590 * Note that (c) is only an issue when the transport module operates 591 * in server mode (i.e. with the ip_server property set to NULL) on a 592 * generic Solaris system which may be exposed directly to the Internet. 593 */ 594 void 595 _fmd_init(fmd_hdl_t *hdl) 596 { 597 struct addrinfo aih; 598 char *auth, *p, *q, *r, *s; 599 int err; 600 601 if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) 602 return; /* failed to register handle */ 603 604 if (fmd_prop_get_int32(hdl, "ip_enable") == FMD_B_FALSE) { 605 fmd_hdl_unregister(hdl); 606 return; 607 } 608 609 (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, 610 sizeof (ip_stat) / sizeof (fmd_stat_t), (fmd_stat_t *)&ip_stat); 611 612 ip_hdl = hdl; 613 (void) pthread_mutex_init(&ip_lock, NULL); 614 615 ip_burp = fmd_prop_get_int64(hdl, "ip_burp"); 616 ip_mtbf = fmd_prop_get_int32(hdl, "ip_mtbf"); 617 ip_qlen = fmd_prop_get_int32(hdl, "ip_qlen"); 618 ip_retry = fmd_prop_get_int32(hdl, "ip_retry"); 619 ip_sleep = fmd_prop_get_int64(hdl, "ip_sleep"); 620 ip_translate = fmd_prop_get_int32(hdl, "ip_translate"); 621 622 ip_size = (size_t)fmd_prop_get_int64(hdl, "ip_bufsize"); 623 ip_size = MAX(ip_size, sizeof (ip_hdr_t)); 624 625 ip_host = fmd_prop_get_string(hdl, "ip_server"); 626 ip_port = fmd_prop_get_string(hdl, "ip_port"); 627 628 bzero(&aih, sizeof (aih)); 629 aih.ai_flags = AI_ADDRCONFIG; 630 aih.ai_family = AF_UNSPEC; 631 aih.ai_socktype = SOCK_STREAM; 632 633 if (ip_host != NULL) 634 fmd_hdl_debug(hdl, "resolving %s:%s\n", ip_host, ip_port); 635 else 636 aih.ai_flags |= AI_PASSIVE; 637 638 err = getaddrinfo(ip_host, ip_port, &aih, &ip_ail); 639 640 if (err != 0) { 641 fmd_prop_free_string(hdl, ip_host); 642 fmd_prop_free_string(hdl, ip_port); 643 644 fmd_hdl_abort(hdl, "failed to resolve host %s port %s: %s\n", 645 ip_host ? ip_host : "<none>", ip_port, gai_strerror(err)); 646 } 647 648 /* 649 * If ip_authority is set, tokenize this string and turn it into an 650 * FMA authority represented as a name-value pair list. We will use 651 * this authority for all transports created by this module. If 652 * ip_authority isn't set, we'll compute authorities on the fly. 653 */ 654 if ((auth = fmd_prop_get_string(hdl, "ip_authority")) != NULL) { 655 (void) nvlist_alloc(&ip_auth, 0, 0); 656 (void) nvlist_add_uint8(ip_auth, 657 FM_VERSION, FM_FMRI_AUTH_VERSION); 658 659 s = alloca(strlen(auth) + 1); 660 (void) strcpy(s, auth); 661 fmd_prop_free_string(hdl, auth); 662 663 for (p = strtok_r(s, ",", &q); p != NULL; 664 p = strtok_r(NULL, ",", &q)) { 665 666 if ((r = strchr(p, '=')) == NULL) { 667 fmd_prop_free_string(hdl, ip_host); 668 fmd_prop_free_string(hdl, ip_port); 669 freeaddrinfo(ip_ail); 670 671 fmd_hdl_abort(hdl, "ip_authority element <%s> " 672 "must be in <name>=<value> form\n", p); 673 } 674 675 *r = '\0'; 676 (void) nvlist_add_string(ip_auth, p, r + 1); 677 *r = '='; 678 } 679 } 680 681 /* 682 * Call ip_xprt_setup() to connect or bind. If it fails and ip_retry 683 * is non-zero, install a timer to try again after 'ip_sleep' nsecs. 684 */ 685 if (ip_xprt_setup(hdl) != 0) 686 (void) fmd_timer_install(hdl, NULL, NULL, ip_sleep); 687 } 688 689 void 690 _fmd_fini(fmd_hdl_t *hdl) 691 { 692 ip_quit++; /* set quit flag before signalling auxiliary threads */ 693 694 while (ip_xps != NULL) 695 ip_xprt_destroy(ip_xps); 696 697 if (ip_auth != NULL) 698 nvlist_free(ip_auth); 699 if (ip_ail != NULL) 700 freeaddrinfo(ip_ail); 701 702 fmd_prop_free_string(hdl, ip_host); 703 fmd_prop_free_string(hdl, ip_port); 704 705 fmd_hdl_unregister(hdl); 706 } 707