4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2014 Gary Mills
32 * Network SNDR/ncall-ip server - based on nfsd
34 #include <sys/types.h>
35 #include <rpc/types.h>
38 #include <sys/socket.h>
39 #include <netconfig.h>
48 #include <rpc/rpc_com.h>
51 #include <netinet/tcp.h>
52 #include <netinet/in.h>
59 #include <sys/resource.h>
61 #include <sys/nsctl/nsctl.h>
65 #include <sys/ncall/ncall.h>
66 #include <sys/ncall/ncall_ip.h>
67 #include <sys/nsctl/libncall.h>
69 #define RDC_POOL_CREATE NC_IOC_POOL_CREATE
70 #define RDC_POOL_RUN NC_IOC_POOL_RUN
71 #define RDC_POOL_WAIT NC_IOC_POOL_WAIT
72 #define RDC_PROGRAM NCALL_PROGRAM
73 #define RDC_SERVICE "ncall"
74 #undef RDC_SVCPOOL_ID /* We are overloading this value */
75 #define RDC_SVCPOOL_ID NCALL_SVCPOOL_ID
76 #define RDC_SVC_NAME "NCALL"
77 #define RDC_VERS_MIN NCALL_VERS_MIN
78 #define RDC_VERS_MAX NCALL_VERS_MAX
80 #else /* !__NCALL__ */
82 #include <sys/nsctl/rdc_ioctl.h>
83 #include <sys/nsctl/rdc_io.h>
84 #include <sys/nsctl/librdc.h>
86 #define RDC_SERVICE "rdc"
87 #define RDC_SVC_NAME "RDC"
89 #endif /* __NCALL__ */
91 #define RDCADMIN "/etc/default/sndr"
96 struct conn_ind
*conn_next
;
97 struct conn_ind
*conn_prev
;
98 struct t_call
*conn_call
;
106 static char *progname
;
107 static struct conn_entry
*conn_polled
;
108 static int num_conns
; /* Current number of connections */
109 static struct pollfd
*poll_array
; /* array of poll descriptors for poll */
110 static size_t num_fds
= 0; /* number of transport fds opened */
111 static void poll_for_action();
112 static void remove_from_poll_list(int);
113 static int do_poll_cots_action(int, int);
114 static int do_poll_clts_action(int, int);
115 static void add_to_poll_list(int, struct netconfig
*);
116 static int bind_to_provider(char *, char *, struct netbuf
**,
117 struct netconfig
**);
118 static int set_addrmask(int, struct netconfig
*, struct netbuf
*);
119 static void conn_close_oldest(void);
120 static boolean_t
conn_get(int, struct netconfig
*, struct conn_ind
**);
121 static void cots_listen_event(int, int);
122 static int discon_get(int, struct netconfig
*, struct conn_ind
**);
123 static int nofile_increase(int);
124 static int is_listen_fd_index(int);
125 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
126 static int sndrsvcpool(int);
127 static int svcwait(int id
);
132 * RPC protocol block. Useful for passing registration information.
135 char *serv
; /* ASCII service name, e.g. "RDC" */
136 int versmin
; /* minimum version no. to be registered */
137 int versmax
; /* maximum version no. to be registered */
138 int program
; /* program no. to be registered */
139 struct protob
*next
; /* next entry on list */
144 static size_t end_listen_fds
;
145 static int debugflg
= 0;
146 static int max_conns_allowed
= -1;
147 static int listen_backlog
= 10;
148 static char *trans_provider
= (char *)NULL
;
149 static int rdcsvc(int, struct netbuf
, struct netconfig
*);
151 /* used by cots_listen_event() */
152 static int (*Mysvc
)(int, struct netbuf
, struct netconfig
*) = rdcsvc
;
155 * Determine valid semantics for rdc.
157 #define OK_TPI_TYPE(_nconf) \
158 (_nconf->nc_semantics == NC_TPI_CLTS || \
159 _nconf->nc_semantics == NC_TPI_COTS || \
160 _nconf->nc_semantics == NC_TPI_COTS_ORD)
162 #define BE32_TO_U32(a) \
163 ((((uint32_t)((uchar_t *)a)[0] & 0xFF) << (uint32_t)24) |\
164 (((uint32_t)((uchar_t *)a)[1] & 0xFF) << (uint32_t)16) |\
165 (((uint32_t)((uchar_t *)a)[2] & 0xFF) << (uint32_t)8) |\
166 ((uint32_t)((uchar_t *)a)[3] & 0xFF))
170 * Only support UDP in DEBUG mode for now
172 static char *defaultproviders
[] = { "/dev/tcp", "/dev/tcp6", "/dev/udp",
175 static char *defaultproviders
[] = { "/dev/tcp6", "/dev/tcp", NULL
};
179 * Number of elements to add to the poll array on each allocation.
181 #define POLL_ARRAY_INC_SIZE 64
182 #define NOFILE_INC_SIZE 64
185 const char *rdc_devr
= "/dev/ncallip";
187 const char *rdc_devr
= "/dev/rdc";
195 int fd
= open(rdc_devr
, O_RDONLY
);
200 return (rdc_fdr
= fd
);
204 sndrsys(int type
, void *arg
)
207 if (!rdc_fdr
&& open_rdc() < 0) { /* open failed */
208 syslog(LOG_ERR
, "open_rdc() failed: %m\n");
210 if ((ret
= ioctl(rdc_fdr
, type
, arg
)) < 0) {
211 syslog(LOG_ERR
, "ioctl(rdc_ioctl) failed: %m\n");
218 rdc_transport_open(struct netconfig
*nconf
)
221 struct strioctl strioc
;
223 if ((nconf
== (struct netconfig
*)NULL
) ||
224 (nconf
->nc_device
== (char *)NULL
)) {
225 syslog(LOG_ERR
, "No netconfig device");
230 * Open the transport device.
232 fd
= t_open(nconf
->nc_device
, O_RDWR
, (struct t_info
*)NULL
);
234 if (t_errno
== TSYSERR
&& errno
== EMFILE
&&
235 (nofile_increase(0) == 0)) {
236 /* Try again with a higher NOFILE limit. */
237 fd
= t_open(nconf
->nc_device
, O_RDWR
, NULL
);
240 if (t_errno
== TSYSERR
) {
241 syslog(LOG_ERR
, "t_open failed: %m");
243 syslog(LOG_ERR
, "t_open failed: %s",
251 * Pop timod because the RPC module must be as close as possible
254 if (ioctl(fd
, I_POP
, 0) < 0) {
255 syslog(LOG_ERR
, "I_POP of timod failed: %m");
256 if (t_close(fd
) == -1) {
257 if (t_errno
== TSYSERR
) {
258 syslog(LOG_ERR
, "t_close failed on %d: %m", fd
);
260 syslog(LOG_ERR
, "t_close failed on %d: %s",
261 fd
, t_errlist
[t_errno
]);
267 if (nconf
->nc_semantics
== NC_TPI_CLTS
) {
269 * Push rpcmod to filter data traffic to KRPC.
271 if (ioctl(fd
, I_PUSH
, "rpcmod") < 0) {
272 syslog(LOG_ERR
, "I_PUSH of rpcmod failed: %m");
277 if (ioctl(fd
, I_PUSH
, "rpcmod") < 0) {
278 syslog(LOG_ERR
, "I_PUSH of CONS rpcmod failed: %m");
279 if (t_close(fd
) == -1) {
280 if (t_errno
== TSYSERR
) {
282 "t_close failed on %d: %m", fd
);
285 "t_close failed on %d: %s",
286 fd
, t_errlist
[t_errno
]);
292 strioc
.ic_cmd
= RPC_SERVER
;
293 strioc
.ic_dp
= (char *)0;
295 strioc
.ic_timout
= -1;
296 /* Tell CONS rpcmod to act like a server stream. */
297 if (ioctl(fd
, I_STR
, &strioc
) < 0) {
298 syslog(LOG_ERR
, "CONS rpcmod set-up ioctl failed: %m");
299 if (t_close(fd
) == -1) {
300 if (t_errno
== TSYSERR
) {
302 "t_close failed on %d: %m", fd
);
305 "t_close failed on %d: %s",
306 fd
, t_errlist
[t_errno
]);
314 * Re-push timod so that we will still be doing TLI
315 * operations on the descriptor.
317 if (ioctl(fd
, I_PUSH
, "timod") < 0) {
318 syslog(LOG_ERR
, "I_PUSH of timod failed: %m");
319 if (t_close(fd
) == -1) {
320 if (t_errno
== TSYSERR
) {
321 syslog(LOG_ERR
, "t_close failed on %d: %m", fd
);
323 syslog(LOG_ERR
, "t_close failed on %d: %s",
324 fd
, t_errlist
[t_errno
]);
335 rdcd_log_tli_error(char *tli_name
, int fd
, struct netconfig
*nconf
)
340 * Save the error code across syslog(), just in case syslog()
341 * gets its own error and, therefore, overwrites errno.
344 if (t_errno
== TSYSERR
) {
345 syslog(LOG_ERR
, "%s(file descriptor %d/transport %s) %m",
346 tli_name
, fd
, nconf
->nc_proto
);
349 "%s(file descriptor %d/transport %s) TLI error %d",
350 tli_name
, fd
, nconf
->nc_proto
, t_errno
);
356 * Called to set up service over a particular transport
359 do_one(char *provider
, char *proto
, struct protob
*protobp0
,
360 int (*svc
)(int, struct netbuf
, struct netconfig
*))
362 struct netbuf
*retaddr
;
363 struct netconfig
*retnconf
;
364 struct netbuf addrmask
;
369 sock
= bind_to_provider(provider
, protobp0
->serv
, &retaddr
,
372 (void) syslog(LOG_ERR
,
373 "Cannot establish %s service over %s: transport setup problem.",
374 protobp0
->serv
, provider
? provider
: proto
);
379 if ((Is_ipv6present() &&
380 (strcmp(provider
, "/dev/tcp6") == 0)) ||
381 (!Is_ipv6present() && (strcmp(provider
, "/dev/tcp") == 0)))
382 (void) syslog(LOG_ERR
,
383 "Cannot establish %s service over %s: transport "
385 protobp0
->serv
, provider
? provider
: proto
);
389 if (set_addrmask(sock
, retnconf
, &addrmask
) < 0) {
390 (void) syslog(LOG_ERR
,
391 "Cannot set address mask for %s", retnconf
->nc_netid
);
397 * Register all versions of the programs in the protocol block list
399 for (vers
= protobp0
->versmin
; vers
<= protobp0
->versmax
; vers
++) {
400 (void) rpcb_unset(protobp0
->program
, vers
, retnconf
);
401 (void) rpcb_set(protobp0
->program
, vers
, retnconf
, retaddr
);
404 if (retnconf
->nc_semantics
== NC_TPI_CLTS
) {
405 /* Don't drop core if supporting module(s) aren't loaded. */
406 (void) signal(SIGSYS
, SIG_IGN
);
409 * svc() doesn't block, it returns success or failure.
411 if ((*svc
)(sock
, addrmask
, retnconf
) < 0) {
412 (void) syslog(LOG_ERR
, "Cannot establish %s service "
413 "over <file desc. %d, protocol %s> : %m. Exiting",
414 protobp0
->serv
, sock
, retnconf
->nc_proto
);
419 * We successfully set up the server over this transport.
420 * Add this descriptor to the one being polled on.
422 add_to_poll_list(sock
, retnconf
);
426 * Set up the SNDR/ncall-ip service over all the available transports.
427 * Returns -1 for failure, 0 for success.
430 do_all(struct protob
*protobp
,
431 int (*svc
)(int, struct netbuf
, struct netconfig
*))
433 struct netconfig
*nconf
;
436 if ((nc
= setnetconfig()) == (NCONF_HANDLE
*)NULL
) {
437 syslog(LOG_ERR
, "setnetconfig failed: %m");
440 while (nconf
= getnetconfig(nc
)) {
441 if ((nconf
->nc_flag
& NC_VISIBLE
) &&
442 strcmp(nconf
->nc_protofmly
, "loopback") != 0 &&
444 do_one(nconf
->nc_device
, nconf
->nc_proto
, protobp
, svc
);
446 (void) endnetconfig(nc
);
451 * Read the /etc/default/sndr configuration file to determine if the
452 * client has been configured for number of threads, backlog or transport
459 char *defval
, *tmp_str
;
463 /* Fail silently if error in opening the default rdc config file */
464 if ((defopen(RDCADMIN
)) == 0) {
465 if ((defval
= defread("SNDR_THREADS=")) != NULL
) {
467 tmp
= strtol(defval
, (char **)NULL
, 10);
469 max_conns_allowed
= tmp
;
472 if ((defval
= defread("SNDR_LISTEN_BACKLOG=")) != NULL
) {
474 tmp
= strtol(defval
, (char **)NULL
, 10);
476 listen_backlog
= tmp
;
479 if ((defval
= defread("SNDR_TRANSPORT=")) != NULL
) {
481 tmp_str
= strdup(defval
);
483 trans_provider
= tmp_str
;
486 /* close defaults file */
487 (void) defopen(NULL
);
492 sndrd_lintmain(int ac
, char **av
)
495 main(int ac
, char **av
)
498 const char *dir
= "/";
502 struct protob
*protobp0
, *protobp
;
505 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
509 (void) setlocale(LC_ALL
, "");
511 (void) textdomain("ncall");
513 (void) textdomain("rdc");
516 progname
= basename(av
[0]);
519 rc
= ncall_check_release(&required
);
521 rc
= rdc_check_release(&required
);
524 (void) fprintf(stderr
,
525 gettext("%s: unable to determine the current "
526 "Solaris release: %s\n"), progname
, strerror(errno
));
528 } else if (rc
== FALSE
) {
529 (void) fprintf(stderr
,
530 gettext("%s: incorrect Solaris release (requires %s)\n"),
535 openlog(progname
, LOG_PID
|LOG_CONS
, LOG_DAEMON
);
539 * Usage: <progname> [-c <number of threads>] [-t protocol] \
540 * [-d] [-l <listen backlog>]
542 while ((i
= getopt(ac
, av
, "ac:t:dl:")) != EOF
) {
548 max_conns_allowed
= atoi(optarg
);
549 if (max_conns_allowed
<= 0)
550 max_conns_allowed
= 16;
558 trans_provider
= optarg
;
562 listen_backlog
= atoi(optarg
);
563 if (listen_backlog
< 0)
569 "Usage: %s [-c <number of threads>] "
570 "[-d] [-t protocol] "
571 "[-l <listen backlog>]\n", progname
);
577 if (chroot(dir
) < 0) {
578 syslog(LOG_ERR
, "chroot failed: %m");
582 if (chdir(dir
) < 0) {
583 syslog(LOG_ERR
, "chdir failed: %m");
590 syslog(LOG_ERR
, "Fork failed\n");
597 * Close existing file descriptors, open "/dev/null" as
598 * standard input, output, and error, and detach from
599 * controlling terminal.
601 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
602 /* use closefrom(3C) from PSARC/2000/193 when possible */
605 for (i
= 0; i
< _NFILE
; i
++)
608 (void) open("/dev/null", O_RDONLY
);
609 (void) open("/dev/null", O_WRONLY
);
614 * ignore all signals apart from SIGTERM.
616 for (i
= 1; i
< _sys_nsig
; i
++)
617 (void) sigset(i
, SIG_IGN
);
619 (void) sigset(SIGTERM
, SIG_DFL
);
622 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
624 * Set up kernel RPC thread pool for the SNDR/ncall-ip server.
626 maxservers
= (max_conns_allowed
< 0 ? 16 : max_conns_allowed
);
627 if (sndrsvcpool(maxservers
)) {
628 (void) syslog(LOG_ERR
,
629 "Can't set up kernel %s service: %m. Exiting", progname
);
634 * Set up blocked thread to do LWP creation on behalf of the kernel.
636 if (svcwait(RDC_SVCPOOL_ID
)) {
637 (void) syslog(LOG_ERR
,
638 "Can't set up %s pool creator: %m, Exiting", progname
);
644 * Build a protocol block list for registration.
646 protobp0
= protobp
= (struct protob
*)malloc(sizeof (struct protob
));
647 protobp
->serv
= RDC_SVC_NAME
;
648 protobp
->versmin
= RDC_VERS_MIN
;
649 protobp
->versmax
= RDC_VERS_MAX
;
650 protobp
->program
= RDC_PROGRAM
;
651 protobp
->next
= (struct protob
*)NULL
;
654 if (do_all(protobp0
, rdcsvc
) == -1)
656 } else if (trans_provider
)
657 do_one(trans_provider
, NULL
, protobp0
, rdcsvc
);
659 for (providerp
= defaultproviders
;
660 *providerp
!= NULL
; providerp
++) {
661 trans_provider
= *providerp
;
662 do_one(trans_provider
, NULL
, protobp0
, rdcsvc
);
669 end_listen_fds
= num_fds
;
671 * Poll for non-data control events on the transport descriptors.
675 syslog(LOG_ERR
, "%s fatal server error\n", progname
);
683 struct t_optmgmt req
, resp
;
688 /* LINTED pointer alignment */
689 opt
= (struct opthdr
*)reqbuf
;
690 opt
->level
= SOL_SOCKET
;
691 opt
->name
= SO_REUSEADDR
;
692 opt
->len
= sizeof (int);
694 /* LINTED pointer alignment */
695 ip
= (int *)&reqbuf
[sizeof (struct opthdr
)];
698 req
.flags
= T_NEGOTIATE
;
699 req
.opt
.len
= sizeof (struct opthdr
) + opt
->len
;
700 req
.opt
.buf
= (char *)opt
;
703 resp
.opt
.buf
= reqbuf
;
704 resp
.opt
.maxlen
= sizeof (reqbuf
);
706 if (t_optmgmt(fd
, &req
, &resp
) < 0 || resp
.flags
!= T_SUCCESS
) {
707 if (t_errno
== TSYSERR
) {
708 syslog(LOG_ERR
, "reuseaddr() t_optmgmt failed: %m\n");
710 syslog(LOG_ERR
, "reuseaddr() t_optmgmt failed: %s\n",
719 * poll on the open transport descriptors for events and errors.
722 poll_for_action(void)
728 * Keep polling until all transports have been closed. When this
729 * happens, we return.
731 while ((int)num_fds
> 0) {
732 nfds
= poll(poll_array
, num_fds
, INFTIM
);
739 * Some errors from poll could be
740 * due to temporary conditions, and we try to
741 * be robust in the face of them. Other
742 * errors (should never happen in theory)
743 * are fatal (eg. EINVAL, EFAULT).
755 (void) syslog(LOG_ERR
,
756 "poll failed: %m. Exiting");
764 * Go through the poll list looking for events.
766 for (i
= 0; i
< num_fds
&& nfds
> 0; i
++) {
767 if (poll_array
[i
].revents
) {
770 * We have a message, so try to read it.
771 * Record the error return in errno,
772 * so that syslog(LOG_ERR, "...%m")
773 * dumps the corresponding error string.
775 if (conn_polled
[i
].nc
.nc_semantics
==
777 errno
= do_poll_clts_action(
778 poll_array
[i
].fd
, i
);
780 errno
= do_poll_cots_action(
781 poll_array
[i
].fd
, i
);
787 * Most returned error codes mean that there is
788 * fatal condition which we can only deal with
789 * by closing the transport.
791 if (errno
!= EAGAIN
&& errno
!= ENOMEM
) {
792 (void) syslog(LOG_ERR
,
793 "Error (%m) reading descriptor %d"
794 "/transport %s. Closing it.",
796 conn_polled
[i
].nc
.nc_proto
);
797 (void) t_close(poll_array
[i
].fd
);
798 remove_from_poll_list(poll_array
[i
].fd
);
799 } else if (errno
== ENOMEM
)
805 (void) syslog(LOG_ERR
,
806 "All transports have been closed with errors. Exiting.");
810 * Allocate poll/transport array entries for this descriptor.
813 add_to_poll_list(int fd
, struct netconfig
*nconf
)
815 static int poll_array_size
= 0;
818 * If the arrays are full, allocate new ones.
820 if (num_fds
== poll_array_size
) {
822 struct conn_entry
*tnp
;
824 if (poll_array_size
!= 0) {
828 tpa
= (struct pollfd
*)0;
830 poll_array_size
+= POLL_ARRAY_INC_SIZE
;
833 * Allocate new arrays.
835 poll_array
= (struct pollfd
*)
836 malloc(poll_array_size
* sizeof (struct pollfd
) + 256);
837 conn_polled
= (struct conn_entry
*)
838 malloc(poll_array_size
* sizeof (struct conn_entry
) + 256);
839 if (poll_array
== (struct pollfd
*)NULL
||
840 conn_polled
== (struct conn_entry
*)NULL
) {
841 syslog(LOG_ERR
, "malloc failed for poll array");
846 * Copy the data of the old ones into new arrays, and
848 * num_fds is guaranteed to be less than
849 * poll_array_size, so this memcpy is safe.
852 (void) memcpy((void *)poll_array
, (void *)tpa
,
853 num_fds
* sizeof (struct pollfd
));
854 (void) memcpy((void *)conn_polled
, (void *)tnp
,
855 num_fds
* sizeof (struct conn_entry
));
862 * Set the descriptor and event list. All possible events are
865 poll_array
[num_fds
].fd
= fd
;
866 poll_array
[num_fds
].events
= POLLIN
|POLLRDNORM
|POLLRDBAND
|POLLPRI
;
869 * Copy the transport data over too.
871 conn_polled
[num_fds
].nc
= *nconf
; /* structure copy */
872 conn_polled
[num_fds
].closing
= 0;
875 * Set the descriptor to non-blocking. Avoids a race
876 * between data arriving on the stream and then having it
877 * flushed before we can read it.
879 if (fcntl(fd
, F_SETFL
, O_NONBLOCK
) == -1) {
880 (void) syslog(LOG_ERR
,
881 "fcntl(file desc. %d/transport %s, F_SETFL, "
882 "O_NONBLOCK): %m. Exiting",
883 num_fds
, nconf
->nc_proto
);
888 * Count this descriptor.
894 remove_from_poll_list(int fd
)
899 for (i
= 0; i
< num_fds
; i
++) {
900 if (poll_array
[i
].fd
== fd
) {
902 num_to_copy
= num_fds
- i
;
903 (void) memcpy((void *)&poll_array
[i
],
904 (void *)&poll_array
[i
+1],
905 num_to_copy
* sizeof (struct pollfd
));
906 (void) memset((void *)&poll_array
[num_fds
], 0,
907 sizeof (struct pollfd
));
908 (void) memcpy((void *)&conn_polled
[i
],
909 (void *)&conn_polled
[i
+1],
910 num_to_copy
* sizeof (struct conn_entry
));
911 (void) memset((void *)&conn_polled
[num_fds
], 0,
912 sizeof (struct conn_entry
));
916 syslog(LOG_ERR
, "attempt to remove nonexistent fd from poll list");
921 conn_close_oldest(void)
927 * Find the oldest connection that is not already in the
928 * process of shutting down.
930 for (i1
= end_listen_fds
; /* no conditional expression */; i1
++) {
933 if (conn_polled
[i1
].closing
== 0)
937 (void) printf("too many connections (%d), releasing oldest (%d)\n",
938 num_conns
, poll_array
[i1
].fd
);
940 syslog(LOG_WARNING
, "too many connections (%d), releasing oldest (%d)",
941 num_conns
, poll_array
[i1
].fd
);
943 fd
= poll_array
[i1
].fd
;
944 if (conn_polled
[i1
].nc
.nc_semantics
== NC_TPI_COTS
) {
946 * For politeness, send a T_DISCON_REQ to the transport
947 * provider. We close the stream anyway.
949 (void) t_snddis(fd
, (struct t_call
*)0);
951 remove_from_poll_list(fd
);
955 * For orderly release, we do not close the stream
956 * until the T_ORDREL_IND arrives to complete
959 if (t_sndrel(fd
) == 0)
960 conn_polled
[i1
].closing
= 1;
965 conn_get(int fd
, struct netconfig
*nconf
, struct conn_ind
**connp
)
967 struct conn_ind
*conn
;
968 struct conn_ind
*next_conn
;
970 conn
= (struct conn_ind
*)malloc(sizeof (*conn
));
972 syslog(LOG_ERR
, "malloc for listen indication failed");
976 /* LINTED pointer alignment */
977 conn
->conn_call
= (struct t_call
*)t_alloc(fd
, T_CALL
, T_ALL
);
978 if (conn
->conn_call
== NULL
) {
980 rdcd_log_tli_error("t_alloc", fd
, nconf
);
984 if (t_listen(fd
, conn
->conn_call
) == -1) {
985 rdcd_log_tli_error("t_listen", fd
, nconf
);
986 (void) t_free((char *)conn
->conn_call
, T_CALL
);
991 if (conn
->conn_call
->udata
.len
> 0) {
993 "rejecting inbound connection(%s) with %d bytes "
995 nconf
->nc_proto
, conn
->conn_call
->udata
.len
);
997 conn
->conn_call
->udata
.len
= 0;
998 (void) t_snddis(fd
, conn
->conn_call
);
999 (void) t_free((char *)conn
->conn_call
, T_CALL
);
1004 if ((next_conn
= *connp
) != NULL
) {
1005 next_conn
->conn_prev
->conn_next
= conn
;
1006 conn
->conn_next
= next_conn
;
1007 conn
->conn_prev
= next_conn
->conn_prev
;
1008 next_conn
->conn_prev
= conn
;
1010 conn
->conn_next
= conn
;
1011 conn
->conn_prev
= conn
;
1018 discon_get(int fd
, struct netconfig
*nconf
, struct conn_ind
**connp
)
1020 struct conn_ind
*conn
;
1021 struct t_discon discon
;
1023 discon
.udata
.buf
= (char *)0;
1024 discon
.udata
.maxlen
= 0;
1025 if (t_rcvdis(fd
, &discon
) == -1) {
1026 rdcd_log_tli_error("t_rcvdis", fd
, nconf
);
1035 if (conn
->conn_call
->sequence
== discon
.sequence
) {
1036 if (conn
->conn_next
== conn
)
1037 *connp
= (struct conn_ind
*)0;
1039 if (conn
== *connp
) {
1040 *connp
= conn
->conn_next
;
1042 conn
->conn_next
->conn_prev
= conn
->conn_prev
;
1043 conn
->conn_prev
->conn_next
= conn
->conn_next
;
1048 conn
= conn
->conn_next
;
1049 } while (conn
!= *connp
);
1055 cots_listen_event(int fd
, int conn_index
)
1057 struct t_call
*call
;
1058 struct conn_ind
*conn
;
1059 struct conn_ind
*conn_head
;
1061 struct netconfig
*nconf
= &conn_polled
[conn_index
].nc
;
1063 struct netbuf addrmask
;
1067 (void) conn_get(fd
, nconf
, &conn_head
);
1069 while ((conn
= conn_head
) != NULL
) {
1070 conn_head
= conn
->conn_next
;
1071 if (conn_head
== conn
)
1074 conn_head
->conn_prev
= conn
->conn_prev
;
1075 conn
->conn_prev
->conn_next
= conn_head
;
1077 call
= conn
->conn_call
;
1081 * If we have already accepted the maximum number of
1082 * connections allowed on the command line, then drop
1083 * the oldest connection (for any protocol) before
1084 * accepting the new connection. Unless explicitly
1085 * set on the command line, max_conns_allowed is -1.
1087 if (max_conns_allowed
!= -1 && num_conns
>= max_conns_allowed
)
1088 conn_close_oldest();
1091 * Create a new transport endpoint for the same proto as
1094 new_fd
= rdc_transport_open(nconf
);
1096 call
->udata
.len
= 0;
1097 (void) t_snddis(fd
, call
);
1098 (void) t_free((char *)call
, T_CALL
);
1099 syslog(LOG_ERR
, "Cannot establish transport over %s",
1104 /* Bind to a generic address/port for the accepting stream. */
1105 if (t_bind(new_fd
, NULL
, NULL
) == -1) {
1106 rdcd_log_tli_error("t_bind", new_fd
, nconf
);
1107 call
->udata
.len
= 0;
1108 (void) t_snddis(fd
, call
);
1109 (void) t_free((char *)call
, T_CALL
);
1110 (void) t_close(new_fd
);
1114 while (t_accept(fd
, new_fd
, call
) == -1) {
1115 if (t_errno
!= TLOOK
) {
1116 rdcd_log_tli_error("t_accept", fd
, nconf
);
1117 call
->udata
.len
= 0;
1118 (void) t_snddis(fd
, call
);
1119 (void) t_free((char *)call
, T_CALL
);
1120 (void) t_close(new_fd
);
1123 while (event
= t_look(fd
)) {
1126 (void) conn_get(fd
, nconf
, &conn_head
);
1130 (void) discon_get(fd
, nconf
,
1136 "unexpected event 0x%x during "
1137 "accept processing (%s)",
1138 event
, nconf
->nc_proto
);
1139 call
->udata
.len
= 0;
1140 (void) t_snddis(fd
, call
);
1141 (void) t_free((char *)call
, T_CALL
);
1142 (void) t_close(new_fd
);
1148 if (set_addrmask(new_fd
, nconf
, &addrmask
) < 0) {
1149 (void) syslog(LOG_ERR
, "Cannot set address mask for %s",
1151 (void) t_snddis(new_fd
, NULL
);
1152 (void) t_free((char *)call
, T_CALL
);
1153 (void) t_close(new_fd
);
1157 /* Tell kRPC about the new stream. */
1158 ret
= (*Mysvc
)(new_fd
, addrmask
, nconf
);
1161 "unable to register with kernel rpc: %m");
1163 (void) t_snddis(new_fd
, NULL
);
1164 (void) t_free((char *)call
, T_CALL
);
1165 (void) t_close(new_fd
);
1170 (void) t_free((char *)call
, T_CALL
);
1173 * Poll on the new descriptor so that we get disconnect
1174 * and orderly release indications.
1177 add_to_poll_list(new_fd
, nconf
);
1179 /* Reset nconf in case it has been moved. */
1180 nconf
= &conn_polled
[conn_index
].nc
;
1186 do_poll_cots_action(int fd
, int conn_index
)
1192 struct conn_entry
*connent
= &conn_polled
[conn_index
];
1193 struct netconfig
*nconf
= &(connent
->nc
);
1194 const char *errorstr
;
1196 while (event
= t_look(fd
)) {
1199 cots_listen_event(fd
, conn_index
);
1204 * Receive a private notification from CONS rpcmod.
1206 i1
= t_rcv(fd
, buf
, sizeof (buf
), &flags
);
1208 syslog(LOG_ERR
, "t_rcv failed");
1211 if (i1
< sizeof (int))
1213 i1
= BE32_TO_U32(buf
);
1214 if (i1
== 1 || i1
== 2) {
1216 * This connection has been idle for too long,
1217 * so release it as politely as we can. If we
1218 * have already initiated an orderly release
1219 * and we get notified that the stream is
1220 * still idle, pull the plug. This prevents
1221 * hung connections from continuing to consume
1224 if (nconf
->nc_semantics
== NC_TPI_COTS
||
1225 connent
->closing
!= 0) {
1226 (void) t_snddis(fd
, (struct t_call
*)0);
1230 * For NC_TPI_COTS_ORD, the stream is closed
1231 * and removed from the poll list when the
1232 * T_ORDREL is received from the provider. We
1233 * don't wait for it here because it may take
1234 * a while for the transport to shut down.
1236 if (t_sndrel(fd
) == -1) {
1238 "unable to send orderly release %m");
1240 connent
->closing
= 1;
1243 "unexpected event from CONS rpcmod %d", i1
);
1247 /* Perform an orderly release. */
1248 if (t_rcvrel(fd
) == 0) {
1249 /* T_ORDREL on listen fd's should be ignored */
1250 if (!is_listen_fd_index(fd
)) {
1251 (void) t_sndrel(fd
);
1256 } else if (t_errno
== TLOOK
) {
1259 rdcd_log_tli_error("t_rcvrel", fd
, nconf
);
1261 * check to make sure we do not close
1264 if (!is_listen_fd_index(fd
))
1271 if (t_rcvdis(fd
, (struct t_discon
*)NULL
) == -1)
1272 rdcd_log_tli_error("t_rcvdis", fd
, nconf
);
1275 * T_DISCONNECT on listen fd's should be ignored.
1277 if (!is_listen_fd_index(fd
))
1283 if (t_errno
== TSYSERR
) {
1284 if ((errorstr
= strerror(errno
)) == NULL
) {
1285 (void) snprintf(buf
, sizeof (buf
),
1286 "Unknown error num %d", errno
);
1287 errorstr
= (const char *)buf
;
1289 } else if (event
== -1)
1290 errorstr
= t_strerror(t_errno
);
1295 "unexpected TLI event (0x%x) on "
1296 "connection-oriented transport(%s, %d):%s",
1297 event
, nconf
->nc_proto
, fd
, errorstr
);
1302 remove_from_poll_list(fd
);
1313 * Called to read and interpret the event on a connectionless descriptor.
1314 * Returns 0 if successful, or a UNIX error code if failure.
1317 do_poll_clts_action(int fd
, int conn_index
)
1322 struct netconfig
*nconf
= &conn_polled
[conn_index
].nc
;
1323 static struct t_unitdata
*unitdata
= NULL
;
1324 static struct t_uderr
*uderr
= NULL
;
1325 static int oldfd
= -1;
1326 struct nd_hostservlist
*host
= NULL
;
1327 struct strbuf ctl
[1], data
[1];
1329 * We just need to have some space to consume the
1330 * message in the event we can't use the TLI interface to do the
1333 * We flush the message using getmsg(). For the control part
1334 * we allocate enough for any TPI header plus 32 bytes for address
1335 * and options. For the data part, there is nothing magic about
1336 * the size of the array, but 256 bytes is probably better than
1337 * 1 byte, and we don't expect any data portion anyway.
1339 * If the array sizes are too small, we handle this because getmsg()
1340 * (called to consume the message) will return MOREDATA|MORECTL.
1341 * Thus we just call getmsg() until it's read the message.
1343 char ctlbuf
[sizeof (union T_primitives
) + 32];
1347 * If this is the same descriptor as the last time
1348 * do_poll_clts_action was called, we can save some
1349 * de-allocation and allocation.
1355 (void) t_free((char *)unitdata
, T_UNITDATA
);
1359 (void) t_free((char *)uderr
, T_UDERROR
);
1365 * Allocate a unitdata structure for receiving the event.
1367 if (unitdata
== NULL
) {
1368 /* LINTED pointer alignment */
1369 unitdata
= (struct t_unitdata
*)t_alloc(fd
, T_UNITDATA
, T_ALL
);
1370 if (unitdata
== NULL
) {
1371 if (t_errno
== TSYSERR
) {
1373 * Save the error code across
1374 * syslog(), just in case
1375 * syslog() gets its own error
1376 * and therefore overwrites errno.
1379 (void) syslog(LOG_ERR
,
1380 "t_alloc(file descriptor %d/transport %s, "
1381 "T_UNITDATA) failed: %m",
1382 fd
, nconf
->nc_proto
);
1385 (void) syslog(LOG_ERR
, "t_alloc(file descriptor %d/"
1386 "transport %s, T_UNITDATA) failed TLI error %d",
1387 fd
, nconf
->nc_proto
, t_errno
);
1396 * The idea is we wait for T_UNITDATA_IND's. Of course,
1397 * we don't get any, because rpcmod filters them out.
1398 * However, we need to call t_rcvudata() to let TLI
1399 * tell us we have a T_UDERROR_IND.
1402 * t_rcvudata(), expecting TLOOK.
1403 * t_look(), expecting T_UDERR.
1404 * t_rcvuderr(), expecting success (0).
1405 * expand destination address into ASCII,
1409 ret
= t_rcvudata(fd
, unitdata
, &flags
);
1410 if (ret
== 0 || t_errno
== TBUFOVFLW
) {
1411 (void) syslog(LOG_WARNING
, "t_rcvudata(file descriptor %d/"
1412 "transport %s) got unexpected data, %d bytes",
1413 fd
, nconf
->nc_proto
, unitdata
->udata
.len
);
1416 * Even though we don't expect any data, in case we do,
1417 * keep reading until there is no more.
1430 * System errors are returned to caller.
1431 * Save the error code across
1432 * syslog(), just in case
1433 * syslog() gets its own error
1434 * and therefore overwrites errno.
1437 (void) syslog(LOG_ERR
,
1438 "t_rcvudata(file descriptor %d/transport %s) %m",
1439 fd
, nconf
->nc_proto
);
1444 (void) syslog(LOG_ERR
,
1445 "t_rcvudata(file descriptor %d/transport %s) TLI error %d",
1446 fd
, nconf
->nc_proto
, t_errno
);
1456 * System errors are returned to caller.
1458 if (t_errno
== TSYSERR
) {
1460 * Save the error code across
1461 * syslog(), just in case
1462 * syslog() gets its own error
1463 * and therefore overwrites errno.
1466 (void) syslog(LOG_ERR
,
1467 "t_look(file descriptor %d/transport %s) %m",
1468 fd
, nconf
->nc_proto
);
1471 (void) syslog(LOG_ERR
,
1472 "t_look(file descriptor %d/transport %s) TLI error %d",
1473 fd
, nconf
->nc_proto
, t_errno
);
1478 (void) syslog(LOG_WARNING
, "t_look(file descriptor %d/"
1479 "transport %s) returned %d not T_UDERR (%d)",
1480 fd
, nconf
->nc_proto
, ret
, T_UDERR
);
1483 if (uderr
== NULL
) {
1484 /* LINTED pointer alignment */
1485 uderr
= (struct t_uderr
*)t_alloc(fd
, T_UDERROR
, T_ALL
);
1486 if (uderr
== NULL
) {
1487 if (t_errno
== TSYSERR
) {
1489 * Save the error code across
1490 * syslog(), just in case
1491 * syslog() gets its own error
1492 * and therefore overwrites errno.
1495 (void) syslog(LOG_ERR
,
1496 "t_alloc(file descriptor %d/transport %s, "
1497 "T_UDERROR) failed: %m",
1498 fd
, nconf
->nc_proto
);
1501 (void) syslog(LOG_ERR
, "t_alloc(file descriptor %d/"
1502 "transport %s, T_UDERROR) failed TLI error: %d",
1503 fd
, nconf
->nc_proto
, t_errno
);
1508 ret
= t_rcvuderr(fd
, uderr
);
1512 * Save the datagram error in errno, so that the
1513 * %m argument to syslog picks up the error string.
1515 errno
= uderr
->error
;
1518 * Log the datagram error, then log the host that
1519 * probably triggerred. Cannot log both in the
1520 * same transaction because of packet size limitations
1523 (void) syslog((errno
== ECONNREFUSED
) ? LOG_DEBUG
: LOG_WARNING
,
1524 "%s response over <file descriptor %d/transport %s> "
1525 "generated error: %m",
1526 progname
, fd
, nconf
->nc_proto
);
1529 * Try to map the client's address back to a
1532 ret
= netdir_getbyaddr(nconf
, &host
, &uderr
->addr
);
1533 if (ret
!= -1 && host
&& host
->h_cnt
> 0 &&
1534 host
->h_hostservs
) {
1535 (void) syslog((errno
== ECONNREFUSED
) ? LOG_DEBUG
: LOG_WARNING
,
1536 "Bad %s response was sent to client with "
1537 "host name: %s; service port: %s",
1538 progname
, host
->h_hostservs
->h_host
,
1539 host
->h_hostservs
->h_serv
);
1543 char *hex
= "0123456789abcdef";
1546 * Mapping failed, print the whole thing
1549 buf
= (char *)malloc(uderr
->addr
.len
* 2 + 1);
1550 for (i
= 0, j
= 0; i
< uderr
->addr
.len
; i
++, j
+= 2) {
1551 buf
[j
] = hex
[((uderr
->addr
.buf
[i
]) >> 4) & 0xf];
1552 buf
[j
+1] = hex
[uderr
->addr
.buf
[i
] & 0xf];
1555 (void) syslog((errno
== ECONNREFUSED
) ?
1556 LOG_DEBUG
: LOG_WARNING
,
1557 "Bad %s response was sent to client with "
1558 "transport address: 0x%s",
1563 if (ret
== 0 && host
!= NULL
)
1564 netdir_free((void *)host
, ND_HOSTSERVLIST
);
1573 * System errors are returned to caller.
1574 * Save the error code across
1575 * syslog(), just in case
1576 * syslog() gets its own error
1577 * and therefore overwrites errno.
1580 (void) syslog(LOG_ERR
,
1581 "t_rcvuderr(file descriptor %d/transport %s) %m",
1582 fd
, nconf
->nc_proto
);
1585 (void) syslog(LOG_ERR
,
1586 "t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
1587 fd
, nconf
->nc_proto
, t_errno
);
1593 * If we get here, then we could not cope with whatever message
1594 * we attempted to read, so flush it. If we did read a message,
1595 * and one isn't present, that is all right, because fd is in
1598 (void) syslog(LOG_ERR
,
1599 "Flushing one input message from <file descriptor %d/transport %s>",
1600 fd
, nconf
->nc_proto
);
1603 * Read and discard the message. Do this this until there is
1604 * no more control/data in the message or until we get an error.
1607 ctl
->maxlen
= sizeof (ctlbuf
);
1609 data
->maxlen
= sizeof (databuf
);
1610 data
->buf
= databuf
;
1612 ret
= getmsg(fd
, ctl
, data
, &flags
);
1621 * Establish service thread.
1624 rdcsvc(int fd
, struct netbuf addrmask
, struct netconfig
*nconf
)
1627 struct ncall_svc_args nsa
;
1628 #else /* !__NCALL__ */
1629 struct rdc_svc_args nsa
;
1630 _rdc_ioctl_t rdc_args
= { 0, };
1631 #endif /* __NCALL__ */
1634 nsa
.nthr
= (max_conns_allowed
< 0 ? 16 : max_conns_allowed
);
1635 (void) strncpy(nsa
.netid
, nconf
->nc_netid
, sizeof (nsa
.netid
));
1636 nsa
.addrmask
.len
= addrmask
.len
;
1637 nsa
.addrmask
.maxlen
= addrmask
.maxlen
;
1638 nsa
.addrmask
.buf
= addrmask
.buf
;
1641 return (sndrsys(NC_IOC_SERVER
, &nsa
));
1642 #else /* !__NCALL__ */
1643 rdc_args
.arg0
= (long)&nsa
;
1644 return (sndrsys(RDC_ENABLE_SVR
, &rdc_args
));
1645 #endif /* __NCALL__ */
1651 nofile_increase(int limit
)
1655 if (getrlimit(RLIMIT_NOFILE
, &rl
) == -1) {
1657 "nofile_increase() getrlimit of NOFILE failed: %m");
1662 rl
.rlim_cur
= limit
;
1664 rl
.rlim_cur
+= NOFILE_INC_SIZE
;
1666 if (rl
.rlim_cur
> rl
.rlim_max
&& rl
.rlim_max
!= RLIM_INFINITY
)
1667 rl
.rlim_max
= rl
.rlim_cur
;
1669 if (setrlimit(RLIMIT_NOFILE
, &rl
) == -1) {
1671 "nofile_increase() setrlimit of NOFILE to %d failed: %m",
1680 rdcd_bindit(struct netconfig
*nconf
, struct netbuf
**addr
,
1681 struct nd_hostserv
*hs
, int backlog
)
1686 struct nd_addrlist
*addrlist
;
1687 struct t_optmgmt req
, resp
;
1691 if ((fd
= rdc_transport_open(nconf
)) == -1) {
1692 syslog(LOG_ERR
, "cannot establish transport service over %s",
1697 addrlist
= (struct nd_addrlist
*)NULL
;
1698 if (netdir_getbyname(nconf
, hs
, &addrlist
) != 0) {
1699 if (strncmp(nconf
->nc_netid
, "udp", 3) != 0) {
1700 syslog(LOG_ERR
, "Cannot get address for transport "
1701 "%s host %s service %s",
1702 nconf
->nc_netid
, hs
->h_host
, hs
->h_serv
);
1708 if (strcmp(nconf
->nc_proto
, "tcp") == 0) {
1710 * If we're running over TCP, then set the
1711 * SO_REUSEADDR option so that we can bind
1712 * to our preferred address even if previously
1713 * left connections exist in FIN_WAIT states.
1714 * This is somewhat bogus, but otherwise you have
1715 * to wait 2 minutes to restart after killing it.
1717 if (reuseaddr(fd
) == -1) {
1719 "couldn't set SO_REUSEADDR option on transport");
1723 if (nconf
->nc_semantics
== NC_TPI_CLTS
)
1728 /* LINTED pointer alignment */
1729 ntb
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ALL
);
1730 if (ntb
== (struct t_bind
*)NULL
) {
1731 syslog(LOG_ERR
, "t_alloc failed: t_errno %d, %m", t_errno
);
1733 netdir_free((void *)addrlist
, ND_ADDRLIST
);
1737 tb
.addr
= *(addrlist
->n_addrs
); /* structure copy */
1739 if (t_bind(fd
, &tb
, ntb
) == -1) {
1740 syslog(LOG_ERR
, "t_bind failed: t_errno %d, %m", t_errno
);
1741 (void) t_free((char *)ntb
, T_BIND
);
1742 netdir_free((void *)addrlist
, ND_ADDRLIST
);
1747 /* make sure we bound to the right address */
1748 if (tb
.addr
.len
!= ntb
->addr
.len
||
1749 memcmp(tb
.addr
.buf
, ntb
->addr
.buf
, tb
.addr
.len
) != 0) {
1750 syslog(LOG_ERR
, "t_bind to wrong address");
1751 (void) t_free((char *)ntb
, T_BIND
);
1752 netdir_free((void *)addrlist
, ND_ADDRLIST
);
1758 netdir_free((void *)addrlist
, ND_ADDRLIST
);
1760 if (strcmp(nconf
->nc_proto
, "tcp") == 0 ||
1761 strcmp(nconf
->nc_proto
, "tcp6") == 0) {
1763 * Disable the Nagle algorithm on TCP connections.
1764 * Connections accepted from this listener will
1765 * inherit the listener options.
1768 /* LINTED pointer alignment */
1769 opt
= (struct opthdr
*)reqbuf
;
1770 opt
->level
= IPPROTO_TCP
;
1771 opt
->name
= TCP_NODELAY
;
1772 opt
->len
= sizeof (int);
1774 /* LINTED pointer alignment */
1775 *(int *)((char *)opt
+ sizeof (*opt
)) = 1;
1777 req
.flags
= T_NEGOTIATE
;
1778 req
.opt
.len
= sizeof (*opt
) + opt
->len
;
1779 req
.opt
.buf
= (char *)opt
;
1781 resp
.opt
.buf
= reqbuf
;
1782 resp
.opt
.maxlen
= sizeof (reqbuf
);
1784 if (t_optmgmt(fd
, &req
, &resp
) < 0 ||
1785 resp
.flags
!= T_SUCCESS
) {
1786 syslog(LOG_ERR
, "couldn't set NODELAY option for "
1787 "proto %s: t_errno = %d, %m", nconf
->nc_proto
,
1798 bind_to_provider(char *provider
, char *serv
, struct netbuf
**addr
,
1799 struct netconfig
**retnconf
)
1801 struct netconfig
*nconf
;
1803 struct nd_hostserv hs
;
1805 hs
.h_host
= HOST_SELF
;
1806 hs
.h_serv
= RDC_SERVICE
; /* serv_name_to_port_name(serv); */
1808 if ((nc
= setnetconfig()) == (NCONF_HANDLE
*)NULL
) {
1809 syslog(LOG_ERR
, "setnetconfig failed: %m");
1812 while (nconf
= getnetconfig(nc
)) {
1813 if (OK_TPI_TYPE(nconf
) &&
1814 strcmp(nconf
->nc_device
, provider
) == 0) {
1816 return (rdcd_bindit(nconf
, addr
, &hs
, listen_backlog
));
1819 (void) endnetconfig(nc
);
1820 if ((Is_ipv6present() && (strcmp(provider
, "/dev/tcp6") == 0)) ||
1821 (!Is_ipv6present() && (strcmp(provider
, "/dev/tcp") == 0)))
1822 syslog(LOG_ERR
, "couldn't find netconfig entry for provider %s",
1829 * For listen fd's index is always less than end_listen_fds.
1830 * It's value is equal to the number of open file descriptors after the
1831 * last listen end point was opened but before any connection was accepted.
1834 is_listen_fd_index(int index
)
1836 return (index
< end_listen_fds
);
1841 * Create an address mask appropriate for the transport.
1842 * The mask is used to obtain the host-specific part of
1843 * a network address when comparing addresses.
1844 * For an internet address the host-specific part is just
1845 * the 32 bit IP address and this part of the mask is set
1846 * to all-ones. The port number part of the mask is zeroes.
1849 set_addrmask(int fd
, struct netconfig
*nconf
, struct netbuf
*mask
)
1854 * Find the size of the address we need to mask.
1856 if (t_getinfo(fd
, &info
) < 0) {
1857 t_error("t_getinfo");
1860 mask
->len
= mask
->maxlen
= info
.addr
;
1861 if (info
.addr
<= 0) {
1862 syslog(LOG_ERR
, "set_addrmask: address size: %ld", info
.addr
);
1866 mask
->buf
= (char *)malloc(mask
->len
);
1867 if (mask
->buf
== NULL
) {
1868 syslog(LOG_ERR
, "set_addrmask: no memory");
1871 (void) memset(mask
->buf
, 0, mask
->len
); /* reset all mask bits */
1873 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0) {
1875 * Set the mask so that the port is ignored.
1877 /* LINTED pointer alignment */
1878 ((struct sockaddr_in
*)mask
->buf
)->sin_addr
.s_addr
=
1880 /* LINTED pointer alignment */
1881 ((struct sockaddr_in
*)mask
->buf
)->sin_family
= (sa_family_t
)~0;
1884 else if (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) {
1885 /* LINTED pointer alignment */
1886 (void) memset(&((struct sockaddr_in6
*)mask
->buf
)->sin6_addr
,
1887 (uchar_t
)~0, sizeof (struct in6_addr
));
1888 /* LINTED pointer alignment */
1889 ((struct sockaddr_in6
*)mask
->buf
)->sin6_family
=
1895 * Set all mask bits.
1897 (void) memset(mask
->buf
, (uchar_t
)~0, mask
->len
);
1902 #if !defined(_SunOS_5_6) && !defined(_SunOS_5_7) && !defined(_SunOS_5_8)
1905 sndrsvcpool(int maxservers
)
1907 struct svcpool_args npa
;
1909 npa
.id
= RDC_SVCPOOL_ID
;
1910 npa
.maxthreads
= maxservers
;
1915 npa
.max_same_xprt
= 0;
1916 return (sndrsys(RDC_POOL_CREATE
, &npa
));
1921 * The following stolen from cmd/fs.d/nfs/lib/thrpool.c
1927 * Thread to call into the kernel and do work on behalf of SNDR/ncall-ip.
1935 while ((err
= sndrsys(RDC_POOL_RUN
, &id
)) != 0) {
1937 * Interrupted by a signal while in the kernel.
1938 * this process is still alive, try again.
1947 * If we weren't interrupted by a signal, but did
1948 * return from the kernel, this thread's work is done,
1949 * and it should exit.
1956 * User-space "creator" thread. This thread blocks in the kernel
1957 * until new worker threads need to be created for the service
1958 * pool. On return to userspace, if there is no error, create a
1959 * new thread for the service pool.
1972 * Call into the kernel, and hang out there
1973 * until a thread needs to be created.
1975 if (err
= sndrsys(RDC_POOL_WAIT
, &id
)) {
1976 if (err
== ECANCELED
|| err
== EBUSY
)
1978 * If we get back ECANCELED, the service
1979 * pool is exiting, and we may as well
1980 * clean up this thread. If EBUSY is
1981 * returned, there's already a thread
1982 * looping on this pool, so we should
1990 (void) thr_create(NULL
, NULL
, svcstart
, (void *)id
,
1991 THR_BOUND
| THR_DETACHED
, &tid
);
2004 * Create a bound thread to wait for kernel LWPs that
2005 * need to be created.
2007 if (thr_create(NULL
, NULL
, svcblock
, (void *)id
,
2008 THR_BOUND
| THR_DETACHED
, &tid
))
2013 #endif /* Solaris 9+ */