escl: Refactor name handling

Scanners are currently passed around by name, which is actually a URL.
Each function parses the URL a little bit, depending on what it needs,
and then sets the same curl options.

This refactors parsing out into a single escl_parse_name() function
called from sane_open and then passes around the resulting ESCL_Device
instead of the raw name.  To set up the curl handle, the new
escl_curl_url() reconstructs a URL from the parsed ESCL_Device and sets
the appropriate options on the handle.  Each place that makes a curl
call is updated to use the new function.
reorg-descriptions
Benjamin Gordon 2020-03-05 14:32:14 -07:00
rodzic 0033357120
commit f6832f2a89
7 zmienionych plików z 162 dodań i 97 usunięć

Wyświetl plik

@ -46,7 +46,7 @@ static int num_devices = 0;
typedef struct Handled {
struct Handled *next;
SANE_String_Const name;
ESCL_Device *device;
char *result;
ESCL_ScanParam param;
SANE_Option_Descriptor opt[NUM_OPTIONS];
@ -72,6 +72,16 @@ escl_free_device(ESCL_Device *current)
return NULL;
}
void
escl_free_handler(escl_sane_t *handler)
{
if (handler == NULL)
return;
escl_free_device(handler->device);
free(handler);
}
static SANE_Status
escl_check_and_add_device(ESCL_Device *current)
{
@ -155,6 +165,9 @@ escl_device_add(int port_nb, const char *model_name, char *ip_address, char *typ
if (strcmp(type, "_uscan._tcp") != 0 && strcmp(type, "http") != 0) {
snprintf(tmp, sizeof(tmp), "%s SSL", model_name);
current->https = SANE_TRUE;
} else {
current->https = SANE_FALSE;
}
model = (char*)(tmp[0] != 0 ? tmp : model_name);
current->model_name = strdup(model);
@ -205,7 +218,7 @@ convertFromESCLDev(ESCL_Device *cdev)
return NULL;
}
if (strcmp(cdev->type, "_uscan._tcp") == 0 || strcmp(cdev->type, "http") == 0)
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);
@ -402,13 +415,13 @@ sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only)
* \return status (if everything is OK, status = SANE_STATUS_GOOD)
*/
static SANE_Status
init_options(SANE_String_Const name, escl_sane_t *s)
init_options(const ESCL_Device *device, escl_sane_t *s)
{
DBG (10, "escl init_options\n");
SANE_Status status = SANE_STATUS_GOOD;
int i = 0;
if (name == NULL)
if (device == NULL)
return (SANE_STATUS_INVAL);
memset (s->opt, 0, sizeof (s->opt));
memset (s->val, 0, sizeof (s->val));
@ -528,6 +541,43 @@ init_options(SANE_String_Const name, escl_sane_t *s)
return (status);
}
SANE_Status
escl_parse_name(SANE_String_Const name, ESCL_Device *device)
{
SANE_String_Const host = NULL;
SANE_String_Const port_str = NULL;
DBG(10, "escl_parse_name\n");
if (name == NULL || device == NULL) {
return SANE_STATUS_INVAL;
}
if (strncmp(name, "https://", 8) == 0) {
device->https = SANE_TRUE;
host = name + 8;
} else if (strncmp(name, "http://", 7) == 0) {
device->https = SANE_FALSE;
host = name + 7;
} else {
DBG(1, "Unknown URL scheme in %s", name);
return SANE_STATUS_INVAL;
}
port_str = strchr(host, ':');
if (port_str == NULL) {
DBG(1, "Port missing from URL: %s", name);
return SANE_STATUS_INVAL;
}
port_str++;
device->port_nb = atoi(port_str);
if (device->port_nb < 1 || device->port_nb > 65535) {
DBG(1, "Invalid port number in URL: %s", name);
return SANE_STATUS_INVAL;
}
device->ip_address = strndup(host, port_str - host - 1);
return SANE_STATUS_GOOD;
}
/**
* \fn SANE_Status sane_open(SANE_String_Const name, SANE_Handle *h)
* \brief Function that establishes a connection with the device named by 'name',
@ -546,23 +596,39 @@ sane_open(SANE_String_Const name, SANE_Handle *h)
if (name == NULL)
return (SANE_STATUS_INVAL);
status = escl_status(name);
if (status != SANE_STATUS_GOOD)
return (status);
handler = (escl_sane_t *)calloc(1, sizeof(escl_sane_t));
if (handler == NULL)
return (SANE_STATUS_NO_MEM);
handler->name = strdup(name);
if (!handler->name) {
DBG (10, "Handle Name allocation failure.\n");
return (SANE_STATUS_NO_MEM);
ESCL_Device *device = calloc(1, sizeof(ESCL_Device));
if (device == NULL) {
DBG (10, "Handle device allocation failure.\n");
return SANE_STATUS_NO_MEM;
}
handler->scanner = escl_capabilities(name, &status);
if (status != SANE_STATUS_GOOD)
status = escl_parse_name(name, device);
if (status != SANE_STATUS_GOOD) {
escl_free_device(device);
return status;
}
status = escl_status(device);
if (status != SANE_STATUS_GOOD) {
escl_free_device(device);
return (status);
status = init_options(name, handler);
if (status != SANE_STATUS_GOOD)
}
handler = (escl_sane_t *)calloc(1, sizeof(escl_sane_t));
if (handler == NULL) {
escl_free_device(device);
return (SANE_STATUS_NO_MEM);
}
handler->device = device; // Handler owns device now.
handler->scanner = escl_capabilities(device, &status);
if (status != SANE_STATUS_GOOD) {
escl_free_handler(handler);
return (status);
}
status = init_options(device, handler);
if (status != SANE_STATUS_GOOD) {
escl_free_handler(handler);
return (status);
}
handler->ps.depth = 8;
handler->ps.last_frame = SANE_TRUE;
handler->ps.format = SANE_FRAME_RGB;
@ -570,8 +636,10 @@ sane_open(SANE_String_Const name, SANE_Handle *h)
handler->ps.lines = MM_TO_PIXEL(handler->val[OPT_BR_Y].w, 300.0);
handler->ps.bytes_per_line = handler->ps.pixels_per_line * 3;
status = sane_get_parameters(handler, 0);
if (status != SANE_STATUS_GOOD)
if (status != SANE_STATUS_GOOD) {
escl_free_handler(handler);
return (status);
}
handler->cancel = SANE_FALSE;
handler->write_scan_data = SANE_FALSE;
handler->decompress_scan_data = SANE_FALSE;
@ -597,7 +665,7 @@ sane_cancel(SANE_Handle h)
handler->scanner->tmp = NULL;
}
handler->cancel = SANE_TRUE;
escl_scanner(handler->name, handler->result);
escl_scanner(handler->device, handler->result);
}
/**
@ -610,7 +678,7 @@ sane_close(SANE_Handle h)
{
DBG (10, "escl sane_close\n");
if (h != NULL) {
free(h);
escl_free_handler(h);
h = NULL;
}
}
@ -727,8 +795,10 @@ sane_start(SANE_Handle h)
int he = 0;
int bps = 0;
if (handler->name == NULL)
if (handler->device == NULL) {
DBG(1, "Missing handler device.\n");
return (SANE_STATUS_INVAL);
}
handler->cancel = SANE_FALSE;
handler->write_scan_data = SANE_FALSE;
handler->decompress_scan_data = SANE_FALSE;
@ -775,10 +845,10 @@ sane_start(SANE_Handle h)
DBG (10, "Default Color allocation failure.\n");
return (SANE_STATUS_NO_MEM);
}
handler->result = escl_newjob(handler->scanner, handler->name, &status);
handler->result = escl_newjob(handler->scanner, handler->device, &status);
if (status != SANE_STATUS_GOOD)
return (status);
status = escl_scan(handler->scanner, handler->name, handler->result);
status = escl_scan(handler->scanner, handler->device, handler->result);
if (status != SANE_STATUS_GOOD)
return (status);
if (!strcmp(handler->scanner->default_format, "image/jpeg"))
@ -905,3 +975,34 @@ sane_set_io_mode(SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ n
{
return (SANE_STATUS_UNSUPPORTED);
}
/**
* \fn void escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path)
* \brief Uses the device info in 'device' and the path from 'path' to construct
* a full URL. Sets this URL and any necessary connection options into
* 'handle'.
*/
void
escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path)
{
int url_len;
char *url;
url_len = snprintf(NULL, 0, "%s://%s:%d%s",
(device->https ? "https" : "http"), device->ip_address,
device->port_nb, path);
url_len++;
url = (char *)malloc(url_len);
snprintf(url, url_len, "%s://%s:%d%s",
(device->https ? "https" : "http"), device->ip_address,
device->port_nb, path);
DBG( 1, "escl_curl_url: URL: %s\n", url );
curl_easy_setopt(handle, CURLOPT_URL, url);
free(url);
if (device->https) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
}

Wyświetl plik

@ -79,10 +79,11 @@ typedef struct {
typedef struct ESCL_Device {
struct ESCL_Device *next;
char *model_name;
int port_nb;
char *model_name;
int port_nb;
char *ip_address;
char *type;
char *type;
SANE_Bool https;
} ESCL_Device;
typedef struct capabilities
@ -158,13 +159,16 @@ enum
ESCL_Device *escl_devices(SANE_Status *status);
SANE_Status escl_device_add(int port_nb, const char *model_name,
char *ip_address, char *type);
SANE_Status escl_status(SANE_String_Const name);
capabilities_t *escl_capabilities(SANE_String_Const name, SANE_Status *status);
char *escl_newjob(capabilities_t *scanner, SANE_String_Const name,
SANE_Status escl_status(const ESCL_Device *device);
capabilities_t *escl_capabilities(const ESCL_Device *device, SANE_Status *status);
char *escl_newjob(capabilities_t *scanner, const ESCL_Device *device,
SANE_Status *status);
SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name,
SANE_Status escl_scan(capabilities_t *scanner, const ESCL_Device *device,
char *result);
void escl_scanner(SANE_String_Const name, char *result);
void escl_scanner(const ESCL_Device *device, char *result);
typedef void CURL;
void escl_curl_url(CURL *handle, const ESCL_Device *device, SANE_String_Const path);
unsigned char *escl_crop_surface(capabilities_t *scanner, unsigned char *surface,
int w, int h, int bps, int *width, int *height);

Wyświetl plik

@ -319,7 +319,7 @@ print_xml_c(xmlNode *node, capabilities_t *scanner)
}
/**
* \fn capabilities_t *escl_capabilities(SANE_String_Const name, SANE_Status *status)
* \fn capabilities_t *escl_capabilities(const ESCL_Device *device, SANE_Status *status)
* \brief Function that finally recovers all the capabilities of the scanner, using curl.
* This function is called in the 'sane_open' function and it's the equivalent of
* the following curl command : "curl http(s)://'ip':'port'/eSCL/ScannerCapabilities".
@ -327,7 +327,7 @@ print_xml_c(xmlNode *node, capabilities_t *scanner)
* \return scanner (the structure that stocks all the capabilities elements)
*/
capabilities_t *
escl_capabilities(SANE_String_Const name, SANE_Status *status)
escl_capabilities(const ESCL_Device *device, SANE_Status *status)
{
capabilities_t *scanner = (capabilities_t*)calloc(1, sizeof(capabilities_t));
CURL *curl_handle = NULL;
@ -335,10 +335,9 @@ escl_capabilities(SANE_String_Const name, SANE_Status *status)
xmlDoc *data = NULL;
xmlNode *node = NULL;
const char *scanner_capabilities = "/eSCL/ScannerCapabilities";
char tmp[PATH_MAX] = { 0 };
*status = SANE_STATUS_GOOD;
if (name == NULL)
if (device == NULL)
*status = SANE_STATUS_NO_MEM;
var = (struct cap *)calloc(1, sizeof(struct cap));
if (var == NULL)
@ -346,15 +345,7 @@ escl_capabilities(SANE_String_Const name, SANE_Status *status)
var->memory = malloc(1);
var->size = 0;
curl_handle = curl_easy_init();
strcpy(tmp, name);
strcat(tmp, scanner_capabilities);
DBG( 1, "Get Capabilities : %s\n", tmp);
curl_easy_setopt(curl_handle, CURLOPT_URL, tmp);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
escl_curl_url(curl_handle, device, scanner_capabilities);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_c);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var);
if (curl_easy_perform(curl_handle) != CURLE_OK) {

Wyświetl plik

@ -122,7 +122,7 @@ download_callback(void *str, size_t size, size_t nmemb, void *userp)
}
/**
* \fn char *escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *status)
* \fn char *escl_newjob (capabilities_t *scanner, const ESCL_Device *device, SANE_Status *status)
* \brief Function that, using curl, uploads the data (composed by the scanner capabilities) to the
* server to download the 'job' and recover the 'new job' (char *result), in LOCATION.
* This function is called in the 'sane_start' function and it's the equivalent of the
@ -131,14 +131,13 @@ download_callback(void *str, size_t size, size_t nmemb, void *userp)
* \return result (the 'new job', situated in LOCATION)
*/
char *
escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *status)
escl_newjob (capabilities_t *scanner, const ESCL_Device *device, SANE_Status *status)
{
CURL *curl_handle = NULL;
struct uploading *upload = NULL;
struct downloading *download = NULL;
const char *scan_jobs = "/eSCL/ScanJobs";
char cap_data[PATH_MAX] = { 0 };
char job_cmd[PATH_MAX] = { 0 };
char *location = NULL;
char *result = NULL;
char *temporary = NULL;
@ -146,7 +145,7 @@ escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *statu
char *format_ext = NULL;
*status = SANE_STATUS_GOOD;
if (name == NULL || scanner == NULL) {
if (device == NULL || scanner == NULL) {
*status = SANE_STATUS_NO_MEM;
DBG( 1, "Create NewJob : the name or the scan are invalid.\n");
return (NULL);
@ -188,13 +187,7 @@ escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *statu
upload->size = strlen(cap_data);
download->memory = malloc(1);
download->size = 0;
strcpy(job_cmd, name);
strcat(job_cmd, scan_jobs);
curl_easy_setopt(curl_handle, CURLOPT_URL, job_cmd);
if (strncmp(name, "https", 5) == 0) {
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
escl_curl_url(curl_handle, device, scan_jobs);
curl_easy_setopt(curl_handle, CURLOPT_POST, 1L);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, upload->read_data);
curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, upload->size);

Wyświetl plik

@ -32,12 +32,12 @@
#include <curl/curl.h>
/**
* \fn void escl_scanner(SANE_String_Const name, char *result)
* \fn void escl_scanner(const ESCL_Device *device, char *result)
* \brief Function that resets the scanner after each scan, using curl.
* This function is called in the 'sane_cancel' function.
*/
void
escl_scanner(SANE_String_Const name, char *result)
escl_scanner(const ESCL_Device *device, char *result)
{
CURL *curl_handle = NULL;
const char *scan_jobs = "/eSCL/ScanJobs";
@ -46,22 +46,14 @@ escl_scanner(SANE_String_Const name, char *result)
int i = 0;
long answer = 0;
if (name == NULL || result == NULL)
if (device == NULL || result == NULL)
return;
CURL_CALL:
curl_handle = curl_easy_init();
if (curl_handle != NULL) {
strcpy(scan_cmd, name);
strcat(scan_cmd, scan_jobs);
strcat(scan_cmd, result);
strcat(scan_cmd, scanner_start);
curl_easy_setopt(curl_handle, CURLOPT_URL, scan_cmd);
DBG( 1, "Reset Job : %s.\n", scan_cmd);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s",
scan_jobs, result, scanner_start);
escl_curl_url(curl_handle, device, scan_cmd);
if (curl_easy_perform(curl_handle) == CURLE_OK) {
curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &answer);
if (i < 3 && answer == 503) {

Wyświetl plik

@ -49,7 +49,7 @@ write_callback(void *str, size_t size, size_t nmemb, void *userp)
}
/**
* \fn SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name, char *result)
* \fn SANE_Status escl_scan(capabilities_t *scanner, const ESCL_Device *device, char *result)
* \brief Function that, after recovering the 'new job', scans the image writed in the
* temporary file, using curl.
* This function is called in the 'sane_start' function and it's the equivalent of
@ -58,7 +58,7 @@ write_callback(void *str, size_t size, size_t nmemb, void *userp)
* \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
escl_scan(capabilities_t __sane_unused__ *scanner, SANE_String_Const name, char *result)
escl_scan(capabilities_t *scanner, const ESCL_Device *device, char *result)
{
CURL *curl_handle = NULL;
const char *scan_jobs = "/eSCL/ScanJobs";
@ -66,21 +66,13 @@ escl_scan(capabilities_t __sane_unused__ *scanner, SANE_String_Const name, char
char scan_cmd[PATH_MAX] = { 0 };
SANE_Status status = SANE_STATUS_GOOD;
if (name == NULL)
if (device == NULL)
return (SANE_STATUS_NO_MEM);
curl_handle = curl_easy_init();
if (curl_handle != NULL) {
strcpy(scan_cmd, name);
strcat(scan_cmd, scan_jobs);
strcat(scan_cmd, result);
strcat(scan_cmd, scanner_start);
curl_easy_setopt(curl_handle, CURLOPT_URL, scan_cmd);
DBG( 1, "Scan : %s.\n", scan_cmd);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
snprintf(scan_cmd, sizeof(scan_cmd), "%s%s%s",
scan_jobs, result, scanner_start);
escl_curl_url(curl_handle, device, scan_cmd);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback);
scanner->tmp = tmpfile();
if (scanner->tmp != NULL) {

Wyświetl plik

@ -110,7 +110,7 @@ print_xml_s(xmlNode *node, SANE_Status *status)
}
/**
* \fn SANE_Status escl_status(SANE_String_Const name)
* \fn SANE_Status escl_status(const ESCL_Device *device)
* \brief Function that finally recovers the scanner status ('Idle', or not), using curl.
* This function is called in the 'sane_open' function and it's the equivalent of
* the following curl command : "curl http(s)://'ip':'port'/eSCL/ScannerStatus".
@ -118,7 +118,7 @@ print_xml_s(xmlNode *node, SANE_Status *status)
* \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
*/
SANE_Status
escl_status(SANE_String_Const name)
escl_status(const ESCL_Device *device)
{
SANE_Status status;
CURL *curl_handle = NULL;
@ -126,9 +126,8 @@ escl_status(SANE_String_Const name)
xmlDoc *data = NULL;
xmlNode *node = NULL;
const char *scanner_status = "/eSCL/ScannerStatus";
char tmp[PATH_MAX] = { 0 };
if (name == NULL)
if (device == NULL)
return (SANE_STATUS_NO_MEM);
var = (struct idle*)calloc(1, sizeof(struct idle));
if (var == NULL)
@ -136,15 +135,8 @@ escl_status(SANE_String_Const name)
var->memory = malloc(1);
var->size = 0;
curl_handle = curl_easy_init();
strcpy(tmp, name);
strcat(tmp, scanner_status);
curl_easy_setopt(curl_handle, CURLOPT_URL, tmp);
DBG( 1, "Get Status : %s.\n", tmp);
if (strncmp(name, "https", 5) == 0) {
DBG( 1, "Ignoring safety certificates, use https\n");
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L);
}
escl_curl_url(curl_handle, device, scanner_status);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_s);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var);
if (curl_easy_perform(curl_handle) != CURLE_OK) {