diff options
author | Zahari Doychev <zahari.doychev@linux.com> | 2014-05-09 14:44:40 +0200 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2014-05-12 18:15:34 +0200 |
commit | 8a3ee94b84ffd1fb75dd8195e74afe89f7e16b2a (patch) | |
tree | 9a579cf4978e40c0f28bb70db0bd9575dd0de8d1 | |
parent | 5bdafcbc862ea8809cd4c086ed9a5875a30e27ae (diff) | |
download | canutils-8a3ee94b84ffd1fb75dd8195e74afe89f7e16b2a.tar.gz canutils-8a3ee94b84ffd1fb75dd8195e74afe89f7e16b2a.tar.xz |
cansend: add handling of ENOBUFS when sending
This patch fixes the "No buffer space available" error when sending in a loop
and using small tx queue length.
Signed-off-by: Zahari Doychev <zahari.doychev@linux.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r-- | src/cansend.c | 48 |
1 files changed, 40 insertions, 8 deletions
diff --git a/src/cansend.c b/src/cansend.c index 97c4320..7126acf 100644 --- a/src/cansend.c +++ b/src/cansend.c @@ -1,13 +1,14 @@ #include <can_config.h> +#include <errno.h> #include <getopt.h> #include <libgen.h> +#include <limits.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <limits.h> #include <net/if.h> @@ -15,6 +16,7 @@ #include <sys/socket.h> #include <sys/types.h> #include <sys/uio.h> +#include <poll.h> #include <linux/can.h> #include <linux/can/raw.h> @@ -32,6 +34,7 @@ static void print_usage(char *prg) " -e --extended send extended frame\n" " -l send message infinite times\n" " --loop=COUNT send message COUNT times\n" + " -p --poll use poll(2) to wait for buffer space while sending\n" " -v, --verbose be verbose\n" " -h, --help this help\n" " --version print version information and exit\n", @@ -53,10 +56,13 @@ int main(int argc, char **argv) int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW; int loopcount = 1, infinite = 0; int s, opt, ret, i, dlc = 0, rtr = 0, extended = 0; + ssize_t len; + int use_poll = 0; int verbose = 0; struct option long_options[] = { { "help", no_argument, 0, 'h' }, + { "poll", no_argument, 0, 'p'}, { "identifier", required_argument, 0, 'i' }, { "rtr", no_argument, 0, 'r' }, { "extended", no_argument, 0, 'e' }, @@ -66,12 +72,16 @@ int main(int argc, char **argv) { 0, 0, 0, 0 }, }; - while ((opt = getopt_long(argc, argv, "hvi:lre", long_options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "hpvi:lre", long_options, NULL)) != -1) { switch (opt) { case 'h': print_usage(basename(argv[0])); exit(0); + case 'p': + use_poll = 1; + break; + case 'v': verbose = 1; break; @@ -97,7 +107,6 @@ int main(int argc, char **argv) case VERSION_OPTION: printf("cansend %s\n", VERSION); exit(0); - default: fprintf(stderr, "Unknown option %c\n", opt); break; @@ -108,7 +117,7 @@ int main(int argc, char **argv) print_usage(basename(argv[0])); exit(0); } - + if (argv[optind] == NULL) { fprintf(stderr, "No Interface supplied\n"); exit(-1); @@ -165,10 +174,33 @@ int main(int argc, char **argv) } while (infinite || loopcount--) { - ret = write(s, &frame, sizeof(frame)); - if (ret == -1) { - perror("write"); - break; + again: + len = write(s, &frame, sizeof(frame)); + if (len == -1) { + switch (errno) { + case ENOBUFS: { + struct pollfd fds = { + .fd = s, + .events = POLLOUT, + }; + + if (!use_poll) { + perror("write"); + exit(EXIT_FAILURE); + } + + ret = poll(&fds, 1, 1000); + if (ret == -1 && errno != -EINTR) { + perror("poll()"); + exit(EXIT_FAILURE); + } + } + case EINTR: /* fallthrough */ + goto again; + default: + perror("write"); + exit(EXIT_FAILURE); + } } } |