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