+/*
+ * Decide on the string used to identify the connection point between
+ * upstream and downstream (be it a Windows named pipe or a
+ * Unix-domain socket or whatever else).
+ *
+ * I wondered about making this a SHA hash of all sorts of pieces of
+ * the PuTTY configuration - essentially everything PuTTY uses to know
+ * where and how to make a connection, including all the proxy details
+ * (or rather, all the _relevant_ ones - only including settings that
+ * other settings didn't prevent from having any effect), plus the
+ * username. However, I think it's better to keep it really simple:
+ * the connection point identifier is derived from the hostname and
+ * port used to index the host-key cache (not necessarily where we
+ * _physically_ connected to, in cases involving proxies or
+ * CONF_loghost), plus the username if one is specified.
+ *
+ * The per-platform code will quite likely hash or obfuscate this name
+ * in turn, for privacy from other users; failing that, it might
+ * transform it to avoid dangerous filename characters and so on. But
+ * that doesn't matter to us: for us, the point is that two session
+ * configurations which return the same string from this function will
+ * be treated as potentially shareable with each other.
+ */
+char *ssh_share_sockname(const char *host, int port, Conf *conf)
+{
+ char *username = get_remote_username(conf);
+ char *sockname;
+
+ if (port == 22) {
+ if (username)
+ sockname = dupprintf("%s@%s", username, host);
+ else
+ sockname = dupprintf("%s", host);
+ } else {
+ if (username)
+ sockname = dupprintf("%s@%s:%d", username, host, port);
+ else
+ sockname = dupprintf("%s:%d", host, port);
+ }
+
+ sfree(username);
+ return sockname;
+}
+
+static void nullplug_socket_log(Plug plug, int type, SockAddr addr, int port,
+ const char *error_msg, int error_code) {}
+static int nullplug_closing(Plug plug, const char *error_msg, int error_code,
+ int calling_back) { return 0; }
+static int nullplug_receive(Plug plug, int urgent, char *data,
+ int len) { return 0; }
+static void nullplug_sent(Plug plug, int bufsize) {}
+
+int ssh_share_test_for_upstream(const char *host, int port, Conf *conf)
+{
+ static const struct plug_function_table fn_table = {
+ nullplug_socket_log,
+ nullplug_closing,
+ nullplug_receive,
+ nullplug_sent,
+ NULL
+ };
+ struct nullplug {
+ const struct plug_function_table *fn;
+ } np;
+
+ char *sockname, *logtext, *ds_err, *us_err;
+ int result;
+ Socket sock;
+
+ np.fn = &fn_table;
+
+ sockname = ssh_share_sockname(host, port, conf);
+
+ sock = NULL;
+ logtext = ds_err = us_err = NULL;
+ result = platform_ssh_share(sockname, conf, (Plug)&np, (Plug)NULL, &sock,
+ &logtext, &ds_err, &us_err, FALSE, TRUE);
+
+ sfree(logtext);
+ sfree(ds_err);
+ sfree(us_err);
+ sfree(sockname);
+
+ if (result == SHARE_NONE) {
+ assert(sock == NULL);
+ return FALSE;
+ } else {
+ assert(result == SHARE_DOWNSTREAM);
+ sk_close(sock);
+ return TRUE;
+ }
+}
+