public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP
@ 2021-07-29 22:41 John Scott
  2021-07-30  9:34 ` Corinna Vinschen
  2021-07-30 16:44 ` Brian Inglis
  0 siblings, 2 replies; 5+ messages in thread
From: John Scott @ 2021-07-29 22:41 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 1307 bytes --]

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:

#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

int main(void) {
	struct addrinfo *res;
	int s = getaddrinfo(NULL, "daytime", &(const struct addrinfo){.ai_flags = AI_PASSIVE, .ai_protocol = IPPROTO_TCP}, &res);
	if(s) {
		fprintf(stderr, "Failed to get address info: %s\n", (s != EAI_SYSTEM) ? gai_strerror(s) : strerror(errno));
		exit(EXIT_FAILURE);
	}

	for(const struct addrinfo *tmp = res; tmp; tmp = tmp->ai_next) {
		int fd = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
		if(fd == -1) {
			perror("Failed to create socket");
		} else if(close(fd) == -1) {
			perror("Failed to close socket");
		}
	}
	freeaddrinfo(res);
}

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()? Remarkably,
changing the service from "daytime" to "http" seems to fix it, which
seems quite strange.

I'm not subscribed, so please CC me on replies.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 252 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP
  2021-07-29 22:41 calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP John Scott
@ 2021-07-30  9:34 ` Corinna Vinschen
  2021-07-30 10:47   ` Corinna Vinschen
  2021-07-30 16:44 ` Brian Inglis
  1 sibling, 1 reply; 5+ messages in thread
From: Corinna Vinschen @ 2021-07-30  9:34 UTC (permalink / raw)
  To: John Scott; +Cc: cygwin

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

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP
  2021-07-30  9:34 ` Corinna Vinschen
@ 2021-07-30 10:47   ` Corinna Vinschen
  2021-07-30 11:02     ` John Scott
  0 siblings, 1 reply; 5+ messages in thread
From: Corinna Vinschen @ 2021-07-30 10:47 UTC (permalink / raw)
  To: cygwin; +Cc: John Scott

On Jul 30 11:34, Corinna Vinschen via Cygwin wrote:
> 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

Just to be precise here, the fact that ai_protocol is IPPROTO_TCP
in this example output is only because of your hints.  If you don't
restrict ai_protocol, you'll get:

    family: 23 socktype 1 protocol 0	AF_INET6, STREAM, any
    family: 2 socktype 1 protocol 0	AF_INET,  STREAM, any

> 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.

I hacked up a patch which is supposed to do exactly that.  In your case
it now returns

  family: 23 socktype 1 protocol 6
  family: 2 socktype 1 protocol 6

and in case you omit the ai_protocol restriction it returns with

  family: 23 socktype 1 protocol 6
  family: 23 socktype 2 protocol 17
  family: 2 socktype 1 protocol 6
  family: 2 socktype 2 protocol 17

rather than with

  family: 23 socktype 0 protocol 0
  family: 2 socktype 0 protocol 0

I've uploaded a new developer snapshot to https://cygwin.com/snapshots

Please give it a try and report back.


Thanks,
Corinna

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP
  2021-07-30 10:47   ` Corinna Vinschen
@ 2021-07-30 11:02     ` John Scott
  0 siblings, 0 replies; 5+ messages in thread
From: John Scott @ 2021-07-30 11:02 UTC (permalink / raw)
  To: cygwin

[-- Attachment #1: Type: text/plain, Size: 281 bytes --]

On Fri, 2021-07-30 at 12:47 +0200, Corinna Vinschen wrote:
> I've uploaded a new developer snapshot to https://cygwin.com/snapshots
> Please give it a try and report back.

Thank you so much! The snapshot works perfectly and now my daytime
server works without code changes.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 252 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP
  2021-07-29 22:41 calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP John Scott
  2021-07-30  9:34 ` Corinna Vinschen
@ 2021-07-30 16:44 ` Brian Inglis
  1 sibling, 0 replies; 5+ messages in thread
From: Brian Inglis @ 2021-07-30 16:44 UTC (permalink / raw)
  To: cygwin; +Cc: John Scott

On 2021-07-29 16:41, John Scott via Cygwin wrote:
> 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()? Remarkably,
> changing the service from "daytime" to "http" seems to fix it, which
> seems quite strange.
> 
> I'm not subscribed, so please CC me on replies.

These obsolete legacy time services have always been available built 
into the inetd server in the inetutils package:

$ info inetutils inetd built-in

"daytime
      Send back the current date and time in a human readable form.  Any
      input is discarded.

time
      Send back the current date and time as a 32-bit integer number,
      nrepresenting the number of seconds since midnight, January 1,
      1900."

You could download the source package to study the implementation.

The time protocol client rdate is available from:

	https://github.com/openbsd/src/tree/master/usr.sbin/rdate

As daytime is text in arbitrary display format (likely ctime(3), 
asctime(3)) telnet, netcat, etc. to the service port was probably used.

For currently supported network time services, Meinberg has for many 
years provided native Windows service ports of the latest releases of 
the ntp.org NTP V4 client/server daemon, including a kernel serial 
driver interface supporting GPS devices with PPS signal pins, the latest 
OpenSSL, a Windows installer, and an interactive monitor to control and 
display service daemon NTP info, and view loopstats and peerstats graphs:

	https://www.meinbergglobal.com/english/sw/ntp.htm#ntp_stable

	https://www.meinbergglobal.com/english/sw/ntp-server-monitor.htm

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

This email may be disturbing to some readers as it contains
too much technical detail. Reader discretion is advised.
[Data in binary units and prefixes, physical quantities in SI.]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-07-30 16:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-29 22:41 calls to socket() fail when calling getaddrinfo() with IPPROTO_TCP John Scott
2021-07-30  9:34 ` Corinna Vinschen
2021-07-30 10:47   ` Corinna Vinschen
2021-07-30 11:02     ` John Scott
2021-07-30 16:44 ` Brian Inglis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).