MEDIUM: stream-interface: provide a generic stream_sock_read0() function

This function is used by the data layer when a zero has been read over a
connection. At the moment it only handles sockets and nothing else. Once
the complete split is done between buffers and stream interfaces, it should
become possible to work regardless on the connection type.
diff --git a/src/sock_raw.c b/src/sock_raw.c
index 5b20f2f..991b46b 100644
--- a/src/sock_raw.c
+++ b/src/sock_raw.c
@@ -44,7 +44,6 @@
 
 /* main event functions used to move data between sockets and buffers */
 static void sock_raw_read(struct connection *conn);
-static void sock_raw_read0(struct stream_interface *si);
 
 
 #if defined(CONFIG_HAP_LINUX_SPLICE)
@@ -436,7 +435,7 @@
 	b->flags |= BF_READ_NULL;
 	if (b->flags & BF_AUTO_CLOSE)
 		buffer_shutw_now(b);
-	sock_raw_read0(si);
+	stream_sock_read0(si);
 	return;
 
  out_error:
@@ -591,55 +590,6 @@
 }
 
 
-/*
- * This function propagates a null read received on a connection. It updates
- * the stream interface. If the stream interface has SI_FL_NOHALF, we also
- * forward the close to the write side.
- */
-static void sock_raw_read0(struct stream_interface *si)
-{
-	si->ib->flags &= ~BF_SHUTR_NOW;
-	if (si->ib->flags & BF_SHUTR)
-		return;
-	si->ib->flags |= BF_SHUTR;
-	si->ib->rex = TICK_ETERNITY;
-	si->flags &= ~SI_FL_WAIT_ROOM;
-
-	if (si->state != SI_ST_EST && si->state != SI_ST_CON)
-		return;
-
-	if (si->ob->flags & BF_SHUTW)
-		goto do_close;
-
-	if (si->flags & SI_FL_NOHALF) {
-		/* we have to shut before closing, otherwise some short messages
-		 * may never leave the system, especially when there are remaining
-		 * unread data in the socket input buffer, or when nolinger is set.
-		 * However, if SI_FL_NOLINGER is explicitly set, we know there is
-		 * no risk so we close both sides immediately.
-		 */
-		if (si->flags & SI_FL_NOLINGER) {
-			si->flags &= ~SI_FL_NOLINGER;
-			setsockopt(si_fd(si), SOL_SOCKET, SO_LINGER,
-				   (struct linger *) &nolinger, sizeof(struct linger));
-		}
-		goto do_close;
-	}
-
-	/* otherwise that's just a normal read shutdown */
-	conn_data_stop_recv(&si->conn);
-	return;
-
- do_close:
-	conn_data_close(&si->conn);
-	fd_delete(si_fd(si));
-	si->state = SI_ST_DIS;
-	si->exp = TICK_ETERNITY;
-	if (si->release)
-		si->release(si);
-	return;
-}
-
 /* stream sock operations */
 struct sock_ops sock_raw = {
 	.update  = stream_int_update_conn,
diff --git a/src/stream_interface.c b/src/stream_interface.c
index 6be0354..17f2447 100644
--- a/src/stream_interface.c
+++ b/src/stream_interface.c
@@ -898,6 +898,55 @@
 	conn_data_stop_both(conn);
 }
 
+/*
+ * This function propagates a null read received on a socket-based connection.
+ * It updates the stream interface. If the stream interface has SI_FL_NOHALF,
+ * the close is also forwarded to the write side as an abort. This function is
+ * still socket-specific as it handles a setsockopt() call to set the SO_LINGER
+ * state on the socket.
+ */
+void stream_sock_read0(struct stream_interface *si)
+{
+	si->ib->flags &= ~BF_SHUTR_NOW;
+	if (si->ib->flags & BF_SHUTR)
+		return;
+	si->ib->flags |= BF_SHUTR;
+	si->ib->rex = TICK_ETERNITY;
+	si->flags &= ~SI_FL_WAIT_ROOM;
+
+	if (si->state != SI_ST_EST && si->state != SI_ST_CON)
+		return;
+
+	if (si->ob->flags & BF_SHUTW)
+		goto do_close;
+
+	if (si->flags & SI_FL_NOHALF) {
+		/* we want to immediately forward this close to the write side */
+		if (si->flags & SI_FL_NOLINGER) {
+			si->flags &= ~SI_FL_NOLINGER;
+			setsockopt(si_fd(si), SOL_SOCKET, SO_LINGER,
+				   (struct linger *) &nolinger, sizeof(struct linger));
+		}
+		/* force flag on ssl to keep session in cache */
+		if (si->conn.data->shutw)
+			si->conn.data->shutw(&si->conn, 0);
+		goto do_close;
+	}
+
+	/* otherwise that's just a normal read shutdown */
+	conn_data_stop_recv(&si->conn);
+	return;
+
+ do_close:
+	conn_data_close(&si->conn);
+	fd_delete(si_fd(si));
+	si->state = SI_ST_DIS;
+	si->exp = TICK_ETERNITY;
+	if (si->release)
+		si->release(si);
+	return;
+}
+
 
 /*
  * Local variables: