diff --git a/app/meson.build b/app/meson.build index befe1658..3a5cb12a 100644 --- a/app/meson.build +++ b/app/meson.build @@ -207,6 +207,7 @@ if get_option('buildtype') == 'debug' 'tests/test_cli.c', 'src/cli.c', 'src/options.c', + 'src/util/net.c', 'src/util/str.c', 'src/util/strbuf.c', 'src/util/term.c', diff --git a/app/scrcpy.1 b/app/scrcpy.1 index 399fd172..7438118b 100644 --- a/app/scrcpy.1 +++ b/app/scrcpy.1 @@ -203,6 +203,18 @@ Enable "show touches" on start, restore the initial value on exit. It only shows physical touches (not clicks from scrcpy). +.TP +.BI "\-\-tunnel\-host " ip +Set the IP address of the adb tunnel to reach the scrcpy server. This option automatically enables --force-adb-forward. + +Default is localhost. + +.TP +.BI "\-\-tunnel\-port " port +Set the TCP port of the adb tunnel to reach the scrcpy server. This option automatically enables --force-adb-forward. + +Default is 0 (not forced): the local port used for establishing the tunnel will be used. + .TP .BI "\-\-v4l2-sink " /dev/videoN Output to v4l2loopback device. diff --git a/app/src/cli.c b/app/src/cli.c index aa71c659..f00611a7 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -9,6 +9,7 @@ #include "options.h" #include "util/log.h" +#include "util/net.h" #include "util/str.h" #include "util/strbuf.h" #include "util/term.h" @@ -46,6 +47,8 @@ #define OPT_V4L2_SINK 1027 #define OPT_DISPLAY_BUFFER 1028 #define OPT_V4L2_BUFFER 1029 +#define OPT_TUNNEL_HOST 1030 +#define OPT_TUNNEL_PORT 1031 struct sc_option { char shortopt; @@ -330,6 +333,25 @@ static const struct sc_option options[] = { "on exit.\n" "It only shows physical touches (not clicks from scrcpy).", }, + { + .longopt_id = OPT_TUNNEL_HOST, + .longopt = "tunnel-host", + .argdesc = "ip", + .text = "Set the IP address of the adb tunnel to reach the scrcpy " + "server. This option automatically enables " + "--force-adb-forward.\n" + "Default is localhost.", + }, + { + .longopt_id = OPT_TUNNEL_PORT, + .longopt = "tunnel-port", + .argdesc = "port", + .text = "Set the TCP port of the adb tunnel to reach the scrcpy " + "server. This option automatically enables " + "--force-adb-forward.\n" + "Default is 0 (not forced): the local port used for " + "establishing the tunnel will be used.", + }, #ifdef HAVE_V4L2 { .longopt_id = OPT_V4L2_SINK, @@ -1127,6 +1149,21 @@ parse_record_format(const char *optarg, enum sc_record_format *format) { return false; } +static bool +parse_ip(const char *optarg, uint32_t *ipv4) { + return net_parse_ipv4(optarg, ipv4); +} + +static bool +parse_port(const char *optarg, uint16_t *port) { + long value; + if (!parse_integer_arg(optarg, &value, false, 0, 0xFFFF, "port")) { + return false; + } + *port = (uint16_t) value; + return true; +} + static enum sc_record_format guess_record_format(const char *filename) { size_t len = strlen(filename); @@ -1199,6 +1236,16 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[], return false; } break; + case OPT_TUNNEL_HOST: + if (!parse_ip(optarg, &opts->tunnel_host)) { + return false; + } + break; + case OPT_TUNNEL_PORT: + if (!parse_port(optarg, &opts->tunnel_port)) { + return false; + } + break; case 'n': opts->control = false; break; diff --git a/app/src/options.c b/app/src/options.c index 82f25342..074bdf08 100644 --- a/app/src/options.c +++ b/app/src/options.c @@ -19,6 +19,8 @@ const struct scrcpy_options scrcpy_options_default = { .first = DEFAULT_LOCAL_PORT_RANGE_FIRST, .last = DEFAULT_LOCAL_PORT_RANGE_LAST, }, + .tunnel_host = 0, + .tunnel_port = 0, .shortcut_mods = { .data = {SC_MOD_LALT, SC_MOD_LSUPER}, .count = 2, diff --git a/app/src/options.h b/app/src/options.h index 434225b9..82d094cd 100644 --- a/app/src/options.h +++ b/app/src/options.h @@ -77,6 +77,8 @@ struct scrcpy_options { enum sc_record_format record_format; enum sc_keyboard_input_mode keyboard_input_mode; struct sc_port_range port_range; + uint32_t tunnel_host; + uint16_t tunnel_port; struct sc_shortcut_mods shortcut_mods; uint16_t max_size; uint32_t bit_rate; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 40bf72a8..61087681 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -345,6 +345,8 @@ scrcpy(struct scrcpy_options *options) { .log_level = options->log_level, .crop = options->crop, .port_range = options->port_range, + .tunnel_host = options->tunnel_host, + .tunnel_port = options->tunnel_port, .max_size = options->max_size, .bit_rate = options->bit_rate, .max_fps = options->max_fps, diff --git a/app/src/server.c b/app/src/server.c index 3f12db62..78127d2d 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -202,8 +202,9 @@ execute_server(struct sc_server *server, } static bool -connect_and_read_byte(struct sc_intr *intr, sc_socket socket, uint16_t port) { - bool ok = net_connect_intr(intr, socket, IPV4_LOCALHOST, port); +connect_and_read_byte(struct sc_intr *intr, sc_socket socket, + uint32_t tunnel_host, uint16_t tunnel_port) { + bool ok = net_connect_intr(intr, socket, tunnel_host, tunnel_port); if (!ok) { return false; } @@ -220,13 +221,13 @@ connect_and_read_byte(struct sc_intr *intr, sc_socket socket, uint16_t port) { } static sc_socket -connect_to_server(struct sc_server *server, uint32_t attempts, sc_tick delay) { - uint16_t port = server->tunnel.local_port; +connect_to_server(struct sc_server *server, uint32_t attempts, sc_tick delay, + uint32_t host, uint16_t port) { do { LOGD("Remaining connection attempts: %d", (int) attempts); sc_socket socket = net_socket(); if (socket != SC_SOCKET_NONE) { - bool ok = connect_and_read_byte(&server->intr, socket, port); + bool ok = connect_and_read_byte(&server->intr, socket, host, port); if (ok) { // it worked! return socket; @@ -352,9 +353,20 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) { goto fail; } } else { + uint32_t tunnel_host = server->params.tunnel_host; + if (!tunnel_host) { + tunnel_host = IPV4_LOCALHOST; + } + + uint16_t tunnel_port = server->params.tunnel_port; + if (!tunnel_port) { + tunnel_port = tunnel->local_port; + } + uint32_t attempts = 100; sc_tick delay = SC_TICK_FROM_MS(100); - video_socket = connect_to_server(server, attempts, delay); + video_socket = connect_to_server(server, attempts, delay, tunnel_host, + tunnel_port); if (video_socket == SC_SOCKET_NONE) { goto fail; } @@ -364,8 +376,8 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) { if (control_socket == SC_SOCKET_NONE) { goto fail; } - bool ok = net_connect_intr(&server->intr, control_socket, - IPV4_LOCALHOST, tunnel->local_port); + bool ok = net_connect_intr(&server->intr, control_socket, tunnel_host, + tunnel_port); if (!ok) { goto fail; } diff --git a/app/src/server.h b/app/src/server.h index 3859c328..cb1fadbb 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -29,6 +29,8 @@ struct sc_server_params { const char *codec_options; const char *encoder_name; struct sc_port_range port_range; + uint32_t tunnel_host; + uint16_t tunnel_port; uint16_t max_size; uint32_t bit_rate; uint16_t max_fps;