modification to debug on a remote server
[phpeclipse.git] / net.sourceforge.phpeclipse.debug.core / src / net / sourceforge / phpdt / internal / debug / core / PHPDBGProxy.java
1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. and others.
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
7
8 Contributors:
9         IBM Corporation - Initial implementation
10         Vicente Fernando - www.alfersoft.com.ar
11         Christian Perkonig - remote debug
12 **********************************************************************/
13 package net.sourceforge.phpdt.internal.debug.core;
14
15 import java.io.BufferedReader;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.io.OutputStream;
19 import java.net.Socket;
20 import java.net.ServerSocket;
21 import java.net.SocketTimeoutException;
22
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IPath;
25 import org.eclipse.core.runtime.Path;
26 import org.eclipse.debug.core.DebugPlugin;
27 import org.eclipse.debug.core.DebugException;
28 import org.eclipse.debug.core.model.IBreakpoint;
29 import net.sourceforge.phpdt.internal.debug.core.model.IPHPDebugTarget;
30 import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame;
31 import net.sourceforge.phpdt.internal.debug.core.model.PHPThread;
32 import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable;
33 import net.sourceforge.phpdt.internal.debug.core.breakpoints.PHPLineBreakpoint;
34
35 public class PHPDBGProxy {
36
37         private ServerSocket server= null;
38         private Socket socket;
39         private BufferedReader reader= null;
40         private PHPDBGInterface DBGInt= null;
41         private IPHPDebugTarget debugTarget= null;
42         private PHPLoop phpLoop;
43         private PHPThread PHPMainThread;
44         private PHPDBGProxy thisProxy= null;
45         private int port;
46         private boolean remote;
47         private IPath remoteSourcePath;
48
49         public PHPDBGProxy() {
50                 thisProxy= this;
51         }
52
53         public PHPDBGProxy(boolean remote,String remoteSourcePath) {
54                 thisProxy= this;
55                 this.remote=remote;
56                 this.remoteSourcePath= new Path(remoteSourcePath);
57         }
58
59         public void start() {
60                 createServerSocket();
61                 this.startPHPLoop();
62         }
63
64         public void stop() {
65                 phpLoop.setShouldStop();
66                 if(DBGInt != null) DBGInt.setShouldStop();
67                 if (!remote) {
68                         try {
69                                 getDebugTarget().getProcess().terminate();
70                         } catch (DebugException e) {
71                                 e.printStackTrace();
72                         }
73                 }
74                 phpLoop.notifyWait();
75         }
76
77         protected ServerSocket getServerSocket() throws IOException {
78                 if (server == null) {
79                         createServerSocket();
80                 }
81                 return server;
82         }
83
84         protected void createServerSocket() {
85 //              port = SocketUtil.findUnusedLocalPort("localhost", 10001, 10101);
86     port =      10001;
87                 if (port == -1) {
88                         PHPDebugCorePlugin.log(5, "Cannot find free port!!!!");
89                         return;
90                 }
91                 try {
92                         if (server == null) {
93                                 server = new ServerSocket(port);
94                                 //System.out.println("ServerSocket on port: " + port);
95                         } 
96                 } catch (IOException e) {
97                         // IO Error
98                         PHPDebugCorePlugin.log(e);
99                         stop();
100                 }
101         }
102
103         public Socket getSocket() throws IOException {
104                 return socket;
105         }
106
107         protected void setDBGInterface(PHPDBGInterface DBGInt) {
108                 this.DBGInt= DBGInt;
109         }
110
111         public BufferedReader getReader() throws IOException {
112                 if (reader == null) {
113                         reader = new BufferedReader(new InputStreamReader(this.getSocket().getInputStream(), "ISO8859_1"));
114                 }
115                 return reader;
116         }
117         
118         public BufferedReader getReader(Socket socket) throws IOException {
119                 if (socket != null)
120                   return new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO8859_1"));
121                 else
122                   return null;
123         }
124
125         public OutputStream getOutputStream() throws IOException {
126                 return this.getSocket().getOutputStream();
127         }
128
129         protected void setBreakPoints() throws IOException, CoreException {
130                 IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
131                 for (int i = 0; i < breakpoints.length; i++) {
132                         addBreakpoint(breakpoints[i]);
133                 }
134         }
135
136         public void addBreakpoint(IBreakpoint breakpoint) {
137                 if (DBGInt == null) return;
138                 int bpNo= 0;
139                 try {
140                         PHPLineBreakpoint phpLBP;
141                         if(breakpoint.getModelIdentifier() == PHPDebugCorePlugin.getDefault().getDescriptor().getUniqueIdentifier()) {
142                                 IPath filename;
143                                 phpLBP= (PHPLineBreakpoint)breakpoint;
144                                 //                              bpNo= DBGInt.addBreakpoint(phpLBP.getMarker().getResource().getLocation().toOSString(), phpLBP.getLineNumber());
145                                 if (remote)
146                                         filename=remoteSourcePath.append(phpLBP.getMarker().getResource().getProjectRelativePath());
147                                 else
148                                         filename=phpLBP.getMarker().getResource().getLocation();
149                                 bpNo= DBGInt.addBreakpoint(filename.toOSString(), phpLBP.getLineNumber());
150                                 phpLBP.setDBGBpNo(bpNo);
151                         }
152                 } catch (IOException e) {
153                         PHPDebugCorePlugin.log(e);
154                         stop();
155                 } catch (CoreException e) {
156                         PHPDebugCorePlugin.log(e);
157                         stop();
158                 }
159         }
160
161         public void removeBreakpoint(IBreakpoint breakpoint) {
162                 if (DBGInt == null) return;
163                 try {
164                         PHPLineBreakpoint phpLBP;
165                         if(breakpoint.getModelIdentifier() == PHPDebugCorePlugin.getDefault().getDescriptor().getUniqueIdentifier()) {
166                                 phpLBP= (PHPLineBreakpoint)breakpoint;
167                                 IPath filename;
168                                 if (remote)
169                                         filename=remoteSourcePath.append(phpLBP.getMarker().getResource().getProjectRelativePath());
170                                 else
171                                         filename=phpLBP.getMarker().getResource().getLocation();
172 //                                      bpNo= DBGInt.addBreakpoint(filename.toOSString(), phpLBP.getLineNumber());                              
173                                 DBGInt.removeBreakpoint(filename.toOSString(), phpLBP.getLineNumber(), phpLBP.getDBGBpNo());
174                         }
175                 } catch (IOException e) {
176                         PHPDebugCorePlugin.log(e);
177                         stop();
178                 } catch (CoreException e) {
179                         PHPDebugCorePlugin.log(e);
180                         stop();
181                 }
182         }
183         
184         public void phpLoopNotify (){
185                 phpLoop.notifyWait();
186         }
187
188         public void startPHPLoop() {
189                 phpLoop = new PHPLoop();
190                 phpLoop.start();
191         }
192
193         public void resume() {
194                 try {
195                         DBGInt.continueExecution();
196                         phpLoop.notifyWait();
197                 } catch (IOException e) {
198                         PHPDebugCorePlugin.log(e);
199                         stop();
200                 }
201         }
202
203         public void pause() {
204                 try {
205                         DBGInt.pauseExecution();
206                 } catch (IOException e) {
207                         PHPDebugCorePlugin.log(e);
208                         stop();
209                 }
210         }
211         protected IPHPDebugTarget getDebugTarget() {
212                 return debugTarget;
213         }
214
215         public void setDebugTarget(IPHPDebugTarget debugTarget) {
216                 this.debugTarget = debugTarget;
217                 debugTarget.setPHPDBGProxy(this);
218         }
219
220         public PHPVariable[] readVariables(PHPStackFrame frame) {
221                 try {
222                         return DBGInt.getVariables(frame);
223                 } catch (IOException ioex) {
224                         ioex.printStackTrace();
225                         throw new RuntimeException(ioex.getMessage());
226                 } catch (DebugException ex) {
227                         ex.printStackTrace();
228                         throw new RuntimeException(ex.getMessage());
229                 }
230         }
231
232         public PHPVariable[] readInstanceVariables(PHPVariable variable) {
233                 try {
234                         return DBGInt.getInstVars(variable);
235                 } catch (DebugException ex) {
236                         ex.printStackTrace();
237                         throw new RuntimeException(ex.getMessage());
238                 }
239
240         }
241
242         public void readStepOverEnd(PHPStackFrame stackFrame) {
243                 try {
244                         DBGInt.stepOver();
245                         phpLoop.notifyWait();
246                 } catch (Exception e) {
247                         PHPDebugCorePlugin.log(e);
248                 }
249         }
250
251         public void readStepReturnEnd(PHPStackFrame stackFrame) {
252                 try {
253                         DBGInt.stepOut();
254                         phpLoop.notifyWait();
255                 } catch (Exception e) {
256                         PHPDebugCorePlugin.log(e);
257                 }
258         }
259
260         public void readStepIntoEnd(PHPStackFrame stackFrame) {
261                 try {
262                         DBGInt.stepInto();
263                         phpLoop.notifyWait();
264                 } catch (Exception e) {
265                         PHPDebugCorePlugin.log(e);
266                 }
267         }
268
269 /*
270         public PHPStackFrame[] readFrames(PHPThread thread) {
271                 //try {
272                         //this.println("th " + thread.getId() + " ; f ");
273                         //return new FramesReader(getMultiReaderStrategy()).readFrames(thread);
274                         return null;
275                 //} catch (IOException e) {
276                 //      PHPDebugCorePlugin.log(e);
277                 //      return null;
278                 //}
279
280         }
281 */
282         
283         public void closeSocket() throws IOException {
284                 if (socket != null) {
285                         socket.close();
286                 }
287         }
288
289         public void closeServerSocket() throws IOException {
290                 if (server != null) {
291                         server.close();
292                 }
293         }
294
295         public int getPort() {
296                 return port;
297         }
298
299         class PHPLoop extends Thread {
300                 private boolean shouldStop;
301         
302                 public PHPLoop() {
303                         shouldStop = false;
304                         this.setName("PHPDebuggerLoop");
305                 }
306
307                 public synchronized void setShouldStop() {
308                         shouldStop = true;
309                 }
310
311                 public synchronized void notifyWait() {
312                         notify();
313                 }
314
315                 public void run() {
316                         try {
317                                 char[] buf= new char[16];
318                                 int i, pos, timeout;
319                                 long interval= 200; // 200ms
320                                 String line;
321                                 PHPStackFrame[] StackList;
322                                 boolean endFile=false;
323                                 boolean newconnect=false;
324                                 Socket newSocket=null;
325                                 PHPDBGInterface newDBGInt;
326                                 int sid=-1;
327                                 
328 //                              synchronized (this) {
329 //                                      wait();
330 //                              }
331                                 
332                                 PHPMainThread = new PHPThread(getDebugTarget(), getPort());
333                                 PHPMainThread.setName("Thread [main]");
334                                 timeout = 0;
335                                 
336 //                              while ((getDebugTarget() == null) && (timeout < 100)) {
337 //                                      sleep(100);
338 //                                      timeout++;
339 //                              }
340                                 // Be sure debug target is set
341 //                              PHPMainThread.setDebugTarget(getDebugTarget());
342                                 getDebugTarget().addThread(PHPMainThread);
343                                 
344                                 //System.out.println("Waiting for breakpoints.");       
345                                 while (!shouldStop)     
346                                 {       
347                                         newconnect=true;
348                 try {
349                   newSocket = server.accept();
350                  //System.out.println("Accepted! : " + socket.toString());
351                 } catch (SocketTimeoutException e) {
352                                                 // no one wants to connect
353                                                 newconnect=false;
354                     } catch (IOException e) {
355                 PHPDebugCorePlugin.log(e);
356               return;
357               }
358         
359                                         if (newconnect)
360                                         {
361                                                 if (DBGInt==null)
362                                                         server.setSoTimeout(1);
363                                                 newDBGInt= new PHPDBGInterface(getReader(newSocket), newSocket.getOutputStream(), thisProxy);
364                                                 newDBGInt.waitResponse(1000);
365                   newDBGInt.flushAllPackets();
366                                                 // Check version and session ID
367                   if ((DBGInt==null) || (DBGInt.getSID()==newDBGInt.getSID()))
368                   {
369                         DBGInt=newDBGInt;
370                                                         try     {
371                                                                 closeSocket();
372                                                         }       catch (IOException e) {
373                                                                 PHPDebugCorePlugin.log(e);
374                                                                 shouldStop=true;
375                                                         }
376                         socket=newSocket;
377                                                         setBreakPoints();
378                                                         DBGInt.continueExecution();                     
379                   } else
380                   {
381                                                         newDBGInt.continueExecution();
382                         newSocket.close();
383                   }
384                                         }
385
386                 if(DBGInt.waitResponse(interval))
387                 {
388                 
389                 DBGInt.flushAllPackets();
390
391                 if (DBGInt.BPUnderHit != 0) {
392                         StackList = DBGInt.getStackList();
393                         if (StackList.length > 0) {
394                         for (i = 0; i < StackList.length; i++) {
395                         StackList[i].setThread(PHPMainThread);
396                         if (DBGInt.getModByNo(StackList[i].getModNo()).equals("")) {
397                                 DBGInt.getSourceTree();
398                         }
399                         StackList[i].setFile(
400                                 DBGInt.getModByNo(StackList[i].getModNo()));
401                         }
402                         PHPMainThread.setStackFrames(StackList);
403                         }
404                         // Fire debug event
405                         PHPMainThread.suspend();
406
407                         synchronized (this) {
408                         wait();
409                         }
410                 }
411                 }
412           if (remote) {
413                 if (PHPMainThread.isTerminated())
414                 {
415                         shouldStop=true;
416                         break;
417                 }
418           } else {
419                 if (PHPMainThread.isTerminated() || getDebugTarget().getProcess().isTerminated())
420                 {
421                                                         shouldStop=true;
422                                                         break;                   
423                 }
424           }
425                                 }
426         } 
427         catch (Exception ex) {
428         PHPDebugCorePlugin.log(ex);
429         System.out.println(ex);
430         } 
431         finally {
432                 try {
433                 getDebugTarget().terminate();
434                 closeSocket();
435                 closeServerSocket();
436                 }
437                 catch (IOException e) {
438                 PHPDebugCorePlugin.log(e);
439                 return;
440         }
441         //System.out.println("Socket loop finished.");
442         }
443                 }
444         }
445 }