summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2013-07-25 12:00:37 (GMT)
committer Denys Vlasenko <vda.linux@googlemail.com>2013-07-25 12:00:37 (GMT)
commit7801148a816a2ab1c2f9437c8992c86722361147 (patch)
tree1da9e43efdfdee33e9ada4bbf86ddcd551ade133
parent688a7e3f0454363e1dfed481e95afcdb818b1c91 (diff)
downloadbusybox-7801148a816a2ab1c2f9437c8992c86722361147.tar.gz
busybox-7801148a816a2ab1c2f9437c8992c86722361147.tar.bz2
Add notes about TCP programming quirks.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--docs/tcp.txt65
1 files changed, 65 insertions, 0 deletions
diff --git a/docs/tcp.txt b/docs/tcp.txt
new file mode 100644
index 0000000..7951e1c
--- /dev/null
+++ b/docs/tcp.txt
@@ -0,0 +1,65 @@
+ Some less-widely known details of TCP connections.
+
+ Properly closing the connection.
+
+After this code sequence:
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ connect(sock, &remote, sizeof(remote));
+ write(sock, buffer, 1000000);
+
+a large block of data is only buffered by kernel, it can't be sent all at once.
+What will happen if we close the socket?
+
+"A host MAY implement a 'half-duplex' TCP close sequence, so that
+ an application that has called close() cannot continue to read
+ data from the connection. If such a host issues a close() call
+ while received data is still pending in TCP, or if new data is
+ received after close() is called, its TCP SHOULD send a RST
+ to show that data was lost."
+
+IOW: if we just close(sock) now, kernel can reset the TCP connection,
+discarding some not-yet sent data.
+
+What can be done about it?
+
+Solution #1: block until sending is done:
+
+ /* When enabled, a close(2) or shutdown(2) will not return until
+ * all queued messages for the socket have been successfully sent
+ * or the linger timeout has been reached.
+ */
+ struct linger {
+ int l_onoff; /* linger active */
+ int l_linger; /* how many seconds to linger for */
+ } linger;
+ linger.l_onoff = 1;
+ linger.l_linger = SOME_NUM;
+ setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
+ close(sock);
+
+Solution #2: tell kernel that you are done sending.
+This makes kernel send FIN, not RST:
+
+ shutdown(sock, SHUT_WR);
+ close(sock);
+
+
+ Defeating Nagle.
+
+Method #1: manually control whether partial sends are allowed:
+
+This prevents partially filled packets being sent:
+
+ int state = 1;
+ setsockopt(fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
+
+and this forces last, partially filled packet (if any) to be sent:
+
+ int state = 0;
+ setsockopt(fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
+
+Method #2: make any write to immediately send data, even if it's partial:
+
+ int state = 1;
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &state, sizeof(state));