Print this page
4953763 Need way to configure NFS window sizes without changing system wide defaults
6216670 NFS server needs a bigger transmit buffer
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.c
+++ new/usr/src/cmd/fs.d/nfs/lib/nfs_tbind.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.
|
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
22 + * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * nfs_tbind.c, common part for nfsd and lockd.
28 28 */
29 29
30 -#pragma ident "%Z%%M% %I% %E% SMI"
31 -
32 30 #define PORTMAP
33 31
34 32 #include <tiuser.h>
35 33 #include <fcntl.h>
36 34 #include <netconfig.h>
37 35 #include <stropts.h>
38 36 #include <errno.h>
39 37 #include <syslog.h>
40 38 #include <rpc/rpc.h>
41 39 #include <rpc/pmap_prot.h>
42 40 #include <sys/time.h>
43 41 #include <sys/resource.h>
44 42 #include <signal.h>
45 43 #include <netdir.h>
46 44 #include <unistd.h>
47 45 #include <string.h>
48 46 #include <netinet/tcp.h>
49 47 #include <malloc.h>
50 48 #include <stdlib.h>
51 49 #include "nfs_tbind.h"
52 50 #include <nfs/nfs.h>
53 51 #include <nfs/nfs_acl.h>
54 52 #include <nfs/nfssys.h>
55 53 #include <nfs/nfs4.h>
56 54 #include <zone.h>
57 55 #include <sys/socket.h>
58 56 #include <tsol/label.h>
59 57
60 58 /*
61 59 * Determine valid semantics for most applications.
62 60 */
63 61 #define OK_TPI_TYPE(_nconf) \
64 62 (_nconf->nc_semantics == NC_TPI_CLTS || \
65 63 _nconf->nc_semantics == NC_TPI_COTS || \
66 64 _nconf->nc_semantics == NC_TPI_COTS_ORD)
67 65
68 66 #define BE32_TO_U32(a) \
69 67 ((((ulong_t)((uchar_t *)a)[0] & 0xFF) << (ulong_t)24) | \
70 68 (((ulong_t)((uchar_t *)a)[1] & 0xFF) << (ulong_t)16) | \
71 69 (((ulong_t)((uchar_t *)a)[2] & 0xFF) << (ulong_t)8) | \
72 70 ((ulong_t)((uchar_t *)a)[3] & 0xFF))
73 71
74 72 /*
75 73 * Number of elements to add to the poll array on each allocation.
76 74 */
77 75 #define POLL_ARRAY_INC_SIZE 64
78 76
79 77 /*
80 78 * Number of file descriptors by which the process soft limit may be
81 79 * increased on each call to nofile_increase(0).
82 80 */
83 81 #define NOFILE_INC_SIZE 64
84 82
85 83 struct conn_ind {
86 84 struct conn_ind *conn_next;
87 85 struct conn_ind *conn_prev;
88 86 struct t_call *conn_call;
89 87 };
90 88
91 89 struct conn_entry {
92 90 bool_t closing;
93 91 struct netconfig nc;
94 92 };
95 93
|
↓ open down ↓ |
54 lines elided |
↑ open up ↑ |
96 94 /*
97 95 * this file contains transport routines common to nfsd and lockd
98 96 */
99 97 static int nofile_increase(int);
100 98 static int reuseaddr(int);
101 99 static int recvucred(int);
102 100 static int anonmlp(int);
103 101 static void add_to_poll_list(int, struct netconfig *);
104 102 static char *serv_name_to_port_name(char *);
105 103 static int bind_to_proto(char *, char *, struct netbuf **,
106 - struct netconfig **);
104 + struct netconfig **, int, int);
107 105 static int bind_to_provider(char *, char *, struct netbuf **,
108 - struct netconfig **);
106 + struct netconfig **, int, int);
109 107 static void conn_close_oldest(void);
110 108 static boolean_t conn_get(int, struct netconfig *, struct conn_ind **);
111 109 static void cots_listen_event(int, int);
112 110 static int discon_get(int, struct netconfig *, struct conn_ind **);
113 111 static int do_poll_clts_action(int, int);
114 112 static int do_poll_cots_action(int, int);
115 113 static void remove_from_poll_list(int);
116 114 static int set_addrmask(int, struct netconfig *, struct netbuf *);
117 115 static int is_listen_fd_index(int);
118 116
119 117 static struct pollfd *poll_array;
120 118 static struct conn_entry *conn_polled;
121 119 static int num_conns; /* Current number of connections */
122 120 int (*Mysvc4)(int, struct netbuf *, struct netconfig *, int,
123 121 struct netbuf *);
122 +static int setopt(int fd, int level, int name, int value);
124 123
125 124 extern bool_t __pmap_set(const rpcprog_t program, const rpcvers_t version,
126 125 const struct netconfig *nconf, const struct netbuf *address);
127 126
128 127 /*
129 128 * Called to create and prepare a transport descriptor for in-kernel
130 129 * RPC service.
131 130 * Returns -1 on failure and a valid descriptor on success.
132 131 */
133 132 int
134 133 nfslib_transport_open(struct netconfig *nconf)
135 134 {
136 135 int fd;
137 136 struct strioctl strioc;
138 137
139 138 if ((nconf == (struct netconfig *)NULL) ||
140 139 (nconf->nc_device == (char *)NULL)) {
141 140 syslog(LOG_ERR, "no netconfig device");
142 141 return (-1);
143 142 }
144 143
145 144 /*
146 145 * Open the transport device.
147 146 */
148 147 fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
149 148 if (fd == -1) {
150 149 if (t_errno == TSYSERR && errno == EMFILE &&
151 150 (nofile_increase(0) == 0)) {
152 151 /* Try again with a higher NOFILE limit. */
153 152 fd = t_open(nconf->nc_device, O_RDWR,
154 153 (struct t_info *)NULL);
155 154 }
156 155 if (fd == -1) {
157 156 syslog(LOG_ERR, "t_open %s failed: t_errno %d, %m",
158 157 nconf->nc_device, t_errno);
159 158 return (-1);
160 159 }
161 160 }
162 161
163 162 /*
164 163 * Pop timod because the RPC module must be as close as possible
165 164 * to the transport.
166 165 */
167 166 if (ioctl(fd, I_POP, 0) < 0) {
168 167 syslog(LOG_ERR, "I_POP of timod failed: %m");
169 168 (void) t_close(fd);
170 169 return (-1);
171 170 }
172 171
173 172 /*
174 173 * Common code for CLTS and COTS transports
175 174 */
176 175 if (ioctl(fd, I_PUSH, "rpcmod") < 0) {
177 176 syslog(LOG_ERR, "I_PUSH of rpcmod failed: %m");
178 177 (void) t_close(fd);
179 178 return (-1);
180 179 }
181 180
182 181 strioc.ic_cmd = RPC_SERVER;
183 182 strioc.ic_dp = (char *)0;
184 183 strioc.ic_len = 0;
185 184 strioc.ic_timout = -1;
186 185
187 186 /* Tell rpcmod to act like a server stream. */
188 187 if (ioctl(fd, I_STR, &strioc) < 0) {
189 188 syslog(LOG_ERR, "rpcmod set-up ioctl failed: %m");
190 189 (void) t_close(fd);
191 190 return (-1);
192 191 }
193 192
194 193 /*
195 194 * Re-push timod so that we will still be doing TLI
196 195 * operations on the descriptor.
197 196 */
198 197 if (ioctl(fd, I_PUSH, "timod") < 0) {
199 198 syslog(LOG_ERR, "I_PUSH of timod failed: %m");
200 199 (void) t_close(fd);
201 200 return (-1);
202 201 }
203 202
204 203 /*
205 204 * Enable options of returning the ip's for udp.
206 205 */
207 206 if (strcmp(nconf->nc_netid, "udp6") == 0)
208 207 __rpc_tli_set_options(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, 1);
209 208 else if (strcmp(nconf->nc_netid, "udp") == 0)
210 209 __rpc_tli_set_options(fd, IPPROTO_IP, IP_RECVDSTADDR, 1);
211 210
212 211 return (fd);
213 212 }
214 213
215 214 static int
216 215 nofile_increase(int limit)
217 216 {
218 217 struct rlimit rl;
219 218
220 219 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
221 220 syslog(LOG_ERR, "getrlimit of NOFILE failed: %m");
222 221 return (-1);
223 222 }
224 223
225 224 if (limit > 0)
226 225 rl.rlim_cur = limit;
227 226 else
228 227 rl.rlim_cur += NOFILE_INC_SIZE;
229 228
230 229 if (rl.rlim_cur > rl.rlim_max &&
231 230 rl.rlim_max != RLIM_INFINITY)
232 231 rl.rlim_max = rl.rlim_cur;
|
↓ open down ↓ |
99 lines elided |
↑ open up ↑ |
233 232
234 233 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
235 234 syslog(LOG_ERR, "setrlimit of NOFILE to %d failed: %m",
236 235 rl.rlim_cur);
237 236 return (-1);
238 237 }
239 238
240 239 return (0);
241 240 }
242 241
242 +static int
243 +nfslib_set_sockbuf(int fd, int which, int val)
244 +{
245 + if ((which != SO_RCVBUF) && (which != SO_SNDBUF))
246 + return (-1);
247 +
248 + syslog(LOG_DEBUG, "Set %s option to %d",
249 + ((which == SO_RCVBUF) ? "SO_RCVBUF" : "SO_SNDBUF"), val);
250 +
251 + if (setopt(fd, SOL_SOCKET, which, val) < 0) {
252 + syslog(LOG_ERR, "couldn't set %s to %d - t_errno = %d",
253 + ((which == SO_RCVBUF) ? "SO_RCVBUF" : "SO_SNDBUF"),
254 + val, t_errno);
255 + syslog(LOG_ERR, "Check and increase system-wide tcp_max_buf");
256 + return (-1);
257 + }
258 + return (0);
259 +}
260 +
243 261 int
244 262 nfslib_bindit(struct netconfig *nconf, struct netbuf **addr,
245 - struct nd_hostserv *hs, int backlog)
263 + struct nd_hostserv *hs, int backlog, int sndbufsz, int rcvbufsz)
246 264 {
247 265 int fd;
248 266 struct t_bind *ntb;
249 267 struct t_bind tb;
250 268 struct nd_addrlist *addrlist;
251 269 struct t_optmgmt req, resp;
252 270 struct opthdr *opt;
253 271 char reqbuf[128];
254 272 bool_t use_any = FALSE;
255 273 bool_t gzone = TRUE;
256 274
257 275 if ((fd = nfslib_transport_open(nconf)) == -1) {
258 276 syslog(LOG_ERR, "cannot establish transport service over %s",
259 277 nconf->nc_device);
260 278 return (-1);
261 279 }
262 280
263 281 addrlist = (struct nd_addrlist *)NULL;
264 282
265 283 /* nfs4_callback service does not used a fieed port number */
266 284
267 285 if (strcmp(hs->h_serv, "nfs4_callback") == 0) {
268 286 tb.addr.maxlen = 0;
269 287 tb.addr.len = 0;
270 288 tb.addr.buf = 0;
271 289 use_any = TRUE;
272 290 gzone = (getzoneid() == GLOBAL_ZONEID);
273 291 } else if (netdir_getbyname(nconf, hs, &addrlist) != 0) {
274 292
275 293 syslog(LOG_ERR,
276 294 "Cannot get address for transport %s host %s service %s",
277 295 nconf->nc_netid, hs->h_host, hs->h_serv);
278 296 (void) t_close(fd);
279 297 return (-1);
280 298 }
281 299
282 300 if (strcmp(nconf->nc_proto, "tcp") == 0) {
283 301 /*
284 302 * If we're running over TCP, then set the
285 303 * SO_REUSEADDR option so that we can bind
286 304 * to our preferred address even if previously
287 305 * left connections exist in FIN_WAIT states.
288 306 * This is somewhat bogus, but otherwise you have
289 307 * to wait 2 minutes to restart after killing it.
290 308 */
291 309 if (reuseaddr(fd) == -1) {
292 310 syslog(LOG_WARNING,
293 311 "couldn't set SO_REUSEADDR option on transport");
294 312 }
295 313 } else if (strcmp(nconf->nc_proto, "udp") == 0) {
296 314 /*
297 315 * In order to run MLP on UDP, we need to handle creds.
298 316 */
299 317 if (recvucred(fd) == -1) {
300 318 syslog(LOG_WARNING,
301 319 "couldn't set SO_RECVUCRED option on transport");
302 320 }
303 321 }
304 322
305 323 /*
306 324 * Make non global zone nfs4_callback port MLP
307 325 */
308 326 if (use_any && is_system_labeled() && !gzone) {
309 327 if (anonmlp(fd) == -1) {
310 328 /*
311 329 * failing to set this option means nfs4_callback
312 330 * could fail silently later. So fail it with
313 331 * with an error message now.
314 332 */
315 333 syslog(LOG_ERR,
316 334 "couldn't set SO_ANON_MLP option on transport");
317 335 (void) t_close(fd);
318 336 return (-1);
319 337 }
320 338 }
321 339
322 340 if (nconf->nc_semantics == NC_TPI_CLTS)
323 341 tb.qlen = 0;
324 342 else
325 343 tb.qlen = backlog;
326 344
327 345 /* LINTED pointer alignment */
328 346 ntb = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL);
329 347 if (ntb == (struct t_bind *)NULL) {
330 348 syslog(LOG_ERR, "t_alloc failed: t_errno %d, %m", t_errno);
331 349 (void) t_close(fd);
332 350 netdir_free((void *)addrlist, ND_ADDRLIST);
333 351 return (-1);
334 352 }
335 353
336 354 /*
337 355 * XXX - what about the space tb->addr.buf points to? This should
338 356 * be either a memcpy() to/from the buf fields, or t_alloc(fd,T_BIND,)
339 357 * should't be called with T_ALL.
340 358 */
341 359 if (addrlist)
342 360 tb.addr = *(addrlist->n_addrs); /* structure copy */
343 361
344 362 if (t_bind(fd, &tb, ntb) == -1) {
345 363 syslog(LOG_ERR, "t_bind failed: t_errno %d, %m", t_errno);
346 364 (void) t_free((char *)ntb, T_BIND);
347 365 netdir_free((void *)addrlist, ND_ADDRLIST);
348 366 (void) t_close(fd);
349 367 return (-1);
350 368 }
351 369
352 370 /* make sure we bound to the right address */
353 371 if (use_any == FALSE &&
354 372 (tb.addr.len != ntb->addr.len ||
355 373 memcmp(tb.addr.buf, ntb->addr.buf, tb.addr.len) != 0)) {
356 374 syslog(LOG_ERR, "t_bind to wrong address");
357 375 (void) t_free((char *)ntb, T_BIND);
358 376 netdir_free((void *)addrlist, ND_ADDRLIST);
359 377 (void) t_close(fd);
360 378 return (-1);
361 379 }
362 380
363 381 /*
364 382 * Call nfs4svc_setport so that the kernel can be
365 383 * informed what port number the daemon is listing
366 384 * for incoming connection requests.
367 385 */
368 386
369 387 if ((nconf->nc_semantics == NC_TPI_COTS ||
370 388 nconf->nc_semantics == NC_TPI_COTS_ORD) && Mysvc4 != NULL)
371 389 (*Mysvc4)(fd, NULL, nconf, NFS4_SETPORT, &ntb->addr);
372 390
373 391 *addr = &ntb->addr;
374 392 netdir_free((void *)addrlist, ND_ADDRLIST);
375 393
376 394 if (strcmp(nconf->nc_proto, "tcp") == 0) {
377 395 /*
378 396 * Disable the Nagle algorithm on TCP connections.
379 397 * Connections accepted from this listener will
380 398 * inherit the listener options.
381 399 */
382 400
383 401 /* LINTED pointer alignment */
384 402 opt = (struct opthdr *)reqbuf;
385 403 opt->level = IPPROTO_TCP;
386 404 opt->name = TCP_NODELAY;
387 405 opt->len = sizeof (int);
388 406
389 407 /* LINTED pointer alignment */
390 408 *(int *)((char *)opt + sizeof (*opt)) = 1;
391 409
392 410 req.flags = T_NEGOTIATE;
393 411 req.opt.len = sizeof (*opt) + opt->len;
394 412 req.opt.buf = (char *)opt;
|
↓ open down ↓ |
139 lines elided |
↑ open up ↑ |
395 413 resp.flags = 0;
396 414 resp.opt.buf = reqbuf;
397 415 resp.opt.maxlen = sizeof (reqbuf);
398 416
399 417 if (t_optmgmt(fd, &req, &resp) < 0 ||
400 418 resp.flags != T_SUCCESS) {
401 419 syslog(LOG_ERR,
402 420 "couldn't set NODELAY option for proto %s: t_errno = %d, %m",
403 421 nconf->nc_proto, t_errno);
404 422 }
423 +
424 + if (sndbufsz > 0)
425 + (void) nfslib_set_sockbuf(fd, SO_SNDBUF, sndbufsz);
426 + if (rcvbufsz > 0)
427 + (void) nfslib_set_sockbuf(fd, SO_RCVBUF, rcvbufsz);
405 428 }
406 429
407 430 return (fd);
408 431 }
409 432
410 433 static int
411 434 setopt(int fd, int level, int name, int value)
412 435 {
413 436 struct t_optmgmt req, resp;
414 437 struct {
415 438 struct opthdr opt;
416 439 int value;
417 440 } reqbuf;
418 441
419 442 reqbuf.opt.level = level;
420 443 reqbuf.opt.name = name;
421 444 reqbuf.opt.len = sizeof (int);
422 445
423 446 reqbuf.value = value;
424 447
425 448 req.flags = T_NEGOTIATE;
426 449 req.opt.len = sizeof (reqbuf);
427 450 req.opt.buf = (char *)&reqbuf;
428 451
429 452 resp.flags = 0;
430 453 resp.opt.buf = (char *)&reqbuf;
431 454 resp.opt.maxlen = sizeof (reqbuf);
432 455
433 456 if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
434 457 t_error("t_optmgmt");
435 458 return (-1);
436 459 }
437 460 return (0);
438 461 }
439 462
440 463 static int
441 464 reuseaddr(int fd)
442 465 {
443 466 return (setopt(fd, SOL_SOCKET, SO_REUSEADDR, 1));
444 467 }
445 468
446 469 static int
447 470 recvucred(int fd)
448 471 {
449 472 return (setopt(fd, SOL_SOCKET, SO_RECVUCRED, 1));
450 473 }
451 474
452 475 static int
453 476 anonmlp(int fd)
454 477 {
455 478 return (setopt(fd, SOL_SOCKET, SO_ANON_MLP, 1));
456 479 }
457 480
458 481 void
459 482 nfslib_log_tli_error(char *tli_name, int fd, struct netconfig *nconf)
460 483 {
461 484 int error;
462 485
463 486 /*
464 487 * Save the error code across syslog(), just in case syslog()
465 488 * gets its own error and, therefore, overwrites errno.
466 489 */
467 490 error = errno;
468 491 if (t_errno == TSYSERR) {
469 492 syslog(LOG_ERR, "%s(file descriptor %d/transport %s) %m",
|
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
470 493 tli_name, fd, nconf->nc_proto);
471 494 } else {
472 495 syslog(LOG_ERR,
473 496 "%s(file descriptor %d/transport %s) TLI error %d",
474 497 tli_name, fd, nconf->nc_proto, t_errno);
475 498 }
476 499 errno = error;
477 500 }
478 501
479 502 /*
480 - * Called to set up service over a particular transport.
503 + * Called to set up service over a particular transport also
504 + * set send and receive buffer size for transport connection.
481 505 */
482 506 void
483 -do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
484 - int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
507 +do_one_setbuf(char *provider, NETSELDECL(proto), struct protob *protobp0,
508 + int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap,
509 + int sndbufsz, int rcvbufsz)
485 510 {
486 511 register int sock;
487 512 struct protob *protobp;
488 513 struct netbuf *retaddr;
489 514 struct netconfig *retnconf;
490 515 struct netbuf addrmask;
491 516 int vers;
492 517 int err;
493 518 int l;
494 519
495 520 if (provider)
496 521 sock = bind_to_provider(provider, protobp0->serv, &retaddr,
497 - &retnconf);
522 + &retnconf, sndbufsz, rcvbufsz);
498 523 else
499 524 sock = bind_to_proto(proto, protobp0->serv, &retaddr,
500 - &retnconf);
525 + &retnconf, sndbufsz, rcvbufsz);
501 526
502 527 if (sock == -1) {
503 528 (void) syslog(LOG_ERR,
504 529 "Cannot establish %s service over %s: transport setup problem.",
505 530 protobp0->serv, provider ? provider : proto);
506 531 return;
507 532 }
508 533
509 534 if (set_addrmask(sock, retnconf, &addrmask) < 0) {
510 535 (void) syslog(LOG_ERR,
511 536 "Cannot set address mask for %s", retnconf->nc_netid);
512 537 return;
513 538 }
514 539
515 540 /*
516 541 * Register all versions of the programs in the protocol block list.
517 542 */
518 543 l = strlen(NC_UDP);
519 544 for (protobp = protobp0; protobp; protobp = protobp->next) {
520 545 for (vers = protobp->versmin; vers <= protobp->versmax;
521 546 vers++) {
522 547 if ((protobp->program == NFS_PROGRAM ||
523 548 protobp->program == NFS_ACL_PROGRAM) &&
524 549 vers == NFS_V4 &&
525 550 strncasecmp(retnconf->nc_proto, NC_UDP, l) == 0)
526 551 continue;
527 552
528 553 if (use_pmap) {
529 554 /*
530 555 * Note that if we're using a portmapper
531 556 * instead of rpcbind then we can't do an
532 557 * unregister operation here.
533 558 *
534 559 * The reason is that the portmapper unset
535 560 * operation removes all the entries for a
536 561 * given program/version regardelss of
537 562 * transport protocol.
538 563 *
539 564 * The caller of this routine needs to ensure
540 565 * that __pmap_unset() has been called for all
541 566 * program/version service pairs they plan
542 567 * to support before they start registering
543 568 * each program/version/protocol triplet.
544 569 */
545 570 (void) __pmap_set(protobp->program, vers,
546 571 retnconf, retaddr);
547 572 } else {
548 573 (void) rpcb_unset(protobp->program, vers,
549 574 retnconf);
550 575 (void) rpcb_set(protobp->program, vers,
551 576 retnconf, retaddr);
552 577 }
553 578 }
554 579 }
555 580
556 581 if (retnconf->nc_semantics == NC_TPI_CLTS) {
557 582 /* Don't drop core if supporting module(s) aren't loaded. */
558 583 (void) signal(SIGSYS, SIG_IGN);
559 584
560 585 /*
561 586 * svc() doesn't block, it returns success or failure.
562 587 */
563 588
564 589 if (svc == NULL && Mysvc4 != NULL)
565 590 err = (*Mysvc4)(sock, &addrmask, retnconf,
566 591 NFS4_SETPORT|NFS4_KRPC_START, retaddr);
567 592 else
568 593 err = (*svc)(sock, addrmask, retnconf);
569 594
570 595 if (err < 0) {
571 596 (void) syslog(LOG_ERR,
572 597 "Cannot establish %s service over <file desc."
573 598 " %d, protocol %s> : %m. Exiting",
574 599 protobp0->serv, sock, retnconf->nc_proto);
|
↓ open down ↓ |
64 lines elided |
↑ open up ↑ |
575 600 exit(1);
576 601 }
577 602 }
578 603
579 604 /*
580 605 * We successfully set up the server over this transport.
581 606 * Add this descriptor to the one being polled on.
582 607 */
583 608 add_to_poll_list(sock, retnconf);
584 609 }
610 +
585 611 /*
586 - * Set up the NFS service over all the available transports.
612 + * Set up the NFS service over all the available transports and
613 + * also set send and receive buffer size for transport connection.
587 614 * Returns -1 for failure, 0 for success.
588 615 */
589 616 int
590 -do_all(struct protob *protobp,
591 - int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
617 +do_all_setbuf(struct protob *protobp,
618 + int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap,
619 + int sndbufsz, int rcvbufsz)
592 620 {
593 621 struct netconfig *nconf;
594 622 NCONF_HANDLE *nc;
595 623 int l;
596 624
597 625 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
598 626 syslog(LOG_ERR, "setnetconfig failed: %m");
599 627 return (-1);
600 628 }
601 629 l = strlen(NC_UDP);
602 630 while (nconf = getnetconfig(nc)) {
603 631 if ((nconf->nc_flag & NC_VISIBLE) &&
604 632 strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0 &&
605 633 OK_TPI_TYPE(nconf) &&
606 634 (protobp->program != NFS4_CALLBACK ||
607 635 strncasecmp(nconf->nc_proto, NC_UDP, l) != 0))
608 - do_one(nconf->nc_device, nconf->nc_proto,
609 - protobp, svc, use_pmap);
636 + do_one_setbuf(nconf->nc_device, nconf->nc_proto,
637 + protobp, svc, use_pmap, sndbufsz, rcvbufsz);
610 638 }
611 639 (void) endnetconfig(nc);
612 640 return (0);
613 641 }
614 642
615 643 /*
644 + * Called to set up service over a particular transport.
645 + */
646 +void
647 +do_one(char *provider, NETSELDECL(proto), struct protob *protobp0,
648 + int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
649 +{
650 + do_one_setbuf(provider, proto, protobp0, svc, use_pmap, 0, 0);
651 +}
652 +
653 +/*
654 + * Set up the NFS service over all the available transports.
655 + * Returns -1 for failure, 0 for success.
656 + */
657 +int
658 +do_all(struct protob *protobp,
659 + int (*svc)(int, struct netbuf, struct netconfig *), int use_pmap)
660 +{
661 + return (do_all_setbuf(protobp, svc, use_pmap, 0, 0));
662 +}
663 +
664 +/*
616 665 * poll on the open transport descriptors for events and errors.
617 666 */
618 667 void
619 668 poll_for_action(void)
620 669 {
621 670 int nfds;
622 671 int i;
623 672
624 673 /*
625 674 * Keep polling until all transports have been closed. When this
626 675 * happens, we return.
627 676 */
628 677 while ((int)num_fds > 0) {
629 678 nfds = poll(poll_array, num_fds, INFTIM);
630 679 switch (nfds) {
631 680 case 0:
632 681 continue;
633 682
634 683 case -1:
635 684 /*
636 685 * Some errors from poll could be
637 686 * due to temporary conditions, and we try to
638 687 * be robust in the face of them. Other
639 688 * errors (should never happen in theory)
640 689 * are fatal (eg. EINVAL, EFAULT).
641 690 */
642 691 switch (errno) {
643 692 case EINTR:
644 693 continue;
645 694
646 695 case EAGAIN:
647 696 case ENOMEM:
648 697 (void) sleep(10);
649 698 continue;
650 699
651 700 default:
652 701 (void) syslog(LOG_ERR,
653 702 "poll failed: %m. Exiting");
654 703 exit(1);
655 704 }
656 705 default:
657 706 break;
658 707 }
659 708
660 709 /*
661 710 * Go through the poll list looking for events.
662 711 */
663 712 for (i = 0; i < num_fds && nfds > 0; i++) {
664 713 if (poll_array[i].revents) {
665 714 nfds--;
666 715 /*
667 716 * We have a message, so try to read it.
668 717 * Record the error return in errno,
669 718 * so that syslog(LOG_ERR, "...%m")
670 719 * dumps the corresponding error string.
671 720 */
672 721 if (conn_polled[i].nc.nc_semantics ==
673 722 NC_TPI_CLTS) {
674 723 errno = do_poll_clts_action(
675 724 poll_array[i].fd, i);
676 725 } else {
677 726 errno = do_poll_cots_action(
678 727 poll_array[i].fd, i);
679 728 }
680 729
681 730 if (errno == 0)
682 731 continue;
683 732 /*
684 733 * Most returned error codes mean that there is
685 734 * fatal condition which we can only deal with
686 735 * by closing the transport.
687 736 */
688 737 if (errno != EAGAIN && errno != ENOMEM) {
689 738 (void) syslog(LOG_ERR,
690 739 "Error (%m) reading descriptor %d/transport %s. Closing it.",
691 740 poll_array[i].fd,
692 741 conn_polled[i].nc.nc_proto);
693 742 (void) t_close(poll_array[i].fd);
694 743 remove_from_poll_list(poll_array[i].fd);
695 744
696 745 } else if (errno == ENOMEM)
697 746 (void) sleep(5);
698 747 }
699 748 }
700 749 }
701 750
702 751 (void) syslog(LOG_ERR,
703 752 "All transports have been closed with errors. Exiting.");
704 753 }
705 754
706 755 /*
707 756 * Allocate poll/transport array entries for this descriptor.
708 757 */
709 758 static void
710 759 add_to_poll_list(int fd, struct netconfig *nconf)
711 760 {
712 761 static int poll_array_size = 0;
713 762
714 763 /*
715 764 * If the arrays are full, allocate new ones.
716 765 */
717 766 if (num_fds == poll_array_size) {
718 767 struct pollfd *tpa;
719 768 struct conn_entry *tnp;
720 769
721 770 if (poll_array_size != 0) {
722 771 tpa = poll_array;
723 772 tnp = conn_polled;
724 773 } else
725 774 tpa = (struct pollfd *)0;
726 775
727 776 poll_array_size += POLL_ARRAY_INC_SIZE;
728 777 /*
729 778 * Allocate new arrays.
730 779 */
731 780 poll_array = (struct pollfd *)
732 781 malloc(poll_array_size * sizeof (struct pollfd) + 256);
733 782 conn_polled = (struct conn_entry *)
734 783 malloc(poll_array_size * sizeof (struct conn_entry) + 256);
735 784 if (poll_array == (struct pollfd *)NULL ||
736 785 conn_polled == (struct conn_entry *)NULL) {
737 786 syslog(LOG_ERR, "malloc failed for poll array");
738 787 exit(1);
739 788 }
740 789
741 790 /*
742 791 * Copy the data of the old ones into new arrays, and
743 792 * free the old ones.
744 793 */
745 794 if (tpa) {
746 795 (void) memcpy((void *)poll_array, (void *)tpa,
747 796 num_fds * sizeof (struct pollfd));
748 797 (void) memcpy((void *)conn_polled, (void *)tnp,
749 798 num_fds * sizeof (struct conn_entry));
750 799 free((void *)tpa);
751 800 free((void *)tnp);
752 801 }
753 802 }
754 803
755 804 /*
756 805 * Set the descriptor and event list. All possible events are
757 806 * polled for.
758 807 */
759 808 poll_array[num_fds].fd = fd;
760 809 poll_array[num_fds].events = POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI;
761 810
762 811 /*
763 812 * Copy the transport data over too.
764 813 */
765 814 conn_polled[num_fds].nc = *nconf;
766 815 conn_polled[num_fds].closing = 0;
767 816
768 817 /*
769 818 * Set the descriptor to non-blocking. Avoids a race
770 819 * between data arriving on the stream and then having it
771 820 * flushed before we can read it.
772 821 */
773 822 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
774 823 (void) syslog(LOG_ERR,
775 824 "fcntl(file desc. %d/transport %s, F_SETFL, O_NONBLOCK): %m. Exiting",
776 825 num_fds, nconf->nc_proto);
777 826 exit(1);
778 827 }
779 828
780 829 /*
781 830 * Count this descriptor.
782 831 */
783 832 ++num_fds;
784 833 }
785 834
786 835 static void
787 836 remove_from_poll_list(int fd)
788 837 {
789 838 int i;
790 839 int num_to_copy;
791 840
792 841 for (i = 0; i < num_fds; i++) {
793 842 if (poll_array[i].fd == fd) {
794 843 --num_fds;
795 844 num_to_copy = num_fds - i;
796 845 (void) memcpy((void *)&poll_array[i],
797 846 (void *)&poll_array[i+1],
798 847 num_to_copy * sizeof (struct pollfd));
799 848 (void) memset((void *)&poll_array[num_fds], 0,
800 849 sizeof (struct pollfd));
801 850 (void) memcpy((void *)&conn_polled[i],
802 851 (void *)&conn_polled[i+1],
803 852 num_to_copy * sizeof (struct conn_entry));
804 853 (void) memset((void *)&conn_polled[num_fds], 0,
805 854 sizeof (struct conn_entry));
806 855 return;
807 856 }
808 857 }
809 858 syslog(LOG_ERR, "attempt to remove nonexistent fd from poll list");
810 859
811 860 }
812 861
813 862 /*
814 863 * Called to read and interpret the event on a connectionless descriptor.
815 864 * Returns 0 if successful, or a UNIX error code if failure.
816 865 */
817 866 static int
818 867 do_poll_clts_action(int fd, int conn_index)
819 868 {
820 869 int error;
821 870 int ret;
822 871 int flags;
823 872 struct netconfig *nconf = &conn_polled[conn_index].nc;
824 873 static struct t_unitdata *unitdata = NULL;
825 874 static struct t_uderr *uderr = NULL;
826 875 static int oldfd = -1;
827 876 struct nd_hostservlist *host = NULL;
828 877 struct strbuf ctl[1], data[1];
829 878 /*
830 879 * We just need to have some space to consume the
831 880 * message in the event we can't use the TLI interface to do the
832 881 * job.
833 882 *
834 883 * We flush the message using getmsg(). For the control part
835 884 * we allocate enough for any TPI header plus 32 bytes for address
836 885 * and options. For the data part, there is nothing magic about
837 886 * the size of the array, but 256 bytes is probably better than
838 887 * 1 byte, and we don't expect any data portion anyway.
839 888 *
840 889 * If the array sizes are too small, we handle this because getmsg()
841 890 * (called to consume the message) will return MOREDATA|MORECTL.
842 891 * Thus we just call getmsg() until it's read the message.
843 892 */
844 893 char ctlbuf[sizeof (union T_primitives) + 32];
845 894 char databuf[256];
846 895
847 896 /*
848 897 * If this is the same descriptor as the last time
849 898 * do_poll_clts_action was called, we can save some
850 899 * de-allocation and allocation.
851 900 */
852 901 if (oldfd != fd) {
853 902 oldfd = fd;
854 903
855 904 if (unitdata) {
856 905 (void) t_free((char *)unitdata, T_UNITDATA);
857 906 unitdata = NULL;
858 907 }
859 908 if (uderr) {
860 909 (void) t_free((char *)uderr, T_UDERROR);
861 910 uderr = NULL;
862 911 }
863 912 }
864 913
865 914 /*
866 915 * Allocate a unitdata structure for receiving the event.
867 916 */
868 917 if (unitdata == NULL) {
869 918 /* LINTED pointer alignment */
870 919 unitdata = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ALL);
871 920 if (unitdata == NULL) {
872 921 if (t_errno == TSYSERR) {
873 922 /*
874 923 * Save the error code across
875 924 * syslog(), just in case
876 925 * syslog() gets its own error
877 926 * and therefore overwrites errno.
878 927 */
879 928 error = errno;
880 929 (void) syslog(LOG_ERR,
881 930 "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed: %m",
882 931 fd, nconf->nc_proto);
883 932 return (error);
884 933 }
885 934 (void) syslog(LOG_ERR,
886 935 "t_alloc(file descriptor %d/transport %s, T_UNITDATA) failed TLI error %d",
887 936 fd, nconf->nc_proto, t_errno);
888 937 goto flush_it;
889 938 }
890 939 }
891 940
892 941 try_again:
893 942 flags = 0;
894 943
895 944 /*
896 945 * The idea is we wait for T_UNITDATA_IND's. Of course,
897 946 * we don't get any, because rpcmod filters them out.
898 947 * However, we need to call t_rcvudata() to let TLI
899 948 * tell us we have a T_UDERROR_IND.
900 949 *
901 950 * algorithm is:
902 951 * t_rcvudata(), expecting TLOOK.
903 952 * t_look(), expecting T_UDERR.
904 953 * t_rcvuderr(), expecting success (0).
905 954 * expand destination address into ASCII,
906 955 * and dump it.
907 956 */
908 957
909 958 ret = t_rcvudata(fd, unitdata, &flags);
910 959 if (ret == 0 || t_errno == TBUFOVFLW) {
911 960 (void) syslog(LOG_WARNING,
912 961 "t_rcvudata(file descriptor %d/transport %s) got unexpected data, %d bytes",
913 962 fd, nconf->nc_proto, unitdata->udata.len);
914 963
915 964 /*
916 965 * Even though we don't expect any data, in case we do,
917 966 * keep reading until there is no more.
918 967 */
919 968 if (flags & T_MORE)
920 969 goto try_again;
921 970
922 971 return (0);
923 972 }
924 973
925 974 switch (t_errno) {
926 975 case TNODATA:
927 976 return (0);
928 977 case TSYSERR:
929 978 /*
930 979 * System errors are returned to caller.
931 980 * Save the error code across
932 981 * syslog(), just in case
933 982 * syslog() gets its own error
934 983 * and therefore overwrites errno.
935 984 */
936 985 error = errno;
937 986 (void) syslog(LOG_ERR,
938 987 "t_rcvudata(file descriptor %d/transport %s) %m",
939 988 fd, nconf->nc_proto);
940 989 return (error);
941 990 case TLOOK:
942 991 break;
943 992 default:
944 993 (void) syslog(LOG_ERR,
945 994 "t_rcvudata(file descriptor %d/transport %s) TLI error %d",
946 995 fd, nconf->nc_proto, t_errno);
947 996 goto flush_it;
948 997 }
949 998
950 999 ret = t_look(fd);
951 1000 switch (ret) {
952 1001 case 0:
953 1002 return (0);
954 1003 case -1:
955 1004 /*
956 1005 * System errors are returned to caller.
957 1006 */
958 1007 if (t_errno == TSYSERR) {
959 1008 /*
960 1009 * Save the error code across
961 1010 * syslog(), just in case
962 1011 * syslog() gets its own error
963 1012 * and therefore overwrites errno.
964 1013 */
965 1014 error = errno;
966 1015 (void) syslog(LOG_ERR,
967 1016 "t_look(file descriptor %d/transport %s) %m",
968 1017 fd, nconf->nc_proto);
969 1018 return (error);
970 1019 }
971 1020 (void) syslog(LOG_ERR,
972 1021 "t_look(file descriptor %d/transport %s) TLI error %d",
973 1022 fd, nconf->nc_proto, t_errno);
974 1023 goto flush_it;
975 1024 case T_UDERR:
976 1025 break;
977 1026 default:
978 1027 (void) syslog(LOG_WARNING,
979 1028 "t_look(file descriptor %d/transport %s) returned %d not T_UDERR (%d)",
980 1029 fd, nconf->nc_proto, ret, T_UDERR);
981 1030 }
982 1031
983 1032 if (uderr == NULL) {
984 1033 /* LINTED pointer alignment */
985 1034 uderr = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ALL);
986 1035 if (uderr == NULL) {
987 1036 if (t_errno == TSYSERR) {
988 1037 /*
989 1038 * Save the error code across
990 1039 * syslog(), just in case
991 1040 * syslog() gets its own error
992 1041 * and therefore overwrites errno.
993 1042 */
994 1043 error = errno;
995 1044 (void) syslog(LOG_ERR,
996 1045 "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed: %m",
997 1046 fd, nconf->nc_proto);
998 1047 return (error);
999 1048 }
1000 1049 (void) syslog(LOG_ERR,
1001 1050 "t_alloc(file descriptor %d/transport %s, T_UDERROR) failed TLI error: %d",
1002 1051 fd, nconf->nc_proto, t_errno);
1003 1052 goto flush_it;
1004 1053 }
1005 1054 }
1006 1055
1007 1056 ret = t_rcvuderr(fd, uderr);
1008 1057 if (ret == 0) {
1009 1058
1010 1059 /*
1011 1060 * Save the datagram error in errno, so that the
1012 1061 * %m argument to syslog picks up the error string.
1013 1062 */
1014 1063 errno = uderr->error;
1015 1064
1016 1065 /*
1017 1066 * Log the datagram error, then log the host that
1018 1067 * probably triggerred. Cannot log both in the
1019 1068 * same transaction because of packet size limitations
1020 1069 * in /dev/log.
1021 1070 */
1022 1071 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1023 1072 "NFS response over <file descriptor %d/transport %s> generated error: %m",
1024 1073 fd, nconf->nc_proto);
1025 1074
1026 1075 /*
1027 1076 * Try to map the client's address back to a
1028 1077 * name.
1029 1078 */
1030 1079 ret = netdir_getbyaddr(nconf, &host, &uderr->addr);
1031 1080 if (ret != -1 && host && host->h_cnt > 0 &&
1032 1081 host->h_hostservs) {
1033 1082 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1034 1083 "Bad NFS response was sent to client with host name: %s; service port: %s",
1035 1084 host->h_hostservs->h_host,
1036 1085 host->h_hostservs->h_serv);
1037 1086 } else {
1038 1087 int i, j;
1039 1088 char *buf;
1040 1089 char *hex = "0123456789abcdef";
1041 1090
1042 1091 /*
1043 1092 * Mapping failed, print the whole thing
1044 1093 * in ASCII hex.
1045 1094 */
1046 1095 buf = (char *)malloc(uderr->addr.len * 2 + 1);
1047 1096 for (i = 0, j = 0; i < uderr->addr.len; i++, j += 2) {
1048 1097 buf[j] = hex[((uderr->addr.buf[i]) >> 4) & 0xf];
1049 1098 buf[j+1] = hex[uderr->addr.buf[i] & 0xf];
1050 1099 }
1051 1100 buf[j] = '\0';
1052 1101 (void) syslog((errno == ECONNREFUSED) ? LOG_DEBUG : LOG_WARNING,
1053 1102 "Bad NFS response was sent to client with transport address: 0x%s",
1054 1103 buf);
1055 1104 free((void *)buf);
1056 1105 }
1057 1106
1058 1107 if (ret == 0 && host != NULL)
1059 1108 netdir_free((void *)host, ND_HOSTSERVLIST);
1060 1109 return (0);
1061 1110 }
1062 1111
1063 1112 switch (t_errno) {
1064 1113 case TNOUDERR:
1065 1114 goto flush_it;
1066 1115 case TSYSERR:
1067 1116 /*
1068 1117 * System errors are returned to caller.
1069 1118 * Save the error code across
1070 1119 * syslog(), just in case
1071 1120 * syslog() gets its own error
1072 1121 * and therefore overwrites errno.
1073 1122 */
1074 1123 error = errno;
1075 1124 (void) syslog(LOG_ERR,
1076 1125 "t_rcvuderr(file descriptor %d/transport %s) %m",
1077 1126 fd, nconf->nc_proto);
1078 1127 return (error);
1079 1128 default:
1080 1129 (void) syslog(LOG_ERR,
1081 1130 "t_rcvuderr(file descriptor %d/transport %s) TLI error %d",
1082 1131 fd, nconf->nc_proto, t_errno);
1083 1132 goto flush_it;
1084 1133 }
1085 1134
1086 1135 flush_it:
1087 1136 /*
1088 1137 * If we get here, then we could not cope with whatever message
1089 1138 * we attempted to read, so flush it. If we did read a message,
1090 1139 * and one isn't present, that is all right, because fd is in
1091 1140 * nonblocking mode.
1092 1141 */
1093 1142 (void) syslog(LOG_ERR,
1094 1143 "Flushing one input message from <file descriptor %d/transport %s>",
1095 1144 fd, nconf->nc_proto);
1096 1145
1097 1146 /*
1098 1147 * Read and discard the message. Do this this until there is
1099 1148 * no more control/data in the message or until we get an error.
1100 1149 */
1101 1150 do {
1102 1151 ctl->maxlen = sizeof (ctlbuf);
1103 1152 ctl->buf = ctlbuf;
1104 1153 data->maxlen = sizeof (databuf);
1105 1154 data->buf = databuf;
1106 1155 flags = 0;
1107 1156 ret = getmsg(fd, ctl, data, &flags);
1108 1157 if (ret == -1)
1109 1158 return (errno);
1110 1159 } while (ret != 0);
1111 1160
1112 1161 return (0);
1113 1162 }
1114 1163
1115 1164 static void
1116 1165 conn_close_oldest(void)
1117 1166 {
1118 1167 int fd;
1119 1168 int i1;
1120 1169
1121 1170 /*
1122 1171 * Find the oldest connection that is not already in the
1123 1172 * process of shutting down.
1124 1173 */
1125 1174 for (i1 = end_listen_fds; /* no conditional expression */; i1++) {
1126 1175 if (i1 >= num_fds)
1127 1176 return;
1128 1177 if (conn_polled[i1].closing == 0)
1129 1178 break;
1130 1179 }
1131 1180 #ifdef DEBUG
1132 1181 printf("too many connections (%d), releasing oldest (%d)\n",
1133 1182 num_conns, poll_array[i1].fd);
1134 1183 #else
1135 1184 syslog(LOG_WARNING, "too many connections (%d), releasing oldest (%d)",
1136 1185 num_conns, poll_array[i1].fd);
1137 1186 #endif
1138 1187 fd = poll_array[i1].fd;
1139 1188 if (conn_polled[i1].nc.nc_semantics == NC_TPI_COTS) {
1140 1189 /*
1141 1190 * For politeness, send a T_DISCON_REQ to the transport
1142 1191 * provider. We close the stream anyway.
1143 1192 */
1144 1193 (void) t_snddis(fd, (struct t_call *)0);
1145 1194 num_conns--;
1146 1195 remove_from_poll_list(fd);
1147 1196 (void) t_close(fd);
1148 1197 } else {
1149 1198 /*
1150 1199 * For orderly release, we do not close the stream
1151 1200 * until the T_ORDREL_IND arrives to complete
1152 1201 * the handshake.
1153 1202 */
1154 1203 if (t_sndrel(fd) == 0)
1155 1204 conn_polled[i1].closing = 1;
1156 1205 }
1157 1206 }
1158 1207
1159 1208 static boolean_t
1160 1209 conn_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1161 1210 {
1162 1211 struct conn_ind *conn;
1163 1212 struct conn_ind *next_conn;
1164 1213
1165 1214 conn = (struct conn_ind *)malloc(sizeof (*conn));
1166 1215 if (conn == NULL) {
1167 1216 syslog(LOG_ERR, "malloc for listen indication failed");
1168 1217 return (FALSE);
1169 1218 }
1170 1219
1171 1220 /* LINTED pointer alignment */
1172 1221 conn->conn_call = (struct t_call *)t_alloc(fd, T_CALL, T_ALL);
1173 1222 if (conn->conn_call == NULL) {
1174 1223 free((char *)conn);
1175 1224 nfslib_log_tli_error("t_alloc", fd, nconf);
1176 1225 return (FALSE);
1177 1226 }
1178 1227
1179 1228 if (t_listen(fd, conn->conn_call) == -1) {
1180 1229 nfslib_log_tli_error("t_listen", fd, nconf);
1181 1230 (void) t_free((char *)conn->conn_call, T_CALL);
1182 1231 free((char *)conn);
1183 1232 return (FALSE);
1184 1233 }
1185 1234
1186 1235 if (conn->conn_call->udata.len > 0) {
1187 1236 syslog(LOG_WARNING,
1188 1237 "rejecting inbound connection(%s) with %d bytes of connect data",
1189 1238 nconf->nc_proto, conn->conn_call->udata.len);
1190 1239
1191 1240 conn->conn_call->udata.len = 0;
1192 1241 (void) t_snddis(fd, conn->conn_call);
1193 1242 (void) t_free((char *)conn->conn_call, T_CALL);
1194 1243 free((char *)conn);
1195 1244 return (FALSE);
1196 1245 }
1197 1246
1198 1247 if ((next_conn = *connp) != NULL) {
1199 1248 next_conn->conn_prev->conn_next = conn;
1200 1249 conn->conn_next = next_conn;
1201 1250 conn->conn_prev = next_conn->conn_prev;
1202 1251 next_conn->conn_prev = conn;
1203 1252 } else {
1204 1253 conn->conn_next = conn;
1205 1254 conn->conn_prev = conn;
1206 1255 *connp = conn;
1207 1256 }
1208 1257 return (TRUE);
1209 1258 }
1210 1259
1211 1260 static int
1212 1261 discon_get(int fd, struct netconfig *nconf, struct conn_ind **connp)
1213 1262 {
1214 1263 struct conn_ind *conn;
1215 1264 struct t_discon discon;
1216 1265
1217 1266 discon.udata.buf = (char *)0;
1218 1267 discon.udata.maxlen = 0;
1219 1268 if (t_rcvdis(fd, &discon) == -1) {
1220 1269 nfslib_log_tli_error("t_rcvdis", fd, nconf);
1221 1270 return (-1);
1222 1271 }
1223 1272
1224 1273 conn = *connp;
1225 1274 if (conn == NULL)
1226 1275 return (0);
1227 1276
1228 1277 do {
1229 1278 if (conn->conn_call->sequence == discon.sequence) {
1230 1279 if (conn->conn_next == conn)
1231 1280 *connp = (struct conn_ind *)0;
1232 1281 else {
1233 1282 if (conn == *connp) {
1234 1283 *connp = conn->conn_next;
1235 1284 }
1236 1285 conn->conn_next->conn_prev = conn->conn_prev;
1237 1286 conn->conn_prev->conn_next = conn->conn_next;
1238 1287 }
1239 1288 free((char *)conn);
1240 1289 break;
1241 1290 }
1242 1291 conn = conn->conn_next;
1243 1292 } while (conn != *connp);
1244 1293
1245 1294 return (0);
1246 1295 }
1247 1296
1248 1297 static void
1249 1298 cots_listen_event(int fd, int conn_index)
1250 1299 {
1251 1300 struct t_call *call;
1252 1301 struct conn_ind *conn;
1253 1302 struct conn_ind *conn_head;
1254 1303 int event;
1255 1304 struct netconfig *nconf = &conn_polled[conn_index].nc;
1256 1305 int new_fd;
1257 1306 struct netbuf addrmask;
1258 1307 int ret = 0;
1259 1308 char *clnt;
1260 1309 char *clnt_uaddr = NULL;
1261 1310 struct nd_hostservlist *clnt_serv = NULL;
1262 1311
1263 1312 conn_head = (struct conn_ind *)0;
1264 1313 (void) conn_get(fd, nconf, &conn_head);
1265 1314
1266 1315 while ((conn = conn_head) != NULL) {
1267 1316 conn_head = conn->conn_next;
1268 1317 if (conn_head == conn)
1269 1318 conn_head = (struct conn_ind *)0;
1270 1319 else {
1271 1320 conn_head->conn_prev = conn->conn_prev;
1272 1321 conn->conn_prev->conn_next = conn_head;
1273 1322 }
1274 1323 call = conn->conn_call;
1275 1324 free((char *)conn);
1276 1325
1277 1326 /*
1278 1327 * If we have already accepted the maximum number of
1279 1328 * connections allowed on the command line, then drop
1280 1329 * the oldest connection (for any protocol) before
1281 1330 * accepting the new connection. Unless explicitly
1282 1331 * set on the command line, max_conns_allowed is -1.
1283 1332 */
1284 1333 if (max_conns_allowed != -1 && num_conns >= max_conns_allowed)
1285 1334 conn_close_oldest();
1286 1335
1287 1336 /*
1288 1337 * Create a new transport endpoint for the same proto as
1289 1338 * the listener.
1290 1339 */
1291 1340 new_fd = nfslib_transport_open(nconf);
1292 1341 if (new_fd == -1) {
1293 1342 call->udata.len = 0;
1294 1343 (void) t_snddis(fd, call);
1295 1344 (void) t_free((char *)call, T_CALL);
1296 1345 syslog(LOG_ERR, "Cannot establish transport over %s",
1297 1346 nconf->nc_device);
1298 1347 continue;
1299 1348 }
1300 1349
1301 1350 /* Bind to a generic address/port for the accepting stream. */
1302 1351 if (t_bind(new_fd, (struct t_bind *)NULL,
1303 1352 (struct t_bind *)NULL) == -1) {
1304 1353 nfslib_log_tli_error("t_bind", new_fd, nconf);
1305 1354 call->udata.len = 0;
1306 1355 (void) t_snddis(fd, call);
1307 1356 (void) t_free((char *)call, T_CALL);
1308 1357 (void) t_close(new_fd);
1309 1358 continue;
1310 1359 }
1311 1360
1312 1361 while (t_accept(fd, new_fd, call) == -1) {
1313 1362 if (t_errno != TLOOK) {
1314 1363 #ifdef DEBUG
1315 1364 nfslib_log_tli_error("t_accept", fd, nconf);
1316 1365 #endif
1317 1366 call->udata.len = 0;
1318 1367 (void) t_snddis(fd, call);
1319 1368 (void) t_free((char *)call, T_CALL);
1320 1369 (void) t_close(new_fd);
1321 1370 goto do_next_conn;
1322 1371 }
1323 1372 while (event = t_look(fd)) {
1324 1373 switch (event) {
1325 1374 case T_LISTEN:
1326 1375 #ifdef DEBUG
1327 1376 printf(
1328 1377 "cots_listen_event(%s): T_LISTEN during accept processing\n", nconf->nc_proto);
1329 1378 #endif
1330 1379 (void) conn_get(fd, nconf, &conn_head);
1331 1380 continue;
1332 1381 case T_DISCONNECT:
1333 1382 #ifdef DEBUG
1334 1383 printf(
1335 1384 "cots_listen_event(%s): T_DISCONNECT during accept processing\n",
1336 1385 nconf->nc_proto);
1337 1386 #endif
1338 1387 (void) discon_get(fd, nconf,
1339 1388 &conn_head);
1340 1389 continue;
1341 1390 default:
1342 1391 syslog(LOG_ERR,
1343 1392 "unexpected event 0x%x during accept processing (%s)",
1344 1393 event, nconf->nc_proto);
1345 1394 call->udata.len = 0;
1346 1395 (void) t_snddis(fd, call);
1347 1396 (void) t_free((char *)call, T_CALL);
1348 1397 (void) t_close(new_fd);
1349 1398 goto do_next_conn;
1350 1399 }
1351 1400 }
1352 1401 }
1353 1402
1354 1403 if (set_addrmask(new_fd, nconf, &addrmask) < 0) {
1355 1404 (void) syslog(LOG_ERR,
1356 1405 "Cannot set address mask for %s",
1357 1406 nconf->nc_netid);
1358 1407 return;
1359 1408 }
1360 1409
1361 1410 /* Tell KRPC about the new stream. */
1362 1411 if (Mysvc4 != NULL)
1363 1412 ret = (*Mysvc4)(new_fd, &addrmask, nconf,
1364 1413 NFS4_KRPC_START, &call->addr);
1365 1414 else
1366 1415 ret = (*Mysvc)(new_fd, addrmask, nconf);
1367 1416
1368 1417 if (ret < 0) {
1369 1418 if (errno != ENOTCONN) {
1370 1419 syslog(LOG_ERR,
1371 1420 "unable to register new connection: %m");
1372 1421 } else {
1373 1422 /*
1374 1423 * This is the only error that could be
1375 1424 * caused by the client, so who was it?
1376 1425 */
1377 1426 if (netdir_getbyaddr(nconf, &clnt_serv,
1378 1427 &(call->addr)) == ND_OK &&
1379 1428 clnt_serv->h_cnt > 0)
1380 1429 clnt = clnt_serv->h_hostservs->h_host;
1381 1430 else
1382 1431 clnt = clnt_uaddr = taddr2uaddr(nconf,
1383 1432 &(call->addr));
1384 1433 /*
1385 1434 * If we don't know who the client was,
1386 1435 * remain silent.
1387 1436 */
1388 1437 if (clnt)
1389 1438 syslog(LOG_ERR,
1390 1439 "unable to register new connection: client %s has dropped connection", clnt);
1391 1440 if (clnt_serv)
1392 1441 netdir_free(clnt_serv, ND_HOSTSERVLIST);
1393 1442 if (clnt_uaddr)
1394 1443 free(clnt_uaddr);
1395 1444 }
1396 1445 free(addrmask.buf);
1397 1446 (void) t_snddis(new_fd, (struct t_call *)0);
1398 1447 (void) t_free((char *)call, T_CALL);
1399 1448 (void) t_close(new_fd);
1400 1449 goto do_next_conn;
1401 1450 }
1402 1451
1403 1452 free(addrmask.buf);
1404 1453 (void) t_free((char *)call, T_CALL);
1405 1454
1406 1455 /*
1407 1456 * Poll on the new descriptor so that we get disconnect
1408 1457 * and orderly release indications.
1409 1458 */
1410 1459 num_conns++;
1411 1460 add_to_poll_list(new_fd, nconf);
1412 1461
1413 1462 /* Reset nconf in case it has been moved. */
1414 1463 nconf = &conn_polled[conn_index].nc;
1415 1464 do_next_conn:;
1416 1465 }
1417 1466 }
1418 1467
1419 1468 static int
1420 1469 do_poll_cots_action(int fd, int conn_index)
1421 1470 {
1422 1471 char buf[256];
1423 1472 int event;
1424 1473 int i1;
1425 1474 int flags;
1426 1475 struct conn_entry *connent = &conn_polled[conn_index];
1427 1476 struct netconfig *nconf = &(connent->nc);
1428 1477 const char *errorstr;
1429 1478
1430 1479 while (event = t_look(fd)) {
1431 1480 switch (event) {
1432 1481 case T_LISTEN:
1433 1482 #ifdef DEBUG
1434 1483 printf("do_poll_cots_action(%s,%d): T_LISTEN event\n", nconf->nc_proto, fd);
1435 1484 #endif
1436 1485 cots_listen_event(fd, conn_index);
1437 1486 break;
1438 1487
1439 1488 case T_DATA:
1440 1489 #ifdef DEBUG
1441 1490 printf("do_poll_cots_action(%d,%s): T_DATA event\n", fd, nconf->nc_proto);
1442 1491 #endif
1443 1492 /*
1444 1493 * Receive a private notification from CONS rpcmod.
1445 1494 */
1446 1495 i1 = t_rcv(fd, buf, sizeof (buf), &flags);
1447 1496 if (i1 == -1) {
1448 1497 syslog(LOG_ERR, "t_rcv failed");
1449 1498 break;
1450 1499 }
1451 1500 if (i1 < sizeof (int))
1452 1501 break;
1453 1502 i1 = BE32_TO_U32(buf);
1454 1503 if (i1 == 1 || i1 == 2) {
1455 1504 /*
1456 1505 * This connection has been idle for too long,
1457 1506 * so release it as politely as we can. If we
1458 1507 * have already initiated an orderly release
1459 1508 * and we get notified that the stream is
1460 1509 * still idle, pull the plug. This prevents
1461 1510 * hung connections from continuing to consume
1462 1511 * resources.
1463 1512 */
1464 1513 #ifdef DEBUG
1465 1514 printf("do_poll_cots_action(%s,%d): ", nconf->nc_proto, fd);
1466 1515 printf("initiating orderly release of idle connection\n");
1467 1516 #endif
1468 1517 if (nconf->nc_semantics == NC_TPI_COTS ||
1469 1518 connent->closing != 0) {
1470 1519 (void) t_snddis(fd, (struct t_call *)0);
1471 1520 goto fdclose;
1472 1521 }
1473 1522 /*
1474 1523 * For NC_TPI_COTS_ORD, the stream is closed
1475 1524 * and removed from the poll list when the
1476 1525 * T_ORDREL is received from the provider. We
1477 1526 * don't wait for it here because it may take
1478 1527 * a while for the transport to shut down.
1479 1528 */
1480 1529 if (t_sndrel(fd) == -1) {
1481 1530 syslog(LOG_ERR,
1482 1531 "unable to send orderly release %m");
1483 1532 }
1484 1533 connent->closing = 1;
1485 1534 } else
1486 1535 syslog(LOG_ERR,
1487 1536 "unexpected event from CONS rpcmod %d", i1);
1488 1537 break;
1489 1538
1490 1539 case T_ORDREL:
1491 1540 #ifdef DEBUG
1492 1541 printf("do_poll_cots_action(%s,%d): T_ORDREL event\n", nconf->nc_proto, fd);
1493 1542 #endif
1494 1543 /* Perform an orderly release. */
1495 1544 if (t_rcvrel(fd) == 0) {
1496 1545 /* T_ORDREL on listen fd's should be ignored */
1497 1546 if (!is_listen_fd_index(conn_index)) {
1498 1547 (void) t_sndrel(fd);
1499 1548 goto fdclose;
1500 1549 }
1501 1550 break;
1502 1551
1503 1552 } else if (t_errno == TLOOK) {
1504 1553 break;
1505 1554 } else {
1506 1555 nfslib_log_tli_error("t_rcvrel", fd, nconf);
1507 1556
1508 1557 /*
1509 1558 * check to make sure we do not close
1510 1559 * listen fd
1511 1560 */
1512 1561 if (is_listen_fd_index(conn_index))
1513 1562 break;
1514 1563 else
1515 1564 goto fdclose;
1516 1565 }
1517 1566
1518 1567 case T_DISCONNECT:
1519 1568 #ifdef DEBUG
1520 1569 printf("do_poll_cots_action(%s,%d): T_DISCONNECT event\n", nconf->nc_proto, fd);
1521 1570 #endif
1522 1571 if (t_rcvdis(fd, (struct t_discon *)NULL) == -1)
1523 1572 nfslib_log_tli_error("t_rcvdis", fd, nconf);
1524 1573
1525 1574 /*
1526 1575 * T_DISCONNECT on listen fd's should be ignored.
1527 1576 */
1528 1577 if (is_listen_fd_index(conn_index))
1529 1578 break;
1530 1579 else
1531 1580 goto fdclose;
1532 1581
1533 1582 case T_ERROR:
1534 1583 default:
1535 1584 if (event == T_ERROR || t_errno == TSYSERR) {
1536 1585 if ((errorstr = strerror(errno)) == NULL) {
1537 1586 (void) sprintf(buf,
1538 1587 "Unknown error num %d", errno);
1539 1588 errorstr = (const char *) buf;
1540 1589 }
1541 1590 } else if (event == -1)
1542 1591 errorstr = t_strerror(t_errno);
1543 1592 else
1544 1593 errorstr = "";
1545 1594 syslog(LOG_ERR,
1546 1595 "unexpected TLI event (0x%x) on "
1547 1596 "connection-oriented transport(%s,%d):%s",
1548 1597 event, nconf->nc_proto, fd, errorstr);
1549 1598 fdclose:
1550 1599 num_conns--;
1551 1600 remove_from_poll_list(fd);
1552 1601 (void) t_close(fd);
1553 1602 return (0);
1554 1603 }
1555 1604 }
1556 1605
1557 1606 return (0);
1558 1607 }
1559 1608
1560 1609 static char *
1561 1610 serv_name_to_port_name(char *name)
1562 1611 {
1563 1612 /*
1564 1613 * Map service names (used primarily in logging) to
1565 1614 * RPC port names (used by netdir_*() routines).
1566 1615 */
1567 1616 if (strcmp(name, "NFS") == 0) {
1568 1617 return ("nfs");
1569 1618 } else if (strcmp(name, "NLM") == 0) {
|
↓ open down ↓ |
944 lines elided |
↑ open up ↑ |
1570 1619 return ("lockd");
1571 1620 } else if (strcmp(name, "NFS4_CALLBACK") == 0) {
1572 1621 return ("nfs4_callback");
1573 1622 }
1574 1623
1575 1624 return ("unrecognized");
1576 1625 }
1577 1626
1578 1627 static int
1579 1628 bind_to_provider(char *provider, char *serv, struct netbuf **addr,
1580 - struct netconfig **retnconf)
1629 + struct netconfig **retnconf, int sndbufsz, int rcvbufsz)
1581 1630 {
1582 1631 struct netconfig *nconf;
1583 1632 NCONF_HANDLE *nc;
1584 1633 struct nd_hostserv hs;
1585 1634
1586 1635 hs.h_host = HOST_SELF;
1587 1636 hs.h_serv = serv_name_to_port_name(serv);
1588 1637
1589 1638 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1590 1639 syslog(LOG_ERR, "setnetconfig failed: %m");
1591 1640 return (-1);
1592 1641 }
1593 1642 while (nconf = getnetconfig(nc)) {
1594 1643 if (OK_TPI_TYPE(nconf) &&
1595 1644 strcmp(nconf->nc_device, provider) == 0) {
1596 1645 *retnconf = nconf;
1597 1646 return (nfslib_bindit(nconf, addr, &hs,
1598 - listen_backlog));
1647 + listen_backlog, sndbufsz, rcvbufsz));
1599 1648 }
1600 1649 }
1601 1650 (void) endnetconfig(nc);
1602 1651
1603 1652 syslog(LOG_ERR, "couldn't find netconfig entry for provider %s",
1604 1653 provider);
1605 1654 return (-1);
1606 1655 }
1607 1656
1608 1657 static int
1609 1658 bind_to_proto(NETSELDECL(proto), char *serv, struct netbuf **addr,
1610 - struct netconfig **retnconf)
1659 + struct netconfig **retnconf, int sndbufsz, int rcvbufsz)
1611 1660 {
1612 1661 struct netconfig *nconf;
1613 1662 NCONF_HANDLE *nc = NULL;
1614 1663 struct nd_hostserv hs;
1615 1664
1616 1665 hs.h_host = HOST_SELF;
1617 1666 hs.h_serv = serv_name_to_port_name(serv);
1618 1667
1619 1668 if ((nc = setnetconfig()) == (NCONF_HANDLE *)NULL) {
1620 1669 syslog(LOG_ERR, "setnetconfig failed: %m");
1621 1670 return (-1);
1622 1671 }
1623 1672 while (nconf = getnetconfig(nc)) {
1624 1673 if (OK_TPI_TYPE(nconf) && NETSELEQ(nconf->nc_proto, proto)) {
1625 1674 *retnconf = nconf;
1626 1675 return (nfslib_bindit(nconf, addr, &hs,
1627 - listen_backlog));
1676 + listen_backlog, sndbufsz, rcvbufsz));
1628 1677 }
1629 1678 }
1630 1679 (void) endnetconfig(nc);
1631 1680
1632 1681 syslog(LOG_ERR, "couldn't find netconfig entry for protocol %s",
1633 1682 proto);
1634 1683 return (-1);
1635 1684 }
1636 1685
1637 1686 #include <netinet/in.h>
1638 1687
1639 1688 /*
1640 1689 * Create an address mask appropriate for the transport.
1641 1690 * The mask is used to obtain the host-specific part of
1642 1691 * a network address when comparing addresses.
1643 1692 * For an internet address the host-specific part is just
1644 1693 * the 32 bit IP address and this part of the mask is set
1645 1694 * to all-ones. The port number part of the mask is zeroes.
1646 1695 */
1647 1696 static int
1648 1697 set_addrmask(fd, nconf, mask)
1649 1698 struct netconfig *nconf;
1650 1699 struct netbuf *mask;
1651 1700 {
1652 1701 struct t_info info;
1653 1702
1654 1703 /*
1655 1704 * Find the size of the address we need to mask.
1656 1705 */
1657 1706 if (t_getinfo(fd, &info) < 0) {
1658 1707 t_error("t_getinfo");
1659 1708 return (-1);
1660 1709 }
1661 1710 mask->len = mask->maxlen = info.addr;
1662 1711 if (info.addr <= 0) {
1663 1712 syslog(LOG_ERR, "set_addrmask: address size: %ld",
1664 1713 info.addr);
1665 1714 return (-1);
1666 1715 }
1667 1716
1668 1717 mask->buf = (char *)malloc(mask->len);
1669 1718 if (mask->buf == NULL) {
1670 1719 syslog(LOG_ERR, "set_addrmask: no memory");
1671 1720 return (-1);
1672 1721 }
1673 1722 (void) memset(mask->buf, 0, mask->len); /* reset all mask bits */
1674 1723
1675 1724 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
1676 1725 /*
1677 1726 * Set the mask so that the port is ignored.
1678 1727 */
1679 1728 /* LINTED pointer alignment */
1680 1729 ((struct sockaddr_in *)mask->buf)->sin_addr.s_addr =
1681 1730 (ulong_t)~0;
1682 1731 /* LINTED pointer alignment */
1683 1732 ((struct sockaddr_in *)mask->buf)->sin_family =
1684 1733 (ushort_t)~0;
1685 1734 } else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
1686 1735 /* LINTED pointer alignment */
1687 1736 (void) memset(&((struct sockaddr_in6 *)mask->buf)->sin6_addr,
1688 1737 (uchar_t)~0, sizeof (struct in6_addr));
1689 1738 /* LINTED pointer alignment */
1690 1739 ((struct sockaddr_in6 *)mask->buf)->sin6_family =
1691 1740 (ushort_t)~0;
1692 1741 } else {
1693 1742
1694 1743 /*
1695 1744 * Set all mask bits.
1696 1745 */
1697 1746 (void) memset(mask->buf, 0xFF, mask->len);
1698 1747 }
1699 1748 return (0);
1700 1749 }
1701 1750
1702 1751 /*
1703 1752 * For listen fd's index is always less than end_listen_fds.
1704 1753 * end_listen_fds is defined externally in the daemon that uses this library.
1705 1754 * It's value is equal to the number of open file descriptors after the
1706 1755 * last listen end point was opened but before any connection was accepted.
1707 1756 */
1708 1757 static int
1709 1758 is_listen_fd_index(int index)
1710 1759 {
1711 1760 return (index < end_listen_fds);
1712 1761 }
|
↓ open down ↓ |
75 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX