Commit 5adf7f97 authored by Philip Withnall's avatar Philip Withnall Committed by Olivier Crête

pseudotcp: Add optional FIN–ACK and RST support

In order to detect cases where the peer closes its connection without an
explicit in-band close message (e.g. in protocols such as Telnet where
there is none), pseudo-TCP needs to grow support for a shutdown
handshake, following the TCP FIN–ACK specification. Arguably it should
have had this all along, but Jingle apparently doesn’t need it.

This adds support for FIN–ACK to the pseudo-TCP implementation. It is
backwards-compatible, only being used if the TCP_OPT_FIN_ACK option is
specified in the SYN segment.

If enabled, full-duplex closes are supported, and the standard method
for notifying a peer of the other end closing its connection (returning
0 from recv()) is used.

Also allow rapidly tearing down a connection, discarding unsent and
unreceived data, by sending an RST segment. This preserves the ability to
do a forced socket closure with pseudo_tcp_socket_close(sock, TRUE).

It also permits graceful socket shutdown in the case where the final ACK
is lost, and one peer gets stuck in the LAST-ACK state: that peer will
eventually re-transmit its FIN segment. The other peer, in the CLOSED
state, will respond with a RST segment, and the first peer will then
reach CLOSED.

References (most useful first):
 • http://tools.ietf.org/html/rfc793#section-3.5http://tools.ietf.org/html/rfc1122#page-87http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.htmlhttp://tools.ietf.org/html/rfc675
Diagram:
 •
