jsr.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Copyright (c) 2011 EIA Electronics
  3. *
  4. * Authors:
  5. * Kurt Van Dijck <kurt.van.dijck@eia.be>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the version 2 of the GNU General Public License
  9. * as published by the Free Software Foundation
  10. */
  11. #include <string.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <errno.h>
  15. #include <inttypes.h>
  16. #include <unistd.h>
  17. #include <getopt.h>
  18. #include <error.h>
  19. #include <poll.h>
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <sys/ioctl.h>
  23. #include <sys/stat.h>
  24. #include "libj1939.h"
  25. /*
  26. * getopt
  27. */
  28. static const char help_msg[] =
  29. "jsr: An SAE J1939 send/recv utility" "\n"
  30. "Usage: jsr [OPTION...] SOURCE [DEST]" "\n"
  31. "\n"
  32. " -v, --verbose Increase verbosity" "\n"
  33. " -p, --priority=VAL J1939 priority (0..7, default 6)" "\n"
  34. " -S, --serialize Strictly serialize outgoing packets" "\n"
  35. " -s, --size Packet size, default autodetected" "\n"
  36. "\n"
  37. " SOURCE [IFACE:][NAME|SA][,PGN]" "\n"
  38. " DEST [NAME|SA]" "\n"
  39. ;
  40. #ifdef _GNU_SOURCE
  41. static struct option long_opts[] = {
  42. { "help", no_argument, NULL, '?', },
  43. { "verbose", no_argument, NULL, 'v', },
  44. { "priority", required_argument, NULL, 'p', },
  45. { "size", required_argument, NULL, 's', },
  46. { "serialize", no_argument, NULL, 'S', },
  47. { },
  48. };
  49. #else
  50. #define getopt_long(argc, argv, optstring, longopts, longindex) \
  51. getopt((argc), (argv), (optstring))
  52. #endif
  53. static const char optstring[] = "vp:s:S?";
  54. /*
  55. * static variables: configurations
  56. */
  57. static struct {
  58. int verbose;
  59. int sendflags; /* flags for sendto() */
  60. int pkt_len;
  61. int priority;
  62. int defined;
  63. #define DEF_SRC 1
  64. #define DEF_DST 2
  65. #define DEF_PRIO 4
  66. struct sockaddr_can src, dst;
  67. } s = {
  68. .priority = 6,
  69. .src.can_addr.j1939 = {
  70. .name = J1939_NO_NAME,
  71. .addr = J1939_NO_ADDR,
  72. .pgn = J1939_NO_PGN,
  73. },
  74. .dst.can_addr.j1939 = {
  75. .name = J1939_NO_NAME,
  76. .addr = J1939_NO_ADDR,
  77. .pgn = J1939_NO_PGN,
  78. },
  79. };
  80. int main(int argc, char **argv)
  81. {
  82. int ret, sock, opt;
  83. unsigned int len;
  84. struct pollfd pfd[2];
  85. uint8_t *buf;
  86. #ifdef _GNU_SOURCE
  87. program_invocation_name = program_invocation_short_name;
  88. #endif
  89. /* argument parsing */
  90. while ((opt = getopt_long(argc, argv, optstring, long_opts, NULL)) != -1)
  91. switch (opt) {
  92. case 'v':
  93. ++s.verbose;
  94. break;
  95. case 's':
  96. s.pkt_len = strtoul(optarg, 0, 0);
  97. if (!s.pkt_len)
  98. error(1, EINVAL, "packet size of %s", optarg);
  99. break;
  100. case 'p':
  101. s.priority = strtoul(optarg, 0, 0);
  102. s.defined |= DEF_PRIO;
  103. break;
  104. case 'S':
  105. s.sendflags |= MSG_SYN;
  106. break;
  107. default:
  108. fputs(help_msg, stderr);
  109. exit(1);
  110. break;
  111. }
  112. if (argv[optind]) {
  113. optarg = argv[optind++];
  114. ret = libj1939_str2addr(optarg, 0, &s.src);
  115. if (ret < 0)
  116. error(1, 0, "bad address spec [%s]", optarg);
  117. s.defined |= DEF_SRC;
  118. }
  119. if (argv[optind]) {
  120. optarg = argv[optind++];
  121. ret = libj1939_str2addr(optarg, 0, &s.dst);
  122. if (ret < 0)
  123. error(1, 0, "bad address spec [%s]", optarg);
  124. s.defined |= DEF_DST;
  125. }
  126. if (!s.pkt_len) {
  127. struct stat st;
  128. if (fstat(STDIN_FILENO, &st) < 0)
  129. error(1, errno, "stat stdin, could not determine buffer size");
  130. s.pkt_len = st.st_size ?: 1024;
  131. }
  132. /* prepare */
  133. buf = malloc(s.pkt_len);
  134. if (!buf)
  135. error(1, errno, "malloc %u", s.pkt_len);
  136. sock = socket(PF_CAN, SOCK_DGRAM, CAN_J1939);
  137. if (sock < 0)
  138. error(1, errno, "socket(can, dgram, j1939)");
  139. if (s.defined & DEF_PRIO) {
  140. ret = setsockopt(sock, SOL_CAN_J1939, SO_J1939_SEND_PRIO, &s.priority, sizeof(s.priority));
  141. if (ret < 0)
  142. error(1, errno, "setsockopt priority");
  143. }
  144. if (s.defined & DEF_SRC) {
  145. s.src.can_family = AF_CAN;
  146. ret = bind(sock, (void *)&s.src, sizeof(s.src));
  147. if (ret < 0)
  148. error(1, errno, "bind(%s), %i", libj1939_addr2str(&s.src), -errno);
  149. }
  150. if (s.defined & DEF_DST) {
  151. s.dst.can_family = AF_CAN;
  152. ret = connect(sock, (void *)&s.dst, sizeof(s.dst));
  153. if (ret < 0)
  154. error(1, errno, "connect(%s), %i", libj1939_addr2str(&s.dst), -errno);
  155. }
  156. pfd[0].fd = STDIN_FILENO;
  157. pfd[0].events = POLLIN;
  158. pfd[1].fd = sock;
  159. pfd[1].events = POLLIN;
  160. /* run */
  161. while (1) {
  162. ret = poll(pfd, sizeof(pfd)/sizeof(pfd[0]), -1);
  163. if (ret < 0) {
  164. if (errno == EINTR)
  165. continue;
  166. error(1, errno, "poll()");
  167. }
  168. if (pfd[0].revents) {
  169. ret = read(pfd[0].fd, buf, s.pkt_len);
  170. if (ret < 0)
  171. error(1, errno, "read(stdin)");
  172. if (!ret)
  173. break;
  174. len = ret;
  175. do {
  176. ret = send(pfd[1].fd, buf, len, s.sendflags);
  177. if (ret < 0)
  178. error(errno != ENOBUFS, errno, "write(%s)",
  179. libj1939_addr2str(&s.src));
  180. } while (ret < 0);
  181. }
  182. if (pfd[1].revents) {
  183. ret = read(pfd[1].fd, buf, s.pkt_len);
  184. if (ret < 0) {
  185. ret = errno;
  186. error(0, errno, "read(%s)", libj1939_addr2str(&s.dst));
  187. switch (ret) {
  188. case EHOSTDOWN:
  189. break;
  190. default:
  191. exit(1);
  192. }
  193. } else {
  194. write(STDOUT_FILENO, buf, ret);
  195. }
  196. }
  197. }
  198. free(buf);
  199. return 0;
  200. }