OpenSSH
[Top] [All Lists]

Local software flow control

To: openssh-unix-dev@mindrot.org
Subject: Local software flow control
From: "Grigoriy A. Sitkarev" <sitkarev@komitex.ru>
Date: Sat, 09 Dec 2006 23:17:43 +0000
Delivered-to: sp-com-lists@consult.net
Delivered-to: openssh-unix-dev-list1@securepoint.com
Delivered-to: openssh-unix-dev-tmda@mindrot.org
Delivered-to: openssh-unix-dev@mindrot.org
List-archive: <http://lists.mindrot.org/pipermail/openssh-unix-dev>
List-help: <mailto:openssh-unix-dev-request@mindrot.org?subject=help>
List-id: Development of portable OpenSSH <openssh-unix-dev.mindrot.org>
List-post: <mailto:openssh-unix-dev@mindrot.org>
List-subscribe: <http://lists.mindrot.org/mailman/listinfo/openssh-unix-dev>, <mailto:openssh-unix-dev-request@mindrot.org?subject=subscribe>
List-unsubscribe: <http://lists.mindrot.org/mailman/listinfo/openssh-unix-dev>, <mailto:openssh-unix-dev-request@mindrot.org?subject=unsubscribe>
Sender: openssh-unix-dev-bounces+openssh-unix-dev-list1=securepoint.com@mindrot.org
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.6) Gecko/20040621
Good day time!

Using openssh with a serial attached terminal figures with a problem with flow control when serial terminal has printer connected to it etc. because ssh disables xon/xoff on associated terminal. At present ssh client always disables xon/xoff on associated terminal device, regarding of it's previous state, e.g. ixon and ixoff options were set or not.

By searching the google i've found some posts where people complained about sshing somewhere and getting disabled xon/xoff on their devices and thus they had to use rlogin because it handles local flow control correctly for them. An easy and quick/dirty method was to remove IXON & IXOFF flags from sshtty.c:enter_raw_mode(), but it can easily brake transparency. Another standart method to use was a must.

According to IETF RFC4254 ssh server can provide client an idea of doing the control flow at the client side. A special SSH_MSG_CHANNEL_REQUEST message with "xon-xoff" string MUST be used, and client MAY ignore this message. This feature is not implemented in OpenSSH, nor in client nor in the server.

As we have a great need in using software flow control on the local side with ssh connection to server, i have decided to implement these options in ssh server and client. The patch must be applied to the openssh 4.5p1 release.

The patch adds two boolean options in ssh and sshd correspondingly "IgnoreFlowControl" and "UseFlowControl". Defaults don't change the usual behaviour of neither ssh and sshd.

When "IgnoreLocalFlow" is set to "no" within ssh client, it handles "xon-xoff" message from sshd and enables or disables local flow control ONLY if it was previously set before ssh was started and associated with terminal device. If no ixon or ixoff option was set on terminal device everything is left as is.

When UseLocalFlow is set to "yes" within sshd server, it requests to enable "xon-xoff" after the client's request of pty allocation succeeds.

Now we can use printers attached to serial terminals and other devices.

In spite of the reason, that patch works well for me, i suppose it might be better but i need developers advice.

Best wishes,
Grigoriy A. Sitkarev

--- openssh-4.5p1/clientloop.c.orig     2006-10-23 17:02:41 +0000
+++ openssh-4.5p1/clientloop.c  2006-12-09 22:00:41 +0000
@@ -1823,7 +1823,7 @@
 client_input_channel_req(int type, u_int32_t seq, void *ctxt)
 {
        Channel *c = NULL;
-       int exitval, id, reply, success = 0;
+       int exitval, lflow, id, reply, success = 0;
        char *rtype;
 
        id = packet_get_int();
@@ -1850,6 +1850,17 @@
                        success = 1;
                }
                packet_check_eom();
+       } else if (strcmp(rtype, "xon-xoff") == 0) {
+               lflow = packet_get_char();
+               debug("client_input_channel_req: server %s local flow control",
+                   lflow ? "allows" : "disallows");
+               if (!options.ignore_local_flow) {
+                       if (lflow)
+                               enter_lflow_mode();
+                       else
+                               leave_lflow_mode();
+               }
+               packet_check_eom();
        }
        if (reply) {
                packet_start(success ?
--- openssh-4.5p1/readconf.c.orig       2006-09-01 05:38:37 +0000
+++ openssh-4.5p1/readconf.c    2006-12-09 21:42:24 +0000
@@ -129,7 +129,7 @@
        oAddressFamily, oGssAuthentication, oGssDelegateCreds,
        oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
        oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
-       oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
+       oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, 
oIgnoreLocalFlow,
        oDeprecated, oUnsupported
 } OpCodes;
 
@@ -226,6 +226,7 @@
        { "tunneldevice", oTunnelDevice },
        { "localcommand", oLocalCommand },
        { "permitlocalcommand", oPermitLocalCommand },
+       { "ignorelocalflow", oIgnoreLocalFlow },
        { NULL, oBadOption }
 };
 
@@ -915,6 +916,10 @@
                intptr = &options->permit_local_command;
                goto parse_flag;
 
+       case oIgnoreLocalFlow:
+               intptr = &options->ignore_local_flow;
+               goto parse_flag;
+
        case oDeprecated:
                debug("%s line %d: Deprecated option \"%s\"",
                    filename, linenum, keyword);
@@ -1065,6 +1070,7 @@
        options->tun_remote = -1;
        options->local_command = NULL;
        options->permit_local_command = -1;
