int makesock(char* host, char* port,char server) { int sfd = 0; struct addrinfo hints; struct addrinfo *addr; memset(&hints,0,sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; if (server == 1) { hints.ai_flags = hints.ai_flags | AI_PASSIVE; } int gai = getaddrinfo(host,port,&hints,&addr); if (gai != 0) { printf("getaddrinfo error\n"); printf(gai_strerror(gai)); } /* borrow socket check from libsocket */ struct addrinfo *check; for (check = addr; check != NULL; check = check->ai_next) { sfd = socket(check->ai_family,check->ai_socktype,check->ai_protocol); if (sfd < 0) continue; if (server == 1) { if (-1 != bind(sfd,check->ai_addr,check->ai_addrlen)) { printf("Listening\n"); setupsock(sfd); break; } } else if (server == 0) { if (-1 != connect(sfd,check->ai_addr,check->ai_addrlen)) { printf("Connected"); setupsock(sfd); break; } } } if (addr != NULL) freeaddrinfo(addr); return(sfd); }
/* * Nfs server daemon mostly just a user context for nfssvc() * * 1 - do file descriptor and signal cleanup * 2 - create the nfsd thread(s) * 3 - create server socket(s) * 4 - register socket with portmap * * For connectionless protocols, just pass the socket into the kernel via * nfssvc(). * For connection based sockets, loop doing accepts. When you get a new * socket from accept, pass the msgsock into the kernel via nfssvc(). * The arguments are: * -r - reregister with portmapper * -t - support only tcp nfs clients * -u - support only udp nfs clients * -n num how many threads to create. * -4 - use only ipv4 * -6 - use only ipv6 */ int main(int argc, char *argv[]) { struct conf cfg[4]; struct pollfd set[__arraycount(cfg)]; int ch, connect_type_cnt; size_t i, nfsdcnt; int reregister; int tcpflag, udpflag; int ip6flag, ip4flag; int s, compat; int parent_fd = -1; pthread_t *workers; #define DEFNFSDCNT 4 nfsdcnt = DEFNFSDCNT; compat = reregister = 0; tcpflag = udpflag = 1; ip6flag = ip4flag = 1; #define GETOPT "46dn:rtu" #define USAGE "[-46drtu] [-n num_servers]" while ((ch = getopt(argc, argv, GETOPT)) != -1) { switch (ch) { case '6': ip6flag = 1; ip4flag = 0; s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (s < 0 && (errno == EPROTONOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT)) ip6flag = 0; else close(s); break; case '4': ip6flag = 0; ip4flag = 1; s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s < 0 && (errno == EPROTONOSUPPORT || errno == EPFNOSUPPORT || errno == EAFNOSUPPORT)) ip4flag = 0; else close(s); break; case 'd': debug++; break; case 'n': nfsdcnt = atoi(optarg); if (nfsdcnt < 1) { warnx("nfsd count %zu; reset to %d", nfsdcnt, DEFNFSDCNT); nfsdcnt = DEFNFSDCNT; } break; case 'r': reregister = 1; break; case 't': compat |= 2; tcpflag = 1; udpflag = 0; break; case 'u': compat |= 1; tcpflag = 0; udpflag = 1; break; default: case '?': usage(); } } argv += optind; argc -= optind; if (compat == 3) { warnx("Old -tu options detected; enabling both udp and tcp."); warnx("This is the default behavior now and you can remove"); warnx("all options."); tcpflag = udpflag = 1; if (ip6flag == 1 && ip4flag == 0) ip4flag = 1; } if (debug == 0) { parent_fd = daemon2_fork(); if (parent_fd == -1) logit(LOG_ERR, "daemon2_fork failed"); openlog("nfsd", LOG_PID, LOG_DAEMON); } memset(cfg, 0, sizeof(cfg)); for (i = 0; i < __arraycount(cfg); i++) { if (ip4flag == 0 && cfg_family[i] == PF_INET) continue; if (ip6flag == 0 && cfg_family[i] == PF_INET6) continue; if (tcpflag == 0 && cfg_protocol[i] == IPPROTO_TCP) continue; if (udpflag == 0 && cfg_protocol[i] == IPPROTO_UDP) continue; tryconf(&cfg[i], i, reregister); } workers = calloc(nfsdcnt, sizeof(*workers)); if (workers == NULL) { logit(LOG_ERR, "thread alloc %s", strerror(errno)); exit(1); } for (i = 0; i < nfsdcnt; i++) { int error; error = pthread_create(&workers[i], NULL, worker, NULL); if (error) { errno = error; logit(LOG_ERR, "pthread_create: %s", strerror(errno)); exit(1); } } connect_type_cnt = 0; for (i = 0; i < __arraycount(cfg); i++) { set[i].fd = -1; set[i].events = POLLIN; set[i].revents = 0; if (cfg[i].nc == NULL) continue; setupsock(&cfg[i], &set[i], i); if (set[i].fd != -1) connect_type_cnt++; } pthread_setname_np(pthread_self(), "master", NULL); if (debug == 0) { daemon2_detach(parent_fd, 0, 0); (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGSYS, nonfs); } if (connect_type_cnt == 0) { for (i = 0; i < nfsdcnt; i++) pthread_join(workers[i], NULL); exit(0); } /* * Loop forever accepting connections and passing the sockets * into the kernel for the mounts. */ for (;;) { if (poll(set, __arraycount(set), INFTIM) == -1) { logit(LOG_ERR, "poll failed: %s", strerror(errno)); exit(1); } for (i = 0; i < __arraycount(set); i++) { struct nfsd_args nfsdargs; struct sockaddr_storage ss; socklen_t len; int msgsock; int on = 1; if ((set[i].revents & POLLIN) == 0) continue; len = sizeof(ss); if ((msgsock = accept(set[i].fd, (struct sockaddr *)&ss, &len)) == -1) { int serrno = errno; logit(LOG_ERR, "accept failed: %s", strerror(errno)); if (serrno == EINTR || serrno == ECONNABORTED) continue; exit(1); } if (setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) logit(LOG_ERR, "setsockopt SO_KEEPALIVE: %s", strerror(errno)); nfsdargs.sock = msgsock; nfsdargs.name = (void *)&ss; nfsdargs.namelen = len; nfssvc(NFSSVC_ADDSOCK, &nfsdargs); (void)close(msgsock); } } }