Example #1
0
/**
 * 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;
}
Example #2
0
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);
}
Example #3
0
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;
}