SWI-Prolog / packages-clib

Assorted external libraries: processes, sockets, MIME, CGI, etc.
8 stars 19 forks source link

tcp_connect address can be a plain port number on Unix but not on Windows #38

Open dgelessus opened 2 years ago

dgelessus commented 2 years ago

An odd OS difference. On Unix (macOS and Linux), one can pass just a port number as the Address into tcp_connect to connect to a local port. On Windows, the same call gives an error, so one has to explicitly pass '':Port or localhost:Port instead.

1 ?- use_module(library(socket)).
true.
2 ?- tcp_connect(8080, Stream, []).
ERROR: Socket error: Cannot assign requested address
ERROR: In:
ERROR:   [14] throw(error(socket_error(wsaeaddrnotavail,'Cannot assign requested address'),_1286))
ERROR:   [12] catch('<garbage_collected>','<garbage_collected>','<garbage_collected>') at c:/program files/swi-prolog/stable/boot/init.pl:562
ERROR:   [10] socket:tcp_connect(8080,_1352,[]) at c:/program files/swi-prolog/stable/library/socket.pl:384
ERROR:    [9] toplevel_call('<garbage_collected>') at c:/program files/swi-prolog/stable/boot/toplevel.pl:1158
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
3 ?- tcp_connect('':8080, Stream, []).
Stream = <stream>(00000000033355D0,0000000003335C30).

According to the docs, tcp_connect/3 actually requires an explicit hostname and shouldn't accept a plain port:

Address is either a Host:Port term or a file name (atom or string). The latter connects to an AF_UNIX socket and requires unix_domain_socket/1.

So the fix would be either to document the Unix behavior and support plain port numbers on Windows as well, or to check and disallow plain port numbers on all platforms. I would vote for the first option, because it avoids breaking existing code - and would also match what SICStus' library(sockets) does 🙂

JanWielemaker commented 2 years ago

I see. In fact, using Wine I get something different: tcp_connect/3 with just a port succeeds, with '':Port raises an exception and using localhost:Port works fine too. I've pushed a patch to initialize the complete address info. No idea how that will work out on the various platforms. It can't be bad to avoid using uninitialized memory though :smile: