escl: Add unix socket support

Curl can pass HTTP traffic through a unix socket instead of TCP with the
CURLOPT_UNIX_SOCKET_PATH option.  This is useful if you have a proxy
listening on a local socket between your computer and the scanner.  Now
that URL parsing is centralized, take advantage of this to support an
extended name scheme: escl:unix:/path/to/socket:URL

These names won't be picked up on the network when avahi scans, but they
can be passed manually with -d or added to /etc/sane.d/escl.conf.  If
the existing escl:URL syntax is used, the socket is not set and the curl
option is not used, so existing network connections work the same as
before.

Since local sockets are optional, the current conf parsing scheme
becomes order dependent.  To avoid this, also add an additional "device"
line type to the config parser. If a line starts with "device", the
remainder of the line is treated as a complete device name/URL and
parsed with the URL parsing added in the previous commit.
reorg-descriptions
Benjamin Gordon 2020-03-05 14:53:42 -07:00
rodzic f6832f2a89
commit 48bc45f46b
3 zmienionych plików z 84 dodań i 19 usunięć

Wyświetl plik

@ -8,6 +8,12 @@
# -> put your device ip instead of '123.456.789.10'.
# -> put the port that you use instead of '88'.
# For example, the lines below are for one device, but if you have several devices to use, you can duplicate the lines below as many times as you have devices.
# You can also configure a device on a single line starting with 'device'
# by writing a complete URL and an optional model name.
#device http://123.456.789.10:8080 OptionalModel1
#device https://123.456.789.10:443 "Optional Model 2"
#device unix:/run/proxy.sock:http://123.456.789.10:80
#[device]

Wyświetl plik

