Can't connect to localhost using IPv4 - "localhost" resolves only to the IPv6 address

Open
#226 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Stale
Tech stack
python
Domain
networking

Research direction

Start in ws4py/client/init.py at the socket.getaddrinfo call around line 95, then review how the selected address is connected. Reproduce with example/echo_client.py and the provided localhost test server; done means localhost connections try the available addresses so an IPv4 server works when IPv6 is unavailable.

Written by the indexing model from the issue text.

Description

Overview
I am trying to connect to a simple test server running on my local machine. I tried running the sample code in example\echo_client.py, but receive an error when the websocket attempts to connect. After digging into it, I discovered that the issue is that the address 'ws://localhost:9000/ws' is being resolved to the IPv6 address ("::1"), but my server is using IPv4 ("127.0.0.1"). The connection works fine if I modify the example code to specify the IPv4 address explicitly rather than using the localhost hostname.

Expected Behavior
It should be possible to connect to an IPv4 server on localhost using the "localhost" hostname. For example, the following should work:

from ws4py.client.threadedclient import WebSocketClient
ws = WebSocketClient('ws://localhost:9000/ws', protocols=['http-only', 'chat'])
ws.connect()

In particular, the example code in example\echo_client.py should work against an IPv4 server, and if not that should be documented.

Actual Behavior
Running the above code (or example\echo_client.py) results in the following error: socket.error: [Errno 10061] No connection could be made because the target machine actively refused it. Here is the stack trace from running echo_client.py:

File "C:\Users\EWillemsma\repos\WebSocket-for-Python\example\echo_client.py", line 28, in <module>
  ws.connect()
File "C:\Python27\Lib\site-packages\ws4py\client\__init__.py", line 215, in connect
  self.sock.connect(self.bind_addr)
File "C:\Python27\Lib\socket.py", line 228, in meth
  return getattr(self._sock,name)(*args)

socket.error: [Errno 10061] No connection could be made because the target machine actively refused it

Running the following modified code works correctly:

ws = WebSocketClient('ws://127.0.0.1:9000/ws', protocols=['http-only', 'chat'])
ws.connect()

Environment
Python 2.7.13
Windows 10 Pro
ws4py version 0.4.2

Steps to Reproduce
Here is my test server code:

from websocket_server import WebsocketServer

def new_client(client, server):
    print "new client: %s"%client
    
def client_left(client, server):
    print "client left: %s"%client
    
def message_received(client, server, message):
    print "message from client: %s"%client
    print message
    server.send_message(client, message)

server = WebsocketServer(host='localhost',port=9000)    
server.set_fn_new_client(new_client)
server.set_fn_client_left(client_left)
server.set_fn_message_received(message_received)

server.run_forever()

Start the test server, then run example/echo_client.py

Further Details
I traced the issue to ws4py\client\__init__.py line 95:

    family, socktype, proto, canonname, sa = socket.getaddrinfo(self.host, self.port,
                                     socket.AF_UNSPEC,
                                     socket.SOCK_STREAM,
                                     0, socket.AI_PASSIVE)[0]

The socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) call does correctly return a list including both the IPv6 and IPv4 addresses, but only the first address (the IPv6) actually gets used. A better approach would be to attempt a connection to each of the returned addresses in turn and keep whichever one is successful.

Dominant language
Python
Stars
1.1k
Forks
285
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Lawouach/WebSocket-for-Python

All issues in Lawouach/WebSocket-for-Python

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.