Use random name for device socket
For the initial connection between the device and the computer, an adb tunnel is established (with "adb reverse" or "adb forward"). The device-side of the tunnel is a local socket having the hard-coded name "scrcpy". This may cause issues when several scrcpy instances are started in a few seconds for the same device, since they will try to bind the same name. To avoid conflicts, make the client generate a random UID, and append this UID to the local socket name ("scrcpy_01234567").
This commit is contained in:
parent
74e3f8b253
commit
4315be1648
8 changed files with 87 additions and 25 deletions
|
@ -7,8 +7,6 @@
|
||||||
#include "util/net_intr.h"
|
#include "util/net_intr.h"
|
||||||
#include "util/process_intr.h"
|
#include "util/process_intr.h"
|
||||||
|
|
||||||
#define SC_SOCKET_NAME "scrcpy"
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
listen_on_port(struct sc_intr *intr, sc_socket socket, uint16_t port) {
|
listen_on_port(struct sc_intr *intr, sc_socket socket, uint16_t port) {
|
||||||
return net_listen_intr(intr, socket, IPV4_LOCALHOST, port, 1);
|
return net_listen_intr(intr, socket, IPV4_LOCALHOST, port, 1);
|
||||||
|
@ -17,10 +15,11 @@ listen_on_port(struct sc_intr *intr, sc_socket socket, uint16_t port) {
|
||||||
static bool
|
static bool
|
||||||
enable_tunnel_reverse_any_port(struct sc_adb_tunnel *tunnel,
|
enable_tunnel_reverse_any_port(struct sc_adb_tunnel *tunnel,
|
||||||
struct sc_intr *intr, const char *serial,
|
struct sc_intr *intr, const char *serial,
|
||||||
|
const char *device_socket_name,
|
||||||
struct sc_port_range port_range) {
|
struct sc_port_range port_range) {
|
||||||
uint16_t port = port_range.first;
|
uint16_t port = port_range.first;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!sc_adb_reverse(intr, serial, SC_SOCKET_NAME, port,
|
if (!sc_adb_reverse(intr, serial, device_socket_name, port,
|
||||||
SC_ADB_NO_STDOUT)) {
|
SC_ADB_NO_STDOUT)) {
|
||||||
// the command itself failed, it will fail on any port
|
// the command itself failed, it will fail on any port
|
||||||
return false;
|
return false;
|
||||||
|
@ -52,7 +51,7 @@ enable_tunnel_reverse_any_port(struct sc_adb_tunnel *tunnel,
|
||||||
}
|
}
|
||||||
|
|
||||||
// failure, disable tunnel and try another port
|
// failure, disable tunnel and try another port
|
||||||
if (!sc_adb_reverse_remove(intr, serial, SC_SOCKET_NAME,
|
if (!sc_adb_reverse_remove(intr, serial, device_socket_name,
|
||||||
SC_ADB_NO_STDOUT)) {
|
SC_ADB_NO_STDOUT)) {
|
||||||
LOGW("Could not remove reverse tunnel on port %" PRIu16, port);
|
LOGW("Could not remove reverse tunnel on port %" PRIu16, port);
|
||||||
}
|
}
|
||||||
|
@ -78,12 +77,13 @@ enable_tunnel_reverse_any_port(struct sc_adb_tunnel *tunnel,
|
||||||
static bool
|
static bool
|
||||||
enable_tunnel_forward_any_port(struct sc_adb_tunnel *tunnel,
|
enable_tunnel_forward_any_port(struct sc_adb_tunnel *tunnel,
|
||||||
struct sc_intr *intr, const char *serial,
|
struct sc_intr *intr, const char *serial,
|
||||||
|
const char *device_socket_name,
|
||||||
struct sc_port_range port_range) {
|
struct sc_port_range port_range) {
|
||||||
tunnel->forward = true;
|
tunnel->forward = true;
|
||||||
|
|
||||||
uint16_t port = port_range.first;
|
uint16_t port = port_range.first;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (sc_adb_forward(intr, serial, port, SC_SOCKET_NAME,
|
if (sc_adb_forward(intr, serial, port, device_socket_name,
|
||||||
SC_ADB_NO_STDOUT)) {
|
SC_ADB_NO_STDOUT)) {
|
||||||
// success
|
// success
|
||||||
tunnel->local_port = port;
|
tunnel->local_port = port;
|
||||||
|
@ -123,13 +123,14 @@ sc_adb_tunnel_init(struct sc_adb_tunnel *tunnel) {
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sc_adb_tunnel_open(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
sc_adb_tunnel_open(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
||||||
const char *serial, struct sc_port_range port_range,
|
const char *serial, const char *device_socket_name,
|
||||||
bool force_adb_forward) {
|
struct sc_port_range port_range, bool force_adb_forward) {
|
||||||
assert(!tunnel->enabled);
|
assert(!tunnel->enabled);
|
||||||
|
|
||||||
if (!force_adb_forward) {
|
if (!force_adb_forward) {
|
||||||
// Attempt to use "adb reverse"
|
// Attempt to use "adb reverse"
|
||||||
if (enable_tunnel_reverse_any_port(tunnel, intr, serial, port_range)) {
|
if (enable_tunnel_reverse_any_port(tunnel, intr, serial,
|
||||||
|
device_socket_name, port_range)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,12 +140,13 @@ sc_adb_tunnel_open(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
||||||
LOGW("'adb reverse' failed, fallback to 'adb forward'");
|
LOGW("'adb reverse' failed, fallback to 'adb forward'");
|
||||||
}
|
}
|
||||||
|
|
||||||
return enable_tunnel_forward_any_port(tunnel, intr, serial, port_range);
|
return enable_tunnel_forward_any_port(tunnel, intr, serial,
|
||||||
|
device_socket_name, port_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sc_adb_tunnel_close(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
sc_adb_tunnel_close(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
||||||
const char *serial) {
|
const char *serial, const char *device_socket_name) {
|
||||||
assert(tunnel->enabled);
|
assert(tunnel->enabled);
|
||||||
|
|
||||||
bool ret;
|
bool ret;
|
||||||
|
@ -152,7 +154,7 @@ sc_adb_tunnel_close(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
||||||
ret = sc_adb_forward_remove(intr, serial, tunnel->local_port,
|
ret = sc_adb_forward_remove(intr, serial, tunnel->local_port,
|
||||||
SC_ADB_NO_STDOUT);
|
SC_ADB_NO_STDOUT);
|
||||||
} else {
|
} else {
|
||||||
ret = sc_adb_reverse_remove(intr, serial, SC_SOCKET_NAME,
|
ret = sc_adb_reverse_remove(intr, serial, device_socket_name,
|
||||||
SC_ADB_NO_STDOUT);
|
SC_ADB_NO_STDOUT);
|
||||||
|
|
||||||
assert(tunnel->server_socket != SC_SOCKET_NONE);
|
assert(tunnel->server_socket != SC_SOCKET_NONE);
|
||||||
|
|
|
@ -34,14 +34,14 @@ sc_adb_tunnel_init(struct sc_adb_tunnel *tunnel);
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
sc_adb_tunnel_open(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
sc_adb_tunnel_open(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
||||||
const char *serial, struct sc_port_range port_range,
|
const char *serial, const char *device_socket_name,
|
||||||
bool force_adb_forward);
|
struct sc_port_range port_range, bool force_adb_forward);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the tunnel
|
* Close the tunnel
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
sc_adb_tunnel_close(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
sc_adb_tunnel_close(struct sc_adb_tunnel *tunnel, struct sc_intr *intr,
|
||||||
const char *serial);
|
const char *serial, const char *device_socket_name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "util/acksync.h"
|
#include "util/acksync.h"
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
#include "util/net.h"
|
#include "util/net.h"
|
||||||
|
#include "util/rand.h"
|
||||||
#ifdef HAVE_V4L2
|
#ifdef HAVE_V4L2
|
||||||
# include "v4l2_sink.h"
|
# include "v4l2_sink.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -265,6 +266,14 @@ sc_server_on_disconnected(struct sc_server *server, void *userdata) {
|
||||||
// event
|
// event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
scrcpy_generate_uid() {
|
||||||
|
struct sc_rand rand;
|
||||||
|
sc_rand_init(&rand);
|
||||||
|
// Only use 31 bits to avoid issues with signed values on the Java-side
|
||||||
|
return sc_rand_u32(&rand) & 0x7FFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
enum scrcpy_exit_code
|
enum scrcpy_exit_code
|
||||||
scrcpy(struct scrcpy_options *options) {
|
scrcpy(struct scrcpy_options *options) {
|
||||||
static struct scrcpy scrcpy;
|
static struct scrcpy scrcpy;
|
||||||
|
@ -298,7 +307,10 @@ scrcpy(struct scrcpy_options *options) {
|
||||||
|
|
||||||
struct sc_acksync *acksync = NULL;
|
struct sc_acksync *acksync = NULL;
|
||||||
|
|
||||||
|
uint32_t uid = scrcpy_generate_uid();
|
||||||
|
|
||||||
struct sc_server_params params = {
|
struct sc_server_params params = {
|
||||||
|
.uid = uid,
|
||||||
.req_serial = options->serial,
|
.req_serial = options->serial,
|
||||||
.select_usb = options->select_usb,
|
.select_usb = options->select_usb,
|
||||||
.select_tcpip = options->select_tcpip,
|
.select_tcpip = options->select_tcpip,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define SC_DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
|
#define SC_DEVICE_SERVER_PATH "/data/local/tmp/scrcpy-server.jar"
|
||||||
|
|
||||||
#define SC_ADB_PORT_DEFAULT 5555
|
#define SC_ADB_PORT_DEFAULT 5555
|
||||||
|
#define SC_SOCKET_NAME_PREFIX "scrcpy_"
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_server_path(void) {
|
get_server_path(void) {
|
||||||
|
@ -197,6 +198,7 @@ execute_server(struct sc_server *server,
|
||||||
cmd[count++] = p; \
|
cmd[count++] = p; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ADD_PARAM("uid=%08x", params->uid);
|
||||||
ADD_PARAM("log_level=%s", log_level_to_server_string(params->log_level));
|
ADD_PARAM("log_level=%s", log_level_to_server_string(params->log_level));
|
||||||
ADD_PARAM("bit_rate=%" PRIu32, params->bit_rate);
|
ADD_PARAM("bit_rate=%" PRIu32, params->bit_rate);
|
||||||
|
|
||||||
|
@ -364,6 +366,7 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
|
||||||
}
|
}
|
||||||
|
|
||||||
server->serial = NULL;
|
server->serial = NULL;
|
||||||
|
server->device_socket_name = NULL;
|
||||||
server->stopped = false;
|
server->stopped = false;
|
||||||
|
|
||||||
server->video_socket = SC_SOCKET_NONE;
|
server->video_socket = SC_SOCKET_NONE;
|
||||||
|
@ -463,7 +466,8 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// we don't need the adb tunnel anymore
|
// we don't need the adb tunnel anymore
|
||||||
sc_adb_tunnel_close(tunnel, &server->intr, serial);
|
sc_adb_tunnel_close(tunnel, &server->intr, serial,
|
||||||
|
server->device_socket_name);
|
||||||
|
|
||||||
// The sockets will be closed on stop if device_read_info() fails
|
// The sockets will be closed on stop if device_read_info() fails
|
||||||
bool ok = device_read_info(&server->intr, video_socket, info);
|
bool ok = device_read_info(&server->intr, video_socket, info);
|
||||||
|
@ -494,7 +498,8 @@ fail:
|
||||||
|
|
||||||
if (tunnel->enabled) {
|
if (tunnel->enabled) {
|
||||||
// Always leave this function with tunnel disabled
|
// Always leave this function with tunnel disabled
|
||||||
sc_adb_tunnel_close(tunnel, &server->intr, serial);
|
sc_adb_tunnel_close(tunnel, &server->intr, serial,
|
||||||
|
server->device_socket_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -764,13 +769,23 @@ run_server(void *data) {
|
||||||
assert(serial);
|
assert(serial);
|
||||||
LOGD("Device serial: %s", serial);
|
LOGD("Device serial: %s", serial);
|
||||||
|
|
||||||
|
int r = asprintf(&server->device_socket_name, SC_SOCKET_NAME_PREFIX "%08x",
|
||||||
|
params->uid);
|
||||||
|
if (r == -1) {
|
||||||
|
LOG_OOM();
|
||||||
|
goto error_connection_failed;
|
||||||
|
}
|
||||||
|
assert(r == sizeof(SC_SOCKET_NAME_PREFIX) - 1 + 8);
|
||||||
|
assert(server->device_socket_name);
|
||||||
|
|
||||||
ok = push_server(&server->intr, serial);
|
ok = push_server(&server->intr, serial);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
goto error_connection_failed;
|
goto error_connection_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = sc_adb_tunnel_open(&server->tunnel, &server->intr, serial,
|
ok = sc_adb_tunnel_open(&server->tunnel, &server->intr, serial,
|
||||||
params->port_range, params->force_adb_forward);
|
server->device_socket_name, params->port_range,
|
||||||
|
params->force_adb_forward);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
goto error_connection_failed;
|
goto error_connection_failed;
|
||||||
}
|
}
|
||||||
|
@ -778,7 +793,8 @@ run_server(void *data) {
|
||||||
// server will connect to our server socket
|
// server will connect to our server socket
|
||||||
sc_pid pid = execute_server(server, params);
|
sc_pid pid = execute_server(server, params);
|
||||||
if (pid == SC_PROCESS_NONE) {
|
if (pid == SC_PROCESS_NONE) {
|
||||||
sc_adb_tunnel_close(&server->tunnel, &server->intr, serial);
|
sc_adb_tunnel_close(&server->tunnel, &server->intr, serial,
|
||||||
|
server->device_socket_name);
|
||||||
goto error_connection_failed;
|
goto error_connection_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,7 +806,8 @@ run_server(void *data) {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
sc_process_terminate(pid);
|
sc_process_terminate(pid);
|
||||||
sc_process_wait(pid, true); // ignore exit code
|
sc_process_wait(pid, true); // ignore exit code
|
||||||
sc_adb_tunnel_close(&server->tunnel, &server->intr, serial);
|
sc_adb_tunnel_close(&server->tunnel, &server->intr, serial,
|
||||||
|
server->device_socket_name);
|
||||||
goto error_connection_failed;
|
goto error_connection_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,6 +901,7 @@ sc_server_destroy(struct sc_server *server) {
|
||||||
}
|
}
|
||||||
|
|
||||||
free(server->serial);
|
free(server->serial);
|
||||||
|
free(server->device_socket_name);
|
||||||
sc_server_params_destroy(&server->params);
|
sc_server_params_destroy(&server->params);
|
||||||
sc_intr_destroy(&server->intr);
|
sc_intr_destroy(&server->intr);
|
||||||
sc_cond_destroy(&server->cond_stopped);
|
sc_cond_destroy(&server->cond_stopped);
|
||||||
|
|
|
@ -22,6 +22,7 @@ struct sc_server_info {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_server_params {
|
struct sc_server_params {
|
||||||
|
uint32_t uid;
|
||||||
const char *req_serial;
|
const char *req_serial;
|
||||||
enum sc_log_level log_level;
|
enum sc_log_level log_level;
|
||||||
const char *crop;
|
const char *crop;
|
||||||
|
@ -54,6 +55,7 @@ struct sc_server {
|
||||||
// The internal allocated strings are copies owned by the server
|
// The internal allocated strings are copies owned by the server
|
||||||
struct sc_server_params params;
|
struct sc_server_params params;
|
||||||
char *serial;
|
char *serial;
|
||||||
|
char *device_socket_name;
|
||||||
|
|
||||||
sc_thread thread;
|
sc_thread thread;
|
||||||
struct sc_server_info info; // initialized once connected
|
struct sc_server_info info; // initialized once connected
|
||||||
|
|
|
@ -15,7 +15,7 @@ public final class DesktopConnection implements Closeable {
|
||||||
|
|
||||||
private static final int DEVICE_NAME_FIELD_LENGTH = 64;
|
private static final int DEVICE_NAME_FIELD_LENGTH = 64;
|
||||||
|
|
||||||
private static final String SOCKET_NAME = "scrcpy";
|
private static final String SOCKET_NAME_PREFIX = "scrcpy";
|
||||||
|
|
||||||
private final LocalSocket videoSocket;
|
private final LocalSocket videoSocket;
|
||||||
private final FileDescriptor videoFd;
|
private final FileDescriptor videoFd;
|
||||||
|
@ -46,11 +46,22 @@ public final class DesktopConnection implements Closeable {
|
||||||
return localSocket;
|
return localSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DesktopConnection open(boolean tunnelForward, boolean control, boolean sendDummyByte) throws IOException {
|
private static String getSocketName(int uid) {
|
||||||
|
if (uid == -1) {
|
||||||
|
// If no UID is set, use "scrcpy" to simplify using scrcpy-server alone
|
||||||
|
return SOCKET_NAME_PREFIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SOCKET_NAME_PREFIX + String.format("_%08x", uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DesktopConnection open(int uid, boolean tunnelForward, boolean control, boolean sendDummyByte) throws IOException {
|
||||||
|
String socketName = getSocketName(uid);
|
||||||
|
|
||||||
LocalSocket videoSocket;
|
LocalSocket videoSocket;
|
||||||
LocalSocket controlSocket = null;
|
LocalSocket controlSocket = null;
|
||||||
if (tunnelForward) {
|
if (tunnelForward) {
|
||||||
LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME);
|
LocalServerSocket localServerSocket = new LocalServerSocket(socketName);
|
||||||
try {
|
try {
|
||||||
videoSocket = localServerSocket.accept();
|
videoSocket = localServerSocket.accept();
|
||||||
if (sendDummyByte) {
|
if (sendDummyByte) {
|
||||||
|
@ -69,10 +80,10 @@ public final class DesktopConnection implements Closeable {
|
||||||
localServerSocket.close();
|
localServerSocket.close();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
videoSocket = connect(SOCKET_NAME);
|
videoSocket = connect(socketName);
|
||||||
if (control) {
|
if (control) {
|
||||||
try {
|
try {
|
||||||
controlSocket = connect(SOCKET_NAME);
|
controlSocket = connect(socketName);
|
||||||
} catch (IOException | RuntimeException e) {
|
} catch (IOException | RuntimeException e) {
|
||||||
videoSocket.close();
|
videoSocket.close();
|
||||||
throw e;
|
throw e;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import java.util.List;
|
||||||
|
|
||||||
public class Options {
|
public class Options {
|
||||||
private Ln.Level logLevel = Ln.Level.DEBUG;
|
private Ln.Level logLevel = Ln.Level.DEBUG;
|
||||||
|
private int uid = -1; // 31-bit non-negative value, or -1
|
||||||
private int maxSize;
|
private int maxSize;
|
||||||
private int bitRate = 8000000;
|
private int bitRate = 8000000;
|
||||||
private int maxFps;
|
private int maxFps;
|
||||||
|
@ -37,6 +38,14 @@ public class Options {
|
||||||
this.logLevel = logLevel;
|
this.logLevel = logLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getUid() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUid(int uid) {
|
||||||
|
this.uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
public int getMaxSize() {
|
public int getMaxSize() {
|
||||||
return maxSize;
|
return maxSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,11 +66,12 @@ public final class Server {
|
||||||
|
|
||||||
Thread initThread = startInitThread(options);
|
Thread initThread = startInitThread(options);
|
||||||
|
|
||||||
|
int uid = options.getUid();
|
||||||
boolean tunnelForward = options.isTunnelForward();
|
boolean tunnelForward = options.isTunnelForward();
|
||||||
boolean control = options.getControl();
|
boolean control = options.getControl();
|
||||||
boolean sendDummyByte = options.getSendDummyByte();
|
boolean sendDummyByte = options.getSendDummyByte();
|
||||||
|
|
||||||
try (DesktopConnection connection = DesktopConnection.open(tunnelForward, control, sendDummyByte)) {
|
try (DesktopConnection connection = DesktopConnection.open(uid, tunnelForward, control, sendDummyByte)) {
|
||||||
if (options.getSendDeviceMeta()) {
|
if (options.getSendDeviceMeta()) {
|
||||||
Size videoSize = device.getScreenInfo().getVideoSize();
|
Size videoSize = device.getScreenInfo().getVideoSize();
|
||||||
connection.sendDeviceMeta(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight());
|
connection.sendDeviceMeta(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight());
|
||||||
|
@ -178,6 +179,13 @@ public final class Server {
|
||||||
String key = arg.substring(0, equalIndex);
|
String key = arg.substring(0, equalIndex);
|
||||||
String value = arg.substring(equalIndex + 1);
|
String value = arg.substring(equalIndex + 1);
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
case "uid":
|
||||||
|
int uid = Integer.parseInt(value, 0x10);
|
||||||
|
if (uid < -1) {
|
||||||
|
throw new IllegalArgumentException("uid may not be negative (except -1 for 'none'): " + uid);
|
||||||
|
}
|
||||||
|
options.setUid(uid);
|
||||||
|
break;
|
||||||
case "log_level":
|
case "log_level":
|
||||||
Ln.Level level = Ln.Level.valueOf(value.toUpperCase(Locale.ENGLISH));
|
Ln.Level level = Ln.Level.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
options.setLogLevel(level);
|
options.setLogLevel(level);
|
||||||
|
|
Loading…
Reference in a new issue