@ -68,6 +68,7 @@ escl_free_device(ESCL_Device *current)
free((void*)current->ip_address);
free((void*)current->model_name);
free((void*)current->type);
free(current->unix_socket);
free(current);
return NULL;
}
@ -82,6 +83,8 @@ escl_free_handler(escl_sane_t *handler)
free(handler);
}
SANE_Status escl_parse_name(SANE_String_Const name, ESCL_Device *device);
static SANE_Status
escl_check_and_add_device(ESCL_Device *current)
{
@ -211,23 +214,31 @@ max_string_size(const SANE_String_Const strings[])
static SANE_Device *
convertFromESCLDev(ESCL_Device *cdev)
{
char tmp[PATH_MAX] = { 0 };
char *tmp;
int len;
char unix_path[PATH_MAX+7] = { 0 };
SANE_Device *sdev = (SANE_Device*) calloc(1, sizeof(SANE_Device));
if (!sdev) {
DBG (10, "Sane_Device allocation failure.\n");
return NULL;
}
if (!cdev->https)
snprintf(tmp, sizeof(tmp), "http://%s:%d", cdev->ip_address, cdev->port_nb);
else
snprintf(tmp, sizeof(tmp), "https://%s:%d", cdev->ip_address, cdev->port_nb);
DBG( 1, "Escl add device : %s\n", tmp);
sdev->name = strdup(tmp);
if (!sdev->name) {
DBG (10, "Name allocation failure.\n");
goto freedev;
if (cdev->unix_socket && strlen(cdev->unix_socket)) {
snprintf(unix_path, sizeof(unix_path), "unix:%s:", cdev->unix_socket);
}
len = snprintf(NULL, 0, "%shttp%s://%s:%d",
unix_path, cdev->https ? "s" : "", cdev->ip_address, cdev->port_nb);
len++;
tmp = (char *)malloc(len);
if (!tmp) {
DBG (10, "Name allocation failure.\n");
goto freedev;
}
snprintf(tmp, len, "%shttp%s://%s:%d",
unix_path, cdev->https ? "s" : "", cdev->ip_address, cdev->port_nb);
sdev->name = tmp;
DBG( 1, "Escl add device : %s\n", tmp);
sdev->model = strdup(cdev->model_name);
if (!sdev->model) {
DBG (10, "Model allocation failure.\n");
@ -319,42 +330,75 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line)
SANE_Status status;
static ESCL_Device *escl_device = NULL;
if (strncmp(line, "device", 6) == 0) {
char *name_str = NULL;
char *opt_model = NULL;
line = sanei_config_get_string(line + 6, &name_str);
DBG (10, "New Escl_Device URL [%s].\n", (name_str ? name_str : "VIDE"));
if (!name_str || !*name_str) {
DBG (1, "Escl_Device URL missing.\n");
return SANE_STATUS_INVAL;
}
if (*line) {
line = sanei_config_get_string(line, &opt_model);
DBG (10, "New Escl_Device model [%s].\n", opt_model);
}
escl_free_device(escl_device);
escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device));
if (!escl_device) {
DBG (10, "New Escl_Device allocation failure.\n");
free(name_str);
return (SANE_STATUS_NO_MEM);
}
status = escl_parse_name(name_str, escl_device);
free(name_str);
if (status != SANE_STATUS_GOOD) {
escl_free_device(escl_device);
escl_device = NULL;
return status;
}
escl_device->model_name = opt_model ? opt_model : strdup("Unknown model");
escl_device->type = strdup("flatbed scanner");
}
if (strncmp(line, "[device]", 8) == 0) {
escl_device = escl_free_device(escl_device);
escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device));
if (!escl_device) {
DBG (10, "New Escl_Device allocation failure.");
DBG (10, "New Escl_Device allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
}
if (strncmp(line, "ip", 2) == 0) {
const char *ip_space = sanei_config_skip_whitespace(line + 2);
DBG (10, "New Escl_Device IP [%s].", (ip_space ? ip_space : "VIDE"));
DBG (10, "New Escl_Device IP [%s].\n", (ip_space ? ip_space : "VIDE"));
if (escl_device != NULL && ip_space != NULL) {
DBG (10, "New Escl_Device IP Affected.");
DBG (10, "New Escl_Device IP Affected.\n");
escl_device->ip_address = strdup(ip_space);
}
}
if (sscanf(line, "port %i", &port) == 1 && port != 0) {
DBG (10, "New Escl_Device PORT [%d].", port);
DBG (10, "New Escl_Device PORT [%d].\n", port);
if (escl_device != NULL) {
DBG (10, "New Escl_Device PORT Affected.");
DBG (10, "New Escl_Device PORT Affected.\n");
escl_device->port_nb = port;
}
}
if (strncmp(line, "model", 5) == 0) {
const char *model_space = sanei_config_skip_whitespace(line + 5);
DBG (10, "New Escl_Device MODEL [%s].", (model_space ? model_space : "VIDE"));
DBG (10, "New Escl_Device MODEL [%s].\n", (model_space ? model_space : "VIDE"));
if (escl_device != NULL && model_space != NULL) {
DBG (10, "New Escl_Device MODEL Affected.");
DBG (10, "New Escl_Device MODEL Affected.\n");
escl_device->model_name = strdup(model_space);
}
}
if (strncmp(line, "type", 4) == 0) {
const char *type_space = sanei_config_skip_whitespace(line + 4);
DBG (10, "New Escl_Device TYPE [%s].", (type_space ? type_space : "VIDE"));
DBG (10, "New Escl_Device TYPE [%s].\n", (type_space ? type_space : "VIDE"));
if (escl_device != NULL && type_space != NULL) {
DBG (10, "New Escl_Device TYPE Affected.");
DBG (10, "New Escl_Device TYPE Affected.\n");
escl_device->type = strdup(type_space);
}
}
@ -551,6 +595,15 @@ escl_parse_name(SANE_String_Const name, ESCL_Device *device)
return SANE_STATUS_INVAL;
}
if (strncmp(name, "unix:", 5) == 0) {
SANE_String_Const socket = name + 5;
name = strchr(socket, ':');
if (name == NULL)
return SANE_STATUS_INVAL;
device->unix_socket = strndup(socket, name - socket);
name++;
}
if (strncmp(name, "https://", 8) == 0) {
device->https = SANE_TRUE;
host = name + 8;
@ -1005,4 +1058,9 @@ escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path)
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
if (device->unix_socket != NULL) {
DBG( 1, "Using local socket %s\n", device->unix_socket );
curl_easy_setopt(handle, CURLOPT_UNIX_SOCKET_PATH,
device->unix_socket);
}
}

Wyświetl plik

@ -84,6 +84,7 @@ typedef struct ESCL_Device {
char *ip_address;
char *type;
SANE_Bool https;
char *unix_socket;
} ESCL_Device;
typedef struct capabilities