From 235fa050403c7335fb2287a280dc6ea8d2d7183b Mon Sep 17 00:00:00 2001 From: Thomas Osterried Date: Mon, 24 Aug 2009 21:13:18 +0000 Subject: fix: on read through closed pipe, call did endless select(), read() = 0, wht consumed 100% CPU power. New options: -W: waits after EOF on stdin. Useful for scripting, for waiting for data coming via fd 3 (ax25 connection) -T secs: idle timout after secs seconds. --- call/call.1 | 8 ++++++- call/call.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 66 insertions(+), 17 deletions(-) (limited to 'call') diff --git a/call/call.1 b/call/call.1 index a10465b..2786975 100644 --- a/call/call.1 +++ b/call/call.1 @@ -4,7 +4,7 @@ call \- make an AX.25, NET/ROM or Rose connection. .SH SYNOPSIS For AX.25 .br -.B call [-b l|e] [-d] [-h] [-m s|e] [-p paclen] [-s mycall] [-r] [-t] [-v] [-w window] port callsign [[via] digipeaters.....] +.B call [-b l|e] [-d] [-h] [-m s|e] [-p paclen] [-s mycall] [-r] [-t] [-T timeout] [-v] [-w window] [-W] port callsign [[via] digipeaters.....] .sp 1 For NET/ROM .br @@ -74,6 +74,9 @@ Connect using the specified source call (you may need to be root). .BI \-S Be silent. Useful for using call in shellscripts (together with option \-r) in order to be really transparent. .TP 10 +.BI "\-T timeout" +Set idle timeout seconds after a connection will be closed automaticaly when there's no data being transferred (in- and outbound). If timeout is set to 3600, the connection will close after 1h inactivity. A value of 0.5 is 500ms. +.TP 10 .BI \-r Selects Raw mode. .TP 10 @@ -85,6 +88,9 @@ Display the version. .TP 10 .BI "\-w window" Specify a specific AX.25 window for this connection. Only valid in AX.25 mode. +.TP 10 +.BI "\-W" +Wait for remote disconnect even if stdin is closed. Normaly, "echo q | call ax0 db0fhn" closes immediately after "echo q" terminates; thus we never see the greeting from db0fhn. With the -W option, call waits until the ax25-connection is disconnected (i.e. db0fhn disconnects after "q" command). Very useful for scripting. You might like to combine it with the -T option. .LP The call program interprets lines beginning with a '~' specially. The following '~' escapes are available. diff --git a/call/call.c b/call/call.c index db76545..7b3aa03 100644 --- a/call/call.c +++ b/call/call.c @@ -83,6 +83,10 @@ int interrupted = FALSE; int paclen = 0; int fd; +int wait_for_remote_disconnect = FALSE; +static struct timeval inactivity_timeout; +int inactivity_timeout_is_set = FALSE; + #define GP_FILENAME_SIZE 255 typedef struct { char file_name[GP_FILENAME_SIZE]; @@ -109,7 +113,7 @@ typedef struct { void usage(void) { - fprintf(stderr, "usage: call [-b l|e] [-d] [-h] [-m s|e] [-p paclen] [-r] [-s mycall] [-t] [-v] [-w window] port callsign [[via] digipeaters...]\n"); + fprintf(stderr, "usage: call [-b l|e] [-d] [-h] [-m s|e] [-p paclen] [-r] [-s mycall] [-t] [-T timeout] [-v] [-w window] [-W] port callsign [[via] digipeaters...]\n"); exit(1); } @@ -1537,6 +1541,7 @@ int cmd_call(char *call[], int mode) int crc = 0; char s[80]; int flags = 0; + int EOF_on_STDIN = FALSE; init_crc(); @@ -1575,29 +1580,43 @@ int cmd_call(char *call[], int mode) while (TRUE) { struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 10; - + if (inactivity_timeout_is_set == TRUE && uploadfile == -1 && downloadfile == -1) { + tv.tv_sec = inactivity_timeout.tv_sec; + tv.tv_usec = inactivity_timeout.tv_usec; + } else { + tv.tv_sec = 0; + tv.tv_usec = 10; + } FD_ZERO(&sock_read); - FD_SET(STDIN_FILENO, &sock_read); + if (EOF_on_STDIN == FALSE) + FD_SET(STDIN_FILENO, &sock_read); FD_SET(fd, &sock_read); FD_ZERO(&sock_write); if (uploadfile != -1) FD_SET(fd, &sock_write); - if (select(fd + 1, &sock_read, &sock_write, NULL, (uploadfile == -1 && downloadfile == -1) ? NULL : &tv) == -1) { - if (!interrupted && errno == EAGAIN) + if (select(fd + 1, &sock_read, &sock_write, NULL, (uploadfile == -1 && downloadfile == -1 && inactivity_timeout_is_set == FALSE) ? NULL : &tv) == -1) { + if (!interrupted && errno == EAGAIN) { + usleep(100000); continue; + } if (!interrupted) perror("select"); break; } + if (inactivity_timeout_is_set == TRUE && !FD_ISSET(fd, &sock_read) && !FD_ISSET(STDIN_FILENO, &sock_read)) { + if (!be_silent) { + printf("*** Inactivity timeout reached. Terminating..\n"); + fflush(stdout); + } + break; + } if (FD_ISSET(fd, &sock_read)) { /* bytes = read(fd, buf, 511); */ bytes = read(fd, buf, sizeof(buf)); if (bytes == 0) { - /* read EOF on stdin */ + /* read EOF on connection */ /* cause program to terminate */ flags &= ~FLAG_RECONNECT; break; @@ -2053,14 +2072,22 @@ int cmd_call(char *call[], int mode) } /* if (bytes == -1 && errno != EWOULDBLOCK && errno != EAGAIN) */ /* if ((bytes == 0 && (mode & (TALKMODE|SLAVEMODE)) == 0) || (bytes == -1 && errno != EWOULDBLOCK && errno != EAGAIN)) */ - if (interrupted - || (bytes == -1 && errno != EWOULDBLOCK - && errno != EAGAIN)) { - if (!interrupted) - perror("input"); + + if (interrupted) break; - } - if (bytes > 0) { + if (bytes == -1) { + if (errno != EWOULDBLOCK && errno != EAGAIN) { + perror("input"); + EOF_on_STDIN = TRUE; + } + usleep(100); + } else if (bytes == 0) { + /* select() indicated that there is data to + * read, but read() returned 0 bytes. + * -> terminate normaly + */ + EOF_on_STDIN = TRUE; + } else if (bytes > 0) { unsigned long offset = 0L; int err = 0; @@ -2089,6 +2116,8 @@ int cmd_call(char *call[], int mode) if (err) break; } + if (EOF_on_STDIN == TRUE && wait_for_remote_disconnect == FALSE) + break; } if (uploadfile != -1) { if (uplsize == 0) { @@ -2203,7 +2232,7 @@ int main(int argc, char **argv) setlinebuf(stdin); - while ((p = getopt(argc, argv, "b:dhm:p:rs:Stvw:")) != -1) { + while ((p = getopt(argc, argv, "b:dhm:p:rs:StT:vw:W")) != -1) { switch (p) { case 'b': if (*optarg != 'e' && *optarg != 'l') { @@ -2248,6 +2277,17 @@ int main(int argc, char **argv) case 'S': be_silent = 1; break; + case 'T': + { double f = atof(optarg); + inactivity_timeout.tv_sec = ((time_t) f) & 0x7fffffff; + inactivity_timeout.tv_usec = (time_t ) (f - (double ) (time_t ) f); + if (f < 0.001 || f > (double) (0x7fffffff) || (inactivity_timeout.tv_sec == 0 && inactivity_timeout.tv_usec == 0)) { + fprintf(stderr, "call: option '-T' must be > 0.001 (1ms) and < 69 years\n"); + return 1; + } + inactivity_timeout_is_set = TRUE; + } + break; case 't': mode = TALKMODE; break; @@ -2274,6 +2314,9 @@ int main(int argc, char **argv) } } break; + case 'W': + wait_for_remote_disconnect = TRUE; + break; case '?': case ':': usage(); -- cgit v1.2.3