1/* 2 * Copyright (c) 1999-2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Copyright (c) 1989, 1993, 1994 25 * The Regents of the University of California. All rights reserved. 26 * 27 * This code is derived from software contributed to Berkeley by 28 * Rick Macklem at The University of Guelph. 29 * 30 * Redistribution and use in source and binary forms, with or without 31 * modification, are permitted provided that the following conditions 32 * are met: 33 * 1. Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * 2. Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in the 37 * documentation and/or other materials provided with the distribution. 38 * 3. All advertising materials mentioning features or use of this software 39 * must display the following acknowledgement: 40 * This product includes software developed by the University of 41 * California, Berkeley and its contributors. 42 * 4. Neither the name of the University nor the names of its contributors 43 * may be used to endorse or promote products derived from this software 44 * without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 */ 58 59#include <sys/param.h> 60#include <sys/syslog.h> 61#include <sys/ioctl.h> 62#include <sys/stat.h> 63#include <sys/wait.h> 64#include <sys/uio.h> 65#include <sys/mount.h> 66#include <sys/socket.h> 67#include <sys/socketvar.h> 68 69#include <oncrpc/rpc.h> 70#include <oncrpc/pmap_clnt.h> 71#include <oncrpc/pmap_prot.h> 72 73#include <nfs/rpcv2.h> 74#include <nfs/nfsproto.h> 75#include <nfs/nfs.h> 76 77#include <err.h> 78#include <errno.h> 79#include <fcntl.h> 80#include <signal.h> 81#include <stdio.h> 82#include <stdlib.h> 83#include <strings.h> 84#include <unistd.h> 85#include <pthread.h> 86 87#include "common.h" 88 89int nfstcpsock, nfstcp6sock; 90int nfsudpsock, nfsudp6sock; 91 92/* 93 * The incredibly complex nfsd thread function 94 */ 95static void * 96nfsd_server_thread(__unused void *arg) 97{ 98 set_thread_sigmask(); 99 if (nfssvc(NFSSVC_NFSD, NULL) < 0) 100 log(LOG_ERR, "nfssvc: %s (%d)", strerror(errno), errno); 101 DEBUG(1, "nfsd thread exiting."); 102 return (NULL); 103} 104 105void * 106nfsd_accept_thread(__unused void *arg) 107{ 108 struct nfsd_args nfsdargs; 109 fd_set ready, sockbits; 110 struct sockaddr_storage peer; 111 struct sockaddr *sa = (struct sockaddr *)&peer; 112 socklen_t len; 113 int maxlistensock = -1; 114 int newsock, on = 1; 115 struct timeval tv; 116 char hostbuf[NI_MAXHOST]; 117 118 set_thread_sigmask(); 119 120 FD_ZERO(&sockbits); 121 if (config.tcp) { 122 if (nfstcpsock != -1) 123 FD_SET(nfstcpsock, &sockbits); 124 if (nfstcp6sock != -1) 125 FD_SET(nfstcp6sock, &sockbits); 126 maxlistensock = MAX(nfstcpsock, nfstcp6sock); 127 } 128 129 /* 130 * Loop until terminated. 131 * If accepting connections, pass new sockets into the kernel. 132 * Otherwise, just sleep waiting for a signal. 133 */ 134 while (!gotterm) { 135 tv.tv_sec = 3600; 136 tv.tv_usec = 0; 137 ready = sockbits; 138 if (select(maxlistensock+1, ((maxlistensock < 0) ? NULL : &ready), NULL, NULL, &tv) < 0) { 139 if (errno == EINTR) 140 continue; 141 log(LOG_ERR, "select failed: %s (%d)", strerror(errno), errno); 142 break; 143 } 144 if (!config.tcp || (maxlistensock < 0)) 145 continue; 146 if ((nfstcpsock >= 0) && FD_ISSET(nfstcpsock, &ready)) { 147 len = sizeof(peer); 148 if ((newsock = accept(nfstcpsock, (struct sockaddr *)&peer, &len)) < 0) { 149 log(LOG_WARNING, "accept failed: %s (%d)", strerror(errno), errno); 150 continue; 151 } 152 if (config.verbose >= 3) { 153 hostbuf[0] = '\0'; 154 getnameinfo(sa, sa->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, 0); 155 DEBUG(1, "NFS IPv4 socket accepted from %s", hostbuf); 156 } 157 memset(&((struct sockaddr_in*)&peer)->sin_zero[0], 0, sizeof(((struct sockaddr_in*)&peer)->sin_zero[0])); 158 if (setsockopt(newsock, SOL_SOCKET, 159 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 160 log(LOG_NOTICE, "setsockopt SO_KEEPALIVE: %s (%d)", strerror(errno), errno); 161 nfsdargs.sock = newsock; 162 nfsdargs.name = (caddr_t)&peer; 163 nfsdargs.namelen = len; 164 nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 165 close(newsock); 166 } 167 if ((nfstcp6sock >= 0) && FD_ISSET(nfstcp6sock, &ready)) { 168 len = sizeof(peer); 169 if ((newsock = accept(nfstcp6sock, (struct sockaddr *)&peer, &len)) < 0) { 170 log(LOG_WARNING, "accept failed: %s (%d)", strerror(errno), errno); 171 continue; 172 } 173 if (config.verbose >= 3) { 174 hostbuf[0] = '\0'; 175 getnameinfo(sa, sa->sa_len, hostbuf, sizeof(hostbuf), NULL, 0, 0); 176 DEBUG(1, "NFS IPv6 socket accepted from %s", hostbuf); 177 } 178 if (setsockopt(newsock, SOL_SOCKET, 179 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 180 log(LOG_NOTICE, "setsockopt SO_KEEPALIVE: %s (%d)", strerror(errno), errno); 181 nfsdargs.sock = newsock; 182 nfsdargs.name = (caddr_t)&peer; 183 nfsdargs.namelen = len; 184 nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 185 close(newsock); 186 } 187 } 188 189 return (NULL); 190} 191 192/* 193 * start a given number of NFS server threads 194 */ 195void 196nfsd_start_server_threads(int count) 197{ 198 int threadcnt, i, rv; 199 pthread_t thd; 200 201 /* set up the server threads */ 202 threadcnt = 0; 203 for (i=0; i < count; i++) { 204 rv = pthread_create(&thd, &pattr, nfsd_server_thread, NULL); 205 if (rv) { 206 log(LOG_ERR, "pthread_create: %s (%d)", strerror(rv), rv); 207 continue; 208 } 209 threadcnt++; 210 } 211 DEBUG(1, "Started %d of %d new nfsd threads", threadcnt, count); 212 /* if no threads started exit */ 213 if (!threadcnt) 214 log(LOG_ERR, "unable to start any nfsd threads"); 215 if (threadcnt != count) 216 log(LOG_WARNING, "only able to create %d of %d nfsd threads", threadcnt, count); 217} 218 219/* 220 * NFS server daemon mostly just a user context for nfssvc() 221 * 222 * 1 - set up server socket(s) 223 * 2 - create the nfsd server threads 224 * 3 - create the nfsd accept thread 225 * 226 * For connectionless protocols, just pass the socket into the kernel via. nfssvc(). 227 * For connection based sockets, the accept thread loops doing the accepts. 228 * When we get a new socket from accept, pass it into the kernel via. nfssvc(). 229 */ 230void 231nfsd(void) 232{ 233 struct nfsd_args nfsdargs; 234 struct sockaddr_storage saddr; 235 struct sockaddr_in *sin = (struct sockaddr_in*)&saddr; 236 struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&saddr; 237 int rv, on = 1; 238 pthread_t thd; 239 240 nfsudpsock = nfsudp6sock = -1; 241 nfstcpsock = nfstcp6sock = -1; 242 243 /* If we are serving UDP, set up the NFS/UDP sockets. */ 244 if (config.udp) { 245 246 /* IPv4 */ 247 if ((nfsudpsock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 248 log(LOG_WARNING, "can't create NFS/UDP IPv4 socket"); 249 if (nfsudpsock >= 0) { 250 nfsudpport = config.port; 251 sin->sin_family = AF_INET; 252 sin->sin_addr.s_addr = INADDR_ANY; 253 sin->sin_port = htons(config.port); 254 sin->sin_len = sizeof(*sin); 255 if (bind(nfsudpsock, (struct sockaddr *)sin, sizeof(*sin)) < 0) { 256 /* socket may still be lingering from previous incarnation */ 257 /* wait a few seconds and try again */ 258 sleep(6); 259 if (bind(nfsudpsock, (struct sockaddr *)sin, sizeof(*sin)) < 0) { 260 log(LOG_WARNING, "can't bind NFS/UDP IPv4 addr"); 261 close(nfsudpsock); 262 nfsudpsock = -1; 263 nfsudpport = 0; 264 } 265 } 266 } 267 if (nfsudpsock >= 0) { 268 nfsdargs.sock = nfsudpsock; 269 nfsdargs.name = NULL; 270 nfsdargs.namelen = 0; 271 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { 272 log(LOG_WARNING, "can't add NFS/UDP IPv4 socket"); 273 close(nfsudpsock); 274 nfsudpsock = -1; 275 nfsudpport = 0; 276 } else { 277 close(nfsudpsock); 278 } 279 } 280 281 /* IPv6 */ 282 if ((nfsudp6sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 283 log(LOG_WARNING, "can't create NFS/UDP IPv6 socket"); 284 if (nfsudp6sock >= 0) { 285 nfsudp6port = config.port; 286 if (setsockopt(nfsudp6sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) 287 log(LOG_WARNING, "setsockopt NFS/UDP IPV6_V6ONLY: %s (%d)", strerror(errno), errno); 288 sin6->sin6_family = AF_INET6; 289 sin6->sin6_addr = in6addr_any; 290 sin6->sin6_port = htons(config.port); 291 sin6->sin6_len = sizeof(*sin6); 292 if (bind(nfsudp6sock, (struct sockaddr *)sin6, sizeof(*sin6)) < 0) { 293 /* socket may still be lingering from previous incarnation */ 294 /* wait a few seconds and try again */ 295 sleep(6); 296 if (bind(nfsudp6sock, (struct sockaddr *)sin6, sizeof(*sin6)) < 0) { 297 log(LOG_WARNING, "can't bind NFS/UDP IPv6 addr"); 298 close(nfsudp6sock); 299 nfsudp6sock = -1; 300 nfsudp6port = 0; 301 } 302 } 303 } 304 if (nfsudp6sock >= 0) { 305 nfsdargs.sock = nfsudp6sock; 306 nfsdargs.name = NULL; 307 nfsdargs.namelen = 0; 308 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { 309 log(LOG_WARNING, "can't add NFS/UDP IPv6 socket"); 310 close(nfsudp6sock); 311 nfsudp6sock = -1; 312 nfsudp6port = 0; 313 } else { 314 close(nfsudp6sock); 315 } 316 } 317 318 } 319 320 /* If we are serving TCP, set up the NFS/TCP socket. */ 321 if (config.tcp) { 322 323 /* IPv4 */ 324 if ((nfstcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 325 log(LOG_WARNING, "can't create NFS/TCP IPv4 socket"); 326 if (nfstcpsock >= 0) { 327 nfstcpport = config.port; 328 if (setsockopt(nfstcpsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) 329 log(LOG_WARNING, "setsockopt NFS/TCP IPv4 SO_REUSEADDR: %s (%d)", strerror(errno), errno); 330 sin->sin_family = AF_INET; 331 sin->sin_addr.s_addr = INADDR_ANY; 332 sin->sin_port = htons(config.port); 333 sin->sin_len = sizeof(*sin); 334 if (bind(nfstcpsock, (struct sockaddr *)sin, sizeof(*sin)) < 0) { 335 log(LOG_WARNING, "can't bind NFS/TCP IPv4 addr"); 336 close(nfstcpsock); 337 nfstcpsock = -1; 338 nfstcpport = 0; 339 } 340 } 341 if ((nfstcpsock >= 0) && (listen(nfstcpsock, 128) < 0)) { 342 log(LOG_WARNING, "NFS IPv4 listen failed"); 343 close(nfstcpsock); 344 nfstcpsock = -1; 345 nfstcpport = 0; 346 } 347 348 /* IPv6 */ 349 if ((nfstcp6sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0) 350 log(LOG_WARNING, "can't create NFS/TCP IPv6 socket"); 351 if (nfstcp6sock >= 0) { 352 nfstcp6port = config.port; 353 if (setsockopt(nfstcp6sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) 354 log(LOG_WARNING, "setsockopt NFS/TCP IPv6 SO_REUSEADDR: %s (%d)", strerror(errno), errno); 355 if (setsockopt(nfstcp6sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) 356 log(LOG_WARNING, "setsockopt NFS/TCP IPV6_V6ONLY: %s (%d)", strerror(errno), errno); 357 sin6->sin6_family = AF_INET6; 358 sin6->sin6_addr = in6addr_any; 359 sin6->sin6_port = htons(config.port); 360 sin6->sin6_len = sizeof(*sin6); 361 if (bind(nfstcp6sock, (struct sockaddr *)sin6, sizeof(*sin6)) < 0) { 362 log(LOG_WARNING, "can't bind NFS/TCP IPv6 addr"); 363 close(nfstcp6sock); 364 nfstcp6sock = -1; 365 nfstcp6port = 0; 366 } 367 } 368 if ((nfstcp6sock >= 0) && (listen(nfstcp6sock, 128) < 0)) { 369 log(LOG_WARNING, "NFS IPv6 listen failed"); 370 close(nfstcp6sock); 371 nfstcp6sock = -1; 372 nfstcp6port = 0; 373 } 374 375 } 376 377 if ((nfsudp6sock < 0) && (nfstcp6sock < 0)) 378 log(LOG_WARNING, "Can't create NFS IPv6 sockets"); 379 if ((nfsudpsock < 0) && (nfstcpsock < 0)) 380 log(LOG_WARNING, "Can't create NFS IPv4 sockets"); 381 if ((nfsudp6sock < 0) && (nfstcp6sock < 0) && 382 (nfsudpsock < 0) && (nfstcpsock < 0)) { 383 log(LOG_ERR, "Can't create any NFS sockets!"); 384 exit(1); 385 } 386 387 /* start up all the server threads */ 388 sysctl_set("vfs.generic.nfs.server.nfsd_thread_max", config.nfsd_threads); 389 nfsd_start_server_threads(config.nfsd_threads); 390 391 /* set up the accept thread */ 392 rv = pthread_create(&thd, &pattr, nfsd_accept_thread, NULL); 393 if (rv) { 394 log(LOG_ERR, "pthread_create: %s (%d)", strerror(rv), rv); 395 exit(1); 396 } 397} 398 399