$OpenBSD: patch-tmate-ssh-client_c,v 1.1.1.1 2017/02/16 20:06:03 jasper Exp $

From fe81322cc4801860c33b1e31970b8f0f6bf603c7 Mon Sep 17 00:00:00 2001
From: Nicolas Viennot <nicolas@viennot.biz>
Date: Thu, 21 Apr 2016 16:05:52 -0400
Subject: [PATCH] Keep alive the socket to make reconnections work properly

From 27169b7c076376718abf98f7a1a6b484bd579314 Mon Sep 17 00:00:00 2001
From: Nicolas Viennot <nicolas@viennot.biz>
Date: Sun, 5 Jun 2016 12:54:25 -0400
Subject: [PATCH] Add missing incldues for FreeBSD

--- tmate-ssh-client.c.orig	Tue Mar 29 05:30:07 2016
+++ tmate-ssh-client.c	Wed Feb  8 20:14:51 2017
@@ -1,7 +1,8 @@
+#include <netinet/in.h>
 #include <sys/socket.h>
 #include <netinet/tcp.h>
 #include <stdio.h>
-#include <event.h>
+#include <event2/event.h>
 #include <assert.h>
 
 #include "tmate.h"
@@ -165,22 +166,48 @@ static void request_passphrase(struct tmate_ssh_client
 	data->password_cb_private = client;
 }
 
+#define KEEPALIVE_CNT		3
+#define KEEPALIVE_IDLE		20
+#define KEEPALIVE_INTVL		10
+
+static void setup_socket(int fd)
+{
+#define SSO(level, optname, val) ({							\
+	int _flag = val;								\
+	if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) {		\
+		tmate_warn("setsockopt(" #level ", " #optname ", %d) failed", val);	\
+	}										\
+})
+
+	SSO(IPPROTO_TCP, TCP_NODELAY, 1);
+	SSO(SOL_SOCKET, SO_KEEPALIVE, 1);
+#ifdef TCP_KEEPALIVE
+	SSO(IPPROTO_TCP, TCP_KEEPALIVE, KEEPALIVE_IDLE);
+#endif
+#ifdef TCP_KEEPCNT
+	SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT);
+#endif
+#ifdef TCP_KEEPIDLE
+	SSO(IPPROTO_TCP, TCP_KEEPIDLE, KEEPALIVE_IDLE);
+#endif
+#ifdef TCP_KEEPINTVL
+	SSO(IPPROTO_TCP, TCP_KEEPINTVL, KEEPALIVE_INTVL);
+#endif
+#undef SSO
+}
+
 static void init_conn_fd(struct tmate_ssh_client *client)
 {
+	int fd;
+
 	if (client->has_init_conn_fd)
 		return;
 
-	if (ssh_get_fd(client->session) < 0)
+	if ((fd = ssh_get_fd(client->session)) < 0)
 		return;
 
-	{
-	int flag = 1;
-	setsockopt(ssh_get_fd(client->session), IPPROTO_TCP,
-		   TCP_NODELAY, &flag, sizeof(flag));
-	}
-
-	event_set(&client->ev_ssh, ssh_get_fd(client->session),
-		  EV_READ | EV_PERSIST, __on_ssh_client_event, client);
+	setup_socket(fd);
+	event_set(&client->ev_ssh, fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client);
 	event_add(&client->ev_ssh, NULL);
 
 	client->has_init_conn_fd = true;
