2 // System.Net.NetworkInformation.NetworkChange
5 // Gonzalo Paniagua Javier (gonzalo@novell.com)
7 // Copyright (c) 2006,2011 Novell, Inc. (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Net.Sockets;
30 using System.Runtime.InteropServices;
31 using System.Threading;
33 namespace System.Net.NetworkInformation {
34 public sealed class NetworkChange {
37 Availability = 1 << 0,
41 static object _lock = new object ();
42 static Socket nl_sock;
43 static SocketAsyncEventArgs nl_args;
44 static EventType pending_events;
47 static NetworkAddressChangedEventHandler AddressChanged;
48 static NetworkAvailabilityChangedEventHandler AvailabilityChanged;
50 private NetworkChange ()
54 public static event NetworkAddressChangedEventHandler NetworkAddressChanged {
55 add { Register (value); }
56 remove { Unregister (value); }
59 public static event NetworkAvailabilityChangedEventHandler NetworkAvailabilityChanged {
60 add { Register (value); }
61 remove { Unregister (value); }
64 //internal Socket (AddressFamily family, SocketType type, ProtocolType proto, IntPtr sock)
66 static bool EnsureSocket ()
71 IntPtr fd = CreateNLSocket ();
72 if (fd.ToInt64 () == -1)
75 nl_sock = new Socket (0, SocketType.Raw, ProtocolType.Udp, fd);
76 nl_args = new SocketAsyncEventArgs ();
77 nl_args.SetBuffer (new byte [8192], 0, 8192);
78 nl_args.Completed += OnDataAvailable;
79 nl_sock.ReceiveAsync (nl_args);
84 // _lock is held by the caller
85 static void MaybeCloseSocket ()
87 if (nl_sock == null || AvailabilityChanged != null || AddressChanged != null)
90 CloseNLSocket (nl_sock.Handle);
91 GC.SuppressFinalize (nl_sock);
96 static bool GetAvailability ()
98 NetworkInterface [] adapters = NetworkInterface.GetAllNetworkInterfaces ();
99 foreach (NetworkInterface n in adapters) {
100 // TODO: also check for a default route present?
101 if (n.NetworkInterfaceType == NetworkInterfaceType.Loopback)
103 if (n.OperationalStatus == OperationalStatus.Up)
109 static void OnAvailabilityChanged (object unused)
111 NetworkAvailabilityChangedEventHandler d = AvailabilityChanged;
112 d (null, new NetworkAvailabilityEventArgs (GetAvailability ()));
115 static void OnAddressChanged (object unused)
117 NetworkAddressChangedEventHandler d = AddressChanged;
118 d (null, EventArgs.Empty);
121 static void OnEventDue (object unused)
125 evts = pending_events;
127 timer.Change (-1, -1);
129 if ((evts & EventType.Availability) != 0)
130 ThreadPool.QueueUserWorkItem (OnAvailabilityChanged);
131 if ((evts & EventType.Address) != 0)
132 ThreadPool.QueueUserWorkItem (OnAddressChanged);
135 static void QueueEvent (EventType type)
139 timer = new Timer (OnEventDue);
140 if (pending_events == 0)
141 timer.Change (150, -1);
142 pending_events |= type;
146 unsafe static void OnDataAvailable (object sender, SocketAsyncEventArgs args)
149 fixed (byte *ptr = args.Buffer) {
150 type = ReadEvents (nl_sock.Handle, new IntPtr (ptr), args.BytesTransferred, 8192);
152 nl_sock.ReceiveAsync (nl_args);
157 static void Register (NetworkAddressChangedEventHandler d)
163 static void Register (NetworkAvailabilityChangedEventHandler d)
166 AvailabilityChanged += d;
169 static void Unregister (NetworkAddressChangedEventHandler d)
177 static void Unregister (NetworkAvailabilityChangedEventHandler d)
180 AvailabilityChanged -= d;
185 #if MONOTOUCH || MONODROID
186 const string LIBNAME = "__Internal";
188 const string LIBNAME = "MonoPosixHelper";
191 [DllImport (LIBNAME, CallingConvention=CallingConvention.Cdecl)]
192 static extern IntPtr CreateNLSocket ();
194 [DllImport (LIBNAME, CallingConvention=CallingConvention.Cdecl)]
195 static extern EventType ReadEvents (IntPtr sock, IntPtr buffer, int count, int size);
197 [DllImport (LIBNAME, CallingConvention=CallingConvention.Cdecl)]
198 static extern IntPtr CloseNLSocket (IntPtr sock);