docs: def create_starttls_connection(
          loop,
          protocol_factory,
          host=None,
          port=None,
          *,
          sock=None,
          ssl_context_factory=None,
          use_starttls=False,
          local_addr=None,
          **kwargs):
      """
      Create a connection which can later be upgraded to use TLS.
  
      .. versionchanged:: 0.4
  
          The `local_addr` argument was added.
  
      :param loop: The event loop to use.
      :type loop: :class:`asyncio.BaseEventLoop`
      :param protocol_factory: Factory for the protocol for the connection
      :param host: The host name or address to connect to
      :type host: :class:`str` or :data:`None`
      :param port: The port to connect to
      :type port: :class:`int` or :data:`None`
      :param sock: A socket to wrap (conflicts with `host` and `port`)
      :type sock: :class:`socket.socket`
      :param ssl_context_factory: Function which returns a
          :class:`OpenSSL.SSL.Context` to use for TLS operations
      :param use_starttls: Flag to control whether TLS is negotiated right away
          or deferredly.
      :type use_starttls: :class:`bool`
      :param local_addr: Address to bind to
  
      This is roughly a copy of the asyncio implementation of
      :meth:`asyncio.BaseEventLoop.create_connection`. It returns a pair
      ``(transport, protocol)``, where `transport` is a newly created
      :class:`STARTTLSTransport` instance. Further keyword arguments are
      forwarded to the constructor of :class:`STARTTLSTransport`.
  
      `loop` must be a :class:`asyncio.BaseEventLoop`, with support for
      :meth:`asyncio.BaseEventLoop.add_reader` and the corresponding writer and
      removal functions for sockets. This is typically a selector type event
      loop.
  
      `protocol_factory` must be a callable which (without any arguments) returns
      a :class:`asyncio.Protocol` which will be connected to the STARTTLS
      transport.
  
      `host` and `port` must be a hostname and a port number, or both
      :data:`None`. Both must be :data:`None`, if and only if `sock` is not
      :data:`None`. In that case, `sock` is used instead of a newly created
      socket. `sock` is put into non-blocking mode and must be a stream socket.
  
      If `use_starttls` is :data:`True`, no TLS handshake will be performed
      initially. Instead, the connection is established without any
      transport-layer security. It is expected that the
      :meth:`STARTTLSTransport.starttls` method is used when the application
      protocol requires TLS. If `use_starttls` is :data:`False`, the TLS
      handshake is initiated right away.
  
      `local_addr` may be an address to bind this side of the socket to. If
      omitted or :data:`None`, the local address is assigned by the operating
      system.
  
      This coroutine returns when the stream is established. If `use_starttls` is
      :data:`False`, this means that the full TLS handshake has to be finished
      for this coroutine to return. Otherwise, no TLS handshake takes place. It
      must be invoked using the :meth:`STARTTLSTransport.starttls` coroutine.
      """
  
      if host is not None and port is not None:
          host_addrs = yield from loop.getaddrinfo(
              host, port,
              type=socket.SOCK_STREAM)
  
          exceptions = []
  
          for family, type, proto, cname, address in host_addrs:
              sock = None
              try:
                  sock = socket.socket(family=family, type=type, proto=proto)
                  sock.setblocking(False)
                  if local_addr is not None:
                      sock.bind(local_addr)
                  yield from loop.sock_connect(sock, address)
              except OSError as exc:
                  if sock is not None:
                      sock.close()
                  exceptions.append(exc)
              else:
                  break
          else:
              if len(exceptions) == 1:
                  raise exceptions[0]
  
              model = str(exceptions[0])
              if all(str(exc) == model for exc in exceptions):
                  raise exceptions[0]
  
              try:
                  from aioxmpp.errors import MultiOSError
              except ImportError:
                  MultiOSError = OSError
  
              exc = MultiOSError(
                  "could not connect to [{}]:{}".format(host, port),
                  exceptions)
              raise exc
      elif sock is None:
          raise ValueError("sock must not be None if host and/or port are None")
      else:
          sock.setblocking(False)
  
      protocol = protocol_factory()
      waiter = asyncio.Future(loop=loop)
      transport = STARTTLSTransport(loop, sock, protocol,
                                    ssl_context_factory=ssl_context_factory,
                                    waiter=waiter,
                                    use_starttls=use_starttls,
                                    **kwargs)
      yield from waiter
  
      return transport, protocol