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    
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    }