Bump package version to 0.4.0
[libjaylink.git] / libjaylink / transport_tcp.c
blobdc38d8ff5bbe8cbbc634c5d846b4fa2e82ff11a2
1 /*
2 * This file is part of the libjaylink project.
4 * Copyright (C) 2015-2017 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 <string.h>
23 #include <sys/types.h>
25 #ifdef _WIN32
26 #include <winsock2.h>
27 #include <ws2tcpip.h>
28 #else
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netdb.h>
33 #include <netinet/in.h>
34 #endif
36 #include "libjaylink.h"
37 #include "libjaylink-internal.h"
39 /**
40 * @file
42 * Transport abstraction layer (TCP/IP).
45 /** @cond PRIVATE */
46 #define CMD_SERVER 0x00
47 #define CMD_CLIENT 0x07
49 /**
50 * Response status code indicating that the maximum number of simultaneous
51 * connections on the device has been reached.
53 #define RESP_MAX_CONNECTIONS 0xfe
55 /** Buffer size in bytes. */
56 #define BUFFER_SIZE 2048
58 /** Timeout for connection establishment in milliseconds. */
59 #define CONNECT_TIMEOUT 5000
60 /** Timeout of a receive operation in milliseconds. */
61 #define RECV_TIMEOUT 5000
62 /** Timeout of a send operation in milliseconds. */
63 #define SEND_TIMEOUT 5000
65 /** String of the port number for the J-Link TCP/IP protocol. */
66 #define PORT_STRING "19020"
68 /** Size of the server's hello message in bytes. */
69 #define SERVER_HELLO_SIZE 4
70 /**
71 * Maximum length of the server name including trailing null-terminator in
72 * bytes.
74 #define SERVER_NAME_MAX_LENGTH 256
75 /** @endcond */
77 static int initialize_handle(struct jaylink_device_handle *devh)
79 struct jaylink_context *ctx;
81 ctx = devh->dev->ctx;
83 devh->buffer_size = BUFFER_SIZE;
84 devh->buffer = malloc(devh->buffer_size);
86 if (!devh->buffer) {
87 log_err(ctx, "Transport buffer malloc failed");
88 return JAYLINK_ERR_MALLOC;
91 devh->read_length = 0;
92 devh->bytes_available = 0;
93 devh->read_pos = 0;
95 devh->write_length = 0;
96 devh->write_pos = 0;
98 return JAYLINK_OK;
101 static void cleanup_handle(struct jaylink_device_handle *devh)
103 free(devh->buffer);
106 static int _recv(struct jaylink_device_handle *devh, uint8_t *buffer,
107 size_t length)
109 struct jaylink_context *ctx;
110 size_t tmp;
112 ctx = devh->dev->ctx;
114 while (length > 0) {
115 tmp = length;
117 if (!socket_recv(devh->sock, buffer, &tmp, 0)) {
118 log_err(ctx, "Failed to receive data from device");
119 return JAYLINK_ERR_IO;
120 } else if (!tmp) {
121 log_err(ctx, "Failed to receive data from device: "
122 "remote connection closed");
123 return JAYLINK_ERR_IO;
126 buffer += tmp;
127 length -= tmp;
129 log_dbgio(ctx, "Received %zu bytes from device", tmp);
132 return JAYLINK_OK;
135 static int handle_server_hello(struct jaylink_device_handle *devh)
137 int ret;
138 struct jaylink_context *ctx;
139 uint8_t buf[SERVER_HELLO_SIZE];
140 char name[SERVER_NAME_MAX_LENGTH];
141 uint16_t proto_version;
142 size_t length;
144 ctx = devh->dev->ctx;
146 ret = _recv(devh, buf, sizeof(buf));
148 if (ret != JAYLINK_OK) {
149 log_err(ctx, "Failed to receive hello message");
150 return ret;
153 if (buf[0] == RESP_MAX_CONNECTIONS) {
154 log_err(ctx, "Maximum number of connections reached");
155 return JAYLINK_ERR;
158 if (buf[0] != CMD_SERVER) {
159 log_err(ctx, "Invalid hello message received");
160 return JAYLINK_ERR_PROTO;
163 proto_version = buffer_get_u16(buf, 1);
165 log_dbg(ctx, "Protocol version: 0x%04x", proto_version);
167 length = buf[3];
168 ret = _recv(devh, (uint8_t *)name, length);
170 if (ret != JAYLINK_OK) {
171 log_err(ctx, "Failed to receive server name");
172 return ret;
175 name[length] = '\0';
177 log_dbg(ctx, "Server name: %s", name);
179 return JAYLINK_OK;
182 static int set_socket_timeouts(struct jaylink_device_handle *devh)
184 struct jaylink_context *ctx;
186 ctx = devh->dev->ctx;
187 #ifdef _WIN32
188 DWORD timeout;
190 timeout = RECV_TIMEOUT;
192 if (!socket_set_option(devh->sock, SOL_SOCKET, SO_RCVTIMEO, &timeout,
193 sizeof(timeout))) {
194 log_err(ctx, "Failed to set socket receive timeout");
195 return JAYLINK_ERR;
198 timeout = SEND_TIMEOUT;
200 if (!socket_set_option(devh->sock, SOL_SOCKET, SO_SNDTIMEO, &timeout,
201 sizeof(timeout))) {
202 log_err(ctx, "Failed to set socket send timeout");
203 return JAYLINK_ERR;
205 #else
206 struct timeval timeout;
208 timeout.tv_sec = RECV_TIMEOUT / 1000;
209 timeout.tv_usec = (RECV_TIMEOUT % 1000) * 1000;
211 if (!socket_set_option(devh->sock, SOL_SOCKET, SO_RCVTIMEO, &timeout,
212 sizeof(struct timeval))) {
213 log_err(ctx, "Failed to set socket receive timeout");
214 return JAYLINK_ERR;
217 timeout.tv_sec = SEND_TIMEOUT / 1000;
218 timeout.tv_usec = (SEND_TIMEOUT % 1000) * 1000;
220 if (!socket_set_option(devh->sock, SOL_SOCKET, SO_SNDTIMEO, &timeout,
221 sizeof(struct timeval))) {
222 log_err(ctx, "Failed to set socket send timeout");
223 return JAYLINK_ERR;
225 #endif
226 return JAYLINK_OK;
229 JAYLINK_PRIV int transport_tcp_open(struct jaylink_device_handle *devh)
231 int ret;
232 struct jaylink_context *ctx;
233 struct jaylink_device *dev;
234 struct addrinfo hints;
235 struct addrinfo *info;
236 int sock;
238 dev = devh->dev;
239 ctx = dev->ctx;
241 log_dbg(ctx, "Trying to open device (IPv4 address = %s)",
242 dev->ipv4_address);
244 ret = initialize_handle(devh);
246 if (ret != JAYLINK_OK) {
247 log_err(ctx, "Initialize device handle failed");
248 return ret;
251 memset(&hints, 0, sizeof(struct addrinfo));
252 hints.ai_family = AF_INET;
253 hints.ai_socktype = SOCK_STREAM;
254 hints.ai_protocol = IPPROTO_TCP;
256 ret = getaddrinfo(dev->ipv4_address, PORT_STRING, &hints, &info);
258 if (ret != 0) {
259 log_err(ctx, "Address lookup failed");
260 cleanup_handle(devh);
261 return JAYLINK_ERR;
264 sock = -1;
266 for (struct addrinfo *rp = info; rp != NULL; rp = rp->ai_next) {
267 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
269 if (sock < 0)
270 continue;
272 ret = socket_connect(sock, info->ai_addr, info->ai_addrlen,
273 CONNECT_TIMEOUT);
275 if (ret == JAYLINK_ERR_TIMEOUT) {
276 freeaddrinfo(info);
277 cleanup_handle(devh);
278 return JAYLINK_ERR_TIMEOUT;
279 } else if (ret == JAYLINK_OK) {
280 break;
283 socket_close(sock);
284 sock = -1;
287 freeaddrinfo(info);
289 if (sock < 0) {
290 log_err(ctx, "Failed to open device");
291 cleanup_handle(devh);
292 return JAYLINK_ERR;
295 log_dbg(ctx, "Device opened successfully");
297 devh->sock = sock;
298 ret = set_socket_timeouts(devh);
300 if (ret != JAYLINK_OK) {
301 socket_close(sock);
302 cleanup_handle(devh);
303 return ret;
306 ret = handle_server_hello(devh);
308 if (ret != JAYLINK_OK) {
309 socket_close(sock);
310 cleanup_handle(devh);
311 return ret;
314 return JAYLINK_OK;
317 JAYLINK_PRIV int transport_tcp_close(struct jaylink_device_handle *devh)
319 struct jaylink_context *ctx;
321 ctx = devh->dev->ctx;
323 log_dbg(ctx, "Closing device (IPv4 address = %s)",
324 devh->dev->ipv4_address);
326 cleanup_handle(devh);
328 log_dbg(ctx, "Device closed successfully");
330 return JAYLINK_OK;
333 JAYLINK_PRIV int transport_tcp_start_write(struct jaylink_device_handle *devh,
334 size_t length, bool has_command)
336 struct jaylink_context *ctx;
338 if (!length)
339 return JAYLINK_ERR_ARG;
341 ctx = devh->dev->ctx;
343 log_dbgio(ctx, "Starting write operation (length = %zu bytes)",
344 length);
346 if (devh->write_pos > 0)
347 log_warn(ctx, "Last write operation left %zu bytes in the "
348 "buffer", devh->write_pos);
350 if (devh->write_length > 0)
351 log_warn(ctx, "Last write operation was not performed");
353 devh->write_length = length;
354 devh->write_pos = 0;
356 if (has_command) {
357 devh->buffer[0] = CMD_CLIENT;
358 devh->write_pos++;
361 return JAYLINK_OK;
364 JAYLINK_PRIV int transport_tcp_start_read(struct jaylink_device_handle *devh,
365 size_t length)
367 struct jaylink_context *ctx;
369 if (!length)
370 return JAYLINK_ERR_ARG;
372 ctx = devh->dev->ctx;
374 log_dbgio(ctx, "Starting read operation (length = %zu bytes)",
375 length);
377 if (devh->bytes_available > 0)
378 log_dbg(ctx, "Last read operation left %zu bytes in the "
379 "buffer", devh->bytes_available);
381 if (devh->read_length > 0)
382 log_warn(ctx, "Last read operation left %zu bytes",
383 devh->read_length);
385 devh->read_length = length;
387 return JAYLINK_OK;
390 JAYLINK_PRIV int transport_tcp_start_write_read(
391 struct jaylink_device_handle *devh, size_t write_length,
392 size_t read_length, bool has_command)
394 struct jaylink_context *ctx;
396 if (!read_length || !write_length)
397 return JAYLINK_ERR_ARG;
399 ctx = devh->dev->ctx;
401 log_dbgio(ctx, "Starting write / read operation (length = "
402 "%zu / %zu bytes)", write_length, read_length);
404 if (devh->write_pos > 0)
405 log_warn(ctx, "Last write operation left %zu bytes in the "
406 "buffer", devh->write_pos);
408 if (devh->write_length > 0)
409 log_warn(ctx, "Last write operation was not performed");
411 if (devh->bytes_available > 0)
412 log_warn(ctx, "Last read operation left %zu bytes in the "
413 "buffer", devh->bytes_available);
415 if (devh->read_length > 0)
416 log_warn(ctx, "Last read operation left %zu bytes",
417 devh->read_length);
419 devh->write_length = write_length;
420 devh->write_pos = 0;
422 if (has_command) {
423 devh->buffer[0] = CMD_CLIENT;
424 devh->write_pos++;
427 devh->read_length = read_length;
428 devh->bytes_available = 0;
429 devh->read_pos = 0;
431 return JAYLINK_OK;
434 static int _send(struct jaylink_device_handle *devh, const uint8_t *buffer,
435 size_t length)
437 struct jaylink_context *ctx;
438 size_t tmp;
440 ctx = devh->dev->ctx;
442 while (length > 0) {
443 tmp = length;
445 if (!socket_send(devh->sock, buffer, &tmp, 0)) {
446 log_err(ctx, "Failed to send data to device");
447 return JAYLINK_ERR_IO;
450 buffer += tmp;
451 length -= tmp;
453 log_dbgio(ctx, "Sent %zu bytes to device", tmp);
456 return JAYLINK_OK;
459 static bool adjust_buffer(struct jaylink_device_handle *devh, size_t size)
461 struct jaylink_context *ctx;
462 uint8_t *buffer;
463 size_t num;
465 ctx = devh->dev->ctx;
467 /* Adjust buffer size to a multiple of BUFFER_SIZE bytes. */
468 num = size / BUFFER_SIZE;
470 if (size % BUFFER_SIZE > 0)
471 num++;
473 size = num * BUFFER_SIZE;
474 buffer = realloc(devh->buffer, size);
476 if (!buffer) {
477 log_err(ctx, "Failed to adjust buffer size to %zu bytes",
478 size);
479 return false;
482 devh->buffer = buffer;
483 devh->buffer_size = size;
485 log_dbg(ctx, "Adjusted buffer size to %zu bytes", size);
487 return true;
490 JAYLINK_PRIV int transport_tcp_write(struct jaylink_device_handle *devh,
491 const uint8_t *buffer, size_t length)
493 int ret;
494 struct jaylink_context *ctx;
495 size_t tmp;
497 ctx = devh->dev->ctx;
499 if (length > devh->write_length) {
500 log_err(ctx, "Requested to write %zu bytes but only %zu bytes "
501 "are expected for the write operation", length,
502 devh->write_length);
503 return JAYLINK_ERR_ARG;
507 * Store data in the buffer if the expected number of bytes for the
508 * write operation is not reached.
510 if (length < devh->write_length) {
511 if (devh->write_pos + length > devh->buffer_size) {
512 if (!adjust_buffer(devh, devh->write_pos + length))
513 return JAYLINK_ERR_MALLOC;
516 memcpy(devh->buffer + devh->write_pos, buffer, length);
518 devh->write_length -= length;
519 devh->write_pos += length;
521 log_dbgio(ctx, "Wrote %zu bytes into buffer", length);
522 return JAYLINK_OK;
526 * Expected number of bytes for this write operation is reached and
527 * therefore the write operation will be performed.
529 devh->write_length = 0;
531 /* Send data directly to the device if the buffer is empty. */
532 if (!devh->write_pos)
533 return _send(devh, buffer, length);
535 tmp = MIN(length, devh->buffer_size - devh->write_pos);
538 * Fill up the internal buffer in order to reduce the number of
539 * messages sent to the device for performance reasons.
541 memcpy(devh->buffer + devh->write_pos, buffer, tmp);
543 length -= tmp;
544 buffer += tmp;
546 log_dbgio(ctx, "Buffer filled up with %zu bytes", tmp);
548 ret = _send(devh, devh->buffer, devh->write_pos + tmp);
550 devh->write_pos = 0;
552 if (ret != JAYLINK_OK)
553 return ret;
555 if (!length)
556 return JAYLINK_OK;
558 return _send(devh, buffer, length);
561 JAYLINK_PRIV int transport_tcp_read(struct jaylink_device_handle *devh,
562 uint8_t *buffer, size_t length)
564 int ret;
565 struct jaylink_context *ctx;
567 ctx = devh->dev->ctx;
569 if (length > devh->read_length) {
570 log_err(ctx, "Requested to read %zu bytes but only %zu bytes "
571 "are expected for the read operation", length,
572 devh->read_length);
573 return JAYLINK_ERR_ARG;
576 if (length <= devh->bytes_available) {
577 memcpy(buffer, devh->buffer + devh->read_pos, length);
579 devh->read_length -= length;
580 devh->bytes_available -= length;
581 devh->read_pos += length;
583 log_dbgio(ctx, "Read %zu bytes from buffer", length);
584 return JAYLINK_OK;
587 if (devh->bytes_available) {
588 memcpy(buffer, devh->buffer + devh->read_pos,
589 devh->bytes_available);
591 buffer += devh->bytes_available;
592 length -= devh->bytes_available;
593 devh->read_length -= devh->bytes_available;
595 log_dbgio(ctx, "Read %zu bytes from buffer to flush it",
596 devh->bytes_available);
598 devh->bytes_available = 0;
599 devh->read_pos = 0;
602 ret = _recv(devh, buffer, length);
604 if (ret != JAYLINK_OK)
605 return ret;
607 devh->read_length -= length;
609 return JAYLINK_OK;