summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTill Kamppeter <till.kamppeter@gmail.com>2017-04-20 17:27:03 -0300
committerTill Kamppeter <till.kamppeter@gmail.com>2017-04-20 17:27:03 -0300
commit3cae655d6f7feaa8e5620f28f38d905f8c3d2838 (patch)
tree7ac3ce119c709d0d729509637e22b0ec8dedf941
parenta78b712cf53326a060bdac439c76938d86e4b9e3 (diff)
White space clean-up in C source code files
-rw-r--r--src/dnssd.c99
-rw-r--r--src/dnssd.h8
-rw-r--r--src/http.c1017
-rw-r--r--src/http.h44
-rw-r--r--src/ippusbxd.c955
-rw-r--r--src/logging.c18
-rw-r--r--src/logging.h8
-rw-r--r--src/options.h48
-rw-r--r--src/tcp.c560
-rw-r--r--src/tcp.h10
-rw-r--r--src/usb.c1415
-rw-r--r--src/usb.h46
12 files changed, 2102 insertions, 2126 deletions
diff --git a/src/dnssd.c b/src/dnssd.c
index 2b168c5..5db8e90 100644
--- a/src/dnssd.c
+++ b/src/dnssd.c
@@ -27,10 +27,9 @@
*/
static void
-dnssd_callback(
- AvahiEntryGroup *g, /* I - Service */
- AvahiEntryGroupState state, /* I - Registration state */
- void *context) /* I - Printer */
+dnssd_callback(AvahiEntryGroup *g, /* I - Service */
+ AvahiEntryGroupState state, /* I - Registration state */
+ void *context) /* I - Printer */
{
(void)context;
@@ -65,10 +64,9 @@ dnssd_callback(
*/
static void
-dnssd_client_cb(
- AvahiClient *c, /* I - Client */
- AvahiClientState state, /* I - Current state */
- void *userdata) /* I - User data (unused) */
+dnssd_client_cb(AvahiClient *c, /* I - Client */
+ AvahiClientState state, /* I - Current state */
+ void *userdata) /* I - User data (unused) */
{
(void)userdata;
int error; /* Error code, if any */
@@ -76,49 +74,48 @@ dnssd_client_cb(
if (!c)
return;
- switch (state)
- {
- default :
- NOTE("Ignore Avahi state %d.", state);
- break;
-
- case AVAHI_CLIENT_CONNECTING:
- NOTE("Waiting for Avahi server.");
- break;
-
- case AVAHI_CLIENT_S_RUNNING:
- NOTE("Avahi server connection got available, registering printer.");
- dnssd_register(c);
- break;
-
- case AVAHI_CLIENT_S_REGISTERING:
- case AVAHI_CLIENT_S_COLLISION:
- NOTE("Dropping printer registration because of possible host name change.");
- if (g_options.dnssd_data->ipp_ref)
- avahi_entry_group_reset(g_options.dnssd_data->ipp_ref);
- break;
-
- case AVAHI_CLIENT_FAILURE:
- if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) {
- NOTE("Avahi server disappeared, unregistering printer");
- dnssd_unregister();
- /* Renewing client */
- if (g_options.dnssd_data->DNSSDClient)
- avahi_client_free(g_options.dnssd_data->DNSSDClient);
- if ((g_options.dnssd_data->DNSSDClient =
- avahi_client_new(avahi_threaded_poll_get
- (g_options.dnssd_data->DNSSDMaster),
- AVAHI_CLIENT_NO_FAIL,
- dnssd_client_cb, NULL, &error)) == NULL) {
- ERR("Error: Unable to initialize DNS-SD client.");
- g_options.terminate = 1;
- }
- } else {
- ERR("Avahi server connection failure: %s",
- avahi_strerror(avahi_client_errno(c)));
- g_options.terminate = 1;
- }
- break;
+ switch (state) {
+ default :
+ NOTE("Ignore Avahi state %d.", state);
+ break;
+
+ case AVAHI_CLIENT_CONNECTING:
+ NOTE("Waiting for Avahi server.");
+ break;
+
+ case AVAHI_CLIENT_S_RUNNING:
+ NOTE("Avahi server connection got available, registering printer.");
+ dnssd_register(c);
+ break;
+
+ case AVAHI_CLIENT_S_REGISTERING:
+ case AVAHI_CLIENT_S_COLLISION:
+ NOTE("Dropping printer registration because of possible host name change.");
+ if (g_options.dnssd_data->ipp_ref)
+ avahi_entry_group_reset(g_options.dnssd_data->ipp_ref);
+ break;
+
+ case AVAHI_CLIENT_FAILURE:
+ if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) {
+ NOTE("Avahi server disappeared, unregistering printer");
+ dnssd_unregister();
+ /* Renewing client */
+ if (g_options.dnssd_data->DNSSDClient)
+ avahi_client_free(g_options.dnssd_data->DNSSDClient);
+ if ((g_options.dnssd_data->DNSSDClient =
+ avahi_client_new(avahi_threaded_poll_get
+ (g_options.dnssd_data->DNSSDMaster),
+ AVAHI_CLIENT_NO_FAIL,
+ dnssd_client_cb, NULL, &error)) == NULL) {
+ ERR("Error: Unable to initialize DNS-SD client.");
+ g_options.terminate = 1;
+ }
+ } else {
+ ERR("Avahi server connection failure: %s",
+ avahi_strerror(avahi_client_errno(c)));
+ g_options.terminate = 1;
+ }
+ break;
}
}
diff --git a/src/dnssd.h b/src/dnssd.h
index fb1b79f..37e977a 100644
--- a/src/dnssd.h
+++ b/src/dnssd.h
@@ -25,7 +25,7 @@ typedef struct dnssd_s {
AvahiEntryGroup *ipp_ref;
} dnssd_t;
-int dnssd_init();
-void dnssd_shutdown();
-int dnssd_register();
-void dnssd_unregister();
+int dnssd_init();
+void dnssd_shutdown();
+int dnssd_register();
+void dnssd_unregister();
diff --git a/src/http.c b/src/http.c
index 1fe8557..68c121b 100644
--- a/src/http.c
+++ b/src/http.c
@@ -29,585 +29,580 @@
struct http_message_t *http_message_new()
{
- struct http_message_t *msg = calloc(1, sizeof(*msg));
- if (msg == NULL) {
- ERR("failed to alloc space for http message");
- return NULL;
- }
+ struct http_message_t *msg = calloc(1, sizeof(*msg));
+ if (msg == NULL) {
+ ERR("failed to alloc space for http message");
+ return NULL;
+ }
- msg->spare_capacity = 0;
- msg->spare_filled = 0;
- msg->spare_buffer = NULL;
+ msg->spare_capacity = 0;
+ msg->spare_filled = 0;
+ msg->spare_buffer = NULL;
- return msg;
+ return msg;
}
void message_free(struct http_message_t *msg)
{
- free(msg->spare_buffer);
- free(msg);
+ free(msg->spare_buffer);
+ free(msg);
}
static void packet_check_completion(struct http_packet_t *pkt)
{
- struct http_message_t *msg = pkt->parent_message;
- // Msg full
- if (msg->claimed_size && msg->received_size >= msg->claimed_size) {
- msg->is_completed = 1;
- NOTE("http: Message completed: Received size >= claimed size");
-
- // Sanity check
- if (msg->spare_filled > 0)
- ERR_AND_EXIT("Msg spare not empty upon completion");
- }
-
- // Pkt full
- if (pkt->expected_size && pkt->filled_size >= pkt->expected_size) {
- pkt->is_completed = 1;
- NOTE("http: Packet completed: Packet full");
- }
-
- // Pkt over capacity
- if (pkt->filled_size > pkt->buffer_capacity) {
- // Santiy check
- ERR_AND_EXIT("Overflowed packet buffer");
- }
+ struct http_message_t *msg = pkt->parent_message;
+ // Msg full
+ if (msg->claimed_size && msg->received_size >= msg->claimed_size) {
+ msg->is_completed = 1;
+ NOTE("http: Message completed: Received size >= claimed size");
+
+ // Sanity check
+ if (msg->spare_filled > 0)
+ ERR_AND_EXIT("Msg spare not empty upon completion");
+ }
+
+ // Pkt full
+ if (pkt->expected_size && pkt->filled_size >= pkt->expected_size) {
+ pkt->is_completed = 1;
+ NOTE("http: Packet completed: Packet full");
+ }
+
+ // Pkt over capacity
+ if (pkt->filled_size > pkt->buffer_capacity) {
+ // Santiy check
+ ERR_AND_EXIT("Overflowed packet buffer");
+ }
}
static int doesMatch(const char *matcher, size_t matcher_len,
const uint8_t *key, size_t key_len)
{
- for (size_t i = 0; i < matcher_len; i++)
- if (i >= key_len || matcher[i] != key[i])
- return 0;
- return 1;
+ for (size_t i = 0; i < matcher_len; i++)
+ if (i >= key_len || matcher[i] != key[i])
+ return 0;
+ return 1;
}
static int inspect_header_field(struct http_packet_t *pkt, size_t header_size,
char *key, size_t key_size)
{
- // Find key
- uint8_t *pos = memmem(pkt->buffer, header_size, key, key_size);
- if (pos == NULL)
- return -1;
-
- // Find first digit
- size_t number_pos = (size_t) (pos - pkt->buffer) + key_size;
- while (number_pos < pkt->filled_size && !isdigit(pkt->buffer[number_pos]))
- ++number_pos;
-
- // Find next non-digit
- size_t number_end = number_pos;
- while (number_end < pkt->filled_size && isdigit(pkt->buffer[number_end]))
- ++number_end;
-
- // Failed to find next non-digit
- // header field might be broken
- if (number_end >= pkt->filled_size)
- return -1;
-
- // Temporary stringification of buffer for atoi()
- uint8_t original_char = pkt->buffer[number_end];
- pkt->buffer[number_end] = '\0';
- int val = atoi((const char *)(pkt->buffer + number_pos));
-
- // Restore buffer
- pkt->buffer[number_end] = original_char;
- return val;
+ // Find key
+ uint8_t *pos = memmem(pkt->buffer, header_size, key, key_size);
+ if (pos == NULL)
+ return -1;
+
+ // Find first digit
+ size_t number_pos = (size_t) (pos - pkt->buffer) + key_size;
+ while (number_pos < pkt->filled_size && !isdigit(pkt->buffer[number_pos]))
+ ++number_pos;
+
+ // Find next non-digit
+ size_t number_end = number_pos;
+ while (number_end < pkt->filled_size && isdigit(pkt->buffer[number_end]))
+ ++number_end;
+
+ // Failed to find next non-digit
+ // header field might be broken
+ if (number_end >= pkt->filled_size)
+ return -1;
+
+ // Temporary stringification of buffer for atoi()
+ uint8_t original_char = pkt->buffer[number_end];
+ pkt->buffer[number_end] = '\0';
+ int val = atoi((const char *)(pkt->buffer + number_pos));
+
+ // Restore buffer
+ pkt->buffer[number_end] = original_char;
+ return val;
}
static void packet_store_excess(struct http_packet_t *pkt)
{
- struct http_message_t *msg = pkt->parent_message;
- if (msg->spare_buffer != NULL)
- ERR_AND_EXIT("Do not store excess to non-empty packet");
-
- if (pkt->expected_size >= pkt->filled_size)
- ERR_AND_EXIT("Do not call packet_store_excess() unless needed");
-
- size_t spare_size = pkt->filled_size - pkt->expected_size;
- size_t non_spare = pkt->expected_size;
- NOTE("HTTP: Storing %d bytes of excess", spare_size);
-
- // Align to BUFFER_STEP
- size_t needed_size = 0;
- needed_size += spare_size / BUFFER_STEP;
- needed_size += (spare_size % BUFFER_STEP) > 0 ? BUFFER_STEP : 0;
-
- if (msg->spare_buffer == NULL) {
- uint8_t *buffer = calloc(1, needed_size);
- if (buffer == NULL)
- ERR_AND_EXIT("Failed to alloc msg spare buffer");
-
- msg->spare_buffer = buffer;
- }
-
- memcpy(msg->spare_buffer, pkt->buffer + non_spare, spare_size);
- pkt->filled_size = non_spare;
-
- msg->spare_capacity = needed_size;
- msg->spare_filled = spare_size;
+ struct http_message_t *msg = pkt->parent_message;
+ if (msg->spare_buffer != NULL)
+ ERR_AND_EXIT("Do not store excess to non-empty packet");
+
+ if (pkt->expected_size >= pkt->filled_size)
+ ERR_AND_EXIT("Do not call packet_store_excess() unless needed");
+
+ size_t spare_size = pkt->filled_size - pkt->expected_size;
+ size_t non_spare = pkt->expected_size;
+ NOTE("HTTP: Storing %d bytes of excess", spare_size);
+
+ // Align to BUFFER_STEP
+ size_t needed_size = 0;
+ needed_size += spare_size / BUFFER_STEP;
+ needed_size += (spare_size % BUFFER_STEP) > 0 ? BUFFER_STEP : 0;
+
+ if (msg->spare_buffer == NULL) {
+ uint8_t *buffer = calloc(1, needed_size);
+ if (buffer == NULL)
+ ERR_AND_EXIT("Failed to alloc msg spare buffer");
+ msg->spare_buffer = buffer;
+ }
+
+ memcpy(msg->spare_buffer, pkt->buffer + non_spare, spare_size);
+ pkt->filled_size = non_spare;
+
+ msg->spare_capacity = needed_size;
+ msg->spare_filled = spare_size;
}
static void packet_take_spare(struct http_packet_t *pkt)
{
- struct http_message_t *msg = pkt->parent_message;
- if (msg->spare_filled == 0)
- return;
+ struct http_message_t *msg = pkt->parent_message;
+ if (msg->spare_filled == 0)
+ return;
- if (msg->spare_buffer == NULL)
- return;
+ if (msg->spare_buffer == NULL)
+ return;
- if (pkt->filled_size > 0)
- ERR_AND_EXIT("pkt should be empty when loading msg spare");
+ if (pkt->filled_size > 0)
+ ERR_AND_EXIT("pkt should be empty when loading msg spare");
- // Take message's buffer
- size_t msg_size = msg->spare_capacity;
- size_t msg_filled = msg->spare_filled;
- uint8_t *msg_buffer = msg->spare_buffer;
+ // Take message's buffer
+ size_t msg_size = msg->spare_capacity;
+ size_t msg_filled = msg->spare_filled;
+ uint8_t *msg_buffer = msg->spare_buffer;
- pkt->buffer_capacity = msg_size;
- pkt->filled_size = msg_filled;
- pkt->buffer = msg_buffer;
+ pkt->buffer_capacity = msg_size;
+ pkt->filled_size = msg_filled;
+ pkt->buffer = msg_buffer;
- msg->spare_capacity = 0;
- msg->spare_filled = 0;
- msg->spare_buffer = NULL;
+ msg->spare_capacity = 0;
+ msg->spare_filled = 0;
+ msg->spare_buffer = NULL;
}
static ssize_t packet_find_chunked_size(struct http_packet_t *pkt)
{
- // NOTE:
- // chunks can have trailers which are
- // tacked on http header fields.
- // NOTE:
- // chunks may also have extensions.
- // No one uses or supports them.
-
- // Find end of size string
- if (pkt->filled_size >= SSIZE_MAX)
- ERR_AND_EXIT("Buffer beyond sane size");
-
- ssize_t max = (ssize_t) pkt->filled_size;
- ssize_t size_end = -1;
- ssize_t miniheader_end = -1;
- ssize_t delimiter_start = -1;
- for (ssize_t i = 0; i < max; i++) {
-
- uint8_t *buf = pkt->buffer;
- if (size_end < 0) {
- // No extension
- if (i + 1 < max && (
- buf[i] == '\r' && // CR
- buf[i + 1] == '\n')// LF
- ) {
- size_end = i + 1;
- miniheader_end = size_end;
- delimiter_start = i;
- break;
- }
-
- // No extension
- if (buf[i] == '\n') // LF
- {
- size_end = i;
- miniheader_end = size_end;
- delimiter_start = i;
- break;
- }
-
- // Has extensions
- if (buf[i] == ';')
- {
- size_end = i;
- continue;
- }
- }
- if (miniheader_end < 0) {
- if (i + 1 < max && (
- buf[i] == '\r' && // CR
- buf[i + 1] == '\n')// LF
- ) {
- miniheader_end = i + 1;
- delimiter_start = i;
- break;
- }
-
- if (buf[i] == '\n') // LF
- {
- miniheader_end = i;
- delimiter_start = i;
- break;
- }
- }
- }
-
- if (miniheader_end < 0) {
- // NOTE: knowing just the size field
- // is not enough since the extensions
- // are not included in the size
- NOTE("failed to find chunk mini-header so far");
- return -1;
- }
-
- // Temporary stringification for strtol()
- uint8_t original_char = *(pkt->buffer + size_end);
- *(pkt->buffer + size_end) = '\0';
- size_t size = strtoul((char *)pkt->buffer, NULL, 16);
- NOTE("Chunk size raw: %s", pkt->buffer);
- *(pkt->buffer + size_end) = original_char;
- if (size > SSIZE_MAX)
- ERR_AND_EXIT("chunk size is insane");
-
- if (size > 0) {
- // Regular chunk
- ssize_t chunk_size = (ssize_t) size; // Chunk body
- chunk_size += miniheader_end + 1; // Mini-header
- chunk_size += 2; // Trailing CRLF
- NOTE("HTTP: Chunk size: %lu", chunk_size);
- return (ssize_t) chunk_size;
- }
-
- // Terminator chunk
- // May have trailers in body
- ssize_t full_size = -1;
- for (ssize_t i = delimiter_start; i < max; i++) {
- uint8_t *buf = pkt->buffer;
- if (i + 3 < max && (
- buf[i] == '\r' && // CR
- buf[i + 1] == '\n' && // LF
- buf[i + 2] == '\r' && // CR
- buf[i + 3] == '\n') // LF
- ) {
- full_size = i + 4;
- break;
- }
-
- if (i + 1 < max &&
- buf[i] == '\n' && // LF
- buf[i + 1] == '\n') // LF
- {
- full_size = i + 2;
- break;
- }
- }
-
- if (full_size < 0) {
- NOTE("Chunk miniheader present but body incomplete");
- return -1;
- }
-
- NOTE("Found end chunked packet");
- pkt->parent_message->is_completed = 1;
- pkt->is_completed = 1;
- return full_size;
+ // NOTE:
+ // chunks can have trailers which are
+ // tacked on http header fields.
+ // NOTE:
+ // chunks may also have extensions.
+ // No one uses or supports them.
+
+ // Find end of size string
+ if (pkt->filled_size >= SSIZE_MAX)
+ ERR_AND_EXIT("Buffer beyond sane size");
+
+ ssize_t max = (ssize_t) pkt->filled_size;
+ ssize_t size_end = -1;
+ ssize_t miniheader_end = -1;
+ ssize_t delimiter_start = -1;
+ for (ssize_t i = 0; i < max; i++) {
+
+ uint8_t *buf = pkt->buffer;
+ if (size_end < 0) {
+ // No extension
+ if (i + 1 < max &&
+ (buf[i] == '\r' && // CR
+ buf[i + 1] == '\n')) { // LF
+ size_end = i + 1;
+ miniheader_end = size_end;
+ delimiter_start = i;
+ break;
+ }
+
+ // No extension
+ if (buf[i] == '\n') { // LF
+ size_end = i;
+ miniheader_end = size_end;
+ delimiter_start = i;
+ break;
+ }
+
+ // Has extensions
+ if (buf[i] == ';') {
+ size_end = i;
+ continue;
+ }
+ }
+ if (miniheader_end < 0) {
+ if (i + 1 < max &&
+ (buf[i] == '\r' && // CR
+ buf[i + 1] == '\n')) { // LF
+ miniheader_end = i + 1;
+ delimiter_start = i;
+ break;
+ }
+
+ if (buf[i] == '\n') { // LF
+ miniheader_end = i;
+ delimiter_start = i;
+ break;
+ }
+ }
+ }
+
+ if (miniheader_end < 0) {
+ // NOTE: knowing just the size field
+ // is not enough since the extensions
+ // are not included in the size
+ NOTE("failed to find chunk mini-header so far");
+ return -1;
+ }
+
+ // Temporary stringification for strtol()
+ uint8_t original_char = *(pkt->buffer + size_end);
+ *(pkt->buffer + size_end) = '\0';
+ size_t size = strtoul((char *)pkt->buffer, NULL, 16);
+ NOTE("Chunk size raw: %s", pkt->buffer);
+ *(pkt->buffer + size_end) = original_char;
+ if (size > SSIZE_MAX)
+ ERR_AND_EXIT("chunk size is insane");
+
+ if (size > 0) {
+ // Regular chunk
+ ssize_t chunk_size = (ssize_t) size; // Chunk body
+ chunk_size += miniheader_end + 1; // Mini-header
+ chunk_size += 2; // Trailing CRLF
+ NOTE("HTTP: Chunk size: %lu", chunk_size);
+ return (ssize_t) chunk_size;
+ }
+
+ // Terminator chunk
+ // May have trailers in body
+ ssize_t full_size = -1;
+ for (ssize_t i = delimiter_start; i < max; i++) {
+ uint8_t *buf = pkt->buffer;
+ if (i + 3 < max &&
+ (buf[i] == '\r' && // CR
+ buf[i + 1] == '\n' && // LF
+ buf[i + 2] == '\r' && // CR
+ buf[i + 3] == '\n')) { // LF
+ full_size = i + 4;
+ break;
+ }
+
+ if (i + 1 < max &&
+ buf[i] == '\n' && // LF
+ buf[i + 1] == '\n') { // LF
+ full_size = i + 2;
+ break;
+ }
+ }
+
+ if (full_size < 0) {
+ NOTE("Chunk miniheader present but body incomplete");
+ return -1;
+ }
+
+ NOTE("Found end chunked packet");
+ pkt->parent_message->is_completed = 1;
+ pkt->is_completed = 1;
+ return full_size;
}
static ssize_t packet_get_header_size(struct http_packet_t *pkt)
{
- if (pkt->header_size != 0)
- goto found;
-
- /* RFC2616 recomends we match newline on \n despite full
- * complience requires the message to use only \r\n
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.3
- */
-
- // Find header
- for (size_t i = 0; i < pkt->filled_size && i < SSIZE_MAX; i++) {
- // two \r\n pairs
- if ((i + 3) < pkt->filled_size &&
- '\r' == pkt->buffer[i] &&
- '\n' == pkt->buffer[i + 1] &&
- '\r' == pkt->buffer[i + 2] &&
- '\n' == pkt->buffer[i + 3]) {
- pkt->header_size = i + 4;
- goto found;
- }
-
- // two \n pairs
- if ((i + 1) < pkt->filled_size &&
- '\n' == pkt->buffer[i] &&
- '\n' == pkt->buffer[i + 1]) {
- pkt->header_size = i + 2;
- goto found;
- }
- }
-
- return -1;
-
-found:
- return (ssize_t) pkt->header_size;
+ if (pkt->header_size != 0)
+ goto found;
+
+ /*
+ * RFC2616 recomends we match newline on \n despite full
+ * complience requires the message to use only \r\n
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.3
+ */
+
+ // Find header
+ for (size_t i = 0; i < pkt->filled_size && i < SSIZE_MAX; i++) {
+ // two \r\n pairs
+ if ((i + 3) < pkt->filled_size &&
+ '\r' == pkt->buffer[i] &&
+ '\n' == pkt->buffer[i + 1] &&
+ '\r' == pkt->buffer[i + 2] &&
+ '\n' == pkt->buffer[i + 3]) {
+ pkt->header_size = i + 4;
+ goto found;
+ }
+
+ // two \n pairs
+ if ((i + 1) < pkt->filled_size &&
+ '\n' == pkt->buffer[i] &&
+ '\n' == pkt->buffer[i + 1]) {
+ pkt->header_size = i + 2;
+ goto found;
+ }
+ }
+
+ return -1;
+
+ found:
+ return (ssize_t) pkt->header_size;
}
enum http_request_t packet_find_type(struct http_packet_t *pkt)
{
- enum http_request_t type = HTTP_UNSET;
- size_t size = 0;
- /* Valid methods for determining http request
- * size are defined by W3 in RFC2616 section 4.4
- * link: http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
- */
-
- /* This function attempts to find what method this
- * packet would use. This is only possible in specific case:
- * 1. if the request uses method 1 we can check the http
- * request type. We must be called on a packet which
- * has the full header.
- * 2. if the request uses method 2 we need the full header
- * but a simple network-byte-order-aware string search
- * works. This function does not work if called with
- * a chunked transport's sub-packet.
- * 3. if the request uses method 3 we again perform the
- * string search.
- *
- * All cases require the packat to contain the full header.
- */
-
- ssize_t header_size_raw = packet_get_header_size(pkt);
- if (header_size_raw < 0) {
- // We don't have the header yet
- goto do_ret;
- }
- size_t header_size = (size_t) header_size_raw;
-
- // Try Transfer-Encoding Chunked
- char xfer_encode_str[] = "Transfer-Encoding: chunked";
- size_t xfer_encode_str_size = sizeof(xfer_encode_str) - 1;
- uint8_t *xfer_encode_pos = memmem(pkt->buffer, header_size,
- xfer_encode_str,
- xfer_encode_str_size);
- if (xfer_encode_pos != NULL) {
- size = 0;
- type = HTTP_CHUNKED;
- goto do_ret;
- }
-
- // Try Content-Length
- char content_length_str[] = "Content-Length: ";
- ssize_t contlen_size = inspect_header_field(pkt, header_size,
- content_length_str, sizeof(content_length_str) - 1);
- if (contlen_size >= 0) {
- size = (size_t) contlen_size + header_size;
- type = HTTP_CONTENT_LENGTH;
- goto do_ret;
- }
-
- // GET requests (start with GET) or answers from the server (start
- // with HTTP)
- if (doesMatch("GET", 3, pkt->buffer, pkt->filled_size) ||
- doesMatch("HTTP", 4, pkt->buffer, pkt->filled_size)) {
- size = header_size;
- type = HTTP_HEADER_ONLY;
- goto do_ret;
- }
-
- // No size was detectable yet header was found
- type = HTTP_UNKNOWN;
- size = 0;
-
-do_ret:
- pkt->parent_message->claimed_size = size;
- pkt->parent_message->type = type;
- return type;
+ enum http_request_t type = HTTP_UNSET;
+ size_t size = 0;
+ /*
+ * Valid methods for determining http request
+ * size are defined by W3 in RFC2616 section 4.4
+ * link: http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
+ */
+
+ /*
+ * This function attempts to find what method this
+ * packet would use. This is only possible in specific case:
+ * 1. if the request uses method 1 we can check the http
+ * request type. We must be called on a packet which
+ * has the full header.
+ * 2. if the request uses method 2 we need the full header
+ * but a simple network-byte-order-aware string search
+ * works. This function does not work if called with
+ * a chunked transport's sub-packet.
+ * 3. if the request uses method 3 we again perform the
+ * string search.
+ *
+ * All cases require the packat to contain the full header.
+ */
+
+ ssize_t header_size_raw = packet_get_header_size(pkt);
+ if (header_size_raw < 0) {
+ // We don't have the header yet
+ goto do_ret;
+ }
+ size_t header_size = (size_t) header_size_raw;
+
+ // Try Transfer-Encoding Chunked
+ char xfer_encode_str[] = "Transfer-Encoding: chunked";
+ size_t xfer_encode_str_size = sizeof(xfer_encode_str) - 1;
+ uint8_t *xfer_encode_pos = memmem(pkt->buffer, header_size,
+ xfer_encode_str,
+ xfer_encode_str_size);
+ if (xfer_encode_pos != NULL) {
+ size = 0;
+ type = HTTP_CHUNKED;
+ goto do_ret;
+ }
+
+ // Try Content-Length
+ char content_length_str[] = "Content-Length: ";
+ ssize_t contlen_size =
+ inspect_header_field(pkt, header_size,
+ content_length_str, sizeof(content_length_str) - 1);
+ if (contlen_size >= 0) {
+ size = (size_t) contlen_size + header_size;
+ type = HTTP_CONTENT_LENGTH;
+ goto do_ret;
+ }
+
+ // GET requests (start with GET) or answers from the server (start
+ // with HTTP)
+ if (doesMatch("GET", 3, pkt->buffer, pkt->filled_size) ||
+ doesMatch("HTTP", 4, pkt->buffer, pkt->filled_size)) {
+ size = header_size;
+ type = HTTP_HEADER_ONLY;
+ goto do_ret;
+ }
+
+ // No size was detectable yet header was found
+ type = HTTP_UNKNOWN;
+ size = 0;
+
+ do_ret:
+ pkt->parent_message->claimed_size = size;
+ pkt->parent_message->type = type;
+ return type;
}
size_t packet_pending_bytes(struct http_packet_t *pkt)
{
- struct http_message_t *msg = pkt->parent_message;
-
- // Check Cache
- if (pkt->expected_size > 0)
- goto pending_known;
-
- if (HTTP_UNSET == msg->type) {
- msg->type = packet_find_type(pkt);
-
- if (HTTP_CHUNKED == msg->type) {
- // Note: this was the packet with the
- // header of our chunked message.
-
- // Save any non-header data we got
- ssize_t header_size = packet_get_header_size(pkt);
-
- // Sanity check
- if (header_size < 0 ||
- (size_t)header_size > pkt->filled_size)
- ERR_AND_EXIT("HTTP: Could not find header twice");
-
- NOTE("HTTP: Chunked header size is %ld bytes",
- header_size);
- pkt->expected_size = (size_t) header_size;
- msg->claimed_size = 0;
- goto pending_known;
- }
- }
-
-
- if (HTTP_CHUNKED == msg->type) {
- if (pkt->filled_size == 0) {
- // Grab chunk's mini-header
- goto pending_known;
- }
-
- if (pkt->expected_size == 0) {
- // Check chunk's mini-header
- ssize_t size = packet_find_chunked_size(pkt);
- if (size <= 0) {
- ERR("=============================================");
- ERR("Malformed chunk-transport http header receivd");
- ERR("Missing chunk's mini-headers in first data");
- ERR("Have %d bytes", pkt->filled_size);
- printf("%.*s\n", (int)pkt->filled_size, pkt->buffer);
- ERR("Malformed chunk-transport http header receivd");
- ERR("=============================================");
- goto pending_known;
- }
-
- pkt->expected_size = (size_t) size;
- msg->claimed_size = 0;
- }
-
- goto pending_known;
- }
- if (HTTP_HEADER_ONLY == msg->type) {
- // Note: we can only know it is header only
- // when the buffer already contains the header.
- // So this next call cannot fail.
- pkt->expected_size = (size_t) packet_get_header_size(pkt);
- msg->claimed_size = pkt->expected_size;
- goto pending_known;
- }
- if (HTTP_CONTENT_LENGTH == msg->type) {
- // Note: find_header() has
- // filled msg's claimed_size
- msg->claimed_size = msg->claimed_size;
- pkt->expected_size = msg->claimed_size;
- goto pending_known;
- }
-
-pending_known:
-
- // Save excess data
- if (pkt->expected_size && pkt->filled_size > pkt->expected_size)
- packet_store_excess(pkt);
-
- size_t expected = pkt->expected_size;
- if (expected == 0)
- expected = msg->claimed_size;
- if (expected == 0)
- expected = pkt->buffer_capacity;
-
- // Sanity check
- if (expected < pkt->filled_size)
- ERR_AND_EXIT("Expected cannot be larger than filled");
-
- size_t pending = expected - pkt->filled_size;
-
- // Expand buffer as needed
- while (pending + pkt->filled_size > pkt->buffer_capacity) {
- ssize_t size_added = packet_expand(pkt);
- if (size_added < 0) {
- WARN("packet at max allowed size");
- return 0;
- }
- if (size_added == 0) {
- ERR("Failed to expand packet");
- return 0;
- }
- }
-
- packet_check_completion(pkt);
-
- return pending;
+ struct http_message_t *msg = pkt->parent_message;
+
+ // Check Cache
+ if (pkt->expected_size > 0)
+ goto pending_known;
+
+ if (HTTP_UNSET == msg->type) {
+ msg->type = packet_find_type(pkt);
+
+ if (HTTP_CHUNKED == msg->type) {
+ // Note: this was the packet with the
+ // header of our chunked message.
+
+ // Save any non-header data we got
+ ssize_t header_size = packet_get_header_size(pkt);
+
+ // Sanity check
+ if (header_size < 0 ||
+ (size_t)header_size > pkt->filled_size)
+ ERR_AND_EXIT("HTTP: Could not find header twice");
+
+ NOTE("HTTP: Chunked header size is %ld bytes",
+ header_size);
+ pkt->expected_size = (size_t) header_size;
+ msg->claimed_size = 0;
+ goto pending_known;
+ }
+ }
+
+ if (HTTP_CHUNKED == msg->type) {
+ if (pkt->filled_size == 0) {
+ // Grab chunk's mini-header
+ goto pending_known;
+ }
+
+ if (pkt->expected_size == 0) {
+ // Check chunk's mini-header
+ ssize_t size = packet_find_chunked_size(pkt);
+ if (size <= 0) {
+ ERR("=============================================");
+ ERR("Malformed chunk-transport http header receivd");
+ ERR("Missing chunk's mini-headers in first data");
+ ERR("Have %d bytes", pkt->filled_size);
+ printf("%.*s\n", (int)pkt->filled_size, pkt->buffer);
+ ERR("Malformed chunk-transport http header receivd");
+ ERR("=============================================");
+ goto pending_known;
+ }
+
+ pkt->expected_size = (size_t) size;
+ msg->claimed_size = 0;
+ }
+
+ goto pending_known;
+ }
+ if (HTTP_HEADER_ONLY == msg->type) {
+ // Note: we can only know it is header only
+ // when the buffer already contains the header.
+ // So this next call cannot fail.
+ pkt->expected_size = (size_t) packet_get_header_size(pkt);
+ msg->claimed_size = pkt->expected_size;
+ goto pending_known;
+ }
+ if (HTTP_CONTENT_LENGTH == msg->type) {
+ // Note: find_header() has
+ // filled msg's claimed_size
+ msg->claimed_size = msg->claimed_size;
+ pkt->expected_size = msg->claimed_size;
+ goto pending_known;
+ }
+
+ pending_known:
+
+ // Save excess data
+ if (pkt->expected_size && pkt->filled_size > pkt->expected_size)
+ packet_store_excess(pkt);
+
+ size_t expected = pkt->expected_size;
+ if (expected == 0)
+ expected = msg->claimed_size;
+ if (expected == 0)
+ expected = pkt->buffer_capacity;
+
+ // Sanity check
+ if (expected < pkt->filled_size)
+ ERR_AND_EXIT("Expected cannot be larger than filled");
+
+ size_t pending = expected - pkt->filled_size;
+
+ // Expand buffer as needed
+ while (pending + pkt->filled_size > pkt->buffer_capacity) {
+ ssize_t size_added = packet_expand(pkt);
+ if (size_added < 0) {
+ WARN("packet at max allowed size");
+ return 0;
+ }
+ if (size_added == 0) {
+ ERR("Failed to expand packet");
+ return 0;
+ }
+ }
+
+ packet_check_completion(pkt);
+
+ return pending;
}
void packet_mark_received(struct http_packet_t *pkt, size_t received)
{
- struct http_message_t *msg = pkt->parent_message;
- msg->received_size += received;
+ struct http_message_t *msg = pkt->parent_message;
+ msg->received_size += received;
- pkt->filled_size += received;
- if (received) {
- NOTE("HTTP: got %lu bytes so: pkt has %lu bytes, "
- "msg has %lu bytes",
- received, pkt->filled_size, msg->received_size);
- }
+ pkt->filled_size += received;
+ if (received) {
+ NOTE("HTTP: got %lu bytes so: pkt has %lu bytes, "
+ "msg has %lu bytes",
+ received, pkt->filled_size, msg->received_size);
+ }
- packet_check_completion(pkt);
+ packet_check_completion(pkt);
- if (pkt->filled_size > pkt->buffer_capacity)
- ERR_AND_EXIT("Overflowed packet's buffer");
+ if (pkt->filled_size > pkt->buffer_capacity)
+ ERR_AND_EXIT("Overflowed packet's buffer");
- if (pkt->expected_size && pkt->filled_size > pkt->expected_size) {
- // Store excess data
- packet_store_excess(pkt);
- }
+ if (pkt->expected_size && pkt->filled_size > pkt->expected_size) {
+ // Store excess data
+ packet_store_excess(pkt);
+ }
}
struct http_packet_t *packet_new(struct http_message_t *parent_msg)
{
- struct http_packet_t *pkt = NULL;
- uint8_t *buf = NULL;
- size_t const capacity = BUFFER_STEP;
-
- assert(parent_msg != NULL);
- pkt = calloc(1, sizeof(*pkt));
- if (pkt == NULL) {
- ERR("failed to alloc packet");
- return NULL;
- }
- pkt->parent_message = parent_msg;
- pkt->expected_size = 0;
-
- // Claim any spare data from prior packets
- packet_take_spare(pkt);
-
- if (pkt->buffer == NULL) {
- buf = calloc(capacity, sizeof(*buf));
- if (buf == NULL) {
- ERR("failed to alloc space for packet's buffer or space for packet");
- free(pkt);
- return NULL;
- }
-
- // Assemble packet
- pkt->buffer = buf;
- pkt->buffer_capacity = capacity;
- pkt->filled_size = 0;
- }
-
- return pkt;
+ struct http_packet_t *pkt = NULL;
+ uint8_t *buf = NULL;
+ size_t const capacity = BUFFER_STEP;
+
+ assert(parent_msg != NULL);
+ pkt = calloc(1, sizeof(*pkt));
+ if (pkt == NULL) {
+ ERR("failed to alloc packet");
+ return NULL;
+ }
+ pkt->parent_message = parent_msg;
+ pkt->expected_size = 0;
+
+ // Claim any spare data from prior packets
+ packet_take_spare(pkt);
+
+ if (pkt->buffer == NULL) {
+ buf = calloc(capacity, sizeof(*buf));
+ if (buf == NULL) {
+ ERR("failed to alloc space for packet's buffer or space for packet");
+ free(pkt);
+ return NULL;
+ }
+
+ // Assemble packet
+ pkt->buffer = buf;
+ pkt->buffer_capacity = capacity;
+ pkt->filled_size = 0;
+ }
+
+ return pkt;
}
void packet_free(struct http_packet_t *pkt)
{
- free(pkt->buffer);
- free(pkt);
+ free(pkt->buffer);
+ free(pkt);
}
#define MAX_PACKET_SIZE (1 << 26) // 64MiB
ssize_t packet_expand(struct http_packet_t *pkt)
{
- size_t cur_size = pkt->buffer_capacity;
- size_t new_size = cur_size * 2;
- if (new_size > MAX_PACKET_SIZE) {
- WARN("HTTP: cannot expand packet beyond limit");
- return -1;
- }
- NOTE("HTTP: doubling packet buffer to %lu", new_size);
-
- uint8_t *new_buf = realloc(pkt->buffer, new_size);
- if (new_buf == NULL) {
- // If realloc fails the original buffer is still valid
- WARN("Failed to expand packet");
- return 0;
- }
- pkt->buffer = new_buf;
- pkt->buffer_capacity = new_size;
-
- size_t diff = new_size - cur_size;
- if (diff > SSIZE_MAX)
- ERR_AND_EXIT("Buffer expanded beyond sane limit");
- return (ssize_t) diff;
+ size_t cur_size = pkt->buffer_capacity;
+ size_t new_size = cur_size * 2;
+ if (new_size > MAX_PACKET_SIZE) {
+ WARN("HTTP: cannot expand packet beyond limit");
+ return -1;
+ }
+ NOTE("HTTP: doubling packet buffer to %lu", new_size);
+
+ uint8_t *new_buf = realloc(pkt->buffer, new_size);
+ if (new_buf == NULL) {
+ // If realloc fails the original buffer is still valid
+ WARN("Failed to expand packet");
+ return 0;
+ }
+ pkt->buffer = new_buf;
+ pkt->buffer_capacity = new_size;
+
+ size_t diff = new_size - cur_size;
+ if (diff > SSIZE_MAX)
+ ERR_AND_EXIT("Buffer expanded beyond sane limit");
+ return (ssize_t) diff;
}
diff --git a/src/http.h b/src/http.h
index 5995c21..4127c53 100644
--- a/src/http.h
+++ b/src/http.h
@@ -17,41 +17,41 @@
#include <sys/types.h>
enum http_request_t {
- HTTP_UNSET,
- HTTP_UNKNOWN,
- HTTP_CHUNKED,
- HTTP_CONTENT_LENGTH,
- HTTP_HEADER_ONLY
+ HTTP_UNSET,
+ HTTP_UNKNOWN,
+ HTTP_CHUNKED,
+ HTTP_CONTENT_LENGTH,
+ HTTP_HEADER_ONLY
};
struct http_message_t {
- enum http_request_t type;
+ enum http_request_t type;
- size_t spare_filled;
- size_t spare_capacity;
- uint8_t *spare_buffer;
+ size_t spare_filled;
+ size_t spare_capacity;
+ uint8_t *spare_buffer;
- size_t unreceived_size;
- uint8_t is_completed;
+ size_t unreceived_size;
+ uint8_t is_completed;
- // Detected from child packets
- size_t claimed_size;
- size_t received_size;
+ // Detected from child packets
+ size_t claimed_size;
+ size_t received_size;
};
struct http_packet_t {
- // Cache
- size_t header_size;
+ // Cache
+ size_t header_size;
- size_t filled_size;
- size_t expected_size;
+ size_t filled_size;
+ size_t expected_size;
- size_t buffer_capacity;
- uint8_t *buffer;
+ size_t buffer_capacity;
+ uint8_t *buffer;
- struct http_message_t *parent_message;
+ struct http_message_t *parent_message;
- uint8_t is_completed;
+ uint8_t is_completed;
};
struct http_message_t *http_message_new(void);
diff --git a/src/ippusbxd.c b/src/ippusbxd.c
index d352593..3ac602f 100644
--- a/src/ippusbxd.c
+++ b/src/ippusbxd.c
@@ -31,515 +31,512 @@
#include "dnssd.h"
struct service_thread_param {
- struct tcp_conn_t *tcp;
- struct usb_sock_t *usb_sock;
- pthread_t thread_handle;
- int thread_num;
+ struct tcp_conn_t *tcp;
+ struct usb_sock_t *usb_sock;
+ pthread_t thread_handle;
+ int thread_num;
};
static void
sigterm_handler(int sig) {
- /* Flag that we should stop and return... */
- g_options.terminate = 1;
- NOTE("Caught signal %d, shutting down ...", sig);
+ /* Flag that we should stop and return... */
+ g_options.terminate = 1;
+ NOTE("Caught signal %d, shutting down ...", sig);
}
static void *service_connection(void *arg_void)
{
- struct service_thread_param *arg =
- (struct service_thread_param *)arg_void;
-
- NOTE("Thread #%d: Starting", arg->thread_num);
- // classify priority
- struct usb_conn_t *usb = NULL;
- int usb_failed = 0;
- while (!arg->tcp->is_closed && usb_failed == 0 && !g_options.terminate) {
- struct http_message_t *server_msg = NULL;
- struct http_message_t *client_msg = NULL;
-
- // Client's request
- client_msg = http_message_new();
- if (client_msg == NULL) {
- ERR("Thread #%d: Failed to create client message", arg->thread_num);
- break;
- }
- NOTE("Thread #%d: M %p: Client msg starting",
- arg->thread_num, client_msg);
-
- while (!client_msg->is_completed) {
- struct http_packet_t *pkt;
- pkt = tcp_packet_get(arg->tcp, client_msg);
- if (pkt == NULL) {
- if (arg->tcp->is_closed) {
- NOTE("Thread #%d: M %p: Client closed connection\n",
- arg->thread_num, client_msg);
- goto cleanup_subconn;
- }
- ERR("Thread #%d: M %p: Got null packet from tcp",
- arg->thread_num, client_msg);
- goto cleanup_subconn;
- }
- if (usb == NULL && arg->usb_sock != NULL) {
- usb = usb_conn_acquire(arg->usb_sock);
- if (usb == NULL) {
- ERR("Thread #%d: M %p: Failed to acquire usb interface",
- arg->thread_num, client_msg);
- packet_free(pkt);
- usb_failed = 1;
- goto cleanup_subconn;
- }
- usb_failed = 0;
- NOTE("Thread #%d: M %p: Interface #%d: acquired usb conn",
- arg->thread_num, client_msg,
- usb->interface_index);
- }
-
- NOTE("Thread #%d: M %p P %p: Pkt from tcp (buffer size: %d)\n===\n%s===",
- arg->thread_num, client_msg, pkt,
- pkt->filled_size,
- hexdump(pkt->buffer, (int)pkt->filled_size));
- // In no-printer mode we simply ignore passing the
- // client message on to the printer
- if (arg->usb_sock != NULL) {
- if (usb_conn_packet_send(usb, pkt) != 0) {
- ERR("Thread #%d: M %p P %p: Interface #%d: Unable to send client package via USB",
- arg->thread_num,
- client_msg, pkt, usb->interface_index);
- packet_free(pkt);
- goto cleanup_subconn;
- }
- NOTE("Thread #%d: M %p P %p: Interface #%d: Client pkt done",
- arg->thread_num,
- client_msg, pkt, usb->interface_index);
- }
- packet_free(pkt);
- }
- if (usb != NULL)
- NOTE("Thread #%d: M %p: Interface #%d: Client msg completed\n",
- arg->thread_num, client_msg,
- usb->interface_index);
- else
- NOTE("Thread #%d: M %p: Client msg completed\n",
- arg->thread_num, client_msg);
- message_free(client_msg);
- client_msg = NULL;
-
-
- // Server's response
- server_msg = http_message_new();
- if (server_msg == NULL) {
- ERR("Thread #%d: Failed to create server message",
- arg->thread_num);
- goto cleanup_subconn;
- }
- if (usb != NULL)
- NOTE("Thread #%d: M %p: Interface #%d: Server msg starting",
- arg->thread_num, server_msg,
- usb->interface_index);
- else
- NOTE("Thread #%d: M %p: Server msg starting",
- arg->thread_num, server_msg);
- while (!server_msg->is_completed) {
- struct http_packet_t *pkt;
- if (arg->usb_sock != NULL) {
- pkt = usb_conn_packet_get(usb, server_msg);
- if (pkt == NULL) {
- usb_failed = 1;
- goto cleanup_subconn;
- }
- } else {
- // In no-printer mode we "invent" the answer
- // of the printer, a simple HTML message as
- // a pseudo web interface
- pkt = packet_new(server_msg);
- snprintf((char*)(pkt->buffer),
- pkt->buffer_capacity - 1,
- "HTTP/1.1 200 OK\r\nContent-Type: text/html; name=ippusbxd.html; charset=UTF-8\r\n\r\n<html><h2>ippusbxd</h2><p>Debug/development mode without connection to IPP-over-USB printer</p></html>\r\n");
- pkt->filled_size = 183;
- // End the TCP connection, so that a
- // web browser does not wait for more data
- server_msg->is_completed = 1;
- arg->tcp->is_closed = 1;
- }
-
- NOTE("Thread #%d: M %p P %p: Pkt from usb (buffer size: %d)\n===\n%s===",
- arg->thread_num, server_msg, pkt, pkt->filled_size,
- hexdump(pkt->buffer, (int)pkt->filled_size));
- if (tcp_packet_send(arg->tcp, pkt) != 0) {
- ERR("Thread #%d: M %p P %p: Unable to send client package via TCP",
- arg->thread_num,
- client_msg, pkt);
- packet_free(pkt);
- goto cleanup_subconn;
- }
- if (usb != NULL)
- NOTE("Thread #%d: M %p P %p: Interface #%d: Server pkt done",
- arg->thread_num, server_msg, pkt,
- usb->interface_index);
- else
- NOTE("Thread #%d: M %p P %p: Server pkt done",
- arg->thread_num, server_msg, pkt);
- packet_free(pkt);
- }
- if (usb != NULL)
- NOTE("Thread #%d: M %p: Interface #%d: Server msg completed\n",
- arg->thread_num, server_msg,
- usb->interface_index);
- else
- NOTE("Thread #%d: M %p: Server msg completed\n",
- arg->thread_num, server_msg);
-
-cleanup_subconn:
- if (usb != NULL && (arg->tcp->is_closed || usb_failed == 1)) {
- NOTE("Thread #%d: M %p: Interface #%d: releasing usb conn",
- arg->thread_num, server_msg, usb->interface_index);
- usb_conn_release(usb);
- usb = NULL;
- }
- if (client_msg != NULL)
- message_free(client_msg);
- if (server_msg != NULL)
- message_free(server_msg);
+ struct service_thread_param *arg =
+ (struct service_thread_param *)arg_void;
+
+ NOTE("Thread #%d: Starting", arg->thread_num);
+ // classify priority
+ struct usb_conn_t *usb = NULL;
+ int usb_failed = 0;
+ while (!arg->tcp->is_closed && usb_failed == 0 && !g_options.terminate) {
+ struct http_message_t *server_msg = NULL;
+ struct http_message_t *client_msg = NULL;
+
+ // Client's request
+ client_msg = http_message_new();
+ if (client_msg == NULL) {
+ ERR("Thread #%d: Failed to create client message", arg->thread_num);
+ break;
+ }
+ NOTE("Thread #%d: M %p: Client msg starting",
+ arg->thread_num, client_msg);
+
+ while (!client_msg->is_completed) {
+ struct http_packet_t *pkt;
+ pkt = tcp_packet_get(arg->tcp, client_msg);
+ if (pkt == NULL) {
+ if (arg->tcp->is_closed) {
+ NOTE("Thread #%d: M %p: Client closed connection\n",
+ arg->thread_num, client_msg);
+ goto cleanup_subconn;
}
-
-
- NOTE("Thread #%d: Closing", arg->thread_num);
- tcp_conn_close(arg->tcp);
- free(arg);
- return NULL;
-}
-
-static void start_daemon()
-{
- // Capture USB device if not in no-printer mode
- struct usb_sock_t *usb_sock;
-
- // Termination flag
- g_options.terminate = 0;
-
- if (g_options.noprinter_mode == 0) {
- usb_sock = usb_open();
- if (usb_sock == NULL)
- goto cleanup_usb;
- } else
- usb_sock = NULL;
-
- // Capture a socket
- uint16_t desired_port = g_options.desired_port;
- struct tcp_sock_t *tcp_socket = NULL, *tcp6_socket = NULL;
- for (;;) {
- tcp_socket = tcp_open(desired_port, g_options.interface);
- tcp6_socket = tcp6_open(desired_port, g_options.interface);
- if (tcp_socket || tcp6_socket || g_options.only_desired_port)
- break;
- // Search for a free port
- desired_port ++;
- // We failed with 0 as port number or we reached the max
- // port number
- if (desired_port == 1 || desired_port == 0)
- // IANA recommendation of 49152 to 65535 for ephemeral
- // ports
- // https://en.wikipedia.org/wiki/Ephemeral_port
- desired_port = 49152;
- NOTE("Access to desired port failed, trying alternative port %d", desired_port);
+ ERR("Thread #%d: M %p: Got null packet from tcp",
+ arg->thread_num, client_msg);
+ goto cleanup_subconn;
+ }
+ if (usb == NULL && arg->usb_sock != NULL) {
+ usb = usb_conn_acquire(arg->usb_sock);
+ if (usb == NULL) {
+ ERR("Thread #%d: M %p: Failed to acquire usb interface",
+ arg->thread_num, client_msg);
+ packet_free(pkt);
+ usb_failed = 1;
+ goto cleanup_subconn;
}
- if (tcp_socket == NULL && tcp6_socket == NULL)
- goto cleanup_tcp;
-
- if (tcp_socket)
- g_options.real_port = tcp_port_number_get(tcp_socket);
- else
- g_options.real_port = tcp_port_number_get(tcp6_socket);
- if (desired_port != 0 && g_options.only_desired_port == 1 &&
- desired_port != g_options.real_port) {
- ERR("Received port number did not match requested port number."
- " The requested port number may be too high.");
- goto cleanup_tcp;
+ usb_failed = 0;
+ NOTE("Thread #%d: M %p: Interface #%d: acquired usb conn",
+ arg->thread_num, client_msg,
+ usb->interface_index);
+ }
+
+ NOTE("Thread #%d: M %p P %p: Pkt from tcp (buffer size: %d)\n===\n%s===",
+ arg->thread_num, client_msg, pkt,
+ pkt->filled_size,
+ hexdump(pkt->buffer, (int)pkt->filled_size));
+ // In no-printer mode we simply ignore passing the
+ // client message on to the printer
+ if (arg->usb_sock != NULL) {
+ if (usb_conn_packet_send(usb, pkt) != 0) {
+ ERR("Thread #%d: M %p P %p: Interface #%d: Unable to send client package via USB",
+ arg->thread_num,
+ client_msg, pkt, usb->interface_index);
+ packet_free(pkt);
+ goto cleanup_subconn;
}
- printf("%u|", g_options.real_port);
- fflush(stdout);
-
- NOTE("Port: %d, IPv4 %savailable, IPv6 %savailable",
- g_options.real_port, tcp_socket ? "" : "not ", tcp6_socket ? "" : "not ");
-
- // Lose connection to caller
- uint16_t pid;
- if (!g_options.nofork_mode && (pid = fork()) > 0) {
- printf("%u|", pid);
- exit(0);
+ NOTE("Thread #%d: M %p P %p: Interface #%d: Client pkt done",
+ arg->thread_num,
+ client_msg, pkt, usb->interface_index);
+ }
+ packet_free(pkt);
+ }
+ if (usb != NULL)
+ NOTE("Thread #%d: M %p: Interface #%d: Client msg completed\n",
+ arg->thread_num, client_msg,
+ usb->interface_index);
+ else
+ NOTE("Thread #%d: M %p: Client msg completed\n",
+ arg->thread_num, client_msg);
+ message_free(client_msg);
+ client_msg = NULL;
+
+ // Server's response
+ server_msg = http_message_new();
+ if (server_msg == NULL) {
+ ERR("Thread #%d: Failed to create server message",
+ arg->thread_num);
+ goto cleanup_subconn;
+ }
+ if (usb != NULL)
+ NOTE("Thread #%d: M %p: Interface #%d: Server msg starting",
+ arg->thread_num, server_msg,
+ usb->interface_index);
+ else
+ NOTE("Thread #%d: M %p: Server msg starting",
+ arg->thread_num, server_msg);
+ while (!server_msg->is_completed) {
+ struct http_packet_t *pkt;
+ if (arg->usb_sock != NULL) {
+ pkt = usb_conn_packet_get(usb, server_msg);
+ if (pkt == NULL) {
+ usb_failed = 1;
+ goto cleanup_subconn;
}
+ } else {
+ // In no-printer mode we "invent" the answer
+ // of the printer, a simple HTML message as
+ // a pseudo web interface
+ pkt = packet_new(server_msg);
+ snprintf((char*)(pkt->buffer),
+ pkt->buffer_capacity - 1,
+ "HTTP/1.1 200 OK\r\nContent-Type: text/html; name=ippusbxd.html; charset=UTF-8\r\n\r\n<html><h2>ippusbxd</h2><p>Debug/development mode without connection to IPP-over-USB printer</p></html>\r\n");
+ pkt->filled_size = 183;
+ // End the TCP connection, so that a
+ // web browser does not wait for more data
+ server_msg->is_completed = 1;
+ arg->tcp->is_closed = 1;
+ }
+
+ NOTE("Thread #%d: M %p P %p: Pkt from usb (buffer size: %d)\n===\n%s===",
+ arg->thread_num, server_msg, pkt, pkt->filled_size,
+ hexdump(pkt->buffer, (int)pkt->filled_size));
+ if (tcp_packet_send(arg->tcp, pkt) != 0) {
+ ERR("Thread #%d: M %p P %p: Unable to send client package via TCP",
+ arg->thread_num,
+ client_msg, pkt);
+ packet_free(pkt);
+ goto cleanup_subconn;
+ }
+ if (usb != NULL)
+ NOTE("Thread #%d: M %p P %p: Interface #%d: Server pkt done",
+ arg->thread_num, server_msg, pkt,
+ usb->interface_index);
+ else
+ NOTE("Thread #%d: M %p P %p: Server pkt done",
+ arg->thread_num, server_msg, pkt);
+ packet_free(pkt);
+ }
+ if (usb != NULL)
+ NOTE("Thread #%d: M %p: Interface #%d: Server msg completed\n",
+ arg->thread_num, server_msg,
+ usb->interface_index);
+ else
+ NOTE("Thread #%d: M %p: Server msg completed\n",
+ arg->thread_num, server_msg);
+
+ cleanup_subconn:
+ if (usb != NULL && (arg->tcp->is_closed || usb_failed == 1)) {
+ NOTE("Thread #%d: M %p: Interface #%d: releasing usb conn",
+ arg->thread_num, server_msg, usb->interface_index);
+ usb_conn_release(usb);
+ usb = NULL;
+ }
+ if (client_msg != NULL)
+ message_free(client_msg);
+ if (server_msg != NULL)
+ message_free(server_msg);
+ }
+
+ NOTE("Thread #%d: Closing", arg->thread_num);
+ tcp_conn_close(arg->tcp);
+ free(arg);
+ return NULL;
+}
- // Redirect SIGINT and SIGTERM so that we do a proper shutdown, unregistering
- // the printer from DNS-SD
+static void start_daemon()
+{
+ // Capture USB device if not in no-printer mode
+ struct usb_sock_t *usb_sock;
+
+ // Termination flag
+ g_options.terminate = 0;
+
+ if (g_options.noprinter_mode == 0) {
+ usb_sock = usb_open();
+ if (usb_sock == NULL)
+ goto cleanup_usb;
+ } else
+ usb_sock = NULL;
+
+ // Capture a socket
+ uint16_t desired_port = g_options.desired_port;
+ struct tcp_sock_t *tcp_socket = NULL, *tcp6_socket = NULL;
+ for (;;) {
+ tcp_socket = tcp_open(desired_port, g_options.interface);
+ tcp6_socket = tcp6_open(desired_port, g_options.interface);
+ if (tcp_socket || tcp6_socket || g_options.only_desired_port)
+ break;
+ // Search for a free port
+ desired_port ++;
+ // We failed with 0 as port number or we reached the max
+ // port number
+ if (desired_port == 1 || desired_port == 0)
+ // IANA recommendation of 49152 to 65535 for ephemeral
+ // ports
+ // https://en.wikipedia.org/wiki/Ephemeral_port
+ desired_port = 49152;
+ NOTE("Access to desired port failed, trying alternative port %d", desired_port);
+ }
+ if (tcp_socket == NULL && tcp6_socket == NULL)
+ goto cleanup_tcp;
+
+ if (tcp_socket)
+ g_options.real_port = tcp_port_number_get(tcp_socket);
+ else
+ g_options.real_port = tcp_port_number_get(tcp6_socket);
+ if (desired_port != 0 && g_options.only_desired_port == 1 &&
+ desired_port != g_options.real_port) {
+ ERR("Received port number did not match requested port number."
+ " The requested port number may be too high.");
+ goto cleanup_tcp;
+ }
+ printf("%u|", g_options.real_port);
+ fflush(stdout);
+
+ NOTE("Port: %d, IPv4 %savailable, IPv6 %savailable",
+ g_options.real_port, tcp_socket ? "" : "not ", tcp6_socket ? "" : "not ");
+
+ // Lose connection to caller
+ uint16_t pid;
+ if (!g_options.nofork_mode && (pid = fork()) > 0) {
+ printf("%u|", pid);
+ exit(0);
+ }
+
+ // Redirect SIGINT and SIGTERM so that we do a proper shutdown, unregistering
+ // the printer from DNS-SD
#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
- sigset(SIGTERM, sigterm_handler);
- sigset(SIGINT, sigterm_handler);
- NOTE("Using signal handler SIGSET");
+ sigset(SIGTERM, sigterm_handler);
+ sigset(SIGINT, sigterm_handler);
+ NOTE("Using signal handler SIGSET");
#elif defined(HAVE_SIGACTION)
- struct sigaction action; /* Actions for POSIX signals */
- memset(&action, 0, sizeof(action));
- sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGTERM);
- action.sa_handler = sigterm_handler;
- sigaction(SIGTERM, &action, NULL);
- sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGINT);
- action.sa_handler = sigterm_handler;
- sigaction(SIGINT, &action, NULL);
- NOTE("Using signal handler SIGACTION");
+ struct sigaction action; /* Actions for POSIX signals */
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGTERM);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGTERM, &action, NULL);
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGINT);
+ action.sa_handler = sigterm_handler;
+ sigaction(SIGINT, &action, NULL);
+ NOTE("Using signal handler SIGACTION");
#else
- signal(SIGTERM, sigterm_handler);
- signal(SIGINT, sigterm_handler);
- NOTE("Using signal handler SIGNAL");
+ signal(SIGTERM, sigterm_handler);
+ signal(SIGINT, sigterm_handler);
+ NOTE("Using signal handler SIGNAL");
#endif /* HAVE_SIGSET */
- // Register for unplug event
- if (usb_can_callback(usb_sock))
- usb_register_callback(usb_sock);
-
- // DNS-SD-broadcast the printer on the local machine so
- // that cups-browsed and ippfind will discover it
- if (usb_sock && g_options.nobroadcast == 0) {
- if (dnssd_init() == -1)
- goto cleanup_tcp;
- }
-
- // Main loop
- int i = 0;
- while (!g_options.terminate) {
- i ++;
- struct service_thread_param *args = calloc(1, sizeof(*args));
- if (args == NULL) {
- ERR("Preparing thread #%d: Failed to alloc space for thread args",
- i);
- goto cleanup_thread;
- }
-
- args->thread_num = i;
- args->usb_sock = usb_sock;
-
- // For each request/response round we use the socket (IPv4 or
- // IPv6) which receives data first
- args->tcp = tcp_conn_select(tcp_socket, tcp6_socket);
- if (g_options.terminate)
- goto cleanup_thread;
- if (args->tcp == NULL) {
- ERR("Preparing thread #%d: Failed to open tcp connection", i);
- goto cleanup_thread;
- }
-
- int status = pthread_create(&args->thread_handle, NULL,
- &service_connection, args);
- if (status) {
- ERR("Creating thread #%d: Failed to spawn thread, error %d",
- i, status);
- goto cleanup_thread;
- }
-
- continue;
-
- cleanup_thread:
- if (args != NULL) {
- if (args->tcp != NULL)
- tcp_conn_close(args->tcp);
- free(args);
- }
- break;
- }
-
-cleanup_tcp:
- if (g_options.dnssd_data != NULL)
- dnssd_shutdown();
-
- if (tcp_socket!= NULL)
- tcp_close(tcp_socket);
- if (tcp6_socket!= NULL)
- tcp_close(tcp6_socket);
-cleanup_usb:
- if (usb_sock != NULL)
- usb_close(usb_sock);
- return;
+ // Register for unplug event
+ if (usb_can_callback(usb_sock))
+ usb_register_callback(usb_sock);
+
+ // DNS-SD-broadcast the printer on the local machine so
+ // that cups-browsed and ippfind will discover it
+ if (usb_sock && g_options.nobroadcast == 0) {
+ if (dnssd_init() == -1)
+ goto cleanup_tcp;
+ }
+
+ // Main loop
+ int i = 0;
+ while (!g_options.terminate) {
+ i ++;
+ struct service_thread_param *args = calloc(1, sizeof(*args));
+ if (args == NULL) {
+ ERR("Preparing thread #%d: Failed to alloc space for thread args",
+ i);
+ goto cleanup_thread;
+ }
+
+ args->thread_num = i;
+ args->usb_sock = usb_sock;
+
+ // For each request/response round we use the socket (IPv4 or
+ // IPv6) which receives data first
+ args->tcp = tcp_conn_select(tcp_socket, tcp6_socket);
+ if (g_options.terminate)
+ goto cleanup_thread;
+ if (args->tcp == NULL) {
+ ERR("Preparing thread #%d: Failed to open tcp connection", i);
+ goto cleanup_thread;
+ }
+
+ int status = pthread_create(&args->thread_handle, NULL,
+ &service_connection, args);
+ if (status) {
+ ERR("Creating thread #%d: Failed to spawn thread, error %d",
+ i, status);
+ goto cleanup_thread;
+ }
+
+ continue;
+
+ cleanup_thread:
+ if (args != NULL) {
+ if (args->tcp != NULL)
+ tcp_conn_close(args->tcp);
+ free(args);
+ }
+ break;
+ }
+
+ cleanup_tcp:
+ if (g_options.dnssd_data != NULL)
+ dnssd_shutdown();
+
+ if (tcp_socket!= NULL)
+ tcp_close(tcp_socket);
+ if (tcp6_socket!= NULL)
+ tcp_close(tcp6_socket);
+ cleanup_usb:
+ if (usb_sock != NULL)
+ usb_close(usb_sock);
+ return;
}
static uint16_t strto16hex(const char *str)
{
- unsigned long val = strtoul(str, NULL, 16);
- if (val > UINT16_MAX)
- exit(1);
- return (uint16_t)val;
+ unsigned long val = strtoul(str, NULL, 16);
+ if (val > UINT16_MAX)
+ exit(1);
+ return (uint16_t)val;
}
static uint16_t strto16dec(const char *str)
{
- unsigned long val = strtoul(str, NULL, 10);
- if (val > UINT16_MAX)
- exit(1);
- return (uint16_t)val;
+ unsigned long val = strtoul(str, NULL, 10);
+ if (val > UINT16_MAX)
+ exit(1);
+ return (uint16_t)val;
}
int main(int argc, char *argv[])
{
- int c;
- int option_index = 0;
- static struct option long_options[] = {
- {"vid", required_argument, 0, 'v' },
- {"pid", required_argument, 0, 'm' },
- {"serial", required_argument, 0, 's' },
- {"bus", required_argument, 0, 'b' },
- {"device", required_argument, 0, 'D' },
- {"bus-device", required_argument, 0, 'X' },
- {"from-port", required_argument, 0, 'P' },
- {"only-port", required_argument, 0, 'p' },
- {"interface", required_argument, 0, 'i' },
- {"logging", no_argument, 0, 'l' },
- {"debug", no_argument, 0, 'd' },
- {"verbose", no_argument, 0, 'q' },
- {"no-fork", no_argument, 0, 'n' },
- {"no-broadcast", no_argument, 0, 'B' },
- {"no-printer", no_argument, 0, 'N' },
- {"help", no_argument, 0, 'h' },
- {NULL, 0, 0, 0 }
- };
- g_options.log_destination = LOGGING_STDERR;
- g_options.only_desired_port = 1;
- g_options.interface = "lo";
- g_options.serial_num = NULL;
- g_options.vendor_id = 0;
- g_options.product_id = 0;
- g_options.bus = 0;
- g_options.device = 0;
-
- while ((c = getopt_long(argc, argv, "qnhdp:P:i:s:lv:m:NB",
- long_options, &option_index)) != -1) {
- switch (c) {
- case '?':
- case 'h':
- g_options.help_mode = 1;
- break;
- case 'p':
- case 'P':
- {
- long long port = 0;
- // Request specific port
- port = atoi(optarg);
- if (port < 0) {
- ERR("Port number must be non-negative");
- return 1;
- }
- if (port > UINT16_MAX) {
- ERR("Port number must be %u or less, "
- "but not negative", UINT16_MAX);
- return 2;
- }
- g_options.desired_port = (uint16_t)port;
- if (c == 'p')
- g_options.only_desired_port = 1;
- else
- g_options.only_desired_port = 0;
- break;
- }
- case 'i':
- // Request a specific network interface
- g_options.interface = strdup(optarg);
- break;
- case 'l':
- g_options.log_destination = LOGGING_SYSLOG;
- break;
- case 'd':
- g_options.nofork_mode = 1;
- g_options.verbose_mode = 1;
- break;
- case 'q':
- g_options.verbose_mode = 1;
- break;
- case 'n':
- g_options.nofork_mode = 1;
- break;
- case 'v':
- g_options.vendor_id = strto16hex(optarg);
- break;
- case 'm':
- g_options.product_id = strto16hex(optarg);
- break;
- case 'b':
- g_options.bus = strto16dec(optarg);
- break;
- case 'D':
- g_options.device = strto16dec(optarg);
- break;
- case 'X':
- {
- char *p = strchr(optarg, ':');
- if (p == NULL) {
- ERR("Bus and device must be given in the format <bus>:<device>");
- return 3;
- }
- p ++;
- g_options.bus = strto16dec(optarg);
- g_options.device = strto16dec(p);
- break;
- }
- case 's':
- g_options.serial_num = (unsigned char *)optarg;
- break;
- case 'N':
- g_options.noprinter_mode = 1;
- break;
- case 'B':
- g_options.nobroadcast = 1;
- break;
- }
+ int c;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"vid", required_argument, 0, 'v' },
+ {"pid", required_argument, 0, 'm' },
+ {"serial", required_argument, 0, 's' },
+ {"bus", required_argument, 0, 'b' },
+ {"device", required_argument, 0, 'D' },
+ {"bus-device", required_argument, 0, 'X' },
+ {"from-port", required_argument, 0, 'P' },
+ {"only-port", required_argument, 0, 'p' },
+ {"interface", required_argument, 0, 'i' },
+ {"logging", no_argument, 0, 'l' },
+ {"debug", no_argument, 0, 'd' },
+ {"verbose", no_argument, 0, 'q' },
+ {"no-fork", no_argument, 0, 'n' },
+ {"no-broadcast", no_argument, 0, 'B' },
+ {"no-printer", no_argument, 0, 'N' },
+ {"help", no_argument, 0, 'h' },
+ {NULL, 0, 0, 0 }
+ };
+ g_options.log_destination = LOGGING_STDERR;
+ g_options.only_desired_port = 1;
+ g_options.interface = "lo";
+ g_options.serial_num = NULL;
+ g_options.vendor_id = 0;
+ g_options.product_id = 0;
+ g_options.bus = 0;
+ g_options.device = 0;
+
+ while ((c = getopt_long(argc, argv, "qnhdp:P:i:s:lv:m:NB",
+ long_options, &option_index)) != -1) {
+ switch (c) {
+ case '?':
+ case 'h':
+ g_options.help_mode = 1;
+ break;
+ case 'p':
+ case 'P':
+ {
+ long long port = 0;
+ // Request specific port
+ port = atoi(optarg);
+ if (port < 0) {
+ ERR("Port number must be non-negative");
+ return 1;
}
-
- if (g_options.help_mode) {
- printf(
- "Usage: %s -v <vendorid> -m <productid> -s <serial> -P <port>\n"
- " %s --bus <bus> --device <device> -P <port>\n"
- " %s -h\n"
- "Options:\n"
- " --help\n"
- " -h Show this help message\n"
- " --vid <vid>\n"
- " -v <vid> Vendor ID of desired printer (as hexadecimal number)\n"
- " --pid <pid>\n"
- " -m <pid> Product ID of desired printer (as hexadecimal number)\n"
- " --serial <serial>\n"
- " -s <serial> Serial number of desired printer\n"
- " --bus <bus>\n"
- " --device <device>\n"
- " --bus-device <bus>:<device>\n"
- " USB bus and device numbers where the device is currently\n"
- " connected (see output of lsusb). Note that these numbers change\n"
- " when the device is disconnected and reconnected. This method of\n"
- " calling ippusbxd is only for calling via UDEV. <bus> and\n"
- " <device> have to be given in decimal numbers.\n"
- " --only-port <portnum>\n"
- " -p <portnum> Port number to bind against, error out if port already taken\n"
- " --from-port <portnum>\n"
- " -P <portnum> Port number to bind against, use another port if port already\n"
- " taken\n"
- " --interface <interface>\n"
- " -i <interface> Network interface to use. Default is the loopback interface\n"
- " (lo, localhost). As the loopback interface does not allow\n"
- " DNS-SD broadcasting with Avahi, set up the dummy interface\n"
- " (dummy0) for DNS-SD broadcasting.\n"
- " --logging\n"
- " -l Redirect logging to syslog\n"
- " --verbose\n"
- " -q Enable verbose tracing\n"
- " --debug\n"
- " -d Debug mode for verbose output and no fork\n"
- " --no-fork\n"
- " -n No-fork mode\n"
- " --no-broadcast\n"
- " -B No-broadcast mode, do not DNS-SD-broadcast\n"
- " --no-printer\n"
- " -N No-printer mode, debug/developer mode which makes ippusbxd\n"
- " run without IPP-over-USB printer\n"
- , argv[0], argv[0], argv[0]);
- return 0;
+ if (port > UINT16_MAX) {
+ ERR("Port number must be %u or less, "
+ "but not negative", UINT16_MAX);
+ return 2;
}
-
- start_daemon();
- return 0;
+ g_options.desired_port = (uint16_t)port;
+ if (c == 'p')
+ g_options.only_desired_port = 1;
+ else
+ g_options.only_desired_port = 0;
+ break;
+ }
+ case 'i':
+ // Request a specific network interface
+ g_options.interface = strdup(optarg);
+ break;
+ case 'l':
+ g_options.log_destination = LOGGING_SYSLOG;
+ break;
+ case 'd':
+ g_options.nofork_mode = 1;
+ g_options.verbose_mode = 1;
+ break;
+ case 'q':
+ g_options.verbose_mode = 1;
+ break;
+ case 'n':
+ g_options.nofork_mode = 1;
+ break;
+ case 'v':
+ g_options.vendor_id = strto16hex(optarg);
+ break;
+ case 'm':
+ g_options.product_id = strto16hex(optarg);
+ break;
+ case 'b':
+ g_options.bus = strto16dec(optarg);
+ break;
+ case 'D':
+ g_options.device = strto16dec(optarg);
+ break;
+ case 'X':
+ {
+ char *p = strchr(optarg, ':');
+ if (p == NULL) {
+ ERR("Bus and device must be given in the format <bus>:<device>");
+ return 3;
+ }
+ p ++;
+ g_options.bus = strto16dec(optarg);
+ g_options.device = strto16dec(p);
+ break;
+ }
+ case 's':
+ g_options.serial_num = (unsigned char *)optarg;
+ break;
+ case 'N':
+ g_options.noprinter_mode = 1;
+ break;
+ case 'B':
+ g_options.nobroadcast = 1;
+ break;
+ }
+ }
+
+ if (g_options.help_mode) {
+ printf("Usage: %s -v <vendorid> -m <productid> -s <serial> -P <port>\n"
+ " %s --bus <bus> --device <device> -P <port>\n"
+ " %s -h\n"
+ "Options:\n"
+ " --help\n"
+ " -h Show this help message\n"
+ " --vid <vid>\n"
+ " -v <vid> Vendor ID of desired printer (as hexadecimal number)\n"
+ " --pid <pid>\n"
+ " -m <pid> Product ID of desired printer (as hexadecimal number)\n"
+ " --serial <serial>\n"
+ " -s <serial> Serial number of desired printer\n"
+ " --bus <bus>\n"
+ " --device <device>\n"
+ " --bus-device <bus>:<device>\n"
+ " USB bus and device numbers where the device is currently\n"
+ " connected (see output of lsusb). Note that these numbers change\n"
+ " when the device is disconnected and reconnected. This method of\n"
+ " calling ippusbxd is only for calling via UDEV. <bus> and\n"
+ " <device> have to be given in decimal numbers.\n"
+ " --only-port <portnum>\n"
+ " -p <portnum> Port number to bind against, error out if port already taken\n"
+ " --from-port <portnum>\n"
+ " -P <portnum> Port number to bind against, use another port if port already\n"
+ " taken\n"
+ " --interface <interface>\n"
+ " -i <interface> Network interface to use. Default is the loopback interface\n"
+ " (lo, localhost). As the loopback interface does not allow\n"
+ " DNS-SD broadcasting with Avahi, set up the dummy interface\n"
+ " (dummy0) for DNS-SD broadcasting.\n"
+ " --logging\n"
+ " -l Redirect logging to syslog\n"
+ " --verbose\n"
+ " -q Enable verbose tracing\n"
+ " --debug\n"
+ " -d Debug mode for verbose output and no fork\n"
+ " --no-fork\n"
+ " -n No-fork mode\n"
+ " --no-broadcast\n"
+ " -B No-broadcast mode, do not DNS-SD-broadcast\n"
+ " --no-printer\n"
+ " -N No-printer mode, debug/developer mode which makes ippusbxd\n"
+ " run without IPP-over-USB printer\n"
+ , argv[0], argv[0], argv[0]);
+ return 0;
+ }
+
+ start_daemon();
+ return 0;
}
diff --git a/src/logging.c b/src/logging.c
index 708f7a1..eba1e15 100644
--- a/src/logging.c
+++ b/src/logging.c
@@ -24,16 +24,16 @@
void BASE_LOG(enum log_level level, const char *fmt, ...)
{
- if (!g_options.verbose_mode && level != LOGGING_ERROR)
- return;
+ if (!g_options.verbose_mode && level != LOGGING_ERROR)
+ return;
- va_list arg;
- va_start(arg, fmt);
- if (g_options.log_destination == LOGGING_STDERR)
- vfprintf(stderr, fmt, arg);
- else if (g_options.log_destination == LOGGING_SYSLOG)
- syslog(LOG_ERR, fmt, arg);
- va_end(arg);
+ va_list arg;
+ va_start(arg, fmt);
+ if (g_options.log_destination == LOGGING_STDERR)
+ vfprintf(stderr, fmt, arg);
+ else if (g_options.log_destination == LOGGING_SYSLOG)
+ syslog(LOG_ERR, fmt, arg);
+ va_end(arg);
}
char* hexdump (void *addr, int len) {
diff --git a/src/logging.h b/src/logging.h
index 704108d..45b00d8 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -19,10 +19,10 @@
#define TID() (pthread_self())
enum log_level {
- LOGGING_ERROR,
- LOGGING_WARNING,
- LOGGING_NOTICE,
- LOGGING_CONFORMANCE,
+ LOGGING_ERROR,
+ LOGGING_WARNING,
+ LOGGING_NOTICE,
+ LOGGING_CONFORMANCE,
};
#define PP_CAT(x, y) PP_CAT_2(x, y)
diff --git a/src/options.h b/src/options.h
index 3e1af6c..02f3c04 100644
--- a/src/options.h
+++ b/src/options.h
@@ -17,36 +17,36 @@
#include "dnssd.h"
enum log_target {
- LOGGING_STDERR,
- LOGGING_SYSLOG
+ LOGGING_STDERR,
+ LOGGING_SYSLOG
};
struct options {
- // Runtime configuration
- uint16_t desired_port;
- int only_desired_port;
- uint16_t real_port;
- char *interface;
- enum log_target log_destination;
+ // Runtime configuration
+ uint16_t desired_port;
+ int only_desired_port;
+ uint16_t real_port;
+ char *interface;
+ enum log_target log_destination;
- // Behavior
- int help_mode;
- int verbose_mode;
- int nofork_mode;
- int noprinter_mode;
- int nobroadcast;
+ // Behavior
+ int help_mode;
+ int verbose_mode;
+ int nofork_mode;
+ int noprinter_mode;
+ int nobroadcast;
- // Printer identity
- unsigned char *serial_num;
- int vendor_id;
- int product_id;
- int bus;
- int device;
- char *device_id;
+ // Printer identity
+ unsigned char *serial_num;
+ int vendor_id;
+ int product_id;
+ int bus;
+ int device;
+ char *device_id;
- // Global variables
- int terminate;
- dnssd_t *dnssd_data;
+ // Global variables
+ int terminate;
+ dnssd_t *dnssd_data;
};
extern struct options g_options;
diff --git a/src/tcp.c b/src/tcp.c
index 9911a5d..a77a4c4 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -37,317 +37,315 @@
struct tcp_sock_t *tcp_open(uint16_t port, char* interface)
{
- struct tcp_sock_t *this = calloc(1, sizeof *this);
- if (this == NULL) {
- ERR("IPv4: callocing this failed");
- goto error;
- }
-
- // Open [S]ocket [D]escriptor
- this->sd = -1;
- this->sd = socket(AF_INET, SOCK_STREAM, 0);
- if (this->sd < 0) {
- ERR("IPv4 socket open failed");
- goto error;
- }
-
- // Find the IP address for the selected interface
- struct ifaddrs *ifaddr, *ifa;
- getifaddrs(&ifaddr);
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL)
- continue;
- if ((strcmp(ifa->ifa_name, interface) == 0) &&
- (ifa->ifa_addr->sa_family == AF_INET))
- break;
- }
- if (ifa == NULL) {
- ERR("Interface %s does not exist or IPv4 IP not found.", interface);
- goto error;
- }
-
- // Configure socket params
- struct sockaddr_in addr, *if_addr;
- if_addr = (struct sockaddr_in *) ifa->ifa_addr;
- memset(&addr, 0, sizeof addr);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = if_addr->sin_addr.s_addr;
- //addr.sin_addr.s_addr = htonl(0xC0A8000F);
- NOTE("IPv4: Binding to %s:%d", inet_ntoa(if_addr->sin_addr), port);
-
- // Bind to the interface/IP/port
- if (bind(this->sd,
- (struct sockaddr *)&addr,
- sizeof addr) < 0) {
- if (g_options.only_desired_port == 1)
- ERR("IPv4 bind on port failed. "
- "Requested port may be taken or require root permissions.");
- goto error;
- }
-
- // Let kernel over-accept max number of connections
- if (listen(this->sd, HTTP_MAX_PENDING_CONNS) < 0) {
- ERR("IPv4 listen failed on socket");
- goto error;
- }
-
- return this;
-
-error:
- if (this != NULL) {
- if (this->sd != -1) {
- close(this->sd);
- }
- free(this);
- }
- return NULL;
+ struct tcp_sock_t *this = calloc(1, sizeof *this);
+ if (this == NULL) {
+ ERR("IPv4: callocing this failed");
+ goto error;
+ }
+
+ // Open [S]ocket [D]escriptor
+ this->sd = -1;
+ this->sd = socket(AF_INET, SOCK_STREAM, 0);
+ if (this->sd < 0) {
+ ERR("IPv4 socket open failed");
+ goto error;
+ }
+
+ // Find the IP address for the selected interface
+ struct ifaddrs *ifaddr, *ifa;
+ getifaddrs(&ifaddr);
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if ((strcmp(ifa->ifa_name, interface) == 0) &&
+ (ifa->ifa_addr->sa_family == AF_INET))
+ break;
+ }
+ if (ifa == NULL) {
+ ERR("Interface %s does not exist or IPv4 IP not found.", interface);
+ goto error;
+ }
+
+ // Configure socket params
+ struct sockaddr_in addr, *if_addr;
+ if_addr = (struct sockaddr_in *) ifa->ifa_addr;
+ memset(&addr, 0, sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = if_addr->sin_addr.s_addr;
+ //addr.sin_addr.s_addr = htonl(0xC0A8000F);
+ NOTE("IPv4: Binding to %s:%d", inet_ntoa(if_addr->sin_addr), port);
+
+ // Bind to the interface/IP/port
+ if (bind(this->sd,
+ (struct sockaddr *)&addr,
+ sizeof addr) < 0) {
+ if (g_options.only_desired_port == 1)
+ ERR("IPv4 bind on port failed. "
+ "Requested port may be taken or require root permissions.");
+ goto error;
+ }
+
+ // Let kernel over-accept max number of connections
+ if (listen(this->sd, HTTP_MAX_PENDING_CONNS) < 0) {
+ ERR("IPv4 listen failed on socket");
+ goto error;
+ }
+
+ return this;
+
+ error:
+ if (this != NULL) {
+ if (this->sd != -1) {
+ close(this->sd);
+ }
+ free(this);
+ }
+ return NULL;
}
struct tcp_sock_t *tcp6_open(uint16_t port, char* interface)
{
- struct tcp_sock_t *this = calloc(1, sizeof *this);
- if (this == NULL) {
- ERR("IPv6: callocing this failed");
- goto error;
- }
-
- // Open [S]ocket [D]escriptor
- this->sd = -1;
- this->sd = socket(AF_INET6, SOCK_STREAM, 0);
- if (this->sd < 0) {
- ERR("Ipv6 socket open failed");
- goto error;
- }
-
- // Find the IP address for the selected interface
- struct ifaddrs *ifaddr, *ifa;
- getifaddrs(&ifaddr);
- for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL)
- continue;
- if ((strcmp(ifa->ifa_name, interface) == 0) &&
- (ifa->ifa_addr->sa_family == AF_INET6))
- break;
- }
- if (ifa == NULL) {
- ERR("Interface %s does not exist or IPv6 IP not found.", interface);
- goto error;
- }
-
- // Configure socket params
- struct sockaddr_in6 addr, *if_addr;
- char buf[64];
- if_addr = (struct sockaddr_in6 *) ifa->ifa_addr;
- memset(&addr, 0, sizeof addr);
- addr.sin6_family = AF_INET6;
- addr.sin6_port = htons(port);
- addr.sin6_addr = if_addr->sin6_addr;
- addr.sin6_scope_id=if_nametoindex(interface);
- if (inet_ntop(addr.sin6_family, (void *)&(addr.sin6_addr),
- buf, sizeof(buf)) == NULL) {
- ERR("Could not determine IPv6 IP address for interface %s.",
- interface);
- goto error;
- }
- NOTE("IPv6: Binding to [%s]:%d", buf, port);
-
- // Bind to the interface/IP/port
- if (bind(this->sd,
- (struct sockaddr *)&addr,
- sizeof addr) < 0) {
- if (g_options.only_desired_port == 1)
- ERR("IPv6 bind on port failed. "
- "Requested port may be taken or require root permissions.");
- goto error;
- }
-
- // Let kernel over-accept max number of connections
- if (listen(this->sd, HTTP_MAX_PENDING_CONNS) < 0) {
- ERR("IPv6 listen failed on socket");
- goto error;
- }
-
- return this;
-
-error:
- if (this != NULL) {
- if (this->sd != -1) {
- close(this->sd);
- }
- free(this);
- }
- return NULL;
+ struct tcp_sock_t *this = calloc(1, sizeof *this);
+ if (this == NULL) {
+ ERR("IPv6: callocing this failed");
+ goto error;
+ }
+
+ // Open [S]ocket [D]escriptor
+ this->sd = -1;
+ this->sd = socket(AF_INET6, SOCK_STREAM, 0);
+ if (this->sd < 0) {
+ ERR("Ipv6 socket open failed");
+ goto error;
+ }
+
+ // Find the IP address for the selected interface
+ struct ifaddrs *ifaddr, *ifa;
+ getifaddrs(&ifaddr);
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL)
+ continue;
+ if ((strcmp(ifa->ifa_name, interface) == 0) &&
+ (ifa->ifa_addr->sa_family == AF_INET6))
+ break;
+ }
+ if (ifa == NULL) {
+ ERR("Interface %s does not exist or IPv6 IP not found.", interface);
+ goto error;
+ }
+
+ // Configure socket params
+ struct sockaddr_in6 addr, *if_addr;
+ char buf[64];
+ if_addr = (struct sockaddr_in6 *) ifa->ifa_addr;
+ memset(&addr, 0, sizeof addr);
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(port);
+ addr.sin6_addr = if_addr->sin6_addr;
+ addr.sin6_scope_id=if_nametoindex(interface);
+ if (inet_ntop(addr.sin6_family, (void *)&(addr.sin6_addr),
+ buf, sizeof(buf)) == NULL) {
+ ERR("Could not determine IPv6 IP address for interface %s.",
+ interface);
+ goto error;
+ }
+ NOTE("IPv6: Binding to [%s]:%d", buf, port);
+
+ // Bind to the interface/IP/port
+ if (bind(this->sd,
+ (struct sockaddr *)&addr,
+ sizeof addr) < 0) {
+ if (g_options.only_desired_port == 1)
+ ERR("IPv6 bind on port failed. "
+ "Requested port may be taken or require root permissions.");
+ goto error;
+ }
+
+ // Let kernel over-accept max number of connections
+ if (listen(this->sd, HTTP_MAX_PENDING_CONNS) < 0) {
+ ERR("IPv6 listen failed on socket");
+ goto error;
+ }
+
+ return this;
+
+ error:
+ if (this != NULL) {
+ if (this->sd != -1) {
+ close(this->sd);
+ }
+ free(this);
+ }
+ return NULL;
}
void tcp_close(struct tcp_sock_t *this)
{
- close(this->sd);
- free(this);
+ close(this->sd);
+ free(this);
}
uint16_t tcp_port_number_get(struct tcp_sock_t *sock)
{
- sock->info_size = sizeof sock->info;
- int query_status = getsockname(
- sock->sd,
- (struct sockaddr *) &(sock->info),
- &(sock->info_size));
- if (query_status == -1) {
- ERR("query on socket port number failed");
- goto error;
- }
-
- return ntohs(sock->info.sin6_port);
-
-error:
- return 0;
+ sock->info_size = sizeof sock->info;
+ int query_status = getsockname(sock->sd,
+ (struct sockaddr *) &(sock->info),
+ &(sock->info_size));
+ if (query_status == -1) {
+ ERR("query on socket port number failed");
+ goto error;
+ }
+
+ return ntohs(sock->info.sin6_port);
+
+ error:
+ return 0;
}
struct http_packet_t *tcp_packet_get(struct tcp_conn_t *tcp,
struct http_message_t *msg)
{
- // Alloc packet ==---------------------------------------------------==
- struct http_packet_t *pkt = packet_new(msg);
- if (pkt == NULL) {
- ERR("failed to create packet for incoming tcp message");
- goto error;
- }
-
- size_t want_size = packet_pending_bytes(pkt);
- if (want_size == 0) {
- NOTE("TCP: Got %lu from spare buffer", pkt->filled_size);
- return pkt;
- }
-
- struct timeval tv;
- tv.tv_sec = 3;
- tv.tv_usec = 0;
- setsockopt(tcp->sd, SOL_SOCKET, SO_RCVTIMEO,
- (char *)&tv, sizeof(struct timeval));
-
- while (want_size != 0 && !msg->is_completed) {
- NOTE("TCP: Getting %d bytes", want_size);
- uint8_t *subbuffer = pkt->buffer + pkt->filled_size;
- ssize_t gotten_size = recv(tcp->sd, subbuffer, want_size, 0);
- if (gotten_size < 0) {
- int errno_saved = errno;
- ERR("recv failed with err %d:%s", errno_saved,
- strerror(errno_saved));
- tcp->is_closed = 1;
- goto error;
- }
- NOTE("TCP: Got %d bytes", gotten_size);
- if (gotten_size == 0) {
- tcp->is_closed = 1;
- if (pkt->filled_size == 0) {
- // Client closed TCP conn
- goto error;
- } else {
- break;
- }
- }
-
- packet_mark_received(pkt, (unsigned) gotten_size);
- want_size = packet_pending_bytes(pkt);
- NOTE("TCP: Want more %d bytes; Message %scompleted", want_size, msg->is_completed ? "" : "not ");
- }
-
- NOTE("TCP: Received %lu bytes", pkt->filled_size);
- return pkt;
-
-error:
- if (pkt != NULL)
- packet_free(pkt);
- return NULL;
+ // Alloc packet ==---------------------------------------------------==
+ struct http_packet_t *pkt = packet_new(msg);
+ if (pkt == NULL) {
+ ERR("failed to create packet for incoming tcp message");
+ goto error;
+ }
+
+ size_t want_size = packet_pending_bytes(pkt);
+ if (want_size == 0) {
+ NOTE("TCP: Got %lu from spare buffer", pkt->filled_size);
+ return pkt;
+ }
+
+ struct timeval tv;
+ tv.tv_sec = 3;
+ tv.tv_usec = 0;
+ setsockopt(tcp->sd, SOL_SOCKET, SO_RCVTIMEO,
+ (char *)&tv, sizeof(struct timeval));
+
+ while (want_size != 0 && !msg->is_completed) {
+ NOTE("TCP: Getting %d bytes", want_size);
+ uint8_t *subbuffer = pkt->buffer + pkt->filled_size;
+ ssize_t gotten_size = recv(tcp->sd, subbuffer, want_size, 0);
+ if (gotten_size < 0) {
+ int errno_saved = errno;
+ ERR("recv failed with err %d:%s", errno_saved,
+ strerror(errno_saved));
+ tcp->is_closed = 1;
+ goto error;
+ }
+ NOTE("TCP: Got %d bytes", gotten_size);
+ if (gotten_size == 0) {
+ tcp->is_closed = 1;
+ if (pkt->filled_size == 0) {
+ // Client closed TCP conn
+ goto error;
+ } else {
+ break;
+ }
+ }
+
+ packet_mark_received(pkt, (unsigned) gotten_size);
+ want_size = packet_pending_bytes(pkt);
+ NOTE("TCP: Want more %d bytes; Message %scompleted", want_size, msg->is_completed ? "" : "not ");
+ }
+
+ NOTE("TCP: Received %lu bytes", pkt->filled_size);
+ return pkt;
+
+ error:
+ if (pkt != NULL)
+ packet_free(pkt);
+ return NULL;
}
int tcp_packet_send(struct tcp_conn_t *conn, struct http_packet_t *pkt)
{
- size_t remaining = pkt->filled_size;
- size_t total = 0;
- while (remaining > 0) {
- ssize_t sent = send(conn->sd, pkt->buffer + total,
- remaining, MSG_NOSIGNAL);
- if (sent < 0) {
- if (errno == EPIPE) {
- conn->is_closed = 1;
- return 0;
- }
- ERR("Failed to sent data over TCP");
- return -1;
- }
-
- size_t sent_ulong = (unsigned) sent;
- total += sent_ulong;
- if (sent_ulong >= remaining)
- remaining = 0;
- else
- remaining -= sent_ulong;
- }
- NOTE("TCP: sent %lu bytes", total);
+ size_t remaining = pkt->filled_size;
+ size_t total = 0;
+ while (remaining > 0) {
+ ssize_t sent = send(conn->sd, pkt->buffer + total,
+ remaining, MSG_NOSIGNAL);
+ if (sent < 0) {
+ if (errno == EPIPE) {
+ conn->is_closed = 1;
return 0;
+ }
+ ERR("Failed to sent data over TCP");
+ return -1;
+ }
+
+ size_t sent_ulong = (unsigned) sent;
+ total += sent_ulong;
+ if (sent_ulong >= remaining)
+ remaining = 0;
+ else
+ remaining -= sent_ulong;
+ }
+ NOTE("TCP: sent %lu bytes", total);
+ return 0;
}
struct tcp_conn_t *tcp_conn_select(struct tcp_sock_t *sock,
struct tcp_sock_t *sock6)
{
- struct tcp_conn_t *conn = calloc(1, sizeof *conn);
- if (conn == NULL) {
- ERR("Calloc for connection struct failed");
- goto error;
- }
- fd_set rfds;
- int retval = 0;
- int nfds = 0;
- FD_ZERO(&rfds);
- if (sock) {
- FD_SET(sock->sd, &rfds);
- nfds = sock->sd;
- }
- if (sock6) {
- FD_SET(sock6->sd, &rfds);
- if (sock6->sd > nfds)
- nfds = sock6->sd;
- }
- if (nfds == 0) {
- ERR("No valid TCP socket supplied.");
- goto error;
- }
- nfds += 1;
- retval = select(nfds, &rfds, NULL, NULL, NULL);
- if (g_options.terminate)
- goto error;
- if (retval < 1) {
- ERR("Failed to open tcp connection");
- goto error;
- }
- if (sock && FD_ISSET(sock->sd, &rfds)) {
- conn->sd = accept(sock->sd, NULL, NULL);
- NOTE ("Using IPv4");
- } else if (sock6 && FD_ISSET(sock6->sd, &rfds)) {
- conn->sd = accept(sock6->sd, NULL, NULL);
- NOTE ("Using IPv6");
- } else {
- ERR("select failed");
- goto error;
- }
- if (conn->sd < 0) {
- ERR("accept failed");
- goto error;
- }
- return conn;
-
-error:
- if (conn != NULL)
- free(conn);
- return NULL;
+ struct tcp_conn_t *conn = calloc(1, sizeof *conn);
+ if (conn == NULL) {
+ ERR("Calloc for connection struct failed");
+ goto error;
+ }
+ fd_set rfds;
+ int retval = 0;
+ int nfds = 0;
+ FD_ZERO(&rfds);
+ if (sock) {
+ FD_SET(sock->sd, &rfds);
+ nfds = sock->sd;
+ }
+ if (sock6) {
+ FD_SET(sock6->sd, &rfds);
+ if (sock6->sd > nfds)
+ nfds = sock6->sd;
+ }
+ if (nfds == 0) {
+ ERR("No valid TCP socket supplied.");
+ goto error;
+ }
+ nfds += 1;
+ retval = select(nfds, &rfds, NULL, NULL, NULL);
+ if (g_options.terminate)
+ goto error;
+ if (retval < 1) {
+ ERR("Failed to open tcp connection");
+ goto error;
+ }
+ if (sock && FD_ISSET(sock->sd, &rfds)) {
+ conn->sd = accept(sock->sd, NULL, NULL);
+ NOTE ("Using IPv4");
+ } else if (sock6 && FD_ISSET(sock6->sd, &rfds)) {
+ conn->sd = accept(sock6->sd, NULL, NULL);
+ NOTE ("Using IPv6");
+ } else {
+ ERR("select failed");
+ goto error;
+ }
+ if (conn->sd < 0) {
+ ERR("accept failed");
+ goto error;
+ }
+ return conn;
+
+ error:
+ if (conn != NULL)
+ free(conn);
+ return NULL;
}
void tcp_conn_close(struct tcp_conn_t *conn)
{
- close(conn->sd);
- free(conn);
+ close(conn->sd);
+ free(conn);
}
-
diff --git a/src/tcp.h b/src/tcp.h
index c671824..e58cb17 100644
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -29,14 +29,14 @@
#define BUFFER_MAX (1 << 20)
struct tcp_sock_t {
- int sd;
- struct sockaddr_in6 info;
- socklen_t info_size;
+ int sd;
+ struct sockaddr_in6 info;
+ socklen_t info_size;
};
struct tcp_conn_t {
- int sd;
- int is_closed;
+ int sd;
+ int is_closed;
};
struct tcp_sock_t *tcp_open(uint16_t, char* interface);
diff --git a/src/usb.c b/src/usb.c
index 7ce46c2..a5aec2c 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -34,90 +34,90 @@ static int bus, dev_addr;
static int is_ippusb_interface(const struct libusb_interface_descriptor *interf)
{
- return interf->bInterfaceClass == 0x07 &&
- interf->bInterfaceSubClass == 0x01 &&
- interf->bInterfaceProtocol == 0x04;
+ return interf->bInterfaceClass == 0x07 &&
+ interf->bInterfaceSubClass == 0x01 &&
+ interf->bInterfaceProtocol == 0x04;
}
static int count_ippoverusb_interfaces(struct libusb_config_descriptor *config)
{
- int ippusb_interface_count = 0;
+ int ippusb_interface_count = 0;
- NOTE("Counting IPP-over-USB interfaces ...");
- for (uint8_t interface_num = 0;
- interface_num < config->bNumInterfaces;
- interface_num++) {
+ NOTE("Counting IPP-over-USB interfaces ...");
+ for (uint8_t interface_num = 0;
+ interface_num < config->bNumInterfaces;
+ interface_num++) {
- const struct libusb_interface *interface = NULL;
- interface = &config->interface[interface_num];
+ const struct libusb_interface *interface = NULL;
+ interface = &config->interface[interface_num];
- for (int alt_num = 0;
- alt_num < interface->num_altsetting;
- alt_num++) {
-
- const struct libusb_interface_descriptor *alt = NULL;
- alt = &interface->altsetting[alt_num];
- NOTE("Interface %d, Alt %d: Class %d, Subclass %d, Protocol %d",
- interface_num, alt_num, alt->bInterfaceClass,
- alt->bInterfaceSubClass, alt->bInterfaceProtocol);
-
- // Check for IPP over USB interfaces
- if (!is_ippusb_interface(alt))
- continue;
-
- NOTE(" -> is IPP-over-USB");
- ippusb_interface_count++;
- break;
- }
- }
+ for (int alt_num = 0;
+ alt_num < interface->num_altsetting;
+ alt_num++) {
+
+ const struct libusb_interface_descriptor *alt = NULL;
+ alt = &interface->altsetting[alt_num];
+ NOTE("Interface %d, Alt %d: Class %d, Subclass %d, Protocol %d",
+ interface_num, alt_num, alt->bInterfaceClass,
+ alt->bInterfaceSubClass, alt->bInterfaceProtocol);
+
+ // Check for IPP over USB interfaces
+ if (!is_ippusb_interface(alt))
+ continue;
+
+ NOTE(" -> is IPP-over-USB");
+ ippusb_interface_count++;
+ break;
+ }
+ }
- NOTE(" -> %d Interfaces", ippusb_interface_count);
- return ippusb_interface_count;
+ NOTE(" -> %d Interfaces", ippusb_interface_count);
+ return ippusb_interface_count;
}
static int is_our_device(libusb_device *dev,
struct libusb_device_descriptor desc)
{
- static const int SERIAL_MAX = 1024;
- unsigned char serial[1024];
- NOTE("Found device: VID %04x, PID %04x on Bus %03d, Device %03d",
- desc.idVendor, desc.idProduct,
- libusb_get_bus_number(dev), libusb_get_device_address(dev));
- if ((g_options.vendor_id && desc.idVendor != g_options.vendor_id) ||
- (g_options.product_id && desc.idProduct != g_options.product_id) ||
- (g_options.bus &&
- libusb_get_bus_number(dev) != g_options.bus) ||
- (g_options.device &&
- libusb_get_device_address(dev) != g_options.device))
- return 0;
-
- if (g_options.serial_num == NULL)
- return 1;
-
- libusb_device_handle *handle = NULL;
- int status = libusb_open(dev, &handle);
- if (status != 0) {
- // Device turned off or disconnected, we cannot retrieve its
- // serial number any more, so we identify it via bus and device
- // addresses
- return (bus == libusb_get_bus_number(dev) &&
- dev_addr == libusb_get_device_address(dev));
- } else {
- // Device is turned on and connected, read out its serial number
- // and use the serial number for identification
- status = libusb_get_string_descriptor_ascii(handle,
- desc.iSerialNumber,
- serial, SERIAL_MAX);
- libusb_close(handle);
-
- if (status <= 0) {
- WARN("Failed to get serial from device");
- return 0;
- }
-
- return strcmp((char *)serial,
- (char *)g_options.serial_num) == 0;
- }
+ static const int SERIAL_MAX = 1024;
+ unsigned char serial[1024];
+ NOTE("Found device: VID %04x, PID %04x on Bus %03d, Device %03d",
+ desc.idVendor, desc.idProduct,
+ libusb_get_bus_number(dev), libusb_get_device_address(dev));
+ if ((g_options.vendor_id && desc.idVendor != g_options.vendor_id) ||
+ (g_options.product_id && desc.idProduct != g_options.product_id) ||
+ (g_options.bus &&
+ libusb_get_bus_number(dev) != g_options.bus) ||
+ (g_options.device &&
+ libusb_get_device_address(dev) != g_options.device))
+ return 0;
+
+ if (g_options.serial_num == NULL)
+ return 1;
+
+ libusb_device_handle *handle = NULL;
+ int status = libusb_open(dev, &handle);
+ if (status != 0) {
+ // Device turned off or disconnected, we cannot retrieve its
+ // serial number any more, so we identify it via bus and device
+ // addresses
+ return (bus == libusb_get_bus_number(dev) &&
+ dev_addr == libusb_get_device_address(dev));
+ } else {
+ // Device is turned on and connected, read out its serial number
+ // and use the serial number for identification
+ status = libusb_get_string_descriptor_ascii(handle,
+ desc.iSerialNumber,
+ serial, SERIAL_MAX);
+ libusb_close(handle);
+
+ if (status <= 0) {
+ WARN("Failed to get serial from device");
+ return 0;
+ }
+
+ return strcmp((char *)serial,
+ (char *)g_options.serial_num) == 0;
+ }
}
int get_device_id(struct libusb_device_handle *handle,
@@ -169,302 +169,296 @@ int get_device_id(struct libusb_device_handle *handle,
struct usb_sock_t *usb_open()
{
- int status_lock;
- struct usb_sock_t *usb = calloc(1, sizeof *usb);
- int status = 1;
- usb->device_id = NULL;
- status = libusb_init(&usb->context);
- if (status < 0) {
- ERR("libusb init failed with error: %s",
- libusb_error_name(status));
- goto error_usbinit;
- }
-
- libusb_device **device_list = NULL;
- ssize_t device_count = libusb_get_device_list(usb->context, &device_list);
- if (device_count < 0) {
- ERR("failed to get list of usb devices");
- goto error;
- }
-
-
- // Discover device and count interfaces ==---------------------------==
- int selected_config = -1;
- unsigned int selected_ipp_interface_count = 0;
- int auto_pick = !((g_options.vendor_id &&
- g_options.product_id) ||
- g_options.serial_num ||
- (g_options.bus &&
- g_options.device));
-
- libusb_device *printer_device = NULL;
-
- if (g_options.vendor_id || g_options.product_id)
- NOTE("Searching for device: VID %04x, PID %04x",
- g_options.vendor_id, g_options.product_id);
- if (g_options.serial_num)
- NOTE("Searching for device with serial number %s",
- g_options.serial_num);
- if (g_options.bus || g_options.device)
- NOTE("Searching for device: Bus %03d, Device %03d",
- g_options.bus, g_options.device);
- if (auto_pick)
- NOTE("Searching for first IPP-over-USB-capable device available");
-
- for (ssize_t i = 0; i < device_count; i++) {
- libusb_device *candidate = device_list[i];
- struct libusb_device_descriptor desc;
- libusb_get_device_descriptor(candidate, &desc);
-
- if (!is_our_device(candidate, desc))
- continue;
-
- // Save VID/PID for exit-on-unplug
- if (g_options.vendor_id == 0)
- g_options.vendor_id = desc.idVendor;
- if (g_options.product_id == 0)
- g_options.product_id = desc.idProduct;
-
- bus = libusb_get_bus_number(candidate);
- dev_addr = libusb_get_device_address(candidate);
- NOTE("Printer connected on bus %03d device %03d",
- bus, dev_addr);
-
- for (uint8_t config_num = 0;
- config_num < desc.bNumConfigurations;
- config_num++) {
- struct libusb_config_descriptor *config = NULL;
- status = libusb_get_config_descriptor(candidate,
- config_num,
- &config);
- if (status < 0) {
- ERR("USB: didn't get config desc %s",
- libusb_error_name(status));
- goto error;
- }
-
- int interface_count = count_ippoverusb_interfaces(config);
- libusb_free_config_descriptor(config);
- if (interface_count >= 2) {
- selected_config = config_num;
- selected_ipp_interface_count = (unsigned) interface_count;
- printer_device = candidate;
- goto found_device;
- }
-
- // CONFTEST: Two or more interfaces are required
- if (interface_count == 1) {
- CONF("usb device has only one ipp interface "
- "in violation of standard");
- goto error;
- }
-
- if (!auto_pick) {
- ERR("No ipp-usb interfaces found");
- goto error;
- }
- }
- }
-found_device:
-
- if (printer_device == NULL) {
- if (!auto_pick) {
- ERR("No printer found by that vid, pid, serial or bus, device");
- } else {
- ERR("No IPP over USB printer found");
- }
- goto error;
- }
-
-
- // Open the printer ==-----------------------------------------------==
- status = libusb_open(printer_device, &usb->printer);
- if (status != 0) {
- ERR("failed to open device");
- goto error;
- }
+ int status_lock;
+ struct usb_sock_t *usb = calloc(1, sizeof *usb);
+ int status = 1;
+ usb->device_id = NULL;
+ status = libusb_init(&usb->context);
+ if (status < 0) {
+ ERR("libusb init failed with error: %s",
+ libusb_error_name(status));
+ goto error_usbinit;
+ }
+ libusb_device **device_list = NULL;
+ ssize_t device_count = libusb_get_device_list(usb->context, &device_list);
+ if (device_count < 0) {
+ ERR("failed to get list of usb devices");
+ goto error;
+ }
- // Open every IPP-USB interface ==-----------------------------------==
- usb->num_interfaces = selected_ipp_interface_count;
- usb->interfaces = calloc(usb->num_interfaces,
- sizeof(*usb->interfaces));
- if (usb->interfaces == NULL) {
- ERR("Failed to alloc interfaces");
- goto error;
- }
+ // Discover device and count interfaces ==---------------------------==
+ int selected_config = -1;
+ unsigned int selected_ipp_interface_count = 0;
+ int auto_pick = !((g_options.vendor_id &&
+ g_options.product_id) ||
+ g_options.serial_num ||
+ (g_options.bus &&
+ g_options.device));
+
+ libusb_device *printer_device = NULL;
+
+ if (g_options.vendor_id || g_options.product_id)
+ NOTE("Searching for device: VID %04x, PID %04x",
+ g_options.vendor_id, g_options.product_id);
+ if (g_options.serial_num)
+ NOTE("Searching for device with serial number %s",
+ g_options.serial_num);
+ if (g_options.bus || g_options.device)
+ NOTE("Searching for device: Bus %03d, Device %03d",
+ g_options.bus, g_options.device);
+ if (auto_pick)
+ NOTE("Searching for first IPP-over-USB-capable device available");
+
+ for (ssize_t i = 0; i < device_count; i++) {
+ libusb_device *candidate = device_list[i];
+ struct libusb_device_descriptor desc;
+ libusb_get_device_descriptor(candidate, &desc);
+
+ if (!is_our_device(candidate, desc))
+ continue;
+
+ // Save VID/PID for exit-on-unplug
+ if (g_options.vendor_id == 0)
+ g_options.vendor_id = desc.idVendor;
+ if (g_options.product_id == 0)
+ g_options.product_id = desc.idProduct;
+
+ bus = libusb_get_bus_number(candidate);
+ dev_addr = libusb_get_device_address(candidate);
+ NOTE("Printer connected on bus %03d device %03d",
+ bus, dev_addr);
+
+ for (uint8_t config_num = 0;
+ config_num < desc.bNumConfigurations;
+ config_num++) {
+ struct libusb_config_descriptor *config = NULL;
+ status = libusb_get_config_descriptor(candidate,
+ config_num,
+ &config);
+ if (status < 0) {
+ ERR("USB: didn't get config desc %s",
+ libusb_error_name(status));
+ goto error;
+ }
+
+ int interface_count = count_ippoverusb_interfaces(config);
+ libusb_free_config_descriptor(config);
+ if (interface_count >= 2) {
+ selected_config = config_num;
+ selected_ipp_interface_count = (unsigned) interface_count;
+ printer_device = candidate;
+ goto found_device;
+ }
+
+ // CONFTEST: Two or more interfaces are required
+ if (interface_count == 1) {
+ CONF("usb device has only one ipp interface "
+ "in violation of standard");
+ goto error;
+ }
+
+ if (!auto_pick) {
+ ERR("No ipp-usb interfaces found");
+ goto error;
+ }
+ }
+ }
+ found_device:
+
+ if (printer_device == NULL) {
+ if (!auto_pick) {
+ ERR("No printer found by that vid, pid, serial or bus, device");
+ } else {
+ ERR("No IPP over USB printer found");
+ }
+ goto error;
+ }
- struct libusb_config_descriptor *config = NULL;
- status = libusb_get_config_descriptor(printer_device,
- (uint8_t)selected_config,
- &config);
- if (status != 0 || config == NULL) {
- ERR("Failed to acquire config descriptor");
- goto error;
- }
+ // Open the printer ==-----------------------------------------------==
+ status = libusb_open(printer_device, &usb->printer);
+ if (status != 0) {
+ ERR("failed to open device");
+ goto error;
+ }
- unsigned int interfs = selected_ipp_interface_count;
- for (uint8_t interf_num = 0;
- interf_num < config->bNumInterfaces;
- interf_num++) {
-
- const struct libusb_interface *interf = NULL;
- interf = &config->interface[interf_num];
- for (int alt_num = 0;
- alt_num < interf->num_altsetting;
- alt_num++) {
-
- const struct libusb_interface_descriptor *alt = NULL;
- alt = &interf->altsetting[alt_num];
-
- // Get the IEE-1284 device ID
- if (usb->device_id == NULL) {
- usb->device_id = calloc(2048, sizeof(char));
- if (usb->device_id == NULL) {
- ERR("Failed to allocate memory for the device ID");
- goto error;
- }
- if (get_device_id(usb->printer, selected_config,
- interf_num, alt_num,
- usb->device_id, 2048) != 0 ||
- strlen(usb->device_id) == 0) {
- NOTE("Could not retrieve device ID for config #%d, interface #%d, alt setting #%d, will try with other combo ...",
- selected_config, interf_num, alt_num);
- free(usb->device_id);
- usb->device_id = NULL;
- g_options.device_id = NULL;
- } else {
- NOTE("USB device ID: %s", usb->device_id);
- g_options.device_id = usb->device_id;
- }
- }
-
- // Skip non-IPP-USB interfaces
- if (!is_ippusb_interface(alt))
- continue;
-
- interfs--;
-
- struct usb_interface *uf = usb->interfaces + interfs;
- uf->interface_number = interf_num;
- uf->libusb_interface_index = alt->bInterfaceNumber;
- uf->interface_alt = alt_num;
-
- // Store interface's two endpoints
- for (int end_i = 0; end_i < alt->bNumEndpoints;
- end_i++) {
- const struct libusb_endpoint_descriptor *end;
- end = &alt->endpoint[end_i];
-
- usb->max_packet_size = end->wMaxPacketSize;
-
- // High bit set means endpoint
- // is an INPUT or IN endpoint.
- uint8_t address = end->bEndpointAddress;
- if (address & 0x80)
- uf->endpoint_in = address;
- else
- uf->endpoint_out = address;
- }
-
- status_lock = sem_init(&uf->lock, 0, 1);
- if (status_lock != 0) {
- ERR("Failed to create interface lock #%d",
- interf_num);
- goto error;
- }
-
- break;
- }
- }
- libusb_free_config_descriptor(config);
- libusb_free_device_list(device_list, 1);
+ // Open every IPP-USB interface ==-----------------------------------==
+ usb->num_interfaces = selected_ipp_interface_count;
+ usb->interfaces = calloc(usb->num_interfaces,
+ sizeof(*usb->interfaces));
+ if (usb->interfaces == NULL) {
+ ERR("Failed to alloc interfaces");
+ goto error;
+ }
+ struct libusb_config_descriptor *config = NULL;
+ status = libusb_get_config_descriptor(printer_device,
+ (uint8_t)selected_config,
+ &config);
+ if (status != 0 || config == NULL) {
+ ERR("Failed to acquire config descriptor");
+ goto error;
+ }
- // Pour interfaces into pool ==--------------------------------------==
- usb->num_avail = usb->num_interfaces;
- usb->interface_pool = calloc(usb->num_avail,
- sizeof(*usb->interface_pool));
- if (usb->interface_pool == NULL) {
- ERR("Failed to alloc interface pool");
- goto error;
+ unsigned int interfs = selected_ipp_interface_count;
+ for (uint8_t interf_num = 0;
+ interf_num < config->bNumInterfaces;
+ interf_num++) {
+
+ const struct libusb_interface *interf = NULL;
+ interf = &config->interface[interf_num];
+ for (int alt_num = 0;
+ alt_num < interf->num_altsetting;
+ alt_num++) {
+
+ const struct libusb_interface_descriptor *alt = NULL;
+ alt = &interf->altsetting[alt_num];
+
+ // Get the IEE-1284 device ID
+ if (usb->device_id == NULL) {
+ usb->device_id = calloc(2048, sizeof(char));
+ if (usb->device_id == NULL) {
+ ERR("Failed to allocate memory for the device ID");
+ goto error;
}
- for (uint32_t i = 0; i < usb->num_avail; i++) {
- usb->interface_pool[i] = i;
+ if (get_device_id(usb->printer, selected_config,
+ interf_num, alt_num,
+ usb->device_id, 2048) != 0 ||
+ strlen(usb->device_id) == 0) {
+ NOTE("Could not retrieve device ID for config #%d, interface #%d, alt setting #%d, will try with other combo ...",
+ selected_config, interf_num, alt_num);
+ free(usb->device_id);
+ usb->device_id = NULL;
+ g_options.device_id = NULL;
+ } else {
+ NOTE("USB device ID: %s", usb->device_id);
+ g_options.device_id = usb->device_id;
}
- NOTE("USB interfaces pool: %d interfaces", usb->num_avail);
-
+ }
+
+ // Skip non-IPP-USB interfaces
+ if (!is_ippusb_interface(alt))
+ continue;
+
+ interfs--;
+
+ struct usb_interface *uf = usb->interfaces + interfs;
+ uf->interface_number = interf_num;
+ uf->libusb_interface_index = alt->bInterfaceNumber;
+ uf->interface_alt = alt_num;
+
+ // Store interface's two endpoints
+ for (int end_i = 0; end_i < alt->bNumEndpoints;
+ end_i++) {
+ const struct libusb_endpoint_descriptor *end;
+ end = &alt->endpoint[end_i];
+
+ usb->max_packet_size = end->wMaxPacketSize;
+
+ // High bit set means endpoint
+ // is an INPUT or IN endpoint.
+ uint8_t address = end->bEndpointAddress;
+ if (address & 0x80)
+ uf->endpoint_in = address;
+ else
+ uf->endpoint_out = address;
+ }
+
+ status_lock = sem_init(&uf->lock, 0, 1);
+ if (status_lock != 0) {
+ ERR("Failed to create interface lock #%d",
+ interf_num);
+ goto error;
+ }
+
+ break;
+ }
+ }
+ libusb_free_config_descriptor(config);
+ libusb_free_device_list(device_list, 1);
+
+ // Pour interfaces into pool ==--------------------------------------==
+ usb->num_avail = usb->num_interfaces;
+ usb->interface_pool = calloc(usb->num_avail,
+ sizeof(*usb->interface_pool));
+ if (usb->interface_pool == NULL) {
+ ERR("Failed to alloc interface pool");
+ goto error;
+ }
+ for (uint32_t i = 0; i < usb->num_avail; i++) {
+ usb->interface_pool[i] = i;
+ }
+ NOTE("USB interfaces pool: %d interfaces", usb->num_avail);
- // Stale lock
- status_lock = sem_init(&usb->num_staled_lock, 0, 1);
- if (status_lock != 0) {
- ERR("Failed to create num_staled lock");
- goto error;
- }
+ // Stale lock
+ status_lock = sem_init(&usb->num_staled_lock, 0, 1);
+ if (status_lock != 0) {
+ ERR("Failed to create num_staled lock");
+ goto error;
+ }
- // Pool management lock
- status_lock = sem_init(&usb->pool_manage_lock, 0, 1);
- if (status_lock != 0) {
- ERR("Failed to create pool management lock");
- goto error;
- }
+ // Pool management lock
+ status_lock = sem_init(&usb->pool_manage_lock, 0, 1);
+ if (status_lock != 0) {
+ ERR("Failed to create pool management lock");
+ goto error;
+ }
- return usb;
-
-error:
- if (device_list != NULL)
- libusb_free_device_list(device_list, 1);
-error_usbinit:
- if (usb != NULL) {
- if (usb->context != NULL)
- libusb_exit(usb->context);
- if (usb->interfaces != NULL)
- free(usb->interfaces);
- if (usb->interface_pool != NULL)
- free(usb->interface_pool);
- free(usb);
- }
- return NULL;
+ return usb;
+
+ error:
+ if (device_list != NULL)
+ libusb_free_device_list(device_list, 1);
+ error_usbinit:
+ if (usb != NULL) {
+ if (usb->context != NULL)
+ libusb_exit(usb->context);
+ if (usb->interfaces != NULL)
+ free(usb->interfaces);
+ if (usb->interface_pool != NULL)
+ free(usb->interface_pool);
+ free(usb);
+ }
+ return NULL;
}
void usb_close(struct usb_sock_t *usb)
{
- // Release interfaces
- for (uint32_t i = 0; i < usb->num_interfaces; i++) {
- int number = usb->interfaces[i].interface_number;
- libusb_release_interface(usb->printer, number);
- sem_destroy(&usb->interfaces[i].lock);
- }
+ // Release interfaces
+ for (uint32_t i = 0; i < usb->num_interfaces; i++) {
+ int number = usb->interfaces[i].interface_number;
+ libusb_release_interface(usb->printer, number);
+ sem_destroy(&usb->interfaces[i].lock);
+ }
- libusb_close(usb->printer);
- if (usb != NULL) {
- if (usb->context != NULL)
- libusb_exit(usb->context);
- sem_destroy(&usb->num_staled_lock);
- if (usb->interfaces != NULL)
- free(usb->interfaces);
- if (usb->interface_pool != NULL)
- free(usb->interface_pool);
- free(usb);
- }
- return;
+ libusb_close(usb->printer);
+ if (usb != NULL) {
+ if (usb->context != NULL)
+ libusb_exit(usb->context);
+ sem_destroy(&usb->num_staled_lock);
+ if (usb->interfaces != NULL)
+ free(usb->interfaces);
+ if (usb->interface_pool != NULL)
+ free(usb->interface_pool);
+ free(usb);
+ }
+ return;
}
int usb_can_callback(struct usb_sock_t *usb)
{
- IGNORE(usb);
+ IGNORE(usb);
- if (!g_options.vendor_id ||
- !g_options.product_id)
- {
- NOTE("Exit-on-unplug requires vid & pid");
- return 0;
- }
+ if (!g_options.vendor_id ||
+ !g_options.product_id) {
+ NOTE("Exit-on-unplug requires vid & pid");
+ return 0;
+ }
- int works = !!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG);
- if (!works)
- WARN("Libusb cannot tell us when to disconnect");
- return works;
+ int works = !!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG);
+ if (!works)
+ WARN("Libusb cannot tell us when to disconnect");
+ return works;
}
static int LIBUSB_CALL usb_exit_on_unplug(libusb_context *context,
@@ -472,438 +466,435 @@ static int LIBUSB_CALL usb_exit_on_unplug(libusb_context *context,
libusb_hotplug_event event,
void *call_data)
{
- IGNORE(context);
- IGNORE(event);
- IGNORE(call_data);
+ IGNORE(context);
+ IGNORE(event);
+ IGNORE(call_data);
- NOTE("Received unplug callback");
+ NOTE("Received unplug callback");
- struct libusb_device_descriptor desc;
- libusb_get_device_descriptor(device, &desc);
+ struct libusb_device_descriptor desc;
+ libusb_get_device_descriptor(device, &desc);
- if (is_our_device(device, desc)) {
+ if (is_our_device(device, desc)) {
- // Unregister DNS-SD for printer on Avahi
- if (g_options.dnssd_data != NULL)
- dnssd_shutdown();
+ // Unregister DNS-SD for printer on Avahi
+ if (g_options.dnssd_data != NULL)
+ dnssd_shutdown();
- exit(0);
- }
+ exit(0);
+ }
- return 0;
+ return 0;
}
static void *usb_pump_events(void *user_data)
{
- IGNORE(user_data);
-
- for (;;) {
- if (g_options.terminate)
- return NULL;
- // NOTE: This is a blocking call so
- // no need for sleep()
- libusb_handle_events_completed(NULL, NULL);
- }
+ IGNORE(user_data);
+
+ for (;;) {
+ if (g_options.terminate)
+ return NULL;
+ // NOTE: This is a blocking call so
+ // no need for sleep()
+ libusb_handle_events_completed(NULL, NULL);
+ }
- return NULL;
+ return NULL;
}
void usb_register_callback(struct usb_sock_t *usb)
{
- IGNORE(usb);
-
- int status = libusb_hotplug_register_callback(
- NULL,
- LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
- // Note: libusb's enum has no default value
- // a bug has been filled with libusb.
- // Please switch the below line to 0
- // once the issue has been fixed in
- // deployed versions of libusb
- // https://github.com/libusb/libusb/issues/35
- // 0,
- LIBUSB_HOTPLUG_ENUMERATE,
- g_options.vendor_id,
- g_options.product_id,
- LIBUSB_HOTPLUG_MATCH_ANY,
- &usb_exit_on_unplug,
- NULL,
- NULL);
- if (status == LIBUSB_SUCCESS) {
- pthread_t thread_handle;
- pthread_create(&thread_handle, NULL, &usb_pump_events, NULL);
- NOTE("Registered unplug callback");
- } else
- ERR("Failed to register unplug callback");
+ IGNORE(usb);
+
+ int status =
+ libusb_hotplug_register_callback(NULL,
+ LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
+ // Note: libusb's enum has no default value
+ // a bug has been filled with libusb.
+ // Please switch the below line to 0
+ // once the issue has been fixed in
+ // deployed versions of libusb
+ // https://github.com/libusb/libusb/issues/35
+ // 0,
+ LIBUSB_HOTPLUG_ENUMERATE,
+ g_options.vendor_id,
+ g_options.product_id,
+ LIBUSB_HOTPLUG_MATCH_ANY,
+ &usb_exit_on_unplug,
+ NULL,
+ NULL);
+ if (status == LIBUSB_SUCCESS) {
+ pthread_t thread_handle;
+ pthread_create(&thread_handle, NULL, &usb_pump_events, NULL);
+ NOTE("Registered unplug callback");
+ } else
+ ERR("Failed to register unplug callback");
}
static void usb_conn_mark_staled(struct usb_conn_t *conn)
{
- if (conn->is_staled)
- return;
+ if (conn->is_staled)
+ return;
- struct usb_sock_t *usb = conn->parent;
+ struct usb_sock_t *usb = conn->parent;
- sem_wait(&usb->num_staled_lock);
- {
- usb->num_staled++;
- }
- sem_post(&usb->num_staled_lock);
+ sem_wait(&usb->num_staled_lock);
+ {
+ usb->num_staled++;
+ }
+ sem_post(&usb->num_staled_lock);
- conn->is_staled = 1;
+ conn->is_staled = 1;
}
static void usb_conn_mark_moving(struct usb_conn_t *conn)
{
- if (!conn->is_staled)
- return;
+ if (!conn->is_staled)
+ return;
- struct usb_sock_t *usb = conn->parent;
+ struct usb_sock_t *usb = conn->parent;
- sem_wait(&usb->num_staled_lock);
- {
- usb->num_staled--;
- }
- sem_post(&usb->num_staled_lock);
+ sem_wait(&usb->num_staled_lock);
+ {
+ usb->num_staled--;
+ }
+ sem_post(&usb->num_staled_lock);
- conn->is_staled = 0;
+ conn->is_staled = 0;
}
static int usb_all_conns_staled(struct usb_sock_t *usb)
{
- int staled;
-
- sem_wait(&usb->num_staled_lock);
- {
- sem_wait(&usb->pool_manage_lock);
- {
- staled = usb->num_staled == usb->num_taken;
- }
- sem_post(&usb->pool_manage_lock);
- }
- sem_post(&usb->num_staled_lock);
+ int staled;
+
+ sem_wait(&usb->num_staled_lock);
+ {
+ sem_wait(&usb->pool_manage_lock);
+ {
+ staled = usb->num_staled == usb->num_taken;
+ }
+ sem_post(&usb->pool_manage_lock);
+ }
+ sem_post(&usb->num_staled_lock);
- return staled;
+ return staled;
}
struct usb_conn_t *usb_conn_acquire(struct usb_sock_t *usb)
{
+ int i;
+
+ if (usb->num_avail <= 0) {
+ NOTE("All USB interfaces busy, waiting ...");
+ for (i = 0; i < 30 && usb->num_avail <= 0; i ++)
+ usleep(100000);
+ if (usb->num_avail <= 0) {
+ ERR("Timed out waiting for a free USB interface");
+ return NULL;
+ }
+ usleep(100000);
+ }
- int i;
- if (usb->num_avail <= 0) {
- NOTE("All USB interfaces busy, waiting ...");
- for (i = 0; i < 30 && usb->num_avail <= 0; i ++)
- usleep(100000);
- if (usb->num_avail <= 0) {
- ERR("Timed out waiting for a free USB interface");
- return NULL;
- }
- usleep(100000);
- }
-
- struct usb_conn_t *conn = calloc(1, sizeof(*conn));
- if (conn == NULL) {
- ERR("Failed to alloc space for usb connection");
- return NULL;
- }
+ struct usb_conn_t *conn = calloc(1, sizeof(*conn));
+ if (conn == NULL) {
+ ERR("Failed to alloc space for usb connection");
+ return NULL;
+ }
- sem_wait(&usb->pool_manage_lock);
- {
- conn->parent = usb;
-
- uint32_t slot = usb->num_taken;
-
- conn->interface_index = usb->interface_pool[slot];
- conn->interface = usb->interfaces + conn->interface_index;
- struct usb_interface *uf = conn->interface;
-
- // Sanity check: Is the interface still free
- if (sem_trywait(&uf->lock)) {
- ERR("Interface #%d (%d) already in use!",
- conn->interface_index,
- uf->libusb_interface_index);
- goto acquire_error;
- }
-
- // Make kernel release interface
- if (libusb_kernel_driver_active(usb->printer,
- uf->libusb_interface_index) == 1) {
- // Only linux supports this
- // other platforms will fail
- // thus we ignore the error code
- // it either works or it does not
- libusb_detach_kernel_driver(usb->printer,
- uf->libusb_interface_index);
- }
-
- // Claim the whole interface
- int status = 0;
- do {
- // Spinlock-like
- // Libusb does not offer a blocking call
- // so we're left with a spinlock
- status = libusb_claim_interface(
- usb->printer, uf->libusb_interface_index);
- if (status) NOTE("Failed to claim interface %d, retrying", conn->interface_index);
- switch (status) {
- case LIBUSB_ERROR_NOT_FOUND:
- ERR("USB Interface did not exist");
- goto acquire_error;
- case LIBUSB_ERROR_NO_DEVICE:
- ERR("Printer was removed");
- goto acquire_error;
- default:
- break;
- }
- } while (status != 0);
-
- // Select the IPP-USB alt setting of the interface
- libusb_set_interface_alt_setting(usb->printer,
- uf->libusb_interface_index,
- uf->interface_alt);
-
- // Take successfully acquired interface from the pool
- usb->num_taken++;
- usb->num_avail--;
- }
- sem_post(&usb->pool_manage_lock);
- return conn;
+ sem_wait(&usb->pool_manage_lock);
+ {
+ conn->parent = usb;
+
+ uint32_t slot = usb->num_taken;
+
+ conn->interface_index = usb->interface_pool[slot];
+ conn->interface = usb->interfaces + conn->interface_index;
+ struct usb_interface *uf = conn->interface;
+
+ // Sanity check: Is the interface still free
+ if (sem_trywait(&uf->lock)) {
+ ERR("Interface #%d (%d) already in use!",
+ conn->interface_index,
+ uf->libusb_interface_index);
+ goto acquire_error;
+ }
+
+ // Make kernel release interface
+ if (libusb_kernel_driver_active(usb->printer,
+ uf->libusb_interface_index) == 1) {
+ // Only linux supports this
+ // other platforms will fail
+ // thus we ignore the error code
+ // it either works or it does not
+ libusb_detach_kernel_driver(usb->printer,
+ uf->libusb_interface_index);
+ }
+
+ // Claim the whole interface
+ int status = 0;
+ do {
+ // Spinlock-like
+ // Libusb does not offer a blocking call
+ // so we're left with a spinlock
+ status = libusb_claim_interface(usb->printer, uf->libusb_interface_index);
+ if (status) NOTE("Failed to claim interface %d, retrying", conn->interface_index);
+ switch (status) {
+ case LIBUSB_ERROR_NOT_FOUND:
+ ERR("USB Interface did not exist");
+ goto acquire_error;
+ case LIBUSB_ERROR_NO_DEVICE:
+ ERR("Printer was removed");
+ goto acquire_error;
+ default:
+ break;
+ }
+ } while (status != 0);
+
+ // Select the IPP-USB alt setting of the interface
+ libusb_set_interface_alt_setting(usb->printer,
+ uf->libusb_interface_index,
+ uf->interface_alt);
+
+ // Take successfully acquired interface from the pool
+ usb->num_taken++;
+ usb->num_avail--;
+ }
+ sem_post(&usb->pool_manage_lock);
+ return conn;
acquire_error:
- sem_post(&usb->pool_manage_lock);
- free(conn);
- return NULL;
-
+ sem_post(&usb->pool_manage_lock);
+ free(conn);
+ return NULL;
}
void usb_conn_release(struct usb_conn_t *conn)
{
- struct usb_sock_t *usb = conn->parent;
- sem_wait(&usb->pool_manage_lock);
- {
- int status = 0;
- do {
- // Spinlock-like
- // Libusb does not offer a blocking call
- // so we're left with a spinlock
- status = libusb_release_interface(usb->printer,
- conn->interface->libusb_interface_index);
- if (status) NOTE("Failed to release interface %d, retrying", conn->interface_index);
- } while (status != 0);
-
- // Return usb interface to pool
- usb->num_taken--;
- usb->num_avail++;
- uint32_t slot = usb->num_taken;
- usb->interface_pool[slot] = conn->interface_index;
-
- // Release our interface lock
- sem_post(&conn->interface->lock);
-
- free(conn);
- }
- sem_post(&usb->pool_manage_lock);
+ struct usb_sock_t *usb = conn->parent;
+ sem_wait(&usb->pool_manage_lock);
+ {
+ int status = 0;
+ do {
+ // Spinlock-like
+ // Libusb does not offer a blocking call
+ // so we're left with a spinlock
+ status = libusb_release_interface(usb->printer,
+ conn->interface->libusb_interface_index);
+ if (status) NOTE("Failed to release interface %d, retrying", conn->interface_index);
+ } while (status != 0);
+
+ // Return usb interface to pool
+ usb->num_taken--;
+ usb->num_avail++;
+ uint32_t slot = usb->num_taken;
+ usb->interface_pool[slot] = conn->interface_index;
+
+ // Release our interface lock
+ sem_post(&conn->interface->lock);
+
+ free(conn);
+ }
+ sem_post(&usb->pool_manage_lock);
}
int usb_conn_packet_send(struct usb_conn_t *conn, struct http_packet_t *pkt)
{
- int size_sent = 0;
- const int timeout = 1000; // 1 sec
- int num_timeouts = 0;
- size_t sent = 0;
- size_t pending = pkt->filled_size;
- while (pending > 0) {
- int to_send = (int)pending;
-
- NOTE("P %p: USB: want to send %d bytes", pkt, to_send);
- int status = libusb_bulk_transfer(conn->parent->printer,
- conn->interface->endpoint_out,
- pkt->buffer + sent, to_send,
- &size_sent, timeout);
- if (status == LIBUSB_ERROR_NO_DEVICE) {
- ERR("P %p: Printer has been disconnected",
- pkt);
- return -1;
- }
- if (status == LIBUSB_ERROR_TIMEOUT) {
- NOTE("P %p: USB: send timed out, retrying", pkt);
-
- if (num_timeouts++ > PRINTER_CRASH_TIMEOUT_RECEIVE) {
- ERR("P %p: Usb send fully timed out",
- pkt);
- return -1;
- }
-
- // Sleep for tenth of a second
- struct timespec sleep_dur;
- sleep_dur.tv_sec = 0;
- sleep_dur.tv_nsec = 100000000;
- nanosleep(&sleep_dur, NULL);
- if (size_sent == 0)
- continue;
- } else if (status < 0) {
- ERR("P %p: USB: send failed with status %s",
- pkt, libusb_error_name(status));
- return -1;
- }
- if (size_sent < 0) {
- ERR("P %p: Unexpected negative size_sent",
- pkt);
- return -1;
- }
-
- pending -= (size_t) size_sent;
- sent += (size_t) size_sent;
- NOTE("P %p: USB: sent %d bytes", pkt, size_sent);
- }
- NOTE("P %p: USB: sent %d bytes in total", pkt, sent);
- return 0;
+ int size_sent = 0;
+ const int timeout = 1000; // 1 sec
+ int num_timeouts = 0;
+ size_t sent = 0;
+ size_t pending = pkt->filled_size;
+ while (pending > 0) {
+ int to_send = (int)pending;
+
+ NOTE("P %p: USB: want to send %d bytes", pkt, to_send);
+ int status = libusb_bulk_transfer(conn->parent->printer,
+ conn->interface->endpoint_out,
+ pkt->buffer + sent, to_send,
+ &size_sent, timeout);
+ if (status == LIBUSB_ERROR_NO_DEVICE) {
+ ERR("P %p: Printer has been disconnected",
+ pkt);
+ return -1;
+ }
+ if (status == LIBUSB_ERROR_TIMEOUT) {
+ NOTE("P %p: USB: send timed out, retrying", pkt);
+
+ if (num_timeouts++ > PRINTER_CRASH_TIMEOUT_RECEIVE) {
+ ERR("P %p: Usb send fully timed out",
+ pkt);
+ return -1;
+ }
+
+ // Sleep for tenth of a second
+ struct timespec sleep_dur;
+ sleep_dur.tv_sec = 0;
+ sleep_dur.tv_nsec = 100000000;
+ nanosleep(&sleep_dur, NULL);
+ if (size_sent == 0)
+ continue;
+ } else if (status < 0) {
+ ERR("P %p: USB: send failed with status %s",
+ pkt, libusb_error_name(status));
+ return -1;
+ }
+ if (size_sent < 0) {
+ ERR("P %p: Unexpected negative size_sent",
+ pkt);
+ return -1;
+ }
+
+ pending -= (size_t) size_sent;
+ sent += (size_t) size_sent;
+ NOTE("P %p: USB: sent %d bytes", pkt, size_sent);
+ }
+ NOTE("P %p: USB: sent %d bytes in total", pkt, sent);
+ return 0;
}
struct http_packet_t *usb_conn_packet_get(struct usb_conn_t *conn, struct http_message_t *msg)
{
- if (msg->is_completed)
- return NULL;
+ if (msg->is_completed)
+ return NULL;
- struct http_packet_t *pkt = packet_new(msg);
- if (pkt == NULL) {
- ERR("failed to create packet for incoming usb message");
- goto cleanup;
- }
+ struct http_packet_t *pkt = packet_new(msg);
+ if (pkt == NULL) {
+ ERR("failed to create packet for incoming usb message");
+ goto cleanup;
+ }
- // File packet
- const int timeout = 1000; // 1 sec
- size_t read_size_ulong = packet_pending_bytes(pkt);
- if (read_size_ulong == 0)
- return pkt;
-
- uint64_t times_staled = 0;
- while (read_size_ulong > 0 && !msg->is_completed) {
- if (read_size_ulong >= INT_MAX)
- goto cleanup;
- int read_size = (int)read_size_ulong;
-
- // Pad read_size to multiple of usb's max packet size
- read_size += (512 - (read_size % 512)) % 512;
-
- // Expand buffer if needed
- if (pkt->buffer_capacity < pkt->filled_size + read_size_ulong)
- if (packet_expand(pkt) < 0) {
- ERR("Failed to ensure room for usb pkt");
- goto cleanup;
- }
-
- int gotten_size = 0;
- int status = libusb_bulk_transfer(
- conn->parent->printer,
+ // File packet
+ const int timeout = 1000; // 1 sec
+ size_t read_size_ulong = packet_pending_bytes(pkt);
+ if (read_size_ulong == 0)
+ return pkt;
+
+ uint64_t times_staled = 0;
+ while (read_size_ulong > 0 && !msg->is_completed) {
+ if (read_size_ulong >= INT_MAX)
+ goto cleanup;
+ int read_size = (int)read_size_ulong;
+
+ // Pad read_size to multiple of usb's max packet size
+ read_size += (512 - (read_size % 512)) % 512;
+
+ // Expand buffer if needed
+ if (pkt->buffer_capacity < pkt->filled_size + read_size_ulong)
+ if (packet_expand(pkt) < 0) {
+ ERR("Failed to ensure room for usb pkt");
+ goto cleanup;
+ }
+
+ int gotten_size = 0;
+ int status = libusb_bulk_transfer(conn->parent->printer,
conn->interface->endpoint_in,
pkt->buffer + pkt->filled_size,
read_size,
&gotten_size, timeout);
- if (status == LIBUSB_ERROR_NO_DEVICE) {
- ERR("Printer has been disconnected");
- goto cleanup;
- }
-
- if (status != 0 && status != LIBUSB_ERROR_TIMEOUT) {
- ERR("bulk xfer failed with error code %d", status);
- ERR("tried reading %d bytes", read_size);
- goto cleanup;
- } else if (status == LIBUSB_ERROR_TIMEOUT) {
- ERR("bulk xfer timed out, retrying ...");
- ERR("tried reading %d bytes, actually read %d bytes",
- read_size, gotten_size);
- }
-
- if (gotten_size < 0) {
- ERR("Negative read size unexpected");
- goto cleanup;
- }
-
- if (gotten_size > 0) {
- times_staled = 0;
- usb_conn_mark_moving(conn);
- } else {
-
- // Performance Test ---------------
- // How long we sleep here has a
- // dramatic affect on how long it
- // takes to load a page.
- // Earlier versions waited a tenth
- // of a second which resulted in
- // minute long page loads.
- // On my HP printer the most obvious
- // bottleneck is the "Unified.js" file
- // which weighs 517.87KB. My profiling
- // looked at how shortening this sleep
- // could improve this file's load times.
- // The cycle count is from perf and
- // covers an entire page load.
- //
- // Below are my results:
- // 1 in 100 == 2447ms, 261M cycles
- // 1 in 1,000 == 483ms, 500M cycles
- // 5 in 10,000 == 433ms, 800M cycles
- // 1 in 10,000 == 320ms, 3000M cycles
- #define TIMEOUT_RATIO (10000 / 5)
- static uint64_t stale_timeout =
- CONN_STALE_THRESHHOLD * TIMEOUT_RATIO;
- static uint64_t crash_timeout =
- PRINTER_CRASH_TIMEOUT_ANSWER * TIMEOUT_RATIO;
- static uint64_t skip_timeout =
- 1000000000 / TIMEOUT_RATIO;
-
- struct timespec sleep_dur;
- sleep_dur.tv_sec = 0;
- sleep_dur.tv_nsec = skip_timeout;
- nanosleep(&sleep_dur, NULL);
-
- if (status == LIBUSB_ERROR_TIMEOUT)
- times_staled += TIMEOUT_RATIO * timeout / 1000;
- else
- times_staled++;
- if (times_staled % TIMEOUT_RATIO == 0 ||
- status == LIBUSB_ERROR_TIMEOUT) {
- NOTE("No bytes received for %d sec.",
- times_staled / TIMEOUT_RATIO);
- if (pkt->filled_size > 0)
- NOTE("Packet so far \n===\n%s===\n",
- hexdump(pkt->buffer,
- pkt->filled_size));
- }
+ if (status == LIBUSB_ERROR_NO_DEVICE) {
+ ERR("Printer has been disconnected");
+ goto cleanup;
+ }
+
+ if (status != 0 && status != LIBUSB_ERROR_TIMEOUT) {
+ ERR("bulk xfer failed with error code %d", status);
+ ERR("tried reading %d bytes", read_size);
+ goto cleanup;
+ } else if (status == LIBUSB_ERROR_TIMEOUT) {
+ ERR("bulk xfer timed out, retrying ...");
+ ERR("tried reading %d bytes, actually read %d bytes",
+ read_size, gotten_size);
+ }
+
+ if (gotten_size < 0) {
+ ERR("Negative read size unexpected");
+ goto cleanup;
+ }
+
+ if (gotten_size > 0) {
+ times_staled = 0;
+ usb_conn_mark_moving(conn);
+ } else {
+
+ // Performance Test ---------------
+ // How long we sleep here has a
+ // dramatic affect on how long it
+ // takes to load a page.
+ // Earlier versions waited a tenth
+ // of a second which resulted in
+ // minute long page loads.
+ // On my HP printer the most obvious
+ // bottleneck is the "Unified.js" file
+ // which weighs 517.87KB. My profiling
+ // looked at how shortening this sleep
+ // could improve this file's load times.
+ // The cycle count is from perf and
+ // covers an entire page load.
+ //
+ // Below are my results:
+ // 1 in 100 == 2447ms, 261M cycles
+ // 1 in 1,000 == 483ms, 500M cycles
+ // 5 in 10,000 == 433ms, 800M cycles
+ // 1 in 10,000 == 320ms, 3000M cycles
+ #define TIMEOUT_RATIO (10000 / 5)
+ static uint64_t stale_timeout =
+ CONN_STALE_THRESHHOLD * TIMEOUT_RATIO;
+ static uint64_t crash_timeout =
+ PRINTER_CRASH_TIMEOUT_ANSWER * TIMEOUT_RATIO;
+ static uint64_t skip_timeout =
+ 1000000000 / TIMEOUT_RATIO;
+
+ struct timespec sleep_dur;
+ sleep_dur.tv_sec = 0;
+ sleep_dur.tv_nsec = skip_timeout;
+ nanosleep(&sleep_dur, NULL);
+
+ if (status == LIBUSB_ERROR_TIMEOUT)
+ times_staled += TIMEOUT_RATIO * timeout / 1000;
+ else
+ times_staled++;
+ if (times_staled % TIMEOUT_RATIO == 0 ||
+ status == LIBUSB_ERROR_TIMEOUT) {
+ NOTE("No bytes received for %d sec.",
+ times_staled / TIMEOUT_RATIO);
+ if (pkt->filled_size > 0)
+ NOTE("Packet so far \n===\n%s===\n",
+ hexdump(pkt->buffer,
+ pkt->filled_size));
+ }
- if (times_staled > stale_timeout) {
- usb_conn_mark_staled(conn);
-
- if (pkt->filled_size > 0 ||
- usb_all_conns_staled(conn->parent) ||
- times_staled > crash_timeout) {
- ERR("USB timed out, giving up waiting for more data");
- break;
- }
- }
- }
-
- if (gotten_size) {
- NOTE("USB: Getting %d bytes of %d",
- read_size, pkt->expected_size);
- NOTE("USB: Got %d bytes", gotten_size);
- }
- packet_mark_received(pkt, (size_t)gotten_size);
- read_size_ulong = packet_pending_bytes(pkt);
+ if (times_staled > stale_timeout) {
+ usb_conn_mark_staled(conn);
+
+ if (pkt->filled_size > 0 ||
+ usb_all_conns_staled(conn->parent) ||
+ times_staled > crash_timeout) {
+ ERR("USB timed out, giving up waiting for more data");
+ break;
}
- NOTE("USB: Received %d bytes of %d with type %d",
- pkt->filled_size, pkt->expected_size, msg->type);
+ }
+ }
+
+ if (gotten_size) {
+ NOTE("USB: Getting %d bytes of %d",
+ read_size, pkt->expected_size);
+ NOTE("USB: Got %d bytes", gotten_size);
+ }
+ packet_mark_received(pkt, (size_t)gotten_size);
+ read_size_ulong = packet_pending_bytes(pkt);
+ }
+ NOTE("USB: Received %d bytes of %d with type %d",
+ pkt->filled_size, pkt->expected_size, msg->type);
- if (pkt->filled_size == 0)
- goto cleanup;
+ if (pkt->filled_size == 0)
+ goto cleanup;
- return pkt;
+ return pkt;
-cleanup:
- if (pkt != NULL)
- packet_free(pkt);
- return NULL;
+ cleanup:
+ if (pkt != NULL)
+ packet_free(pkt);
+ return NULL;
}
diff --git a/src/usb.h b/src/usb.h
index a46c974..c86f483 100644
--- a/src/usb.h
+++ b/src/usb.h
@@ -23,39 +23,38 @@
#define CONN_STALE_THRESHHOLD 5
struct usb_interface {
- uint8_t interface_number;
- uint8_t libusb_interface_index;
- int interface_alt;
- uint8_t endpoint_in;
- uint8_t endpoint_out;
- sem_t lock;
+ uint8_t interface_number;
+ uint8_t libusb_interface_index;
+ int interface_alt;
+ uint8_t endpoint_in;
+ uint8_t endpoint_out;
+ sem_t lock;
};
struct usb_sock_t {
- libusb_context *context;
- libusb_device_handle *printer;
- char *device_id;
- int max_packet_size;
+ libusb_context *context;
+ libusb_device_handle *printer;
+ char *device_id;
+ int max_packet_size;
- uint32_t num_interfaces;
- struct usb_interface *interfaces;
+ uint32_t num_interfaces;
+ struct usb_interface *interfaces;
- uint32_t num_staled;
- sem_t num_staled_lock;
+ uint32_t num_staled;
+ sem_t num_staled_lock;
- sem_t pool_manage_lock;
- uint32_t num_avail;
- uint32_t num_taken;
-
- uint32_t *interface_pool;
+ sem_t pool_manage_lock;
+ uint32_t num_avail;
+ uint32_t num_taken;
+ uint32_t *interface_pool;
};
struct usb_conn_t {
- struct usb_sock_t *parent;
- struct usb_interface *interface;
- uint32_t interface_index;
- int is_staled;
+ struct usb_sock_t *parent;
+ struct usb_interface *interface;
+ uint32_t interface_index;
+ int is_staled;
};
struct usb_sock_t *usb_open(void);
@@ -69,4 +68,3 @@ void usb_conn_release(struct usb_conn_t *);
int usb_conn_packet_send(struct usb_conn_t *, struct http_packet_t *);
struct http_packet_t *usb_conn_packet_get(struct usb_conn_t *, struct http_message_t *);
-