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.
*
* (C) 2010 Collabora Ltd.
* Contact: Youness Alaoui
* (C) 2010, 2014 Collabora Ltd.
* Contact: Philip Withnall
*
* The contents of this file are subject to the Mozilla Public License Version
......@@ -22,6 +22,7 @@
*
* Contributors:
* Youness Alaoui, Collabora Ltd.
* Philip Withnall, Collabora Ltd.
*
* 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
......@@ -136,8 +137,21 @@ typedef enum {
* @TCP_SYN_RECEIVED: The socket has received a connection request (SYN) packet.
* @TCP_ESTABLISHED: The socket is connected
* @TCP_CLOSED: The socket has been closed
*
* An enum representing the state of the #PseudoTcpSocket.
* @TCP_FIN_WAIT_1: The socket has been closed locally but not remotely
* (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>
*
* Since: 0.0.11
......@@ -147,7 +161,13 @@ typedef enum {
TCP_SYN_SENT,
TCP_SYN_RECEIVED,
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;
/**
......@@ -175,7 +195,7 @@ typedef enum {
* @PseudoTcpOpened: The #PseudoTcpSocket is now connected
* @PseudoTcpReadable: The socket is readable
* @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.
*
* 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,
* @self: The #PseudoTcpSocket object.
* @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
* pending data before closing.
* Close the socket for sending. IF @force is set to %FALSE, the socket will
* 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>
<para>
......
......@@ -292,6 +292,7 @@ pseudo_tcp_socket_recv
pseudo_tcp_socket_send
pseudo_tcp_socket_close
pseudo_tcp_socket_is_closed
pseudo_tcp_socket_is_closed_remotely
pseudo_tcp_socket_get_error
pseudo_tcp_socket_get_next_clock
pseudo_tcp_socket_notify_clock
......
......@@ -183,6 +183,8 @@ readable (PseudoTcpSocket *sock, gpointer data)
} else {
pseudo_tcp_socket_close (sock, FALSE);
}
} else if (len == 0) {
pseudo_tcp_socket_close (sock, FALSE);
}
} while (len > 0);
......
......@@ -138,6 +138,8 @@ static void readable (PseudoTcpSocket *sock, gpointer data)
exit (-1);
}
}
} else if (len == 0) {
pseudo_tcp_socket_close (sock, FALSE);
}
} 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