001    package com.skype.ipc;
002    
003    import java.io.IOException;
004    import java.io.InputStream;
005    import java.io.OutputStream;
006    import java.net.InetAddress;
007    import java.net.InetSocketAddress;
008    import java.net.Socket;
009    import java.net.SocketTimeoutException;
010    
011    public class TransportFactory {
012    
013        public class Result {
014            InputTransporting  in;
015            OutputTransporting out;
016        }
017    
018        public TransportFactory() {
019        }
020    
021        public Result init(ClientConfiguration cfg, ConnectionListener listener) {
022           if (cfg.useTcpTransport()) {
023              return createTcpConnection(cfg, listener);
024           }
025           return createLocalConnection(cfg, listener);
026        }
027    
028        private Result createTcpConnection(ClientConfiguration cfg, ConnectionListener listener) {
029            // create the socket and connect it
030            Socket socket = new Socket();
031            InetSocketAddress endpoint;
032    
033            try {
034                endpoint = new InetSocketAddress(InetAddress.getByName(cfg.getIp()), cfg.getPort());
035             } catch (java.net.UnknownHostException e) {
036                 if (listener != null) {
037                     listener.sidOnDisconnected("UnknownHostException: "+cfg.getIp());
038                 }
039                 return null;
040             }
041    
042             int retry   = cfg.getConnectionNumRetries();
043             int timeout = cfg.getConnectionRetryInitialLatency();
044             while (retry != 0) {
045                 try {
046                     if (listener != null)
047                         listener.sidOnConnecting();
048                     socket.connect(endpoint, timeout);
049                     socket.setTcpNoDelay(true);
050                     socket.setKeepAlive(true);
051                 } catch (SocketTimeoutException to) {
052                     if (retry-- > 0) {
053                         timeout += timeout/2;
054                     } else {
055                         if (listener != null) {
056                             listener.sidOnDisconnected("SocketTimeoutException when connecting");
057                         }
058                         return null;
059                     }
060                 } catch (IOException e) {
061                     if (listener != null) {
062                         listener.sidOnDisconnected("IOException when connecting");
063                     }
064                     return null;
065                 }
066                 retry = 0;
067             }
068    
069             InputStream  ins;
070             OutputStream outs;
071    
072             try {
073                 ins   = socket.getInputStream();
074                 outs  = socket.getOutputStream();
075             } catch (IOException e) {
076                 listener.sidOnDisconnected("socket disconnected\n");
077                 return null;
078             }
079    
080             return createConnection(cfg, listener, ins, outs);
081        }
082    
083        protected Result createConnection(ClientConfiguration cfg, ConnectionListener listener, InputStream ins, OutputStream outs) {
084             Result result = new Result();
085    
086             if (cfg.isWithoutTls()) {
087                 result.in = new LoggedBufferedInputStream (ins, cfg);
088                 result.out= new LoggedBufferedOutputStream(outs, cfg);
089             } else {
090                 try {
091                     LoggedTlsInputOutputStream wrapper = new LoggedTlsInputOutputStream(ins, outs, cfg); 
092                     result.in = wrapper;
093                     result.out= wrapper;
094                 } catch (IOException e) {
095                     listener.sidOnDisconnected("TLS handshake failure\n");
096                     return null;
097                 }
098             }
099    
100             if (!doHandshake(cfg, listener, result.in, result.out)) 
101                 result = null;
102    
103             return result;
104        }
105    
106        protected boolean doHandshake(ClientConfiguration configuration, ConnectionListener listener, InputTransporting in, OutputTransporting out) {
107            String setup = "";
108    
109            boolean ok = true;
110            if (configuration.isWithoutTls()) {
111                try {
112                    setup = configuration.getCertificate();
113                } catch (IOException e) {
114                    listener.sidOnDisconnected("unable to read certificate file");
115                    ok    = false;
116                }
117            }       
118    
119            if (ok) {
120                setup += configuration.getHandshakeSetup();
121    
122                String appTokenLenHexStr=Integer.toHexString(setup.length());
123                while(appTokenLenHexStr.length()<8)  {
124                    appTokenLenHexStr="0"+appTokenLenHexStr;
125                }
126          
127                try {
128                    out.writeBytes(appTokenLenHexStr.getBytes());
129                    out.writeBytesAndFlush(setup.getBytes());
130                    byte[] rsp = new byte[2];
131                    in.readBytes(rsp);
132                    ok = rsp[0] == 'O' && rsp[1] == 'K';
133                } catch (IOException e) {
134                    ok = false;
135                }
136            }
137    
138            if (ok) {
139                 listener.sidOnConnected();
140            } else {
141                 listener.sidOnDisconnected("failed handshake\n");
142            }
143    
144            return ok;
145        }
146    
147        protected Result createLocalConnection(ClientConfiguration cfg, ConnectionListener listener) {
148            if (listener != null) {
149                listener.sidOnDisconnected("local transport not supported\n");
150            }
151            return null;
152        }
153    
154    }
155