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

-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to