+       options->ignore_local_flow = -1;
 }
 
 /*
@@ -1199,6 +1205,8 @@
                options->tun_remote = SSH_TUNID_ANY;
        if (options->permit_local_command == -1)
                options->permit_local_command = 0;
+       if (options->ignore_local_flow == -1)
+               options->ignore_local_flow = 1;
        /* options->local_command should not be set by default */
        /* options->proxy_command should not be set by default */
        /* options->user will be set in the main program if appropriate */

--- openssh-4.5p1/readconf.h.orig       2006-08-05 02:39:40 +0000
+++ openssh-4.5p1/readconf.h    2006-12-09 21:47:19 +0000
@@ -120,6 +120,7 @@
 
        char    *local_command;
        int     permit_local_command;
+       int     ignore_local_flow;
 
 }       Options;
 
--- openssh-4.5p1/servconf.c.orig       2006-08-18 14:23:15 +0000
+++ openssh-4.5p1/servconf.c    2006-12-09 21:27:27 +0000
@@ -120,6 +120,7 @@
        options->authorized_keys_file2 = NULL;
        options->num_accept_env = 0;
        options->permit_tun = -1;
+       options->use_local_flow = -1;
        options->num_permitted_opens = -1;
        options->adm_forced_command = NULL;
 }
@@ -249,6 +250,8 @@
                options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
        if (options->permit_tun == -1)
                options->permit_tun = SSH_TUNMODE_NO;
+       if (options->use_local_flow == -1)
+               options->use_local_flow = 0;
 
        /* Turn privilege separation on by default */
        if (use_privsep == -1)
@@ -293,6 +296,7 @@
        sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
        sMatch, sPermitOpen, sForceCommand,
        sUsePrivilegeSeparation,
+       sUseLocalFlow,
        sDeprecated, sUnsupported
 } ServerOpCodes;
 
@@ -403,6 +407,7 @@
        { "match", sMatch, SSHCFG_ALL },
        { "permitopen", sPermitOpen, SSHCFG_ALL },
        { "forcecommand", sForceCommand, SSHCFG_ALL },
+       { "uselocalflow", sUseLocalFlow, SSHCFG_GLOBAL },
        { NULL, sBadOption, 0 }
 };
 
@@ -1253,6 +1258,10 @@
                        options->adm_forced_command = xstrdup(cp + len);
                return 0;
 
+       case sUseLocalFlow:
+               intptr = &options->use_local_flow;
+               goto parse_flag;
+               
        case sDeprecated:
                logit("%s line %d: Deprecated option %s",
                    filename, linenum, arg);

--- openssh-4.5p1/servconf.h.orig       2006-08-18 14:23:15 +0000
+++ openssh-4.5p1/servconf.h    2006-12-09 21:19:56 +0000
@@ -138,6 +138,8 @@
 
        int     use_pam;                /* Enable auth via PAM */
 
+       int     use_local_flow;         /* Enable xon-xoff request */
+       
        int     permit_tun;
 
        int     num_permitted_opens;

--- openssh-4.5p1/session.c.orig        2006-10-23 17:01:56 +0000
+++ openssh-4.5p1/session.c     2006-12-09 21:25:13 +0000
@@ -1854,6 +1854,16 @@
 
        packet_check_eom();
        session_proctitle(s);
+       
+       if (options.use_local_flow) {
+               packet_start(SSH2_MSG_CHANNEL_REQUEST);
+               packet_put_int(s->chanid);
+               packet_put_cstring("xon-xoff");
+               packet_put_char(0);
+               packet_put_char(1);
+               packet_send();
+       }
+
        return 1;
 }
 
--- openssh-4.5p1/sshpty.h.orig 2006-08-05 02:39:41 +0000
+++ openssh-4.5p1/sshpty.h      2006-12-09 18:51:57 +0000
@@ -19,6 +19,8 @@
 struct termios get_saved_tio(void);
 void    leave_raw_mode(void);
 void    enter_raw_mode(void);
+void    leave_lflow_mode(void);
+void    enter_lflow_mode(void);
 
 int     pty_allocate(int *, int *, char *, size_t);
 void    pty_release(const char *);

--- openssh-4.5p1/sshtty.c.orig 2006-08-05 02:39:41 +0000
+++ openssh-4.5p1/sshtty.c      2006-12-09 18:37:46 +0000
@@ -46,6 +46,7 @@
 
 static struct termios _saved_tio;
 static int _in_raw_mode = 0;
+static int _in_lflow_mode = 0;
 
 struct termios
 get_saved_tio(void)
@@ -54,6 +55,48 @@
 }
 
 void
+enter_lflow_mode(void)
+{
+       struct termios tio;
+
+       if (_in_lflow_mode)
+               return;
+       
+       if (tcgetattr(fileno(stdin), &tio) == -1) {
+               perror("tcgetattr");
+               return;
+       }
+       if (_saved_tio.c_iflag & IXON)
+               tio.c_iflag |= IXON;
+       if (_saved_tio.c_iflag & IXOFF)
+               tio.c_iflag |= IXOFF;
+       
+       if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) {
+               perror("tcsetattr");
+       } else
+               _in_lflow_mode = 1;
+}
+
+void
+leave_lflow_mode(void)
+{
+       struct termios tio;
+       
+       if (!_in_lflow_mode)
+               return;
+       
+       if (tcgetattr(fileno(stdin), &tio) == -1) {
+               perror("tcgetattr");
+               return;
+       }
+       tio.c_iflag &= ~(IXON | IXOFF);
+       if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) {
+               perror("tcsetattr");
+       } else
+               _in_lflow_mode = 0;
+}
+
+void
 leave_raw_mode(void)
 {
        if (!_in_raw_mode)
_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@mindrot.org
http://lists.mindrot.org/mailman/listinfo/openssh-unix-dev
<Prev in Thread] Current Thread [Next in Thread>
  • Local software flow control, Grigoriy A. Sitkarev <=