    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