Print this page
3910 t_look(3NSL) should never return T_ERROR
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/avs/rdc/sndrd.c
+++ new/usr/src/cmd/avs/rdc/sndrd.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]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26 /*
27 27 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 + * Copyright 2014 Gary Mills
28 29 */
29 30
30 31 /*
31 32 * Network SNDR/ncall-ip server - based on nfsd
32 33 */
33 34 #include <sys/types.h>
34 35 #include <rpc/types.h>
35 36 #include <errno.h>
36 37 #include <netdb.h>
37 38 #include <sys/socket.h>
38 39 #include <netconfig.h>
39 40 #include <stropts.h>
40 41 #include <fcntl.h>
41 42 #include <stdio.h>
42 43 #include <strings.h>
43 44 #include <signal.h>
44 45 #include <unistd.h>
45 46 #include <stdlib.h>
46 47 #include <netdir.h>
47 48 #include <rpc/rpc_com.h>
48 49 #include <rpc/rpc.h>
49 50 #include <tiuser.h>
50 51 #include <netinet/tcp.h>
51 52 #include <netinet/in.h>
52 53 #include <syslog.h>
53 54 #include <locale.h>
54 55 #include <langinfo.h>
55 56 #include <libintl.h>
56 57 #include <libgen.h>
57 58 #include <deflt.h>
58 59 #include <sys/resource.h>
59 60
60 61 #include <sys/nsctl/nsctl.h>
61 62
62 63 #ifdef __NCALL__
63 64
64 65 #include <sys/ncall/ncall.h>
65 66 #include <sys/ncall/ncall_ip.h>
66 67 #include <sys/nsctl/libncall.h>
67 68
68 69 #define RDC_POOL_CREATE NC_IOC_POOL_CREATE
69 70 #define RDC_POOL_RUN NC_IOC_POOL_RUN
70 71 #define RDC_POOL_WAIT NC_IOC_POOL_WAIT
71 72 #define RDC_PROGRAM NCALL_PROGRAM
72 73 #define RDC_SERVICE "ncall"
73 74 #undef RDC_SVCPOOL_ID /* We are overloading this value */
74 75 #define RDC_SVCPOOL_ID NCALL_SVCPOOL_ID
75 76 #define RDC_SVC_NAME "NCALL"
76 77 #define RDC_VERS_MIN NCALL_VERS_MIN
77 78 #define RDC_VERS_MAX NCALL_VERS_MAX
78 79
79 80 #else /* !__NCALL__ */
80 81
81 82 #include <sys/nsctl/rdc_ioctl.h>
82 83 #include <sys/nsctl/rdc_io.h>
83 84 #include <sys/nsctl/librdc.h>
84 85
85 86 #define RDC_SERVICE "rdc"
86 87 #define RDC_SVC_NAME "RDC"
87 88
88 89 #endif /* __NCALL__ */
89 90
90 91 #define RDCADMIN "/etc/default/sndr"
91 92
92 93 #include <nsctl.h>
93 94
94 95 struct conn_ind {
95 96 struct conn_ind *conn_next;
96 97 struct conn_ind *conn_prev;
97 98 struct t_call *conn_call;
98 99 };
99 100
100 101 struct conn_entry {
101 102 bool_t closing;
102 103 struct netconfig nc;
103 104 };
104 105
105 106 static char *progname;
106 107 static struct conn_entry *conn_polled;
107 108 static int num_conns; /* Current number of connections */
108 109 static struct pollfd *poll_array; /* array of poll descriptors for poll */
109 110 static size_t num_fds = 0; /* number of transport fds opened */
110 111 static void poll_for_action();
111 112 static void remove_from_poll_list(int);
112 113 static int do_poll_cots_action(int, int);
113 114 static int do_poll_clts_action(int, int);
114 115 static void add_to_poll_list(int, struct netconfig *);
115 116 static int bind_to_provider(char *, char *, struct netbuf **,
116 117 struct netconfig **);
117 118 static int set_addrmask(int, struct netconfig *, struct netbuf *);
118 119 static void conn_close_oldest(void);
119 120 static boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
120 121 static void cots_listen_event(int, int);
121 122 static int discon_get(int, struct netconfig *, struct conn_ind **);
122 123 static int nofile_increase(int);
123 124 static int is_listen_fd_index(int);
124 125 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
125 126 static int sndrsvcpool(int);
126 127 static int svcwait(int id);
127 128 #endif
128 129
129 130
130 131 /*
131 132 * RPC protocol block. Useful for passing registration information.
132 133 */
133 134 struct protob {
134 135 char *serv; /* ASCII service name, e.g. "RDC" */
135 136 int versmin; /* minimum version no. to be registered */
136 137 int versmax; /* maximum version no. to be registered */
137 138 int program; /* program no. to be registered */
138 139 struct protob *next; /* next entry on list */
139 140 };
140 141
141 142
142 143
143 144 static size_t end_listen_fds;
144 145 static int debugflg = 0;
145 146 static int max_conns_allowed = -1;
146 147 static int listen_backlog = 10;
147 148 static char *trans_provider = (char *)NULL;
148 149 static int rdcsvc(int, struct netbuf, struct netconfig *);
149 150
150 151 /* used by cots_listen_event() */
151 152 static int (*Mysvc)(int, struct netbuf, struct netconfig *) = rdcsvc;
152 153
153 154 /*
154 155 * Determine valid semantics for rdc.
155 156 */
156 157 #define OK_TPI_TYPE(_nconf) \
157 158 (_nconf->nc_semantics == NC_TPI_CLTS || \
158 159 _nconf->nc_semantics == NC_TPI_COTS || \
159 160 _nconf->nc_semantics == NC_TPI_COTS_ORD)
160 161
161 162 #define BE32_TO_U32(a) \
162 163 ((((uint32_t)((uchar_t *)a)[0] & 0xFF) << (uint32_t)24) |\
163 164 (((uint32_t)((uchar_t *)a)[1] & 0xFF) << (uint32_t)16) |\
164 165 (((uint32_t)((uchar_t *)a)[2] & 0xFF) << (uint32_t)8) |\
165 166 ((uint32_t)((uchar_t *)a)[3] & 0xFF))
166 167
167 168 #ifdef DEBUG
168 169 /*
169 170 * Only support UDP in DEBUG mode for now
170 171 */
171 172 static char *defaultproviders[] = { "/dev/tcp", "/dev/tcp6", "/dev/udp",
172 173 "/dev/udp6", NULL };
173 174 #else
174 175 static char *defaultproviders[] = { "/dev/tcp6", "/dev/tcp", NULL };
175 176 #endif
176 177
177 178 /*
178 179 * Number of elements to add to the poll array on each allocation.
179 180 */
180 181 #define POLL_ARRAY_INC_SIZE 64
181 182 #define NOFILE_INC_SIZE 64
182 183
183 184 #ifdef __NCALL__
184 185 const char *rdc_devr = "/dev/ncallip";
185 186 #else
186 187 const char *rdc_devr = "/dev/rdc";
187 188 #endif
188 189
189 190 static int rdc_fdr;
190 191 static int
191 192
192 193 open_rdc(void)
193 194 {
194 195 int fd = open(rdc_devr, O_RDONLY);
195 196
196 197 if (fd < 0)
197 198 return (-1);
198 199
199 200 return (rdc_fdr = fd);
200 201 }
201 202
202 203 static int
203 204 sndrsys(int type, void *arg)
204 205 {
205 206 int ret = -1;
206 207 if (!rdc_fdr && open_rdc() < 0) { /* open failed */
207 208 syslog(LOG_ERR, "open_rdc() failed: %m\n");
208 209 } else {
209 210 if ((ret = ioctl(rdc_fdr, type, arg)) < 0) {
210 211 syslog(LOG_ERR, "ioctl(rdc_ioctl) failed: %m\n");
211 212 }
212 213 }
213 214 return (ret);
214 215 }
215 216
216 217 int
217 218 rdc_transport_open(struct netconfig *nconf)
218 219 {
219 220 int fd;
220 221 struct strioctl strioc;
221 222
222 223 if ((nconf == (struct netconfig *)NULL) ||
223 224 (nconf->nc_device == (char *)NULL)) {
224 225 syslog(LOG_ERR, "No netconfig device");
225 226 return (-1);
226 227 }
227 228
228 229 /*
229 230 * Open the transport device.
230 231 */
231 232 fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
232 233 if (fd == -1) {
233 234 if (t_errno == TSYSERR && errno == EMFILE &&
234 235 (nofile_increase(0) == 0)) {
235 236 /* Try again with a higher NOFILE limit. */
236 237 fd = t_open(nconf->nc_device, O_RDWR, NULL);
237 238 }
238 239 if (fd == -1) {
239 240 if (t_errno == TSYSERR) {
240 241 syslog(LOG_ERR, "t_open failed: %m");
241 242 } else {
242 243 syslog(LOG_ERR, "t_open failed: %s",
243 244 t_errlist[t_errno]);
244 245 }
245 246 return (-1);
246 247 }
247 248 }
248 249
249 250 /*
250 251 * Pop timod because the RPC module must be as close as possible
251 252 * to the transport.
252 253 */
253 254 if (ioctl(fd, I_POP, 0) < 0) {
254 255 syslog(LOG_ERR, "I_POP of timod failed: %m");
255 256 if (t_close(fd) == -1) {
256 257 if (t_errno == TSYSERR) {
257 258 syslog(LOG_ERR, "t_close failed on %d: %m", fd);
258 259 } else {
259 260 syslog(LOG_ERR, "t_close failed on %d: %s",
260 261 fd, t_errlist[t_errno]);
261 262 }
262 263 }
263 264 return (-1);
264 265 }
265 266
266 267 if (nconf->nc_semantics == NC_TPI_CLTS) {
267 268 /*
268 269 * Push rpcmod to filter data traffic to KRPC.
269 270 */
270 271 if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
271 272 syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
272 273 (void) t_close(fd);
273 274 return (-1);
274 275 }
275 276 } else {
276 277 if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
277 278 syslog(LOG_ERR, "I_PUSH of CONS rpcmod failed: %m");
278 279 if (t_close(fd) == -1) {
279 280 if (t_errno == TSYSERR) {
280 281 syslog(LOG_ERR,
281 282 "t_close failed on %d: %m", fd);
282 283 } else {
283 284 syslog(LOG_ERR,
284 285 "t_close failed on %d: %s",
285 286 fd, t_errlist[t_errno]);
286 287 }
287 288 }
288 289 return (-1);
289 290 }
290 291
291 292 strioc.ic_cmd = RPC_SERVER;
292 293 strioc.ic_dp = (char *)0;
293 294 strioc.ic_len = 0;
294 295 strioc.ic_timout = -1;
295 296 /* Tell CONS rpcmod to act like a server stream. */
296 297 if (ioctl(fd, I_STR, &strioc) < 0) {
297 298 syslog(LOG_ERR, "CONS rpcmod set-up ioctl failed: %m");
298 299 if (t_close(fd) == -1) {
299 300 if (t_errno == TSYSERR) {
300 301 syslog(LOG_ERR,
301 302 "t_close failed on %d: %m", fd);
302 303 } else {
303 304 syslog(LOG_ERR,
304 305 "t_close failed on %d: %s",
305 306 fd, t_errlist[t_errno]);
306 307 }
307 308 }
308 309 return (-1);
309 310 }
310 311 }
311 312
312 313 /*
313 314 * Re-push timod so that we will still be doing TLI
314 315 * operations on the descriptor.
315 316 */
316 317 if (ioctl(fd, I_PUSH, "timod") < 0) {
317 318 syslog(LOG_ERR, "I_PUSH of timod failed: %m");
318 319 if (t_close(fd) == -1) {
319 320 if (t_errno == TSYSERR) {
320 321 syslog(LOG_ERR, "t_close failed on %d: %m", fd);
321 322 } else {
322 323 syslog(LOG_ERR, "t_close failed on %d: %s",
323 324 fd, t_errlist[t_errno]);
324 325 }
325 326 }
326 327 return (-1);
327 328 }
328 329
329 330 return (fd);
330 331 }
331 332
332 333
333 334 void
334 335 rdcd_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
335 336 {
336 337 int error;
337 338
338 339 /*
339 340 * Save the error code across syslog(), just in case syslog()
340 341 * gets its own error and, therefore, overwrites errno.
341 342 */
342 343 error = errno;
343 344 if (t_errno == TSYSERR) {
344 345 syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
345 346 tli_name, fd, nconf->nc_proto);
346 347 } else {
347 348 syslog(LOG_ERR,
348 349 "%s(file descriptor %d/transport %s) TLI error %d",
349 350 tli_name, fd, nconf->nc_proto, t_errno);
350 351 }
351 352 errno = error;
352 353 }
353 354
354 355 /*
355 356 * Called to set up service over a particular transport
356 357 */
357 358 void
358 359 do_one(char *provider, char *proto, struct protob *protobp0,
359 360 int (*svc)(int, struct netbuf, struct netconfig *))
360 361 {
361 362 struct netbuf *retaddr;
362 363 struct netconfig *retnconf;
363 364 struct netbuf addrmask;
364 365 int vers;
365 366 int sock;
366 367
367 368 if (provider) {
368 369 sock = bind_to_provider(provider, protobp0->serv, &retaddr,
369 370 &retnconf);
370 371 } else {
371 372 (void) syslog(LOG_ERR,
372 373 "Cannot establish %s service over %s: transport setup problem.",
373 374 protobp0->serv, provider ? provider : proto);
374 375 return;
375 376 }
376 377
377 378 if (sock == -1) {
378 379 if ((Is_ipv6present() &&
379 380 (strcmp(provider, "/dev/tcp6") == 0)) ||
380 381 (!Is_ipv6present() && (strcmp(provider, "/dev/tcp") == 0)))
381 382 (void) syslog(LOG_ERR,
382 383 "Cannot establish %s service over %s: transport "
383 384 "setup problem.",
384 385 protobp0->serv, provider ? provider : proto);
385 386 return;
386 387 }
387 388
388 389 if (set_addrmask(sock, retnconf, &addrmask) < 0) {
389 390 (void) syslog(LOG_ERR,
390 391 "Cannot set address mask for %s", retnconf->nc_netid);
391 392 return;
392 393 }
393 394
394 395
395 396 /*
396 397 * Register all versions of the programs in the protocol block list
397 398 */
398 399 for (vers = protobp0->versmin; vers <= protobp0->versmax; vers++) {
399 400 (void) rpcb_unset(protobp0->program, vers, retnconf);
400 401 (void) rpcb_set(protobp0->program, vers, retnconf, retaddr);
401 402 }
402 403
403 404 if (retnconf->nc_semantics == NC_TPI_CLTS) {
404 405 /* Don't drop core if supporting module(s) aren't loaded. */
405 406 (void) signal(SIGSYS, SIG_IGN);
406 407
407 408 /*
408 409 * svc() doesn't block, it returns success or failure.
409 410 */
410 411 if ((*svc)(sock, addrmask, retnconf) < 0) {
411 412 (void) syslog(LOG_ERR, "Cannot establish %s service "
412 413 "over <file desc. %d, protocol %s> : %m. Exiting",
413 414 protobp0->serv, sock, retnconf->nc_proto);
414 415 exit(1);
415 416 }
416 417 }
417 418 /*
418 419 * We successfully set up the server over this transport.
419 420 * Add this descriptor to the one being polled on.
420 421 */
421 422 add_to_poll_list(sock, retnconf);
422 423 }
423 424
424 425 /*
425 426 * Set up the SNDR/ncall-ip service over all the available transports.
426 427 * Returns -1 for failure, 0 for success.
427 428 */
428 429 int
429 430 do_all(struct protob *protobp,
430 431 int (*svc)(int, struct netbuf, struct netconfig *))
431 432 {
432 433 struct netconfig *nconf;
433 434 NCONF_HANDLE *nc;
434 435
435 436 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
436 437 syslog(LOG_ERR, "setnetconfig failed: %m");
437 438 return (-1);
438 439 }
439 440 while (nconf = getnetconfig(nc)) {
440 441 if ((nconf->nc_flag & NC_VISIBLE) &&
441 442 strcmp(nconf->nc_protofmly, "loopback") != 0 &&
442 443 OK_TPI_TYPE(nconf))
443 444 do_one(nconf->nc_device, nconf->nc_proto, protobp, svc);
444 445 }
445 446 (void) endnetconfig(nc);
446 447 return (0);
447 448 }
448 449
449 450 /*
450 451 * Read the /etc/default/sndr configuration file to determine if the
451 452 * client has been configured for number of threads, backlog or transport
452 453 * provider.
453 454 */
454 455
455 456 static void
456 457 read_default(void)
457 458 {
458 459 char *defval, *tmp_str;
459 460 int errno;
460 461 int tmp;
461 462
462 463 /* Fail silently if error in opening the default rdc config file */
463 464 if ((defopen(RDCADMIN)) == 0) {
464 465 if ((defval = defread("SNDR_THREADS=")) != NULL) {
465 466 errno = 0;
466 467 tmp = strtol(defval, (char **)NULL, 10);
467 468 if (errno == 0) {
468 469 max_conns_allowed = tmp;
469 470 }
470 471 }
471 472 if ((defval = defread("SNDR_LISTEN_BACKLOG=")) != NULL) {
472 473 errno = 0;
473 474 tmp = strtol(defval, (char **)NULL, 10);
474 475 if (errno == 0) {
475 476 listen_backlog = tmp;
476 477 }
477 478 }
478 479 if ((defval = defread("SNDR_TRANSPORT=")) != NULL) {
479 480 errno = 0;
480 481 tmp_str = strdup(defval);
481 482 if (errno == 0) {
482 483 trans_provider = tmp_str;
483 484 }
484 485 }
485 486 /* close defaults file */
486 487 (void) defopen(NULL);
487 488 }
488 489 }
489 490 #ifdef lint
490 491 int
491 492 sndrd_lintmain(int ac, char **av)
492 493 #else
493 494 int
494 495 main(int ac, char **av)
495 496 #endif
496 497 {
497 498 const char *dir = "/";
498 499 int allflag = 0;
499 500 int pid;
500 501 int i, rc;
501 502 struct protob *protobp0, *protobp;
502 503 char **providerp;
503 504 char *required;
504 505 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
505 506 int maxservers;
506 507 #endif
507 508
508 509 (void) setlocale(LC_ALL, "");
509 510 #ifdef __NCALL__
510 511 (void) textdomain("ncall");
511 512 #else
512 513 (void) textdomain("rdc");
513 514 #endif
514 515
515 516 progname = basename(av[0]);
516 517
517 518 #ifdef __NCALL__
518 519 rc = ncall_check_release(&required);
519 520 #else
520 521 rc = rdc_check_release(&required);
521 522 #endif
522 523 if (rc < 0) {
523 524 (void) fprintf(stderr,
524 525 gettext("%s: unable to determine the current "
525 526 "Solaris release: %s\n"), progname, strerror(errno));
526 527 exit(1);
527 528 } else if (rc == FALSE) {
528 529 (void) fprintf(stderr,
529 530 gettext("%s: incorrect Solaris release (requires %s)\n"),
530 531 progname, required);
531 532 exit(1);
532 533 }
533 534
534 535 openlog(progname, LOG_PID|LOG_CONS, LOG_DAEMON);
535 536 read_default();
536 537
537 538 /*
538 539 * Usage: <progname> [-c <number of threads>] [-t protocol] \
539 540 * [-d] [-l <listen backlog>]
540 541 */
541 542 while ((i = getopt(ac, av, "ac:t:dl:")) != EOF) {
542 543 switch (i) {
543 544 case 'a':
544 545 allflag = 1;
545 546 break;
546 547 case 'c':
547 548 max_conns_allowed = atoi(optarg);
548 549 if (max_conns_allowed <= 0)
549 550 max_conns_allowed = 16;
550 551 break;
551 552
552 553 case 'd':
553 554 debugflg++;
554 555 break;
555 556
556 557 case 't':
557 558 trans_provider = optarg;
558 559 break;
559 560
560 561 case 'l':
561 562 listen_backlog = atoi(optarg);
562 563 if (listen_backlog < 0)
563 564 listen_backlog = 32;
564 565 break;
565 566
566 567 default:
567 568 syslog(LOG_ERR,
568 569 "Usage: %s [-c <number of threads>] "
569 570 "[-d] [-t protocol] "
570 571 "[-l <listen backlog>]\n", progname);
571 572 exit(1);
572 573 break;
573 574 }
574 575 }
575 576
576 577 if (chroot(dir) < 0) {
577 578 syslog(LOG_ERR, "chroot failed: %m");
578 579 exit(1);
579 580 }
580 581
581 582 if (chdir(dir) < 0) {
582 583 syslog(LOG_ERR, "chdir failed: %m");
583 584 exit(1);
584 585 }
585 586
586 587 if (!debugflg) {
587 588 pid = fork();
588 589 if (pid < 0) {
589 590 syslog(LOG_ERR, "Fork failed\n");
590 591 exit(1);
591 592 }
592 593 if (pid != 0)
593 594 exit(0);
594 595
595 596 /*
596 597 * Close existing file descriptors, open "/dev/null" as
597 598 * standard input, output, and error, and detach from
598 599 * controlling terminal.
599 600 */
600 601 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
601 602 /* use closefrom(3C) from PSARC/2000/193 when possible */
602 603 closefrom(0);
603 604 #else
604 605 for (i = 0; i < _NFILE; i++)
605 606 (void) close(i);
606 607 #endif
607 608 (void) open("/dev/null", O_RDONLY);
608 609 (void) open("/dev/null", O_WRONLY);
609 610 (void) dup(1);
610 611 (void) setsid();
611 612
612 613 /*
613 614 * ignore all signals apart from SIGTERM.
614 615 */
615 616 for (i = 1; i < _sys_nsig; i++)
616 617 (void) sigset(i, SIG_IGN);
617 618
618 619 (void) sigset(SIGTERM, SIG_DFL);
619 620 }
620 621
621 622 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
622 623 /*
623 624 * Set up kernel RPC thread pool for the SNDR/ncall-ip server.
624 625 */
625 626 maxservers = (max_conns_allowed < 0 ? 16 : max_conns_allowed);
626 627 if (sndrsvcpool(maxservers)) {
627 628 (void) syslog(LOG_ERR,
628 629 "Can't set up kernel %s service: %m. Exiting", progname);
629 630 exit(1);
630 631 }
631 632
632 633 /*
633 634 * Set up blocked thread to do LWP creation on behalf of the kernel.
634 635 */
635 636 if (svcwait(RDC_SVCPOOL_ID)) {
636 637 (void) syslog(LOG_ERR,
637 638 "Can't set up %s pool creator: %m, Exiting", progname);
638 639 exit(1);
639 640 }
640 641 #endif
641 642
642 643 /*
643 644 * Build a protocol block list for registration.
644 645 */
645 646 protobp0 = protobp = (struct protob *)malloc(sizeof (struct protob));
646 647 protobp->serv = RDC_SVC_NAME;
647 648 protobp->versmin = RDC_VERS_MIN;
648 649 protobp->versmax = RDC_VERS_MAX;
649 650 protobp->program = RDC_PROGRAM;
650 651 protobp->next = (struct protob *)NULL;
651 652
652 653 if (allflag) {
653 654 if (do_all(protobp0, rdcsvc) == -1)
654 655 exit(1);
655 656 } else if (trans_provider)
656 657 do_one(trans_provider, NULL, protobp0, rdcsvc);
657 658 else {
658 659 for (providerp = defaultproviders;
659 660 *providerp != NULL; providerp++) {
660 661 trans_provider = *providerp;
661 662 do_one(trans_provider, NULL, protobp0, rdcsvc);
662 663 }
663 664 }
664 665
665 666 done:
666 667 free(protobp);
667 668
668 669 end_listen_fds = num_fds;
669 670 /*
670 671 * Poll for non-data control events on the transport descriptors.
671 672 */
672 673 poll_for_action();
673 674
674 675 syslog(LOG_ERR, "%s fatal server error\n", progname);
675 676
676 677 return (-1);
677 678 }
678 679
679 680 static int
680 681 reuseaddr(int fd)
681 682 {
682 683 struct t_optmgmt req, resp;
683 684 struct opthdr *opt;
684 685 char reqbuf[128];
685 686 int *ip;
686 687
687 688 /* LINTED pointer alignment */
688 689 opt = (struct opthdr *)reqbuf;
689 690 opt->level = SOL_SOCKET;
690 691 opt->name = SO_REUSEADDR;
691 692 opt->len = sizeof (int);
692 693
693 694 /* LINTED pointer alignment */
694 695 ip = (int *)&reqbuf[sizeof (struct opthdr)];
695 696 *ip = 1;
696 697
697 698 req.flags = T_NEGOTIATE;
698 699 req.opt.len = sizeof (struct opthdr) + opt->len;
699 700 req.opt.buf = (char *)opt;
700 701
701 702 resp.flags = 0;
702 703 resp.opt.buf = reqbuf;
703 704 resp.opt.maxlen = sizeof (reqbuf);
704 705
705 706 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
706 707 if (t_errno == TSYSERR) {
707 708 syslog(LOG_ERR, "reuseaddr() t_optmgmt failed: %m\n");
708 709 } else {
709 710 syslog(LOG_ERR, "reuseaddr() t_optmgmt failed: %s\n",
710 711 t_errlist[t_errno]);
711 712 }
712 713 return (-1);
713 714 }
714 715 return (0);
715 716 }
716 717
717 718 /*
718 719 * poll on the open transport descriptors for events and errors.
719 720 */
720 721 void
721 722 poll_for_action(void)
722 723 {
723 724 int nfds;
724 725 int i;
725 726
726 727 /*
727 728 * Keep polling until all transports have been closed. When this
728 729 * happens, we return.
729 730 */
730 731 while ((int)num_fds > 0) {
731 732 nfds = poll(poll_array, num_fds, INFTIM);
732 733 switch (nfds) {
733 734 case 0:
734 735 continue;
735 736
736 737 case -1:
737 738 /*
738 739 * Some errors from poll could be
739 740 * due to temporary conditions, and we try to
740 741 * be robust in the face of them. Other
741 742 * errors (should never happen in theory)
742 743 * are fatal (eg. EINVAL, EFAULT).
743 744 */
744 745 switch (errno) {
745 746 case EINTR:
746 747 continue;
747 748
748 749 case EAGAIN:
749 750 case ENOMEM:
750 751 (void) sleep(10);
751 752 continue;
752 753
753 754 default:
754 755 (void) syslog(LOG_ERR,
755 756 "poll failed: %m. Exiting");
756 757 exit(1);
757 758 }
758 759 default:
759 760 break;
760 761 }
761 762
762 763 /*
763 764 * Go through the poll list looking for events.
764 765 */
765 766 for (i = 0; i < num_fds && nfds > 0; i++) {
766 767 if (poll_array[i].revents) {
767 768 nfds--;
768 769 /*
769 770 * We have a message, so try to read it.
770 771 * Record the error return in errno,
771 772 * so that syslog(LOG_ERR, "...%m")
772 773 * dumps the corresponding error string.
773 774 */
774 775 if (conn_polled[i].nc.nc_semantics ==
775 776 NC_TPI_CLTS) {
776 777 errno = do_poll_clts_action(
777 778 poll_array[i].fd, i);
778 779 } else {
779 780 errno = do_poll_cots_action(
780 781 poll_array[i].fd, i);
781 782 }
782 783
783 784 if (errno == 0)
784 785 continue;
785 786 /*
786 787 * Most returned error codes mean that there is
787 788 * fatal condition which we can only deal with
788 789 * by closing the transport.
789 790 */
790 791 if (errno != EAGAIN && errno != ENOMEM) {
791 792 (void) syslog(LOG_ERR,
792 793 "Error (%m) reading descriptor %d"
793 794 "/transport %s. Closing it.",
794 795 poll_array[i].fd,
795 796 conn_polled[i].nc.nc_proto);
796 797 (void) t_close(poll_array[i].fd);
797 798 remove_from_poll_list(poll_array[i].fd);
798 799 } else if (errno == ENOMEM)
799 800 (void) sleep(5);
800 801 }
801 802 }
802 803 }
803 804
804 805 (void) syslog(LOG_ERR,
805 806 "All transports have been closed with errors. Exiting.");
806 807 }
807 808
808 809 /*
809 810 * Allocate poll/transport array entries for this descriptor.
810 811 */
811 812 static void
812 813 add_to_poll_list(int fd, struct netconfig *nconf)
813 814 {
814 815 static int poll_array_size = 0;
815 816
816 817 /*
817 818 * If the arrays are full, allocate new ones.
818 819 */
819 820 if (num_fds == poll_array_size) {
820 821 struct pollfd *tpa;
821 822 struct conn_entry *tnp;
822 823
823 824 if (poll_array_size != 0) {
824 825 tpa = poll_array;
825 826 tnp = conn_polled;
826 827 } else
827 828 tpa = (struct pollfd *)0;
828 829
829 830 poll_array_size += POLL_ARRAY_INC_SIZE;
830 831
831 832 /*
832 833 * Allocate new arrays.
833 834 */
834 835 poll_array = (struct pollfd *)
835 836 malloc(poll_array_size * sizeof (struct pollfd) + 256);
836 837 conn_polled = (struct conn_entry *)
837 838 malloc(poll_array_size * sizeof (struct conn_entry) + 256);
838 839 if (poll_array == (struct pollfd *)NULL ||
839 840 conn_polled == (struct conn_entry *)NULL) {
840 841 syslog(LOG_ERR, "malloc failed for poll array");
841 842 exit(1);
842 843 }
843 844
844 845 /*
845 846 * Copy the data of the old ones into new arrays, and
846 847 * free the old ones.
847 848 * num_fds is guaranteed to be less than
848 849 * poll_array_size, so this memcpy is safe.
849 850 */
850 851 if (tpa) {
851 852 (void) memcpy((void *)poll_array, (void *)tpa,
852 853 num_fds * sizeof (struct pollfd));
853 854 (void) memcpy((void *)conn_polled, (void *)tnp,
854 855 num_fds * sizeof (struct conn_entry));
855 856 free((void *)tpa);
856 857 free((void *)tnp);
857 858 }
858 859 }
859 860
860 861 /*
861 862 * Set the descriptor and event list. All possible events are
862 863 * polled for.
863 864 */
864 865 poll_array[num_fds].fd = fd;
865 866 poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
866 867
867 868 /*
868 869 * Copy the transport data over too.
869 870 */
870 871 conn_polled[num_fds].nc = *nconf; /* structure copy */
871 872 conn_polled[num_fds].closing = 0;
872 873
873 874 /*
874 875 * Set the descriptor to non-blocking. Avoids a race
875 876 * between data arriving on the stream and then having it
876 877 * flushed before we can read it.
877 878 */
878 879 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
879 880 (void) syslog(LOG_ERR,
880 881 "fcntl(file desc. %d/transport %s, F_SETFL, "
881 882 "O_NONBLOCK): %m. Exiting",
882 883 num_fds, nconf->nc_proto);
883 884 exit(1);
884 885 }
885 886
886 887 /*
887 888 * Count this descriptor.
888 889 */
889 890 ++num_fds;
890 891 }
891 892
892 893 static void
893 894 remove_from_poll_list(int fd)
894 895 {
895 896 int i;
896 897 int num_to_copy;
897 898
898 899 for (i = 0; i < num_fds; i++) {
899 900 if (poll_array[i].fd == fd) {
900 901 --num_fds;
901 902 num_to_copy = num_fds - i;
902 903 (void) memcpy((void *)&poll_array[i],
903 904 (void *)&poll_array[i+1],
904 905 num_to_copy * sizeof (struct pollfd));
905 906 (void) memset((void *)&poll_array[num_fds], 0,
906 907 sizeof (struct pollfd));
907 908 (void) memcpy((void *)&conn_polled[i],
908 909 (void *)&conn_polled[i+1],
909 910 num_to_copy * sizeof (struct conn_entry));
910 911 (void) memset((void *)&conn_polled[num_fds], 0,
911 912 sizeof (struct conn_entry));
912 913 return;
913 914 }
914 915 }
915 916 syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
916 917
917 918 }
918 919
919 920 static void
920 921 conn_close_oldest(void)
921 922 {
922 923 int fd;
923 924 int i1;
924 925
925 926 /*
926 927 * Find the oldest connection that is not already in the
927 928 * process of shutting down.
928 929 */
929 930 for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
930 931 if (i1 >= num_fds)
931 932 return;
932 933 if (conn_polled[i1].closing == 0)
933 934 break;
934 935 }
935 936 #ifdef DEBUG
936 937 (void) printf("too many connections (%d), releasing oldest (%d)\n",
937 938 num_conns, poll_array[i1].fd);
938 939 #else
939 940 syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
940 941 num_conns, poll_array[i1].fd);
941 942 #endif
942 943 fd = poll_array[i1].fd;
943 944 if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
944 945 /*
945 946 * For politeness, send a T_DISCON_REQ to the transport
946 947 * provider. We close the stream anyway.
947 948 */
948 949 (void) t_snddis(fd, (struct t_call *)0);
949 950 num_conns--;
950 951 remove_from_poll_list(fd);
951 952 (void) t_close(fd);
952 953 } else {
953 954 /*
954 955 * For orderly release, we do not close the stream
955 956 * until the T_ORDREL_IND arrives to complete
956 957 * the handshake.
957 958 */
958 959 if (t_sndrel(fd) == 0)
959 960 conn_polled[i1].closing = 1;
960 961 }
961 962 }
962 963
963 964 static boolean_t
964 965 conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
965 966 {
966 967 struct conn_ind *conn;
967 968 struct conn_ind *next_conn;
968 969
969 970 conn = (struct conn_ind *)malloc(sizeof (*conn));
970 971 if (conn == NULL) {
971 972 syslog(LOG_ERR, "malloc for listen indication failed");
972 973 return (FALSE);
973 974 }
974 975
975 976 /* LINTED pointer alignment */
976 977 conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
977 978 if (conn->conn_call == NULL) {
978 979 free((char *)conn);
979 980 rdcd_log_tli_error("t_alloc", fd, nconf);
980 981 return (FALSE);
981 982 }
982 983
983 984 if (t_listen(fd, conn->conn_call) == -1) {
984 985 rdcd_log_tli_error("t_listen", fd, nconf);
985 986 (void) t_free((char *)conn->conn_call, T_CALL);
986 987 free((char *)conn);
987 988 return (FALSE);
988 989 }
989 990
990 991 if (conn->conn_call->udata.len > 0) {
991 992 syslog(LOG_WARNING,
992 993 "rejecting inbound connection(%s) with %d bytes "
993 994 "of connect data",
994 995 nconf->nc_proto, conn->conn_call->udata.len);
995 996
996 997 conn->conn_call->udata.len = 0;
997 998 (void) t_snddis(fd, conn->conn_call);
998 999 (void) t_free((char *)conn->conn_call, T_CALL);
999 1000 free((char *)conn);
1000 1001 return (FALSE);
1001 1002 }
1002 1003
1003 1004 if ((next_conn = *connp) != NULL) {
1004 1005 next_conn->conn_prev->conn_next = conn;
1005 1006 conn->conn_next = next_conn;
1006 1007 conn->conn_prev = next_conn->conn_prev;
1007 1008 next_conn->conn_prev = conn;
1008 1009 } else {
1009 1010 conn->conn_next = conn;
1010 1011 conn->conn_prev = conn;
1011 1012 *connp = conn;
1012 1013 }
1013 1014 return (TRUE);
1014 1015 }
1015 1016
1016 1017 static int
1017 1018 discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1018 1019 {
1019 1020 struct conn_ind *conn;
1020 1021 struct t_discon discon;
1021 1022
1022 1023 discon.udata.buf = (char *)0;
1023 1024 discon.udata.maxlen = 0;
1024 1025 if (t_rcvdis(fd, &discon) == -1) {
1025 1026 rdcd_log_tli_error("t_rcvdis", fd, nconf);
1026 1027 return (-1);
1027 1028 }
1028 1029
1029 1030 conn = *connp;
1030 1031 if (conn == NULL)
1031 1032 return (0);
1032 1033
1033 1034 do {
1034 1035 if (conn->conn_call->sequence == discon.sequence) {
1035 1036 if (conn->conn_next == conn)
1036 1037 *connp = (struct conn_ind *)0;
1037 1038 else {
1038 1039 if (conn == *connp) {
1039 1040 *connp = conn->conn_next;
1040 1041 }
1041 1042 conn->conn_next->conn_prev = conn->conn_prev;
1042 1043 conn->conn_prev->conn_next = conn->conn_next;
1043 1044 }
1044 1045 free((char *)conn);
1045 1046 break;
1046 1047 }
1047 1048 conn = conn->conn_next;
1048 1049 } while (conn != *connp);
1049 1050
1050 1051 return (0);
1051 1052 }
1052 1053
1053 1054 static void
1054 1055 cots_listen_event(int fd, int conn_index)
1055 1056 {
1056 1057 struct t_call *call;
1057 1058 struct conn_ind *conn;
1058 1059 struct conn_ind *conn_head;
1059 1060 int event;
1060 1061 struct netconfig *nconf = &conn_polled[conn_index].nc;
1061 1062 int new_fd;
1062 1063 struct netbuf addrmask;
1063 1064 int ret = 0;
1064 1065
1065 1066 conn_head = NULL;
1066 1067 (void) conn_get(fd, nconf, &conn_head);
1067 1068
1068 1069 while ((conn = conn_head) != NULL) {
1069 1070 conn_head = conn->conn_next;
1070 1071 if (conn_head == conn)
1071 1072 conn_head = NULL;
1072 1073 else {
1073 1074 conn_head->conn_prev = conn->conn_prev;
1074 1075 conn->conn_prev->conn_next = conn_head;
1075 1076 }
1076 1077 call = conn->conn_call;
1077 1078 free(conn);
1078 1079
1079 1080 /*
1080 1081 * If we have already accepted the maximum number of
1081 1082 * connections allowed on the command line, then drop
1082 1083 * the oldest connection (for any protocol) before
1083 1084 * accepting the new connection. Unless explicitly
1084 1085 * set on the command line, max_conns_allowed is -1.
1085 1086 */
1086 1087 if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
1087 1088 conn_close_oldest();
1088 1089
1089 1090 /*
1090 1091 * Create a new transport endpoint for the same proto as
1091 1092 * the listener.
1092 1093 */
1093 1094 new_fd = rdc_transport_open(nconf);
1094 1095 if (new_fd == -1) {
1095 1096 call->udata.len = 0;
1096 1097 (void) t_snddis(fd, call);
1097 1098 (void) t_free((char *)call, T_CALL);
1098 1099 syslog(LOG_ERR, "Cannot establish transport over %s",
1099 1100 nconf->nc_device);
1100 1101 continue;
1101 1102 }
1102 1103
1103 1104 /* Bind to a generic address/port for the accepting stream. */
1104 1105 if (t_bind(new_fd, NULL, NULL) == -1) {
1105 1106 rdcd_log_tli_error("t_bind", new_fd, nconf);
1106 1107 call->udata.len = 0;
1107 1108 (void) t_snddis(fd, call);
1108 1109 (void) t_free((char *)call, T_CALL);
1109 1110 (void) t_close(new_fd);
1110 1111 continue;
1111 1112 }
1112 1113
1113 1114 while (t_accept(fd, new_fd, call) == -1) {
1114 1115 if (t_errno != TLOOK) {
1115 1116 rdcd_log_tli_error("t_accept", fd, nconf);
1116 1117 call->udata.len = 0;
1117 1118 (void) t_snddis(fd, call);
1118 1119 (void) t_free((char *)call, T_CALL);
1119 1120 (void) t_close(new_fd);
1120 1121 goto do_next_conn;
1121 1122 }
1122 1123 while (event = t_look(fd)) {
1123 1124 switch (event) {
1124 1125 case T_LISTEN:
1125 1126 (void) conn_get(fd, nconf, &conn_head);
1126 1127 continue;
1127 1128
1128 1129 case T_DISCONNECT:
1129 1130 (void) discon_get(fd, nconf,
1130 1131 &conn_head);
1131 1132 continue;
1132 1133
1133 1134 default:
1134 1135 syslog(LOG_ERR,
1135 1136 "unexpected event 0x%x during "
1136 1137 "accept processing (%s)",
1137 1138 event, nconf->nc_proto);
1138 1139 call->udata.len = 0;
1139 1140 (void) t_snddis(fd, call);
1140 1141 (void) t_free((char *)call, T_CALL);
1141 1142 (void) t_close(new_fd);
1142 1143 goto do_next_conn;
1143 1144 }
1144 1145 }
1145 1146 }
1146 1147
1147 1148 if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
1148 1149 (void) syslog(LOG_ERR, "Cannot set address mask for %s",
1149 1150 nconf->nc_netid);
1150 1151 (void) t_snddis(new_fd, NULL);
1151 1152 (void) t_free((char *)call, T_CALL);
1152 1153 (void) t_close(new_fd);
1153 1154 continue;
1154 1155 }
1155 1156
1156 1157 /* Tell kRPC about the new stream. */
1157 1158 ret = (*Mysvc)(new_fd, addrmask, nconf);
1158 1159 if (ret < 0) {
1159 1160 syslog(LOG_ERR,
1160 1161 "unable to register with kernel rpc: %m");
1161 1162 free(addrmask.buf);
1162 1163 (void) t_snddis(new_fd, NULL);
1163 1164 (void) t_free((char *)call, T_CALL);
1164 1165 (void) t_close(new_fd);
1165 1166 goto do_next_conn;
1166 1167 }
1167 1168
1168 1169 free(addrmask.buf);
1169 1170 (void) t_free((char *)call, T_CALL);
1170 1171
1171 1172 /*
1172 1173 * Poll on the new descriptor so that we get disconnect
1173 1174 * and orderly release indications.
1174 1175 */
1175 1176 num_conns++;
1176 1177 add_to_poll_list(new_fd, nconf);
1177 1178
1178 1179 /* Reset nconf in case it has been moved. */
1179 1180 nconf = &conn_polled[conn_index].nc;
1180 1181 do_next_conn:;
1181 1182 }
1182 1183 }
1183 1184
1184 1185 static int
1185 1186 do_poll_cots_action(int fd, int conn_index)
1186 1187 {
1187 1188 char buf[256];
1188 1189 int event;
1189 1190 int i1;
1190 1191 int flags;
1191 1192 struct conn_entry *connent = &conn_polled[conn_index];
1192 1193 struct netconfig *nconf = &(connent->nc);
1193 1194 const char *errorstr;
1194 1195
1195 1196 while (event = t_look(fd)) {
1196 1197 switch (event) {
1197 1198 case T_LISTEN:
1198 1199 cots_listen_event(fd, conn_index);
1199 1200 break;
1200 1201
1201 1202 case T_DATA:
1202 1203 /*
1203 1204 * Receive a private notification from CONS rpcmod.
1204 1205 */
1205 1206 i1 = t_rcv(fd, buf, sizeof (buf), &flags);
1206 1207 if (i1 == -1) {
1207 1208 syslog(LOG_ERR, "t_rcv failed");
1208 1209 break;
1209 1210 }
1210 1211 if (i1 < sizeof (int))
1211 1212 break;
1212 1213 i1 = BE32_TO_U32(buf);
1213 1214 if (i1 == 1 || i1 == 2) {
1214 1215 /*
1215 1216 * This connection has been idle for too long,
1216 1217 * so release it as politely as we can. If we
1217 1218 * have already initiated an orderly release
1218 1219 * and we get notified that the stream is
1219 1220 * still idle, pull the plug. This prevents
1220 1221 * hung connections from continuing to consume
1221 1222 * resources.
1222 1223 */
1223 1224 if (nconf->nc_semantics == NC_TPI_COTS ||
1224 1225 connent->closing != 0) {
1225 1226 (void) t_snddis(fd, (struct t_call *)0);
1226 1227 goto fdclose;
1227 1228 }
1228 1229 /*
1229 1230 * For NC_TPI_COTS_ORD, the stream is closed
1230 1231 * and removed from the poll list when the
1231 1232 * T_ORDREL is received from the provider. We
1232 1233 * don't wait for it here because it may take
1233 1234 * a while for the transport to shut down.
1234 1235 */
1235 1236 if (t_sndrel(fd) == -1) {
1236 1237 syslog(LOG_ERR,
1237 1238 "unable to send orderly release %m");
1238 1239 }
1239 1240 connent->closing = 1;
1240 1241 } else
1241 1242 syslog(LOG_ERR,
1242 1243 "unexpected event from CONS rpcmod %d", i1);
1243 1244 break;
1244 1245
1245 1246 case T_ORDREL:
1246 1247 /* Perform an orderly release. */
1247 1248 if (t_rcvrel(fd) == 0) {
1248 1249 /* T_ORDREL on listen fd's should be ignored */
1249 1250 if (!is_listen_fd_index(fd)) {
1250 1251 (void) t_sndrel(fd);
1251 1252 goto fdclose;
1252 1253 }
1253 1254 break;
1254 1255
1255 1256 } else if (t_errno == TLOOK) {
1256 1257 break;
1257 1258 } else {
1258 1259 rdcd_log_tli_error("t_rcvrel", fd, nconf);
1259 1260 /*
1260 1261 * check to make sure we do not close
1261 1262 * listen fd
1262 1263 */
1263 1264 if (!is_listen_fd_index(fd))
1264 1265 break;
1265 1266 else
1266 1267 goto fdclose;
1267 1268 }
1268 1269
1269 1270 case T_DISCONNECT:
1270 1271 if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
↓ open down ↓ |
1233 lines elided |
↑ open up ↑ |
1271 1272 rdcd_log_tli_error("t_rcvdis", fd, nconf);
1272 1273
1273 1274 /*
1274 1275 * T_DISCONNECT on listen fd's should be ignored.
1275 1276 */
1276 1277 if (!is_listen_fd_index(fd))
1277 1278 break;
1278 1279 else
1279 1280 goto fdclose;
1280 1281
1281 - case T_ERROR:
1282 1282 default:
1283 - if (event == T_ERROR || t_errno == TSYSERR) {
1283 + if (t_errno == TSYSERR) {
1284 1284 if ((errorstr = strerror(errno)) == NULL) {
1285 1285 (void) snprintf(buf, sizeof (buf),
1286 1286 "Unknown error num %d", errno);
1287 1287 errorstr = (const char *)buf;
1288 1288 }
1289 1289 } else if (event == -1)
1290 1290 errorstr = t_strerror(t_errno);
1291 1291 else
1292 1292 errorstr = "";
1293 1293 #ifdef DEBUG
1294 1294 syslog(LOG_ERR,
1295 1295 "unexpected TLI event (0x%x) on "
1296 1296 "connection-oriented transport(%s, %d):%s",
1297 1297 event, nconf->nc_proto, fd, errorstr);
1298 1298 #endif
1299 1299
1300 1300 fdclose:
1301 1301 num_conns--;
1302 1302 remove_from_poll_list(fd);
1303 1303 (void) t_close(fd);
1304 1304 return (0);
1305 1305 }
1306 1306 }
1307 1307
1308 1308 return (0);
1309 1309 }
1310 1310
1311 1311
1312 1312 /*
1313 1313 * Called to read and interpret the event on a connectionless descriptor.
1314 1314 * Returns 0 if successful, or a UNIX error code if failure.
1315 1315 */
1316 1316 static int
1317 1317 do_poll_clts_action(int fd, int conn_index)
1318 1318 {
1319 1319 int error;
1320 1320 int ret;
1321 1321 int flags;
1322 1322 struct netconfig *nconf = &conn_polled[conn_index].nc;
1323 1323 static struct t_unitdata *unitdata = NULL;
1324 1324 static struct t_uderr *uderr = NULL;
1325 1325 static int oldfd = -1;
1326 1326 struct nd_hostservlist *host = NULL;
1327 1327 struct strbuf ctl[1], data[1];
1328 1328 /*
1329 1329 * We just need to have some space to consume the
1330 1330 * message in the event we can't use the TLI interface to do the
1331 1331 * job.
1332 1332 *
1333 1333 * We flush the message using getmsg(). For the control part
1334 1334 * we allocate enough for any TPI header plus 32 bytes for address
1335 1335 * and options. For the data part, there is nothing magic about
1336 1336 * the size of the array, but 256 bytes is probably better than
1337 1337 * 1 byte, and we don't expect any data portion anyway.
1338 1338 *
1339 1339 * If the array sizes are too small, we handle this because getmsg()
1340 1340 * (called to consume the message) will return MOREDATA|MORECTL.
1341 1341 * Thus we just call getmsg() until it's read the message.
1342 1342 */
1343 1343 char ctlbuf[sizeof (union T_primitives) + 32];
1344 1344 char databuf[256];
1345 1345
1346 1346 /*
1347 1347 * If this is the same descriptor as the last time
1348 1348 * do_poll_clts_action was called, we can save some
1349 1349 * de-allocation and allocation.
1350 1350 */
1351 1351 if (oldfd != fd) {
1352 1352 oldfd = fd;
1353 1353
1354 1354 if (unitdata) {
1355 1355 (void) t_free((char *)unitdata, T_UNITDATA);
1356 1356 unitdata = NULL;
1357 1357 }
1358 1358 if (uderr) {
1359 1359 (void) t_free((char *)uderr, T_UDERROR);
1360 1360 uderr = NULL;
1361 1361 }
1362 1362 }
1363 1363
1364 1364 /*
1365 1365 * Allocate a unitdata structure for receiving the event.
1366 1366 */
1367 1367 if (unitdata == NULL) {
1368 1368 /* LINTED pointer alignment */
1369 1369 unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
1370 1370 if (unitdata == NULL) {
1371 1371 if (t_errno == TSYSERR) {
1372 1372 /*
1373 1373 * Save the error code across
1374 1374 * syslog(), just in case
1375 1375 * syslog() gets its own error
1376 1376 * and therefore overwrites errno.
1377 1377 */
1378 1378 error = errno;
1379 1379 (void) syslog(LOG_ERR,
1380 1380 "t_alloc(file descriptor %d/transport %s, "
1381 1381 "T_UNITDATA) failed: %m",
1382 1382 fd, nconf->nc_proto);
1383 1383 return (error);
1384 1384 }
1385 1385 (void) syslog(LOG_ERR, "t_alloc(file descriptor %d/"
1386 1386 "transport %s, T_UNITDATA) failed TLI error %d",
1387 1387 fd, nconf->nc_proto, t_errno);
1388 1388 goto flush_it;
1389 1389 }
1390 1390 }
1391 1391
1392 1392 try_again:
1393 1393 flags = 0;
1394 1394
1395 1395 /*
1396 1396 * The idea is we wait for T_UNITDATA_IND's. Of course,
1397 1397 * we don't get any, because rpcmod filters them out.
1398 1398 * However, we need to call t_rcvudata() to let TLI
1399 1399 * tell us we have a T_UDERROR_IND.
1400 1400 *
1401 1401 * algorithm is:
1402 1402 * t_rcvudata(), expecting TLOOK.
1403 1403 * t_look(), expecting T_UDERR.
1404 1404 * t_rcvuderr(), expecting success (0).
1405 1405 * expand destination address into ASCII,
1406 1406 * and dump it.
1407 1407 */
1408 1408
1409 1409 ret = t_rcvudata(fd, unitdata, &flags);
1410 1410 if (ret == 0 || t_errno == TBUFOVFLW) {
1411 1411 (void) syslog(LOG_WARNING, "t_rcvudata(file descriptor %d/"
1412 1412 "transport %s) got unexpected data, %d bytes",
1413 1413 fd, nconf->nc_proto, unitdata->udata.len);
1414 1414
1415 1415 /*
1416 1416 * Even though we don't expect any data, in case we do,
1417 1417 * keep reading until there is no more.
1418 1418 */
1419 1419 if (flags & T_MORE)
1420 1420 goto try_again;
1421 1421
1422 1422 return (0);
1423 1423 }
1424 1424
1425 1425 switch (t_errno) {
1426 1426 case TNODATA:
1427 1427 return (0);
1428 1428 case TSYSERR:
1429 1429 /*
1430 1430 * System errors are returned to caller.
1431 1431 * Save the error code across
1432 1432 * syslog(), just in case
1433 1433 * syslog() gets its own error
1434 1434 * and therefore overwrites errno.
1435 1435 */
1436 1436 error = errno;
1437 1437 (void) syslog(LOG_ERR,
1438 1438 "t_rcvudata(file descriptor %d/transport %s) %m",
1439 1439 fd, nconf->nc_proto);
1440 1440 return (error);
1441 1441 case TLOOK:
1442 1442 break;
1443 1443 default:
1444 1444 (void) syslog(LOG_ERR,
1445 1445 "t_rcvudata(file descriptor %d/transport %s) TLI error %d",
1446 1446 fd, nconf->nc_proto, t_errno);
1447 1447 goto flush_it;
1448 1448 }
1449 1449
1450 1450 ret = t_look(fd);
1451 1451 switch (ret) {
1452 1452 case 0:
1453 1453 return (0);
1454 1454 case -1:
1455 1455 /*
1456 1456 * System errors are returned to caller.
1457 1457 */
1458 1458 if (t_errno == TSYSERR) {
1459 1459 /*
1460 1460 * Save the error code across
1461 1461 * syslog(), just in case
1462 1462 * syslog() gets its own error
1463 1463 * and therefore overwrites errno.
1464 1464 */
1465 1465 error = errno;
1466 1466 (void) syslog(LOG_ERR,
1467 1467 "t_look(file descriptor %d/transport %s) %m",
1468 1468 fd, nconf->nc_proto);
1469 1469 return (error);
1470 1470 }
1471 1471 (void) syslog(LOG_ERR,
1472 1472 "t_look(file descriptor %d/transport %s) TLI error %d",
1473 1473 fd, nconf->nc_proto, t_errno);
1474 1474 goto flush_it;
1475 1475 case T_UDERR:
1476 1476 break;
1477 1477 default:
1478 1478 (void) syslog(LOG_WARNING, "t_look(file descriptor %d/"
1479 1479 "transport %s) returned %d not T_UDERR (%d)",
1480 1480 fd, nconf->nc_proto, ret, T_UDERR);
1481 1481 }
1482 1482
1483 1483 if (uderr == NULL) {
1484 1484 /* LINTED pointer alignment */
1485 1485 uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
1486 1486 if (uderr == NULL) {
1487 1487 if (t_errno == TSYSERR) {
1488 1488 /*
1489 1489 * Save the error code across
1490 1490 * syslog(), just in case
1491 1491 * syslog() gets its own error
1492 1492 * and therefore overwrites errno.
1493 1493 */
1494 1494 error = errno;
1495 1495 (void) syslog(LOG_ERR,
1496 1496 "t_alloc(file descriptor %d/transport %s, "
1497 1497 "T_UDERROR) failed: %m",
1498 1498 fd, nconf->nc_proto);
1499 1499 return (error);
1500 1500 }
1501 1501 (void) syslog(LOG_ERR, "t_alloc(file descriptor %d/"
1502 1502 "transport %s, T_UDERROR) failed TLI error: %d",
1503 1503 fd, nconf->nc_proto, t_errno);
1504 1504 goto flush_it;
1505 1505 }
1506 1506 }
1507 1507
1508 1508 ret = t_rcvuderr(fd, uderr);
1509 1509 if (ret == 0) {
1510 1510
1511 1511 /*
1512 1512 * Save the datagram error in errno, so that the
1513 1513 * %m argument to syslog picks up the error string.
1514 1514 */
1515 1515 errno = uderr->error;
1516 1516
1517 1517 /*
1518 1518 * Log the datagram error, then log the host that
1519 1519 * probably triggerred. Cannot log both in the
1520 1520 * same transaction because of packet size limitations
1521 1521 * in /dev/log.
1522 1522 */
1523 1523 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1524 1524 "%s response over <file descriptor %d/transport %s> "
1525 1525 "generated error: %m",
1526 1526 progname, fd, nconf->nc_proto);
1527 1527
1528 1528 /*
1529 1529 * Try to map the client's address back to a
1530 1530 * name.
1531 1531 */
1532 1532 ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
1533 1533 if (ret != -1 && host && host->h_cnt > 0 &&
1534 1534 host->h_hostservs) {
1535 1535 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1536 1536 "Bad %s response was sent to client with "
1537 1537 "host name: %s; service port: %s",
1538 1538 progname, host->h_hostservs->h_host,
1539 1539 host->h_hostservs->h_serv);
1540 1540 } else {
1541 1541 int i, j;
1542 1542 char *buf;
1543 1543 char *hex = "0123456789abcdef";
1544 1544
1545 1545 /*
1546 1546 * Mapping failed, print the whole thing
1547 1547 * in ASCII hex.
1548 1548 */
1549 1549 buf = (char *)malloc(uderr->addr.len * 2 + 1);
1550 1550 for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
1551 1551 buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
1552 1552 buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
1553 1553 }
1554 1554 buf[j] = '\0';
1555 1555 (void) syslog((errno == ECONNREFUSED) ?
1556 1556 LOG_DEBUG : LOG_WARNING,
1557 1557 "Bad %s response was sent to client with "
1558 1558 "transport address: 0x%s",
1559 1559 progname, buf);
1560 1560 free((void *)buf);
1561 1561 }
1562 1562
1563 1563 if (ret == 0 && host != NULL)
1564 1564 netdir_free((void *)host, ND_HOSTSERVLIST);
1565 1565 return (0);
1566 1566 }
1567 1567
1568 1568 switch (t_errno) {
1569 1569 case TNOUDERR:
1570 1570 goto flush_it;
1571 1571 case TSYSERR:
1572 1572 /*
1573 1573 * System errors are returned to caller.
1574 1574 * Save the error code across
1575 1575 * syslog(), just in case
1576 1576 * syslog() gets its own error
1577 1577 * and therefore overwrites errno.
1578 1578 */
1579 1579 error = errno;
1580 1580 (void) syslog(LOG_ERR,
1581 1581 "t_rcvuderr(file descriptor %d/transport %s) %m",
1582 1582 fd, nconf->nc_proto);
1583 1583 return (error);
1584 1584 default:
1585 1585 (void) syslog(LOG_ERR,
1586 1586 "t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
1587 1587 fd, nconf->nc_proto, t_errno);
1588 1588 goto flush_it;
1589 1589 }
1590 1590
1591 1591 flush_it:
1592 1592 /*
1593 1593 * If we get here, then we could not cope with whatever message
1594 1594 * we attempted to read, so flush it. If we did read a message,
1595 1595 * and one isn't present, that is all right, because fd is in
1596 1596 * nonblocking mode.
1597 1597 */
1598 1598 (void) syslog(LOG_ERR,
1599 1599 "Flushing one input message from <file descriptor %d/transport %s>",
1600 1600 fd, nconf->nc_proto);
1601 1601
1602 1602 /*
1603 1603 * Read and discard the message. Do this this until there is
1604 1604 * no more control/data in the message or until we get an error.
1605 1605 */
1606 1606 do {
1607 1607 ctl->maxlen = sizeof (ctlbuf);
1608 1608 ctl->buf = ctlbuf;
1609 1609 data->maxlen = sizeof (databuf);
1610 1610 data->buf = databuf;
1611 1611 flags = 0;
1612 1612 ret = getmsg(fd, ctl, data, &flags);
1613 1613 if (ret == -1)
1614 1614 return (errno);
1615 1615 } while (ret != 0);
1616 1616
1617 1617 return (0);
1618 1618 }
1619 1619
1620 1620 /*
1621 1621 * Establish service thread.
1622 1622 */
1623 1623 static int
1624 1624 rdcsvc(int fd, struct netbuf addrmask, struct netconfig *nconf)
1625 1625 {
1626 1626 #ifdef __NCALL__
1627 1627 struct ncall_svc_args nsa;
1628 1628 #else /* !__NCALL__ */
1629 1629 struct rdc_svc_args nsa;
1630 1630 _rdc_ioctl_t rdc_args = { 0, };
1631 1631 #endif /* __NCALL__ */
1632 1632
1633 1633 nsa.fd = fd;
1634 1634 nsa.nthr = (max_conns_allowed < 0 ? 16 : max_conns_allowed);
1635 1635 (void) strncpy(nsa.netid, nconf->nc_netid, sizeof (nsa.netid));
1636 1636 nsa.addrmask.len = addrmask.len;
1637 1637 nsa.addrmask.maxlen = addrmask.maxlen;
1638 1638 nsa.addrmask.buf = addrmask.buf;
1639 1639
1640 1640 #ifdef __NCALL__
1641 1641 return (sndrsys(NC_IOC_SERVER, &nsa));
1642 1642 #else /* !__NCALL__ */
1643 1643 rdc_args.arg0 = (long)&nsa;
1644 1644 return (sndrsys(RDC_ENABLE_SVR, &rdc_args));
1645 1645 #endif /* __NCALL__ */
1646 1646 }
1647 1647
1648 1648
1649 1649
1650 1650 static int
1651 1651 nofile_increase(int limit)
1652 1652 {
1653 1653 struct rlimit rl;
1654 1654
1655 1655 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
1656 1656 syslog(LOG_ERR,
1657 1657 "nofile_increase() getrlimit of NOFILE failed: %m");
1658 1658 return (-1);
1659 1659 }
1660 1660
1661 1661 if (limit > 0)
1662 1662 rl.rlim_cur = limit;
1663 1663 else
1664 1664 rl.rlim_cur += NOFILE_INC_SIZE;
1665 1665
1666 1666 if (rl.rlim_cur > rl.rlim_max && rl.rlim_max != RLIM_INFINITY)
1667 1667 rl.rlim_max = rl.rlim_cur;
1668 1668
1669 1669 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
1670 1670 syslog(LOG_ERR,
1671 1671 "nofile_increase() setrlimit of NOFILE to %d failed: %m",
1672 1672 rl.rlim_cur);
1673 1673 return (-1);
1674 1674 }
1675 1675
1676 1676 return (0);
1677 1677 }
1678 1678
1679 1679 int
1680 1680 rdcd_bindit(struct netconfig *nconf, struct netbuf **addr,
1681 1681 struct nd_hostserv *hs, int backlog)
1682 1682 {
1683 1683 int fd;
1684 1684 struct t_bind *ntb;
1685 1685 struct t_bind tb;
1686 1686 struct nd_addrlist *addrlist;
1687 1687 struct t_optmgmt req, resp;
1688 1688 struct opthdr *opt;
1689 1689 char reqbuf[128];
1690 1690
1691 1691 if ((fd = rdc_transport_open(nconf)) == -1) {
1692 1692 syslog(LOG_ERR, "cannot establish transport service over %s",
1693 1693 nconf->nc_device);
1694 1694 return (-1);
1695 1695 }
1696 1696
1697 1697 addrlist = (struct nd_addrlist *)NULL;
1698 1698 if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
1699 1699 if (strncmp(nconf->nc_netid, "udp", 3) != 0) {
1700 1700 syslog(LOG_ERR, "Cannot get address for transport "
1701 1701 "%s host %s service %s",
1702 1702 nconf->nc_netid, hs->h_host, hs->h_serv);
1703 1703 }
1704 1704 (void) t_close(fd);
1705 1705 return (-1);
1706 1706 }
1707 1707
1708 1708 if (strcmp(nconf->nc_proto, "tcp") == 0) {
1709 1709 /*
1710 1710 * If we're running over TCP, then set the
1711 1711 * SO_REUSEADDR option so that we can bind
1712 1712 * to our preferred address even if previously
1713 1713 * left connections exist in FIN_WAIT states.
1714 1714 * This is somewhat bogus, but otherwise you have
1715 1715 * to wait 2 minutes to restart after killing it.
1716 1716 */
1717 1717 if (reuseaddr(fd) == -1) {
1718 1718 syslog(LOG_WARNING,
1719 1719 "couldn't set SO_REUSEADDR option on transport");
1720 1720 }
1721 1721 }
1722 1722
1723 1723 if (nconf->nc_semantics == NC_TPI_CLTS)
1724 1724 tb.qlen = 0;
1725 1725 else
1726 1726 tb.qlen = backlog;
1727 1727
1728 1728 /* LINTED pointer alignment */
1729 1729 ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
1730 1730 if (ntb == (struct t_bind *)NULL) {
1731 1731 syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno);
1732 1732 (void) t_close(fd);
1733 1733 netdir_free((void *)addrlist, ND_ADDRLIST);
1734 1734 return (-1);
1735 1735 }
1736 1736
1737 1737 tb.addr = *(addrlist->n_addrs); /* structure copy */
1738 1738
1739 1739 if (t_bind(fd, &tb, ntb) == -1) {
1740 1740 syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno);
1741 1741 (void) t_free((char *)ntb, T_BIND);
1742 1742 netdir_free((void *)addrlist, ND_ADDRLIST);
1743 1743 (void) t_close(fd);
1744 1744 return (-1);
1745 1745 }
1746 1746
1747 1747 /* make sure we bound to the right address */
1748 1748 if (tb.addr.len != ntb->addr.len ||
1749 1749 memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0) {
1750 1750 syslog(LOG_ERR, "t_bind to wrong address");
1751 1751 (void) t_free((char *)ntb, T_BIND);
1752 1752 netdir_free((void *)addrlist, ND_ADDRLIST);
1753 1753 (void) t_close(fd);
1754 1754 return (-1);
1755 1755 }
1756 1756
1757 1757 *addr = &ntb->addr;
1758 1758 netdir_free((void *)addrlist, ND_ADDRLIST);
1759 1759
1760 1760 if (strcmp(nconf->nc_proto, "tcp") == 0 ||
1761 1761 strcmp(nconf->nc_proto, "tcp6") == 0) {
1762 1762 /*
1763 1763 * Disable the Nagle algorithm on TCP connections.
1764 1764 * Connections accepted from this listener will
1765 1765 * inherit the listener options.
1766 1766 */
1767 1767
1768 1768 /* LINTED pointer alignment */
1769 1769 opt = (struct opthdr *)reqbuf;
1770 1770 opt->level = IPPROTO_TCP;
1771 1771 opt->name = TCP_NODELAY;
1772 1772 opt->len = sizeof (int);
1773 1773
1774 1774 /* LINTED pointer alignment */
1775 1775 *(int *)((char *)opt + sizeof (*opt)) = 1;
1776 1776
1777 1777 req.flags = T_NEGOTIATE;
1778 1778 req.opt.len = sizeof (*opt) + opt->len;
1779 1779 req.opt.buf = (char *)opt;
1780 1780 resp.flags = 0;
1781 1781 resp.opt.buf = reqbuf;
1782 1782 resp.opt.maxlen = sizeof (reqbuf);
1783 1783
1784 1784 if (t_optmgmt(fd, &req, &resp) < 0 ||
1785 1785 resp.flags != T_SUCCESS) {
1786 1786 syslog(LOG_ERR, "couldn't set NODELAY option for "
1787 1787 "proto %s: t_errno = %d, %m", nconf->nc_proto,
1788 1788 t_errno);
1789 1789 }
1790 1790 }
1791 1791
1792 1792 return (fd);
1793 1793 }
1794 1794
1795 1795
1796 1796 /* ARGSUSED */
1797 1797 static int
1798 1798 bind_to_provider(char *provider, char *serv, struct netbuf **addr,
1799 1799 struct netconfig **retnconf)
1800 1800 {
1801 1801 struct netconfig *nconf;
1802 1802 NCONF_HANDLE *nc;
1803 1803 struct nd_hostserv hs;
1804 1804
1805 1805 hs.h_host = HOST_SELF;
1806 1806 hs.h_serv = RDC_SERVICE; /* serv_name_to_port_name(serv); */
1807 1807
1808 1808 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1809 1809 syslog(LOG_ERR, "setnetconfig failed: %m");
1810 1810 return (-1);
1811 1811 }
1812 1812 while (nconf = getnetconfig(nc)) {
1813 1813 if (OK_TPI_TYPE(nconf) &&
1814 1814 strcmp(nconf->nc_device, provider) == 0) {
1815 1815 *retnconf = nconf;
1816 1816 return (rdcd_bindit(nconf, addr, &hs, listen_backlog));
1817 1817 }
1818 1818 }
1819 1819 (void) endnetconfig(nc);
1820 1820 if ((Is_ipv6present() && (strcmp(provider, "/dev/tcp6") == 0)) ||
1821 1821 (!Is_ipv6present() && (strcmp(provider, "/dev/tcp") == 0)))
1822 1822 syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
1823 1823 provider);
1824 1824 return (-1);
1825 1825 }
1826 1826
1827 1827
1828 1828 /*
1829 1829 * For listen fd's index is always less than end_listen_fds.
1830 1830 * It's value is equal to the number of open file descriptors after the
1831 1831 * last listen end point was opened but before any connection was accepted.
1832 1832 */
1833 1833 static int
1834 1834 is_listen_fd_index(int index)
1835 1835 {
1836 1836 return (index < end_listen_fds);
1837 1837 }
1838 1838
1839 1839
1840 1840 /*
1841 1841 * Create an address mask appropriate for the transport.
1842 1842 * The mask is used to obtain the host-specific part of
1843 1843 * a network address when comparing addresses.
1844 1844 * For an internet address the host-specific part is just
1845 1845 * the 32 bit IP address and this part of the mask is set
1846 1846 * to all-ones. The port number part of the mask is zeroes.
1847 1847 */
1848 1848 static int
1849 1849 set_addrmask(int fd, struct netconfig *nconf, struct netbuf *mask)
1850 1850 {
1851 1851 struct t_info info;
1852 1852
1853 1853 /*
1854 1854 * Find the size of the address we need to mask.
1855 1855 */
1856 1856 if (t_getinfo(fd, &info) < 0) {
1857 1857 t_error("t_getinfo");
1858 1858 return (-1);
1859 1859 }
1860 1860 mask->len = mask->maxlen = info.addr;
1861 1861 if (info.addr <= 0) {
1862 1862 syslog(LOG_ERR, "set_addrmask: address size: %ld", info.addr);
1863 1863 return (-1);
1864 1864 }
1865 1865
1866 1866 mask->buf = (char *)malloc(mask->len);
1867 1867 if (mask->buf == NULL) {
1868 1868 syslog(LOG_ERR, "set_addrmask: no memory");
1869 1869 return (-1);
1870 1870 }
1871 1871 (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */
1872 1872
1873 1873 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
1874 1874 /*
1875 1875 * Set the mask so that the port is ignored.
1876 1876 */
1877 1877 /* LINTED pointer alignment */
1878 1878 ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
1879 1879 (in_addr_t)~0;
1880 1880 /* LINTED pointer alignment */
1881 1881 ((struct sockaddr_in *)mask->buf)->sin_family = (sa_family_t)~0;
1882 1882 }
1883 1883 #ifdef NC_INET6
1884 1884 else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
1885 1885 /* LINTED pointer alignment */
1886 1886 (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
1887 1887 (uchar_t)~0, sizeof (struct in6_addr));
1888 1888 /* LINTED pointer alignment */
1889 1889 ((struct sockaddr_in6 *)mask->buf)->sin6_family =
1890 1890 (sa_family_t)~0;
1891 1891 }
1892 1892 #endif
1893 1893 else {
1894 1894 /*
1895 1895 * Set all mask bits.
1896 1896 */
1897 1897 (void) memset(mask->buf, (uchar_t)~0, mask->len);
1898 1898 }
1899 1899 return (0);
1900 1900 }
1901 1901
1902 1902 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
1903 1903
1904 1904 static int
1905 1905 sndrsvcpool(int maxservers)
1906 1906 {
1907 1907 struct svcpool_args npa;
1908 1908
1909 1909 npa.id = RDC_SVCPOOL_ID;
1910 1910 npa.maxthreads = maxservers;
1911 1911 npa.redline = 0;
1912 1912 npa.qsize = 0;
1913 1913 npa.timeout = 0;
1914 1914 npa.stksize = 0;
1915 1915 npa.max_same_xprt = 0;
1916 1916 return (sndrsys(RDC_POOL_CREATE, &npa));
1917 1917 }
1918 1918
1919 1919
1920 1920 /*
1921 1921 * The following stolen from cmd/fs.d/nfs/lib/thrpool.c
1922 1922 */
1923 1923
1924 1924 #include <thread.h>
1925 1925
1926 1926 /*
1927 1927 * Thread to call into the kernel and do work on behalf of SNDR/ncall-ip.
1928 1928 */
1929 1929 static void *
1930 1930 svcstart(void *arg)
1931 1931 {
1932 1932 int id = (int)arg;
1933 1933 int err;
1934 1934
1935 1935 while ((err = sndrsys(RDC_POOL_RUN, &id)) != 0) {
1936 1936 /*
1937 1937 * Interrupted by a signal while in the kernel.
1938 1938 * this process is still alive, try again.
1939 1939 */
1940 1940 if (err == EINTR)
1941 1941 continue;
1942 1942 else
1943 1943 break;
1944 1944 }
1945 1945
1946 1946 /*
1947 1947 * If we weren't interrupted by a signal, but did
1948 1948 * return from the kernel, this thread's work is done,
1949 1949 * and it should exit.
1950 1950 */
1951 1951 thr_exit(NULL);
1952 1952 return (NULL);
1953 1953 }
1954 1954
1955 1955 /*
1956 1956 * User-space "creator" thread. This thread blocks in the kernel
1957 1957 * until new worker threads need to be created for the service
1958 1958 * pool. On return to userspace, if there is no error, create a
1959 1959 * new thread for the service pool.
1960 1960 */
1961 1961 static void *
1962 1962 svcblock(void *arg)
1963 1963 {
1964 1964 int id = (int)arg;
1965 1965
1966 1966 /* CONSTCOND */
1967 1967 while (1) {
1968 1968 thread_t tid;
1969 1969 int err;
1970 1970
1971 1971 /*
1972 1972 * Call into the kernel, and hang out there
1973 1973 * until a thread needs to be created.
1974 1974 */
1975 1975 if (err = sndrsys(RDC_POOL_WAIT, &id)) {
1976 1976 if (err == ECANCELED || err == EBUSY)
1977 1977 /*
1978 1978 * If we get back ECANCELED, the service
1979 1979 * pool is exiting, and we may as well
1980 1980 * clean up this thread. If EBUSY is
1981 1981 * returned, there's already a thread
1982 1982 * looping on this pool, so we should
1983 1983 * give up.
1984 1984 */
1985 1985 break;
1986 1986 else
1987 1987 continue;
1988 1988 }
1989 1989
1990 1990 (void) thr_create(NULL, NULL, svcstart, (void *)id,
1991 1991 THR_BOUND | THR_DETACHED, &tid);
1992 1992 }
1993 1993
1994 1994 thr_exit(NULL);
1995 1995 return (NULL);
1996 1996 }
1997 1997
1998 1998 static int
1999 1999 svcwait(int id)
2000 2000 {
2001 2001 thread_t tid;
2002 2002
2003 2003 /*
2004 2004 * Create a bound thread to wait for kernel LWPs that
2005 2005 * need to be created.
2006 2006 */
2007 2007 if (thr_create(NULL, NULL, svcblock, (void *)id,
2008 2008 THR_BOUND | THR_DETACHED, &tid))
2009 2009 return (1);
2010 2010
2011 2011 return (0);
2012 2012 }
2013 2013 #endif /* Solaris 9+ */
↓ open down ↓ |
720 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX