title: ConnectEx requires the socket to be "initially bound", but to what?
body: <p>The <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms737606%28v=vs.85%29.aspx" rel="noreferrer">ConnectEx</a> function requires an "unconnected, previously bound socket".  Indeed, if I omit the <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms737550%28v=vs.85%29.aspx" rel="noreferrer">bind</a> step in my example (see below), <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms737606%28v=vs.85%29.aspx" rel="noreferrer">ConnectEx</a> fails with <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms681391%28v=vs.85%29.aspx#WSAEINVAL" rel="noreferrer">WSAEINVAL</a>.</p>
  
  <p>Here's my current understanding: before calling <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms737606%28v=vs.85%29.aspx" rel="noreferrer">ConnectEx</a>, <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms737550%28v=vs.85%29.aspx" rel="noreferrer">bind</a> the socket to <code>INADDR_ANY</code> and port 0 (unless it is already bound):</p>
  
  <pre><code>struct sockaddr_in addr;
  ZeroMemory(&amp;addr, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = 0;
  rc = bind(sock, (SOCKADDR*) &amp;addr, sizeof(addr));
  if (rc != 0) { ... bind failed; call WSAGetLastError to see why ... }
  </code></pre>
  
  <p>Or for an IPv6 socket:</p>
  
  <pre><code>struct sockaddr_in6 addr;
  ZeroMemory(&amp;addr, sizeof(addr));
  addr.sin6_family = AF_INET6;
  addr.sin6_addr = in6addr_any;
  addr.sin6_port = 0;
  rc = bind(sock, (SOCKADDR*) &amp;addr, sizeof(addr));
  if (rc != 0) { ... bind failed; call WSAGetLastError to see why ... }
  </code></pre>
  
  <p>This lets the operating system assign a <em>local address</em> to our socket (as opposed to the <em>remote address</em> we are connecting to).  <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx" rel="noreferrer">connect</a> does this step automatically, but <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms737606%28v=vs.85%29.aspx" rel="noreferrer">ConnectEx</a> does not.</p>
  
  <p>My questions are:</p>
  
  <ol>
  <li><p>Is my assessment correct?</p></li>
  <li><p>Is there a way to do this automatic bind that is agnostic to the address family, or will I have to handle each of <code>AF_INET</code>, <code>AF_INET6</code>, <code>AF_BTH</code> (Bluetooth), etc. manually?</p></li>
  </ol>
  
  <p>Working ConnectEx example (also on Gist: <a href="https://gist.github.com/4158972" rel="noreferrer">https://gist.github.com/4158972</a>):</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;WinSock2.h&gt;
  #include &lt;MSWSock.h&gt;
  #include &lt;WS2tcpip.h&gt;
  
  #pragma comment(lib, "Ws2_32.lib")
  
  struct mswsock_s {
      LPFN_CONNECTEX ConnectEx;
  } mswsock;
  
  static BOOL load_mswsock(void)
  {
      SOCKET sock;
      DWORD dwBytes;
      int rc;
  
      /* Dummy socket needed for WSAIoctl */
      sock = socket(AF_INET, SOCK_STREAM, 0);
      if (sock == INVALID_SOCKET)
          return FALSE;
  
      {
          GUID guid = WSAID_CONNECTEX;
          rc = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
                        &amp;guid, sizeof(guid),
                        &amp;mswsock.ConnectEx, sizeof(mswsock.ConnectEx),
                        &amp;dwBytes, NULL, NULL);
          if (rc != 0)
              return FALSE;
      }
  
      rc = closesocket(sock);
      if (rc != 0)
          return FALSE;
  
      return TRUE;
  }
  
  int main(int argc, char *argv[])
  {
      int rc;
      BOOL ok;
      WSADATA wsaData;
      SOCKET sock;
  
      rc = WSAStartup(MAKEWORD(2,2), &amp;wsaData);
      if (rc != 0) {
          printf("WSAStartup failed: %d\n", rc);
          return 1;
      }
      if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
          printf("Your computer is from the wrong millenium.\n");
          WSACleanup();
          return 1;
      }
  
      if (!load_mswsock()) {
          printf("Error loading mswsock functions: %d\n", WSAGetLastError());
          return 1;
      }
  
      sock = socket(AF_INET, SOCK_STREAM, 0);
      if (sock == INVALID_SOCKET) {
          printf("socket: %d\n", WSAGetLastError());
          return 1;
      }
  
      /* ConnectEx requires the socket to be initially bound. */
      {
          struct sockaddr_in addr;
          ZeroMemory(&amp;addr, sizeof(addr));
          addr.sin_family = AF_INET;
          addr.sin_addr.s_addr = INADDR_ANY;
          addr.sin_port = 0;
          rc = bind(sock, (SOCKADDR*) &amp;addr, sizeof(addr));
          if (rc != 0) {
              printf("bind failed: %d\n", WSAGetLastError());
              return 1;
          }
      }
  
      /* Issue ConnectEx and wait for the operation to complete. */
      {
          OVERLAPPED ol;
          ZeroMemory(&amp;ol, sizeof(ol));
  
          sockaddr_in addr;
          ZeroMemory(&amp;addr, sizeof(addr));
          addr.sin_family = AF_INET;
          addr.sin_addr.s_addr = inet_addr("173.194.37.36"); // google.com
          addr.sin_port = htons(80);
  
          ok = mswsock.ConnectEx(sock, (SOCKADDR*) &amp;addr, sizeof(addr), NULL, 0, NULL, &amp;ol);
          if (ok) {
              printf("ConnectEx succeeded immediately\n");
          } else if (WSAGetLastError() == ERROR_IO_PENDING) {
              printf("ConnectEx pending\n");
  
              DWORD numBytes;
              ok = GetOverlappedResult((HANDLE) sock, &amp;ol, &amp;numBytes, TRUE);
              if (ok)
                  printf("ConnectEx succeeded\n");
              else
                  printf("ConnectEx failed: %d\n", WSAGetLastError());
          } else {
              printf("ConnectEx failed: %d\n", WSAGetLastError());
              return 1;
          }
      }
  
      /* Make the socket more well-behaved. */
      rc = setsockopt(sock, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
      if (rc != 0) {
          printf("SO_UPDATE_CONNECT_CONTEXT failed: %d\n", WSAGetLastError());
          return 1;
      }
  
      /* This will fail if SO_UPDATE_CONNECT_CONTEXT was not performed. */
      rc = shutdown(sock, SD_BOTH);
      if (rc != 0) {
          printf("shutdown failed: %d\n", WSAGetLastError());
          return 1;
      }
  
      printf("Done\n");
      return 0;
  }
  </code></pre>