[Monodevelop-patches-list] r2489 - in trunk/MonoDevelop/Extras/BooBinding: . BooShell BooShellServer Gui Gui/OptionPanels Properties Remoting

Peter Johanson <latexer@gentoo.org> pjohanson at mono-cvs.ximian.com
Wed Apr 27 22:38:46 EDT 2005


Author: pjohanson
Date: 2005-04-27 22:38:46 -0400 (Wed, 27 Apr 2005)
New Revision: 2489

Added:
   trunk/MonoDevelop/Extras/BooBinding/BooShell/
   trunk/MonoDevelop/Extras/BooBinding/BooShell/BooShell.boo
   trunk/MonoDevelop/Extras/BooBinding/BooShellServer/
   trunk/MonoDevelop/Extras/BooBinding/BooShellServer/BooShellServer.boo
   trunk/MonoDevelop/Extras/BooBinding/Remoting/
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixChannel.cs
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClient.cs
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientChannel.cs
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientTransportSink.cs
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientTransportSinkProvider.cs
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixListener.cs
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixMessageIO.cs
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixServerChannel.cs
   trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixServerTransportSink.cs
Modified:
   trunk/MonoDevelop/Extras/BooBinding/BooShellPadContent.boo
   trunk/MonoDevelop/Extras/BooBinding/ChangeLog
   trunk/MonoDevelop/Extras/BooBinding/Gui/BooShellModel.boo
   trunk/MonoDevelop/Extras/BooBinding/Gui/IShellModel.boo
   trunk/MonoDevelop/Extras/BooBinding/Gui/OptionPanels/CodeCompilationPanel.boo
   trunk/MonoDevelop/Extras/BooBinding/Gui/OptionPanels/GeneralShellPanel.boo
   trunk/MonoDevelop/Extras/BooBinding/Gui/ShellTextView.boo
   trunk/MonoDevelop/Extras/BooBinding/Makefile.am
   trunk/MonoDevelop/Extras/BooBinding/Properties/ShellProperties.boo
Log:
Lots of updates to the boo shell, interpreter now runs out of process, and added the option of loading the assemblies from the currently open combine/project.


Added: trunk/MonoDevelop/Extras/BooBinding/BooShell/BooShell.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/BooShell/BooShell.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/BooShell/BooShell.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,127 @@
+#region license
+// Copyright (c) 2005, Peter Johanson (latexer at gentoo.org)
+// All rights reserved.
+//
+// BooBinding is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// BooBinding is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with BooBinding; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#endregion
+
+namespace BooBinding.BooShell
+
+import System
+import System.Collections
+import System.IO
+import Boo.Lang.Interpreter
+import Boo.Lang.Compiler
+
+import Gtk
+import GLib
+
+class BooShell(MarshalByRefObject):
+	private _interpreter = InteractiveInterpreter(RememberLastValue: true, Print: print)
+
+	private _commandQueue = Queue()
+	private _outputQueue = Queue()
+
+	private _thread as System.Threading.Thread
+
+	private _processing as string = "true"
+
+	def Reset() as bool:
+		EnqueueCommand (ShellCommand (ShellCommandType.Reset, null))
+		return true
+	
+	def LoadAssembly (assemblyPath as string) as bool:
+		EnqueueCommand (ShellCommand (ShellCommandType.Load, assemblyPath))
+		return true
+	
+	def GetOutput() as (string):
+		_tmp as string
+		lock _processing:
+			_tmp = _processing
+
+		while _tmp == "true":
+			lock _processing:
+				_tmp = _processing
+			// Sleep to let other thread process (and grab lock)
+			System.Threading.Thread.Sleep (10)
+
+		ret as (string)
+		lock _outputQueue:
+			if _outputQueue.Count > 0:
+				ret = array (string, _outputQueue.Count)
+				_outputQueue.CopyTo (ret, 0)
+				_outputQueue.Clear()
+
+		return ret
+		
+	def QueueInput (line as string):
+		EnqueueCommand (ShellCommand (ShellCommandType.Eval, line))
+
+	def ThreadRun():
+		Application.Init()
+		GLib.Idle.Add(ProcessCommands)
+		Application.Run()
+
+	def ProcessCommands() as bool:
+		com as ShellCommand
+		lock _commandQueue:
+			if _commandQueue.Count > 0:
+				com = _commandQueue.Dequeue()
+		if com.Type == ShellCommandType.Eval:
+			if com.Data is not null:
+				lock _outputQueue:
+					_interpreter.LoopEval(com.Data)
+		elif com.Type == ShellCommandType.Reset:
+			_interpreter.Reset()
+		elif com.Type == ShellCommandType.Load:
+			if com.Data is not null:
+				_interpreter.load(com.Data)
+
+		com.Type = ShellCommandType.NoOp
+
+		lock _commandQueue:
+			if _commandQueue.Count == 0:
+				lock _processing:
+					_processing = "false"
+
+		return true
+	
+	def Run():
+		_thread = System.Threading.Thread(ThreadRun)
+		_thread.Start()
+	
+	def print(obj):
+		_outputQueue.Enqueue(obj)
+	
+	def EnqueueCommand (command as ShellCommand):
+		lock _commandQueue:
+			_commandQueue.Enqueue (command)
+			lock _processing:
+				_processing = "true"
+	
+
+public enum ShellCommandType:
+	NoOp
+	Reset
+	Load
+	Eval
+
+public struct ShellCommand:
+	Type as ShellCommandType
+	Data as string
+
+	def constructor (type, data):
+		self.Type = type
+		self.Data = data

Modified: trunk/MonoDevelop/Extras/BooBinding/BooShellPadContent.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/BooShellPadContent.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/BooShellPadContent.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -43,7 +43,9 @@
 	
 	def CreateBooShell():
 		_scroller = Gtk.ScrolledWindow()
-		_shellView = ShellTextView (BooShellModel())
+		_user = System.Environment.GetEnvironmentVariable("USER")
+		_model = BooShellModel ("../AddIns/BackendBindings/BooShellServer.exe", "/tmp/md-booshell-${_user}")
+		_shellView = ShellTextView (_model)
 		_scroller.Add(_shellView)
 
 	override def RedrawContent():
@@ -52,4 +54,5 @@
 
 	override def Dispose():
 		_shellView.Dispose()
+		_scroller.Dispose()
 		

Added: trunk/MonoDevelop/Extras/BooBinding/BooShellServer/BooShellServer.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/BooShellServer/BooShellServer.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/BooShellServer/BooShellServer.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,47 @@
+#region license
+// Copyright (c) 2005, Peter Johanson (latexer at gentoo.org)
+// All rights reserved.
+//
+// BooBinding is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+// 
+// BooBinding is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with BooBinding; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#endregion
+
+namespace BooBinding.BooShellServer
+
+import System
+import System.IO
+import System.Collections
+
+import System.Net.Sockets
+import System.Runtime.Remoting
+import System.Runtime.Remoting.Channels
+
+import BooBinding.Remoting
+import BooBinding.BooShell
+import Mono.Posix
+
+if argv.Length != 1:
+	print "ERROR: BooShellServer called with an invalid number of arguments"
+	System.Environment.Exit(1)
+
+print "Starting server listening on ${argv[0]}"
+File.Delete (argv[0])
+props = Hashtable()
+props["path"] = argv[0]
+chan = UnixChannel (props, BinaryClientFormatterSinkProvider (), BinaryServerFormatterSinkProvider ())
+ChannelServices.RegisterChannel(chan);
+RemotingConfiguration.RegisterWellKnownServiceType(
+                typeof(BooShell), "BooShell", WellKnownObjectMode.Singleton);
+	
+Console.ReadLine()

Modified: trunk/MonoDevelop/Extras/BooBinding/ChangeLog
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/ChangeLog	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/ChangeLog	2005-04-28 02:38:46 UTC (rev 2489)
@@ -1,4 +1,18 @@
 2005-04-25  Peter Johanson <latexer at gentoo.org>
 
