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 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
71 * Maximum length of the server name including trailing null-terminator in
74 #define SERVER_NAME_MAX_LENGTH 256
77 static int initialize_handle(struct jaylink_device_handle
*devh
)
79 struct jaylink_context
*ctx
;
83 devh
->buffer_size
= BUFFER_SIZE
;
84 devh
->buffer
= malloc(devh
->buffer_size
);
87 log_err(ctx
, "Transport buffer malloc failed");
88 return JAYLINK_ERR_MALLOC
;
91 devh
->read_length
= 0;
92 devh
->bytes_available
= 0;
95 devh
->write_length
= 0;
101 static void cleanup_handle(struct jaylink_device_handle
*devh
)
106 static int _recv(struct jaylink_device_handle
*devh
, uint8_t *buffer
,
109 struct jaylink_context
*ctx
;
112 ctx
= devh
->dev
->ctx
;
117 if (!socket_recv(devh
->sock
, buffer
, &tmp
, 0)) {
118 log_err(ctx
, "Failed to receive data from device");
119 return JAYLINK_ERR_IO
;
121 log_err(ctx
, "Failed to receive data from device: "
122 "remote connection closed");
123 return JAYLINK_ERR_IO
;
129 log_dbgio(ctx
, "Received %zu bytes from device", tmp
);
135 static int handle_server_hello(struct jaylink_device_handle
*devh
)
138 struct jaylink_context
*ctx
;
139 uint8_t buf
[SERVER_HELLO_SIZE
];
140 char name
[SERVER_NAME_MAX_LENGTH
];
141 uint16_t proto_version
;
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");
153 if (buf
[0] == RESP_MAX_CONNECTIONS
) {
154 log_err(ctx
, "Maximum number of connections reached");
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
);
168 ret
= _recv(devh
, (uint8_t *)name
, length
);
170 if (ret
!= JAYLINK_OK
) {
171 log_err(ctx
, "Failed to receive server name");
177 log_dbg(ctx
, "Server name: %s", name
);
182 static int set_socket_timeouts(struct jaylink_device_handle
*devh
)
184 struct jaylink_context
*ctx
;
186 ctx
= devh
->dev
->ctx
;
190 timeout
= RECV_TIMEOUT
;
192 if (!socket_set_option(devh
->sock
, SOL_SOCKET
, SO_RCVTIMEO
, &timeout
,
194 log_err(ctx
, "Failed to set socket receive timeout");
198 timeout
= SEND_TIMEOUT
;
200 if (!socket_set_option(devh
->sock
, SOL_SOCKET
, SO_SNDTIMEO
, &timeout
,
202 log_err(ctx
, "Failed to set socket send timeout");
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");
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");
229 JAYLINK_PRIV
int transport_tcp_open(struct jaylink_device_handle
*devh
)
232 struct jaylink_context
*ctx
;
233 struct jaylink_device
*dev
;
234 struct addrinfo hints
;
235 struct addrinfo
*info
;
241 log_dbg(ctx
, "Trying to open device (IPv4 address = %s)",
244 ret
= initialize_handle(devh
);
246 if (ret
!= JAYLINK_OK
) {
247 log_err(ctx
, "Initialize device handle failed");
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
);
259 log_err(ctx
, "Address lookup failed");
260 cleanup_handle(devh
);
266 for (struct addrinfo
*rp
= info
; rp
!= NULL
; rp
= rp
->ai_next
) {
267 sock
= socket(rp
->ai_family
, rp
->ai_socktype
, rp
->ai_protocol
);
272 ret
= socket_connect(sock
, info
->ai_addr
, info
->ai_addrlen
,
275 if (ret
== JAYLINK_ERR_TIMEOUT
) {
277 cleanup_handle(devh
);
278 return JAYLINK_ERR_TIMEOUT
;
279 } else if (ret
== JAYLINK_OK
) {
290 log_err(ctx
, "Failed to open device");
291 cleanup_handle(devh
);
295 log_dbg(ctx
, "Device opened successfully");
298 ret
= set_socket_timeouts(devh
);
300 if (ret
!= JAYLINK_OK
) {
302 cleanup_handle(devh
);
306 ret
= handle_server_hello(devh
);
308 if (ret
!= JAYLINK_OK
) {
310 cleanup_handle(devh
);
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");
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
;
339 return JAYLINK_ERR_ARG
;
341 ctx
= devh
->dev
->ctx
;
343 log_dbgio(ctx
, "Starting write operation (length = %zu bytes)",
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
;
357 devh
->buffer
[0] = CMD_CLIENT
;
364 JAYLINK_PRIV
int transport_tcp_start_read(struct jaylink_device_handle
*devh
,
367 struct jaylink_context
*ctx
;
370 return JAYLINK_ERR_ARG
;
372 ctx
= devh
->dev
->ctx
;
374 log_dbgio(ctx
, "Starting read operation (length = %zu bytes)",
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",
385 devh
->read_length
= length
;
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",
419 devh
->write_length
= write_length
;
423 devh
->buffer
[0] = CMD_CLIENT
;
427 devh
->read_length
= read_length
;
428 devh
->bytes_available
= 0;
434 static int _send(struct jaylink_device_handle
*devh
, const uint8_t *buffer
,
437 struct jaylink_context
*ctx
;
440 ctx
= devh
->dev
->ctx
;
445 if (!socket_send(devh
->sock
, buffer
, &tmp
, 0)) {
446 log_err(ctx
, "Failed to send data to device");
447 return JAYLINK_ERR_IO
;
453 log_dbgio(ctx
, "Sent %zu bytes to device", tmp
);
459 static bool adjust_buffer(struct jaylink_device_handle
*devh
, size_t size
)
461 struct jaylink_context
*ctx
;
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)
473 size
= num
* BUFFER_SIZE
;
474 buffer
= realloc(devh
->buffer
, size
);
477 log_err(ctx
, "Failed to adjust buffer size to %zu bytes",
482 devh
->buffer
= buffer
;
483 devh
->buffer_size
= size
;
485 log_dbg(ctx
, "Adjusted buffer size to %zu bytes", size
);
490 JAYLINK_PRIV
int transport_tcp_write(struct jaylink_device_handle
*devh
,
491 const uint8_t *buffer
, size_t length
)
494 struct jaylink_context
*ctx
;
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
,
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
);
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
);
546 log_dbgio(ctx
, "Buffer filled up with %zu bytes", tmp
);
548 ret
= _send(devh
, devh
->buffer
, devh
->write_pos
+ tmp
);
552 if (ret
!= 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
)
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
,
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
);
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;
602 ret
= _recv(devh
, buffer
, length
);
604 if (ret
!= JAYLINK_OK
)
607 devh
->read_length
-= length
;