2e92b6328d77164a88d911a5aa646205d727c1e0
[mono.git] / support / mac-reachability.c
1 //
2 // mac-reachability.c: System.Net.NetworkingInformation.NetworkChange
3 // implementation for Mac OS X using SystemConfiguration's
4 // NetworkReachability API.
5 //
6 // Authors:
7 //  Aaron Bockover (abock@xamarin.com)
8 //
9 // Copyright (c) 2013 Xamarin, Inc. (http://www.xamarin.com)
10 //
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:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
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.
29 //
30
31 int mono_sc_reachability_enabled ();
32
33 #if defined(PLATFORM_MACOSX) || defined(TARGET_IOS)
34
35 int
36 mono_sc_reachability_enabled ()
37 {
38         return 1;
39 }
40
41 #include <SystemConfiguration/SCNetworkReachability.h>
42 #include <netinet/in.h>
43
44 typedef void (*mono_sc_reachability_callback)(int);
45
46 typedef struct {
47         SCNetworkReachabilityRef reachability;
48         mono_sc_reachability_callback callback;
49 } mono_sc_reachability;
50
51 mono_sc_reachability * mono_sc_reachability_new (mono_sc_reachability_callback callback);
52 void mono_sc_reachability_free (mono_sc_reachability *reachability);
53 int mono_sc_reachability_is_available (mono_sc_reachability *reachability);
54
55 static int
56 _mono_sc_reachability_is_available (SCNetworkReachabilityFlags flags)
57 {
58         return (flags & kSCNetworkFlagsReachable) && (flags & kSCNetworkFlagsConnectionRequired) == 0;
59 }
60
61 static void
62 _mono_sc_reachability_callback (SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *user)
63 {
64         mono_sc_reachability *reachability;
65         
66         if (user == NULL) {
67                 return;
68         }
69
70         reachability = (mono_sc_reachability *)user;
71         if (reachability->callback == NULL) {
72                 return;
73         }
74
75         reachability->callback (_mono_sc_reachability_is_available (flags));
76 }
77
78 mono_sc_reachability *
79 mono_sc_reachability_new (mono_sc_reachability_callback callback)
80 {
81         struct sockaddr_in zero;
82         SCNetworkReachabilityRef reachability;
83         SCNetworkReachabilityContext context = {0,};
84         mono_sc_reachability *instance;
85
86         if (callback == NULL) {
87                 return NULL;
88         }
89
90         bzero (&zero, sizeof (zero));
91         zero.sin_len = sizeof (zero);
92         zero.sin_family = AF_INET;
93
94         reachability = SCNetworkReachabilityCreateWithAddress (NULL, (const struct sockaddr *)&zero);
95         if (reachability == NULL) {
96                 return NULL;
97         }
98
99         instance = (mono_sc_reachability *)malloc (sizeof (mono_sc_reachability));
100         instance->reachability = reachability;
101         instance->callback = callback;
102
103         context.info = instance;
104
105         if (!SCNetworkReachabilitySetCallback (reachability, _mono_sc_reachability_callback, &context) ||
106                 !SCNetworkReachabilityScheduleWithRunLoop (reachability, CFRunLoopGetCurrent (), kCFRunLoopDefaultMode)) {
107                 mono_sc_reachability_free (instance);
108                 return NULL;
109         }
110
111         return instance;
112 }
113
114 void
115 mono_sc_reachability_free (mono_sc_reachability *reachability)
116 {
117         if (reachability != NULL) {
118                 if (reachability->reachability != NULL) {
119                         SCNetworkReachabilityUnscheduleFromRunLoop (reachability->reachability,
120                                 CFRunLoopGetCurrent (), kCFRunLoopDefaultMode);
121                         CFRelease (reachability->reachability);
122                         reachability->reachability = NULL;
123                 }
124
125                 reachability->callback = NULL;
126                 free (reachability);
127                 reachability = NULL;
128         }
129 }
130
131 int
132 mono_sc_reachability_is_available (mono_sc_reachability *reachability)
133 {
134         SCNetworkReachabilityFlags flags;
135         return reachability != NULL && reachability->reachability != NULL &&
136                 SCNetworkReachabilityGetFlags (reachability->reachability, &flags) &&
137                 _mono_sc_reachability_is_available (flags);
138 }
139
140 #else
141
142 int
143 mono_sc_reachability_enabled ()
144 {
145         return 0;
146 }
147
148 #endif