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