/** * nfs_svc_create - start up RPC svc listeners * @name: C string containing name of new service * @program: RPC program number to register * @version: RPC version number to register * @dispatch: address of function that handles incoming RPC requests * @port: if not zero, transport listens on this port * * Sets up network transports for receiving RPC requests, and starts * the RPC dispatcher. Returns the number of started network transports. */ unsigned int nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, void (*dispatch)(struct svc_req *, SVCXPRT *), const uint16_t port) { const struct sigaction create_sigaction = { .sa_handler = SIG_IGN, }; unsigned int visible, up, servport; struct netconfig *nconf; void *handlep; /* * Ignore SIGPIPE to avoid exiting sideways when peers * close their TCP connection while we're trying to reply * to them. */ (void)sigaction(SIGPIPE, &create_sigaction, NULL); handlep = setnetconfig(); if (handlep == NULL) { xlog(L_ERROR, "Failed to access local netconfig database: %s", nc_sperror()); return 0; } visible = 0; up = 0; while ((nconf = getnetconfig(handlep)) != NULL) { if (!(nconf->nc_flag & NC_VISIBLE)) continue; visible++; if (port == 0) servport = getservport(program, nconf->nc_proto); else servport = port; up += svc_create_nconf(name, program, version, dispatch, servport, nconf); } if (visible == 0) xlog(L_ERROR, "Failed to find any visible netconfig entries"); if (endnetconfig(handlep) == -1) xlog(L_ERROR, "Failed to close local netconfig database: %s", nc_sperror()); return up; }
static int svc_socket (u_long number, int type, int protocol, int reuse) { struct sockaddr_in addr; socklen_t len = sizeof (struct sockaddr_in); int sock, ret; const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp"; if ((sock = __socket (AF_INET, type, protocol)) < 0) { perror (_("svc_socket: socket creation problem")); return sock; } if (reuse) { ret = 1; ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof (ret)); if (ret < 0) { perror (_("svc_socket: socket reuse problem")); return ret; } } memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_port = htons(getservport(number, proto)); if (bind(sock, (struct sockaddr *) &addr, len) < 0) { perror (_("svc_socket: bind problem")); (void) __close(sock); sock = -1; } return svcsock_nonblock(sock); }
static int svc_socket (u_long number, int type, int protocol, int reuse) { struct sockaddr_in addr; socklen_t len = sizeof (struct sockaddr_in); int sock, ret; const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp"; if ((sock = __socket (AF_INET, type, protocol)) < 0) { perror (_("svc_socket: socket creation problem")); return sock; } if (reuse) { ret = 1; ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof (ret)); if (ret < 0) { perror (_("svc_socket: socket reuse problem")); return ret; } } memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_port = htons(getservport(number, proto)); if (bind(sock, (struct sockaddr *) &addr, len) < 0) { perror (_("svc_socket: bind problem")); (void) __close(sock); sock = -1; } if (sock >= 0) { /* This socket might be shared among multiple processes * if mountd is run multi-threaded. So it is safest to * make it non-blocking, else all threads might wake * one will get the data, and the others will block * indefinitely. * In all cases, transaction on this socket are atomic * (accept for TCP, packet-read and packet-write for UDP) * so O_NONBLOCK will not confuse unprepared code causing * it to corrupt messages. * It generally safest to have O_NONBLOCK when doing an accept * as if we get a RST after the SYN and before accept runs, * we can block despite being told there was an acceptable * connection. */ int flags; if ((flags = fcntl(sock, F_GETFL)) < 0) { perror (_("svc_socket: can't get socket flags")); (void) __close (sock); sock = -1; } else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) { perror (_("svc_socket: can't set socket flags")); (void) __close (sock); sock = -1; } } return sock; }