4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
29 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
43 * Checks to see whether the program is still bound to the
44 * claimed address and returns the univeral merged address
50 #include <netconfig.h>
52 #include <sys/syslog.h>
56 /* the following just to get my address */
58 #include <sys/socket.h>
59 #include <netinet/in.h>
66 mutex_t fd_lock
; /* protects fd */
67 struct netconfig
*nconf
;
72 static struct fdlist
*fdhead
; /* Link list of the check fd's */
73 static struct fdlist
*fdtail
;
74 static char *nullstring
= "";
77 * Returns 1 if the given address is bound for the given addr & transport
78 * For all error cases, we assume that the address is bound
79 * Returns 0 for success.
82 * uaddr: the universal address
85 check_bound(struct fdlist
*fdl
, char *uaddr
)
89 struct t_bind taddr
, *baddr
;
92 if (fdl
->check_binding
== FALSE
)
95 na
= uaddr2taddr(fdl
->nconf
, uaddr
);
97 return (TRUE
); /* punt, should never happen */
101 (void) mutex_lock(&fdl
->fd_lock
);
103 baddr
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
);
105 (void) mutex_unlock(&fdl
->fd_lock
);
106 netdir_free((char *)na
, ND_ADDR
);
109 if (t_bind(fd
, &taddr
, baddr
) != 0) {
110 (void) mutex_unlock(&fdl
->fd_lock
);
111 netdir_free((char *)na
, ND_ADDR
);
112 (void) t_free((char *)baddr
, T_BIND
);
115 if (t_unbind(fd
) != 0) {
116 /* Bad fd. Purge this fd */
118 fdl
->fd
= t_open(fdl
->nconf
->nc_device
, O_RDWR
, NULL
);
120 fdl
->check_binding
= FALSE
;
122 (void) mutex_unlock(&fdl
->fd_lock
);
123 ans
= memcmp(taddr
.addr
.buf
, baddr
->addr
.buf
, baddr
->addr
.len
);
124 netdir_free((char *)na
, ND_ADDR
);
125 (void) t_free((char *)baddr
, T_BIND
);
126 return (ans
== 0 ? FALSE
: TRUE
);
130 * Keep open one more file descriptor for this transport, which
131 * will be used to determine whether the given service is up
132 * or not by trying to bind to the registered address.
133 * We are ignoring errors here. It trashes taddr and baddr;
134 * but that perhaps should not matter.
136 * We check for the following conditions:
137 * 1. Is it possible for t_bind to fail in the case where
138 * we bind to an already bound address and have any
139 * other error number besides TNOADDR.
140 * 2. If an address is specified in bind addr, can I bind to
142 * 3. If NULL is specified in bind addr, can I bind to the
143 * address to which the fd finally got bound.
146 add_bndlist(struct netconfig
*nconf
, struct t_bind
*taddr
, struct t_bind
*baddr
)
150 struct netconfig
*newnconf
;
152 struct t_bind tmpaddr
;
154 newnconf
= getnetconfigent(nconf
->nc_netid
);
155 if (newnconf
== NULL
)
157 fdl
= (struct fdlist
*)malloc((uint_t
)sizeof (struct fdlist
));
159 freenetconfigent(newnconf
);
160 syslog(LOG_ERR
, "no memory!");
163 (void) mutex_init(&fdl
->fd_lock
, USYNC_THREAD
, NULL
);
164 fdl
->nconf
= newnconf
;
166 if (fdhead
== NULL
) {
173 fdl
->check_binding
= FALSE
;
174 if ((fdl
->fd
= t_open(nconf
->nc_device
, O_RDWR
, &tinfo
)) < 0) {
176 * Note that we haven't dequeued this entry nor have we freed
177 * the netconfig structure.
181 "%s: add_bndlist cannot open connection: %s",
182 nconf
->nc_netid
, t_errlist
[t_errno
]);
187 /* Set the qlen only for cots transports */
188 switch (tinfo
.servtype
) {
200 if (t_bind(fdl
->fd
, taddr
, baddr
) != 0) {
201 if (t_errno
== TNOADDR
) {
202 fdl
->check_binding
= TRUE
;
203 return (0); /* All is fine */
205 /* Perhaps condition #1 */
207 fprintf(stderr
, "%s: add_bndlist cannot bind (1): %s",
208 nconf
->nc_netid
, t_errlist
[t_errno
]);
214 if (!memcmp(taddr
->addr
.buf
, baddr
->addr
.buf
,
215 (int)baddr
->addr
.len
)) {
221 /* Set the qlen only for cots transports */
222 switch (tinfo
.servtype
) {
233 tmpaddr
.addr
.len
= tmpaddr
.addr
.maxlen
= 0;
234 tmpaddr
.addr
.buf
= NULL
;
235 if (t_bind(fdl
->fd
, &tmpaddr
, taddr
) != 0) {
237 fprintf(stderr
, "%s: add_bndlist cannot bind (2): %s",
238 nconf
->nc_netid
, t_errlist
[t_errno
]);
242 /* Now fdl->fd is bound to a transport chosen address */
243 if ((fd
= t_open(nconf
->nc_device
, O_RDWR
, &tinfo
)) < 0) {
246 "%s: add_bndlist cannot open connection: %s",
247 nconf
->nc_netid
, t_errlist
[t_errno
]);
251 if (t_bind(fd
, taddr
, baddr
) != 0) {
252 if (t_errno
== TNOADDR
) {
254 * This transport is schizo. Previously it handled a
255 * request to bind to an already bound transport by
256 * returning a different bind address, and now it's
257 * returning a TNOADDR for essentially the same
258 * request. The spec may allow this behavior, so
259 * we'll just assume we can't do bind checking with
266 fprintf(stderr
, "%s: add_bndlist cannot bind (3): %s",
267 nconf
->nc_netid
, t_errlist
[t_errno
]);
273 if (!memcmp(taddr
->addr
.buf
, baddr
->addr
.buf
,
274 (int)baddr
->addr
.len
)) {
275 switch (tinfo
.servtype
) {
278 if (baddr
->qlen
== 1) {
290 fdl
->check_binding
= TRUE
;
305 is_bound(char *netid
, char *uaddr
)
309 for (fdl
= fdhead
; fdl
; fdl
= fdl
->next
)
310 if (strcmp(fdl
->nconf
->nc_netid
, netid
) == 0)
314 return (check_bound(fdl
, uaddr
));
317 /* Return pointer to port string in the universal address */
318 #define UADDR_PRT_INDX(UADDR, PORT) { \
319 PORT = strrchr(UADDR, '.'); \
320 while (*--PORT != '.'); }
322 * Returns NULL if there was some system error.
323 * Returns "" if the address was not bound, i.e the server crashed.
324 * Returns the merged address otherwise.
327 mergeaddr(SVCXPRT
*xprt
, char *netid
, char *uaddr
, char *saddr
)
330 struct nd_mergearg ma
;
333 for (fdl
= fdhead
; fdl
; fdl
= fdl
->next
)
334 if (strcmp(fdl
->nconf
->nc_netid
, netid
) == 0)
338 if (check_bound(fdl
, uaddr
) == FALSE
)
339 /* that server died */
342 * If saddr is not NULL, the remote client may have included the
343 * address by which it contacted us. Use that for the "client" uaddr,
344 * otherwise use the info from the SVCXPRT.
350 /* retrieve the client's address */
351 ma
.c_uaddr
= taddr2uaddr(fdl
->nconf
, svc_getrpccaller(xprt
));
352 if (ma
.c_uaddr
== NULL
) {
353 syslog(LOG_ERR
, "taddr2uaddr failed for %s: %s",
354 fdl
->nconf
->nc_netid
, netdir_sperror());
360 /* Not an INET address? */
361 if ((strcmp(fdl
->nconf
->nc_protofmly
, NC_INET
) != 0) &&
362 (strcmp(fdl
->nconf
->nc_protofmly
, NC_INET6
) != 0)) {
364 stat
= netdir_options(fdl
->nconf
, ND_MERGEADDR
, 0, (char *)&ma
);
366 /* Inet address, but no xp_ltaddr */
367 else if ((ma
.s_uaddr
= taddr2uaddr(fdl
->nconf
,
368 &(xprt
)->xp_ltaddr
)) == NULL
) {
370 stat
= netdir_options(fdl
->nconf
, ND_MERGEADDR
, 0, (char *)&ma
);
373 * (xprt)->xp_ltaddr contains portmap's port address.
374 * Overwrite this with actual application's port address
375 * before returning to the caller.
377 char *s_uport
, *uport
;
379 /* Get the INET/INET6 address part from ma.s_uaddr */
380 UADDR_PRT_INDX(ma
.s_uaddr
, s_uport
);
383 /* Get the port info from uaddr */
384 UADDR_PRT_INDX(uaddr
, uport
);
386 ma
.m_uaddr
= malloc(strlen(ma
.s_uaddr
) + strlen(uport
) + 1);
387 if (ma
.m_uaddr
== NULL
) {
388 syslog(LOG_ERR
, "mergeaddr: no memory!");
395 /* Copy IP address into the Universal address holder */
396 strcpy(ma
.m_uaddr
, ma
.s_uaddr
);
397 /* Append port info to the Universal address holder */
398 strcat(ma
.m_uaddr
, uport
);
406 syslog(LOG_ERR
, "netdir_merge failed for %s: %s",
407 fdl
->nconf
->nc_netid
, netdir_sperror());
415 * Returns a netconf structure from its internal list. This
416 * structure should not be freed.
419 rpcbind_get_conf(char *netid
)
423 for (fdl
= fdhead
; fdl
; fdl
= fdl
->next
)
424 if (strcmp(fdl
->nconf
->nc_netid
, netid
) == 0)