1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <string.h>
21: #include <time.h>
22: #include <unistd.h>
23: #include <sys/ioctl.h>
24: #include <sys/socket.h>
25: #include <rpc/pmap_prot.h>
26: #include <rpc/pmap_clnt.h>
27: #include <rpcsvc/nis.h>
28:
29: #include "nis_intern.h"
30:
31:
32: struct cu_data
33: {
34: int cu_sock;
35: bool_t cu_closeit;
36: struct sockaddr_in cu_raddr;
37: int cu_rlen;
38: struct timeval cu_wait;
39: struct timeval cu_total;
40: struct rpc_err cu_error;
41: XDR cu_outxdrs;
42: u_int cu_xdrpos;
43: u_int cu_sendsz;
44: char *cu_outbuf;
45: u_int cu_recvsz;
46: char cu_inbuf[1];
47: };
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64: u_short
65: __pmap_getnisport (struct sockaddr_in *address, u_long program,
66: u_long version, u_int protocol)
67: {
68: const struct timeval timeout = {1, 0};
69: const struct timeval tottimeout = {1, 0};
70: u_short port = 0;
71: int socket = -1;
72: CLIENT *client;
73: struct pmap parms;
74:
75: address->sin_port = htons (PMAPPORT);
76: client = clntudp_bufcreate (address, PMAPPROG, PMAPVERS, timeout, &socket,
77: RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
78: if (client != (CLIENT *) NULL)
79: {
80: parms.pm_prog = program;
81: parms.pm_vers = version;
82: parms.pm_prot = protocol;
83: parms.pm_port = 0;
84: if (CLNT_CALL (client, PMAPPROC_GETPORT, (xdrproc_t) xdr_pmap,
85: (caddr_t) & parms, (xdrproc_t) xdr_u_short,
86: (caddr_t) & port, tottimeout) != RPC_SUCCESS)
87: {
88: rpc_createerr.cf_stat = RPC_PMAPFAILURE;
89: clnt_geterr (client, &rpc_createerr.cf_error);
90: }
91: else
92: {
93: if (port == 0)
94: rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
95: }
96: CLNT_DESTROY (client);
97: }
98:
99: address->sin_port = 0;
100: return port;
101: }
102:
103:
104:
105: struct findserv_req
106: {
107: struct sockaddr_in sin;
108: u_int32_t xid;
109: u_int server_nr;
110: u_int server_ep;
111: };
112:
113:
114: static long int
115: __nis_findfastest_with_timeout (dir_binding *bind,
116: const struct timeval *timeout)
117: {
118: static const struct timeval TIMEOUT00 = { 0, 0 };
119: struct findserv_req *pings;
120: struct sockaddr_in sin, saved_sin;
121: int found = -1;
122: u_int32_t xid_seed;
123: int sock, dontblock = 1;
124: CLIENT *clnt;
125: u_long i, j, pings_count, pings_max, fastest = -1;
126: struct cu_data *cu;
127:
128: pings_max = bind->server_len * 2;
129:
130: pings_count = 0;
131: pings = malloc (sizeof (struct findserv_req) * pings_max);
132: xid_seed = (u_int32_t) (time (NULL) ^ getpid ());
133:
134: if (__builtin_expect (pings == NULL, 0))
135: return -1;
136:
137: memset (&sin, '\0', sizeof (sin));
138: sin.sin_family = AF_INET;
139: for (i = 0; i < bind->server_len; i++)
140: for (j = 0; j < bind->server_val[i].ep.ep_len; ++j)
141: if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0)
142: if ((bind->server_val[i].ep.ep_val[j].proto == NULL) ||
143: (bind->server_val[i].ep.ep_val[j].proto[0] == '-') ||
144: (bind->server_val[i].ep.ep_val[j].proto[0] == '\0'))
145: {
146: sin.sin_addr.s_addr =
147: inetstr2int (bind->server_val[i].ep.ep_val[j].uaddr);
148: if (sin.sin_addr.s_addr == 0)
149: continue;
150: sin.sin_port = htons (__pmap_getnisport (&sin, NIS_PROG,
151: NIS_VERSION,
152: IPPROTO_UDP));
153: if (sin.sin_port == 0)
154: continue;
155:
156: if (pings_count >= pings_max)
157: {
158: struct findserv_req *new_pings;
159:
160: pings_max += 10;
161: new_pings = realloc (pings, sizeof (struct findserv_req) *
162: pings_max);
163: if (__builtin_expect (new_pings == NULL, 0))
164: {
165: free (pings);
166: return -1;
167: }
168: pings = new_pings;
169: }
170: memcpy ((char *) &pings[pings_count].sin, (char *) &sin,
171: sizeof (sin));
172: memcpy ((char *)&saved_sin, (char *)&sin, sizeof(sin));
173: pings[pings_count].xid = xid_seed + pings_count;
174: pings[pings_count].server_nr = i;
175: pings[pings_count].server_ep = j;
176: ++pings_count;
177: }
178:
179:
180: if (pings_count == 0)
181: {
182: free (pings);
183: return -1;
184: }
185:
186:
187: sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
188: clnt = clntudp_create (&saved_sin, NIS_PROG, NIS_VERSION, *timeout, &sock);
189: if (clnt == NULL)
190: {
191: close (sock);
192: free (pings);
193: return -1;
194: }
195: auth_destroy (clnt->cl_auth);
196: clnt->cl_auth = authunix_create_default ();
197: cu = (struct cu_data *) clnt->cl_private;
198: ioctl (sock, FIONBIO, &dontblock);
199:
200: for (i = 0; i < pings_count; ++i)
201: {
202:
203: *((u_int32_t *) (cu->cu_outbuf)) = pings[i].xid - 1;
204: memcpy ((char *) &cu->cu_raddr, (char *) &pings[i].sin,
205: sizeof (struct sockaddr_in));
206:
207: clnt_call (clnt, NULLPROC,
208: (xdrproc_t) xdr_void, (caddr_t) 0,
209: (xdrproc_t) xdr_void, (caddr_t) 0, TIMEOUT00);
210: }
211:
212: while (found == -1) {
213:
214: int rc = clnt_call (clnt, NULLPROC,
215: (xdrproc_t) NULL, (caddr_t) 0,
216: (xdrproc_t) xdr_void, (caddr_t) 0,
217: *timeout);
218: if (RPC_SUCCESS == rc) {
219: fastest = *((u_int32_t *) (cu->cu_inbuf)) - xid_seed;
220: if (fastest < pings_count) {
221: bind->server_used = pings[fastest].server_nr;
222: bind->current_ep = pings[fastest].server_ep;
223: found = 1;
224: }
225: } else {
226:
227: break;
228: }
229: }
230:
231:
232: auth_destroy (clnt->cl_auth);
233: clnt_destroy (clnt);
234: close (sock);
235:
236: free (pings);
237:
238: return found;
239: }
240:
241:
242: long int
243: __nis_findfastest (dir_binding *bind)
244: {
245: struct timeval timeout = { __NIS_PING_TIMEOUT_START, 0 };
246: long int found = -1;
247: long int retry = __NIS_PING_RETRY + 1;
248:
249: while (retry--)
250: {
251: found = __nis_findfastest_with_timeout (bind, &timeout);
252: if (found != -1)
253: break;
254: timeout.tv_sec += __NIS_PING_TIMEOUT_INCREMENT;
255: }
256:
257: return found;
258: }