Add functions to query information about TCP/IP devices
[libjaylink.git] / libjaylink / transport.c
blob5000a205a46d56adc3a02bc2cc8848eaf98b1566
1 /*
2 * This file is part of the libjaylink project.
4 * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <string.h>
25 #include "libjaylink.h"
26 #include "libjaylink-internal.h"
29 * libusb.h includes windows.h and therefore must be included after anything
30 * that includes winsock2.h.
32 #include <libusb.h>
34 /**
35 * @file
37 * Transport abstraction layer.
40 /** Timeout of an USB transfer in milliseconds. */
41 #define USB_TIMEOUT 1000
43 /**
44 * Number of consecutive timeouts before an USB transfer will be treated as
45 * timed out.
47 #define NUM_TIMEOUTS 2
49 /** Chunk size in bytes in which data is transferred. */
50 #define CHUNK_SIZE 2048
52 static int initialize_handle(struct jaylink_device_handle *devh)
54 int ret;
55 struct jaylink_context *ctx;
56 struct libusb_config_descriptor *config;
57 const struct libusb_interface *interface;
58 const struct libusb_interface_descriptor *desc;
59 const struct libusb_endpoint_descriptor *ep_desc;
60 bool found_interface;
61 bool found_endpoint_in;
62 bool found_endpoint_out;
63 uint8_t i;
65 ctx = devh->dev->ctx;
66 devh->interface_number = 0;
69 * Retrieve active configuration descriptor to determine the endpoints
70 * for the interface number of the device.
72 ret = libusb_get_active_config_descriptor(devh->dev->usb_dev, &config);
74 if (ret == LIBUSB_ERROR_IO) {
75 log_err(ctx, "Failed to get configuration descriptor: "
76 "input/output error.");
77 return JAYLINK_ERR_IO;
78 } else if (ret != LIBUSB_SUCCESS) {
79 log_err(ctx, "Failed to get configuration descriptor: %s.",
80 libusb_error_name(ret));
81 return JAYLINK_ERR;
84 found_interface = false;
86 for (i = 0; i < config->bNumInterfaces; i++) {
87 interface = &config->interface[i];
88 desc = &interface->altsetting[0];
90 if (desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC)
91 continue;
93 if (desc->bInterfaceSubClass != LIBUSB_CLASS_VENDOR_SPEC)
94 continue;
96 if (desc->bNumEndpoints < 2)
97 continue;
99 found_interface = true;
100 devh->interface_number = i;
101 break;
104 if (!found_interface) {
105 log_err(ctx, "No suitable interface found.");
106 libusb_free_config_descriptor(config);
107 return JAYLINK_ERR;
110 found_endpoint_in = false;
111 found_endpoint_out = false;
113 for (i = 0; i < desc->bNumEndpoints; i++) {
114 ep_desc = &desc->endpoint[i];
116 if (ep_desc->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
117 devh->endpoint_in = ep_desc->bEndpointAddress;
118 found_endpoint_in = true;
119 } else {
120 devh->endpoint_out = ep_desc->bEndpointAddress;
121 found_endpoint_out = true;
125 libusb_free_config_descriptor(config);
127 if (!found_endpoint_in) {
128 log_err(ctx, "Interface IN endpoint not found.");
129 return JAYLINK_ERR;
132 if (!found_endpoint_out) {
133 log_err(ctx, "Interface OUT endpoint not found.");
134 return JAYLINK_ERR;
137 log_dbg(ctx, "Using endpoint %02x (IN) and %02x (OUT).",
138 devh->endpoint_in, devh->endpoint_out);
140 /* Buffer size must be a multiple of CHUNK_SIZE bytes. */
141 devh->buffer_size = CHUNK_SIZE;
142 devh->buffer = malloc(devh->buffer_size);
144 if (!devh->buffer) {
145 log_err(ctx, "Transport buffer malloc failed.");
146 return JAYLINK_ERR_MALLOC;
149 devh->read_length = 0;
150 devh->bytes_available = 0;
151 devh->read_pos = 0;
153 devh->write_length = 0;
154 devh->write_pos = 0;
156 return JAYLINK_OK;
159 static void cleanup_handle(struct jaylink_device_handle *devh)
161 free(devh->buffer);
165 * Open a device.
167 * This function must be called before any other function of the transport
168 * abstraction layer for the given device handle is called.
170 * @param[in,out] devh Device handle.
172 * @retval JAYLINK_OK Success.
173 * @retval JAYLINK_ERR_IO Input/output error.
174 * @retval JAYLINK_ERR Other error conditions.
176 JAYLINK_PRIV int transport_open(struct jaylink_device_handle *devh)
178 int ret;
179 struct jaylink_device *dev;
180 struct jaylink_context *ctx;
181 struct libusb_device_handle *usb_devh;
183 dev = devh->dev;
184 ctx = dev->ctx;
186 log_dbg(ctx, "Trying to open device (bus:address = %03u:%03u).",
187 libusb_get_bus_number(dev->usb_dev),
188 libusb_get_device_address(dev->usb_dev));
190 ret = initialize_handle(devh);
192 if (ret != JAYLINK_OK) {
193 log_err(ctx, "Failed to initialize device handle.");
194 return ret;
197 ret = libusb_open(dev->usb_dev, &usb_devh);
199 if (ret == LIBUSB_ERROR_IO) {
200 log_err(ctx, "Failed to open device: input/output error.");
201 cleanup_handle(devh);
202 return JAYLINK_ERR_IO;
203 } else if (ret != LIBUSB_SUCCESS) {
204 log_err(ctx, "Failed to open device: %s.",
205 libusb_error_name(ret));
206 cleanup_handle(devh);
207 return JAYLINK_ERR;
210 ret = libusb_claim_interface(usb_devh, devh->interface_number);
212 if (ret == LIBUSB_ERROR_IO) {
213 log_err(ctx, "Failed to claim interface: input/output error.");
214 return JAYLINK_ERR_IO;
215 } else if (ret != LIBUSB_SUCCESS) {
216 log_err(ctx, "Failed to claim interface: %s.",
217 libusb_error_name(ret));
218 cleanup_handle(devh);
219 libusb_close(usb_devh);
220 return JAYLINK_ERR;
223 log_dbg(ctx, "Device opened successfully.");
225 devh->usb_devh = usb_devh;
227 return JAYLINK_OK;
231 * Close a device.
233 * After this function has been called no other function of the transport
234 * abstraction layer for the given device handle must be called.
236 * @param[in,out] devh Device handle.
238 * @retval JAYLINK_OK Success.
239 * @retval JAYLINK_ERR Other error conditions.
241 JAYLINK_PRIV int transport_close(struct jaylink_device_handle *devh)
243 int ret;
244 struct jaylink_device *dev;
245 struct jaylink_context *ctx;
247 dev = devh->dev;
248 ctx = dev->ctx;
250 log_dbg(ctx, "Closing device (bus:address = %03u:%03u).",
251 libusb_get_bus_number(dev->usb_dev),
252 libusb_get_device_address(dev->usb_dev));
254 ret = libusb_release_interface(devh->usb_devh, devh->interface_number);
256 libusb_close(devh->usb_devh);
257 cleanup_handle(devh);
259 if (ret != LIBUSB_SUCCESS) {
260 log_err(ctx, "Failed to release interface: %s.",
261 libusb_error_name(ret));
262 return JAYLINK_ERR;
265 log_dbg(ctx, "Device closed successfully.");
267 return JAYLINK_OK;
271 * Start a write operation for a device.
273 * The data of a write operation must be written with at least one call of
274 * transport_write(). It is required that all data of a write operation is
275 * written before an other write and/or read operation is started.
277 * @param[in,out] devh Device handle.
278 * @param[in] length Number of bytes of the write operation.
279 * @param[in] has_command Determines whether the data of the write operation
280 * contains the protocol command.
282 * @retval JAYLINK_OK Success.
283 * @retval JAYLINK_ERR_ARG Invalid arguments.
285 JAYLINK_PRIV int transport_start_write(struct jaylink_device_handle *devh,
286 size_t length, bool has_command)
288 struct jaylink_context *ctx;
290 (void)has_command;
292 if (!length)
293 return JAYLINK_ERR_ARG;
295 ctx = devh->dev->ctx;
297 log_dbg(ctx, "Starting write operation (length = %zu bytes).", length);
299 if (devh->write_pos > 0)
300 log_warn(ctx, "Last write operation left %zu bytes in the "
301 "buffer.", devh->write_pos);
303 if (devh->write_length > 0)
304 log_warn(ctx, "Last write operation was not performed.");
306 devh->write_length = length;
307 devh->write_pos = 0;
309 return JAYLINK_OK;
313 * Start a read operation for a device.
315 * The data of a read operation must be read with at least one call of
316 * transport_read(). It is required that all data of a read operation is read
317 * before an other write and/or read operation is started.
319 * @param[in,out] devh Device handle.
320 * @param[in] length Number of bytes of the read operation.
322 * @retval JAYLINK_OK Success.
323 * @retval JAYLINK_ERR_ARG Invalid arguments.
325 JAYLINK_PRIV int transport_start_read(struct jaylink_device_handle *devh,
326 size_t length)
328 struct jaylink_context *ctx;
330 if (!length)
331 return JAYLINK_ERR_ARG;
333 ctx = devh->dev->ctx;
335 log_dbg(ctx, "Starting read operation (length = %zu bytes).", length);
337 if (devh->bytes_available > 0)
338 log_dbg(ctx, "Last read operation left %zu bytes in the "
339 "buffer.", devh->bytes_available);
341 if (devh->read_length > 0)
342 log_warn(ctx, "Last read operation left %zu bytes.",
343 devh->read_length);
345 devh->read_length = length;
347 return JAYLINK_OK;
351 * Start a write and read operation for a device.
353 * This function starts a write and read operation as the consecutive call of
354 * transport_start_write() and transport_start_read() but has a different
355 * meaning from the protocol perspective and can therefore not be replaced by
356 * these functions and vice versa.
358 * @note The write operation must be completed first before the read operation
359 * must be processed.
361 * @param[in,out] devh Device handle.
362 * @param[in] write_length Number of bytes of the write operation.
363 * @param[in] read_length Number of bytes of the read operation.
364 * @param[in] has_command Determines whether the data of the write operation
365 * contains the protocol command.
367 * @retval JAYLINK_OK Success.
368 * @retval JAYLINK_ERR_ARG Invalid arguments.
370 JAYLINK_PRIV int transport_start_write_read(struct jaylink_device_handle *devh,
371 size_t write_length, size_t read_length, bool has_command)
373 struct jaylink_context *ctx;
375 (void)has_command;
377 if (!read_length || !write_length)
378 return JAYLINK_ERR_ARG;
380 ctx = devh->dev->ctx;
382 log_dbg(ctx, "Starting write / read operation (length = "
383 "%zu / %zu bytes).", write_length, read_length);
385 if (devh->write_pos > 0)
386 log_warn(ctx, "Last write operation left %zu bytes in the "
387 "buffer.", devh->write_pos);
389 if (devh->write_length > 0)
390 log_warn(ctx, "Last write operation was not performed.");
392 if (devh->bytes_available > 0)
393 log_warn(ctx, "Last read operation left %zu bytes in the "
394 "buffer.", devh->bytes_available);
396 if (devh->read_length > 0)
397 log_warn(ctx, "Last read operation left %zu bytes.",
398 devh->read_length);
400 devh->write_length = write_length;
401 devh->write_pos = 0;
403 devh->read_length = read_length;
404 devh->bytes_available = 0;
405 devh->read_pos = 0;
407 return JAYLINK_OK;
410 static bool adjust_buffer(struct jaylink_device_handle *devh, size_t size)
412 struct jaylink_context *ctx;
413 size_t num_chunks;
414 uint8_t *buffer;
416 ctx = devh->dev->ctx;
418 /* Adjust buffer size to a multiple of CHUNK_SIZE bytes. */
419 num_chunks = size / CHUNK_SIZE;
421 if (size % CHUNK_SIZE > 0)
422 num_chunks++;
424 size = num_chunks * CHUNK_SIZE;
425 buffer = realloc(devh->buffer, size);
427 if (!buffer) {
428 log_err(ctx, "Failed to adjust buffer size to %zu bytes.",
429 size);
430 return false;
433 devh->buffer = buffer;
434 devh->buffer_size = size;
436 log_dbg(ctx, "Adjusted buffer size to %zu bytes.", size);
438 return true;
441 static int usb_send(struct jaylink_device_handle *devh, const uint8_t *buffer,
442 size_t length)
444 int ret;
445 struct jaylink_context *ctx;
446 unsigned int tries;
447 int transferred;
449 ctx = devh->dev->ctx;
450 tries = NUM_TIMEOUTS;
452 while (tries > 0 && length > 0) {
453 /* Send data in chunks of CHUNK_SIZE bytes to the device. */
454 ret = libusb_bulk_transfer(devh->usb_devh, devh->endpoint_out,
455 (unsigned char *)buffer, MIN(CHUNK_SIZE, length),
456 &transferred, USB_TIMEOUT);
458 if (ret == LIBUSB_SUCCESS) {
459 tries = NUM_TIMEOUTS;
460 } else if (ret == LIBUSB_ERROR_TIMEOUT) {
461 log_warn(ctx, "Sending data to device timed out, "
462 "retrying.");
463 tries--;
464 } else if (ret == LIBUSB_ERROR_IO) {
465 log_err(ctx, "Failed to send data to device: "
466 "input/output error.");
467 return JAYLINK_ERR_IO;
468 } else {
469 log_err(ctx, "Failed to send data to device: %s.",
470 libusb_error_name(ret));
471 return JAYLINK_ERR;
474 buffer += transferred;
475 length -= transferred;
477 log_dbg(ctx, "Sent %i bytes to device.", transferred);
480 if (!length)
481 return JAYLINK_OK;
483 log_err(ctx, "Sending data to device timed out.");
485 return JAYLINK_ERR_TIMEOUT;
489 * Write data to a device.
491 * Before this function is used transport_start_write() or
492 * transport_start_write_read() must be called to start a write operation. The
493 * total number of written bytes must not exceed the number of bytes of the
494 * write operation.
496 * @note A write operation will be performed and the data will be sent to the
497 * device when the number of written bytes reaches the number of bytes of
498 * the write operation. Before that the data will be written into a
499 * buffer.
501 * @param[in,out] devh Device handle.
502 * @param[in] buffer Buffer to write data from.
503 * @param[in] length Number of bytes to write.
505 * @retval JAYLINK_OK Success.
506 * @retval JAYLINK_ERR_ARG Invalid arguments.
507 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
508 * @retval JAYLINK_ERR_IO Input/output error.
509 * @retval JAYLINK_ERR Other error conditions.
511 JAYLINK_PRIV int transport_write(struct jaylink_device_handle *devh,
512 const uint8_t *buffer, size_t length)
514 int ret;
515 struct jaylink_context *ctx;
516 size_t num_chunks;
517 size_t fill_bytes;
518 size_t tmp;
520 ctx = devh->dev->ctx;
522 if (length > devh->write_length) {
523 log_err(ctx, "Requested to write %zu bytes but only %zu bytes "
524 "are expected for the write operation.", length,
525 devh->write_length);
526 return JAYLINK_ERR_ARG;
530 * Store data in the buffer if the expected number of bytes for the
531 * write operation is not reached.
533 if (length < devh->write_length) {
534 if (devh->write_pos + length > devh->buffer_size) {
535 if (!adjust_buffer(devh, devh->write_pos + length))
536 return JAYLINK_ERR_MALLOC;
539 memcpy(devh->buffer + devh->write_pos, buffer, length);
541 devh->write_length -= length;
542 devh->write_pos += length;
544 log_dbg(ctx, "Wrote %zu bytes into buffer.", length);
545 return JAYLINK_OK;
549 * Expected number of bytes for this write operation is reached and
550 * therefore the write operation will be performed.
552 devh->write_length = 0;
554 /* Send data directly to the device if the buffer is empty. */
555 if (!devh->write_pos)
556 return usb_send(devh, buffer, length);
559 * Calculate the number of bytes to fill up the buffer to reach a
560 * multiple of CHUNK_SIZE bytes. This ensures that the data from the
561 * buffer will be sent to the device in chunks of CHUNK_SIZE bytes.
562 * Note that this is why the buffer size must be a multiple of
563 * CHUNK_SIZE bytes.
565 num_chunks = devh->write_pos / CHUNK_SIZE;
567 if (devh->write_pos % CHUNK_SIZE)
568 num_chunks++;
570 fill_bytes = (num_chunks * CHUNK_SIZE) - devh->write_pos;
571 tmp = MIN(length, fill_bytes);
573 if (tmp > 0) {
574 memcpy(devh->buffer + devh->write_pos, buffer, tmp);
576 length -= tmp;
577 buffer += tmp;
579 log_dbg(ctx, "Buffer filled up with %zu bytes.", tmp);
582 /* Send buffered data to the device. */
583 ret = usb_send(devh, devh->buffer, devh->write_pos + tmp);
584 devh->write_pos = 0;
586 if (ret != JAYLINK_OK)
587 return ret;
589 if (!length)
590 return JAYLINK_OK;
592 /* Send remaining data to the device. */
593 return usb_send(devh, buffer, length);
596 static int usb_recv(struct jaylink_device_handle *devh, uint8_t *buffer,
597 size_t *length)
599 int ret;
600 struct jaylink_context *ctx;
601 unsigned int tries;
602 int transferred;
604 ctx = devh->dev->ctx;
605 tries = NUM_TIMEOUTS;
606 transferred = 0;
608 while (tries > 0 && !transferred) {
609 /* Always request CHUNK_SIZE bytes from the device. */
610 ret = libusb_bulk_transfer(devh->usb_devh, devh->endpoint_in,
611 (unsigned char *)buffer, CHUNK_SIZE, &transferred,
612 USB_TIMEOUT);
614 if (ret == LIBUSB_ERROR_TIMEOUT) {
615 log_warn(ctx, "Receiving data from device timed out, "
616 "retrying.");
617 tries--;
618 continue;
619 } else if (ret == LIBUSB_ERROR_IO) {
620 log_err(ctx, "Failed to receive data from device: "
621 "input/output error.");
622 return JAYLINK_ERR_IO;
623 } else if (ret != LIBUSB_SUCCESS) {
624 log_err(ctx, "Failed to receive data from device: %s.",
625 libusb_error_name(ret));
626 return JAYLINK_ERR;
629 log_dbg(ctx, "Received %i bytes from device.", transferred);
632 /* Ignore a possible timeout if at least one byte was received. */
633 if (transferred > 0) {
634 *length = transferred;
635 return JAYLINK_OK;
638 log_err(ctx, "Receiving data from device timed out.");
640 return JAYLINK_ERR_TIMEOUT;
644 * Read data from a device.
646 * Before this function is used transport_start_read() or
647 * transport_start_write_read() must be called to start a read operation. The
648 * total number of read bytes must not exceed the number of bytes of the read
649 * operation.
651 * @param[in,out] devh Device handle.
652 * @param[out] buffer Buffer to read data into on success. Its content is
653 * undefined on failure.
654 * @param[in] length Number of bytes to read.
656 * @retval JAYLINK_OK Success.
657 * @retval JAYLINK_ERR_ARG Invalid arguments.
658 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
659 * @retval JAYLINK_ERR_IO Input/output error.
660 * @retval JAYLINK_ERR Other error conditions.
662 JAYLINK_PRIV int transport_read(struct jaylink_device_handle *devh,
663 uint8_t *buffer, size_t length)
665 int ret;
666 struct jaylink_context *ctx;
667 size_t bytes_received;
668 size_t tmp;
670 ctx = devh->dev->ctx;
672 if (length > devh->read_length) {
673 log_err(ctx, "Requested to read %zu bytes but only %zu bytes "
674 "are expected for the read operation.", length,
675 devh->read_length);
676 return JAYLINK_ERR_ARG;
679 if (length <= devh->bytes_available) {
680 memcpy(buffer, devh->buffer + devh->read_pos, length);
682 devh->read_length -= length;
683 devh->bytes_available -= length;
684 devh->read_pos += length;
686 log_dbg(ctx, "Read %zu bytes from buffer.", length);
687 return JAYLINK_OK;
690 if (devh->bytes_available > 0) {
691 memcpy(buffer, devh->buffer + devh->read_pos,
692 devh->bytes_available);
694 buffer += devh->bytes_available;
695 length -= devh->bytes_available;
696 devh->read_length -= devh->bytes_available;
698 log_dbg(ctx, "Read %zu bytes from buffer to flush it.",
699 devh->bytes_available);
701 devh->bytes_available = 0;
702 devh->read_pos = 0;
705 while (length > 0) {
707 * If less than CHUNK_SIZE bytes are requested from the device,
708 * store the received data into the internal buffer instead of
709 * directly into the user provided buffer. This is necessary to
710 * prevent a possible buffer overflow because the number of
711 * requested bytes from the device is always CHUNK_SIZE and
712 * therefore up to CHUNK_SIZE bytes may be received.
713 * Note that this is why the internal buffer size must be at
714 * least CHUNK_SIZE bytes.
716 if (length < CHUNK_SIZE) {
717 ret = usb_recv(devh, devh->buffer, &bytes_received);
719 if (ret != JAYLINK_OK)
720 return ret;
722 tmp = MIN(bytes_received, length);
723 memcpy(buffer, devh->buffer, tmp);
726 * Setup the buffer for the remaining data if more data
727 * was received from the device than was requested.
729 if (bytes_received > length) {
730 devh->bytes_available = bytes_received - tmp;
731 devh->read_pos = tmp;
734 buffer += tmp;
735 length -= tmp;
736 devh->read_length -= tmp;
738 log_dbg(ctx, "Read %zu bytes from buffer.", tmp);
739 } else {
740 ret = usb_recv(devh, buffer, &bytes_received);
742 if (ret != JAYLINK_OK)
743 return ret;
745 buffer += bytes_received;
746 length -= bytes_received;
747 devh->read_length -= bytes_received;
749 log_dbg(ctx, "Read %zu bytes from device.",
750 bytes_received);
754 return JAYLINK_OK;