123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- /*
- * Copyright (c) 2011 EIA Electronics
- *
- * Authors:
- * Kurt Van Dijck <kurt.van.dijck@eia.be>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the version 2 of the GNU General Public License
- * as published by the Free Software Foundation
- */
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <inttypes.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <error.h>
- #include <poll.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/stat.h>
- #include "libj1939.h"
- /*
- * getopt
- */
- static const char help_msg[] =
- "jsr: An SAE J1939 send/recv utility" "\n"
- "Usage: jsr [OPTION...] SOURCE [DEST]" "\n"
- "\n"
- " -v, --verbose Increase verbosity" "\n"
- " -p, --priority=VAL J1939 priority (0..7, default 6)" "\n"
- " -S, --serialize Strictly serialize outgoing packets" "\n"
- " -s, --size Packet size, default autodetected" "\n"
- "\n"
- " SOURCE [IFACE:][NAME|SA][,PGN]" "\n"
- " DEST [NAME|SA]" "\n"
- ;
- #ifdef _GNU_SOURCE
- static struct option long_opts[] = {
- { "help", no_argument, NULL, '?', },
- { "verbose", no_argument, NULL, 'v', },
- { "priority", required_argument, NULL, 'p', },
- { "size", required_argument, NULL, 's', },
- { "serialize", no_argument, NULL, 'S', },
- { },
- };
- #else
- #define getopt_long(argc, argv, optstring, longopts, longindex) \
- getopt((argc), (argv), (optstring))
- #endif
- static const char optstring[] = "vp:s:S?";
- /*
- * static variables: configurations
- */
- static struct {
- int verbose;
- int sendflags; /* flags for sendto() */
- int pkt_len;
- int priority;
- int defined;
- #define DEF_SRC 1
- #define DEF_DST 2
- #define DEF_PRIO 4
- struct sockaddr_can src, dst;
- } s = {
- .priority = 6,
- .src.can_addr.j1939 = {
- .name = J1939_NO_NAME,
- .addr = J1939_NO_ADDR,
- .pgn = J1939_NO_PGN,
- },
- .dst.can_addr.j1939 = {
- .name = J1939_NO_NAME,
- .addr = J1939_NO_ADDR,
- .pgn = J1939_NO_PGN,
- },
- };
- int main(int argc, char **argv)
- {
- int ret, sock, opt;
- unsigned int len;
- struct pollfd pfd[2];
- uint8_t *buf;
- #ifdef _GNU_SOURCE
- program_invocation_name = program_invocation_short_name;
- #endif
- /* argument parsing */
- while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
- switch (opt) {
- case 'v':
- ++s.verbose;
- break;
- case 's':
- s.pkt_len = strtoul(optarg, 0, 0);
- if (!s.pkt_len)
- error(1, EINVAL, "packet size of %s", optarg);
- break;
- case 'p':
- s.priority = strtoul(optarg, 0, 0);
- s.defined |= DEF_PRIO;
- break;
- case 'S':
- s.sendflags |= MSG_SYN;
- break;
- default:
- fputs(help_msg, stderr);
- exit(1);
- break;
- }
- if (argv[optind]) {
- optarg = argv[optind++];
- ret = libj1939_str2addr(optarg, 0, &s.src);
- if (ret < 0)
- error(1, 0, "bad address spec [%s]", optarg);
- s.defined |= DEF_SRC;
- }
- if (argv[optind]) {
- optarg = argv[optind++];
- ret = libj1939_str2addr(optarg, 0, &s.dst);
- if (ret < 0)
- error(1, 0, "bad address spec [%s]", optarg);
- s.defined |= DEF_DST;
- }
- if (!s.pkt_len) {
- struct stat st;
- if (fstat(STDIN_FILENO, &st) < 0)
- error(1, errno, "stat stdin, could not determine buffer size");
- s.pkt_len = st.st_size ?: 1024;
- }
- /* prepare */
- buf = malloc(s.pkt_len);
- if (!buf)
- error(1, errno, "malloc %u", s.pkt_len);
- sock = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
- if (sock < 0)
- error(1, errno, "socket(can, dgram, j1939)");
- if (s.defined & DEF_PRIO) {
- ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &s.priority, sizeof(s.priority));
- if (ret < 0)
- error(1, errno, "setsockopt priority");
- }
- if (s.defined & DEF_SRC) {
- s.src.can_family = AF_CAN;
- ret = bind(sock, (void *)&s.src, sizeof(s.src));
- if (ret < 0)
- error(1, errno, "bind(%s), %i", libj1939_addr2str(&s.src), -errno);
- }
- if (s.defined & DEF_DST) {
- s.dst.can_family = AF_CAN;
- ret = connect(sock, (void *)&s.dst, sizeof(s.dst));
- if (ret < 0)
- error(1, errno, "connect(%s), %i", libj1939_addr2str(&s.dst), -errno);
- }
- pfd[0].fd = STDIN_FILENO;
- pfd[0].events = POLLIN;
- pfd[1].fd = sock;
- pfd[1].events = POLLIN;
- /* run */
- while (1) {
- ret = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), -1);
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- error(1, errno, "poll()");
- }
- if (pfd[0].revents) {
- ret = read(pfd[0].fd, buf, s.pkt_len);
- if (ret < 0)
- error(1, errno, "read(stdin)");
- if (!ret)
- break;
- len = ret;
- do {
- ret = send(pfd[1].fd, buf, len, s.sendflags);
- if (ret < 0)
- error(errno != ENOBUFS, errno, "write(%s)",
- libj1939_addr2str(&s.src));
- } while (ret < 0);
- }
- if (pfd[1].revents) {
- ret = read(pfd[1].fd, buf, s.pkt_len);
- if (ret < 0) {
- ret = errno;
- error(0, errno, "read(%s)", libj1939_addr2str(&s.dst));
- switch (ret) {
- case EHOSTDOWN:
- break;
- default:
- exit(1);
- }
- } else {
- write(STDOUT_FILENO, buf, ret);
- }
- }
- }
- free(buf);
- return 0;
- }
|