How can I have my server keep sending information while listining with a timeout - sockets

I'm trying to simulate a TCP protocol while using UDP.
I want my server to be able to send chunks of the file the client requested while waiting for acks from the client.
My idea is to send chunk then recv (listen for ack) but that makes it so I can only send chunk nº2 after receiving ack nº1.
Should I just send all of them in a loop and then wait for all the acks in a loop with timeouts?
Or is there way to have recv in the background with a timeout and if it receives an ack it stops the setsockopt timeout feature, and if the timeout occurs it interrupts the current script to resend that chunk?
Edit:
My bad didn't mention it was using C.
OS is linux.
Server-Side Libraries:
packet-format.h
arpa/inet.h
limits.h
netinet/in.h
stdbool.h
stddef.h
stdio.h
stdlib.h
string.h
sys/socket.h
unistd.h
Client-Side Libraries:
packet-format.h
limits.h
netdb.h
stdbool.h
stddef.h
stdio.h
stdlib.h
string.h
unistd.h

Related

Timed out recv producing both EAGAIN and ETIMEDOUT?

For a blocking recv with SO_RCVTIMEO set via setsockopt, what is the difference between EAGAIN and ETIMEDOUT?
I have a blocking recv which is occasionally failing, but it fails (returning -1) in different ways depending on the client which is connected to my server. One client produces "Resource temporarily unavailable", and the other produces "Connection timed out". The socket man page says
if no data has been transferred and the timeout has been reached then
-1 is returned with errno set to EAGAIN or EWOULDBLOCK
with no mention of ETIMEDOUT. I'm guessing that one of the clients is still producing TCP keepalives, but I can't find any docs on this. I'm on Linux 3.10, Centos 7.5.
ETIMEDOUT is almost certainly a response to a previous send(). send() is asynchronous. If it doesn't return -1, all that means is that data was transferred into the local socket send buffer. It is sent, or not sent, asynchronously, and if there was an error in that process it can only be delivered via the next system call: in this case, recv().
It isn't clear that there is any problem here to solve

Can I write() to a socket just after connect() call, but before TCP connection established?

My experiment showed that I can write to a non-blocking socket just after the connect() call, with no TCP connection established yet, and the written data correctly received by the peer after connection occured (asynchronously). Is this guaranteed on Linux / FreeBSD? I mean, will write() return > 0 when the connection is still in progress? Or maybe I was lucky and the TCP connection was successfully established between the connect() and write() calls?
The experiment code:
int fd = socket (PF_INET, SOCK_STREAM, 0);
fcntl(fd, F_SETFL, O_NONBLOCK)
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(_ip_port.port);
addr.sin_addr.s_addr = htonl(_ip_port.ipv4);
int res = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
// HERE: res == -1, errno == 115 (EINPROGRESS)
int r = ::write(fd, "TEST", 4);
// HERE: r == 4
P.S.
I process multiple listening and connecting sockets (incoming and outgoing connections) in single thread and manage them by epoll. Usually, when I want to create a new outgoing connection, I call non-blocking connect() and wait the EPOLLOUT (epoll event) and then write() my data. But I noticed that I can begin writing before the EPOLLOUT and get appropriate result. Can I trust this approach or should I use my old fashion approach?
P.P.S.
I repeated my experiment with a remote host with latency 170ms and got different results: the write() (just after connect()) returned -1 with errno == EAGAIN. So, yes, my first experiment was not fair (connecting to fast localhost), but still I think the "write() just next to connect()" can be used: if write() returned -1 and EAGAIN, I wait the EPOLLOUT and retry writing. But I agree, this is dirty and useless approach.
Can I write() to a socket just after connect() call, but before TCP connection established?
Sure, you can. It's just likely to fail.
Per the POSIX specification of write():
[ECONNRESET]
A write was attempted on a socket that is not connected.
Per the Linux man page for write():
EDESTADDRREQ
fd refers to a datagram socket for which a peer address has
not been set using connect(2).
If the TCP connect has not completed, your write() call will fail.
At least on Linux, the socket is marked as not writable until the [SYN, ACK] is received from the peer. This means the system will not send any application data over the network until the [SYN, ACK] is received.
If the socket is in non-blocking mode, you must use select/poll/epoll to wait until it becomes writable (otherwise write calls will fail with EAGAIN and no data will be enqueued). When the socket becomes writable, the kernel has usually already sent an empty [ACK] message to the peer before the application has had time to write the first data, which results in some unnecessary overhead due to the API design.
What appears to be working is to after calling connect on a non-blocking socket and getting EINPROGRESS, set the socket to blocking and then start to write data. Then the kernel will internally first wait until the [SYN, ACK] is received from the peer and then send the application data and the initial ACK in a single packet, which will avoid that empty [ACK]. Note that the write call will block until [SYN, ACK] is received and will e.g. return -1 with errno ECONNREFUSED, ETIMEDOUT etc. if the connection fails. This approach however does not work in WSL 1 (Windows Subsystem for Linux), which just fails will EPIPE immediately (no SIGPIPE though).
In any case, not much can be done to eliminate this initial round-trip time due to the design of TCP. If the TCP Fast Open (TFO) feature is supported by both endpoints however, and can accept its security issues, this round-trip can be eliminated. See https://lwn.net/Articles/508865/ for more info.

