diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2013-09-17 16:24:01 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2013-09-17 16:24:01 +0200 |
| commit | d7ea34ee710fe97fc57235dce165fcc5f50a512a (patch) | |
| tree | 4d6aea04b91c2bd984bc18aae52ad09aedb71756 /docs | |
| parent | 32ed30d96b56ea7322218061f09e62feda9948e3 (diff) | |
| download | busybox-w32-d7ea34ee710fe97fc57235dce165fcc5f50a512a.tar.gz busybox-w32-d7ea34ee710fe97fc57235dce165fcc5f50a512a.tar.bz2 busybox-w32-d7ea34ee710fe97fc57235dce165fcc5f50a512a.zip | |
Documentation update
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/tcp.txt | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/docs/tcp.txt b/docs/tcp.txt index 766766387..2000f3110 100644 --- a/docs/tcp.txt +++ b/docs/tcp.txt | |||
| @@ -18,8 +18,11 @@ What will happen if we close the socket? | |||
| 18 | received after close() is called, its TCP SHOULD send a RST | 18 | received after close() is called, its TCP SHOULD send a RST |
| 19 | to show that data was lost." | 19 | to show that data was lost." |
| 20 | 20 | ||
| 21 | IOW: if we just close(sock) now, kernel can reset the TCP connection, | 21 | IOW: if we just close(sock) now, kernel can reset the TCP connection |
| 22 | discarding some not-yet sent data. | 22 | (send RST packet). |
| 23 | |||
| 24 | This is problematic for two reasons: it discards some not-yet sent | ||
| 25 | data, and it may be reported as error, not EOF, on peer's side. | ||
| 23 | 26 | ||
| 24 | What can be done about it? | 27 | What can be done about it? |
| 25 | 28 | ||
| @@ -46,14 +49,14 @@ This makes kernel send FIN after all data is written: | |||
| 46 | 49 | ||
| 47 | However, experiments on Linux 3.9.4 show that kernel can return from | 50 | However, experiments on Linux 3.9.4 show that kernel can return from |
| 48 | shutdown() and from close() before all data is sent, | 51 | shutdown() and from close() before all data is sent, |
| 49 | and if peer sends any data to us after this, kernel stll responds with | 52 | and if peer sends any data to us after this, kernel still responds with |
| 50 | RST before all our data is sent. | 53 | RST before all our data is sent. |
| 51 | 54 | ||
| 52 | In practice the protocol in use often does not allow peer to send | 55 | In practice the protocol in use often does not allow peer to send |
| 53 | such data to us, in which case this solution is acceptable. | 56 | such data to us, in which case this solution is acceptable. |
| 54 | 57 | ||
| 55 | If you know that peer is going to close its end after it sees our FIN | 58 | Solution #3: if you know that peer is going to close its end after it sees |
| 56 | (as EOF), it might be a good idea to perform a read after shutdown(). | 59 | our FIN (as EOF), it might be a good idea to perform a read after shutdown(). |
| 57 | When read finishes with 0-sized result, we conclude that peer received all | 60 | When read finishes with 0-sized result, we conclude that peer received all |
| 58 | the data, saw EOF, and closed its end. | 61 | the data, saw EOF, and closed its end. |
| 59 | 62 | ||
| @@ -61,6 +64,14 @@ However, this incurs small performance penalty (we run for a longer time) | |||
| 61 | and requires safeguards (nonblocking reads, timeouts etc) against | 64 | and requires safeguards (nonblocking reads, timeouts etc) against |
| 62 | malicious peers which don't close the connection. | 65 | malicious peers which don't close the connection. |
| 63 | 66 | ||
| 67 | Solutions #1 and #2 can be combined: | ||
| 68 | |||
| 69 | /* ...set up struct linger... then: */ | ||
| 70 | setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); | ||
| 71 | shutdown(sock, SHUT_WR); | ||
| 72 | /* At this point, kernel sent FIN packet, not RST, to the peer, */ | ||
| 73 | /* even if there is buffered read data from the peer. */ | ||
| 74 | close(sock); | ||
| 64 | 75 | ||
| 65 | Defeating Nagle. | 76 | Defeating Nagle. |
| 66 | 77 | ||
