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/>.
23 #include <sys/types.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
33 #include <netinet/in.h>
36 #include "libjaylink.h"
37 #include "libjaylink-internal.h"
42 * Transport abstraction layer (TCP/IP).
46 #define CMD_SERVER 0x00
47 #define CMD_CLIENT 0x07
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 of a receive operation in milliseconds. */
59 #define RECV_TIMEOUT 5000
60 /** Timeout of a send operation in milliseconds. */
61 #define SEND_TIMEOUT 5000
63 /** String of the port number for the J-Link TCP/IP protocol. */
64 #define PORT_STRING "19020"
66 /** Size of the server's hello message in bytes. */
67 #define SERVER_HELLO_SIZE 4
69 * Maximum length of the server name including trailing null-terminator in
72 #define SERVER_NAME_MAX_LENGTH 256
75 static int initialize_handle(struct jaylink_device_handle
*devh
)
77 struct jaylink_context
*ctx
;
81 devh
->buffer_size
= BUFFER_SIZE
;
82 devh
->buffer
= malloc(devh
->buffer_size
);
85 log_err(ctx
, "Transport buffer malloc failed.");
86 return JAYLINK_ERR_MALLOC
;
89 devh
->read_length
= 0;
90 devh
->bytes_available
= 0;
93 devh
->write_length
= 0;
99 static void cleanup_handle(struct jaylink_device_handle
*devh
)
104 static int _recv(struct jaylink_device_handle
*devh
, uint8_t *buffer
,
107 struct jaylink_context
*ctx
;
110 ctx
= devh
->dev
->ctx
;
115 if (!socket_recv(devh
->sock
, buffer
, &tmp
, 0)) {
116 log_err(ctx
, "Failed to receive data from device.");
117 return JAYLINK_ERR_IO
;
119 log_err(ctx
, "Failed to receive data from device: "
120 "remote connection closed.");
121 return JAYLINK_ERR_IO
;
127 log_dbgio(ctx
, "Received %zu bytes from device.", tmp
);
133 static int handle_server_hello(struct jaylink_device_handle
*devh
)
136 struct jaylink_context
*ctx
;
137 uint8_t buf
[SERVER_HELLO_SIZE
];
138 char name
[SERVER_NAME_MAX_LENGTH
];
139 uint16_t proto_version
;
142 ctx
= devh
->dev
->ctx
;
144 ret
= _recv(devh
, buf
, sizeof(buf
));
146 if (ret
!= JAYLINK_OK
) {
147 log_err(ctx
, "Failed to receive hello message.");
151 if (buf
[0] == RESP_MAX_CONNECTIONS
) {
152 log_err(ctx
, "Maximum number of connections reached.");
156 if (buf
[0] != CMD_SERVER
) {
157 log_err(ctx
, "Invalid hello message received.");
158 return JAYLINK_ERR_PROTO
;
161 proto_version
= buffer_get_u16(buf
, 1);
163 log_dbg(ctx
, "Protocol version: 0x%04x.", proto_version
);
166 ret
= _recv(devh
, (uint8_t *)name
, length
);
168 if (ret
!= JAYLINK_OK
) {
169 log_err(ctx
, "Failed to receive server name.");
175 log_dbg(ctx
, "Server name: %s.", name
);
180 static int set_socket_timeouts(struct jaylink_device_handle
*devh
)
182 struct jaylink_context
*ctx
;
184 ctx
= devh
->dev
->ctx
;
188 timeout
= RECV_TIMEOUT
;
190 if (!socket_set_option(devh
->sock
, SOL_SOCKET
, SO_RCVTIMEO
, &timeout
,
192 log_err(ctx
, "Failed to set socket receive timeout.");
196 timeout
= SEND_TIMEOUT
;
198 if (!socket_set_option(devh
->sock
, SOL_SOCKET
, SO_SNDTIMEO
, &timeout
,
200 log_err(ctx
, "Failed to set socket send timeout.");
204 struct timeval timeout
;
206 timeout
.tv_sec
= RECV_TIMEOUT
/ 1000;
207 timeout
.tv_usec
= (RECV_TIMEOUT
% 1000) * 1000;
209 if (!socket_set_option(devh
->sock
, SOL_SOCKET
, SO_RCVTIMEO
, &timeout
,
210 sizeof(struct timeval
))) {
211 log_err(ctx
, "Failed to set socket receive timeout.");
215 timeout
.tv_sec
= SEND_TIMEOUT
/ 1000;
216 timeout
.tv_usec
= (SEND_TIMEOUT
% 1000) * 1000;
218 if (!socket_set_option(devh
->sock
, SOL_SOCKET
, SO_SNDTIMEO
, &timeout
,
219 sizeof(struct timeval
))) {
220 log_err(ctx
, "Failed to set socket send timeout.");
227 JAYLINK_PRIV
int transport_tcp_open(struct jaylink_device_handle
*devh
)
230 struct jaylink_context
*ctx
;
231 struct jaylink_device
*dev
;
232 struct addrinfo hints
;
233 struct addrinfo
*info
;
240 log_dbg(ctx
, "Trying to open device (IPv4 address = %s).",
243 ret
= initialize_handle(devh
);
245 if (ret
!= JAYLINK_OK
) {
246 log_err(ctx
, "Initialize device handle failed.");
250 memset(&hints
, 0, sizeof(struct addrinfo
));
251 hints
.ai_family
= AF_INET
;
252 hints
.ai_socktype
= SOCK_STREAM
;
253 hints
.ai_protocol
= IPPROTO_TCP
;
255 ret
= getaddrinfo(dev
->ipv4_address
, PORT_STRING
, &hints
, &info
);
258 log_err(ctx
, "Address lookup failed.");
259 cleanup_handle(devh
);
265 for (rp
= info
; rp
!= NULL
; rp
= rp
->ai_next
) {
266 sock
= socket(rp
->ai_family
, rp
->ai_socktype
, rp
->ai_protocol
);
271 if (!connect(sock
, info
->ai_addr
, info
->ai_addrlen
))
281 log_err(ctx
, "Failed to open device.");
282 cleanup_handle(devh
);
286 log_dbg(ctx
, "Device opened successfully.");
289 ret
= set_socket_timeouts(devh
);
291 if (ret
!= JAYLINK_OK
) {
293 cleanup_handle(devh
);
297 ret
= handle_server_hello(devh
);
299 if (ret
!= JAYLINK_OK
) {
301 cleanup_handle(devh
);
308 JAYLINK_PRIV
int transport_tcp_close(struct jaylink_device_handle
*devh
)
310 struct jaylink_context
*ctx
;
312 ctx
= devh
->dev
->ctx
;
314 log_dbg(ctx
, "Closing device (IPv4 address = %s).",
315 devh
->dev
->ipv4_address
);
317 cleanup_handle(devh
);
319 log_dbg(ctx
, "Device closed successfully.");
324 JAYLINK_PRIV
int transport_tcp_start_write(struct jaylink_device_handle
*devh
,
325 size_t length
, bool has_command
)
327 struct jaylink_context
*ctx
;
330 return JAYLINK_ERR_ARG
;
332 ctx
= devh
->dev
->ctx
;
334 log_dbgio(ctx
, "Starting write operation (length = %zu bytes).",
337 if (devh
->write_pos
> 0)
338 log_warn(ctx
, "Last write operation left %zu bytes in the "
339 "buffer.", devh
->write_pos
);
341 if (devh
->write_length
> 0)
342 log_warn(ctx
, "Last write operation was not performed.");
344 devh
->write_length
= length
;
348 devh
->buffer
[0] = CMD_CLIENT
;
355 JAYLINK_PRIV
int transport_tcp_start_read(struct jaylink_device_handle
*devh
,
358 struct jaylink_context
*ctx
;
361 return JAYLINK_ERR_ARG
;
363 ctx
= devh
->dev
->ctx
;
365 log_dbgio(ctx
, "Starting read operation (length = %zu bytes).",
368 if (devh
->bytes_available
> 0)
369 log_dbg(ctx
, "Last read operation left %zu bytes in the "
370 "buffer.", devh
->bytes_available
);
372 if (devh
->read_length
> 0)
373 log_warn(ctx
, "Last read operation left %zu bytes.",
376 devh
->read_length
= length
;
381 JAYLINK_PRIV
int transport_tcp_start_write_read(
382 struct jaylink_device_handle
*devh
, size_t write_length
,
383 size_t read_length
, bool has_command
)
385 struct jaylink_context
*ctx
;
387 if (!read_length
|| !write_length
)
388 return JAYLINK_ERR_ARG
;
390 ctx
= devh
->dev
->ctx
;
392 log_dbgio(ctx
, "Starting write / read operation (length = "
393 "%zu / %zu bytes).", write_length
, read_length
);
395 if (devh
->write_pos
> 0)
396 log_warn(ctx
, "Last write operation left %zu bytes in the "
397 "buffer.", devh
->write_pos
);
399 if (devh
->write_length
> 0)
400 log_warn(ctx
, "Last write operation was not performed.");
402 if (devh
->bytes_available
> 0)
403 log_warn(ctx
, "Last read operation left %zu bytes in the "
404 "buffer.", devh
->bytes_available
);
406 if (devh
->read_length
> 0)
407 log_warn(ctx
, "Last read operation left %zu bytes.",
410 devh
->write_length
= write_length
;
414 devh
->buffer
[0] = CMD_CLIENT
;
418 devh
->read_length
= read_length
;
419 devh
->bytes_available
= 0;
425 static int _send(struct jaylink_device_handle
*devh
, const uint8_t *buffer
,
428 struct jaylink_context
*ctx
;
431 ctx
= devh
->dev
->ctx
;
436 if (!socket_send(devh
->sock
, buffer
, &tmp
, 0)) {
437 log_err(ctx
, "Failed to send data to device.");
438 return JAYLINK_ERR_IO
;
444 log_dbgio(ctx
, "Sent %zu bytes to device.", tmp
);
450 static bool adjust_buffer(struct jaylink_device_handle
*devh
, size_t size
)
452 struct jaylink_context
*ctx
;
456 ctx
= devh
->dev
->ctx
;
458 /* Adjust buffer size to a multiple of BUFFER_SIZE bytes. */
459 num
= size
/ BUFFER_SIZE
;
461 if (size
% BUFFER_SIZE
> 0)
464 size
= num
* BUFFER_SIZE
;
465 buffer
= realloc(devh
->buffer
, size
);
468 log_err(ctx
, "Failed to adjust buffer size to %zu bytes.",
473 devh
->buffer
= buffer
;
474 devh
->buffer_size
= size
;
476 log_dbg(ctx
, "Adjusted buffer size to %zu bytes.", size
);
481 JAYLINK_PRIV
int transport_tcp_write(struct jaylink_device_handle
*devh
,
482 const uint8_t *buffer
, size_t length
)
485 struct jaylink_context
*ctx
;
488 ctx
= devh
->dev
->ctx
;
490 if (length
> devh
->write_length
) {
491 log_err(ctx
, "Requested to write %zu bytes but only %zu bytes "
492 "are expected for the write operation.", length
,
494 return JAYLINK_ERR_ARG
;
498 * Store data in the buffer if the expected number of bytes for the
499 * write operation is not reached.
501 if (length
< devh
->write_length
) {
502 if (devh
->write_pos
+ length
> devh
->buffer_size
) {
503 if (!adjust_buffer(devh
, devh
->write_pos
+ length
))
504 return JAYLINK_ERR_MALLOC
;
507 memcpy(devh
->buffer
+ devh
->write_pos
, buffer
, length
);
509 devh
->write_length
-= length
;
510 devh
->write_pos
+= length
;
512 log_dbgio(ctx
, "Wrote %zu bytes into buffer.", length
);
517 * Expected number of bytes for this write operation is reached and
518 * therefore the write operation will be performed.
520 devh
->write_length
= 0;
522 /* Send data directly to the device if the buffer is empty. */
523 if (!devh
->write_pos
)
524 return _send(devh
, buffer
, length
);
526 tmp
= MIN(length
, devh
->buffer_size
- devh
->write_pos
);
529 * Fill up the internal buffer in order to reduce the number of
530 * messages sent to the device for performance reasons.
532 memcpy(devh
->buffer
+ devh
->write_pos
, buffer
, tmp
);
537 log_dbgio(ctx
, "Buffer filled up with %zu bytes.", tmp
);
539 ret
= _send(devh
, devh
->buffer
, devh
->write_pos
+ tmp
);
543 if (ret
!= JAYLINK_OK
)
549 return _send(devh
, buffer
, length
);
552 JAYLINK_PRIV
int transport_tcp_read(struct jaylink_device_handle
*devh
,
553 uint8_t *buffer
, size_t length
)
556 struct jaylink_context
*ctx
;
558 ctx
= devh
->dev
->ctx
;
560 if (length
> devh
->read_length
) {
561 log_err(ctx
, "Requested to read %zu bytes but only %zu bytes "
562 "are expected for the read operation.", length
,
564 return JAYLINK_ERR_ARG
;
567 if (length
<= devh
->bytes_available
) {
568 memcpy(buffer
, devh
->buffer
+ devh
->read_pos
, length
);
570 devh
->read_length
-= length
;
571 devh
->bytes_available
-= length
;
572 devh
->read_pos
+= length
;
574 log_dbgio(ctx
, "Read %zu bytes from buffer.", length
);
578 if (devh
->bytes_available
) {
579 memcpy(buffer
, devh
->buffer
+ devh
->read_pos
,
580 devh
->bytes_available
);
582 buffer
+= devh
->bytes_available
;
583 length
-= devh
->bytes_available
;
584 devh
->read_length
-= devh
->bytes_available
;
586 log_dbgio(ctx
, "Read %zu bytes from buffer to flush it.",
587 devh
->bytes_available
);
589 devh
->bytes_available
= 0;
593 ret
= _recv(devh
, buffer
, length
);
595 if (ret
!= JAYLINK_OK
)
598 devh
->read_length
-= length
;