@@ -89,7 +89,81 @@ var Tunnel = function Tunnel(key, port, uniqueIdentifier, callback) {
8989 return options ;
9090 }
9191
92- fs . exists ( localBinary , function ( exists ) {
92+ function runTunnelCmd ( tunnelOptions , subProcessTimeout , processOutputHook , callback ) {
93+ var isRunning , subProcess , timeoutHandle ;
94+
95+ var callbackOnce = function ( err , result ) {
96+ clearTimeout ( timeoutHandle ) ;
97+ if ( subProcess && isRunning ) {
98+ try {
99+ process . kill ( subProcess . pid , 'SIGKILL' ) ;
100+ subProcess = null ;
101+ } catch ( e ) {
102+ logger . debug ( '[%s] failed to kill process:' , new Date ( ) , e ) ;
103+ }
104+ }
105+
106+ callback && callback ( err , result ) ;
107+ callback = null ;
108+ } ;
109+
110+ isRunning = true ;
111+
112+ try {
113+ subProcess = exec ( localBinary , tunnelOptions , function ( error , stdout ) {
114+ isRunning = false ;
115+
116+ if ( error ) {
117+ callbackOnce ( new Error ( 'failed to get process output: ' + error ) ) ;
118+ } else if ( stdout ) {
119+ processOutputHook ( stdout , callbackOnce ) ;
120+ }
121+ } ) ;
122+
123+ subProcess . stdout . on ( 'data' , function ( data ) {
124+ processOutputHook ( data , callbackOnce ) ;
125+ } ) ;
126+ } catch ( e ) {
127+ // Handles EACCESS and other errors when binary file exists,
128+ // but doesn't have necessary permissions (among other issues)
129+ callbackOnce ( new Error ( 'failed to get process output: ' + e ) ) ;
130+ }
131+
132+ if ( subProcessTimeout > 0 ) {
133+ timeoutHandle = setTimeout ( function ( ) {
134+ callbackOnce ( new Error ( 'failed to get process output: command timeout' ) ) ;
135+ } , subProcessTimeout ) ;
136+ }
137+ }
138+
139+ function getTunnelBinaryVersion ( callback ) {
140+ var subProcessTimeout = 3000 ;
141+
142+ runTunnelCmd ( [ '-version' ] , subProcessTimeout , function ( data , done ) {
143+ var matches = / v e r s i o n \s + ( \d + ( \. \d + ) * ) / . exec ( data ) ;
144+ var version = ( matches && matches . length > 2 ) && matches [ 1 ] ;
145+ logger . debug ( '[%s] Tunnel binary: found version' , new Date ( ) , version ) ;
146+
147+ done ( isFinite ( version ) ? null : new Error ( 'failed to get binary version' ) , parseFloat ( version ) ) ;
148+ } , callback ) ;
149+ }
150+
151+ function verifyTunnelBinary ( callback ) {
152+ logger . debug ( '[%s] Verifying tunnel binary' , new Date ( ) ) ;
153+
154+ fs . exists ( localBinary , function ( exists ) {
155+ if ( ! exists ) {
156+ logger . debug ( '[%s] Verifying tunnel binary: file does not exist' , new Date ( ) ) ;
157+ callback ( false ) ;
158+ } else {
159+ getTunnelBinaryVersion ( function ( err , version ) {
160+ callback ( ! err && isFinite ( version ) ) ;
161+ } ) ;
162+ }
163+ } ) ;
164+ }
165+
166+ verifyTunnelBinary ( function ( exists ) {
93167 if ( exists ) {
94168 tunnelLauncher ( ) ;
95169 return ;
0 commit comments