<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    We're writing a Twisted 14.0.0 application (on Python 2.7.7, Mac OS
    10.9.3) that uses Conch as an SSH client; this is working fine. 
    However, we have the requirement that in an advanced mode of
    operation for power users that the application take advantage of
    OpenSSH connection multiplexing over an
    already-established-by-the-user OpenSSH ControlMaster session (via
    an OpenSSH ControlPath socket) instead of using Conch.<br>
    <br>
    OpenSSH requires its new session command and forwarded file
    descriptors to be sent over the socket in a very particular way: 
    the command must be sent first, followed by message with a '\0' byte
    with each forwarded file descriptor.  OpenSSH ignores the '\0' for
    each file descriptor, extracting the file descriptors themselves
    from the message's ancillary data.<br>
    <br>
    The following will not work because none of the calls to write()
    send their data until control is returned to the reactor, while
    sendFileDescriptor() queues up the descriptors such that they get
    sent them with the very next data that is sent -- which wind up
    being the first three bytes of the command rather than the three
    '\0' bytes.<br>
    <br>
    <pre>class OpenSSHMuxProtocol( protocol.Protocol ):
    # built via reactor.connectUNIX()
    def sendCommand( self, command ):
        # Does not work:
        self.transport.write( command )
        self.transport.sendFileDescriptor( sys.stdin.fileno() )
        self.transport.write( '\0' ) # payload for the stdin file descriptor
        self.transport.sendFileDescriptor( sys.stdout.fileno() )
        self.transport.write( '\0' ) # payload for the stdout file descriptor
        self.transport.sendFileDescriptor( sys.stdout.fileno() )
        self.transport.write( '\0' ) # payload for the stderr file descriptor
        # ^^^ Does not work</pre>
    <br>
    But this next solution <i>does</i> work:<br>
    <br>
    <meta http-equiv="content-type" content="text/html;
      charset=ISO-8859-1">
    <meta http-equiv="content-type" content="text/html;
      charset=ISO-8859-1">
    <pre>from socket import SOL_SOCKET
from twisted.python.sendmsg import SCM_RIGHTS, send1msg

class OpenSSHMuxProtocol( protocol.Protocol ):
    # built via reactor.connectUNIX()
    def sendCommand( self, command ):
        self.transport.writeSomeData( command ) # data is sent over the socket immediately
        send1msg( self.transport.socket.fileno(), "\0", 0,
            [ ( SOL_SOCKET, SCM_RIGHTS, pack( 'i', sys.stdin.fileno() ) ) ] )
        send1msg( self.transport.socket.fileno(), "\0", 0,
            [ ( SOL_SOCKET, SCM_RIGHTS, pack( 'i', sys.stdout.fileno() ) ) ] )
        send1msg( self.transport.socket.fileno(), "\0", 0,
            [ ( SOL_SOCKET, SCM_RIGHTS, pack( 'i', sys.stderr.fileno() ) ) ] )</pre>
    <br>
    My questions are:<br>
    <br>
    Is it bad to bypass the reactor and send data directly/immediately
    this way using writeSomeData() and send1msg()?  Note that
    sendCommand() actually gets called in response to a
    OpenSSHMuxProtocol.dataReceived() event.  If bypassing the reactor
    this way is bad, how bad is it and what are the consequences or
    effects?<br>
    <br>
    Is there a better way to get a working solution?  I think I'd need
    some way to guarantee that the write of the command was actually
    sent to the OpenSSH server before the file descriptors are forwarded
    -- for example, if a Deferred was used whose first callback wrote
    the command and whose second callback forwarded the descriptors,
    would a call to the reactor to actually sent the command be
    guaranteed between the two callbacks?<br>
    <br>
    Any information and/or advice is appreciated!<br>
    <br>
    <pre class="moz-signature" cols="72">-- 
  Mark Montague
  <a class="moz-txt-link-abbreviated" href="mailto:mark@catseye.org">mark@catseye.org</a></pre>
  </body>
</html>