/* * Get a UDP socket, bind it, figure out the port, * and advertise the port as program "prog". * * XXX - it would be nice if you could advertise ascii strings. */ int udp_server(u_long prog, int rdwr) { int sock; struct sockaddr_in s; if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("socket"); exit(1); } sock_optimize(sock, rdwr); bzero((void*)&s, sizeof(s)); s.sin_family = AF_INET; #ifdef NO_PORTMAPPER s.sin_port = htons(prog); #endif if (bind(sock, (struct sockaddr*)&s, sizeof(s)) < 0) { perror("bind"); exit(2); } #ifdef PORTMAP (void)pmap_unset(prog, (u_long)1); if (!pmap_set(prog, (u_long)1, (u_long)IPPROTO_UDP, (unsigned short)sockport(sock))) { perror("pmap_set"); exit(5); } #endif return (sock); }
/* Add a service program to the callout list. The dispatch routine will be called when a rpc request for this program number comes in. */ bool_t svc_register (SVCXPRT * xprt, rpcprog_t prog, rpcvers_t vers, void (*dispatch) (struct svc_req *, SVCXPRT *), rpcproc_t protocol) { struct svc_callout *prev; register struct svc_callout *s; if ((s = svc_find (prog, vers, &prev)) != NULL_SVC) { if (s->sc_dispatch == dispatch) goto pmap_it; /* he is registering another xptr */ return FALSE; } s = (struct svc_callout *) mem_alloc (sizeof (struct svc_callout)); if (s == (struct svc_callout *) 0) return FALSE; s->sc_prog = prog; s->sc_vers = vers; s->sc_dispatch = dispatch; s->sc_next = svc_head; svc_head = s; pmap_it: /* now register the information with the local binder service */ if (protocol) return pmap_set (prog, vers, protocol, xprt->xp_port); return TRUE; }
/* * Add a service program to the callout list. * The dispatch routine will be called when a rpc request for this * program number comes in. */ bool_t svc_register(SVCXPRT *xprt, u_long prog, u_long vers, void (*dispatch)(), int protocol) { struct svc_callout *prev; struct svc_callout *s; if ((s = svc_find(prog, vers, &prev)) != NULL) { if (s->sc_dispatch == dispatch) goto pmap_it; /* he is registering another xptr */ return (FALSE); } s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); if (s == NULL) { return (FALSE); } s->sc_prog = prog; s->sc_vers = vers; s->sc_dispatch = dispatch; s->sc_next = svc_head; svc_head = s; pmap_it: /* now register the information with the local binder service */ if (protocol) { return (pmap_set(prog, vers, protocol, xprt->xp_port)); } return (TRUE); }
int main(int argn, char *argc[]) { //Program parameters : argc[1] : HostName or Host IP // argc[2] : Server Program Number // other arguments depend on test case //run_mode can switch into stand alone program or program launch by shell script //1 : stand alone, debug mode, more screen information //0 : launch by shell script as test case, only one printf -> result status int run_mode = 0; int test_status = 1; //Default test result set to FAILED int progNum = 5000000; //This test doesn't care with progNum, just local test of reg/unreg... int port = 600; SVCXPRT *transp = NULL; //Initialization pmap_unset(progNum, VERSNUM); if (run_mode) { printf("Before creation\n"); } transp = svcudp_create(RPC_ANYSOCK); pmap_set(progNum, VERSNUM, IPPROTO_UDP, port); test_status = !pmap_unset(progNum, VERSNUM); //This last printf gives the result status to the tests suite //normally should be 0: test has passed or 1: test has failed printf("%d\n", test_status); return test_status; }
/* * Add a service program to the callout list. * The dispatch routine will be called when a rpc request for this * program number comes in. */ bool svc_register(SVCXPRT *xprt, u_long prog, u_long vers, void (*dispatch) (struct svc_req *req, SVCXPRT *xprt), int protocol) { struct svc_callout *prev; struct svc_callout *s; assert(xprt != NULL); assert(dispatch != NULL); s = svc_find((rpcprog_t) prog, (rpcvers_t) vers, &prev, NULL); if (s) { if (s->rec.sc_dispatch == dispatch) goto pmap_it; /* he is registering another xprt */ return (false); } s = mem_alloc(sizeof(struct svc_callout)); s->rec.sc_prog = (rpcprog_t) prog; s->rec.sc_vers = (rpcvers_t) vers; s->rec.sc_dispatch = dispatch; s->sc_next = svc_head; svc_head = s; pmap_it: /* now register the information with the local binder service */ if (protocol) return (pmap_set(prog, vers, protocol, xprt->xp_port)); return (true); }
static PyObject * portmap_set(PyObject *self, PyObject *args) { unsigned long program, version; int protocol; unsigned short port; if (!PyArg_ParseTuple(args, "kkiH:set", &program, &version, &protocol, &port)) return NULL; // Tai: removed the unset here so we can bind both TCP and UDP pmap_set(program, version, protocol, port); Py_INCREF(Py_None); return Py_None; }
static void register_port (int portnum, int abort_if_fail) { #ifdef HAVE_PMAP_SET /* Register our service with the portmapper */ /* protocol: pmap_set (prognum, versnum, protocol, portp) */ if (pmap_set (RPC_PROGNUM, RPC_PROGVER, IPPROTO_TCP, portnum)) signal (SIGINT, signal_int_handler); else { fprintf (stderr, "Cannot register service with portmapper\n"); if (abort_if_fail) exit (1); } #else if (abort_if_fail) { fprintf (stderr, "This system lacks port registration, try using the -p\n" "flag to force installation at a given port"); } #endif }
/************************************************************************ * * * This routine is used to register a specific function which will be * * called when there is a message. * * User function to be called can be NULL, indicating unregistering * * message, or user-func address, which takes a form of * * func(u_long proc_id, where proc_id is ID number. * * Ipgmsg *msg) where msg is a message. * * * * Return program number for success and 0 for failure. * * * * In RPC term, SERVER registers/unregisters program and version number * * */ u_long ipgwin_register_msg_receive( u_long prognum, /* program ID */ u_long versnum, /* program version */ void (*userfunc)(u_long, Ipgmsg*)) { Svcmsg *current, *prev; /* ptrs used for message item */ Svcmsg *newitem; /* new created item */ SVCXPRT *transp; /* transport info */ int protocol; /* protocol */ /* Check if the msgid has been registered or not. If the message */ /* has been registered, only change the user function. If the user */ /* function is NULL, delete the message item from the list. If the */ /* message has not been registered, add the new message item at the */ /* first of the list. */ for (current=prev=svchead; current; prev=current, current=current->next) { if ((current->prognum == prognum) && (current->versnum == versnum)) /* Found */ { svc_unregister(current->prognum, current->versnum); svc_destroy(current->xprt); if (current == prev) /* Only one item on the list */ svchead = NULL; else prev->next = current->next; (void)free((char *)current); if (userfunc == NULL) return(prognum) ; else break; } } /* Create an RPC with TCP socket */ if ((transp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { STDERR("Can't create RPC"); return(0); } /* Get the "transient" program number if prognum is zero */ if (prognum == 0) { /* The "transient" program number starts at 0x40000000 */ /* Get the unused number. */ prognum = 0x40000000; while (!pmap_set(prognum, versnum, IPPROTO_TCP, transp->xp_port)) prognum++; /* We don't need to register it at svc_register since pmap_set */ /* has done it. */ protocol = 0; } else { /* Erase the pormapper's table */ pmap_unset(prognum, versnum); protocol = IPPROTO_TCP; } /* Register the portmapper. */ /* Note that Sun suggests that the program number ranges from */ /* 0x20000000 to 0x5fffffff. However, our routine doesn't */ /* check for this limit. */ #ifdef SOLARIS if (!svc_register(transp, prognum, versnum, ipgwin_priv_msg_receive, protocol)) #elif LINUX if (!svc_register(transp, prognum, versnum, ipgwin_priv_msg_receive, protocol)) #else if (!svc_register(transp, prognum, versnum, (void (*)(DOTDOTDOT))ipgwin_priv_msg_receive, protocol)) #endif { STDERR("ipgwin_register_msg_receive:Can't register RPC"); svc_destroy(transp); return(0); } /* Create new item */ if ((newitem = (Svcmsg *)malloc(sizeof(Svcmsg))) == NULL) { PERROR("ipgwin_register_message_receive:malloc:Message is not registered"); return(0); } newitem->xprt = transp; newitem->prognum = prognum; newitem->versnum = versnum; newitem->msgfunc = userfunc; /* Add a new item at the front of the list */ newitem->next = svchead; svchead = newitem; return(prognum); }
/* * Create a TCP socket, bind it to a port, call 'listen' (we are a * server), and inform the portmap (rpcbind) service. Does _not_ create * an RPC SVCXPRT or do the xprt_register() or svc_fds() stuff. * * Arguments: * sockp Pointer to socket (file) descriptor. Set on and only on * success. * localIpAddr The IP address, in network byte order, of the * local interface to use. May be htonl(INADDR_ANY). * localPort The number of the local port on which the LDM server * should listen. * Returns: * 0 Success. * EACCES The process doesn't have appropriate privileges. * EADDRINUSE The local address is already in use. * EADDRNOTAVAIL The specified address is not available from the local * machine. * EAFNOSUPPORT The system doesn't support IP. * EMFILE No more file descriptors are available for this process. * ENFILE No more file descriptors are available for the system. * ENOBUFS Insufficient resources were available in the system. * ENOMEM Insufficient memory was available. * ENOSR There were insufficient STREAMS resources available. * EOPNOTSUPP The socket protocol does not support listen(). * EPROTONOSUPPORT The system doesn't support TCP. */ static int create_ldm_tcp_svc( int* sockp, in_addr_t localIpAddr, unsigned localPort) { int error = 0; /* success */ int sock; /* * Get a TCP socket. */ udebug("create_ldm_tcp_svc(): Getting TCP socket"); sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) { error = errno; serror("Couldn't get socket for server"); } else { unsigned short port = (unsigned short) localPort; struct sockaddr_in addr; socklen_t len = sizeof(addr); /* * Eliminate problem with EADDRINUSE for reserved socket. * We get this if an upstream data source hasn't tried to * write on the other end and we are in FIN_WAIT_2 */ udebug("create_ldm_tcp_svc(): Eliminating EADDRINUSE problem."); { int on = 1; (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); } (void) memset(&addr, 0, len); addr.sin_family = AF_INET; addr.sin_addr.s_addr = localIpAddr; addr.sin_port = (short) htons((short) port); /* * If privilege available, set it so we can bind to the port for LDM * services. Also needed for the pmap_set() call. */ udebug("create_ldm_tcp_svc(): Getting root privs"); rootpriv(); udebug("create_ldm_tcp_svc(): Binding socket"); if (bind(sock, (struct sockaddr *) &addr, len) < 0) { error = errno; serror("Couldn't obtain local address %s:%u for server", inet_ntoa(addr.sin_addr), (unsigned) port); if (error == EACCES) { error = 0; addr.sin_port = 0; /* let system assign port */ if (bind(sock, (struct sockaddr *) &addr, len) < 0) { error = errno; serror("Couldn't obtain local address %s:* for server", inet_ntoa(addr.sin_addr)); } } /* requested port is reserved */ } /* couldn't bind to requested port */ if (!error) { /* * Get the local address associated with the bound socket. */ udebug("create_ldm_tcp_svc(): Calling getsockname()"); if (getsockname(sock, (struct sockaddr *) &addr, &len) < 0) { error = errno; serror("Couldn't get local address of server's socket"); } else { port = (short) ntohs((short) addr.sin_port); unotice("Using local address %s:%u", inet_ntoa(addr.sin_addr), (unsigned) port); udebug("create_ldm_tcp_svc(): Calling listen()"); if (listen(sock, 32) != 0) { error = errno; serror("Couldn't listen() on server's socket"); } else { /* * Register with the portmapper if it's running. The * check to see if it's running is made because on a * FreeBSD 4.7-STABLE system, a pmap_set() call takes * one minute even if the portmapper isn't running. */ udebug("create_ldm_tcp_svc(): Checking portmapper"); if (local_portmapper_running()) { udebug("create_ldm_tcp_svc(): Registering"); if (pmap_set(LDMPROG, 6, IPPROTO_TCP, port) == 0) { uwarn("Can't register TCP service %lu on " "port %u", LDMPROG, (unsigned) port); uwarn("Downstream LDMs won't be able to " "connect via the RPC portmapper daemon " "(rpcbind(8), portmap(8), etc.)"); } else { portIsMapped = 1; (void) pmap_set(LDMPROG, 5, IPPROTO_TCP, port); } } /* a local portmapper is running */ /* * Done with the need for privilege. */ udebug("create_ldm_tcp_svc(): Releasing root privs"); unpriv(); *sockp = sock; } /* listen() success */ } /* getsockname() success */ } /* "sock" is bound to local address */ if (error) (void) close(sock); } /* "sock" is open */ return error; }
/* This one _can_ be used to begin grabbing messages (if they want to build their own main function) */ void flick_server_run() { int maxconn = -1; fd_set fds; flick_server_list *tmp = lst; struct sockaddr_in server; short port = -1; int sock; int len = sizeof(struct sockaddr_in); FLICK_BUFFER the_buf, return_buf; the_buf.real_buf_start = the_buf.buf_read = the_buf.buf_start = the_buf.buf_current = (void *)calloc(8192, 1); the_buf.real_buf_end = the_buf.buf_end = (((char *) the_buf.buf_start) + 8188); return_buf.real_buf_start = return_buf.real_buf_end = return_buf.buf_read = 0; return_buf.buf_start = return_buf.buf_current = (void *)calloc(8192, 1); return_buf.buf_end = ((char *) return_buf.buf_start) + 8188; if(!the_buf.buf_start || !return_buf.buf_start) { perror("Insufficient memory for server buffers"); exit(1); } FD_ZERO(&fds); /* Get the listening socket & port for this machine */ while(tmp) { /* Get a socket for this skeleton function */ sock = get_a_socket(); memset((char *)&server, 0, sizeof(server)); server.sin_family = AF_INET; /* Get a port for this skeleton function */ server.sin_port = 0; if (bind(sock, (struct sockaddr *) &server, len) != 0) { perror("cannot `bind' to socket"); exit(1); } if ((getsockname(sock, (struct sockaddr *) &server, &len) != 0) || (listen(sock, 8) != 0)) { perror("cannot `getsockname' or `listen'"); exit(1); } tmp->sock = sock; port = ntohs(server.sin_port); /* Register the port with the RPC port mapper & initialize the fd_set */ pmap_unset(tmp->server.prog_num, tmp->server.vers_num); pmap_set(tmp->server.prog_num, tmp->server.vers_num, IPPROTO_TCP, port); FD_SET(sock, &fds); if (sock > maxconn) maxconn = sock; tmp = tmp->next; } /* Accept new clients, read client requests & send replies forever... */ while (1) { int qty = select(maxconn + 1, &fds, 0, 0, 0); flick_server_list *last = 0; tmp = lst; while (qty > 0) { if (FD_ISSET(tmp->sock, &fds)) { if (tmp->listen) { flick_server_list *new_list = (flick_server_list *)malloc(sizeof(flick_server_list)); if (!new_list) exit(1); new_list->next = lst; lst = new_list; lst->sock = accept(tmp->sock, 0, 0); lst->func = tmp->func; lst->server = tmp->server; lst->listen = 0; if (lst->sock > maxconn) maxconn = lst->sock; } else do { FLICK_TARGET_STRUCT ts; ts.socket_fd = tmp->sock; ts.port = port; if (flick_server_get_request(&ts, &the_buf)) { switch ((*tmp->func)(&the_buf, &return_buf)) { case FLICK_OPERATION_SUCCESS:{ flick_server_send_reply(&ts, &return_buf); break; } case FLICK_OPERATION_SUCCESS_NOREPLY:{ break; } default /* FLICK_OPERATION_FAILURE */ :{ /* the socket has been closed */ if (last) { last->next = tmp->next; free(tmp); tmp = last; } else { lst = tmp->next; free(tmp); tmp = 0; } break; }} } else { /* the socket has been closed */ if (last) { last->next = tmp->next; free(tmp); tmp = last; } else { lst = tmp->next; free(tmp); tmp = 0; } } } while (flick_buffer_contains_more(&the_buf)); qty--; } last = tmp; if (tmp) tmp = tmp->next; else tmp = lst; } if (qty < 0) fprintf(stderr,"Error %d in server\n", errno); /* reset the file descriptor list */ FD_ZERO(&fds); tmp = lst; while (tmp) { FD_SET(tmp->sock, &fds); tmp = tmp->next; } } exit(1); }
static status_e activate_rpc( struct service *sp ) { union xsockaddr tsin; socklen_t sin_len = sizeof(tsin); unsigned long vers ; struct service_config *scp = SVC_CONF( sp ) ; struct rpc_data *rdp = SC_RPCDATA( scp ) ; char *sid = SC_ID( scp ) ; unsigned registered_versions = 0 ; int sd = SVC_FD( sp ) ; const char *func = "activate_rpc" ; if( SC_BIND_ADDR(scp) != 0 ) memcpy( &tsin, SC_BIND_ADDR(scp), sizeof(tsin) ); else memset( &tsin, 0, sizeof(tsin)); if ( SC_PROTOVAL ( scp ) == IPPROTO_TCP ) { M_SET ( scp->sc_xflags, SF_NOLIBWRAP ); } if( SC_IPV4( scp ) ) { tsin.sa_in.sin_family = AF_INET ; sin_len = sizeof(struct sockaddr_in); } else if( SC_IPV6( scp ) ) { tsin.sa_in6.sin6_family = AF_INET6 ; sin_len = sizeof(struct sockaddr_in6); } if ( bind( sd, &tsin.sa, sin_len ) == -1 ) { msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; return( FAILED ) ; } /* * Find the port number that was assigned to the socket */ if ( getsockname( sd, &tsin.sa, &sin_len ) == -1 ) { msg( LOG_ERR, func, "getsockname failed (%m). service = %s", sid ) ; return( FAILED ) ; } if( tsin.sa.sa_family == AF_INET ) SC_SET_PORT( scp, ntohs( tsin.sa_in.sin_port ) ) ; else if( tsin.sa.sa_family == AF_INET6 ) SC_SET_PORT( scp, ntohs( tsin.sa_in6.sin6_port ) ) ; /* * Try to register as many versions as possible */ for ( vers = RD_MINVERS( rdp ) ; vers <= RD_MAXVERS( rdp ) ; vers++ ) { /* Is this right? For instance, if we have both tcp and udp services, * this will unregister the previously registered protocol. * pmap_unset(RD_PROGNUM(rdp), vers); */ if ( pmap_set( RD_PROGNUM( rdp ), vers, SC_PROTOVAL( scp ), SC_PORT( scp ) ) ) registered_versions++ ; else msg( LOG_ERR, func, "pmap_set failed. service=%s program=%ld version=%ld", sid, RD_PROGNUM( rdp ), vers ) ; sleep(1); } if ( debug.on ) msg( LOG_DEBUG, func, "Registered %d versions of %s", registered_versions, sid ) ; return( ( registered_versions == 0 ) ? FAILED : OK ) ; }
/* * Nfs server daemon mostly just a user context for nfssvc() * * 1 - do file descriptor and signal cleanup * 2 - fork the nfsd(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 tcp nfs clients * -u - support udp nfs clients * followed by "n" which is the number of nfsds' to fork off */ int main(int argc, char *argv[]) { struct nfsd_args nfsdargs; struct sockaddr_in inetaddr, inetpeer; fd_set *ready, *sockbits; size_t fd_size; int ch, connect_type_cnt, i, maxsock = 0, msgsock; int nfsdcnt = DEFNFSDCNT, on, reregister = 0, sock; int udpflag = 0, tcpflag = 0, tcpsock; const char *errstr = NULL; socklen_t len; /* Start by writing to both console and log. */ openlog("nfsd", LOG_PID | LOG_PERROR, LOG_DAEMON); if (argc == 1) udpflag = 1; while ((ch = getopt(argc, argv, "n:rtu")) != -1) switch (ch) { case 'n': nfsdcnt = strtonum(optarg, 1, MAXNFSDCNT, &errstr); if (errstr) { syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg); return(1); } break; case 'r': reregister = 1; break; case 't': tcpflag = 1; break; case 'u': udpflag = 1; break; default: usage(); }; argv += optind; argc -= optind; /* * XXX * Backward compatibility, trailing number is the count of daemons. */ if (argc > 1) usage(); if (argc == 1) { nfsdcnt = strtonum(argv[0], 1, MAXNFSDCNT, &errstr); if (errstr) { syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg); return(1); } } if (debug == 0) { daemon(0, 0); (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGSYS, nonfs); } (void)signal(SIGCHLD, reapchild); if (reregister) { if (udpflag && (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) { syslog(LOG_ERR, "can't register with portmap for UDP (%m)."); return (1); } if (tcpflag && (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) { syslog(LOG_ERR, "can't register with portmap for TCP (%m)."); return (1); } return (0); } /* Cut back to writing to log only. */ closelog(); openlog("nfsd", LOG_PID, LOG_DAEMON); for (i = 0; i < nfsdcnt; i++) { switch (fork()) { case -1: syslog(LOG_ERR, "fork: %m"); return (1); case 0: break; default: continue; } setproctitle("server"); nsd.nsd_nfsd = NULL; if (nfssvc(NFSSVC_NFSD, &nsd) < 0) { syslog(LOG_ERR, "nfssvc: %m"); return (1); } return (0); } /* If we are serving udp, set up the socket. */ if (udpflag) { if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "can't create udp socket"); return (1); } memset(&inetaddr, 0, sizeof inetaddr); inetaddr.sin_family = AF_INET; inetaddr.sin_addr.s_addr = INADDR_ANY; inetaddr.sin_port = htons(NFS_PORT); inetaddr.sin_len = sizeof(inetaddr); if (bind(sock, (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) { syslog(LOG_ERR, "can't bind udp addr"); return (1); } if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) { syslog(LOG_ERR, "can't register with udp portmap"); return (1); } nfsdargs.sock = sock; nfsdargs.name = NULL; nfsdargs.namelen = 0; if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { syslog(LOG_ERR, "can't Add UDP socket"); return (1); } (void)close(sock); } /* Now set up the master server socket waiting for tcp connections. */ on = 1; connect_type_cnt = 0; if (tcpflag) { if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { syslog(LOG_ERR, "can't create tcp socket"); return (1); } if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); memset(&inetaddr, 0, sizeof inetaddr); inetaddr.sin_family = AF_INET; inetaddr.sin_addr.s_addr = INADDR_ANY; inetaddr.sin_port = htons(NFS_PORT); inetaddr.sin_len = sizeof(inetaddr); if (bind(tcpsock, (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) { syslog(LOG_ERR, "can't bind tcp addr"); return (1); } if (listen(tcpsock, 5) < 0) { syslog(LOG_ERR, "listen failed"); return (1); } if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) { syslog(LOG_ERR, "can't register tcp with portmap"); return (1); } maxsock = tcpsock; connect_type_cnt++; } if (connect_type_cnt == 0) return (0); setproctitle("master"); /* * Allocate space for the fd_set pointers and fill in sockbits */ fd_size = howmany(maxsock + 1, NFDBITS) * sizeof(fd_mask); sockbits = malloc(fd_size); ready = malloc(fd_size); if (sockbits == NULL || ready == NULL) { syslog(LOG_ERR, "cannot allocate memory"); return (1); } memset(sockbits, 0, fd_size); if (tcpflag) FD_SET(tcpsock, sockbits); /* * Loop forever accepting connections and passing the sockets * into the kernel for the mounts. */ for (;;) { memcpy(ready, sockbits, fd_size); if (connect_type_cnt > 1) { if (select(maxsock + 1, ready, NULL, NULL, NULL) < 1) { syslog(LOG_ERR, "select failed: %m"); return (1); } } if (tcpflag && FD_ISSET(tcpsock, ready)) { len = sizeof(inetpeer); if ((msgsock = accept(tcpsock, (struct sockaddr *)&inetpeer, &len)) < 0) { if (errno == EWOULDBLOCK || errno == EINTR || errno == ECONNABORTED) continue; syslog(LOG_ERR, "accept failed: %m"); return (1); } memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero)); if (setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m"); nfsdargs.sock = msgsock; nfsdargs.name = (caddr_t)&inetpeer; nfsdargs.namelen = sizeof(inetpeer); if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { syslog(LOG_ERR, "can't Add TCP socket"); return (1); } (void)close(msgsock); } } }
static int getprognum(long *prognum, SVCXPRT **xprt, char *fd_str, char *prog_str, long vers, char *tp_type) { static ulong_t start = 0x40000000; int fd; #ifdef TDRPC ushort_t port; int proto; #else struct netconfig *nc; struct netbuf *nb; #endif /* If prognum specified, use it instead of transient hassel. */ if (*prognum) { *xprt = NULL; sprintf(fd_str, "-1"); /* have child close all fds */ sprintf(prog_str, "%u", *prognum); return (TRUE); } /* * Transient hassel: * - parent must create mapping since someone else could * steal the transient prognum before child created it * - pass the child the fd to use for service * - close the fd (after exec), free xprt, leave mapping intact */ #ifdef TDRPC if (strcmp(tp_type, "udp") != 0) { proto = IPPROTO_UDP; *xprt = svcudp_bufcreate(RPC_ANYSOCK, 0, 0); } else { proto = IPPROTO_TCP; *xprt = svctcp_create(RPC_ANYSOCK, 0, 0); } if (*xprt == NULL) return (FALSE); port = (*xprt)->xp_port; fd = (*xprt)->xp_sock; while (!pmap_set(start, vers, proto, port)) start++; #else /* tp_type is legit: users choice or a loopback netid */ if ((nc = getnetconfigent(tp_type)) == NULL) return (FALSE); if ((*xprt = svc_tli_create(RPC_ANYFD, nc, NULL, 0, 0)) == NULL) { freenetconfigent(nc); return (FALSE); } nb = &(*xprt)->xp_ltaddr; fd = (*xprt)->xp_fd; while (!rpcb_set(start, vers, nc, nb)) start++; freenetconfigent(nc); #endif *prognum = start; sprintf(fd_str, "%u", fd); sprintf(prog_str, "%u", *prognum); return (TRUE); }