This is the mail archive of the
cygwin
mailing list for the Cygwin project.
Re: TCP_CORK (aka TCP_NOPUSH) does not work
On 2019-07-30 15:30, Lavrentiev, Anton (NIH/NLM/NCBI) [C] via cygwin wrote:
> Consider the following code:
> $ cat cork.c
> #include <arpa/inet.h>
> #include <netinet/in.h>
> #include <netinet/tcp.h>
> #include <unistd.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <sys/socket.h>
> #include <sys/types.h>
> #if defined(TCP_NOPUSH) && !defined(TCP_CORK)
> # define TCP_CORK TCP_NOPUSH
> #endif
For POSIX only non-Nagle TCP_NODELAY is required:
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_tcp.h.html
and even then says:
"The implementation need not allow the value of the option to be set via
setsockopt() or retrieved via getsockopt()."
TCP_CORK is Linux only; TCP_NOPUSH is BSD only; Windows does its own thing:
https://baus.net/on-tcp_cork/
https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options
Regular SO options on Windows:
https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options
You can abuse Nagle to get similar behaviour cross-platform:
https://stackoverflow.com/a/22118709
> int main(int argc, const char* argv[])
> {
> union {
> struct sockaddr_in in;
> struct sockaddr sa;
> } addr;
> int sock, cork = 1;
>
> memset(&addr, 0, sizeof(addr));
> if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
> perror("socket");
> addr.in.sin_family = AF_INET;
> addr.in.sin_addr.s_addr = inet_addr(argv[1]);
> addr.in.sin_port = htons((unsigned short) atoi(argv[2]));
> if (connect(sock, &addr.sa, sizeof(addr.in)) < 0)
> perror("connect");
> if (setsockopt(sock, IPPROTO_TCP, TCP_CORK, (char*) &cork, sizeof(cork)) != 0)
> perror("cork");
> return 0;
> }
> When compiled and run under Cygwin, the last syscall, setsockopt(), returns
> an error, Protocol not available:
> gcc cork.c
> ./a.exe 8.8.8.8 443
> cork: Protocol not available
This is error ENOPROTOOPT, where the message is misleading, but as suggested by
the name, means that the socket option is not supported for that protocol;
getsockopt(3p/3posix) says: "The option is not supported by the protocol."
getsockopt(2) for Linux and FreeBSD say: "The option is unknown at the level
indicated." and given the POSIX statement above, that error should be treated as
a warning to do something different.
> The same code works under Linux just fine. I straced both.
> gcc cork.c
> ./a.out 8.8.8.8 443
> Any ideas? Is TCP_NOPUSH (which is a BSDism, BTW) not actually usable on
Cygwin? If not, why is it in the header file <netinet/tcp.h>?
If a socket option is defined, perhaps for compatibility, it should either be
used or ignored, rather than giving an error.
If you are not going to support a socket option, and generate an error, it would
be better to not define the option and generate the error at compile time,
instead of failing at run time.
--
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.
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple