Send exact number of bytes over a socket - erlang

I have read that in Erlang using gen_tcp the data sent over the socket can be aggregated in a single stream. How can i force the socket to send exactly a specific number of bytes?

TCP is a stream protocol (unlike UDP which is packet oriented) which e.g. means that the receiving application can't tell if the available data comes from one or several send() calls on the client.
You don't really have any control over the number of bytes being sent in a TCP packet, multiple send() calls may result in one TCP packet being received, and one send() call may result in several TCP packets being sent. This is controlled by the OS TCP stack.
In Erlang you can use the the socket option {packet, 1|2|4} to gen_tcp:connect and gen_tcp:listen to create a packet-oriented handling of the TCP data. This inserts a 1,2 or 4 bytes prefix to each send() and the receiving side (assuming it is also erlang and uses the same {packet, N} option) will read data until the sent number of bytes has been received, regardless of how the message was fragmented into TCP packets.
A call to gen_tcp:recv will block until the expected number of bytes has been read. And same for active mode sockets, the message is sent with the expected number of bytes.

Related

Does SCTP really prevent head-of-line blocking?

I've known about SCTP for a decade or so, and although I never got to use it yet, I've always wanted to, because of some of its promising (purported) features:
multi-homing
multiplexing w/o head-of-line blocking
mixed order/unordered delivery on the same connection (aka association)
no TIME_WAIT
no SYN flooding
A Comparison between QUIC and SCTP however claims
SCTP intended to get rid of HOL-Blocking by substreams, but its
Transmission Sequence Number (TSN) couples together the transmission
of all data chunks. [...] As a result, in SCTP if a packet is lost,
all the packets with TSN after this lost packet cannot be received
until it is retransmitted.
That statement surprised me because:
removing head-of-line blocking is a stated goal of SCTP
SCTP does have a per-stream sequence number, see below quote from RFC 4960, which should allow processing per stream, regardless of the association-global TSN
SCTP has been in use in the telecommunications sector for perhaps close to 2 decades, so how could this have been missed?
Internally, SCTP assigns a Stream Sequence Number to each message
passed to it by the SCTP user. On the receiving side, SCTP ensures
that messages are delivered to the SCTP user in sequence within a
given stream. However, while one stream may be blocked waiting for
the next in-sequence user message, delivery from other streams may
proceed.
Also, there is a paper Head-of-line Blocking in TCP and SCTP: Analysis and Measurements that actually measures round-trip time of a multiplexed echo service in the face of package loss and concludes:
Our results reveal that [..] a small number of SCTP streams or SCTP unordered mode can avoid this head-of-line blocking. The alternative solution of multiple TCP connections performs worse in most cases.
The answer is not very scholarly, but at least according to the specification in RFC 4960, SCTP seems capable of circumventing head-of-line blocking. The relevant claim seems to be in Section 7.1.
Note: TCP guarantees in-sequence delivery of data to its upper-layer protocol within a single TCP session. This means that when TCP notices a gap in the received sequence number, it waits until the gap is filled before delivering the data that was received with sequence numbers higher than that of the missing data. On the other hand, SCTP can deliver data to its upper-layer protocol even if there is a gap in TSN if the Stream Sequence Numbers are in sequence for a particular stream (i.e., the missing DATA chunks are for a different stream) or if unordered delivery is indicated. Although this does not affect cwnd, it might affect rwnd calculation.
A dilemma is what does "are in sequence for a particular stream" entail? There is some stipulation about delaying delivery to the upper layer until packages are reordered (see Section 6.6, below), but reordering doesn't seem to be conditioned by filling the gaps at the level of the association. Also note the mention in Section 6.2 on the complex distinction between ACK and delivery to the ULP (Upper Layer Protocol).
Whether other stipulations of the RFC indirectly result in the occurence of HOL, and whether it is effective in real-life implementations and situations - these questions warrant further investigation.
Below are some of the excerpts which I've come across in the RFC and which may be relevant.
RFC 4960, Section 6.2 Acknowledgement on Reception of DATA Chunks
When the receiver's advertised window is 0, the receiver MUST drop any new incoming DATA chunk with a TSN larger than the largest TSN received so far. If the new incoming DATA chunk holds a TSN value less than the largest TSN received so far, then the receiver SHOULD drop the largest TSN held for reordering and accept the new incoming DATA chunk. In either case, if such a DATA chunk is dropped, the receiver MUST immediately send back a SACK with the current receive window showing only DATA chunks received and accepted so far. The dropped DATA chunk(s) MUST NOT be included in the SACK, as they were not accepted.
Under certain circumstances, the data receiver may need to drop DATA chunks that it has received but hasn't released from its receive buffers (i.e., delivered to the ULP). These DATA chunks may have been acked in Gap Ack Blocks. For example, the data receiver may be holding data in its receive buffers while reassembling a fragmented user message from its peer when it runs out of receive buffer space. It may drop these DATA chunks even though it has acknowledged them in Gap Ack Blocks. If a data receiver drops DATA chunks, it MUST NOT include them in Gap Ack Blocks in subsequent SACKs until they are received again via retransmission. In addition, the endpoint should take into account the dropped data when calculating its a_rwnd.
Circumstances which highlight how senders may receive acknowledgement for chunks which are ultimately not delivered to the ULP (Upper Layer Protocol).Note this applies to chunks with TSN higher than the Cumulative TSN (i.e. from Gap Ack Blocks). This together with unreliability of SACK order represent good reasons for the stipulation in Section 7.1 (see below).
RFC 4960, Section 6.6 Ordered and Unordered Delivery
Within a stream, an endpoint MUST deliver DATA chunks received with the U flag set to 0 to the upper layer according to the order of their Stream Sequence Number. If DATA chunks arrive out of order of their Stream Sequence Number, the endpoint MUST hold the received DATA chunks from delivery to the ULP until they are reordered.
This is the only stipulation on ordered delivery within a stream in this section; seemingly, reordering does not depend on filling the gaps in ACK-ed chunks.
RFC 4960, Section 7.1 SCTP Differences from TCP Congestion Control
Gap Ack Blocks in the SCTP SACK carry the same semantic meaning as the TCP SACK. TCP considers the information carried in the SACK as advisory information only. SCTP considers the information carried in the Gap Ack Blocks in the SACK chunk as advisory. In SCTP, any DATA chunk that has been acknowledged by SACK, including DATA that arrived at the receiving end out of order, is not considered fully delivered until the Cumulative TSN Ack Point passes the TSN of the DATA chunk (i.e., the DATA chunk has been acknowledged by the Cumulative TSN Ack field in the SACK).
This is stated from the perspective of the sending endpoint, and is accurate for the reason emphasized in section 6.6 above.
Note: TCP guarantees in-sequence delivery of data to its upper-layer protocol within a single TCP session. This means that when TCP notices a gap in the received sequence number, it waits until the gap is filled before delivering the data that was received with sequence numbers higher than that of the missing data. On the other hand, SCTP can deliver data to its upper-layer protocol even if there is a gap in TSN if the Stream Sequence Numbers are in sequence for a particular stream (i.e., the missing DATA chunks are for a different stream) or if unordered delivery is indicated. Although this does not affect cwnd, it might affect rwnd calculation.
This seems to be the core answer to what interests you.
In support of this argument, the format of the SCTP SACK chunk as exposed here and here.

sendto() incoherent behaviour on UDP socket

I use an UDP socket on iOS. I experience a very strange behaviour when setting it to non-blocking mode and/or simulating a bad connection.
To set the socket in non-blocking mode with the usual fcntl:
fcntl(socketfd, F_SETFL, O_NONBLOCK);
To simulate bad connection I use Network Link Conditioneer with 5/5 in/out packet loss and 50KBps out limit (which guarantees in my case that system out buffer will be full at some point).
I send data with sendto() and I clock the call with clock() and a printf().
Here is the data from my tests, data in ms:
blocking, good connection: min 0/max 929/avg 226/std 111
blocking, bad connection: min 0/max 611/avg 38/std 84
non blocking, good connection: min 0/max 6244/avg 601/std 1071
non blocking, bad connection: min 0/max 5774/avg 400/std 747
I also notice that in case 2 there are many entries with 0 ms, meaning that sendto() has returned immediately, that explains the low average and standard deviation of the case.
At all occasions sendto() returned a positive value corresponding to the number of bytes that were requested to be sent.
Now, there are several things I just can't understand:
in blocking mode, I expect it to block until there are available system buffers to store the data, it seems instead that the data is discarded (since the call returns immediately)
in non-blocking mode, I expect sendto() to return an error when it would block, instead from the data it seems that the call blocks until there is actually space to perform it
The behaviour seems inverted, with the exception that sendto never reports a failure.
What am I doing wrong?
Socket creation:
int socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
// error checks
setsockopt(socketfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
int tos = 0xB8; // VOICE
setsockopt(socketfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
int rc = fcntl(m_iSocket, F_SETFL, O_NONBLOCK);
if (rc != 0) {
// error of fcntl is notified
}
Sending to:
sendto(socketfd, buffer, buffer_length, 0, (struct sockaddr *) &m_sRemoteHost, sizeof(m_sRemoteHost))
How do you know your system's send buffer is getting full? You're just assuming that because you've rate-limited your connection, data backs up in the send buffer. It's more likely that it's getting dropped somewhere else. Since UDP makes no guarantees that any packet will be delivered, any piece of software or hardware anywhere on the packet's path is free to drop it at any time for any reason.
Per the UDP page on Wikipedia:
UDP is a minimal message-oriented transport layer protocol that is
documented in RFC 768. UDP provides no guarantees to the upper layer
protocol for message delivery and the UDP layer retains no state of
UDP messages once sent. For this reason, UDP sometimes is referred to
as Unreliable Datagram Protocol.

Can we have two simultaneous udp streams between 2 specific pairs of IPs and Ports?

I'm trying to inspect and analyze my network traffic. Suddenly I found something confusing. I was thought that packets are splited to streams based on their (SRC_IP, DES_IP, SRC_PORT, SRC_PORT , PROTOCOL_NUM). But now I found two groups of packets with equal above features but interpreted as two different streams in Wireshark:
As you see below, the RTP packets with even packet numbers are a single stream and the RTP packets with odd packet number are another stream, while both has equal (SRC_IP, DES_IP, SRC_PORT, SRC_PORT , PROTOCOL_NUM). Why?
To compare the statistics:
They are interpreted as two different streams:
You are just looking at the UDP traffic from either direction. UDP stream 2 is from 192.168.1.162 to 192.168.1.159 and UDP stream 3 is from 192.168.1.159 to 192.168.1.162.
While there are two UDP streams, there is only one RTP session. This is because the RFC protocol states that you cannot multiplex on the same port. From RTP RFC Section 5.2.
In RTP, multiplexing is provided by the destination transport address
(network address and port number) which is different for each RTP session.
So, yes there are two simultaneous UDP streams, but it is just both hosts talking to each other during a RTP session.

How do I implement a labview server and client to send and receive network packets in parallel?

I am writing two programs (server.vi) and (client.vi). that communicate with each other over a TCP connection.
After the client opens a TCP connection with the server, the server responds with a packet of type "A". The client sends another packet of type "A" back to the server as an acknowledgement. At this point the server starts sending a continous stream of packets of type "B" to the client. And the client starts sending a continous stream of packets with type "C".
This means the sending an receiving of packets with types B and C will be in parallel.
How should I implement something like this in labview?
Here is one idea i have and I was hoping someone could either comment or provide a better suggestion.
the server has two while loops
a. first while loop consists of a TCP read function that receives packets of type "C".
b. second while loop consists of a TCP write function that sends packets of type "B"
the client has two while loops
a. first while loop consists of a TCP write function that sends packets of type "C"
b. second while loop consists of a TCP read function that receives packets of type "B".
This way we are sending and receiving packets of type "B" and "C" in parallel.
All the while loops are independent of each other and are essentially infinite unless both client and server programs are stopped.
Does this make any sense? Is there a more clever / better aproach to doing this?
That sounds like the appropriate way to have two processes run in parallel in LabVIEW, yes.
Have a look at the examples that come with LabVIEW - in LV 2012 there's a 'TCP Communicator - Active.vi' (Help->Find Examples->Networking->TCP & UDP) that looks like it does something similar to what you're describing.
You need to figure out when and how to stop each loop - the example above uses a local variable but you could also do it with a notifier, for example.

what is the byte order of received packets

I want to write a receiver program using raw socket
it will use recvfrom() to receive packets
so I want to check the IP header and tcp header of a packet
when a program sends a packet, it will pay attention to the network byte order and host byte order problem
but for my recever program, when I use recvfrom(sockfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&len);
what is the byte order of the data in the packets? it is network byte order or host byte order?
and how to deal with it?
for this example
http://www.binarytides.com/packet-sniffer-code-in-c-using-linux-sockets-bsd/
the author doesn't take into account the byte order problem when dealing with the received packets, why?
thanks!
what is the byte order of the data in the packets?
The convention is that network order is big endian order. However, the data you receive is the data you sent: nobody magically modifies "integers" to change their endianness.
and how to deal with it?
Use ntohl and ntohs when interpreting integer data
Be aware that bitfield endianness isn't standard
the author doesn't take into account the byte order problem when
dealing with the received packets,
The link you posted shows ntohs and ntohl calls. The author does handle endianness at least to some extent.

Resources