*/
void (*unthrottle) (void *handle, int);
int (*cfg_info) (void *handle);
+ /* Only implemented in the SSH protocol: check whether a
+ * connection-sharing upstream exists for a given configuration. */
+ int (*test_for_upstream)(const char *host, int port, Conf *conf);
const char *name;
int protocol;
int default_port;
raw_provide_logctx,
raw_unthrottle,
raw_cfg_info,
+ NULL /* test_for_upstream */,
"raw",
PROT_RAW,
0
rlogin_provide_logctx,
rlogin_unthrottle,
rlogin_cfg_info,
+ NULL /* test_for_upstream */,
"rlogin",
PROT_RLOGIN,
513
}
}
+static int ssh_test_for_upstream(const char *host, int port, Conf *conf)
+{
+ char *savedhost;
+ int savedport;
+ int ret;
+
+ ssh_hostport_setup(host, port, conf, &savedhost, &savedport, NULL);
+ ret = ssh_share_test_for_upstream(savedhost, savedport, conf);
+ sfree(savedhost);
+
+ return ret;
+}
+
/*
* Connect to specified host and port.
* Returns an error message, or NULL on success.
ssh_provide_logctx,
ssh_unthrottle,
ssh_cfg_info,
+ ssh_test_for_upstream,
"ssh",
PROT_SSH,
22
extern Socket ssh_connection_sharing_init(const char *host, int port,
Conf *conf, Ssh ssh, void **state);
+int ssh_share_test_for_upstream(const char *host, int port, Conf *conf);
void share_got_pkt_from_server(void *ctx, int type,
unsigned char *pkt, int pktlen);
void share_activate(void *state, const char *server_verstring);
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;
+ }
+}
+
/*
* Init function for connection sharing. We either open a listening
* socket and become an upstream, or connect to an existing one and
telnet_provide_logctx,
telnet_unthrottle,
telnet_cfg_info,
+ NULL /* test_for_upstream */,
"telnet",
PROT_TELNET,
23
null_init, null_free, null_reconfig, null_send, null_sendbuffer, null_size,
null_special, null_get_specials, null_connected, null_exitcode, null_sendok,
null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle,
- null_cfg_info, "null", -1, 0
+ null_cfg_info, NULL /* test_for_upstream */, "null", -1, 0
};
Backend loop_backend = {
loop_init, loop_free, null_reconfig, loop_send, null_sendbuffer, null_size,
null_special, null_get_specials, null_connected, null_exitcode, null_sendok,
null_ldisc, null_provide_ldisc, null_provide_logctx, null_unthrottle,
- null_cfg_info, "loop", -1, 0
+ null_cfg_info, NULL /* test_for_upstream */, "loop", -1, 0
};
struct loop_state {
int errors;
int use_subsystem = 0;
int got_host = FALSE;
+ int just_test_share_exists = FALSE;
unsigned long now;
struct winsize size;
--argc;
provide_xrm_string(*++argv);
}
+ } else if (!strcmp(p, "-shareexists")) {
+ just_test_share_exists = TRUE;
} else {
fprintf(stderr, "plink: unknown option \"%s\"\n", p);
errors = 1;
!conf_get_str_nthstrkey(conf, CONF_portfwd, 0))
conf_set_int(conf, CONF_ssh_simple, TRUE);
+ if (just_test_share_exists) {
+ if (!back->test_for_upstream) {
+ fprintf(stderr, "Connection sharing not supported for connection "
+ "type '%s'\n", back->name);
+ return 1;
+ }
+ if (back->test_for_upstream(conf_get_str(conf, CONF_host),
+ conf_get_int(conf, CONF_port), conf))
+ return 0;
+ else
+ return 1;
+ }
+
/*
* Start up the connection.
*/
pty_provide_logctx,
pty_unthrottle,
pty_cfg_info,
+ NULL /* test_for_upstream */,
"pty",
-1,
0
serial_provide_logctx,
serial_unthrottle,
serial_cfg_info,
+ NULL /* test_for_upstream */,
"serial",
PROT_SERIAL,
0
int errors;
int got_host = FALSE;
int use_subsystem = 0;
+ int just_test_share_exists = FALSE;
unsigned long now, next, then;
sklist = NULL;
} else if (!strcmp(p, "-pgpfp")) {
pgp_fingerprints();
exit(1);
+ } else if (!strcmp(p, "-shareexists")) {
+ just_test_share_exists = TRUE;
} else {
fprintf(stderr, "plink: unknown option \"%s\"\n", p);
errors = 1;
logctx = log_init(NULL, conf);
console_provide_logctx(logctx);
+ if (just_test_share_exists) {
+ if (!back->test_for_upstream) {
+ fprintf(stderr, "Connection sharing not supported for connection "
+ "type '%s'\n", back->name);
+ return 1;
+ }
+ if (back->test_for_upstream(conf_get_str(conf, CONF_host),
+ conf_get_int(conf, CONF_port), conf))
+ return 0;
+ else
+ return 1;
+ }
+
/*
* Start up the connection.
*/
serial_provide_logctx,
serial_unthrottle,
serial_cfg_info,
+ NULL /* test_for_upstream */,
"serial",
PROT_SERIAL,
0