+	* Properties/GeneralShellProperties.boo:
+	* Gui/*: Lots of changes to handle new shell
+	handling, as well as adding the ability to
+	load the assemblies generated by the currently
+	open solution/combine.
+	* Remoting/*: Library for doing remoting
+	using unix sockets
+	* BooShell/BooShell.boo: New shell object
+	created out of process from MD for projection
+	* BooShellServer/BooShellServer.boo: Remoting
+	server for serving up the BooShell objects
+
+2005-04-25  Peter Johanson <latexer at gentoo.org>
+
 	* Initial import of the Boo addin.
 

Modified: trunk/MonoDevelop/Extras/BooBinding/Gui/BooShellModel.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Gui/BooShellModel.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Gui/BooShellModel.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -20,70 +20,115 @@
 namespace BooBinding.Gui
 
 import System
+import System.Diagnostics
 import System.Collections
 import System.IO
-import Boo.Lang.Interpreter
-import Boo.Lang.Compiler
 import BooBinding.Properties
 
+import BooBinding.BooShell
+import BooBinding.Remoting
+import System.Runtime.Remoting
+import System.Runtime.Remoting.Channels
+
 class BooShellModel(IShellModel):
+	private _props = BooShellProperties()
+
+	private _commandQueue = Queue()
+	private _outputQueue = Queue()
+
+	private _outputHandler as callable
 	
-	private _interpreter = InteractiveInterpreter(RememberLastValue: true, Print: print)
+	private _thread as System.Threading.Thread
 
-	private _outSink as StreamWriter
-	private _outSource as StreamReader
+	private _process as Process
 
-	private props = BooShellProperties()
+	private _booShell as BooShell
 
 	MimeType as string:
 		get:
 			return "text/x-boo"
 
-	def constructor():
-		_stream = MemoryStream()
-		_outSink = StreamWriter(_stream)
-		_outSource = StreamReader (_stream)
-	
 	Properties as ShellProperties:
 		get:
-			return props
+			return _props
 	
-	def Reset() as bool:
-		_interpreter.Reset()
-		return true
-		
-	def ProcessInput (line as String) as (string):
-		// Make sure our fake stdout is at the beginning
-		_outSink.BaseStream.SetLength(0)
-		_outSink.BaseStream.Seek(0, SeekOrigin.Begin)
+	def constructor ():
+		pass
 
-		// Save tradition stdout, and redirect Console
-		// to local StreamWriter. Catches any print, etc calls
-		// to be output to the local shell
-		_stdout = Console.Out
-		Console.SetOut(_outSink)
+	def constructor (program_path as string, socket_path as string):
+		StartShellServer (program_path, socket_path)
+		GetRemoteShellObject (socket_path)
+		_booShell.Run()
 
-		_interpreter.LoopEval(line)
+	def StartShellServer(program_path as string, socket_path as string):
+		psi = ProcessStartInfo()
+		psi.FileName = "mono"
+		psi.Arguments = "${program_path} ${socket_path}"
+		_process = Process.Start(psi)
+	
+	def GetRemoteShellObject (socket_path as string):
+		chan = UnixChannel (Hashtable(), BinaryClientFormatterSinkProvider (), BinaryServerFormatterSinkProvider ())
+		ChannelServices.RegisterChannel(chan)
+		_booShell = Activator.GetObject (typeof(BooShell), "unix://${socket_path}?BooShell")
 
-		// Restore stdout, and prep our fake stdout for reading
-		Console.SetOut(_stdout)
-		_outSink.Flush()
-		_outSink.BaseStream.Seek(0, SeekOrigin.Begin)
+			
+	def Reset() as bool:
+		_booShell.Reset()
+		return true
+	
+	def LoadAssembly (assemblyPath as string) as bool:
+		_booShell.LoadAssembly (assemblyPath)
+		return true
+	
+	def GetOutput() as (string):
+		ret as (string)
+		lock _outputQueue:
+			if _outputQueue.Count > 0:
+				ret = array (string, _outputQueue.Count)
+				_outputQueue.CopyTo (ret, 0)
+				_outputQueue.Clear()
 
-		retList = ArrayList()
-		_outputLine as string = _outSource.ReadLine()
+		return ret
 
-		while _outputLine is not null:
-			retList.Add(_outputLine)
-			_outputLine = _outSource.ReadLine()
+		
+	def QueueInput (line as string):
+		lock _commandQueue:
+			_commandQueue.Enqueue (line)
 
-		ret = cast ((string), retList.ToArray(typeof(string)))
+	def ThreadRun():
+		while true:
+			com as string
+			lock _commandQueue:
+				if _commandQueue.Count > 0:
+					com = _commandQueue.Dequeue()
+			if com is not null:
+				_booShell.QueueInput (com)
+				lines = _booShell.GetOutput()
+				if lines is not null:
+					EnqueueOutput(lines)
+				com = null
+				lock _outputQueue:
+					if _outputHandler is not null:
+						_outputHandler()
 
-		_ = _interpreter.LastValue
-		if _ is not null:
-			_interpreter.SetValue("_", _)
-
-		return ret
 	
+	def Run():
+		_thread = System.Threading.Thread(ThreadRun)
+		_thread.Start()
+	
+	def RegisterOutputHandler (handler as callable):
+		_outputHandler = handler
+	
+	def EnqueueOutput (lines as (string)):
+		lock _outputQueue:
+			for line in lines:
+				_outputQueue.Enqueue(line)
+	
+	def Dispose():
+		_thread.Abort()
+		_process.Kill()
+		_booShell = null
+		
 	def print(obj):
-		print "${obj}"
+		lock _outputQueue:
+			_outputQueue.Enqueue(obj)

Modified: trunk/MonoDevelop/Extras/BooBinding/Gui/IShellModel.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Gui/IShellModel.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Gui/IShellModel.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -26,9 +26,23 @@
 	def Reset() as bool:
 		pass
 
-	def ProcessInput (line as String) as (string):
+	def LoadAssembly (assemblyPath as string) as bool:
 		pass
+
+	def RegisterOutputHandler (handler as callable):
+		pass
+
+	def Run():
+		pass
 	
+	def GetOutput() as (string):
+		pass
+	
+	def QueueInput (line as string):
+		pass
+	
+	def Dispose():
+		pass
 
 	Properties as ShellProperties:
 		get:

Modified: trunk/MonoDevelop/Extras/BooBinding/Gui/OptionPanels/CodeCompilationPanel.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Gui/OptionPanels/CodeCompilationPanel.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Gui/OptionPanels/CodeCompilationPanel.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -53,7 +53,7 @@
 
 	private outputAssembly = Entry ()
 	private outputDirectory = Entry()
-	// Waiting on resolution of a boo bug before we can use this
+	// Waiting on easy method for setting entry text before using
 	//private outputDirectory as FolderEntry = FolderEntry ("Output Directory")
 	private compilerPath = Entry ()
 	private culture = Entry ()

Modified: trunk/MonoDevelop/Extras/BooBinding/Gui/OptionPanels/GeneralShellPanel.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Gui/OptionPanels/GeneralShellPanel.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Gui/OptionPanels/GeneralShellPanel.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -39,6 +39,7 @@
 	private autoIndentCheckButton = Gtk.CheckButton ()
 	private resetClearsScrollbackCheckButton = Gtk.CheckButton ()
 	private resetClearsHistoryCheckButton = Gtk.CheckButton ()
+	private loadAssemblyCheckButton = Gtk.CheckButton ()
 
 	private fontOptionsLabel = Gtk.Label ()
 	private fontButton = FontButton ()
@@ -55,6 +56,7 @@
 		autoIndentCheckButton.Label = GettextCatalog.GetString ("Automatically indent new lines in code blocks")
 		resetClearsScrollbackCheckButton.Label = GettextCatalog.GetString ("Shell reset clears scollback")
 		resetClearsHistoryCheckButton.Label = GettextCatalog.GetString ("Shell reset clears command history")
+		loadAssemblyCheckButton.Label = GettextCatalog.GetString ("Load project assemblies after building them (Causes shell reset)")
 		fontOptionsLabel.Markup = String.Format ("<b>{0}</b>", GettextCatalog.GetString ("Font"))
 		defaultMonoRadio = RadioButton (GettextCatalog.GetString ("Use default monospace font"))
 		customFontRadio = RadioButton (defaultMonoRadio, GettextCatalog.GetString ("Use custom font:"))
@@ -80,6 +82,9 @@
 		hboxTmp.PackStart (resetClearsHistoryCheckButton, false, false, 6)
 		vbox.PackStart (hboxTmp, false, false, 0)
 		hboxTmp = HBox()
+		hboxTmp.PackStart (loadAssemblyCheckButton, false, false, 6)
+		vbox.PackStart (hboxTmp, false, false, 0)
+		hboxTmp = HBox()
 		hboxTmp.PackStart (fontOptionsLabel, false, false, 0)
 		vbox.PackStart (hboxTmp, false, false, 12)
 		hboxTmp = HBox()
@@ -103,6 +108,7 @@
 		autoIndentCheckButton.Active = Properties.AutoIndentBlocks
 		resetClearsScrollbackCheckButton.Active = Properties.ResetClearsScrollback
 		resetClearsHistoryCheckButton.Active = Properties.ResetClearsHistory
+		loadAssemblyCheckButton.Active =  Properties.LoadAssemblyAfterBuild
 
 
 	public override def StorePanelContents() as bool:
@@ -118,6 +124,8 @@
 			Properties.ResetClearsScrollback = resetClearsScrollbackCheckButton.Active
 		if Properties.ResetClearsHistory != resetClearsHistoryCheckButton.Active:
 			Properties.ResetClearsHistory = resetClearsHistoryCheckButton.Active
+		if Properties.LoadAssemblyAfterBuild != loadAssemblyCheckButton.Active:
+			Properties.LoadAssemblyAfterBuild = loadAssemblyCheckButton.Active
 		return true
 	
 	private def ItemToggled (o, args as EventArgs):

Modified: trunk/MonoDevelop/Extras/BooBinding/Gui/ShellTextView.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Gui/ShellTextView.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Gui/ShellTextView.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -25,6 +25,7 @@
 
 import Gtk
 import Gdk
+import GLib
 import Pango
 import GtkSourceView
 
@@ -32,6 +33,7 @@
 import MonoDevelop.Core.Services
 import MonoDevelop.Services
 import MonoDevelop.Core.Properties
+import MonoDevelop.Internal.Project
 import Boo.IO
 
 
@@ -60,6 +62,12 @@
 	private _reset_clears_history as bool
 	private _reset_clears_scrollback as bool
 	private _auto_indent as bool
+	private _load_assembly_after_build as bool
+
+	private _projService as ProjectService
+	private _proj as Project
+
+	private _assembliesLoaded as bool
 	
 	def constructor(model as IShellModel):
 		service = cast(SourceViewService,ServiceManager.GetService(typeof(SourceViewService)))
@@ -75,10 +83,12 @@
 		self.ModifyFont(Model.Properties.Font)
 
 		Model.Properties.InternalProperties.PropertyChanged += OnPropertyChanged
+		Model.RegisterOutputHandler (HandleOutput)
 
 		_auto_indent = Model.Properties.AutoIndentBlocks
 		_reset_clears_scrollback = Model.Properties.ResetClearsScrollback
 		_reset_clears_history = Model.Properties.ResetClearsHistory
+		_load_assembly_after_build = Model.Properties.LoadAssemblyAfterBuild
 
 
 		// The 'Freezer' tag is used to keep everything except
@@ -87,7 +97,69 @@
 		tag.Editable = false
 		Buffer.TagTable.Add (tag)
 		prompt(false)
+
+		_projService = ServiceManager.GetService(typeof(ProjectService))
+		_projService.EndBuild += ProjectCompiled
+		_projService.CurrentProjectChanged += ProjectChanged
+
+		// Run our model. Needs to happen for models which may spawn threads,
+		// processes, etc
+		Model.Run()
 	
+	def ProjectChanged (sender, e as ProjectEventArgs):
+		_proj = e.Project
+
+	def ProjectCompiled (compiled as bool):
+		if _load_assembly_after_build and compiled:
+			Model.Reset()
+			resetGui()
+			loadProjectAssemblies ()
+
+	def loadProjectAssemblies():
+		for assembly in getProjectAssemblies ():
+			if (System.IO.File.Exists(assembly)):
+				Model.Reset()
+				Model.LoadAssembly (assembly)
+		_assembliesLoaded = true
+					
+
+	def getProjectAssemblies():
+		_assemblies = []
+		if (_proj is not null):
+			assembly = _proj.GetOutputFileName()
+			if assembly is not null:
+				_assemblies.Add(assembly)
+		else:
+			_combine = _projService.CurrentOpenCombine
+			if _combine is null:
+				return
+
+			projects = _combine.GetAllProjects()
+			if projects is null:
+				return
+			for entry as Project in projects:
+				if entry is null:
+					continue
+				assembly = entry.GetOutputFileName()
+				if assembly is not null:
+					_assemblies.Add(assembly)
+
+		return _assemblies
+
+	def HandleOutput():
+		GLib.Idle.Add (outputIdleProcessor)
+	
+	def outputIdleProcessor() as bool:
+		output = Model.GetOutput()
+		if output is not null:
+			for line as string in output:
+				processOutput (line )
+		prompt (true)
+		return false
+			
+	override def Dispose():
+		Model.Dispose()
+
 	#region Overrides of the standard methods for event handling
 	override def OnPopulatePopup (menu as Gtk.Menu):
 		_copyScriptInput = ImageMenuItem (GettextCatalog.GetString ("Copy Script"))
@@ -98,26 +170,41 @@
 		_saveScriptToFile.Image = Gtk.Image (Stock.SaveAs, Gtk.IconSize.Menu)
 		_saveScriptToFile.Activated += OnSaveScript
 		
+		_loadAssemblies = ImageMenuItem (GettextCatalog.GetString ("Load Project Assemblies (forces shell reset)"))
+		_loadAssemblies.Image = Gtk.Image (Stock.Add, Gtk.IconSize.Menu)
+		_loadAssemblies.Activated += def():
+			if Model.Reset ():
+				resetGui ()
+				loadProjectAssemblies ()
+		
 		_reset = ImageMenuItem (GettextCatalog.GetString ("Reset Shell"))
 		_reset.Image = Gtk.Image (Stock.Clear, Gtk.IconSize.Menu)
 		_reset.Activated += def():
 			if Model.Reset():
 				resetGui()
-		
+				_assembliesLoaded = false
+
 		if _scriptLines.Length <= 0:
 			_copyScriptInput.Sensitive = false
 			_saveScriptToFile.Sensitive = false
 			_reset.Sensitive = false
 
+		if (_assembliesLoaded == false) and (len (getProjectAssemblies ()) > 0):
+			_loadAssemblies.Sensitive = true
+		else:
+			_loadAssemblies.Sensitive = false
+
 		_sep = Gtk.SeparatorMenuItem()
 		menu.Prepend(_sep)
 		menu.Prepend(_copyScriptInput)
 		menu.Prepend(_saveScriptToFile)
+		menu.Prepend(_loadAssemblies)
 		menu.Prepend(_reset)
 		
 		_sep.Show()
 		_copyScriptInput.Show()
 		_saveScriptToFile.Show()
+		_loadAssemblies.Show()
 		_reset.Show()
 	
 	override def OnKeyPressEvent (ev as Gdk.EventKey):
@@ -250,13 +337,7 @@
 	
 	#region local private methods
 	private def processInput (line as string):
-		// Send our input out to be processed by the model
-		// and handle any output received in return
-		_results = self.Model.ProcessInput (line)
-		if _results:
-			for line as string in _results:
-				processOutput (line)
-		prompt(true)
+		Model.QueueInput (line)
 	
 	private def processOutput (line as string):
 		end = Buffer.EndIter
@@ -309,6 +390,8 @@
 			_reset_clears_scrollback = Model.Properties.ResetClearsScrollback
 		elif e.Key == "ResetClearsHistory":
 			_reset_clears_history = Model.Properties.ResetClearsHistory
+		elif e.Key == "LoadAssemblyAfterBuild":
+			_load_assembly_after_build = Model.Properties.LoadAssemblyAfterBuild
 
 		return
 

Modified: trunk/MonoDevelop/Extras/BooBinding/Makefile.am
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Makefile.am	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Makefile.am	2005-04-28 02:38:46 UTC (rev 2489)
@@ -1,19 +1,36 @@
 
 ADDIN_BUILD = $(top_builddir)/build/AddIns/BackendBindings
 ASSEMBLY = $(ADDIN_BUILD)/BooBinding.dll
+REMOTING_LIB = $(ADDIN_BUILD)/BooShellUnixRemoting.dll
+BOOSHELL_LIB = $(ADDIN_BUILD)/BooShell.dll
+BOOSHELL_SERVER_EXE = $(ADDIN_BUILD)/BooShellServer.exe
 
 DLLS = -r:System.Drawing \
 	-r:System.Xml \
+	-r:System.Runtime.Remoting \
 	-r:$(top_builddir)/build/bin/MonoDevelop.Core.dll \
 	-r:$(top_builddir)/build/bin/MonoDevelop.SourceEditor.dll \
 	-r:$(top_builddir)/build/bin/MonoDevelop.Base.dll \
 	-r:$(top_builddir)/build/bin/ICSharpCode.SharpRefactory.dll \
 	-r:$(top_builddir)/build/bin/MonoDevelop.Gui.Widgets.dll \
+	-r:$(BOOSHELL_LIB) \
+	-r:$(REMOTING_LIB) \
 	$(BOO_LIBS) \
 	$(GTK_SHARP_LIBS) \
 	$(GCONF_SHARP_LIBS) \
 	$(GTKSOURCEVIEW_SHARP_LIBS)
 
+REMOTING_DLLS = -r:System.Runtime.Remoting \
+		-r:Mono.Posix
+
+BOOSHELL_DLLS = $(GTK_SHARP_LIBS) \
+		$(BOO_LIBS)
+
+BOOSHELL_SERVER_DLLS = -r:$(BOOSHELL_LIB) \
+			-r:$(REMOTING_LIB) \
+			-r:System.Runtime.Remoting \
+			-r:Mono.Posix
+
 FILES = \
 Gui/ShellTextView.boo \
 Gui/IShellModel.boo \
@@ -39,6 +56,20 @@
 Parser/Tree.boo \
 Parser/Visitor.boo
 
+REMOTING_FILES = Remoting/UnixChannel.cs \
+Remoting/UnixClient.cs \
+Remoting/UnixClientChannel.cs \
+Remoting/UnixClientTransportSink.cs \
+Remoting/UnixClientTransportSinkProvider.cs \
+Remoting/UnixListener.cs \
+Remoting/UnixMessageIO.cs \
+Remoting/UnixServerChannel.cs \
+Remoting/UnixServerTransportSink.cs
+
+BOOSHELL_FILES = BooShell/BooShell.boo
+
+BOOSHELL_SERVER_FILES= BooShellServer/BooShellServer.boo
+
 TEMPLATES = \
 templates/BooGtkSharpProject.xpt.xml \
 templates/BooGtkSharpWindow.xft.xml \
@@ -46,10 +77,12 @@
 templates/EmptyBooProject.xpt.xml
 
 build_sources = $(addprefix $(srcdir)/, $(FILES))
+remoting_build_sources = $(addprefix $(srcdir)/, $(REMOTING_FILES))
+booshell_build_sources = $(addprefix $(srcdir)/, $(BOOSHELL_FILES))
+booshell_server_build_sources = $(addprefix $(srcdir)/, $(BOOSHELL_SERVER_FILES))
 
 ADDIN = BooBinding.addin.xml
 
-
 TEMPLATES_DIR = $(ADDIN_BUILD)/templates
 
 build_TEMPLATES = $(addprefix $(TEMPLATES_DIR)/, $(notdir $(TEMPLATES)))
@@ -57,7 +90,8 @@
 src_TEMPLATES = $(addprefix $(srcdir)/, $(TEMPLATES))
 
 if ENABLE_BOO
-all: $(ASSEMBLY) $(ADDIN_BUILD)/$(ADDIN) $(build_TEMPLATES)
+all: $(ASSEMBLY) $(ADDIN_BUILD)/$(ADDIN) $(build_TEMPLATES) \
+	$(BOOSHELL_LIB) $(BOOSHELL_SERVER_EXE)
 else
 all:
 endif
@@ -74,18 +108,32 @@
 	mkdir -p $(ADDIN_BUILD)
 	cp $(srcdir)/$(ADDIN) $(ADDIN_BUILD)/.
 
-$(ASSEMBLY): $(FILES)
+$(ASSEMBLY): $(FILES) $(REMOTING_LIB)
 	mkdir -p $(ADDIN_BUILD)
 	$(BOOC) $(DLLS) $(build_sources) -o:$@ -t:library
 
+$(REMOTING_LIB): $(REMOTING_FILES)
+	mkdir -p $(ADDIN_BUILD)
+	$(MCS) $(REMOTING_DLLS) $(remoting_build_sources) -out:$@ -t:library
+
+$(BOOSHELL_LIB): $(BOOSHELL_FILES)
+	mkdir -p $(ADDIN_BUILD)
+	$(BOOC) $(BOOSHELL_DLLS) $(booshell_build_sources) -o:$@ -t:library
+
+$(BOOSHELL_SERVER_EXE): $(BOOSHELL_SERVER_FILES)
+	mkdir -p $(ADDIN_BUILD)
+	$(BOOC) $(BOOSHELL_SERVER_DLLS) $(booshell_server_build_sources) -o:$@
+
 if ENABLE_BOO
 assemblydir = $(libdir)/monodevelop/AddIns/BackendBindings
-assembly_DATA = $(ASSEMBLY) $(ADDIN)
+assembly_DATA = $(ASSEMBLY) $(ADDIN) $(REMOTING_LIB) $(BOOSHELL_LIB) \
+		$(BOOSHELL_SERVER_EXE)
 
 templatedir = $(assemblydir)/templates
 template_DATA = $(TEMPLATES)
 endif
 
-CLEANFILES = $(ASSEMBLY) $(ASSEMBLY).mdb
-EXTRA_DIST = $(FILES) $(ADDIN) $(TEMPLATES)
+CLEANFILES = $(ASSEMBLY) $(REMOTING_LIB) $(BOOSHELL_LIB) $(BOOSHELL_SERVER_EXE)
+EXTRA_DIST = $(FILES) $(ADDIN) $(TEMPLATES) $(REMOTING_FILES) \
+	     $(BOOSHELL_FILES) $(BOOSHELL_SERVER_FILES)
 

Modified: trunk/MonoDevelop/Extras/BooBinding/Properties/ShellProperties.boo
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Properties/ShellProperties.boo	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Properties/ShellProperties.boo	2005-04-28 02:38:46 UTC (rev 2489)
@@ -56,3 +56,9 @@
 			return properties.GetProperty ("ResetClearsHistory", true)
 		set:
 			properties.SetProperty ("ResetClearsHistory", value)
+
+	LoadAssemblyAfterBuild as bool:
+		get:
+			return properties.GetProperty ("LoadAssemblyAfterBuild", true)
+		set:
+			properties.SetProperty ("LoadAssemblyAfterBuild", value)

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixChannel.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixChannel.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixChannel.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,145 @@
+//
+// System.Runtime.Remoting.Channels.Unix.UnixChannel.cs
+//
+// Author: Rodrigo Moya (rodrigo at ximian.com)
+//     Lluis Sanchez Gual (lluis at ideary.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Channels;
+using System.Text.RegularExpressions;
+
+namespace BooBinding.Remoting
+{
+    public class UnixChannel : IChannelReceiver, IChannel, IChannelSender
+    {
+        private UnixClientChannel _clientChannel;
+        private UnixServerChannel _serverChannel = null;
+        private string _name = "unix";
+        private int _priority = 1;
+    
+        public UnixChannel (): this ("")
+        {
+        }
+
+        public UnixChannel (string path)
+        {
+            Hashtable ht = new Hashtable();
+            ht["path"] = path;
+            Init(ht, null, null);
+        }
+
+        void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink)
+        {
+            _clientChannel = new UnixClientChannel (properties,clientSink);
+
+            if(properties["path"] != null)
+                _serverChannel = new UnixServerChannel(properties, serverSink);
+            
+            object val = properties ["name"];
+            if (val != null) _name = val as string;
+            
+            val = properties ["priority"];
+            if (val != null) _priority = Convert.ToInt32 (val);
+        }
+
+
+        public UnixChannel (IDictionary properties,
+                            IClientChannelSinkProvider clientSinkProvider,
+                            IServerChannelSinkProvider serverSinkProvider)
+        {
+            Init (properties, clientSinkProvider, serverSinkProvider);
+        }
+
+        public IMessageSink CreateMessageSink(string url, object remoteChannelData, out string objectURI)
+        {
+            return _clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI);
+        }
+
+        public string ChannelName
+        {
+            get { return _name; }
+        }
+
+        public int ChannelPriority
+        {
+            get { return _priority; }
+        }
+
+        public void StartListening (object data)
+        {
+            if (_serverChannel != null) _serverChannel.StartListening (data);
+        }
+        
+        public void StopListening (object data)
+        {
+            if (_serverChannel != null) _serverChannel.StopListening(data);
+        }
+
+        public string[] GetUrlsForUri (string uri)
+        {
+            if (_serverChannel != null) return _serverChannel.GetUrlsForUri(uri);
+            else return null;
+        }
+
+        public object ChannelData
+        {
+            get 
+            {
+                if (_serverChannel != null) return _serverChannel.ChannelData;
+                else return null;
+            }
+        }
+
+        public string Parse (string url, out string objectURI)
+        {
+            return UnixChannel.ParseUnixURL (url, out objectURI);
+        }
+
+        internal static string ParseUnixURL (string url, out string objectURI)
+        {
+            // format: "unix:///path/to/unix/socket?/path/to/object"
+            
+            objectURI = null;
+            
+            Match m = Regex.Match (url, "unix://?([^?]*)[?]?(.*)$");
+
+            if (!m.Success)
+                return null;
+            
+            string sockPath = m.Groups[1].Value;
+            objectURI = m.Groups[2].Value;
+
+            
+            if (objectURI == string.Empty)
+                objectURI = null;
+
+            return sockPath;
+        }
+    }
+}

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClient.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClient.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClient.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,231 @@
+//
+// UnixListener.cs
+//
+// Authors:
+//	Joe Shaw (joeshaw at novell.com)
+//
+// Copyright (C) 2004-2005 Novell, Inc.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+
+using Mono.Posix;
+
+namespace BooBinding.Remoting {
+
+	public class UnixClient : IDisposable {
+		NetworkStream stream;
+		Socket client;
+		bool disposed;
+
+		public UnixClient ()
+		{
+			if (client != null) {
+				client.Close ();
+				client = null;
+			}
+
+			client = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
+		}
+
+		public UnixClient (string path) : this ()
+		{
+			if (path == null)
+				throw new ArgumentNullException ("ep");
+
+			Connect (path);
+		}
+
+		public UnixClient (UnixEndPoint ep) : this ()
+		{
+			if (ep == null)
+				throw new ArgumentNullException ("ep");
+
+			Connect (ep);
+		}
+
+		// UnixListener uses this when accepting a connection.
+		internal UnixClient (Socket sock)
+		{
+			Client = sock;
+		}
+
+		protected Socket Client {
+			get { return client; }
+			set {
+				client = value;
+				stream = null;
+			}
+		}
+
+		public PeerCred PeerCredential {
+			get {
+				CheckDisposed ();
+				return new PeerCred (client);
+			}
+		}
+        
+		public LingerOption LingerState {
+			get {
+				CheckDisposed ();
+				return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket,
+									      SocketOptionName.Linger);
+			}
+
+			set {
+				CheckDisposed ();
+				client.SetSocketOption (SocketOptionLevel.Socket,
+							SocketOptionName.Linger, value);
+			}
+		}
+
+		public int ReceiveBufferSize {
+			get {
+				CheckDisposed ();
+				return (int) client.GetSocketOption (SocketOptionLevel.Socket,
+								     SocketOptionName.ReceiveBuffer);
+			}
+
+			set {
+				CheckDisposed ();
+				client.SetSocketOption (SocketOptionLevel.Socket,
+							SocketOptionName.ReceiveBuffer, value);
+			}
+		}
+            
+		public int ReceiveTimeout {
+			get {
+				CheckDisposed ();
+				return (int) client.GetSocketOption (SocketOptionLevel.Socket,
+								     SocketOptionName.ReceiveTimeout);
+			}
+
+			set {
+				CheckDisposed ();
+				client.SetSocketOption (SocketOptionLevel.Socket,
+							SocketOptionName.ReceiveTimeout, value);
+			}
+		}
+        
+		public int SendBufferSize {
+			get {
+				CheckDisposed ();
+				return (int) client.GetSocketOption (SocketOptionLevel.Socket,
+								     SocketOptionName.SendBuffer);
+			}
+
+			set {
+				CheckDisposed ();
+				client.SetSocketOption (SocketOptionLevel.Socket,
+							SocketOptionName.SendBuffer, value);
+			}
+		}
+        
+		public int SendTimeout {
+			get {
+				CheckDisposed ();
+				return (int) client.GetSocketOption (SocketOptionLevel.Socket,
+								     SocketOptionName.SendTimeout);
+			}
+
+			set {
+				CheckDisposed ();
+				client.SetSocketOption (SocketOptionLevel.Socket,
+							SocketOptionName.SendTimeout, value);
+			}
+		}
+        
+		public void Close ()
+		{
+			CheckDisposed ();
+			Dispose ();
+		}
+        
+		public void Connect (UnixEndPoint remoteEndPoint)
+		{
+			CheckDisposed ();
+			client.Connect (remoteEndPoint);
+			stream = new NetworkStream (client, true);
+		}
+        
+		public void Connect (string path)
+		{
+			CheckDisposed ();
+			Connect (new UnixEndPoint (path));
+		}
+        
+		public void Dispose ()
+		{
+			Dispose (true);
+			GC.SuppressFinalize (this);
+		}
+
+		protected virtual void Dispose (bool disposing)
+		{
+			if (disposed)
+				return;
+
+			if (disposing) {
+				// release managed resources
+				NetworkStream s = stream;
+				stream = null;
+				if (s != null) {
+					// This closes the socket as well, as the NetworkStream
+					// owns the socket.
+					s.Close();
+					s = null;
+				} else if (client != null){
+					client.Close ();
+				}
+				client = null;
+			}
+
+			disposed = true;
+		}
+
+		public NetworkStream GetStream ()
+		{
+			CheckDisposed ();
+			if (stream == null)
+				stream = new NetworkStream (client, true);
+
+			return stream;
+		}
+        
+		void CheckDisposed ()
+		{
+			if (disposed)
+				throw new ObjectDisposedException (GetType().FullName);
+		}        
+
+		~UnixClient ()
+		{
+			Dispose (false);
+		}
+	}
+}
+

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientChannel.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientChannel.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientChannel.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,134 @@
+//
+// System.Runtime.Remoting.Channels.Unix.UnixClientChannel.cs
+//
+// Author: Dietmar Maurer (dietmar at ximian.com)
+//     Lluis Sanchez Gual (lluis at ideary.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Net.Sockets;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Channels;
+using System.Threading;
+
+namespace BooBinding.Remoting
+{
+    public class UnixClientChannel : IChannelSender, IChannel
+    {
+        int priority = 1;                    
+        string name = "unix";
+        IClientChannelSinkProvider _sinkProvider;
+        
+        public UnixClientChannel ()
+        {
+            _sinkProvider = new BinaryClientFormatterSinkProvider ();
+            _sinkProvider.Next = new UnixClientTransportSinkProvider ();
+        }
+
+        public UnixClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
+        {
+            object val = properties ["name"];
+            if (val != null) name = val as string;
+            
+            val = properties ["priority"];
+            if (val != null) priority = Convert.ToInt32 (val);
+            
+            if (sinkProvider != null)
+            {
+                _sinkProvider = sinkProvider;
+
+                // add the unix provider at the end of the chain
+                IClientChannelSinkProvider prov = sinkProvider;
+                while (prov.Next != null) prov = prov.Next;
+                prov.Next = new UnixClientTransportSinkProvider ();
+
+                // Note: a default formatter is added only when
+                // no sink providers are specified in the config file.
+            }
+            else
+            {
+                _sinkProvider = new BinaryClientFormatterSinkProvider ();
+                _sinkProvider.Next = new UnixClientTransportSinkProvider ();
+            }
+
+        }
+
+        public UnixClientChannel (string name, IClientChannelSinkProvider sinkProvider)
+        {
+            this.name = name;
+            _sinkProvider = sinkProvider;
+
+            // add the unix provider at the end of the chain
+            IClientChannelSinkProvider prov = sinkProvider;
+            while (prov.Next != null) prov = prov.Next;
+            prov.Next = new UnixClientTransportSinkProvider ();
+        }
+        
+        public string ChannelName
+        {
+            get {
+                return name;
+            }
+        }
+
+        public int ChannelPriority
+        {
+            get {
+                return priority;
+            }
+        }
+
+        public IMessageSink CreateMessageSink (string url,
+                                               object remoteChannelData,
+                                               out string objectURI)
+        {
+            if (url != null && Parse (url, out objectURI) != null)
+                return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
+                                                                                
+            if (remoteChannelData != null) {
+                IChannelDataStore ds = remoteChannelData as IChannelDataStore;
+                if (ds != null && ds.ChannelUris.Length > 0)
+                    url = ds.ChannelUris [0];
+                else {
+                    objectURI = null;
+                    return null;
+                }
+            }
+            
+            if (Parse (url, out objectURI) == null)
+                return null;
+
+            return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
+        }
+
+        public string Parse (string url, out string objectURI)
+        {
+            return UnixChannel.ParseUnixURL (url, out objectURI);
+        }
+    }
+}

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientTransportSink.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientTransportSink.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientTransportSink.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,235 @@
+//
+// System.Runtime.Remoting.Channels.Unix.UnixClientTransportSink.cs
+//
+// Author: Dietmar Maurer (dietmar at ximian.com)
+//     Lluis Sanchez Gual (lluis at ideary.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.Remoting.Channels;
+using System.Runtime.Remoting;
+using System.Runtime.Remoting.Messaging;
+using System.Collections;
+using System.IO;
+using System.Threading;
+
+namespace BooBinding.Remoting
+{
+    internal class UnixClientTransportSink : IClientChannelSink
+    {
+        string _path;
+        string _url;
+        
+        public UnixClientTransportSink (string url)
+        {
+            string objectUri;
+            _path = UnixChannel.ParseUnixURL (url, out objectUri);
+            _url = url;
+        }
+
+        public IDictionary Properties
+        {
+            get 
+            {
+                return null;
+            }
+        }
+
+        public IClientChannelSink NextChannelSink
+        {
+            get 
+            {
+                // we are the last one
+                return null;
+            }
+        }
+
+        public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
+                                         ITransportHeaders headers, Stream requestStream)
+        {
+            UnixConnection connection = null;
+            bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
+
+            try
+            {
+                if (headers == null) headers = new TransportHeaders();
+                headers [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
+                
+                // Sends the stream using a connection from the pool
+                // and creates a WorkItem that will wait for the
+                // response of the server
+
+                connection = new UnixConnection (new UnixClient (_path));
+                UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
+
+                if (!isOneWay) 
+                {
+                    sinkStack.Push (this, connection);
+                    ThreadPool.QueueUserWorkItem (new WaitCallback(ReadAsyncUnixMessage), sinkStack);
+                }
+                else
+                    connection.Close();
+            }
+            catch
+            {
+                if (connection != null) connection.Close();
+                if (!isOneWay) throw;
+            }
+        }
+
+        private void ReadAsyncUnixMessage(object data)
+        {
+            // This method is called by a new thread to asynchronously
+            // read the response to a request
+
+            // The stack was provided as state data in QueueUserWorkItem
+            IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
+
+            // The first sink in the stack is this sink. Pop it and
+            // get the status data, which is the UnixConnection used to send
+            // the request
+            UnixConnection connection = (UnixConnection)stack.Pop(this);
+
+            try
+            {
+                ITransportHeaders responseHeaders;
+
+                // Read the response, blocking if necessary
+                MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream);
+
+                if (status != MessageStatus.MethodMessage)
+                    throw new RemotingException ("Unknown response message from server");
+
+                Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
+
+                // Free the connection, so it can be reused
+                connection.Close();
+                connection = null;
+
+                // Ok, proceed with the other sinks
+                stack.AsyncProcessResponse (responseHeaders, responseStream);
+            }
+            catch
+            {
+                if (connection != null) connection.Close();
+                throw;
+            }
+        }
+    
+        public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
+                                          object state, ITransportHeaders headers,
+                                          Stream stream)
+        {
+            // Should never be called
+            throw new NotSupportedException();
+        }
+
+        public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
+        {
+            return null;
+        }
+        
+        public void ProcessMessage (IMessage msg,
+                                    ITransportHeaders requestHeaders,
+                                    Stream requestStream,
+                                    out ITransportHeaders responseHeaders,
+                                    out Stream responseStream)
+        {
+            UnixConnection connection = null;
+            try
+            {
+                if (requestHeaders == null) requestHeaders = new TransportHeaders();
+                requestHeaders [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
+                
+                // Sends the message
+                connection = new UnixConnection (new UnixClient (_path));
+
+                UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
+
+                // Reads the response
+                MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream);
+
+                if (status != MessageStatus.MethodMessage)
+                    throw new RemotingException ("Unknown response message from server, status: " + status);
+
+                responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
+            }
+            finally
+            {
+                if (connection != null) 
+                    connection.Close();
+            }
+        }
+
+    }
+
+    internal class UnixConnection
+    {
+        DateTime _controlTime;
+        Stream _stream;
+        UnixClient _client;
+        byte[] _buffer;
+
+        public UnixConnection (UnixClient client)
+        {
+            _client = client;
+            _client.ReceiveTimeout = 10000; // 10 seconds
+            _stream = client.GetStream();
+            _controlTime = DateTime.Now;
+            _buffer = new byte[UnixMessageIO.DefaultStreamBufferSize];
+        }
+
+        public UnixClient Client {
+            get { return _client; }
+        }
+
+        public Stream Stream
+        {
+            get { return _stream; }
+        }
+
+        public DateTime ControlTime
+        {
+            get { return _controlTime; }
+            set { _controlTime = value; }
+        }
+
+        // This is a "thread safe" buffer that can be used by 
+        // UnixClientTransportSink to read or send data to the stream.
+        // The buffer is "thread safe" since only one thread can
+        // use a connection at a given time.
+        public byte[] Buffer
+        {
+            get { return _buffer; }
+        }
+
+        public void Close()
+        {
+            _client.Close();
+        }
+    }
+
+}

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientTransportSinkProvider.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientTransportSinkProvider.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixClientTransportSinkProvider.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,62 @@
+//
+// System.Runtime.Remoting.Channels.Unix.UnixClientTransportSinkProvider.cs
+//
+// Author: Dietmar Maurer (dietmar at ximian.com)
+//     Lluis Sanchez (lsg at ctv.es)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.Remoting.Channels;
+
+namespace BooBinding.Remoting
+{
+    internal class UnixClientTransportSinkProvider : IClientChannelSinkProvider
+    {
+        public UnixClientTransportSinkProvider ()
+        {
+            // what should we do here ?
+        }
+
+        public IClientChannelSinkProvider Next
+        {
+            get 
+            {
+                return null;
+            }
+
+            set 
+            {
+                // ignore, we are always the last in the chain 
+            }
+        }
+
+        public IClientChannelSink CreateSink (IChannelSender channel, string url,
+                                              object remoteChannelData)
+        {
+            return new UnixClientTransportSink (url);
+        }
+    }
+}

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixListener.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixListener.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixListener.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,179 @@
+//
+// UnixListener.cs
+//
+// Authors:
+//	Joe Shaw (joeshaw at novell.com)
+//
+// Copyright (C) 2004-2005 Novell, Inc.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.IO;
+
+using Mono.Posix;
+
+namespace BooBinding.Remoting {
+
+	public class UnixListener : IDisposable {
+		bool disposed;
+		bool listening;
+		Socket server;
+		EndPoint savedEP;
+ 
+		void Init (UnixEndPoint ep)
+		{
+			Cleanup (ep);
+			listening = false;
+			string filename = ep.Filename;
+			if (File.Exists (filename)) {
+				Socket conn = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
+				try {
+					conn.Connect (ep);
+					conn.Close ();
+					throw new InvalidOperationException ("There's already a server listening on " + filename);
+				} catch (SocketException se) {
+				}
+				File.Delete (filename);
+			}
+
+			server = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
+			server.Bind (ep);
+			savedEP = server.LocalEndPoint;
+		}
+        
+		public UnixListener (string path)
+		{
+			if (!Directory.Exists (Path.GetDirectoryName (path)))
+				Directory.CreateDirectory (Path.GetDirectoryName (path));
+            
+			Init (new UnixEndPoint (path));
+		}
+
+		public UnixListener (UnixEndPoint localEndPoint)
+		{
+			if (localEndPoint == null)
+				throw new ArgumentNullException ("localendPoint");
+
+			Init (localEndPoint);
+		}
+        
+		public EndPoint LocalEndpoint {
+			get { return savedEP; }
+		}
+        
+		protected Socket Server {
+			get { return server; }
+		}
+        
+		public Socket AcceptSocket ()
+		{
+			CheckDisposed ();
+			if (!listening)
+				throw new InvalidOperationException ("Socket is not listening");
+
+			return server.Accept ();
+		}
+        
+		public UnixClient AcceptUnixClient ()
+		{
+			CheckDisposed ();
+			if (!listening)
+				throw new InvalidOperationException ("Socket is not listening");
+
+			return new UnixClient (AcceptSocket ());
+		}
+        
+		~UnixListener ()
+		{
+			Dispose (false);
+		}
+    
+		public bool Pending ()
+		{
+			CheckDisposed ();
+			if (!listening)
+				throw new InvalidOperationException ("Socket is not listening");
+
+			return server.Poll (1000, SelectMode.SelectRead);
+		}
+        
+		public void Start ()
+		{
+			Start (5);
+		}
+        
+		public void Start (int backlog)
+		{
+			CheckDisposed ();
+			if (listening)
+				return;
+
+			server.Listen (backlog);
+			listening = true;
+		}
+
+		public void Stop ()
+		{
+			CheckDisposed ();
+			Dispose (true);
+		}
+
+		public void Dispose ()
+		{
+			Dispose (true);
+			GC.SuppressFinalize (this);
+		}
+
+		protected void Dispose (bool disposing)
+		{
+			if (disposed)
+				return;
+
+			if (disposing) {
+				if (server != null)
+					server.Close ();
+
+				server = null;
+			}
+
+			disposed = true;
+		}
+        
+		void CheckDisposed ()
+		{
+			if (disposed)
+				throw new ObjectDisposedException (GetType().FullName);
+		}        
+
+		static void Cleanup (UnixEndPoint ep)
+		{
+			string path = ((UnixEndPoint) ep).Filename;
+			if (File.Exists (path))
+				File.Delete (path);
+		}
+	}
+
+}

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixMessageIO.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixMessageIO.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixMessageIO.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,281 @@
+// System.Runtime.Remoting.Channels.Unix.UnixMessageIO.cs
+//
+// Author: Lluis Sanchez Gual (lluis at ideary.com)
+//
+// (C) 2002 Lluis Sanchez Gual
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Collections;
+using System.IO;
+using System.Text;
+using System.Net.Sockets;
+using System.Runtime.Remoting.Channels;
+
+namespace BooBinding.Remoting 
+{
+    enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
+
+    internal class UnixMessageIO
+    {
+        static byte[][] _msgHeaders = 
+            {
+                new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
+                new byte[] { 255, 255, 255, 255, 255, 255 }
+            };
+                            
+        public static int DefaultStreamBufferSize = 1000;
+
+        // Identifies an incoming message
+        public static MessageStatus ReceiveMessageStatus (Stream networkStream)
+        {
+            try
+            {
+                bool[] isOnTrack = new bool[_msgHeaders.Length];
+                bool atLeastOneOnTrack = true;
+                int i = 0;
+
+                while (atLeastOneOnTrack)
+                {
+                    atLeastOneOnTrack = false;
+                    byte c = (byte)networkStream.ReadByte();
+                    for (int n = 0; n<_msgHeaders.Length; n++)
+                    {
+                        if (i > 0 && !isOnTrack[n]) continue;
+
+                        isOnTrack[n] = (c == _msgHeaders[n][i]);
+                        if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
+                        atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
+                    }
+                    i++;
+                }
+                return MessageStatus.Unknown;
+            }
+            catch (IOException e)
+            {
+                // Stream closed
+                return MessageStatus.CancelSignal;
+            }
+        }
+
+        public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
+        {
+            if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
+
+            // Writes the message start header
+            byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
+            networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
+
+            // Writes header tag (0x0000 if request stream, 0x0002 if response stream)
+            if(requestHeaders[CommonTransportKeys.RequestUri]!=null) buffer [0] = (byte) 0;
+            else buffer[0] = (byte) 2;
+            buffer [1] = (byte) 0 ;
+
+            // Writes ID
+            buffer [2] = (byte) 0;
+
+            // Writes assemblyID????
+            buffer [3] = (byte) 0;
+
+            // Writes the length of the stream being sent (not including the headers)
+            int num = (int)data.Length;
+            buffer [4] = (byte) num;
+            buffer [5] = (byte) (num >> 8);
+            buffer [6] = (byte) (num >> 16);
+            buffer [7] = (byte) (num >> 24);
+            networkStream.Write(buffer, 0, 8);
+    
+            // Writes the message headers
+            SendHeaders (networkStream, requestHeaders, buffer);
+
+            // Writes the stream
+            if (data is MemoryStream)
+            {
+                // The copy of the stream can be optimized. The internal
+                // buffer of MemoryStream can be used.
+                MemoryStream memStream = (MemoryStream)data;
+                networkStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
+            }
+            else
+            {
+                int nread = data.Read (buffer, 0, buffer.Length);
+                while (nread > 0)
+                {
+                    networkStream.Write (buffer, 0, nread);
+                    nread = data.Read (buffer, 0, buffer.Length);
+                }
+            }
+        }
+
+        private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)
+        {
+            // Writes the headers as a sequence of strings
+            if (networkStream != null)
+            {
+                IEnumerator e = requestHeaders.GetEnumerator();
+                while (e.MoveNext())
+                {
+                    DictionaryEntry hdr = (DictionaryEntry)e.Current;
+                    switch (hdr.Key.ToString())
+                    {
+                    case CommonTransportKeys.RequestUri: 
+                        buffer[0] = 4; buffer[1] = 0; buffer[2] = 1;
+                        networkStream.Write(buffer, 0, 3);
+                        break;
+                    case "Content-Type": 
+                        buffer[0] = 6; buffer[1] = 0; buffer[2] = 1;
+                        networkStream.Write(buffer, 0, 3);
+                        break;
+                    default: 
+                        buffer[0] = 1; buffer[1] = 0; buffer[2] = 1;
+                        networkStream.Write(buffer, 0, 3);
+                        SendString (networkStream, hdr.Key.ToString(), buffer);
+                        break;
+                    }
+                    networkStream.WriteByte (1);
+                    SendString (networkStream, hdr.Value.ToString(), buffer);
+                }
+            }
+            networkStream.WriteByte (0);    // End of headers
+            networkStream.WriteByte (0);
+        }
+        
+        public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
+        {
+            byte headerType;
+            headerType = (byte) networkStream.ReadByte ();
+            networkStream.ReadByte ();
+
+            TransportHeaders headers = new TransportHeaders ();
+
+            while (headerType != 0)
+            {
+                string key;
+                networkStream.ReadByte ();    // byte 1
+                switch (headerType)
+                {
+                case 4: key = CommonTransportKeys.RequestUri; break;
+                case 6: key = "Content-Type"; break;
+                case 1: key = ReceiveString (networkStream, buffer); break;
+                default: throw new NotSupportedException ("Unknown header code: " + headerType);
+                }
+                networkStream.ReadByte ();    // byte 1
+                headers[key] = ReceiveString (networkStream, buffer);
+
+                headerType = (byte) networkStream.ReadByte ();
+                networkStream.ReadByte ();
+            }
+
+            return headers;
+        }
+        
+        public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer)
+        {
+            headers = null;
+
+            if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
+
+            // Reads header tag:  0 -> Stream with headers or 2 -> Response Stream
+            byte head = (byte)networkStream.ReadByte();
+            byte c = (byte)networkStream.ReadByte();
+
+            c = (byte)networkStream.ReadByte();
+            c = (byte)networkStream.ReadByte();
+
+            // Gets the length of the data stream
+            int nr = 0;
+            while (nr < 4)
+                nr += networkStream.Read (buffer, nr, 4 - nr);
+
+            int byteCount = (buffer [0] | (buffer [1] << 8) |
+                             (buffer [2] << 16) | (buffer [3] << 24));
+
+            // Reads the headers
+            headers = ReceiveHeaders (networkStream, buffer);
+
+            byte[] resultBuffer = new byte[byteCount];
+
+            nr = 0;
+            while (nr < byteCount)
+                nr += networkStream.Read (resultBuffer, nr, byteCount - nr);
+
+            
+            return new MemoryStream(resultBuffer);
+        }        
+
+        private static void SendString (Stream networkStream, string str, byte[] buffer)
+        {
+            // Allocates a buffer. Use the internal buffer if it is 
+            // big enough. If not, create a new one.
+
+            int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4;    //+4 bytes for storing the string length
+            if (maxBytes > buffer.Length)
+                buffer = new byte[maxBytes];
+
+            int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
+
+            // store number of bytes (not number of chars!)
+
+            buffer [0] = (byte) num;
+            buffer [1] = (byte) (num >> 8);
+            buffer [2] = (byte) (num >> 16);
+            buffer [3] = (byte) (num >> 24);
+
+            // Write the string bytes
+            networkStream.Write (buffer, 0, num + 4);
+        }
+
+        private static string ReceiveString (Stream networkStream, byte[] buffer)
+        {
+            int nr = 0;
+            while (nr < 4)
+                nr += networkStream.Read (buffer, nr, 4 - nr);
+
+            // Reads the number of bytes (not chars!)
+
+            int byteCount = (buffer [0] | (buffer [1] << 8) |
+                             (buffer [2] << 16) | (buffer [3] << 24));
+
+            if (byteCount == 0) return string.Empty;
+
+            // Allocates a buffer of the correct size. Use the
+            // internal buffer if it is big enough
+
+            if (byteCount > buffer.Length)
+                buffer = new byte[byteCount];
+
+            // Reads the string
+
+            nr = 0;
+            while (nr < byteCount)
+                nr += networkStream.Read (buffer, nr, byteCount - nr);
+
+            char[] chars = Encoding.UTF8.GetChars(buffer, 0, byteCount);
+    
+            return new string(chars);
+        }
+        
+    }
+}

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixServerChannel.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixServerChannel.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixServerChannel.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,328 @@
+//
+// System.Runtime.Remoting.Channels.Unix.UnixServerChannel.cs
+//
+// Author: Rodrigo Moya (rodrigo at ximian.com)
+//     Lluis Sanchez Gual (lluis at ideary.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Runtime.Remoting.Messaging;
+using System.Text.RegularExpressions;
+using System.Net.Sockets;
+using System.Net;
+using System.Threading;
+using System.IO;
+using System.Runtime.Remoting.Channels;
+
+namespace BooBinding.Remoting
+{
+    public class UnixServerChannel : IChannelReceiver, IChannel
+    {
+        string path = null;
+        string name = "unix";
+
+        int priority = 1;
+        bool supressChannelData = false;
+        bool useIpAddress = false;
+        
+        IPAddress bindAddress = IPAddress.Any;
+        Thread server_thread = null;
+        UnixListener listener;
+        UnixServerTransportSink sink;
+        ChannelDataStore channel_data;
+        int _maxConcurrentConnections = 100;
+        ArrayList _activeConnections = new ArrayList();
+        
+        
+        void Init (IServerChannelSinkProvider serverSinkProvider) 
+        {
+            if (serverSinkProvider == null) 
+            {
+                serverSinkProvider = new BinaryServerFormatterSinkProvider ();
+            }
+            
+            // Gets channel data from the chain of channel providers
+
+            channel_data = new ChannelDataStore (null);
+            IServerChannelSinkProvider provider = serverSinkProvider;
+            while (provider != null)
+            {
+                provider.GetChannelData(channel_data);
+                provider = provider.Next;
+            }
+
+            // Creates the sink chain that will process all incoming messages
+
+            IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
+            sink = new UnixServerTransportSink (next_sink);
+        }
+        
+        public UnixServerChannel (string path)
+        {
+            this.path = path;
+            Init (null);
+        }
+
+        public UnixServerChannel (IDictionary properties,
+                                  IServerChannelSinkProvider serverSinkProvider)
+        {
+            foreach(DictionaryEntry property in properties)
+            {
+                switch((string)property.Key)
+                {
+                case "path":
+                    path = property.Value as string;
+                    break;
+                case "priority":
+                    priority = Convert.ToInt32(property.Value);
+                    break;
+                case "supressChannelData":
+                    supressChannelData = Convert.ToBoolean (property.Value);
+                    break;
+                }
+            }            
+            Init (serverSinkProvider);
+        }
+
+        public UnixServerChannel (string name, string path,
+                                  IServerChannelSinkProvider serverSinkProvider)
+        {
+            this.name = name;
+            this.path = path;
+            Init (serverSinkProvider);
+        }
+        
+        public UnixServerChannel (string name, string path)
+        {
+            this.name = name;
+            this.path = path;
+            Init (null);
+        }
+        
+        public object ChannelData
+        {
+            get {
+                if (supressChannelData) return null;
+                else return channel_data;
+            }
+        }
+
+        public string ChannelName
+        {
+            get {
+                return name;
+            }
+        }
+
+        public int ChannelPriority
+        {
+            get {
+                return priority;
+            }
+        }
+
+        public string GetChannelUri ()
+        {
+            return "unix://" + path;
+        }
+        
+        public string[] GetUrlsForUri (string uri)
+        {
+            if (!uri.StartsWith ("/")) uri = "/" + uri;
+
+            string [] chnl_uris = channel_data.ChannelUris;
+            string [] result = new String [chnl_uris.Length];
+
+            for (int i = 0; i < chnl_uris.Length; i++) 
+                result [i] = chnl_uris [i] + uri;
+            
+            return result;
+        }
+
+        public string Parse (string url, out string objectURI)
+        {
+            return UnixChannel.ParseUnixURL (url, out objectURI);
+        }
+
+        void WaitForConnections ()
+        {
+            try
+            {
+                while (true) 
+                {
+                    UnixClient client = listener.AcceptUnixClient ();
+                    CreateListenerConnection (client);
+                }
+            }
+            catch
+            {}
+        }
+
+        internal void CreateListenerConnection (UnixClient client)
+        {
+            lock (_activeConnections)
+                {
+                    if (_activeConnections.Count >= _maxConcurrentConnections)
+                        Monitor.Wait (_activeConnections);
+
+                    if (server_thread == null) return;    // Server was stopped while waiting
+
+                    ClientConnection reader = new ClientConnection (this, client, sink);
+                    Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
+                    thread.Start();
+                    thread.IsBackground = true;
+                    _activeConnections.Add (thread);
+                }
+        }
+
+        internal void ReleaseConnection (Thread thread)
+        {
+            lock (_activeConnections)
+                {
+                    _activeConnections.Remove (thread);
+                    Monitor.Pulse (_activeConnections);
+                }
+        }
+        
+        public void StartListening (object data)
+        {
+            listener = new UnixListener (path);
+            Mono.Unix.Syscall.chmod (path,
+                                     Mono.Unix.FilePermissions.S_IRUSR |
+                                     Mono.Unix.FilePermissions.S_IWUSR |
+                                     Mono.Unix.FilePermissions.S_IRGRP |
+                                     Mono.Unix.FilePermissions.S_IWGRP |
+                                     Mono.Unix.FilePermissions.S_IROTH |
+                                     Mono.Unix.FilePermissions.S_IWOTH);
+
+            if (server_thread == null) 
+            {
+                listener.Start ();
+                
+                string[] uris = new String [1];
+                uris = new String [1];
+                uris [0] = GetChannelUri ();
+                channel_data.ChannelUris = uris;
+
+                server_thread = new Thread (new ThreadStart (WaitForConnections));
+                server_thread.IsBackground = true;
+                server_thread.Start ();
+            }
+        }
+
+        public void StopListening (object data)
+        {
+            if (server_thread == null) return;
+
+            lock (_activeConnections)
+                {
+                    server_thread.Abort ();
+                    server_thread = null;
+                    listener.Stop ();
+
+                    foreach (Thread thread in _activeConnections)
+                        thread.Abort();
+
+                    _activeConnections.Clear();
+                    Monitor.PulseAll (_activeConnections);
+                }
+        }
+    }
+
+    class ClientConnection
+    {
+        UnixClient _client;
+        UnixServerTransportSink _sink;
+        Stream _stream;
+        UnixServerChannel _serverChannel;
+
+        byte[] _buffer = new byte[UnixMessageIO.DefaultStreamBufferSize];
+
+        public ClientConnection (UnixServerChannel serverChannel, UnixClient client, UnixServerTransportSink sink)
+        {
+            _serverChannel = serverChannel;
+            _client = client;
+            _sink = sink;
+        }
+
+        public UnixClient Client {
+            get { return _client; }
+        }
+
+        public Stream Stream
+        {
+            get { return _stream; }
+        }
+
+        public byte[] Buffer
+        {
+            get { return _buffer; }
+        }
+
+        public void ProcessMessages()
+        {
+            _stream = _client.GetStream();
+
+            try
+            {
+                bool end = false;
+                while (!end)
+                {
+                    MessageStatus type = UnixMessageIO.ReceiveMessageStatus (_stream);
+
+                    switch (type)
+                    {
+                    case MessageStatus.MethodMessage:
+                        _sink.InternalProcessMessage (this);
+                        break;
+
+                    case MessageStatus.CancelSignal:
+                        end = true;
+                        break;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                //                Console.WriteLine (ex);
+            }
+            finally
+            {
+                _stream.Close();
+                _serverChannel.ReleaseConnection (Thread.CurrentThread);
+            }
+        }
+        
+        public bool IsLocal
+        {
+            get
+            {
+                return true;
+            }
+        }
+    }
+}

Added: trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixServerTransportSink.cs
===================================================================
--- trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixServerTransportSink.cs	2005-04-27 22:58:24 UTC (rev 2488)
+++ trunk/MonoDevelop/Extras/BooBinding/Remoting/UnixServerTransportSink.cs	2005-04-28 02:38:46 UTC (rev 2489)
@@ -0,0 +1,132 @@
+//
+// System.Runtime.Remoting.Channels.Unix.UnixServerTransportSink.cs
+//
+// Author: Rodrigo Moya (rodrigo at ximian.com)
+//     Lluis Sanchez Gual (lsg at ctv.es)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Runtime.Remoting.Messaging;
+using System.IO;
+using System.Runtime.Remoting.Channels;
+using Mono.Posix;
+
+namespace BooBinding.Remoting
+{
+    internal class UnixServerTransportSink : IServerChannelSink, IChannelSinkBase
+    {
+        IServerChannelSink next_sink;
+        
+        public UnixServerTransportSink (IServerChannelSink next)
+        {
+            next_sink = next;
+        }
+        
+        public IServerChannelSink NextChannelSink 
+        {
+            get 
+            {
+                return next_sink;
+            }
+        }
+
+        public IDictionary Properties 
+        {
+            get 
+            {
+                if (next_sink != null) return next_sink.Properties;
+                else return null;
+            }
+        }
+
+        public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
+                                          IMessage msg, ITransportHeaders headers, Stream responseStream)
+        {
+            ClientConnection connection = (ClientConnection)state;
+            UnixMessageIO.SendMessageStream (connection.Stream, responseStream, headers, connection.Buffer);
+        }
+
+        public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
+                                         IMessage msg, ITransportHeaders headers)
+        {
+            return null;
+        }
+        
+        public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
+                                                IMessage requestMsg,
+                                                ITransportHeaders requestHeaders,
+                                                Stream requestStream,
+                                                out IMessage responseMsg,
+                                                out ITransportHeaders responseHeaders,
+                                                out Stream responseStream)
+        {
+            // this is the first sink, and UnixServerChannel does not call it.
+            throw new NotSupportedException ();
+        }
+
+        internal void InternalProcessMessage (ClientConnection connection)
+        {
+            // Reads the headers and the request stream
+
+            Stream requestStream;
+            ITransportHeaders requestHeaders;
+
+            requestStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out requestHeaders, connection.Buffer);
+
+            try {
+                PeerCred cred = connection.Client.PeerCredential;
+                requestHeaders["__uid"] = cred.UserID;
+            } catch (Exception e) {
+                Console.WriteLine ("Couldn't get the peer cred: " + e);
+            }
+
+            // Pushes the connection object together with the sink. This information
+            // will be used for sending the response in an async call.
+
+            ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
+            sinkStack.Push(this, connection);
+
+            ITransportHeaders responseHeaders;
+            Stream responseStream;
+            IMessage responseMsg;
+
+            ServerProcessing proc = next_sink.ProcessMessage(sinkStack, null, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
+
+            switch (proc)
+            {
+            case ServerProcessing.Complete:
+                UnixMessageIO.SendMessageStream (connection.Stream, responseStream, responseHeaders, connection.Buffer);
+                break;
+
+            case ServerProcessing.Async:
+            case ServerProcessing.OneWay:
+                break;
+            }
+        }
+    }
+}
+




More information about the Monodevelop-patches-list mailing list