socket.bind for AF_UNIX requires raw sockaddr struct
Port, board and/or hardware
unix
MicroPython version
MicroPython v1.26.0 Unix port, standard variant.
Reproduction
On real python this works to create a socket in /tmp/socket:
import socket
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind("/tmp/socket")
For micropython's unix port it requires that the bind() argument be a raw sockaddr struct:
import socket
import struct
sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
sock.bind(struct.pack("H", socket.AF_UNIX) + "/tmp/socket".encode())
Expected behaviour
The socket in /tmp/socket would be created.
Observed behaviour
% ./build/micropython-1.26.0/ports/unix/build-standard/micropython ./sockdemo.py
Traceback (most recent call last):
File "./sockdemo.py", line 4, in <module>
OSError: [Errno 22] EINVAL
Additional Information
No, I've provided everything above.
Code of Conduct
Yes, I agree
Binding AF_UNIX sockets fails
Using the Unix port of Micropython at version v1.8.4-87-g53bfcc9-dirty, trying to bind a Unix domain socket fails.
The following code:
import socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.bind('/tmp/socket')
works under CPython, but fails (without much description) under Micropython:
Traceback (most recent call last):
File "unix_socket.py", line 3, in <module>
File "/.../socket.py", line 49, in bind
File "/.../socket.py", line 22, in _resolve_addr
OSError: [addrinfo error -8]
On line 13-14 in socket.py (from latest micropython-lib) in function _resolve_addr there are the following lines:
if isinstance(addr, (bytes, bytearray)):
return addr
By passing the socket name as bytes, or changing the tuple passed to isinstance to (bytes, bytearray, str), I get past _resolve_addr and instead get the following error message:
Traceback (most recent call last):
File "unix_socket.py", line 3, in <module>
File "/.../socket.py", line 49, in bind
File "/.../socket.py", line 49, in bind
OSError: [Errno 22] EINVAL
EINVAL is a bit more descriptive, but doesn't help much. According to the man page of bind, EINVAL can mean one of the following:
- "The socket is already bound to an address." - Nope.
- "addrlen is wrong, or addr is not a valid address for this socket's domain." - More likely.
Both passing name as string and bytes works in CPython.