diff options
author | Diva Canto | 2011-04-30 09:24:15 -0700 |
---|---|---|
committer | Diva Canto | 2011-04-30 09:24:15 -0700 |
commit | d8ee0cbe1cf93ca521f52ce39aa2a15cb5784e48 (patch) | |
tree | 4958279e2c75dcfa50021a8e559fb6ddc0a76725 /OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |
parent | Delaying starting the scripts on TPs and crossings until the agent is root. (diff) | |
download | opensim-SC-d8ee0cbe1cf93ca521f52ce39aa2a15cb5784e48.zip opensim-SC-d8ee0cbe1cf93ca521f52ce39aa2a15cb5784e48.tar.gz opensim-SC-d8ee0cbe1cf93ca521f52ce39aa2a15cb5784e48.tar.bz2 opensim-SC-d8ee0cbe1cf93ca521f52ce39aa2a15cb5784e48.tar.xz |
First stab at cleaning up Caps. Compiles. Untested.
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs new file mode 100644 index 0000000..6eebd9d --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006, Clutch, Inc. | ||
3 | * Original Author: Jeff Cesnik | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * - Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * | ||
9 | * - Redistributions of source code must retain the above copyright notice, this | ||
10 | * list of conditions and the following disclaimer. | ||
11 | * - Neither the name of the openmetaverse.org nor the names | ||
12 | * of its contributors may be used to endorse or promote products derived from | ||
13 | * this software without specific prior written permission. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||
19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
25 | * POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Net; | ||
30 | using System.Net.Sockets; | ||
31 | using System.Threading; | ||
32 | using log4net; | ||
33 | |||
34 | namespace OpenMetaverse | ||
35 | { | ||
36 | /// <summary> | ||
37 | /// Base UDP server | ||
38 | /// </summary> | ||
39 | public abstract class OpenSimUDPBase | ||
40 | { | ||
41 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
42 | |||
43 | /// <summary> | ||
44 | /// This method is called when an incoming packet is received | ||
45 | /// </summary> | ||
46 | /// <param name="buffer">Incoming packet buffer</param> | ||
47 | protected abstract void PacketReceived(UDPPacketBuffer buffer); | ||
48 | |||
49 | /// <summary>UDP port to bind to in server mode</summary> | ||
50 | protected int m_udpPort; | ||
51 | |||
52 | /// <summary>Local IP address to bind to in server mode</summary> | ||
53 | protected IPAddress m_localBindAddress; | ||
54 | |||
55 | /// <summary>UDP socket, used in either client or server mode</summary> | ||
56 | private Socket m_udpSocket; | ||
57 | |||
58 | /// <summary>Flag to process packets asynchronously or synchronously</summary> | ||
59 | private bool m_asyncPacketHandling; | ||
60 | |||
61 | /// <summary>The all important shutdown flag</summary> | ||
62 | private volatile bool m_shutdownFlag = true; | ||
63 | |||
64 | /// <summary>Returns true if the server is currently listening, otherwise false</summary> | ||
65 | public bool IsRunning { get { return !m_shutdownFlag; } } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Default constructor | ||
69 | /// </summary> | ||
70 | /// <param name="bindAddress">Local IP address to bind the server to</param> | ||
71 | /// <param name="port">Port to listening for incoming UDP packets on</param> | ||
72 | public OpenSimUDPBase(IPAddress bindAddress, int port) | ||
73 | { | ||
74 | m_localBindAddress = bindAddress; | ||
75 | m_udpPort = port; | ||
76 | } | ||
77 | |||
78 | /// <summary> | ||
79 | /// Start the UDP server | ||
80 | /// </summary> | ||
81 | /// <param name="recvBufferSize">The size of the receive buffer for | ||
82 | /// the UDP socket. This value is passed up to the operating system | ||
83 | /// and used in the system networking stack. Use zero to leave this | ||
84 | /// value as the default</param> | ||
85 | /// <param name="asyncPacketHandling">Set this to true to start | ||
86 | /// receiving more packets while current packet handler callbacks are | ||
87 | /// still running. Setting this to false will complete each packet | ||
88 | /// callback before the next packet is processed</param> | ||
89 | /// <remarks>This method will attempt to set the SIO_UDP_CONNRESET flag | ||
90 | /// on the socket to get newer versions of Windows to behave in a sane | ||
91 | /// manner (not throwing an exception when the remote side resets the | ||
92 | /// connection). This call is ignored on Mono where the flag is not | ||
93 | /// necessary</remarks> | ||
94 | public void Start(int recvBufferSize, bool asyncPacketHandling) | ||
95 | { | ||
96 | m_asyncPacketHandling = asyncPacketHandling; | ||
97 | |||
98 | if (m_shutdownFlag) | ||
99 | { | ||
100 | const int SIO_UDP_CONNRESET = -1744830452; | ||
101 | |||
102 | IPEndPoint ipep = new IPEndPoint(m_localBindAddress, m_udpPort); | ||
103 | |||
104 | m_log.DebugFormat( | ||
105 | "[UDPBASE]: Binding UDP listener using internal IP address config {0}:{1}", | ||
106 | ipep.Address, ipep.Port); | ||
107 | |||
108 | m_udpSocket = new Socket( | ||
109 | AddressFamily.InterNetwork, | ||
110 | SocketType.Dgram, | ||
111 | ProtocolType.Udp); | ||
112 | |||
113 | try | ||
114 | { | ||
115 | // This udp socket flag is not supported under mono, | ||
116 | // so we'll catch the exception and continue | ||
117 | m_udpSocket.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); | ||
118 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag set"); | ||
119 | } | ||
120 | catch (SocketException) | ||
121 | { | ||
122 | m_log.Debug("[UDPBASE]: SIO_UDP_CONNRESET flag not supported on this platform, ignoring"); | ||
123 | } | ||
124 | |||
125 | if (recvBufferSize != 0) | ||
126 | m_udpSocket.ReceiveBufferSize = recvBufferSize; | ||
127 | |||
128 | m_udpSocket.Bind(ipep); | ||
129 | |||
130 | // we're not shutting down, we're starting up | ||
131 | m_shutdownFlag = false; | ||
132 | |||
133 | // kick off an async receive. The Start() method will return, the | ||
134 | // actual receives will occur asynchronously and will be caught in | ||
135 | // AsyncEndRecieve(). | ||
136 | AsyncBeginReceive(); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /// <summary> | ||
141 | /// Stops the UDP server | ||
142 | /// </summary> | ||
143 | public void Stop() | ||
144 | { | ||
145 | if (!m_shutdownFlag) | ||
146 | { | ||
147 | // wait indefinitely for a writer lock. Once this is called, the .NET runtime | ||
148 | // will deny any more reader locks, in effect blocking all other send/receive | ||
149 | // threads. Once we have the lock, we set shutdownFlag to inform the other | ||
150 | // threads that the socket is closed. | ||
151 | m_shutdownFlag = true; | ||
152 | m_udpSocket.Close(); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | private void AsyncBeginReceive() | ||
157 | { | ||
158 | // allocate a packet buffer | ||
159 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut(); | ||
160 | UDPPacketBuffer buf = new UDPPacketBuffer(); | ||
161 | |||
162 | if (!m_shutdownFlag) | ||
163 | { | ||
164 | try | ||
165 | { | ||
166 | // kick off an async read | ||
167 | m_udpSocket.BeginReceiveFrom( | ||
168 | //wrappedBuffer.Instance.Data, | ||
169 | buf.Data, | ||
170 | 0, | ||
171 | UDPPacketBuffer.BUFFER_SIZE, | ||
172 | SocketFlags.None, | ||
173 | ref buf.RemoteEndPoint, | ||
174 | AsyncEndReceive, | ||
175 | //wrappedBuffer); | ||
176 | buf); | ||
177 | } | ||
178 | catch (SocketException e) | ||
179 | { | ||
180 | if (e.SocketErrorCode == SocketError.ConnectionReset) | ||
181 | { | ||
182 | m_log.Warn("[UDPBASE]: SIO_UDP_CONNRESET was ignored, attempting to salvage the UDP listener on port " + m_udpPort); | ||
183 | bool salvaged = false; | ||
184 | while (!salvaged) | ||
185 | { | ||
186 | try | ||
187 | { | ||
188 | m_udpSocket.BeginReceiveFrom( | ||
189 | //wrappedBuffer.Instance.Data, | ||
190 | buf.Data, | ||
191 | 0, | ||
192 | UDPPacketBuffer.BUFFER_SIZE, | ||
193 | SocketFlags.None, | ||
194 | ref buf.RemoteEndPoint, | ||
195 | AsyncEndReceive, | ||
196 | //wrappedBuffer); | ||
197 | buf); | ||
198 | salvaged = true; | ||
199 | } | ||
200 | catch (SocketException) { } | ||
201 | catch (ObjectDisposedException) { return; } | ||
202 | } | ||
203 | |||
204 | m_log.Warn("[UDPBASE]: Salvaged the UDP listener on port " + m_udpPort); | ||
205 | } | ||
206 | } | ||
207 | catch (ObjectDisposedException) { } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | private void AsyncEndReceive(IAsyncResult iar) | ||
212 | { | ||
213 | // Asynchronous receive operations will complete here through the call | ||
214 | // to AsyncBeginReceive | ||
215 | if (!m_shutdownFlag) | ||
216 | { | ||
217 | // Asynchronous mode will start another receive before the | ||
218 | // callback for this packet is even fired. Very parallel :-) | ||
219 | if (m_asyncPacketHandling) | ||
220 | AsyncBeginReceive(); | ||
221 | |||
222 | // get the buffer that was created in AsyncBeginReceive | ||
223 | // this is the received data | ||
224 | //WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState; | ||
225 | //UDPPacketBuffer buffer = wrappedBuffer.Instance; | ||
226 | UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState; | ||
227 | |||
228 | try | ||
229 | { | ||
230 | // get the length of data actually read from the socket, store it with the | ||
231 | // buffer | ||
232 | buffer.DataLength = m_udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint); | ||
233 | |||
234 | // call the abstract method PacketReceived(), passing the buffer that | ||
235 | // has just been filled from the socket read. | ||
236 | PacketReceived(buffer); | ||
237 | } | ||
238 | catch (SocketException) { } | ||
239 | catch (ObjectDisposedException) { } | ||
240 | finally | ||
241 | { | ||
242 | //wrappedBuffer.Dispose(); | ||
243 | |||
244 | // Synchronous mode waits until the packet callback completes | ||
245 | // before starting the receive to fetch another packet | ||
246 | if (!m_asyncPacketHandling) | ||
247 | AsyncBeginReceive(); | ||
248 | } | ||
249 | |||
250 | } | ||
251 | } | ||
252 | |||
253 | public void AsyncBeginSend(UDPPacketBuffer buf) | ||
254 | { | ||
255 | if (!m_shutdownFlag) | ||
256 | { | ||
257 | try | ||
258 | { | ||
259 | m_udpSocket.BeginSendTo( | ||
260 | buf.Data, | ||
261 | 0, | ||
262 | buf.DataLength, | ||
263 | SocketFlags.None, | ||
264 | buf.RemoteEndPoint, | ||
265 | AsyncEndSend, | ||
266 | buf); | ||
267 | } | ||
268 | catch (SocketException) { } | ||
269 | catch (ObjectDisposedException) { } | ||
270 | } | ||
271 | } | ||
272 | |||
273 | void AsyncEndSend(IAsyncResult result) | ||
274 | { | ||
275 | try | ||
276 | { | ||
277 | // UDPPacketBuffer buf = (UDPPacketBuffer)result.AsyncState; | ||
278 | m_udpSocket.EndSendTo(result); | ||
279 | } | ||
280 | catch (SocketException) { } | ||
281 | catch (ObjectDisposedException) { } | ||
282 | } | ||
283 | } | ||
284 | } | ||