Are socket options inherited across accept() from the listening socket?

后端 未结 4 421
北恋
北恋 2020-12-24 11:46

Suppose the listening socket passed to accept has non-default options set on it with setsockopt. Are these options (some or all of them?) inherited

相关标签:
4条回答
  • 2020-12-24 12:23

    No, they're not necessarily inherited. Try this sample, which sets the receive buffer size (SO_RCVBUF) on the initial socket to a non-default value and then compares the result with the inherited socket. Run this code, which listens on TCP port 12345, and then connect to it from any other program.

    #include <errno.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>
    
    void die(const char *f)
    {
      printf("%s: %s\n", f, strerror(errno));
      exit(1);
    }
    
    int main(void)
    {
      int s = socket(AF_INET, SOCK_STREAM, 0);
      if(s < 0)
        die("socket");
    
      int rcvbuf;
      socklen_t optlen = sizeof(rcvbuf);
      if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
        die("getsockopt (1)");
      printf("initial rcvbuf: %d\n", rcvbuf);
      rcvbuf *= 2;
      if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
        die("setsockopt");
      printf("set rcvbuf to %d\n", rcvbuf);
    
      struct sockaddr_in sin;
      memset(&sin, 0, sizeof(sin));
      sin.sin_family = AF_INET;
      sin.sin_port = htons(12345);
      sin.sin_addr.s_addr = INADDR_ANY;
      if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        die("bind");
    
      if(listen(s, 10) < 0)
        die("listen");
    
      struct sockaddr_in client_addr;
      socklen_t addr_len = sizeof(client_addr);
      int s2 = accept(s, (struct sockaddr *)&client_addr, &addr_len);
      if(s2 < 0)
        die("accept");
      printf("accepted connection\n");
      optlen = sizeof(rcvbuf);
      if(getsockopt(s2, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
        die("getsockopt (2)");
    
      printf("new rcvbuf: %d\n", rcvbuf);
    
      return 0;
    }
    

    Result on a machine running Linux 3.0.0-21-generic:

    initial rcvbuf: 87380
    set rcvbuf to 174760
    accepted connection
    new rcvbuf: 262142
    
    0 讨论(0)
  • 2020-12-24 12:25

    Socket options is the place where things go that don't fit elsewhere. So, it's expected for different socket options to have different inheriting behaviour. Whether to inherit or not a socket option is decided on a case by case basis.

    0 讨论(0)
  • 2020-12-24 12:28

    The answer is No for POSIX conforming implementations, as I read it.

    From the POSIX-2017 spec for accept():

    The accept() function shall extract the first connection on the queue of pending connections, create a new socket with the same socket type protocol and address family as the specified socket, and allocate a new file descriptor for that socket.

    Note it is explicitly a "new socket", not a "full or partial copy of the socket being unqueued", so should have no options different from the default for that socket type and address family. While the copy behavior may be desirable, this is left as an extension interface a platform may have. I haven't seen that any platform does implement one, however, so it could be added to the standard. It is therefore on the application to use getsockopt()/setsockopt() to copy any attributes, that differ from the defaults, from the queue socket to the returned socket, not the responsibility of the interface, before any use of that socket to send or receive data.

    0 讨论(0)
  • 2020-12-24 12:46

    Several of the socket options are handled at lower levels of the system. While most of the socket options could be set using the setsockopt. Reference:man setsockopt And since you are mentioning only POSIX on any Linux, in general, as your scope. The accept() (Reference: man accept) does have a certain amount of discretion on what socket options should be inherited and what options to reject from the listening fd.

    accept() does not modify the original socket passed to it as argument. The new socket returned by accept() does not inherit file status flags such as O_NONBLOCK,O_ASYNC from the listening socket.

    So, instead of relying on the inheritance or non-inheritance of the listening socket properties(which is bound to vary across implementations and licenses), the accepted socket should be explicitly set with the desired socket options.(Best practice)

    man pages and the implementation codes in your machine would be the most relevant specification for the accept() behavior.There's no common or standard specification existing across multiple variants of Linux.

    0 讨论(0)
提交回复
热议问题