Fiddler doesn't work

Fiddler almost not work for me. Seems the problem only with https.
For example to open https google.com I need to wait around 40 seconds
Screenshots:
immediately after request
after ~40 seconds
Fiddler log:
18:02:46:3326 Fiddler Running...
18:02:46:3922 Windows 8+ AppContainer isolation feature detected.
18:03:09:5427 Assembly 'C:\Program Files (x86)\Fiddler2\CertMaker.dll' was not found. Using default Certificate Generator.
18:03:09:5467 /Fiddler.CertMaker> Using Fiddler.DefaultCertificateProvider+CertEnrollEngine for certificate generation; UseWildcards=False.
18:03:11:3745 HTTPSLint> Warning: ClientHello record was 508 bytes long. Some servers have problems with ClientHello's greater than 255 bytes. githubcom /ssllabs/research/wiki/Long-Handshake-Intolerance
18:03:11:3855 HTTPSLint> Warning: ClientHello record was 508 bytes long. Some servers have problems with ClientHello's greater than 255 bytes. githubcom /ssllabs/research/wiki/Long-Handshake-Intolerance
18:03:11:3895 HTTPSLint> Warning: ClientHello record was 508 bytes long. Some servers have problems with ClientHello's greater than 255 bytes. githubcom /ssllabs/research/wiki/Long-Handshake-Intolerance
18:03:11:3915 HTTPSLint> Warning: ClientHello record was 508 bytes long. Some servers have problems with ClientHello's greater than 255 bytes. githubcom /ssllabs/research/wiki/Long-Handshake-Intolerance
18:03:11:3945 HTTPSLint> Warning: ClientHello record was 508 bytes long. Some servers have problems with ClientHello's greater than 255 bytes. githubcom /ssllabs/research/wiki/Long-Handshake-Intolerance
18:03:20:2192 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6091.
18:03:20:3110 [Fiddler] No HTTP request was received from (chrome:10428) new client socket, port 6134.
18:03:20:3120 [Fiddler] No HTTP request was received from (chrome:10428) new client socket, port 6130.
18:03:28:8160 HTTPSLint> Warning: ClientHello record was 508 bytes long. Some servers have problems with ClientHello's greater than 255 bytes. githubcom /ssllabs/research/wiki/Long-Handshake-Intolerance
18:03:30:2198 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6095.
18:03:30:2198 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6097.
18:03:30:2198 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6099.
18:03:30:2198 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6101.
18:03:50:2219 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6163.
18:03:50:2219 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6141.
18:03:50:2219 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6167.
18:04:10:2230 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6176.
18:04:10:2230 [Fiddler] No HTTPS request was received from (chrome:10428) new client socket, port 6179.
Many times in chrome I see: Waiting for proxy tunnel...and site shows This webpage is not available (ERR_TIMED_OUT)
In EDGE I even can't open http site for all sub requests I see blue up arrow which means fiddler trying to load it (after ~40 seconds I get loaded all that requests)
I tried to reset Internet Properties-> Advanced tab-> Restore advanced settings - it doesn't help me.
Also I tried to restarted my system, also I restarted fiddler after any changes I made.
Fiddler settings:
Certificates generated by CertEnroll engine. I tried to change it to MakeCert. Few times I reset All certificates, also manually removes certificates.
Browsers: Chrome/Firefox
Gateway info in fiddler: No upstream gateway proxy is configured.
Recently I made clear installation of Windows 10.
I do not have any Antivirus.
Windows 10 Pro x64
Fiddler v4.6.2.0
I need fiddler for my work. Please help me
UPDATED:
This is can be issue with Protocols. Currently in fiddler I have next protocols:
fiddler.network.https> HTTPS handshake to www.bing.com (for #4) failed. System.IO.IOException Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. < An existing connection was forcibly closed by the remote host
and
fiddler.network.https> HTTPS handshake to www.google.com.ua (for #23) failed. System.ComponentModel.Win32Exception The client and server cannot communicate, because they do not possess a common algorithm
As I thought the issue was with protocols enabled in Internet Options in Windows and Fiddler protocols.
I ticked Use SSL 3.0 and use TSL 1.0 in Interent properties (all other should be unticked)
in Fiddler protocols I typed: ;ssl3;tls1.0
And after this changes everything works perfectly
Yes, Use SSL 3.0 and use TSL 1.0 in Internet properties for it to work. Previously I also did the same mistake but now working fine. I also checked on fiddler for the same.

socket programming for bad network

client:
socket(), connect() and then
for (1 to 1024) {
write(1024 bytes)
}
exit(0);
server:
socket(), bind(), listen()
while (1) {
accept()
while((n = read()) {
if (n == -1) abort(); /* never happended */
total_read += n
}
close()
}
now, client runs on Mac under NAT and server runs on my VPS (abroad)
generally, it works fine (client send all data and exit & server recv all data)
however, when client is running but suddenly the network is broken for couple minutes(and regain), the client won't exit after a long long time... I kill it with control + C and run it again, the server seems not read the data any more (client is still running)
here is what netstat shows:
client:
tcp4 0 130312 192.168.1.254.58573 A.B.C.D.8888 ESTABLISHED
server:
tcp 0 0 A.B.C.D:8888 a.b.c.d:54566 ESTABLISHED 10970/a.out
tcp 102136 0 A.B.C.D:8888 a.b.c.d:60916 ESTABLISHED -
A.B.C.D is my VPS address
a.b.c.d is my public client address
my quesiton is:
1, why ?
2, server will works fine after restarting, how to write code to get rid of it without restarting ?
In TCP, there's no way to tell that a connection has failed unless you try to send something on the connection. TCP doesn't perform active monitoring of the connection (actually, there are optional "keepalive" packets, but these are not normally sent until the connection has been idle for a couple of hours). When you send something, you'll eventually get an error if there's a timeout waiting for the other machine to return an acknowledgement. But if you're just reading data without sending, you can't tell that the connection has failed -- it just looks like the sender doesn't have anything to send.
You can resolve this by designing your application so that the client is required to send something every N seconds. Then set a timer in the server that detects that you haven't received anything for more than N seconds (you should add a little extra time to allow for transient delays).
When the network is broken what happens is that you clients keep sending data and at some point the socket send buffer gets full (I understand from what you show that you are sending 1024 Bytes, 1024 times, 1MB in total). The default for send buffer could be 16KB (surely less than 1MB). Then when the client tries to write, it gets blocked forever.
BTW, now I'm answering your question I don't know whether eventually after a number of TCP timeouts, TCP gives up and closes the socket making the socket interface return with error. I think that's not happening ... :) - So, connect fails if there is a problem in the network but write and read do not fail.
In the server side, the server gets blocked in read because it never receives the EOF.
Solution:
In the client side use non-blocking sockets, if the network is broken, at some point write will return with error EWOULDBLOCK. Then you will realize the send buffer is full for some reason. At that point, you could clouse the connection and try to connect again. If the network is broken, you will receive an error.
In the server side also use non-blocking sockets and select() function with a timeout. After a few timeouts you may decide there is a problem with the new connection and close it.

FIN,ACK after PSH,ACK

I'm trying to implement a communication between a legacy system and a Linux system but I constantly get one of the following scenarios:
(The legacy system is server, the Linux is client)
Function recv(2) returns 0 (the peer has performed an orderly shutdown.)
> SYN
< SYN, ACK
> ACK
< PSH, ACK (the data)
> FIN, ACK
< ACK
> RST
< FIN, ACK
> RST
> RST
Function connect(2) returns -1 (error)
> SYN
< RST, ACK
When the server have send its data, the client should answer with data, but instead I get a "FIN, ACK"
Why is it like this? How should I interpret this? I'm not that familiar with TCP at this level
When the server have send its data, the client should answer with data, but I instead get a "FIN, ACK" Why is it like this? How should I interpret this?
It could be that once the server has sent the data (line 4) the client closes the socket or terminates prematurely and the operating system closes its socket and sends FIN (line 5). The server replies to FIN with ACK but the client has ceased to exist already and its operating system responds with RST. (I would expect the client OS to silently ignore and discard any TCP segments arriving for a closed connection during the notorious TIME-WAIT state, but that doesn't happen for some reason.)
http://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_termination:
Some host TCP stacks may implement a half-duplex close sequence, as Linux or HP-UX do. If such a host actively closes a connection but still has not read all the incoming data the stack already received from the link, this host sends a RST instead of a FIN (Section 4.2.2.13 in RFC 1122). This allows a TCP application to be sure the remote application has read all the data the former sent—waiting the FIN from the remote side, when it actively closes the connection. However, the remote TCP stack cannot distinguish between a Connection Aborting RST and this Data Loss RST. Both cause the remote stack to throw away all the data it received, but that the application still didn't read
After FIN, PSH, ACK --> One transaction completed
Second request receiving but sending [RST] seq=140 win=0 len=0