http://en.wikipedia.org/wiki/Transmission_Control_Protocol#mediaviewer/File:TCP_CLOSE.svg
parent 480725bd
This diff is collapsed.
/* /*
* This file is part of the Nice GLib ICE library. * This file is part of the Nice GLib ICE library.
* *
* (C) 2010 Collabora Ltd. * (C) 2010, 2014 Collabora Ltd.
* Contact: Youness Alaoui * Contact: Philip Withnall
* *
* The contents of this file are subject to the Mozilla Public License Version * The contents of this file are subject to the Mozilla Public License Version
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
* *
* Contributors: * Contributors:
* Youness Alaoui, Collabora Ltd. * Youness Alaoui, Collabora Ltd.
* Philip Withnall, Collabora Ltd.
* *
* Alternatively, the contents of this file may be used under the terms of the * Alternatively, the contents of this file may be used under the terms of the
* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
...@@ -136,8 +137,21 @@ typedef enum { ...@@ -136,8 +137,21 @@ typedef enum {
* @TCP_SYN_RECEIVED: The socket has received a connection request (SYN) packet. * @TCP_SYN_RECEIVED: The socket has received a connection request (SYN) packet.
* @TCP_ESTABLISHED: The socket is connected * @TCP_ESTABLISHED: The socket is connected
* @TCP_CLOSED: The socket has been closed * @TCP_CLOSED: The socket has been closed
* * @TCP_FIN_WAIT_1: The socket has been closed locally but not remotely
* An enum representing the state of the #PseudoTcpSocket. * (Since: UNRELEASED)
* @TCP_FIN_WAIT_2: The socket has been closed locally but not remotely
* (Since: UNRELEASED)
* @TCP_CLOSING: The socket has been closed locally and remotely
* (Since: UNRELEASED)
* @TCP_TIME_WAIT: The socket has been closed locally and remotely
* (Since: UNRELEASED)
* @TCP_CLOSE_WAIT: The socket has been closed remotely but not locally
* (Since: UNRELEASED)
* @TCP_LAST_ACK: The socket has been closed locally and remotely
* (Since: UNRELEASED)
*
* An enum representing the state of the #PseudoTcpSocket. These states
* correspond to the TCP states in RFC 793.
* <para> See also: #PseudoTcpSocket:state </para> * <para> See also: #PseudoTcpSocket:state </para>
* *
* Since: 0.0.11 * Since: 0.0.11
...@@ -147,7 +161,13 @@ typedef enum { ...@@ -147,7 +161,13 @@ typedef enum {
TCP_SYN_SENT, TCP_SYN_SENT,
TCP_SYN_RECEIVED, TCP_SYN_RECEIVED,
TCP_ESTABLISHED, TCP_ESTABLISHED,
TCP_CLOSED TCP_CLOSED,
TCP_FIN_WAIT_1,
TCP_FIN_WAIT_2,
TCP_CLOSING,
TCP_TIME_WAIT,
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
} PseudoTcpState; } PseudoTcpState;
/** /**
...@@ -175,7 +195,7 @@ typedef enum { ...@@ -175,7 +195,7 @@ typedef enum {
* @PseudoTcpOpened: The #PseudoTcpSocket is now connected * @PseudoTcpOpened: The #PseudoTcpSocket is now connected
* @PseudoTcpReadable: The socket is readable * @PseudoTcpReadable: The socket is readable
* @PseudoTcpWritable: The socket is writable * @PseudoTcpWritable: The socket is writable
* @PseudoTcpClosed: The socket was closed * @PseudoTcpClosed: The socket was closed (both sides)
* @WritePacket: This callback is called when the socket needs to send data. * @WritePacket: This callback is called when the socket needs to send data.
* *
* A structure containing callbacks functions that will be called by the * A structure containing callbacks functions that will be called by the
...@@ -294,8 +314,12 @@ gint pseudo_tcp_socket_send(PseudoTcpSocket *self, const char * buffer, ...@@ -294,8 +314,12 @@ gint pseudo_tcp_socket_send(PseudoTcpSocket *self, const char * buffer,
* @self: The #PseudoTcpSocket object. * @self: The #PseudoTcpSocket object.
* @force: %TRUE to close the socket forcefully, %FALSE to close it gracefully * @force: %TRUE to close the socket forcefully, %FALSE to close it gracefully
* *
* Close the socket. IF @force is set to %FALSE, the socket will finish sending * Close the socket for sending. IF @force is set to %FALSE, the socket will
* pending data before closing. * finish sending pending data before closing.
*
* The socket will only be fully closed once the peer has also closed their end
* of the connection — until that point, pseudo_tcp_socket_recv() can still be
* called to receive data from the peer.
* *
<note> <note>
<para> <para>
......
...@@ -292,6 +292,7 @@ pseudo_tcp_socket_recv ...@@ -292,6 +292,7 @@ pseudo_tcp_socket_recv
pseudo_tcp_socket_send pseudo_tcp_socket_send
pseudo_tcp_socket_close pseudo_tcp_socket_close
pseudo_tcp_socket_is_closed pseudo_tcp_socket_is_closed
pseudo_tcp_socket_is_closed_remotely
pseudo_tcp_socket_get_error pseudo_tcp_socket_get_error
pseudo_tcp_socket_get_next_clock pseudo_tcp_socket_get_next_clock
pseudo_tcp_socket_notify_clock pseudo_tcp_socket_notify_clock
......
...@@ -183,6 +183,8 @@ readable (PseudoTcpSocket *sock, gpointer data) ...@@ -183,6 +183,8 @@ readable (PseudoTcpSocket *sock, gpointer data)
} else { } else {
pseudo_tcp_socket_close (sock, FALSE); pseudo_tcp_socket_close (sock, FALSE);
} }
} else if (len == 0) {
pseudo_tcp_socket_close (sock, FALSE);
} }
} while (len > 0); } while (len > 0);
......
...@@ -138,6 +138,8 @@ static void readable (PseudoTcpSocket *sock, gpointer data) ...@@ -138,6 +138,8 @@ static void readable (PseudoTcpSocket *sock, gpointer data)
exit (-1); exit (-1);
} }
} }
} else if (len == 0) {
pseudo_tcp_socket_close (sock, FALSE);
} }
} while (len > 0); } while (len > 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment