diff --git a/CMakeLists.txt b/CMakeLists.txt index c7991ab..a5e5c30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,10 @@ if(NOT ANDROID) libj1939.c ) + target_link_libraries(j1939 + PRIVATE can + ) + add_library(isobusfs SHARED isobusfs/isobusfs_cmn.c isobusfs/isobusfs_cmn_dh.c @@ -134,7 +138,7 @@ if(NOT ANDROID) ) target_link_libraries(isobusfs-cli - PRIVATE isobusfs can + PRIVATE isobusfs can j1939 ) add_executable(isobusfs-srv @@ -148,7 +152,7 @@ if(NOT ANDROID) ) target_link_libraries(isobusfs-srv - PRIVATE isobusfs can + PRIVATE isobusfs can j1939 ) install(TARGETS @@ -167,7 +171,7 @@ foreach(name ${PROGRAMS}) if("${name}" IN_LIST PROGRAMS_J1939) target_link_libraries(${name} - PRIVATE j1939 + PRIVATE j1939 can ) elseif("${name}" IN_LIST PROGRAMS_CANLIB) target_link_libraries(${name} diff --git a/isobusfs/isobusfs_cli.c b/isobusfs/isobusfs_cli.c index b6bcd77..6d74bba 100644 --- a/isobusfs/isobusfs_cli.c +++ b/isobusfs/isobusfs_cli.c @@ -336,7 +336,7 @@ int isobusfs_cli_process_events_and_tasks(struct isobusfs_priv *priv) if (priv->state == ISOBUSFS_CLI_STATE_SELFTEST) dont_wait = true; - ret = isobusfs_cmn_prepare_for_events(&priv->cmn, &nfds, dont_wait); + ret = libj1939_prepare_for_events(&priv->cmn, &nfds, dont_wait); if (ret) return ret; @@ -354,7 +354,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv) struct sockaddr_can addr = priv->sockname; int ret; - ret = isobusfs_cmn_open_socket(); + ret = libj1939_open_socket(); if (ret < 0) return ret; @@ -362,7 +362,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv) /* TODO: this is TX only socket */ addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL; - ret = isobusfs_cmn_bind_socket(priv->sock_main, &addr); + ret = libj1939_bind_socket(priv->sock_main, &addr); if (ret < 0) return ret; @@ -370,7 +370,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv) if (ret < 0) return ret; - ret = isobusfs_cmn_socket_prio(priv->sock_main, ISOBUSFS_PRIO_DEFAULT); + ret = libj1939_socket_prio(priv->sock_main, ISOBUSFS_PRIO_DEFAULT); if (ret < 0) return ret; @@ -378,7 +378,7 @@ static int isobusfs_cli_sock_main_prepare(struct isobusfs_priv *priv) if (ret < 0) return ret; - return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, + return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_main, EPOLLIN); } @@ -398,7 +398,7 @@ static int isobusfs_cli_sock_int_prepare(struct isobusfs_priv *priv) if (ret < 0) return ret; - return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, + return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, STDIN_FILENO, EPOLLIN); } @@ -407,7 +407,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv) struct sockaddr_can addr = priv->sockname; int ret; - ret = isobusfs_cmn_open_socket(); + ret = libj1939_open_socket(); if (ret < 0) return ret; @@ -419,7 +419,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv) /* TODO: this is TX only socket */ addr.can_addr.j1939.pgn = J1939_NO_PGN; - ret = isobusfs_cmn_bind_socket(priv->sock_ccm, &addr); + ret = libj1939_bind_socket(priv->sock_ccm, &addr); if (ret < 0) return ret; @@ -427,7 +427,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv) if (ret < 0) return ret; - ret = isobusfs_cmn_socket_prio(priv->sock_ccm, ISOBUSFS_PRIO_DEFAULT); + ret = libj1939_socket_prio(priv->sock_ccm, ISOBUSFS_PRIO_DEFAULT); if (ret < 0) return ret; @@ -436,7 +436,7 @@ static int isobusfs_cli_sock_ccm_prepare(struct isobusfs_priv *priv) return ret; /* poll for errors to get confirmation if our packets are send */ - return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_ccm, + return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_ccm, EPOLLERR); } @@ -445,23 +445,23 @@ static int isobusfs_cli_sock_nack_prepare(struct isobusfs_priv *priv) struct sockaddr_can addr = priv->sockname; int ret; - ret = isobusfs_cmn_open_socket(); + ret = libj1939_open_socket(); if (ret < 0) return ret; priv->sock_nack = ret; addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK; - ret = isobusfs_cmn_bind_socket(priv->sock_nack, &addr); + ret = libj1939_bind_socket(priv->sock_nack, &addr); if (ret < 0) return ret; - ret = isobusfs_cmn_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK); + ret = libj1939_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK); if (ret < 0) return ret; /* poll for errors to get confirmation if our packets are send */ - return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, + return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_nack, EPOLLIN); } @@ -471,7 +471,7 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv) struct sockaddr_can addr = priv->sockname; int ret; - ret = isobusfs_cmn_open_socket(); + ret = libj1939_open_socket(); if (ret < 0) return ret; @@ -481,11 +481,11 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv) addr.can_addr.j1939.name = J1939_NO_NAME; addr.can_addr.j1939.addr = J1939_NO_ADDR; addr.can_addr.j1939.pgn = ISOBUSFS_PGN_FS_TO_CL; - ret = isobusfs_cmn_bind_socket(priv->sock_bcast_rx, &addr); + ret = libj1939_bind_socket(priv->sock_bcast_rx, &addr); if (ret < 0) return ret; - ret = isobusfs_cmn_set_broadcast(priv->sock_bcast_rx); + ret = libj1939_set_broadcast(priv->sock_bcast_rx); if (ret < 0) return ret; @@ -493,7 +493,7 @@ static int isobusfs_cli_sock_bcast_prepare(struct isobusfs_priv *priv) if (ret < 0) return ret; - return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_bcast_rx, + return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_bcast_rx, EPOLLIN); } @@ -501,7 +501,7 @@ static int isobusfs_cli_sock_prepare(struct isobusfs_priv *priv) { int ret; - ret = isobusfs_cmn_create_epoll(); + ret = libj1939_create_epoll(); if (ret < 0) return ret; @@ -647,8 +647,8 @@ int main(int argc, char *argv[]) bzero(priv, sizeof(*priv)); - isobusfs_init_sockaddr_can(&priv->sockname, J1939_NO_PGN); - isobusfs_init_sockaddr_can(&priv->peername, ISOBUSFS_PGN_CL_TO_FS); + libj1939_init_sockaddr_can(&priv->sockname, J1939_NO_PGN); + libj1939_init_sockaddr_can(&priv->peername, ISOBUSFS_PGN_CL_TO_FS); ret = isobusfs_cli_parse_args(priv, argc, argv); if (ret) diff --git a/isobusfs/isobusfs_cli.h b/isobusfs/isobusfs_cli.h index 71d375d..6689c6c 100644 --- a/isobusfs/isobusfs_cli.h +++ b/isobusfs/isobusfs_cli.h @@ -103,7 +103,7 @@ struct isobusfs_priv { struct isobusfs_buf_log tx_buf_log; enum isobusfs_cli_state state; - struct isobusfs_cmn cmn; + struct libj1939_cmn cmn; uint8_t handle; uint32_t read_offset; diff --git a/isobusfs/isobusfs_cmn.c b/isobusfs/isobusfs_cmn.c index a6c7c96..4481407 100644 --- a/isobusfs/isobusfs_cmn.c +++ b/isobusfs/isobusfs_cmn.c @@ -125,29 +125,6 @@ void isobusfs_log_level_set(log_level_t level) log_level = level; } -int isobusfs_get_timeout_ms(struct timespec *ts) -{ - struct timespec curr_time; - int64_t time_diff; - int timeout_ms; - - clock_gettime(CLOCK_MONOTONIC, &curr_time); - time_diff = timespec_diff_ms(ts, &curr_time); - if (time_diff < 0) { - /* Too late to send next message. Send it now */ - timeout_ms = 0; - } else { - if (time_diff > INT_MAX) { - warn("timeout too long: %" PRId64 " ms", time_diff); - time_diff = INT_MAX; - } - - timeout_ms = time_diff; - } - - return timeout_ms; -} - const char *isobusfs_error_to_str(enum isobusfs_error err) { switch (err) { @@ -238,15 +215,6 @@ enum isobusfs_error linux_error_to_isobusfs_error(int linux_err) } } - -void isobusfs_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn) -{ - sac->can_family = AF_CAN; - sac->can_addr.j1939.addr = J1939_NO_ADDR; - sac->can_addr.j1939.name = J1939_NO_NAME; - sac->can_addr.j1939.pgn = pgn; -} - static void isobusfs_print_timestamp(struct isobusfs_err_msg *emsg, const char *name, struct timespec *cur) { @@ -520,28 +488,6 @@ int isobusfs_send(int sock, const void *data, size_t len, return 0; } -/** - * isobusfs_cmn_open_socket - Open a CAN J1939 socket - * - * This function opens a CAN J1939 socket and returns the file descriptor - * on success. In case of an error, the function returns the negative - * error code. - */ -int isobusfs_cmn_open_socket(void) -{ - int ret; - - /* Create a new CAN J1939 socket */ - ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939); - if (ret < 0) { - /* Get the error code and print an error message */ - ret = -errno; - pr_err("socket(j1939): %d (%s)", ret, strerror(ret)); - return ret; - } - return ret; -} - /** * isobusfs_cmn_configure_socket_filter - Configure a J1939 socket filter * @sock: Socket file descriptor @@ -650,47 +596,6 @@ int isobusfs_cmn_configure_error_queue(int sock) return 0; } -/** - * isobusfs_cmn_bind_socket - Bind a J1939 socket to a given address - * @sock: socket file descriptor - * @addr: pointer to a sockaddr_can structure containing the address - * information to bind the socket to - * - * This function binds a J1939 socket to the specified address. It returns - * 0 on successful binding or a negative error code on failure. - * - * Return: 0 on success, or a negative error code on failure. - */ -int isobusfs_cmn_bind_socket(int sock, struct sockaddr_can *addr) -{ - int ret; - - ret = bind(sock, (void *)addr, sizeof(*addr)); - if (ret < 0) { - ret = -errno; - pr_err("failed to bind: %d (%s)", ret, strerror(ret)); - return ret; - } - - return 0; -} - -int isobusfs_cmn_socket_prio(int sock, int prio) -{ - int ret; - - ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, - &prio, sizeof(prio)); - if (ret < 0) { - ret = -errno; - pr_warn("Failed to set priority %i. Error %i (%s)", prio, ret, - strerror(ret)); - return ret; - } - - return 0; -} - int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr) { int ret; @@ -705,32 +610,6 @@ int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr) return 0; } -/** - * isobusfs_cmn_set_broadcast - Enable broadcast option for a socket - * @sock: socket file descriptor - * - * This function enables the SO_BROADCAST option for the given socket, - * allowing it to send and receive broadcast messages. It returns 0 on success - * or a negative error code on failure. - * - * Return: 0 on success, or a negative error code on failure. - */ -int isobusfs_cmn_set_broadcast(int sock) -{ - int broadcast = true; - int ret; - - ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, - sizeof(broadcast)); - if (ret < 0) { - ret = -errno; - pr_err("setsockopt(SO_BROADCAST): %d (%s)", ret, strerror(ret)); - return ret; - } - - return 0; -} - /* FIXME: linger is currently not supported by the kernel J1939 stack * but it would be nice to have it. Especially if we wont to stop sending * messages on a socket when the connection is lost. @@ -753,70 +632,6 @@ int isobusfs_cmn_set_linger(int sock) return 0; } -int isobusfs_cmn_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events) -{ - struct epoll_event ev = {0}; - int ret; - - ev.events = events; - ev.data.fd = sock; - - ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev); - if (ret < 0) { - ret = errno; - pr_err("epoll_ctl(EPOLL_CTL_ADD): %d (%s)", ret, strerror(ret)); - return ret; - } - - return 0; -} - -int isobusfs_cmn_create_epoll(void) -{ - int ret, epoll_fd; - - epoll_fd = epoll_create1(0); - if (epoll_fd < 0) { - ret = -errno; - pr_err("epoll_create1: %d (%s)", ret, strerror(ret)); - return ret; - } - - return epoll_fd; -} - -int isobusfs_cmn_prepare_for_events(struct isobusfs_cmn *cmn, int *nfds, - bool dont_wait) -{ - int ret, timeout_ms; - - if (dont_wait) - timeout_ms = 0; - else - timeout_ms = isobusfs_get_timeout_ms(&cmn->next_send_time); - - ret = epoll_wait(cmn->epoll_fd, cmn->epoll_events, - cmn->epoll_events_size, timeout_ms); - if (ret < 0) { - ret = -errno; - if (ret != -EINTR) { - *nfds = 0; - return ret; - } - } - - *nfds = ret; - - ret = clock_gettime(CLOCK_MONOTONIC, &cmn->last_time); - if (ret < 0) { - ret = -errno; - pr_err("failed to get time: %i (%s)", ret, strerror(ret)); - return ret; - } - - return 0; -} - void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size, size_t x) { diff --git a/isobusfs/isobusfs_cmn.h b/isobusfs/isobusfs_cmn.h index 7373ea3..23fa582 100644 --- a/isobusfs/isobusfs_cmn.h +++ b/isobusfs/isobusfs_cmn.h @@ -257,15 +257,6 @@ struct isobusfs_err_msg { struct isobusfs_stats *stats; }; -struct isobusfs_cmn { - int epoll_fd; - struct epoll_event *epoll_events; - size_t epoll_events_size; - struct timespec next_send_time; - struct timespec last_time; -}; - -void isobusfs_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn); int isobusfs_recv_err(int sock, struct isobusfs_err_msg *emsg); /* @@ -300,7 +291,6 @@ static inline uint8_t isobusfs_cg_function_to_buf(enum isobusfs_cg cg, const char *isobusfs_error_to_str(enum isobusfs_error err); enum isobusfs_error linux_error_to_isobusfs_error(int linux_err); -int isobusfs_get_timeout_ms(struct timespec *ts); void isobusfs_send_nack(int sock, struct isobusfs_msg *msg); void isobufs_store_tx_data(struct isobusfs_buf_log *buffer, uint8_t *data); void isobusfs_dump_tx_data(const struct isobusfs_buf_log *buffer); @@ -313,20 +303,11 @@ int isobusfs_send(int sock, const void *data, size_t len, void isobusfs_cmn_dump_last_x_bytes(const uint8_t *buffer, size_t buffer_size, size_t x); -int isobusfs_cmn_open_socket(void); int isobusfs_cmn_configure_socket_filter(int sock, pgn_t pgn); int isobusfs_cmn_configure_error_queue(int sock); -int isobusfs_cmn_bind_socket(int sock, struct sockaddr_can *addr); int isobusfs_cmn_connect_socket(int sock, struct sockaddr_can *addr); -int isobusfs_cmn_set_broadcast(int sock); -int isobusfs_cmn_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events); -int isobusfs_cmn_create_epoll(void); -int isobusfs_cmn_socket_prio(int sock, int prio); int isobusfs_cmn_set_linger(int sock); -int isobusfs_cmn_prepare_for_events(struct isobusfs_cmn *cmn, int *nfds, - bool dont_wait); - /* ============ directory handling ============ */ int isobusfs_cmn_dh_validate_dir_path(const char *path, bool writable); diff --git a/isobusfs/isobusfs_srv.c b/isobusfs/isobusfs_srv.c index 9429dbb..479182e 100644 --- a/isobusfs/isobusfs_srv.c +++ b/isobusfs/isobusfs_srv.c @@ -250,7 +250,7 @@ static int isobusfs_srv_process_events_and_tasks(struct isobusfs_srv_priv *priv) { int ret, nfds; - ret = isobusfs_cmn_prepare_for_events(&priv->cmn, &nfds, false); + ret = libj1939_prepare_for_events(&priv->cmn, &nfds, false); if (ret) return ret; @@ -268,7 +268,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv) struct sockaddr_can addr = priv->addr; int ret; - ret = isobusfs_cmn_open_socket(); + ret = libj1939_open_socket(); if (ret < 0) return ret; @@ -283,11 +283,11 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv) * PGN? */ addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS; - ret = isobusfs_cmn_bind_socket(priv->sock_fss, &addr); + ret = libj1939_bind_socket(priv->sock_fss, &addr); if (ret < 0) return ret; - ret = isobusfs_cmn_set_broadcast(priv->sock_fss); + ret = libj1939_set_broadcast(priv->sock_fss); if (ret < 0) return ret; @@ -295,7 +295,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv) if (ret < 0) return ret; - ret = isobusfs_cmn_socket_prio(priv->sock_fss, ISOBUSFS_PRIO_FSS); + ret = libj1939_socket_prio(priv->sock_fss, ISOBUSFS_PRIO_FSS); if (ret < 0) return ret; @@ -308,7 +308,7 @@ static int isobusfs_srv_sock_fss_prepare(struct isobusfs_srv_priv *priv) return ret; /* poll for errors to get confirmation if our packets are send */ - return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_fss, + return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_fss, EPOLLERR); } @@ -317,7 +317,7 @@ static int isobusfs_srv_sock_in_prepare(struct isobusfs_srv_priv *priv) struct sockaddr_can addr = priv->addr; int ret; - ret = isobusfs_cmn_open_socket(); + ret = libj1939_open_socket(); if (ret < 0) return ret; @@ -325,12 +325,12 @@ static int isobusfs_srv_sock_in_prepare(struct isobusfs_srv_priv *priv) /* keep address and name and overwrite PGN */ addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS; - ret = isobusfs_cmn_bind_socket(priv->sock_in, &addr); + ret = libj1939_bind_socket(priv->sock_in, &addr); if (ret < 0) return ret; - return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_in, - EPOLLIN); + return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, priv->sock_in, + EPOLLIN); } static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv) @@ -338,24 +338,24 @@ static int isobusfs_srv_sock_nack_prepare(struct isobusfs_srv_priv *priv) struct sockaddr_can addr = priv->addr; int ret; - ret = isobusfs_cmn_open_socket(); + ret = libj1939_open_socket(); if (ret < 0) return ret; priv->sock_nack = ret; addr.can_addr.j1939.pgn = ISOBUS_PGN_ACK; - ret = isobusfs_cmn_bind_socket(priv->sock_nack, &addr); + ret = libj1939_bind_socket(priv->sock_nack, &addr); if (ret < 0) return ret; - ret = isobusfs_cmn_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK); + ret = libj1939_socket_prio(priv->sock_nack, ISOBUSFS_PRIO_ACK); if (ret < 0) return ret; /* poll for errors to get confirmation if our packets are send */ - return isobusfs_cmn_add_socket_to_epoll(priv->cmn.epoll_fd, - priv->sock_nack, EPOLLIN); + return libj1939_add_socket_to_epoll(priv->cmn.epoll_fd, + priv->sock_nack, EPOLLIN); } /** @@ -370,7 +370,7 @@ static int isobusfs_srv_sock_prepare(struct isobusfs_srv_priv *priv) { int ret; - ret = isobusfs_cmn_create_epoll(); + ret = libj1939_create_epoll(); if (ret < 0) return ret; @@ -762,7 +762,7 @@ int main(int argc, char *argv[]) memset(priv, 0, sizeof(*priv)); /* Initialize sockaddr_can with a non-configurable PGN */ - isobusfs_init_sockaddr_can(&priv->addr, J1939_NO_PGN); + libj1939_init_sockaddr_can(&priv->addr, J1939_NO_PGN); priv->server_version = ISOBUSFS_SRV_VERSION; /* Parse command line arguments */ diff --git a/isobusfs/isobusfs_srv.h b/isobusfs/isobusfs_srv.h index 7389afb..557348e 100644 --- a/isobusfs/isobusfs_srv.h +++ b/isobusfs/isobusfs_srv.h @@ -103,7 +103,7 @@ struct isobusfs_srv_priv { int clients_count; struct isobusfs_buf_log tx_buf_log; - struct isobusfs_cmn cmn; + struct libj1939_cmn cmn; struct isobusfs_srv_volume volumes[ISOBUSFS_SRV_MAX_VOLUMES]; int volume_count; diff --git a/isobusfs/isobusfs_srv_cm.c b/isobusfs/isobusfs_srv_cm.c index 9a9fac8..b5b8d1e 100644 --- a/isobusfs/isobusfs_srv_cm.c +++ b/isobusfs/isobusfs_srv_cm.c @@ -213,14 +213,14 @@ static int isobusfs_srv_init_client(struct isobusfs_srv_priv *priv, return -EINVAL; } - ret = isobusfs_cmn_open_socket(); + ret = libj1939_open_socket(); if (ret < 0) return ret; client->sock = ret; addr.can_addr.j1939.pgn = ISOBUSFS_PGN_CL_TO_FS; - ret = isobusfs_cmn_bind_socket(client->sock, &addr); + ret = libj1939_bind_socket(client->sock, &addr); if (ret < 0) return ret; @@ -243,7 +243,7 @@ static int isobusfs_srv_init_client(struct isobusfs_srv_priv *priv, goto close_socket; } - ret = isobusfs_cmn_socket_prio(client->sock, ISOBUSFS_PRIO_DEFAULT); + ret = libj1939_socket_prio(client->sock, ISOBUSFS_PRIO_DEFAULT); if (ret < 0) return ret; diff --git a/j1939cat.c b/j1939cat.c index 50fe5da..23715ea 100644 --- a/j1939cat.c +++ b/j1939cat.c @@ -97,15 +97,6 @@ static const char help_msg[] = static const char optstring[] = "?hi:vs:rp:P:R:B"; - -static void j1939cat_init_sockaddr_can(struct sockaddr_can *sac) -{ - sac->can_family = AF_CAN; - sac->can_addr.j1939.addr = J1939_NO_ADDR; - sac->can_addr.j1939.name = J1939_NO_NAME; - sac->can_addr.j1939.pgn = J1939_NO_PGN; -} - static ssize_t j1939cat_send_one(struct j1939cat_priv *priv, int out_fd, const void *buf, size_t buf_size) { @@ -766,8 +757,8 @@ int main(int argc, char *argv[]) priv->polltimeout = 100000; priv->repeat = 1; - j1939cat_init_sockaddr_can(&priv->sockname); - j1939cat_init_sockaddr_can(&priv->peername); + libj1939_init_sockaddr_can(&priv->sockname, J1939_NO_PGN); + libj1939_init_sockaddr_can(&priv->peername, J1939_NO_PGN); ret = j1939cat_parse_args(priv, argc, argv); if (ret) diff --git a/libj1939.c b/libj1939.c index 506b525..ed9a554 100644 --- a/libj1939.c +++ b/libj1939.c @@ -11,19 +11,24 @@ */ #include +#include +#include #include +#include +#include +#include +#include #include #include #include - -#include -#include +#include #include +#include +#include #include -#include - #include "libj1939.h" +#include "lib.h" /* static data */ static struct if_nameindex *saved; @@ -195,3 +200,232 @@ const char *libj1939_addr2str(const struct sockaddr_can *can) return buf; } +void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn) +{ + sac->can_family = AF_CAN; + sac->can_addr.j1939.addr = J1939_NO_ADDR; + sac->can_addr.j1939.name = J1939_NO_NAME; + sac->can_addr.j1939.pgn = pgn; +} + +/** + * libj1939_open_socket - Open a new J1939 socket + * + * This function opens a new J1939 socket. + * + * Return: The file descriptor of the new socket, or a negative error code. + */ +int libj1939_open_socket(void) +{ + int ret; + + /* Create a new CAN J1939 socket */ + ret = socket(PF_CAN, SOCK_DGRAM, CAN_J1939); + if (ret < 0) { + /* Get the error code and print an error message */ + ret = -errno; + pr_err("socket(j1939): %d (%s)", ret, strerror(ret)); + return ret; + } + return ret; +} + +/** + * libj1939_bind_socket - Bind a J1939 socket to a specific address + * @sock: The file descriptor of the socket + * @addr: The address to bind to + * + * This function binds a J1939 socket to a specific address. + * + * Return: 0 on success, or a negative error code. + */ +int libj1939_bind_socket(int sock, struct sockaddr_can *addr) +{ + int ret; + + ret = bind(sock, (void *)addr, sizeof(*addr)); + if (ret < 0) { + ret = -errno; + pr_err("failed to bind: %d (%s)", ret, strerror(ret)); + return ret; + } + + return 0; +} + +/** + * libj1939_socket_prio - Set the priority of a J1939 socket + * @sock: The file descriptor of the socket + * @prio: The priority to set + * + * This function sets the priority of a J1939 socket. + * + * Return: 0 on success, or a negative error code. + */ +int libj1939_socket_prio(int sock, int prio) +{ + int ret; + + ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, + &prio, sizeof(prio)); + if (ret < 0) { + ret = -errno; + pr_warn("Failed to set priority %i. Error %i (%s)", prio, ret, + strerror(ret)); + return ret; + } + + return 0; +} + +/** + * libj1939_set_broadcast - Enable broadcast on a J1939 socket + * @sock: The file descriptor of the socket + * + * This function enables broadcast on a J1939 socket. + * + * Return: 0 on success, or a negative error code. + */ +int libj1939_set_broadcast(int sock) +{ + int broadcast = true; + int ret; + + ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, + sizeof(broadcast)); + if (ret < 0) { + ret = -errno; + pr_err("setsockopt(SO_BROADCAST): %d (%s)", ret, strerror(ret)); + return ret; + } + + return 0; +} + +/** + * libj1939_add_socket_to_epoll - Add a socket to an epoll instance + * @epoll_fd: The file descriptor of the epoll instance + * @sock: The file descriptor of the socket + * @events: The events to monitor + * + * This function adds a socket to an epoll instance. + * + * Return: 0 on success, or a negative error code. + */ +int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events) +{ + struct epoll_event ev = {0}; + int ret; + + ev.events = events; + ev.data.fd = sock; + + ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev); + if (ret < 0) { + ret = errno; + pr_err("epoll_ctl(EPOLL_CTL_ADD): %d (%s)", ret, strerror(ret)); + return ret; + } + + return 0; +} + +/** + * libj1939_create_epoll - Create a new epoll instance + * + * This function creates a new epoll instance. + * + * Return: The file descriptor of the new epoll instance, or a negative error + * code. + */ +int libj1939_create_epoll(void) +{ + int ret, epoll_fd; + + epoll_fd = epoll_create1(0); + if (epoll_fd < 0) { + ret = -errno; + pr_err("epoll_create1: %d (%s)", ret, strerror(ret)); + return ret; + } + + return epoll_fd; +} + +/** + * libj1939_get_timeout_ms - Get the timeout in milliseconds until a specific + * time + * @ts: The time to wait for + * @return: The timeout in milliseconds until the specified time + * + * This function calculates the timeout in milliseconds until a specific time. + * + * Return: The timeout in milliseconds until the specified time. + */ +static int libj1939_get_timeout_ms(struct timespec *ts) +{ + struct timespec curr_time; + int64_t time_diff; + int timeout_ms; + + clock_gettime(CLOCK_MONOTONIC, &curr_time); + time_diff = timespec_diff_ms(ts, &curr_time); + if (time_diff < 0) { + /* Too late to send next message. Send it now */ + timeout_ms = 0; + } else { + if (time_diff > INT_MAX) { + pr_warn("timeout too long: %" PRId64 " ms", time_diff); + time_diff = INT_MAX; + } + + timeout_ms = time_diff; + } + + return timeout_ms; +} + +/** + * libj1939_prepare_for_events - Prepare and wait for events on an epoll + * @cmn: The common J1939 instance data + * @nfds: The number of file descriptors that are ready + * @dont_wait: Don't wait for events, just check if there are any + * + * This function calculates the timeout until the next message should be sent + * or any other event should be handled, prepares the epoll instance for events + * by waiting for the specified timeout or until an event occurs, and waits for + * events on the epoll instance. + * + * Return: 0 on success, or a negative error code. + */ +int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds, + bool dont_wait) +{ + int ret, timeout_ms; + + if (dont_wait) + timeout_ms = 0; + else + timeout_ms = libj1939_get_timeout_ms(&cmn->next_send_time); + + ret = epoll_wait(cmn->epoll_fd, cmn->epoll_events, + cmn->epoll_events_size, timeout_ms); + if (ret < 0) { + ret = -errno; + if (ret != -EINTR) { + *nfds = 0; + return ret; + } + } + + *nfds = ret; + + ret = clock_gettime(CLOCK_MONOTONIC, &cmn->last_time); + if (ret < 0) { + ret = -errno; + pr_err("failed to get time: %i (%s)", ret, strerror(ret)); + return ret; + } + + return 0; +} diff --git a/libj1939.h b/libj1939.h index b6832cf..44393a2 100644 --- a/libj1939.h +++ b/libj1939.h @@ -13,9 +13,11 @@ /* needed on some 64 bit platforms to get consistent 64-bit types */ #define __SANE_USERSPACE_TYPES__ -#include #include #include +#include +#include +#include #ifndef J1939_LIB_H #define J1939_LIB_H @@ -24,10 +26,30 @@ extern "C" { #endif +struct libj1939_cmn { + int epoll_fd; + struct epoll_event *epoll_events; + size_t epoll_events_size; + struct timespec next_send_time; + struct timespec last_time; +}; + void libj1939_parse_canaddr(char *spec, struct sockaddr_can *paddr); extern int libj1939_str2addr(const char *str, char **endp, struct sockaddr_can *can); extern const char *libj1939_addr2str(const struct sockaddr_can *can); +void libj1939_init_sockaddr_can(struct sockaddr_can *sac, uint32_t pgn); + +int libj1939_open_socket(void); +int libj1939_bind_socket(int sock, struct sockaddr_can *addr); +int libj1939_socket_prio(int sock, int prio); +int libj1939_set_broadcast(int sock); +int libj1939_add_socket_to_epoll(int epoll_fd, int sock, uint32_t events); +int libj1939_create_epoll(void); + +int libj1939_prepare_for_events(struct libj1939_cmn *cmn, int *nfds, + bool dont_wait); + #ifdef __cplusplus } #endif