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