Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-43236

QNativeSocketEnginePrivate::nativeConnect() for Windows is insane

    XMLWordPrintable

Details

    • Task
    • Resolution: Unresolved
    • P2: Important
    • None
    • 5.1.1
    • Network: Sockets
    • None

    Description

      Linked to QTBUG-42567 .

      In fact, the main problem is with QNativeSocketEngine::connectToHost():

      If false is returned, state() should be called to see if the
      socket is in ConnectingState. If so, a delayed TCP connection is
      taking place, and connectToHost() must be called again later to
      determine if the connection was established successfully or
      not. The second connection attempt must be made when the socket is
      ready for writing.

      And indeed, the connection notifier (which is triggered when an ongoing connection attempt finished) just calls connectToHost(), which leads to the second connect() call on the same socket descriptor. If the socket has successfuly connected to the remote host, then EISCONN/WSAEISCONN error is immediately reported by the OS, and the QAbstractSocket changes its state to ConnectedState.

      However, if the connection has failed, it means that a connect() is called on an unconnected socket which, frankly, probably ought to just start another connection attempt. That's not the case on Linux: in "connect(); select(); connect();" sequence the second connect() functions essentially like getsockopt(s, SOL_SOCKET, SO_ERROR) — but that's not the case on Windows, and the "workaround" is truly insane:

      After WSAConnect() is called on the socket for the second time, getsockopt(SO_ERROR) is immediately called (in hopes to retrieve the previous error, I assume), but the OS sometimes manages to reset the error on the socket before getsockopt() gets called anyway, so this scheme doesn't work. And apparently it was noticed that sometimes it doesn't work, and it was "fixed" somewhen between 4.8.3 and 5.1.1 — by calling getsockopt() twice in a tight loop. I fail to see what that would accomplish, or how, because the actual fix is much, much simpler:

      nativeConnect(), before calling WSAConnect, should check whether socketState is ConnectingState, and if it's true, getsockopt(SO_ERROR) should be called immediately. If it reports no error, then the connection was successful, assign ConnectedState to socketState and return true; if it reports an error, call setError() with proper error value, assign UnconnectedStateto socketState and return false.

      Only if socketState is not ConnnectingState should WSAConnect() be called. In fact, this change works on Linux as well, and in fact, the "call getsockopt(SO_ERROR) after select() on a connect()ing socket" idiom is used by virtually every Linux network library – except Qt, bizarrely enough.

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              thiago Thiago Macieira
              joker_vd Semyon Kholodnov
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:

                Gerrit Reviews

                  There are no open Gerrit changes