title: MacOS SO_REUSEADDR/SO_REUSEPORT not consistent with Linux?
body: <p>Consider this code:</p>
  
  <pre><code>#include &lt;arpa/inet.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;sys/ioctl.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;stdlib.h&gt;
  
  #define SERVADDR "::1"
  #define PORT 12345
  
  int main() {
      int sd = -1;
  
      if ((sd = socket(AF_INET6, SOCK_STREAM, 0)) &lt; 0) {
          fprintf(stderr, "socket() failed: %d", errno);
          exit(1);
      }
  
      int flag = 1;
      if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &amp;flag, sizeof(flag)) == -1) {
          fprintf(stderr, "Setsockopt %d, SO_REUSEADDR failed with errno %d\n", sd, errno);
          exit(2);
      }
      if(setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &amp;flag, sizeof(flag)) == -1) {
          fprintf(stderr, "Setsockopt %d, SO_REUSEPORT failed with errno %d\n", sd, errno);
          exit(3);
      }
  
      struct sockaddr_in6 addr;
      memset(&amp;addr, 0, sizeof(addr));
      addr.sin6_family = AF_INET6;
      addr.sin6_port = htons(23456);
  
      if(bind(sd, (struct sockaddr*)&amp;addr, sizeof(addr)) == -1) {
          fprintf(stderr, "Bind %d failed with errno %d: %s\n", sd, errno, strerror(errno));
          exit(4);
      }
  
      struct sockaddr_in6 server_addr;
      memset(&amp;server_addr, 0, sizeof(server_addr));
  
      server_addr.sin6_family = AF_INET6;
      inet_pton(AF_INET6, SERVADDR, &amp;server_addr.sin6_addr);
      server_addr.sin6_port = htons(PORT);
  
      if (connect(sd, (struct sockaddr *)&amp;server_addr, sizeof(server_addr)) == -1) {
          fprintf(stderr, "Connect %d failed with errno %d: %s\n", sd, errno, strerror(errno));
          exit(5);
      }
  
      printf("Seems like it worked this time!\n");
      close(sd);
  }
  </code></pre>
  
  <p>Pretty simple:</p>
  
  <ul>
  <li>create socket</li>
  <li>set <code>SO_REUSEADDR</code></li>
  <li>set <code>SO_REUSEPORT</code></li>
  <li>bind to local port <code>23456</code></li>
  <li>connect to <code>::1</code> on port <code>12345</code></li>
  </ul>
  
  <p>Weirdly enough on MacOS running this in a row causes this:</p>
  
  <pre><code>$ for i in {1..5}; do ./ipv6; done
  Seems like it worked this time!
  Connect 3 failed with errno 48: Address already in use
  Connect 3 failed with errno 48: Address already in use
  Connect 3 failed with errno 48: Address already in use
  Connect 3 failed with errno 48: Address already in use
  $
  </code></pre>
  
  <p>While running this on Linux seems to work just fine:</p>
  
  <pre><code>$ for i in {1..5}; do ./ipv6; done
  Seems like it worked this time!
  Seems like it worked this time!
  Seems like it worked this time!
  Seems like it worked this time!
  Seems like it worked this time!
  $
  </code></pre>
  
  <p>I have a listener on port <code>12345</code>:</p>
  
  <pre><code>$ nc -6 -l -v -p12345 -k
  </code></pre>
  
  <p>This is NOT limited to IPv6, tried the same thing with IPv4 - same behavior.</p>
  
  <p>Can anybody explain it?</p>
  
  <p>I previously thought it was failing in <code>bind()</code> but it's in <code>connect()</code>.</p>
  
  <h2>Edit #1</h2>
  
  <p>According to <a href="https://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t">this</a> - applies to BSD:</p>
  
  <p><em>So if you bind two sockets of the same protocol to the same source address and port and try to connect them both to the same destination address and port, <code>connect()</code> will actually fail with the error <code>EADDRINUSE</code> for the second socket you try to connect, which means that a socket with an identical tuple of five values is already connected.</em></p>
  
  <p>So that makes sense why that doesn't work. What doesn't make sense if how is it possible this actually works on Linux?</p>
  
  <p>I'd ideally of course have this work on MacOS but I currently feel like it might not be possible - I'd however still like to understand how Linux does it.</p>