calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP
Corinna Vinschen
corinna-cygwin@cygwin.com
Fri Jul 30 09:34:34 GMT 2021
Hi John,
On Jul 29 22:41, John Scott via Cygwin wrote:
> Hi,
>
> I was wondering why my daytime server doesn't work when built for
> Cygwin, and I have been able to narrow it down to this reproducible
> test case:
> [...]
> This code fails with "Failed to create socket: Invalid argument". Does
> anyone have an idea why this happens, given that the arguments to
> socket() come directly from the call to getaddrinfo()?
Welcome to the Windows implementation of getaddrinfo.
Assuming you call getaddrinfo (NULL, "daytime", NULL, &result), you get
the following return from Linux:
family: 2 socktype 1 protocol 6 AF_INET, STREAM, TCP
family: 2 socktype 2 protocol 17 AF_INET, DGRAM, UCP
family: 10 socktype 1 protocol 6 AF_INET6, STREAM, TCP
family: 10 socktype 2 protocol 17 AF_INET6, DGRAM, UCP
The same call on Windows returns:
family: 23 socktype 0 protocol 0 AF_INET6, any, any
family: 2 socktype 0 protocol 0 AF_INET, any, any
If the service supports both, TCP and UDP, then socktype and protocol
are always 0 on Windows. The restriction from the hints parameter
*only* restricts the output for that very field!
I.e., your hints with .ai_protocol = IPPROTO_TCP only restricts the
output of the ai_protocol field, not the output of the ai_socktype
field:
family: 23 socktype 0 protocol 6 AF_INET6, any, TCP
family: 2 socktype 0 protocol 6 AF_INET, any, TCP
On Linux you get the less surprising result
family: 2 socktype 1 protocol 6 AF_INET, STREAM, TCP
family: 10 socktype 1 protocol 6 AF_INET6, STREAM, TCP
> Remarkably,
> changing the service from "daytime" to "http" seems to fix it, which
> seems quite strange.
Yeah, that's a bad joke as well. The reason is that the http service is
defined for TCP only. Not for UDP. As a result, Windows' getaddrinfo
suddenly returns a valid ai_socktype field:
family: 23 socktype 1 protocol 6 AF_INET6, STREAM, TCP
family: 2 socktype 1 protocol 6 AF_INET, STREAM, TCP
Cygwin implements a shallow (~300 lines) wrapper over the WinSock
GetAddrInfoW function and otherwise relies on the values returned by the
OS. However, it already duplicates the returned list to self-allocated
memory, which is required for fork(2) semantics. It should be possible
to improve the wrapper to duplicate entries with socktype and protocol
0-entries, but that would be in the next Cygwin version earliest.
Back to your problem. For the time being, you can easily "fix" your
code by changing the hints:
- int s = getaddrinfo(NULL, "daytime", &(const struct addrinfo){.ai_flags = AI_PASSIVE, .ai_protocol = IPPROTO_TCP}, &res);
+ int s = getaddrinfo(NULL, "daytime", &(const struct addrinfo){.ai_flags = AI_PASSIVE, .ai_socktype = SOCK_STREAM}, &res);
This returns
family: 23 socktype 1 protocol 0 AF_INET6, STREAM, any
family: 2 socktype 1 protocol 0 AF_INET, STREAM, any
The content of the protocol parameter doesn't really matter to socket(2),
so it will work on Cygwin as well as on Linux and others.
HTH,
Corinna
More information about the Cygwin
mailing list