001 package com.skype.ipc;
002
003 import java.io.EOFException;
004 import java.io.File;
005 import java.io.FileNotFoundException;
006 import java.io.FileOutputStream;
007 import java.io.IOException;
008 import java.io.InputStream;
009 import java.io.OutputStream;
010 import java.net.InetAddress;
011 import java.net.InetSocketAddress;
012 import java.net.Socket;
013 import java.net.SocketAddress;
014
015 import com.skype.util.Log;
016
017 public class TCPSocketTransport implements Transport {
018
019 // INTERFACE IMPLEMENTATION
020 private static final String TAG = "TCPSocketTransport";
021
022 public TCPSocketTransport(String IpAddress, int Port) {
023 super();
024 this.mIpAddress = IpAddress;
025 this.mPort = Port;
026 buffer=new byte[BUFFERSIZE];
027 bufferidx=0;
028 bufferend=0;
029 try {
030 mInetAddress = InetAddress.getByName(mIpAddress);
031 mSocketAddress = new InetSocketAddress(mInetAddress, mPort);
032 } catch (java.net.UnknownHostException e) {
033 Log.d(TAG,"UnknownHost: "+ e.getMessage());
034 }
035 }
036
037 private String mIpAddress = null;
038 private int mPort = 0;
039 private boolean mConnected = false;
040 private Socket mSocket;
041 private InetAddress mInetAddress;
042 private SocketAddress mSocketAddress;
043 private static int mSocketTimeout = 1 * 1000; // x * 1 sec(in millis)
044 private boolean isLogging = false;
045 private FileOutputStream logFileOut = null;
046 private FileOutputStream logFileIn = null;
047
048 public boolean connect() throws IOException {
049 Log.d(TAG, "TCPSocketTransport::connect() called");
050 if (!mConnected) {
051 try {
052 mSocket = new Socket(); // create unconnected socket
053 mSocket.connect(mSocketAddress, mSocketTimeout);
054 mSocket.setTcpNoDelay(true);
055 Log.d(TAG,"Socket created:"+mSocket);
056 // Get the input/output streams
057 ins = mSocket.getInputStream();
058 outs = mSocket.getOutputStream();
059
060 // We successfully connected our socket
061 mConnected = true;
062 } catch (java.net.UnknownHostException e) {
063 Log.e(TAG,"UnknownHost: "+ e.getMessage());
064 } catch (java.io.IOException e) {
065 Log.e(TAG,"IO: "+e.getMessage());
066 }
067 }
068 return mConnected;
069 }
070
071 public void disconnect() throws IOException {
072 if (mConnected) {
073 try {
074 ins.close();
075 ins = null;
076 outs.close();
077 outs = null;
078 mSocket.close();
079 } catch (IOException e) {
080 Log.e(e.getClass().getName(), e.getMessage());
081 }
082 mConnected = false;
083 }
084 }
085
086 public boolean isConnected() throws IOException {
087 return mConnected;
088 }
089
090 @Override
091 public void startLogging(String logFileName)
092 {
093 assert( ! isLogging);
094
095 if (logFileName != null && ! logFileName.isEmpty()) {
096 try {
097 logFileOut = new FileOutputStream(new File(logFileName + ".out.bin"), false);
098 logFileIn = new FileOutputStream(new File(logFileName + ".in.bin"), false);
099 isLogging = true;
100 Log.d(TAG, "Transport logging started");
101 }
102 catch (FileNotFoundException e) {
103 Log.e(TAG, "Unable to open transport log files using:" + logFileName);
104 }
105 }
106 }
107
108 public int peek() throws IOException
109 {
110 // Log.d(TAG, "TCPSocketTransport::peek() called");
111 synchronized (ins) {
112 return (ReadByte(true));
113 }
114 }
115
116 public int read() throws IOException
117 {
118 synchronized(ins)
119 {
120 return(ReadByte(false));
121 }
122 }
123
124 public int read(int numBytes, byte[] bytes) throws IOException
125 {
126 synchronized(ins)
127 {
128 for(int n=0;n<numBytes;n++)
129 {
130 bytes[n]=ReadByte(false);
131 }
132 }
133 return numBytes;
134 /*
135 if (mConnected) {
136 try {
137 instream.read(bytes, 0, numBytes);
138 }
139 catch (IOException e) {
140 Log.e(e.getClass().getName(), e.getMessage());
141 }
142 }
143 return true;
144 */
145 }
146
147 public int read(int numBytes, byte[] bytes, boolean requirenumbytes) throws IOException
148 {
149 if(!requirenumbytes)
150 {
151 return read(numBytes,bytes);
152 }
153 for(int n=0;n<numBytes;n++)
154 {
155 synchronized(ins)
156 {
157 bytes[n]=ReadByte(false);
158 }
159 }
160 //Log.d(TAG, "TCPSocketTransport - bytes read from chunk are:");
161 //dumpBytes(bytes,numBytes);
162 return numBytes;
163 }
164
165 public boolean write(byte b) throws IOException {
166 if (mConnected) {
167 try {
168 synchronized(outs)
169 {
170 outs.write(b);
171 //Log.d(TAG,"Write: " + Integer.toHexString(b & 0xFF) + " " + (char)b + " " + (int)(b & 0xFF));
172 if (isLogging) {
173 logFileOut.write(b);
174 }
175 }
176 }
177 catch (EOFException e) {
178 Log.e(TAG, e.getMessage());
179 throw e;
180 }
181 catch (IOException e) {
182 Log.e(TAG, e.getMessage());
183 throw e;
184 }
185 }
186 return true;
187 }
188
189 public boolean write(int numBytes, byte[] bytes) throws IOException
190 {
191 if (mConnected) {
192 try {
193 synchronized(outs)
194 {
195 outs.write(bytes, 0, numBytes);
196 // for(int i=0;i<numBytes;i++)
197 // {
198 // Log.d(TAG,"Write: " + Integer.toHexString(bytes[i] & 0xFF) + " " + (char)bytes[i] + " " + (int)(bytes[i] & 0xFF));
199 // }
200 if (isLogging) {
201 logFileOut.write(bytes,0, numBytes);
202 }
203 }
204 }
205 catch (IOException e) {
206 Log.e(e.getClass().getName(), e.getMessage());
207 throw e;
208 }
209 }
210 return true;
211 }
212
213 public InputStream GetInputStream()
214 {
215 return ins;
216 }
217
218 public OutputStream GetOutputStream()
219 {
220 return outs;
221 }
222
223 //// CLASS INTERNALS
224
225 public static final int BUFFERSIZE=1024*64; //bytes
226 public static final int STREAMTIMEOUT=1000*60*10; //ms
227
228 private InputStream ins;
229 private OutputStream outs;
230 private byte[] buffer;
231 private int bufferidx;
232 private int bufferend;
233
234 private byte ReadByte(boolean peek) throws IOException
235 {
236 //Log.d(TAG,"ReadByte entered");
237 while(bufferidx==bufferend)
238 {
239 //Log.d(TAG, "Transport buffer reading more...");
240 bufferidx=0;
241 bufferend=0;
242 bufferend=ins.read(buffer); // blocks
243
244 if(bufferend==-1)
245 {
246 Log.e(TAG,"Socket transport is returning -1.");
247 mConnected = false;
248 throw new EOFException("Socket transport stream EOF");
249 }
250 else
251 {
252 //Log.d(TAG, "Transport buffer read some more...");
253 }
254 }
255 byte retbyte=buffer[bufferidx];
256 if(peek)
257 {
258 // Log.d(TAG,"Peek: " + Integer.toHexString(retbyte & 0xFF) + " " + (char)retbyte + " " + (int)(retbyte & 0xFF));
259 }
260 else
261 {
262 // Log.d(TAG,"Read: " + Integer.toHexString(retbyte & 0xFF) + " " + (char)retbyte + " " + (int)(retbyte & 0xFF));
263 if (isLogging) {
264 logFileIn.write(retbyte);
265 }
266
267 bufferidx++;
268 }
269 return retbyte;
270 }
271
272 @Override
273 public boolean hasMore() throws IOException {
274 return !(bufferidx==bufferend);
275 }
276 }