Skip to content
This repository was archived by the owner on Sep 6, 2023. It is now read-only.

Conversation

@nickzoic
Copy link
Collaborator

Fix for #31 ... check return code of lwip_getaddrinfo and throw exceptions when appropriate.

@dpgeorge
Copy link
Member

dpgeorge commented Mar 1, 2017

Running CPython with socket.getaddrinfo('', 80) gives me an error... so perhaps the empty string is just a special case for bind? Regardless, I think this patch is ok as it is.

@nickzoic
Copy link
Collaborator Author

nickzoic commented Mar 1, 2017

Yeah, I think there's a bunch of special rules around parsing addresses which may be dotted quads or their decimal equivalents: you can see this elsewhere in unix:

$ echo $(( 0x08080808 ))
134744072
$ ping 134744072
PING 134744072 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=49.4 ms
$ ping 127.257
PING 127.257 (127.0.1.1) 56(84) bytes of data.
64 bytes from 127.0.1.1: icmp_seq=1 ttl=64 time=0.050 ms

I've only allowed for "" as a special case for "0.0.0.0" which I'm not sure is quite the right thing to do either.

@nickzoic
Copy link
Collaborator Author

nickzoic commented Oct 3, 2017

Closing this: the important bit of the change was done in 1365f7f

@nickzoic nickzoic closed this Oct 3, 2017
@MrSurly
Copy link
Contributor

MrSurly commented Oct 4, 2017

Running CPython with socket.getaddrinfo('', 80) gives me an error... so perhaps the empty string is just a special case for bind? Regardless, I think this patch is ok as it is.

The unix port needs quite a bit of fixing up around getaddrinfo to match CPython and other µPy ports. Makes it difficult to write compatible code.

@nickzoic
Copy link
Collaborator Author

nickzoic commented Oct 4, 2017 via email

@MrSurly
Copy link
Contributor

MrSurly commented Oct 4, 2017

I was more referring to this:

CPython, and µPy ESP32

>>> socket.getaddrinfo('0.0.0.0', 80)
[(2, 1, 6, '', ('0.0.0.0', 80)), (2, 2, 17, '', ('0.0.0.0', 80)), (2, 3, 0, '', ('0.0.0.0', 80))]

µPy Unix

socket.getaddrinfo('0.0.0.0', 80)
[(2, 1, 6, None, bytearray(b'\x02\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')), (2, 2, 17, None, bytearray(b'\x02\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')), (2, 3, 0, None, bytearray(b'\x02\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'))]

I know there was a recent discussion around why this is, but I don't think having a single µPy port that behaves very differently (from other µPy ports, and even CPython) for getaddrinfo makes much sense.

@nickzoic
Copy link
Collaborator Author

nickzoic commented Oct 4, 2017 via email

@dpgeorge
Copy link
Member

dpgeorge commented Oct 4, 2017

For the case of getaddrinfo: the returned values (or at least the 5th entry in the tuple) is considered an opaque address. It can be passed to socket methods to specify an address but otherwise should be considered port/system dependent. Taking that point of view, the ports are all consistent including consistency with CPython.

@MrSurly what kind of compatible code is hard to write in this sense?

@MrSurly
Copy link
Contributor

MrSurly commented Oct 4, 2017

[Long rant about code compatibility ahead]

Short Version: I should be able to copy-paste µPy code between ports, with a reasonable assurance that it will just work. CPython3 socket examples should just work.

Long Version:

I've been doing a lot of prototyping of socket code lately, and I would expect that doing so would be easier on the Unix port before moving it to the target device. So I compiled the Unix port, aimed it at my code that worked on the ESP32 and ... it didn't work.

However, It did work in CPython3.

I don't think it's too much to assume that µPy ESP32 code should be 100% compatible (barring HW specifics) with µPy Unix.

what kind of compatible code is hard to write in this sense?

In the sense you've defined here, it's not hard, but there is a preponderance of "prior art" that doesn't fit that definition:

Internet examples in general

There is a ton a example code (particularly server code) out there with idioms such as:

socket.bind(('0.0.0.0', 8080))

The official Python 3 example code

These examples are directly from the Python 3 Socket Programming HOWTO:

# create an INET, STREAMing socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# now connect to the web server on port 80 - the normal http port
s.connect(("www.python.org", 80))
# create an INET, STREAMing socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind the socket to a public host, and a well-known port
serversocket.bind((socket.gethostname(), 80))
# become a server socket
serversocket.listen(5)

This is, frankly, super useful, and arguably Pythonic.

The Python 3 documenation for getaddrinfo

The Python 3 documentation doesn't mention anything about the last item being opaque (emphasis mine):

In these tuples, family, type, proto are all integers and are meant to be passed to the socket() function. canonname will be a string representing the canonical name of the host if AI_CANONNAME is part of the flags argument; else canonname will be empty. sockaddr is a tuple describing a socket address, whose format depends on the returned family (a (address, port) 2-tuple for AF_INET, a (address, port, flow info, scope id) 4-tuple for AF_INET6), and is meant to be passed to the socket.connect() method.

Off topic: module aliases

Continuing the vein of writing compatible code, the Unix port also doesn't have weak links for the common modules. import socket works on ESP32, whereas it's an ImportError on the Unix port. It's arguable that if you're using an ESP32, that you know it's a "micro" version of that module, but then again nobody accidentally uses the Unix port -- forcing the name to be usocket seems odd.

@pfalcon
Copy link
Contributor

pfalcon commented Oct 4, 2017

@MrSurly : You seem to be missing a lot what MicroPython is, even though it's documented and shown to every contributor on first (and every) contribution: https://github.com/micropython/micropython/wiki/ContributorGuidelines . MicroPython is not CPython, nor there's even an aim to be one. Need CPython? Use CPython. All the other misunderestandings stem from not understanding that.

There're separate APIs for MicroPython, representing minimal'ish subset of CPython APIs, living in separate modules (starting with "u"). Whoever wants to go beyond that, writes a CPython compatible module. The unix port is the reference port of MicroPython, showing how to do it right.

However, other ports add more things to themselves, initially thought to be "conveniences", but has long became "misconveniences", as they confuse people who aren't prepared to read the documentation. These include things like any function beyond core MicroPython API, symbolic addresses accepted by socket functions beyond getaddrinfo(), module symlinks, etc. All these lead for careless newcomers to see the upside down picture of MicroPython world - that it's there to replace CPython for them or that Unix port lacks something. No, other ports have superfluous features. Don't like inconsistency? Feel free to start thinking about removing them.

The same applies to features in general - the more you add, the harder you do it on yourself ("aimed it at my code that worked on the ESP32 and ... it didn't work."). Worse, you do it harder on the users. That's why adhoc port features are frowned upon in the mainline.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants