Sign in Join
Wiki copytemporary

macOS SCNetworkReachability API: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: macOS SCNetworkReachability API

OldNewLine
1+*(macOS only)*
2+
3+## Overview
4+
5+The `SCNetworkReachability` programming interface allows an application to determine the status of a system's current network configuration and the reachability of a target host. A remote host is considered reachable when a data packet, sent by an application into the network stack, can leave the local device. Reachability does not guarantee that the data packet will actually be received by the host.
6+
7+The SCNetworkReachability programming interface supports a synchronous and an asynchronous model. In the synchronous model, you get the reachability status by calling the *SCNetworkReachabilityGetFlags* function. In the asynchronous model, you can schedule the SCNetworkReachability object on the run loop of a client object’s thread. The client implements a callback function to receive notifications when the reachability status of a given remote host changes. Note that these functions follow Core Foundation naming conventions. A function that has "Create" or "Copy" in its name returns a reference you must release with the CFRelease function.
8+
9+The example below implements the asynchronous model which is useful for monitoring connectivity.
10+
11+## Example code
12+
13+``` pascal
14+{
15+Pascal GUI version of the Apple sample command line utility SimpleReach in C
16+which demonstrates the System Configuration framework reachability APIs.
17+https://developer.apple.com/library/archive/samplecode/SimpleReach/Introduction
18+/Intro.html#//apple_ref/doc/uid/DTS10003238
19+}
20+
21+unit Unit1;
22+
23+{$mode objfpc}{$H+}
24+{$linkframework SystemConfiguration}
25+
26+interface
27+
28+uses
29+ SysUtils, Forms, StdCtrls, MacOSAll, Controls;
30+
31+type
32+
33+ { TForm1 }
34+
35+ TForm1 = class(TForm)
36+ MonitorButton: TButton;
37+ QuitButton: TButton;
38+ HostnameEdit: TEdit;
39+ HostnameLabel: TLabel;
40+ Memo1: TMemo;
41+ procedure FormKeyPress(Sender: TObject; var Key: char);
42+ procedure MonitorButtonClick(Sender: TObject);
43+ procedure QuitButtonClick(Sender: TObject);
44+ private
45+
46+ public
47+
48+ end;
49+
50+ // pocedure requires mwpascal calling convention
51+ type TProcedure = procedure(target: SCNetworkReachabilityRef;
52+ flags: SCNetworkConnectionFlags; info: pointer); mwpascal;
53+
54+var
55+ Form1: TForm1;
56+ callout: TProcedure;
57+ monitoring: Boolean = False;
58+
59+implementation
60+
61+{$R *.lfm}
62+
63+{ TForm1 }
64+
65+// Print flag meanings
66+procedure print_header;
67+begin
68+ Form1.Memo1.Lines.Add('T' + #09 + 'kSCNetworkFlagsTransientConnection');
69+ Form1.Memo1.Lines.Add('R' + #09 + 'kSCNetworkFlagsReachable');
70+ Form1.Memo1.Lines.Add('C' + #09 + 'kSCNetworkFlagsConnectionRequired');
71+ Form1.Memo1.Lines.Add('A' + #09 + 'kSCNetworkFlagsConnectionAutomatic');
72+ Form1.Memo1.Lines.Add('I' + #09 + 'kSCNetworkFlagsInterventionRequired');
73+ Form1.Memo1.Lines.Add('L' + #09 + 'kSCNetworkFlagsIsLocalAddress');
74+ Form1.Memo1.Lines.Add('D' + #09 + 'kSCNetworkFlagsIsDirect' + LineEnding);
75+end;
76+
77+// The procedure to print current reachability flags
78+procedure print_flags(flags: SCNetworkConnectionFlags);
79+var
80+ statusStr: String;
81+begin
82+ statusStr := DateTimeToStr(Now) + ' : ';
83+
84+ // The specified node name or address can be reached via a transient
85+ // connection, such as PPP.
86+ if(flags and kSCNetworkFlagsTransientConnection > 0) then
87+ statusStr := statusStr + 'T'
88+ else
89+ statusStr := statusStr + '-';
90+
91+ // The specified node name or address can be reached using the current network
92+ // configuration.
93+ if(flags and kSCNetworkFlagsReachable > 0) then
94+ statusStr := statusStr + 'R'
95+ else
96+ statusStr := statusStr + '-';
97+
98+ // The specified node name or address can be reached using the current network
99+ // configuration, but a connection must first be established.
100+ // eg Returned for a dialup connection that was not currently active
101+ if(flags and kSCNetworkFlagsConnectionRequired > 0) then
102+ statusStr := statusStr + 'C'
103+ else
104+ statusStr := statusStr + '-';
105+
106+ // The specified node name or address can be reached using the current network
107+ // configuration, but a connection must first be established.
108+ // Any traffic directed to the specified name or address will initiate the
109+ // connection
110+ if(flags and kSCNetworkFlagsConnectionAutomatic > 0) then
111+ statusStr := statusStr + 'A'
112+ else
113+ statusStr := statusStr + '-';
114+
115+ // The specified node name or address can be reached using the current network
116+ // configuration, but a connection must first be established.
117+ // Returned when there is a dial-on-traffic configuration and manual
118+ // intervention required eg due to no dial tone, password etc.
119+ if(flags and kSCNetworkFlagsInterventionRequired > 0) then
120+ statusStr := statusStr + 'I'
121+ else
122+ statusStr := statusStr + '-';
123+
124+ // The specified node name or address is one associated with a network
125+ // interface on the current system.
126+ if(flags and kSCNetworkFlagsIsLocalAddress > 0) then
127+ statusStr := statusStr + 'L'
128+ else
129+ statusStr := statusStr + '-';
130+
131+ // Network traffic to the specified node name or address does not go through
132+ // a gateway, but is routed directly to one of the interfaces in the system.
133+ if(flags and kSCNetworkFlagsIsDirect > 0) then
134+ statusStr := statusStr + 'D'
135+ else
136+ statusStr := statusStr + '-';
137+
138+ Form1.Memo1.Lines.Add(statusStr);
139+end;
140+
141+// The procedure to be called when the reachability of the target changes.
142+procedure status_callback(target: SCNetworkReachabilityRef; flags: SCNetworkConnectionFlags; info: pointer); mwpascal;
143+begin
144+ print_flags(flags);
145+end;
146+
147+// Start monitoring/ Stop monitoring
148+procedure TForm1.MonitorButtonClick(Sender: TObject);
149+var
150+ context: SCNetworkReachabilityContext;
151+ hostname: PChar;
152+ charArray: Array[0..254] of Char;
153+ count: Integer;
154+ status: boolean;
155+ target: SCNetworkReachabilityRef;
156+begin
157+ // Action iff we have text in HostnameEdit.Text
158+ if(length(HostnameEdit.Text) = 0) then
159+ exit;
160+
161+ // Update monitoring status
162+ if(monitoring = True) then
163+ begin
164+ // Remove our callback from the runloop.
165+ SCNetworkReachabilityUnscheduleFromRunLoop(target, CFRunLoopGetCurrent, kCFRunLoopDefaultMode);
166+ // Update status of button, memo, flag
167+ MonitorButton.Caption := 'Monitor';
168+ Form1.Memo1.Lines.Add('Monitoring stopped');
169+ monitoring := False;
170+ exit;
171+ end;
172+
173+ // Set flag
174+ monitoring := True;
175+ MonitorButton.Caption := 'Stop';
176+
177+ // Print flag meanings
178+ print_header;
179+
180+ // Convert HostnameEdit.Text to PChar; ensure final char is null
181+ hostname := charArray;
182+ for count := 0 to 254 do
183+ hostname[count] := #00;
184+ for count := 0 to Length(HostnameEdit.Text) do
185+ hostname[count] := HostnameEdit.Text[count + 1];
186+
187+ // Setup the context structure for the callback - we just use the hostname
188+ context.copyDescription := Nil; // Nil if unused
189+ context.info := hostname; // C pointer to user-specified block of data
190+ context.release := Nil; // Nil if unused
191+ context.retain := Nil; // Nil if unused
192+ context.version := 0; // Structure version always zero
193+
194+ // Setup our callback procedure variable to be called when the reachability of
195+ // the target changes.
196+ callout := @status_callback;
197+
198+ Try
199+ // Create the target from the hostname
200+ target := SCNetworkReachabilityCreateWithName(Nil, hostname);
201+
202+ // Set our callback
203+ status := SCNetworkReachabilitySetCallback(target, callout, context);
204+ if(status <> true) then
205+ Form1.Memo1.Lines.Add('callback status err: ' + BoolToStr(status));
206+
207+ // Install our callback on the runloop.
208+ status := SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetCurrent, kCFRunLoopDefaultMode);
209+ if(status <> true) then
210+ Form1.Memo1.Lines.Add('schedule status err: ' + BoolToStr(status));
211+ Finally
212+ // Housekeeping
213+ CFRelease(target);
214+ End;
215+end;
216+
217+// Allow ENTER key to trigger Monitor Button
218+// Form1.KeyPreview must be set to True in code/Obj Inspector
219+procedure TForm1.FormKeyPress(Sender: TObject; var Key: char);
220+begin
221+ if(key = #13) then
222+ MonitorButton.Click;
223+end;
224+
225+// Exit application
226+procedure TForm1.QuitButtonClick(Sender: TObject);
227+begin
228+ if(monitoring = True) then
229+ begin
230+ MonitorButton.Click;
231+ Application.ProcessMessages;
232+ Sleep(750);
233+ end;
234+
235+ Close;
236+end;
237+
238+end.
239+```
240+
241+## External links
242+
243+- [Apple: SCNetworkReachabilityCreateWithName](https://developer.apple.com/documentation/systemconfiguration/1514904-scnetworkreachabilitycreatewithn).
244+- [Apple: SCNetworkReachabilityGetFlags](https://developer.apple.com/documentation/systemconfiguration/1514924-scnetworkreachabilitygetflags).
245+- [Apple: SCNetworkReachabilityFlags](https://developer.apple.com/documentation/systemconfiguration/scnetworkreachabilityflags).
246+- [Apple: SCNetworkReachabilitySetCallback](https://developer.apple.com/documentation/systemconfiguration/1514903-scnetworkreachabilitysetcallback).
247+- [Apple: SCNetworkReachabilityRef](https://developer.apple.com/documentation/systemconfiguration/scnetworkreachabilityref).
248+- [Apple: SCNetworkReachabilityContext](https://developer.apple.com/documentation/systemconfiguration/scnetworkreachabilitycontext).
249+- [Apple: SCNetworkReachabilityScheduleWithRunLoop](https://developer.apple.com/documentation/systemconfiguration/1514894-scnetworkreachabilityschedulewit).
250+- [Apple: SCNetworkReachabilityUnscheduleFromRunLoop](https://developer.apple.com/documentation/systemconfiguration/1514899-scnetworkreachabilityunschedulef).
251+
252+---
253+*From the Free Pascal wiki, page "macOS SCNetworkReachability API", as it stood on 2021-11-20 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
254+Category: Code
255+Category: Example programs
256+Category: Networking
257+Category: macOS

Back to history