2 // Mono.Remoting.Channels.Unix.UnixServerChannel.cs
4 // Author: Rodrigo Moya (rodrigo@ximian.com)
5 // Lluis Sanchez Gual (lluis@ideary.com)
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
33 using System
.Runtime
.Remoting
.Messaging
;
34 using System
.Text
.RegularExpressions
;
35 using System
.Net
.Sockets
;
37 using System
.Threading
;
39 using System
.Runtime
.Remoting
.Channels
;
42 namespace Mono
.Remoting
.Channels
.Unix
44 public class UnixServerChannel
: IChannelReceiver
, IChannel
50 bool supressChannelData
= false;
52 Thread server_thread
= null;
53 UnixListener listener
;
54 UnixServerTransportSink sink
;
55 ChannelDataStore channel_data
;
56 int _maxConcurrentConnections
= 100;
57 ArrayList _activeConnections
= new ArrayList();
60 void Init (IServerChannelSinkProvider serverSinkProvider
)
62 if (serverSinkProvider
== null)
64 serverSinkProvider
= new UnixBinaryServerFormatterSinkProvider ();
67 // Gets channel data from the chain of channel providers
69 channel_data
= new ChannelDataStore (null);
70 IServerChannelSinkProvider provider
= serverSinkProvider
;
71 while (provider
!= null)
73 provider
.GetChannelData(channel_data
);
74 provider
= provider
.Next
;
77 // Creates the sink chain that will process all incoming messages
79 IServerChannelSink next_sink
= ChannelServices
.CreateServerChannelSinkChain (serverSinkProvider
, this);
80 sink
= new UnixServerTransportSink (next_sink
);
82 StartListening (null);
85 public UnixServerChannel (string path
)
91 public UnixServerChannel (IDictionary properties
,
92 IServerChannelSinkProvider serverSinkProvider
)
94 foreach(DictionaryEntry property
in properties
)
96 switch((string)property
.Key
)
99 path
= property
.Value
as string;
102 priority
= Convert
.ToInt32(property
.Value
);
104 case "supressChannelData":
105 supressChannelData
= Convert
.ToBoolean (property
.Value
);
109 Init (serverSinkProvider
);
112 public UnixServerChannel (string name
, string path
,
113 IServerChannelSinkProvider serverSinkProvider
)
117 Init (serverSinkProvider
);
120 public UnixServerChannel (string name
, string path
)
127 public object ChannelData
130 if (supressChannelData
) return null;
131 else return channel_data
;
135 public string ChannelName
142 public int ChannelPriority
149 public string GetChannelUri ()
151 return "unix://" + path
;
154 public string[] GetUrlsForUri (string uri
)
156 if (!uri
.StartsWith ("/")) uri
= "/" + uri
;
158 string [] chnl_uris
= channel_data
.ChannelUris
;
159 string [] result
= new String
[chnl_uris
.Length
];
161 for (int i
= 0; i
< chnl_uris
.Length
; i
++)
162 result
[i
] = chnl_uris
[i
] + "?" + uri
;
167 public string Parse (string url
, out string objectURI
)
169 return UnixChannel
.ParseUnixURL (url
, out objectURI
);
172 void WaitForConnections ()
178 Socket client
= listener
.AcceptSocket ();
179 CreateListenerConnection (client
);
186 internal void CreateListenerConnection (Socket client
)
188 lock (_activeConnections
)
190 if (_activeConnections
.Count
>= _maxConcurrentConnections
)
191 Monitor
.Wait (_activeConnections
);
193 if (server_thread
== null) return; // Server was stopped while waiting
195 ClientConnection reader
= new ClientConnection (this, client
, sink
);
196 Thread thread
= new Thread (new ThreadStart (reader
.ProcessMessages
));
198 thread
.IsBackground
= true;
199 _activeConnections
.Add (thread
);
203 internal void ReleaseConnection (Thread thread
)
205 lock (_activeConnections
)
207 _activeConnections
.Remove (thread
);
208 Monitor
.Pulse (_activeConnections
);
212 public void StartListening (object data
)
214 listener
= new UnixListener (path
);
215 Mono
.Unix
.Native
.Syscall
.chmod (path
,
216 Mono
.Unix
.Native
.FilePermissions
.S_IRUSR
|
217 Mono
.Unix
.Native
.FilePermissions
.S_IWUSR
|
218 Mono
.Unix
.Native
.FilePermissions
.S_IRGRP
|
219 Mono
.Unix
.Native
.FilePermissions
.S_IWGRP
|
220 Mono
.Unix
.Native
.FilePermissions
.S_IROTH
|
221 Mono
.Unix
.Native
.FilePermissions
.S_IWOTH
);
223 if (server_thread
== null)
227 string[] uris
= new String
[1];
228 uris
= new String
[1];
229 uris
[0] = GetChannelUri ();
230 channel_data
.ChannelUris
= uris
;
232 server_thread
= new Thread (new ThreadStart (WaitForConnections
));
233 server_thread
.IsBackground
= true;
234 server_thread
.Start ();
238 public void StopListening (object data
)
240 if (server_thread
== null) return;
242 lock (_activeConnections
)
244 server_thread
.Abort ();
245 server_thread
= null;
248 foreach (Thread thread
in _activeConnections
)
251 _activeConnections
.Clear();
252 Monitor
.PulseAll (_activeConnections
);
257 class ClientConnection
260 UnixServerTransportSink _sink
;
262 UnixServerChannel _serverChannel
;
264 byte[] _buffer
= new byte[UnixMessageIO
.DefaultStreamBufferSize
];
266 public ClientConnection (UnixServerChannel serverChannel
, Socket client
, UnixServerTransportSink sink
)
268 _serverChannel
= serverChannel
;
273 public Socket Client
{
274 get { return _client; }
279 get { return _buffer; }
282 public void ProcessMessages()
284 byte[] buffer
= new byte[256];
285 _stream
= new BufferedStream (new NetworkStream (_client
));
292 MessageStatus type
= UnixMessageIO
.ReceiveMessageStatus (_stream
, buffer
);
296 case MessageStatus
.MethodMessage
:
297 _sink
.InternalProcessMessage (this, _stream
);
300 case MessageStatus
.Unknown
:
301 case MessageStatus
.CancelSignal
:
309 // Console.WriteLine (ex);
315 _serverChannel
.ReleaseConnection (Thread
.CurrentThread
);