mirror of
https://github.com/upa/mscp.git
synced 2026-02-04 03:24:58 +08:00
add -g option to specify TCP cc algorithm
This commit introduce SSH_OPTIONS_CCALGO option to the libssh patch and add -g CONGESTION option to mscp.
This commit is contained in:
@@ -56,6 +56,7 @@ struct mscp_opts {
|
||||
#define MSCP_SSH_MAX_CIPHER_STR 32
|
||||
#define MSCP_SSH_MAX_HMAC_STR 32
|
||||
#define MSCP_SSH_MAX_COMP_STR 32 /* yes, no, zlib, zlib@openssh.com, none */
|
||||
#define MSCP_SSH_MAX_CCALGO_STR 16
|
||||
#define MSCP_SSH_MAX_PASSWORD 128
|
||||
#define MSCP_SSH_MAX_PASSPHRASE 128
|
||||
|
||||
@@ -72,6 +73,7 @@ struct mscp_ssh_opts {
|
||||
char cipher[MSCP_SSH_MAX_CIPHER_STR]; /** cipher spec */
|
||||
char hmac[MSCP_SSH_MAX_HMAC_STR]; /** hmacp spec */
|
||||
char compress[MSCP_SSH_MAX_COMP_STR]; /** yes, no, zlib@openssh.com */
|
||||
char ccalgo[MSCP_SSH_MAX_CCALGO_STR]; /** TCP cc algorithm */
|
||||
|
||||
char password[MSCP_SSH_MAX_PASSWORD]; /** password auth passowrd */
|
||||
char passphrase[MSCP_SSH_MAX_PASSPHRASE]; /** passphrase for private key */
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
|
||||
index 7103f303..c64eb39d 100644
|
||||
--- a/ConfigureChecks.cmake
|
||||
+++ b/ConfigureChecks.cmake
|
||||
@@ -258,6 +258,7 @@ if (UNIX)
|
||||
check_library_exists(util forkpty "" HAVE_LIBUTIL)
|
||||
check_function_exists(cfmakeraw HAVE_CFMAKERAW)
|
||||
check_function_exists(__strtoull HAVE___STRTOULL)
|
||||
+ check_symbol_exists(TCP_CONGESTION "netinet/tcp.h" HAVE_TCP_CONGESTION)
|
||||
endif (UNIX)
|
||||
|
||||
set(LIBSSH_REQUIRED_LIBRARIES ${_REQUIRED_LIBRARIES} CACHE INTERNAL "libssh required system libraries")
|
||||
diff --git a/config.h.cmake b/config.h.cmake
|
||||
index 1357615b..1e915ead 100644
|
||||
--- a/config.h.cmake
|
||||
+++ b/config.h.cmake
|
||||
@@ -237,6 +237,8 @@
|
||||
|
||||
#cmakedefine HAVE_GCC_BOUNDED_ATTRIBUTE 1
|
||||
|
||||
+#cmakedefine HAVE_TCP_CONGESTION 1
|
||||
+
|
||||
/* Define to 1 if you want to enable GSSAPI */
|
||||
#cmakedefine WITH_GSSAPI 1
|
||||
|
||||
diff --git a/include/libssh/buffer.h b/include/libssh/buffer.h
|
||||
index a55a1b40..e34e075c 100644
|
||||
--- a/include/libssh/buffer.h
|
||||
@@ -12,10 +37,18 @@ index a55a1b40..e34e075c 100644
|
||||
int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len);
|
||||
|
||||
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
|
||||
index 7857a77b..3eef7a16 100644
|
||||
index 7857a77b..6b4d481c 100644
|
||||
--- a/include/libssh/libssh.h
|
||||
+++ b/include/libssh/libssh.h
|
||||
@@ -833,6 +833,7 @@ LIBSSH_API const char* ssh_get_hmac_in(ssh_session session);
|
||||
@@ -402,6 +402,7 @@ enum ssh_options_e {
|
||||
SSH_OPTIONS_GSSAPI_AUTH,
|
||||
SSH_OPTIONS_GLOBAL_KNOWNHOSTS,
|
||||
SSH_OPTIONS_NODELAY,
|
||||
+ SSH_OPTIONS_CCALGO,
|
||||
SSH_OPTIONS_PUBLICKEY_ACCEPTED_TYPES,
|
||||
SSH_OPTIONS_PROCESS_CONFIG,
|
||||
SSH_OPTIONS_REKEY_DATA,
|
||||
@@ -833,6 +834,7 @@ LIBSSH_API const char* ssh_get_hmac_in(ssh_session session);
|
||||
LIBSSH_API const char* ssh_get_hmac_out(ssh_session session);
|
||||
|
||||
LIBSSH_API ssh_buffer ssh_buffer_new(void);
|
||||
@@ -23,7 +56,7 @@ index 7857a77b..3eef7a16 100644
|
||||
LIBSSH_API void ssh_buffer_free(ssh_buffer buffer);
|
||||
#define SSH_BUFFER_FREE(x) \
|
||||
do { if ((x) != NULL) { ssh_buffer_free(x); x = NULL; } } while(0)
|
||||
@@ -843,6 +844,8 @@ LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
|
||||
@@ -843,6 +845,8 @@ LIBSSH_API void *ssh_buffer_get(ssh_buffer buffer);
|
||||
LIBSSH_API uint32_t ssh_buffer_get_len(ssh_buffer buffer);
|
||||
LIBSSH_API int ssh_session_set_disconnect_message(ssh_session session, const char *message);
|
||||
|
||||
@@ -32,6 +65,18 @@ index 7857a77b..3eef7a16 100644
|
||||
#ifndef LIBSSH_LEGACY_0_4
|
||||
#include "libssh/legacy.h"
|
||||
#endif
|
||||
diff --git a/include/libssh/session.h b/include/libssh/session.h
|
||||
index d3e5787c..15183d1b 100644
|
||||
--- a/include/libssh/session.h
|
||||
+++ b/include/libssh/session.h
|
||||
@@ -232,6 +232,7 @@ struct ssh_session_struct {
|
||||
int gss_delegate_creds;
|
||||
int flags;
|
||||
int nodelay;
|
||||
+ char *ccalgo;
|
||||
bool config_processed;
|
||||
uint8_t options_seen[SOC_MAX];
|
||||
uint64_t rekey_data;
|
||||
diff --git a/include/libssh/sftp.h b/include/libssh/sftp.h
|
||||
index c855df8a..0fcdb9b8 100644
|
||||
--- a/include/libssh/sftp.h
|
||||
@@ -158,6 +203,106 @@ index e0068015..cc0caf35 100644
|
||||
/**
|
||||
* @brief Ensure the buffer has at least a certain preallocated size.
|
||||
*
|
||||
diff --git a/src/connect.c b/src/connect.c
|
||||
index 57e37e63..c02397d5 100644
|
||||
--- a/src/connect.c
|
||||
+++ b/src/connect.c
|
||||
@@ -156,6 +156,20 @@ static int set_tcp_nodelay(socket_t socket)
|
||||
sizeof(opt));
|
||||
}
|
||||
|
||||
+static int set_tcp_ccalgo(socket_t socket, const char *ccalgo)
|
||||
+{
|
||||
+#ifdef HAVE_TCP_CONGESTION
|
||||
+ return setsockopt(socket,
|
||||
+ IPPROTO_TCP,
|
||||
+ TCP_CONGESTION,
|
||||
+ (void *)ccalgo,
|
||||
+ strlen(ccalgo));
|
||||
+#else
|
||||
+ errno = ENOTSUP;
|
||||
+ return -1;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
@@ -256,6 +270,18 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host,
|
||||
}
|
||||
}
|
||||
|
||||
+ if (session->opts.ccalgo) {
|
||||
+ rc = set_tcp_ccalgo(s, session->opts.ccalgo);
|
||||
+ if (rc < 0) {
|
||||
+ ssh_set_error(session, SSH_FATAL,
|
||||
+ "Failed to set TCP_CONGESTION on socket: %s",
|
||||
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
|
||||
+ ssh_connect_socket_close(s);
|
||||
+ s = -1;
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
errno = 0;
|
||||
rc = connect(s, itr->ai_addr, itr->ai_addrlen);
|
||||
if (rc == -1 && (errno != 0) && (errno != EINPROGRESS)) {
|
||||
diff --git a/src/options.c b/src/options.c
|
||||
index 49aaefa2..9f7360c3 100644
|
||||
--- a/src/options.c
|
||||
+++ b/src/options.c
|
||||
@@ -210,6 +210,7 @@ int ssh_options_copy(ssh_session src, ssh_session *dest)
|
||||
new->opts.gss_delegate_creds = src->opts.gss_delegate_creds;
|
||||
new->opts.flags = src->opts.flags;
|
||||
new->opts.nodelay = src->opts.nodelay;
|
||||
+ new->opts.ccalgo = src->opts.ccalgo;
|
||||
new->opts.config_processed = src->opts.config_processed;
|
||||
new->common.log_verbosity = src->common.log_verbosity;
|
||||
new->common.callbacks = src->common.callbacks;
|
||||
@@ -450,6 +451,10 @@ int ssh_options_set_algo(ssh_session session,
|
||||
* Set it to disable Nagle's Algorithm (TCP_NODELAY) on the
|
||||
* session socket. (int, 0=false)
|
||||
*
|
||||
+ * - SSH_OPTIONS_CCALGO
|
||||
+ * Set it to specify TCP congestion control algorithm on the
|
||||
+ * session socket (Linux only). (int, 0=false)
|
||||
+ *
|
||||
* - SSH_OPTIONS_PROCESS_CONFIG
|
||||
* Set it to false to disable automatic processing of per-user
|
||||
* and system-wide OpenSSH configuration files. LibSSH
|
||||
@@ -1013,6 +1018,20 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
session->opts.nodelay = (*x & 0xff) > 0 ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
+ case SSH_OPTIONS_CCALGO:
|
||||
+ v = value;
|
||||
+ if (v == NULL || v[0] == '\0') {
|
||||
+ ssh_set_error_invalid(session);
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ SAFE_FREE(session->opts.ccalgo);
|
||||
+ session->opts.ccalgo = strdup(v);
|
||||
+ if (session->opts.ccalgo == NULL) {
|
||||
+ ssh_set_error_oom(session);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
case SSH_OPTIONS_PROCESS_CONFIG:
|
||||
if (value == NULL) {
|
||||
ssh_set_error_invalid(session);
|
||||
diff --git a/src/session.c b/src/session.c
|
||||
index 6025c133..6b197526 100644
|
||||
--- a/src/session.c
|
||||
+++ b/src/session.c
|
||||
@@ -108,6 +108,7 @@ ssh_session ssh_new(void)
|
||||
session->opts.fd = -1;
|
||||
session->opts.compressionlevel = 7;
|
||||
session->opts.nodelay = 0;
|
||||
+ session->opts.ccalgo = NULL;
|
||||
|
||||
session->opts.flags = SSH_OPT_FLAG_PASSWORD_AUTH |
|
||||
SSH_OPT_FLAG_PUBKEY_AUTH |
|
||||
diff --git a/src/sftp.c b/src/sftp.c
|
||||
index e01012a8..702623a0 100644
|
||||
--- a/src/sftp.c
|
||||
|
||||
14
src/main.c
14
src/main.c
@@ -21,7 +21,8 @@ void usage(bool print_help) {
|
||||
"Usage: mscp [vqDHdNh] [-n nr_conns] [-m coremask] [-u max_startups]\n"
|
||||
" [-s min_chunk_sz] [-S max_chunk_sz] [-a nr_ahead] [-b buf_sz]\n"
|
||||
" [-l login_name] [-p port] [-F ssh_config] [-i identity_file]\n"
|
||||
" [-c cipher_spec] [-M hmac_spec] [-C compress] source ... target\n"
|
||||
" [-c cipher_spec] [-M hmac_spec] [-C compress] [-g congestion]\n"
|
||||
" source ... target\n"
|
||||
"\n");
|
||||
|
||||
if (!print_help)
|
||||
@@ -51,6 +52,7 @@ void usage(bool print_help) {
|
||||
" -M HMAC hmac spec\n"
|
||||
" -C COMPRESS enable compression: "
|
||||
"yes, no, zlib, zlib@openssh.com\n"
|
||||
" -g CONGESTION specify TCP congestion control algorithm\n"
|
||||
" -H disable hostkey check\n"
|
||||
" -d increment ssh debug output level\n"
|
||||
" -N enable Nagle's algorithm (default disabled)\n"
|
||||
@@ -202,7 +204,8 @@ int main(int argc, char **argv)
|
||||
memset(&o, 0, sizeof(o));
|
||||
o.severity = MSCP_SEVERITY_WARN;
|
||||
|
||||
while ((ch = getopt(argc, argv, "n:m:u:s:S:a:b:vqDrl:p:i:F:c:M:C:HdNh")) != -1) {
|
||||
while ((ch = getopt(argc, argv,
|
||||
"n:m:u:s:S:a:b:vqDrl:p:i:F:c:M:C:g:HdNh")) != -1) {
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
o.nr_threads = atoi(optarg);
|
||||
@@ -287,6 +290,13 @@ int main(int argc, char **argv)
|
||||
}
|
||||
strncpy(s.compress, optarg, MSCP_SSH_MAX_COMP_STR);
|
||||
break;
|
||||
case 'g':
|
||||
if (strlen(optarg) > MSCP_SSH_MAX_CCALGO_STR - 1) {
|
||||
fprintf(stderr, "long ccalgo string: %s\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
strncpy(s.ccalgo, optarg, MSCP_SSH_MAX_CCALGO_STR);
|
||||
break;
|
||||
case 'H':
|
||||
s.no_hostkey_check = true;
|
||||
break;
|
||||
|
||||
@@ -109,6 +109,7 @@ static PyObject *wrap_mscp_init(PyObject *self, PyObject *args, PyObject *kw)
|
||||
"cipher", /* const char * */
|
||||
"hmac", /* const char * */
|
||||
"compress", /* const char * */
|
||||
"ccalgo", /* const char * */
|
||||
"password", /* const char * */
|
||||
"passphrase", /* const char * */
|
||||
|
||||
@@ -117,10 +118,10 @@ static PyObject *wrap_mscp_init(PyObject *self, PyObject *args, PyObject *kw)
|
||||
"enable_nagle", /* bool */
|
||||
NULL,
|
||||
};
|
||||
const char *fmt = "si" "|" "ii" "kkk" "s" "iii" "ssss" "sssss" "ipp";
|
||||
const char *fmt = "si" "|" "ii" "kkk" "s" "iii" "ssss" "ssssss" "ipp";
|
||||
char *coremask = NULL;
|
||||
char *login_name = NULL, *port = NULL, *config = NULL, *identity = NULL;
|
||||
char *cipher = NULL, *hmac = NULL, *compress = NULL;
|
||||
char *cipher = NULL, *hmac = NULL, *compress = NULL, *ccalgo = NULL;
|
||||
char *password = NULL, *passphrase = NULL;
|
||||
|
||||
struct instance *i;
|
||||
@@ -154,6 +155,7 @@ static PyObject *wrap_mscp_init(PyObject *self, PyObject *args, PyObject *kw)
|
||||
&cipher,
|
||||
&hmac,
|
||||
&compress,
|
||||
&ccalgo,
|
||||
&password,
|
||||
&passphrase,
|
||||
&i->so.debug_level,
|
||||
@@ -179,6 +181,8 @@ static PyObject *wrap_mscp_init(PyObject *self, PyObject *args, PyObject *kw)
|
||||
strncpy(i->so.hmac, hmac, MSCP_SSH_MAX_HMAC_STR - 1);
|
||||
if (compress)
|
||||
strncpy(i->so.compress, compress, MSCP_SSH_MAX_COMP_STR - 1);
|
||||
if (ccalgo)
|
||||
strncpy(i->so.ccalgo, ccalgo, MSCP_SSH_MAX_CCALGO_STR - 1);
|
||||
if (password)
|
||||
strncpy(i->so.password, password, MSCP_SSH_MAX_PASSWORD - 1);
|
||||
if (passphrase)
|
||||
|
||||
@@ -64,6 +64,12 @@ static int ssh_set_opts(ssh_session ssh, struct mscp_ssh_opts *opts)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_specified(opts->ccalgo) &&
|
||||
ssh_options_set(ssh, SSH_OPTIONS_CCALGO, opts->ccalgo) < 0) {
|
||||
mscp_set_error("failed to set cclago");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if NOT specified to enable Nagle's algorithm, disable it (set TCP_NODELAY) */
|
||||
if (!opts->enable_nagle) {
|
||||
int v = 1;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
test_e2e.py: End-to-End test for mscp executable.
|
||||
"""
|
||||
|
||||
import platform
|
||||
import pytest
|
||||
import os
|
||||
|
||||
@@ -268,6 +269,21 @@ def test_compression(mscp, src_prefix, dst_prefix, compress):
|
||||
src.cleanup()
|
||||
dst.cleanup()
|
||||
|
||||
@pytest.mark.parametrize("src_prefix, dst_prefix", param_remote_prefix)
|
||||
def test_ccalgo(mscp, src_prefix, dst_prefix):
|
||||
src = File("src", size = 1024 * 1024).make()
|
||||
dst = File("dst").make()
|
||||
if platform.system() == "Darwin":
|
||||
# Darwin does not support TCP_CONGESTION
|
||||
algo = "cubic"
|
||||
run = run2ng
|
||||
elif platform.system() == "Linux":
|
||||
# Linux supports TCP_CONGESTION
|
||||
with open("/proc/sys/net/ipv4/tcp_allowed_congestion_control", r) as f:
|
||||
algo = f.read().strip().split().pop()
|
||||
run = run2ok
|
||||
run([mscp, "-H", "-vvv", "-g", algo, src_prefix + src.path, dst_prefix + "dst"])
|
||||
|
||||
|
||||
testhost = "mscptestlocalhost"
|
||||
testhost_prefix = "{}:{}/".format(testhost, os.getcwd()) # use current dir
|
||||
|
||||
@@ -121,6 +121,7 @@ param_invalid_kwargs = [
|
||||
{ "cipher": "invalid" },
|
||||
{ "hmac": "invalid"},
|
||||
{ "compress": "invalid"},
|
||||
{ "ccalgo": "invalid"},
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("kw", param_invalid_kwargs)
|
||||
|
||||
Reference in New Issue
Block a user