Print this page
patch tsoome-feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fm/modules/common/ip-transport/ip.c
+++ new/usr/src/cmd/fm/modules/common/ip-transport/ip.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 #include <sys/types.h>
27 27 #include <sys/socket.h>
28 28 #include <sys/sysmacros.h>
29 29 #include <sys/fm/protocol.h>
30 30
31 31 #include <netinet/in.h>
32 32 #include <arpa/inet.h>
33 33
34 34 #include <strings.h>
35 35 #include <unistd.h>
36 36 #include <pthread.h>
37 37 #include <fcntl.h>
38 38 #include <errno.h>
39 39 #include <netdb.h>
40 40 #include <poll.h>
41 41 #include <stdarg.h>
42 42
43 43 #include <fm/fmd_api.h>
44 44
45 45 #define IP_MAGIC "\177FMA" /* magic string identifying a packet header */
46 46 #define IP_MAGLEN 4 /* length of magic string */
47 47 #define IP_DEBUG_OFF 0 /* No informational debugging printed */
48 48 #define IP_DEBUG_FINE 1 /* Basic debug information printed (default) */
49 49 #define IP_DEBUG_FINER 2 /* More debug information printed. */
50 50 #define IP_DEBUG_FINEST 3 /* All debug information printed */
51 51
52 52 typedef struct ip_hdr {
53 53 char iph_magic[IP_MAGLEN]; /* magic string */
54 54 uint32_t iph_size; /* packed size */
55 55 } ip_hdr_t;
56 56
57 57 typedef struct ip_buf {
58 58 void *ipb_buf; /* data buffer */
59 59 size_t ipb_size; /* size of buffer */
60 60 } ip_buf_t;
61 61
62 62 typedef struct ip_cinfo { /* Connection specific information */
63 63 struct addrinfo *ipc_addr; /* Connection address(es) */
64 64 char *ipc_name; /* The name of the server or interface */
65 65 int ipc_retry; /* The number of connection retries */
66 66 boolean_t ipc_accept; /* Will connection accept clients */
67 67 id_t ipc_timer; /* FMD timer id for connection */
68 68 struct ip_cinfo *ipc_next; /* Next conneciton in list */
69 69 } ip_cinfo_t;
70 70
71 71 typedef struct ip_xprt {
72 72 fmd_xprt_t *ipx_xprt; /* transport handle */
73 73 int ipx_flags; /* transport flags */
74 74 int ipx_fd; /* socket file descriptor */
75 75 int ipx_done; /* flag indicating connection closed */
76 76 pthread_t ipx_tid; /* recv-side auxiliary thread */
77 77 ip_buf_t ipx_sndbuf; /* buffer for sending events */
78 78 ip_buf_t ipx_rcvbuf; /* buffer for receiving events */
79 79 ip_cinfo_t *ipx_cinfo; /* info for reconnect */
80 80 id_t ipx_spnd_timer; /* connection suspend timer */
81 81 char *ipx_addr; /* address:port of remote connection */
82 82 struct ip_xprt *ipx_next; /* next ip_xprt in global list */
83 83 } ip_xprt_t;
84 84
85 85 #define IPX_ID(a) ((a)->ipx_addr == NULL ? "(Not connected)" : (a)->ipx_addr)
86 86
87 87 typedef struct ip_stat {
88 88 fmd_stat_t ips_accfail; /* failed accepts */
89 89 fmd_stat_t ips_badmagic; /* invalid packet headers */
90 90 fmd_stat_t ips_packfail; /* failed packs */
91 91 fmd_stat_t ips_unpackfail; /* failed unpacks */
92 92 } ip_stat_t;
93 93
94 94 static void ip_xprt_create(fmd_xprt_t *, int, int, ip_cinfo_t *, char *);
95 95 static void ip_xprt_destroy(ip_xprt_t *);
96 96
97 97 static ip_stat_t ip_stat = {
98 98 { "accfail", FMD_TYPE_UINT64, "failed accepts" },
99 99 { "badmagic", FMD_TYPE_UINT64, "invalid packet headers" },
100 100 { "packfail", FMD_TYPE_UINT64, "failed packs" },
101 101 { "unpackfail", FMD_TYPE_UINT64, "failed unpacks" },
102 102 };
103 103
104 104 static fmd_hdl_t *ip_hdl; /* module handle */
105 105 static pthread_mutex_t ip_lock; /* lock for ip_xps list */
106 106 static ip_xprt_t *ip_xps; /* list of active transports */
107 107 static pthread_mutex_t ip_conns_lock; /* lock for ip_conns list */
108 108 static ip_cinfo_t *ip_conns; /* list of all configured connection info */
109 109 static nvlist_t *ip_auth; /* authority to use for transport(s) */
110 110 static size_t ip_size; /* default buffer size */
111 111 static volatile int ip_quit; /* signal to quit */
112 112 static int ip_qlen; /* queue length for listen(3SOCKET) */
113 113 static int ip_mtbf; /* mtbf for simulating packet drop */
114 114 static int ip_external; /* set transport to be "external" */
115 115 static int ip_no_remote_repair; /* disallow remote repair */
116 116 static int ip_hconly; /* only cache faults that are hc-scheme */
117 117 static int ip_rdonly; /* force transport to be rdonly */
118 118 static int ip_hc_present_only; /* only cache faults if hc-scheme and present */
119 119 static char *ip_domain_name; /* set domain name for received list.suspects */
120 120 static hrtime_t ip_burp; /* make mtbf slower by adding this much delay */
121 121 static int ip_translate; /* call fmd_xprt_translate() before sending */
122 122 static char *ip_port; /* port to connect to (or bind to if server) */
123 123 static int ip_retry; /* retry count for ip_xprt_setup() -1=forever */
124 124 static hrtime_t ip_sleep; /* sleep delay for ip_xprt_setup() */
125 125 static int ip_debug_level; /* level for printing debug messages */
126 126
127 127 /*
128 128 * Prints a debug message to the fmd debug framework if the debug level is set
129 129 * to at least the given level.
130 130 */
131 131 static void
132 132 ip_debug(int level, char *fmt, ...)
133 133 {
134 134 if (ip_debug_level >= level) {
135 135 va_list args;
136 136 va_start(args, fmt);
137 137 fmd_hdl_vdebug(ip_hdl, fmt, args);
138 138 va_end(args);
139 139 }
140 140 }
141 141
142 142 /*
143 143 * Allocate space in ipx_sndbuf for a header and a packed XDR encoding of
144 144 * the specified nvlist, and then send the buffer to our remote peer.
145 145 */
146 146 static int
147 147 ip_fmdo_send(fmd_hdl_t *hdl, fmd_xprt_t *xp, fmd_event_t *ep, nvlist_t *nvl)
148 148 {
149 149 ip_xprt_t *ipx;
150 150 size_t size, nvsize;
151 151 char *buf, *nvbuf;
152 152 ip_hdr_t *iph;
153 153 ssize_t r, n;
154 154 int err;
155 155
156 156 if (xp == NULL) {
157 157 ip_debug(IP_DEBUG_FINE, "ip_fmdo_send failed: xp=NULL\n");
158 158 return (FMD_SEND_FAILED);
159 159 }
160 160 ipx = fmd_xprt_getspecific(hdl, xp);
161 161
162 162 /*
163 163 * For testing purposes, if ip_mtbf is non-zero, use this to pseudo-
164 164 * randomly simulate the need for retries. If ip_burp is also set,
165 165 * then we also suspend the transport for a bit and wake it up again.
166 166 */
167 167 if (ip_mtbf != 0 && gethrtime() % ip_mtbf == 0) {
168 168 if (ip_burp != 0) {
169 169 ip_debug(IP_DEBUG_FINE, "burping ipx %s", IPX_ID(ipx));
170 170 ipx->ipx_flags |= FMD_XPRT_SUSPENDED;
171 171 ipx->ipx_spnd_timer = fmd_timer_install(
172 172 ip_hdl, ipx, NULL, ip_burp);
173 173 fmd_xprt_suspend(ip_hdl, xp);
174 174 }
175 175 return (FMD_SEND_RETRY);
176 176 }
177 177
178 178 if (ip_translate && (nvl = fmd_xprt_translate(hdl, xp, ep)) == NULL) {
179 179 fmd_hdl_error(hdl, "failed to translate event %p", (void *)ep);
180 180 return (FMD_SEND_FAILED);
181 181 }
182 182
183 183 (void) nvlist_size(nvl, &nvsize, NV_ENCODE_XDR);
184 184 size = r = sizeof (ip_hdr_t) + nvsize;
185 185
186 186 if (ipx->ipx_sndbuf.ipb_size < size) {
187 187 fmd_hdl_free(hdl, ipx->ipx_sndbuf.ipb_buf,
188 188 ipx->ipx_sndbuf.ipb_size);
189 189 ipx->ipx_sndbuf.ipb_size = P2ROUNDUP(size, 16);
190 190 ipx->ipx_sndbuf.ipb_buf = fmd_hdl_alloc(hdl,
191 191 ipx->ipx_sndbuf.ipb_size, FMD_SLEEP);
192 192 }
193 193
194 194 buf = ipx->ipx_sndbuf.ipb_buf;
195 195 iph = (ip_hdr_t *)(uintptr_t)buf;
196 196 nvbuf = buf + sizeof (ip_hdr_t);
197 197
198 198 bcopy(IP_MAGIC, iph->iph_magic, IP_MAGLEN);
199 199 iph->iph_size = htonl(nvsize);
200 200 err = nvlist_pack(nvl, &nvbuf, &nvsize, NV_ENCODE_XDR, 0);
201 201
202 202 if (ip_translate)
203 203 nvlist_free(nvl);
204 204
205 205 if (err != 0) {
206 206 fmd_hdl_error(ip_hdl, "failed to pack event for "
207 207 "transport %p: %s\n", (void *)ipx->ipx_xprt, strerror(err));
208 208 ip_stat.ips_packfail.fmds_value.ui64++;
209 209 return (FMD_SEND_FAILED);
210 210 }
211 211
212 212 while (!ip_quit && r != 0) {
213 213 if ((n = send(ipx->ipx_fd, buf, r, 0)) < 0) {
214 214 if (errno != EINTR && errno != EWOULDBLOCK) {
215 215 ip_debug(IP_DEBUG_FINE,
216 216 "failed to send to %s", IPX_ID(ipx));
217 217 return (FMD_SEND_FAILED);
218 218 }
219 219 continue;
220 220 }
221 221 buf += n;
222 222 r -= n;
223 223 }
224 224
225 225 ip_debug(IP_DEBUG_FINEST, "Sent event %d bytes to %s",
226 226 size, IPX_ID(ipx));
227 227 return (FMD_SEND_SUCCESS);
228 228 }
229 229
230 230 /*
231 231 * Sends events over transports that are configured read only. When the module
232 232 * is in read only mode it will receive all events and only send events that
233 233 * have a subscription set.
234 234 *
235 235 * The configuration file will have to set prop ip_rdonly true and also
236 236 * subscribe for events that are desired to be sent over the transport in order
237 237 * for this function to be used.
238 238 */
239 239 /* ARGSUSED */
240 240 static void
241 241 ip_fmdo_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
242 242 {
243 243 int err;
244 244 ip_xprt_t *ipx;
245 245
246 246 if (ip_rdonly && !ip_quit) {
247 247 (void) pthread_mutex_lock(&ip_lock);
248 248
249 249 for (ipx = ip_xps; ipx != NULL; ipx = ipx->ipx_next) {
250 250 err = ip_fmdo_send(hdl, ipx->ipx_xprt, ep, nvl);
251 251 while (FMD_SEND_RETRY == err) {
252 252 err = ip_fmdo_send(hdl, ipx->ipx_xprt, ep, nvl);
253 253 }
254 254 }
255 255 (void) pthread_mutex_unlock(&ip_lock);
256 256 }
257 257 }
258 258
259 259 /*
260 260 * Receive a chunk of data of the specified size from our remote peer. The
261 261 * data is received into ipx_rcvbuf, and then a pointer to the buffer is
262 262 * returned. NOTE: The data is only valid until the next call to ip_xprt_recv.
263 263 * If the connection breaks or ip_quit is set during receive, NULL is returned.
264 264 */
265 265 static void *
266 266 ip_xprt_recv(ip_xprt_t *ipx, size_t size)
267 267 {
268 268 char *buf = ipx->ipx_rcvbuf.ipb_buf;
269 269 ssize_t n, r = size;
270 270
271 271 if (ipx->ipx_rcvbuf.ipb_size < size) {
272 272 fmd_hdl_free(ip_hdl, ipx->ipx_rcvbuf.ipb_buf,
273 273 ipx->ipx_rcvbuf.ipb_size);
274 274 ipx->ipx_rcvbuf.ipb_size = P2ROUNDUP(size, 16);
275 275 ipx->ipx_rcvbuf.ipb_buf = buf = fmd_hdl_alloc(ip_hdl,
276 276 ipx->ipx_rcvbuf.ipb_size, FMD_SLEEP);
277 277 }
278 278
279 279 while (!ip_quit && r != 0) {
280 280 if ((n = recv(ipx->ipx_fd, buf, r, MSG_WAITALL)) == 0) {
281 281 ipx->ipx_done++;
282 282 return (NULL);
283 283 }
284 284
285 285 if (n < 0) {
286 286 if (errno != EINTR && errno != EWOULDBLOCK) {
287 287 ip_debug(IP_DEBUG_FINE,
288 288 "failed to recv on ipx %s", IPX_ID(ipx));
289 289 }
290 290 continue;
291 291 }
292 292 /* Reset retry counter after a successful connection */
293 293 if (ipx->ipx_cinfo) {
294 294 ipx->ipx_cinfo->ipc_retry = ip_retry;
295 295 }
296 296
297 297 buf += n;
298 298 r -= n;
299 299 }
300 300
301 301 return (r ? NULL: ipx->ipx_rcvbuf.ipb_buf);
302 302 }
303 303
304 304 /*
305 305 * Sets the address/port of the remote connection in the connection info struct
306 306 * This is called after a TCP session has been set up with a known remote
307 307 * address (sap)
308 308 */
309 309 static void
310 310 ip_xprt_set_addr(ip_xprt_t *ipx, const struct sockaddr *sap)
311 311 {
312 312 const struct sockaddr_in6 *sin6 = (const void *)sap;
313 313 const struct sockaddr_in *sin = (const void *)sap;
314 314
315 315 char buf[INET6_ADDRSTRLEN + 16];
316 316 struct in_addr v4addr;
317 317 in_port_t port;
318 318 int n;
319 319
320 320 ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_set_addr");
321 321
322 322 if (sap->sa_family == AF_INET6 &&
323 323 IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
324 324 IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &v4addr);
325 325 (void) inet_ntop(AF_INET, &v4addr, buf, sizeof (buf));
326 326 port = ntohs(sin6->sin6_port);
327 327 } else if (sap->sa_family == AF_INET6) {
328 328 (void) inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof (buf));
329 329 port = ntohs(sin6->sin6_port);
330 330 } else {
331 331 (void) inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof (buf));
332 332 port = ntohs(sin->sin_port);
333 333 }
334 334
335 335 n = strlen(buf);
336 336 (void) snprintf(buf + n, sizeof (buf) - n, ":%u", port);
337 337
338 338 if (ipx->ipx_addr)
339 339 fmd_hdl_strfree(ip_hdl, ipx->ipx_addr);
340 340 ipx->ipx_addr = fmd_hdl_strdup(ip_hdl, buf, FMD_SLEEP);
341 341 ip_debug(IP_DEBUG_FINE, "connection addr is %s on %p",
342 342 ipx->ipx_addr, (void *)ipx);
343 343 }
344 344
345 345 static nvlist_t *
346 346 ip_xprt_auth(ip_xprt_t *ipx)
347 347 {
348 348 nvlist_t *nvl;
349 349 int err;
350 350
351 351 ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_auth");
352 352
353 353 if (ip_auth != NULL)
354 354 err = nvlist_dup(ip_auth, &nvl, 0);
355 355 else
356 356 err = nvlist_alloc(&nvl, 0, 0);
357 357
358 358 if (err != 0) {
359 359 fmd_hdl_abort(ip_hdl, "failed to create nvlist for "
360 360 "authority: %s\n", strerror(err));
361 361 }
362 362
363 363 if (ip_auth != NULL)
364 364 return (nvl);
365 365
366 366 ip_debug(IP_DEBUG_FINE, "ip_authority %s=%s\n",
367 367 FM_FMRI_AUTH_SERVER, ipx->ipx_addr);
368 368
369 369 (void) nvlist_add_uint8(nvl, FM_VERSION, FM_FMRI_AUTH_VERSION);
370 370 (void) nvlist_add_string(nvl, FM_FMRI_AUTH_SERVER, ipx->ipx_addr);
371 371
372 372 return (nvl);
373 373 }
374 374
375 375 static void
376 376 ip_xprt_accept(ip_xprt_t *ipx)
377 377 {
378 378 struct sockaddr_storage sa;
379 379 socklen_t salen = sizeof (sa);
380 380 fmd_xprt_t *xp;
381 381 int fd;
382 382
383 383 ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_accept");
384 384
385 385 if ((fd = accept(ipx->ipx_fd, (struct sockaddr *)&sa, &salen)) == -1) {
386 386 fmd_hdl_error(ip_hdl, "failed to accept connection");
387 387 ip_stat.ips_accfail.fmds_value.ui64++;
388 388 return;
389 389 }
390 390 ip_debug(IP_DEBUG_FINE, "Accepted socket on fd %d", fd);
391 391
392 392 ip_xprt_set_addr(ipx, (struct sockaddr *)&sa);
393 393 xp = fmd_xprt_open(ip_hdl, ipx->ipx_flags,
394 394 ip_xprt_auth(ipx), NULL);
395 395 ip_xprt_create(xp, fd, ipx->ipx_flags, ipx->ipx_cinfo, ipx->ipx_addr);
396 396 }
397 397
398 398 static void
399 399 ip_xprt_recv_event(ip_xprt_t *ipx)
400 400 {
401 401 ip_hdr_t *iph;
402 402 nvlist_t *nvl;
403 403 size_t size;
404 404 void *buf;
405 405 int err;
406 406
407 407 if ((iph = ip_xprt_recv(ipx, sizeof (ip_hdr_t))) == NULL)
408 408 return; /* connection broken */
409 409
410 410 if (bcmp(iph->iph_magic, IP_MAGIC, IP_MAGLEN) != 0) {
411 411 fmd_hdl_error(ip_hdl,
412 412 "invalid hdr magic %x.%x.%x.%x from transport %s\n",
413 413 iph->iph_magic[0], iph->iph_magic[1], iph->iph_magic[2],
414 414 iph->iph_magic[3], IPX_ID(ipx));
415 415 ip_stat.ips_badmagic.fmds_value.ui64++;
416 416 return;
417 417 }
418 418
419 419 size = ntohl(iph->iph_size);
420 420
421 421 if ((buf = ip_xprt_recv(ipx, size)) == NULL)
422 422 return; /* connection broken */
423 423
424 424 if ((err = nvlist_unpack(buf, size, &nvl, 0)) != 0) {
425 425 fmd_hdl_error(ip_hdl, "failed to unpack event from "
426 426 "transport %s: %s\n",
427 427 IPX_ID(ipx), strerror(err));
428 428 ip_stat.ips_unpackfail.fmds_value.ui64++;
429 429 } else {
430 430 if (ip_domain_name)
431 431 fmd_xprt_add_domain(ip_hdl, nvl, ip_domain_name);
432 432 fmd_xprt_post(ip_hdl, ipx->ipx_xprt, nvl, 0);
433 433 }
434 434
435 435 if (fmd_xprt_error(ip_hdl, ipx->ipx_xprt)) {
436 436 fmd_hdl_error(ip_hdl, "protocol error on transport %p",
437 437 (void *)ipx->ipx_xprt);
438 438 ipx->ipx_done++;
439 439 }
440 440 ip_debug(IP_DEBUG_FINEST, "Recv event %d bytes from %s",
441 441 size, IPX_ID(ipx));
442 442 }
443 443
444 444 static void
445 445 ip_xprt_thread(void *arg)
446 446 {
447 447 ip_xprt_t *ipx = arg;
448 448 struct sockaddr_storage sa;
449 449 socklen_t salen = sizeof (sa);
450 450 struct pollfd pfd;
451 451
452 452 ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_thread");
453 453
454 454 while (!ip_quit && !ipx->ipx_done) {
455 455 if (ipx->ipx_xprt != NULL || (ipx->ipx_flags & FMD_XPRT_ACCEPT))
456 456 pfd.events = POLLIN;
457 457 else
458 458 pfd.events = POLLOUT;
459 459
460 460 pfd.fd = ipx->ipx_fd;
461 461 pfd.revents = 0;
462 462
463 463 if (poll(&pfd, 1, -1) <= 0)
464 464 continue; /* loop around and check ip_quit */
465 465
466 466 if (pfd.revents & (POLLHUP | POLLERR)) {
467 467 ip_debug(IP_DEBUG_FINE, "hangup fd %d\n", ipx->ipx_fd);
468 468 break;
469 469 }
470 470
471 471 if (pfd.revents & POLLOUT) {
472 472 /*
473 473 * Once we're connected, there's no reason to have our
474 474 * calls to recv() and send() be non-blocking since we
475 475 * we have separate threads for each: clear O_NONBLOCK.
476 476 */
477 477 (void) fcntl(ipx->ipx_fd, F_SETFL,
478 478 fcntl(ipx->ipx_fd, F_GETFL, 0) & ~O_NONBLOCK);
479 479
480 480 if (getpeername(ipx->ipx_fd, (struct sockaddr *)&sa,
481 481 &salen) != 0) {
482 482 ip_debug(IP_DEBUG_FINE,
483 483 "Not connected, no remote name for fd %d. "
484 484 " Will retry.",
485 485 ipx->ipx_fd);
486 486 bzero(&sa, sizeof (sa));
487 487 break;
488 488 }
489 489 ip_xprt_set_addr(ipx, (struct sockaddr *)&sa);
490 490 ipx->ipx_xprt = fmd_xprt_open(ip_hdl, ipx->ipx_flags,
491 491 ip_xprt_auth(ipx), ipx);
492 492
493 493 ip_debug(IP_DEBUG_FINE, "connect fd %d ipx %p",
494 494 ipx->ipx_fd, (void *)ipx);
495 495 continue;
496 496 }
497 497
498 498 if (pfd.revents & POLLIN) {
499 499 if (ipx->ipx_xprt == NULL)
500 500 ip_xprt_accept(ipx);
501 501 else
502 502 ip_xprt_recv_event(ipx);
503 503 }
504 504 }
505 505
506 506 ipx->ipx_cinfo->ipc_timer = fmd_timer_install(ip_hdl, ipx, NULL, 0);
507 507 ip_debug(IP_DEBUG_FINE, "close fd %d (timer %d)", ipx->ipx_fd,
508 508 (int)ipx->ipx_cinfo->ipc_timer);
509 509 }
510 510
511 511 static void
512 512 ip_xprt_create(fmd_xprt_t *xp, int fd, int flags, ip_cinfo_t *cinfo, char *addr)
513 513 {
514 514 ip_xprt_t *ipx = fmd_hdl_zalloc(ip_hdl, sizeof (ip_xprt_t), FMD_SLEEP);
515 515
516 516 ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_create %p", (void *)ipx);
517 517
518 518 ipx->ipx_xprt = xp;
519 519 ipx->ipx_flags = flags;
520 520 ipx->ipx_fd = fd;
521 521 ipx->ipx_tid = fmd_thr_create(ip_hdl, ip_xprt_thread, ipx);
522 522 ipx->ipx_cinfo = cinfo;
523 523 ipx->ipx_addr = fmd_hdl_strdup(ip_hdl, addr, FMD_SLEEP);
524 524
525 525 if (ipx->ipx_xprt != NULL)
526 526 fmd_xprt_setspecific(ip_hdl, ipx->ipx_xprt, ipx);
527 527
528 528 (void) pthread_mutex_lock(&ip_lock);
529 529
530 530 ipx->ipx_next = ip_xps;
531 531 ip_xps = ipx;
532 532
533 533 (void) pthread_mutex_unlock(&ip_lock);
534 534 }
535 535
536 536 static void
537 537 ip_xprt_destroy(ip_xprt_t *ipx)
538 538 {
539 539 ip_xprt_t *ipp, **ppx = &ip_xps;
540 540
541 541 ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_destory %s %p",
542 542 IPX_ID(ipx), (void *)ipx);
543 543
544 544 (void) pthread_mutex_lock(&ip_lock);
545 545
546 546 for (ipp = *ppx; ipp != NULL; ipp = ipp->ipx_next) {
547 547 if (ipp != ipx)
548 548 ppx = &ipp->ipx_next;
549 549 else
550 550 break;
551 551 }
552 552
553 553 if (ipp != ipx) {
554 554 (void) pthread_mutex_unlock(&ip_lock);
555 555 fmd_hdl_abort(ip_hdl, "ipx %p not on xps list\n", (void *)ipx);
556 556 }
557 557
558 558 *ppx = ipx->ipx_next;
559 559 ipx->ipx_next = NULL;
560 560
561 561 (void) pthread_mutex_unlock(&ip_lock);
562 562
563 563 if (ipx->ipx_spnd_timer)
564 564 fmd_timer_remove(ip_hdl, ipx->ipx_spnd_timer);
565 565
566 566 fmd_thr_signal(ip_hdl, ipx->ipx_tid);
567 567 fmd_thr_destroy(ip_hdl, ipx->ipx_tid);
568 568
569 569 if (ipx->ipx_xprt != NULL)
570 570 fmd_xprt_close(ip_hdl, ipx->ipx_xprt);
571 571
572 572 fmd_hdl_free(ip_hdl, ipx->ipx_sndbuf.ipb_buf, ipx->ipx_sndbuf.ipb_size);
573 573 fmd_hdl_free(ip_hdl, ipx->ipx_rcvbuf.ipb_buf, ipx->ipx_rcvbuf.ipb_size);
574 574
575 575 (void) close(ipx->ipx_fd);
576 576 if (ipx->ipx_addr) {
577 577 fmd_hdl_strfree(ip_hdl, ipx->ipx_addr);
578 578 ipx->ipx_addr = NULL;
579 579 }
580 580 fmd_hdl_free(ip_hdl, ipx, sizeof (ip_xprt_t));
581 581 }
582 582
583 583 /*
584 584 * Loop through the addresses in the connection info structure that were
585 585 * created by getaddrinfo() in ip_setup_addr during initialization (_fmd_init)
586 586 * and for each one attempt to create a socket and initialize it. If we are
587 587 * successful, return zero. If we fail, we check ip_retry: if it is non-zero
588 588 * we return the last errno and let our caller retry ip_xprt_setup() later. If
589 589 * ip_retry reaches zero, we call fmd_hdl_abort() with an appropriate message.
590 590 */
591 591 static int
592 592 ip_xprt_setup(fmd_hdl_t *hdl, ip_cinfo_t *cinfo)
593 593 {
594 594 int err, fd, oflags, xflags, optval = 1;
595 595 struct addrinfo *aip;
596 596 const char *s1, *s2;
597 597 struct addrinfo *ail = cinfo->ipc_addr;
598 598
599 599 ip_debug(IP_DEBUG_FINER, "Enter ip_xprt_setup %s\n",
600 600 cinfo->ipc_name == NULL ? "localhost" : cinfo->ipc_name);
601 601
602 602 /*
603 603 * Set up flags as specified in the .conf file. Note that these are
604 604 * mostly only used for testing purposes, allowing the transport to
605 605 * be set up in various modes.
606 606 */
607 607 xflags = (ip_rdonly == FMD_B_TRUE) ? FMD_XPRT_RDONLY : FMD_XPRT_RDWR;
608 608 if (cinfo->ipc_accept)
609 609 xflags |= FMD_XPRT_ACCEPT;
610 610 if (ip_external == FMD_B_TRUE)
611 611 xflags |= FMD_XPRT_EXTERNAL;
612 612 if (ip_no_remote_repair == FMD_B_TRUE)
613 613 xflags |= FMD_XPRT_NO_REMOTE_REPAIR;
614 614 if (ip_hconly == FMD_B_TRUE)
615 615 xflags |= FMD_XPRT_HCONLY;
616 616 if (ip_hc_present_only == FMD_B_TRUE)
617 617 xflags |= FMD_XPRT_HC_PRESENT_ONLY;
618 618
619 619 for (aip = ail; aip != NULL; aip = aip->ai_next) {
620 620 if (aip->ai_family != AF_INET && aip->ai_family != AF_INET6)
621 621 continue; /* ignore anything that isn't IPv4 or IPv6 */
622 622
623 623 if ((fd = socket(aip->ai_family,
624 624 aip->ai_socktype, aip->ai_protocol)) == -1) {
625 625 err = errno;
626 626 continue;
627 627 }
628 628
629 629 oflags = fcntl(fd, F_GETFL, 0);
630 630 (void) fcntl(fd, F_SETFL, oflags | O_NONBLOCK);
631 631
632 632 if (xflags & FMD_XPRT_ACCEPT) {
633 633 err = setsockopt(fd, SOL_SOCKET,
634 634 SO_REUSEADDR, &optval, sizeof (optval)) != 0 ||
635 635 bind(fd, aip->ai_addr, aip->ai_addrlen) != 0 ||
636 636 listen(fd, ip_qlen) != 0;
637 637 } else {
638 638 err = connect(fd, aip->ai_addr, aip->ai_addrlen);
639 639 if (err)
640 640 err = errno;
641 641 if (err == EINPROGRESS)
642 642 err = 0;
643 643 }
644 644
645 645 if (err == 0) {
646 646 ip_xprt_create(NULL, fd, xflags, cinfo, NULL);
647 647 ip_debug(IP_DEBUG_FINER, "Exit ip_xprt_setup");
648 648 return (0);
649 649 }
650 650
651 651 ip_debug(IP_DEBUG_FINE, "Error=%d errno=%d", err, errno);
652 652
653 653 err = errno;
654 654 (void) close(fd);
655 655 }
656 656
657 657 if (cinfo->ipc_name != NULL) {
658 658 s1 = "failed to connect to";
659 659 s2 = cinfo->ipc_name;
660 660 } else {
661 661 s1 = "failed to listen on";
662 662 s2 = ip_port;
663 663 }
664 664
665 665 if (err == EACCES || cinfo->ipc_retry-- == 0)
666 666 fmd_hdl_abort(hdl, "%s %s: %s\n", s1, s2, strerror(err));
667 667
668 668 ip_debug(IP_DEBUG_FINE, "%s %s: %s (will retry)\n",
669 669 s1, s2, strerror(err));
670 670 ip_debug(IP_DEBUG_FINER, "Exit ip_xprt_setup");
671 671 return (err);
672 672 }
673 673
674 674 /*
675 675 * Free address based resources
676 676 */
677 677 static void
678 678 ip_addr_cleanup()
679 679 {
680 680 ip_cinfo_t *conn;
681 681
682 682 (void) pthread_mutex_lock(&ip_conns_lock);
683 683 conn = ip_conns;
684 684 while (conn != NULL) {
685 685 ip_conns = conn->ipc_next;
686 686 if (conn->ipc_addr != NULL)
687 687 freeaddrinfo(conn->ipc_addr);
688 688 conn->ipc_addr = NULL;
689 689 if (conn->ipc_timer)
690 690 fmd_timer_remove(ip_hdl, conn->ipc_timer);
691 691 fmd_hdl_strfree(ip_hdl, conn->ipc_name);
692 692 fmd_hdl_free(ip_hdl, conn, sizeof (ip_cinfo_t));
693 693 conn = ip_conns;
694 694 }
695 695 (void) pthread_mutex_unlock(&ip_conns_lock);
696 696
697 697 fmd_prop_free_string(ip_hdl, ip_port);
698 698 }
699 699
700 700 static boolean_t
701 701 ip_argis_cinfo(void *arg)
702 702 {
703 703 boolean_t exists = B_FALSE;
704 704 ip_cinfo_t *conn;
705 705
706 706 (void) pthread_mutex_lock(&ip_conns_lock);
707 707 for (conn = ip_conns; conn != NULL; conn = conn->ipc_next) {
708 708 if (conn == arg) {
709 709 exists = B_TRUE;
710 710 break;
711 711 }
712 712 }
713 713 (void) pthread_mutex_unlock(&ip_conns_lock);
714 714
715 715 return (exists);
716 716 }
717 717
718 718
719 719 static ip_cinfo_t *
720 720 ip_create_cinfo(char *server, boolean_t accept)
721 721 {
722 722 int err;
723 723 struct addrinfo aih;
724 724 ip_cinfo_t *cinfo = fmd_hdl_zalloc(
725 725 ip_hdl, sizeof (ip_cinfo_t), FMD_NOSLEEP);
726 726
727 727 if (cinfo == NULL)
728 728 return (NULL);
729 729
730 730 cinfo->ipc_accept = accept;
731 731 cinfo->ipc_retry = ip_retry;
732 732 if (server != NULL) {
733 733 cinfo->ipc_name = fmd_hdl_strdup(ip_hdl, server, FMD_NOSLEEP);
734 734 if (cinfo->ipc_name == NULL) {
735 735 fmd_hdl_free(ip_hdl, cinfo, sizeof (ip_cinfo_t));
736 736 return (NULL);
737 737 }
738 738 }
739 739
740 740 bzero(&aih, sizeof (aih));
741 741 aih.ai_flags = AI_ADDRCONFIG;
742 742 aih.ai_family = AF_UNSPEC;
743 743 aih.ai_socktype = SOCK_STREAM;
744 744 if (server != NULL) {
745 745 ip_debug(IP_DEBUG_FINE, "resolving %s:%s\n", server, ip_port);
746 746 } else {
747 747 aih.ai_flags |= AI_PASSIVE;
748 748 cinfo->ipc_name = fmd_hdl_strdup(
749 749 ip_hdl, "localhost", FMD_NOSLEEP);
750 750 if (cinfo->ipc_name == NULL) {
751 751 fmd_hdl_free(ip_hdl, cinfo, sizeof (ip_cinfo_t));
752 752 return (NULL);
753 753 }
754 754 }
755 755
756 756 err = getaddrinfo(server, ip_port, &aih, &cinfo->ipc_addr);
757 757 if (err != 0) {
758 758 fmd_hdl_error(ip_hdl, "failed to resolve host %s port %s: %s\n",
759 759 cinfo->ipc_name, ip_port, gai_strerror(err));
760 760 cinfo->ipc_addr = NULL;
761 761 fmd_hdl_strfree(ip_hdl, cinfo->ipc_name);
762 762 fmd_hdl_free(ip_hdl, cinfo, sizeof (ip_cinfo_t));
763 763 cinfo = NULL;
764 764 }
765 765 return (cinfo);
766 766 }
767 767
768 768 /*
769 769 * Setup a single ip address for ip connection.
770 770 * If unable to setup any of the addresses then all addresses will be cleaned up
771 771 * and non-zero will be returned.
772 772 */
773 773 static int
774 774 ip_setup_addr(char *server, boolean_t accept)
775 775 {
776 776 int err = 0;
777 777 ip_cinfo_t *cinfo = ip_create_cinfo(server, accept);
778 778
779 779 if (cinfo == NULL) {
780 780 ip_addr_cleanup();
781 781 err++;
782 782 } else {
783 783 (void) pthread_mutex_lock(&ip_conns_lock);
784 784 cinfo->ipc_next = ip_conns;
785 785 ip_conns = cinfo;
786 786 (void) pthread_mutex_unlock(&ip_conns_lock);
787 787 }
788 788 return (err);
789 789 }
790 790
791 791 /*
792 792 * Setup a ip addresses for an ip connection. The address can be a comma
793 793 * separated list of addresses as well.
794 794 * If unable to setup any of the addresses then all addresses will be cleaned up
795 795 * and non-zero will be returned.
796 796 */
797 797 static int
798 798 ip_setup_addrs(char *server, boolean_t accept)
799 799 {
800 800 int err = 0;
801 801 char *addr = server;
802 802 char *p;
803 803
804 804 for (p = server; *p != '\0'; p++) {
805 805 if (*p == ',') {
806 806 *p = '\0';
807 807 err = ip_setup_addr(addr, accept);
808 808 *p = ',';
809 809 if (err)
810 810 return (err);
811 811 addr = ++p;
812 812 if (*addr == '\0')
813 813 break;
814 814 }
815 815 }
816 816 if (*addr != '\0') {
817 817 err = ip_setup_addr(addr, accept);
818 818 }
819 819 return (err);
820 820 }
821 821
822 822 /*
823 823 * Starts all connections for each configured network address. If there is an
824 824 * error starting a connection a timer will be started for a retry.
825 825 */
826 826 static void
827 827 ip_start_connections()
828 828 {
829 829 ip_cinfo_t *conn;
830 830
831 831 (void) pthread_mutex_lock(&ip_conns_lock);
832 832 for (conn = ip_conns; conn != NULL; conn = conn->ipc_next) {
833 833 if (ip_xprt_setup(ip_hdl, conn) != 0) {
834 834 conn->ipc_timer = fmd_timer_install(ip_hdl, conn, NULL,
835 835 ip_sleep);
836 836 }
837 837 }
838 838 (void) pthread_mutex_unlock(&ip_conns_lock);
839 839 }
840 840
841 841 /*
842 842 * Timeout handler for the transport module. We use these types of timeouts:
843 843 *
844 844 * (a) arg is ip_cinfo_t: attempt ip_xprt_setup(), re-install timeout to retry
845 845 * (b) arg is ip_xprt_t, FMD_XPRT_SUSPENDED: call fmd_xprt_resume() on arg
846 846 * (c) arg is ip_xprt_t, !FMD_XPRT_SUSPENDED: call ip_xprt_destroy() on arg
847 847 * (d) arg is NULL, ignore as this shouldn't happen
848 848 *
849 849 * Case (c) is required as we need to cause the module's main thread, which
850 850 * runs this timeout handler, to join with the transport's auxiliary thread.
851 851 * If the connection is a client then a timer will be installed to retry
852 852 * connecting to the server.
853 853 */
854 854 static void
855 855 ip_timeout(fmd_hdl_t *hdl, id_t id, void *arg) {
856 856 int install_timer;
857 857 ip_cinfo_t *cinfo;
858 858 ip_xprt_t *ipx;
859 859
860 860 if (arg == NULL) {
861 861 fmd_hdl_error(hdl, "ip_timeout failed because hg arg is NULL");
862 862 } else if (ip_argis_cinfo(arg)) {
863 863 ip_debug(IP_DEBUG_FINER,
864 864 "Enter ip_timeout (a) install new timer");
865 865 cinfo = arg;
866 866 if ((ip_xprt_setup(hdl, arg) != 0) && !ip_quit)
867 867 cinfo->ipc_timer = fmd_timer_install(
868 868 hdl, cinfo, NULL, ip_sleep);
869 869 else
870 870 cinfo->ipc_timer = NULL;
871 871 } else {
872 872 ipx = arg;
873 873 if (ipx->ipx_flags & FMD_XPRT_SUSPENDED) {
874 874 ipx->ipx_spnd_timer = NULL;
875 875 ip_debug(IP_DEBUG_FINE, "timer %d waking ipx %p",
876 876 (int)id, arg);
877 877 ipx->ipx_flags &= ~FMD_XPRT_SUSPENDED;
878 878 fmd_xprt_resume(hdl, ipx->ipx_xprt);
879 879 } else {
880 880 ip_debug(IP_DEBUG_FINE, "timer %d closing ipx %p",
881 881 (int)id, arg);
882 882 cinfo = ipx->ipx_cinfo;
883 883 install_timer = (ipx->ipx_flags & FMD_XPRT_ACCEPT) !=
884 884 FMD_XPRT_ACCEPT;
885 885 ip_xprt_destroy(ipx);
886 886 if (install_timer && !ip_quit)
887 887 cinfo->ipc_timer = fmd_timer_install(
888 888 hdl, cinfo, NULL, ip_sleep);
889 889 else
890 890 cinfo->ipc_timer = NULL;
891 891 }
892 892 }
893 893 }
894 894
895 895 static const fmd_prop_t fmd_props[] = {
896 896 { "ip_authority", FMD_TYPE_STRING, NULL },
897 897 { "ip_bufsize", FMD_TYPE_SIZE, "4k" },
898 898 { "ip_burp", FMD_TYPE_TIME, "0" },
899 899 { "ip_enable", FMD_TYPE_BOOL, "false" },
900 900 { "ip_mtbf", FMD_TYPE_INT32, "0" },
901 901 { "ip_external", FMD_TYPE_BOOL, "true" },
902 902 { "ip_no_remote_repair", FMD_TYPE_BOOL, "true" },
903 903 { "ip_hconly", FMD_TYPE_BOOL, "false" },
904 904 { "ip_rdonly", FMD_TYPE_BOOL, "false" },
905 905 { "ip_hc_present_only", FMD_TYPE_BOOL, "false" },
906 906 { "ip_domain_name", FMD_TYPE_STRING, NULL },
907 907 { "ip_port", FMD_TYPE_STRING, "664" },
908 908 { "ip_qlen", FMD_TYPE_INT32, "32" },
909 909 { "ip_retry", FMD_TYPE_INT32, "-1" }, /* -1=forever */
910 910 { "ip_server", FMD_TYPE_STRING, NULL }, /* server name */
911 911 { "ip_sleep", FMD_TYPE_TIME, "10s" },
912 912 { "ip_translate", FMD_TYPE_BOOL, "false" },
913 913 { "ip_bind_addr", FMD_TYPE_STRING, NULL }, /* network interface addr */
914 914 { "ip_debug_level", FMD_TYPE_INT32, "1" }, /* debug levels 0-3 */
915 915 { NULL, 0, NULL }
916 916 };
917 917
918 918 static const fmd_hdl_ops_t fmd_ops = {
919 919 ip_fmdo_recv, /* fmdo_recv */
920 920 ip_timeout, /* fmdo_timeout */
921 921 NULL, /* fmdo_close */
922 922 NULL, /* fmdo_stats */
923 923 NULL, /* fmdo_gc */
924 924 ip_fmdo_send, /* fmdo_send */
925 925 };
926 926
927 927 static const fmd_hdl_info_t fmd_info = {
928 928 "IP Transport Agent", "1.0", &fmd_ops, fmd_props
929 929 };
930 930
931 931 /*
932 932 * Initialize the ip-transport module as either a server or a client. Note
933 933 * that the ip-transport module is not enabled by default under Solaris:
934 934 * at present we require a developer or tool to "setprop ip_enable true".
935 935 * If ip-transport is needed in the future out-of-the-box on one or more Sun
936 936 * platforms, the code to check 'ip_enable' should be replaced with:
937 937 *
938 938 * (a) configuring ip-transport to operate in client mode by default,
939 939 * (b) a platform-specific configuration mechanism, or
940 940 * (c) a means to assure security and prevent denial-of-service attacks.
941 941 *
942 942 * Note that (c) is only an issue when the transport module operates
943 943 * in server mode (i.e. with the ip_server property set to NULL) on a
944 944 * generic Solaris system which may be exposed directly to the Internet.
945 945 * The property ip_bind_addr can be used to define a private network interface
946 946 * to use so that the service is not exposed to the Internet.
947 947 */
948 948 void
949 949 _fmd_init(fmd_hdl_t *hdl)
950 950 {
951 951 char *addr, *auth, *p, *q, *r, *s;
952 952 int err;
953 953
954 954 if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
955 955 return; /* failed to register handle */
956 956
957 957 if (fmd_prop_get_int32(hdl, "ip_enable") == FMD_B_FALSE) {
958 958 fmd_hdl_unregister(hdl);
959 959 return;
960 960 }
961 961
962 962 (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC,
963 963 sizeof (ip_stat) / sizeof (fmd_stat_t), (fmd_stat_t *)&ip_stat);
964 964
965 965 ip_hdl = hdl;
966 966 (void) pthread_mutex_init(&ip_lock, NULL);
967 967
968 968 ip_burp = fmd_prop_get_int64(hdl, "ip_burp");
969 969 ip_mtbf = fmd_prop_get_int32(hdl, "ip_mtbf");
970 970 ip_external = fmd_prop_get_int32(hdl, "ip_external");
971 971 ip_no_remote_repair = fmd_prop_get_int32(hdl, "ip_no_remote_repair");
972 972 ip_hconly = fmd_prop_get_int32(hdl, "ip_hconly");
973 973 ip_rdonly = fmd_prop_get_int32(hdl, "ip_rdonly");
974 974 ip_hc_present_only = fmd_prop_get_int32(hdl, "ip_hc_present_only");
975 975 ip_domain_name = fmd_prop_get_string(hdl, "ip_domain_name");
976 976 ip_qlen = fmd_prop_get_int32(hdl, "ip_qlen");
977 977 ip_retry = fmd_prop_get_int32(hdl, "ip_retry");
978 978 ip_sleep = fmd_prop_get_int64(hdl, "ip_sleep");
979 979 ip_translate = fmd_prop_get_int32(hdl, "ip_translate");
980 980
981 981 ip_size = (size_t)fmd_prop_get_int64(hdl, "ip_bufsize");
982 982 ip_size = MAX(ip_size, sizeof (ip_hdr_t));
983 983 ip_port = fmd_prop_get_string(hdl, "ip_port");
984 984 ip_debug_level = fmd_prop_get_int32(hdl, "ip_debug_level");
985 985
986 986 ip_conns = NULL;
987 987 addr = fmd_prop_get_string(hdl, "ip_bind_addr");
988 988 if (addr != NULL) {
989 989 err = ip_setup_addrs(addr, B_TRUE);
990 990 if (err) {
991 991 fmd_hdl_abort(hdl, "Unable to setup ip_bind_addr %s",
992 992 addr);
993 993 return;
994 994 }
995 995 fmd_prop_free_string(hdl, addr);
996 996 }
997 997 addr = fmd_prop_get_string(hdl, "ip_server");
998 998 if (addr != NULL) {
999 999 err = ip_setup_addrs(addr, B_FALSE);
1000 1000 if (err) {
1001 1001 fmd_hdl_abort(hdl, "Unable to setup ip_server %s",
1002 1002 addr);
1003 1003 return;
1004 1004 }
1005 1005 fmd_prop_free_string(hdl, addr);
1006 1006 }
1007 1007
1008 1008 /*
1009 1009 * If no specific connecitons configured then set up general server
1010 1010 * listening on all network ports.
1011 1011 */
1012 1012 if (ip_conns == NULL) {
1013 1013 if (ip_setup_addr(NULL, B_TRUE) != 0) {
1014 1014 fmd_hdl_abort(hdl, "Unable to setup server.");
1015 1015 return;
1016 1016 }
1017 1017 }
1018 1018
1019 1019 /*
1020 1020 * If ip_authority is set, tokenize this string and turn it into an
1021 1021 * FMA authority represented as a name-value pair list. We will use
1022 1022 * this authority for all transports created by this module. If
1023 1023 * ip_authority isn't set, we'll compute authorities on the fly.
1024 1024 */
1025 1025 if ((auth = fmd_prop_get_string(hdl, "ip_authority")) != NULL) {
1026 1026 (void) nvlist_alloc(&ip_auth, 0, 0);
1027 1027 (void) nvlist_add_uint8(ip_auth,
1028 1028 FM_VERSION, FM_FMRI_AUTH_VERSION);
1029 1029
1030 1030 s = strdupa(auth);
1031 1031 fmd_prop_free_string(hdl, auth);
1032 1032
1033 1033 for (p = strtok_r(s, ",", &q); p != NULL;
1034 1034 p = strtok_r(NULL, ",", &q)) {
1035 1035
1036 1036 if ((r = strchr(p, '=')) == NULL) {
1037 1037 ip_addr_cleanup();
1038 1038 fmd_hdl_abort(hdl, "ip_authority element <%s> "
1039 1039 "must be in <name>=<value> form\n", p);
1040 1040 }
1041 1041
1042 1042 *r = '\0';
1043 1043 (void) nvlist_add_string(ip_auth, p, r + 1);
1044 1044 *r = '=';
1045 1045 }
1046 1046 }
1047 1047
1048 1048 ip_start_connections();
↓ open down ↓ |
1048 lines elided |
↑ open up ↑ |
1049 1049 }
1050 1050
1051 1051 void
1052 1052 _fmd_fini(fmd_hdl_t *hdl)
1053 1053 {
1054 1054 ip_quit++; /* set quit flag before signalling auxiliary threads */
1055 1055
1056 1056 while (ip_xps != NULL)
1057 1057 ip_xprt_destroy(ip_xps);
1058 1058
1059 - if (ip_auth != NULL)
1060 - nvlist_free(ip_auth);
1059 + nvlist_free(ip_auth);
1061 1060
1062 1061 ip_addr_cleanup();
1063 1062
1064 1063 if (ip_domain_name != NULL)
1065 1064 fmd_prop_free_string(ip_hdl, ip_domain_name);
1066 1065
1067 1066 fmd_hdl_unregister(hdl);
1068 1067 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX