diff --git a/backend/epsonds-tcp.c b/backend/epsonds-tcp.c new file mode 100644 index 000000000..6ec31a18b --- /dev/null +++ b/backend/epsonds-tcp.c @@ -0,0 +1,212 @@ +#define DEBUG_DECLARE_ONLY + +#include "epsonds.h" +#include "epsonds-net.h" +#include "epsonds-tcp.h" +#include "sanei_tcp.h" +#include "sane/config.h" +#include +#ifdef HAVE_OPENSSL +#include +#include +#endif +#include + +#include "sane/sanei_debug.h" + + + +#ifdef HAVE_SYS_TIME_H +# include +#endif + +typedef struct epsonds_scanner epsonds_scanner; + +SANE_Status epsonds_tcp_open(epsonds_scanner* s, const char *host, int port) { + + SANE_Status status = SANE_STATUS_GOOD; + + if(s == NULL || host == NULL) { + return SANE_STATUS_INVAL; + } + + status = sanei_tcp_open(&s->hw->name[4], 1865, &s->fd); + if (status == SANE_STATUS_GOOD) { + + ssize_t read; + struct timeval tv; + unsigned char buf[5]; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); + + s->netlen = 0; + DBG(5, "host = %s\n", &s->hw->name[4]); + + DBG(32, "awaiting welcome message\n"); + /* the scanner sends a kind of welcome msg */ + // XXX check command type, answer to connect is 0x80 + read = eds_recv(s, buf, 5, &status); + if (read != 5) { + sanei_tcp_close(s->fd); + s->fd = -1; + status = SANE_STATUS_INVAL; + } + else { + return SANE_STATUS_GOOD; + } +#ifdef HAVE_OPENSSL + SSL_CTX *ssl = NULL; + BIO *bio = NULL; + crypt_context *crypt_ctx = NULL; + + crypt_ctx = (crypt_context*)malloc(sizeof(crypt_context)); + if(crypt_ctx == NULL) { + return SANE_STATUS_INVAL; + } + + ssl = SSL_CTX_new( TLS_client_method()); + if (ssl == NULL) { + free(crypt_ctx); + return SANE_STATUS_INVAL; + } + + + bio = BIO_new_ssl_connect(ssl); + if (bio == NULL) { + SSL_CTX_free(ssl); + free(crypt_ctx); + return SANE_STATUS_INVAL; + } + + char port_s[5]; + snprintf(port_s, sizeof(port_s), "%d", port); + + DBG(1, "port_s=%s", port_s); + BIO_set_conn_hostname(bio, host); + BIO_set_conn_port(bio, port_s); + + BIO_set_ssl_renegotiate_timeout(bio, 2); + + if (BIO_do_connect(bio) <= 0) { + BIO_free_all(bio); + SSL_CTX_free(ssl); + free(crypt_ctx); + return SANE_STATUS_INVAL; + } + + crypt_ctx->bio = bio; + crypt_ctx->ssl = ssl; + + s -> cryptContext = crypt_ctx; + + read = eds_recv(s, buf, 5, &status); + if (read != 5) { + epsonds_tcp_close(s); + s->fd = -1; + return SANE_STATUS_INVAL; + } +#endif + } + return status; +} + +void epsonds_tcp_close(epsonds_scanner* s) { +#ifdef HAVE_OPENSSL + if(s->cryptContext == NULL) { + sanei_tcp_close(s->fd); + } + else { + BIO_free_all(s->cryptContext->bio); + s->cryptContext->bio = NULL; + SSL_CTX_free(s->cryptContext->ssl); + s->cryptContext->ssl= NULL; + free(s->cryptContext); + s->cryptContext = NULL; + } +#else + sanei_tcp_close(s->fd); +#endif + s->fd = -1; +} + +ssize_t epsonds_tcp_read(epsonds_scanner* s, unsigned char *buf, ssize_t wanted) { + ssize_t read = -1; + +#ifdef HAVE_OPENSSL + if(s->cryptContext == NULL) { + int ready; + fd_set readable; + struct timeval tv; + + tv.tv_sec = 10; + tv.tv_usec = 0; + + FD_ZERO(&readable); + FD_SET(s->fd, &readable); + + ready = select(s->fd + 1, &readable, NULL, NULL, &tv); + if (ready > 0) { + read = sanei_tcp_read(s->fd, buf, wanted); + } else { + DBG(15, "%s: select failed: %d\n", __func__, ready); + } + } + else { + size_t bytes_recv = 0; + ssize_t rc = 1; + + if (wanted > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + + while (bytes_recv < wanted && rc > 0) + { + rc = BIO_read(s->cryptContext->bio, buf+bytes_recv, wanted-bytes_recv); + if (rc > 0) + bytes_recv += rc; + DBG(1, "wanted=%d, bytes_recv:%d, rc=%d\n", wanted, bytes_recv, rc); + } + + read = bytes_recv; + } +#else + int ready; + fd_set readable; + struct timeval tv; + + tv.tv_sec = 10; + tv.tv_usec = 0; + + FD_ZERO(&readable); + FD_SET(s->fd, &readable); + + ready = select(s->fd + 1, &readable, NULL, NULL, &tv); + if (ready > 0) { + read = sanei_tcp_read(s->fd, buf, wanted); + } else { + DBG(15, "%s: select failed: %d\n", __func__, ready); + } +#endif + + return read; +} + +ssize_t epsonds_tcp_write(epsonds_scanner* s, unsigned char *buf, size_t count) { +#ifdef HAVE_OPENSSL + if(s->cryptContext == NULL) { + return sanei_tcp_write(s->fd, buf, count); + } + else { + if(INT_MAX < count) { + return -1; + } + return BIO_write(s->cryptContext->bio, buf, count); + } +#else + return sanei_tcp_write(s->fd, buf, count); +#endif +} diff --git a/backend/epsonds-tcp.h b/backend/epsonds-tcp.h new file mode 100644 index 000000000..5bb9e2363 --- /dev/null +++ b/backend/epsonds-tcp.h @@ -0,0 +1,13 @@ + +#ifndef _EPSONDS_TCP_H_ +#define _EPSONDS_TCP_H_ + +#include +#include "../include/sane/sane.h" + +extern void epsonds_tcp_close(struct epsonds_scanner* s); +extern SANE_Status epsonds_tcp_open(struct epsonds_scanner* s, const char *host, int port); +extern ssize_t epsonds_tcp_read(struct epsonds_scanner* s, unsigned char *buf, ssize_t wanted); +extern ssize_t epsonds_tcp_write(struct epsonds_scanner* s, unsigned char *buf, size_t count); + +#endif