Read Me About MoreSCF
=====================
1.1

System Configuration framework (SCF) allows you to programmatically configure network settings. SCF provides a nice, abstract, extensible API for manipulating persistent preferences.  However, older versions of the framework do not provide a high-level API.  Thus, prior to Mac OS X 10.4, if you want to do common operations, like creating a new set (known as a "location" in the user interface), you have to combine a number of diverse APIs from I/O Kit, System Configuration, and Core Foundation.

MoreSCF is an attempt to make this easier.  It includes a library of code to do all of the things that the user might do in the Network preferences panel.  For example, you can create a new location, duplicate a location, activate and inactivate services (known as "ports" in the user interface), and so on.  MoreSCF also provides high-level APIs to do common operations, such as creating a new set that contains a single PPP dialup service.

System Configuration framework was introduced in Mac OS X 10.1.  In theory, MoreSCF could work on that system or later.  In practice, I have tested it back to Mac OS X 10.3.

IMPORTANT: If your product requires Mac OS X 10.4 or later, you should use the new, high-level System Configuration framework API instead of MoreSCF.  This API, defined in the "SCNetworkConfiguration.h" header file, includes routines for doing all of things that MoreSCF does.  By using this API you make your code simpler and more future-proof.


Packing List
------------
The sample contains the following items:

o Read Me.txt -- A document that redirects you to this document.

o MoreSCF -- A folder containing MoreSCF and various support files.
  - Read Me About MoreSCF.txt -- This document.
  - MoreSCFHelpers.h -- Interface to the following.
  - MoreSCFHelpers.c -- A high-level module that provides commonly 
    used System Configuration framework functions, such as creating 
    a new set that contains a single PPP dialup service.
  - MoreSCF.h -- Interface to the following.
  - MoreSCF.c -- A mid-level module layered on top of the SCPreferences 
    component of System Configuration framework. This module recasts 
    the SCPreferences API in terms that you would recognize from 
    looking at the Network preferences panel.
  - MoreSCFDigest.h -- Interface to the following.
  - MoreSCFDigest.c -- Code to create SCPreferences entities from 
    simple C structures.
  - MoreSCFPortScanner.h -- Interface to the following.
  - MoreSCFPortScanner.c -- Code to scan the I/O Registry for 
    network-capable ports.
  - MoreSCFCCLScanner.h -- Interface to the following.
  - MoreSCFCCLScanner.c -- Code to scan the system for modem scripts (CCLs).
  - MoreSCFTest -- A program that both tests MoreSCF and gives an example 
    of its use.

o MoreCFQ -- MoreIsBetter Core Foundation utilities.


Using the Sample
----------------
The sample includes a compiled version of the MoreSCFTest command line tool.  This tool modifies the SCF preferences, which means you must run it as root.  The following example assumes that you've downloaded the sample to your desktop:

$ sudo Desktop/MoreSCF/MoreSCF/MoreSCFTest/build/Debug/MoreSCFTest -lq
Password: ********
MoreSCFTest
Running all tests

LeakTest(TestPortScanner)
LeakTest(TestPortScannerOld)
MoreSCFPortScanner.c: You should install a port name callback.
LeakTest(TestCCLScanner)
LeakTest(TestCopySetsDict)
LeakTest(TestSetEnumerationAndSwitch)
LeakTest(TestDuplicateAndDeleteSet)
LeakTest(TestRenameSet)
LeakTest(TestServiceEnumerate)
LeakTest(TestDuplicateAndDeleteService)
LeakTest(TestRenameService)
LeakTest(TestEnumerateEntities)
LeakTest(TestCreateSet)
LeakTest(TestISP)
LeakTest(TestAppleTalk)
LeakTest(TestTrivialCreate)

You can also run an individual test by naming it as an argument:

$ Desktop/MoreSCF/MoreSCF/MoreSCFTest/build/Debug/MoreSCFTest TestCCLScanner
MoreSCFTest
TestCCLScanner
   3Com Impact Analog 14.4
   3Com Impact ISDN 56K
   3Com Impact ISDN 56K MLPPP
   3Com Impact ISDN 64K
   3Com Impact ISDN 64K MLPPP
   Apple External 56K Modem (v.32)
   Apple External 56K Modem (v.34)
   Apple External 56K Modem (v.90)
   Apple External 56K Modem (v.92)
   Apple Internal 56K Modem (v.32)
   Apple Internal 56K Modem (v.34)
 * Apple Internal 56K Modem (v.90)
   Apple Internal 56K Modem (v.92)
[...]

When running all tests the tool takes quite some time to run (up to a few minutes on my ancient test machine).  As long as it runs to completion it should leave your network preferences how it found them.  However, if you stop it halfway through you may need to manually restore your preferences.

Some of the tests requires that you have a location called "DefaultLocationForMoreSCFTest".  You should create this location using the Network panel of System Preferences.  Just create the location and leave its settings unmodified.  The test uses this location to verify that a new set created by MoreSCF exactly matches a default set created by the control panel.

Note: Under some circumstances the TestCreateSet test will fail because the newly created set doesn't exactly match the contents of "DefaultLocationForMoreSCFTest".  There are a few common reasons for this.

o Your "DefaultLocationForMoreSCFTest" set might be is out of date; to rectify this simply open the control panel, deleting the existing "DefaultLocationForMoreSCFTest" location and create a new one.

o You might have NetInfo enabled; to rectify this, turn off NetInfo using the "Directory Setup" application, then update your "DefaultLocationForMoreSCFTest" set as described previously.

o The "DefaultLocationForMoreSCFTest" might be set to use non-DHCP address acquisition (in the "Configure" popup menu).  This can happen if you create the new set when your current set is not using DHCP.  In that case the Network preferences panel creates a set with the same address acquisition mode as your current set.  This anomalous behavior is not replicated by MoreSCF.  To make TestCreateSet run without error, open the Network preferences panel and modify the services within the "DefaultLocationForMoreSCFTest" set to acquire address via PPP.


Building the Sample
-------------------
The sample was built using Xcode 2.4.1 on Mac OS X 10.4.8.  To build the sample, open the MoreSCFTest project file (MoreSCF/MoreSCFTest/MoreSCFTest.xcodeproj) and choose Build from the Build menu.  By default this builds the Debug build configuration, resulting in a new executable tool (MoreSCF/MoreSCFTest/build/Debug/MoreSCFTest).

Note: When you build the Intel side of the universal binary, you'll see warnings of the form:

    #warning MoreSCF is deprecated if you are building for 10.4 or later.

This is because MoreSCF is not recommended for use on Mac OS X 10.4 and later (you should instead use the nice high-level API from "SCNetworkConfiguration.h"), and all Intel-based Macintosh computers 10.4 or later.  If you get this warning, you should consider removing MoreSCF from your product and using the System Configuration framework directly.  If that's not feasible, you can quieten the warning by setting the MORE_SCF_NO_DEPRECATION_WARNINGS compile-time variable.


SCF Hints and Tips
------------------
This section describes a number of things to keep in mind while working with SCF, or indeed MoreSCF.

o Documentation -- You can find System Configuration framework documentation in the Darwin > Networking section of the ADC Reference Library.  The current URLs on the Apple developer web site are:

<http://developer.apple.com/documentation/Networking/Conceptual/SystemConfigFrameworks/index.html>
<http://developer.apple.com/documentation/Networking/Reference/SysConfig/index.html>

o Running with Privileges -- Code that modifies the System Configuration framework preferences must run as root (with effective user ID of 0).  There are simple ways to work around this during development (described below).  However, your final product will need to be smarter about this, possibly including privileged helper tool to do the actual SCF work.  For more information, see the various documents and samples in the Security > Authorization section of the ADC Reference Library.

<http://developer.apple.com/referencelibrary/Security/idxAuthorization-date.html>

o SCF Preferences -- Current versions of Mac OS X store SCF preferences in "/Library/Preferences/SystemConfiguration/preferences.plist".  You should never code this full path into your application, but this knowledge can be helpful when debugging.  For example:

  - You can launch PropertyListEditor (in "/Developer/Applications/Utilities") 
    and open this file for a structured view of the current preferences.

  - You can back up and restore your preferences using the following 
    Terminal commands.  This is especially useful when debugging SCF code 
    that has gone bad.

    $ sudo cp /Library/Preferences/SystemConfiguration/preferences.plist \
    /Library/Preferences/SystemConfiguration/preferences-bu.plist
    $ sudo cp /Library/Preferences/SystemConfiguration/preferences-bu.plist \
    /Library/Preferences/SystemConfiguration/preferences.plist

o scutil -- Apple provides a command line utility, <x-man-page://8/scutil>, that lets you look at the current state of the SCF dynamic store.  You can use this utility to see how your SCF code affects the actual network configuration.  The following is a simple example of how to use scutil.

    $ scutil
    > list
      subKey [0] = DirectoryService:PID
      subKey [1] = Plugin:IPConfiguration
      subKey [2] = Setup:
      subKey [3] = Setup:/
      subKey [4] = Setup:/Network/Global/IPv4
      subKey [5] = Setup:/Network/HostNames
      subKey [6] = Setup:/Network/Interface/en1/AirPort
      subKey [7] = Setup:/Network/Service/[...]
      subKey [8] = Setup:/Network/Service/[...]/IPv4
      subKey [9] = Setup:/Network/Service/[...]/IPv6
      subKey [10] = Setup:/Network/Service/[...]/Interface
      subKey [11] = Setup:/Network/Service/[...]/Proxies
      subKey [12] = Setup:/Network/Service/[...]
      subKey [13] = Setup:/Network/Service/[...]/Ethernet
      subKey [14] = Setup:/Network/Service/[...]/IPv4
      subKey [15] = Setup:/Network/Service/[...]/IPv6
      subKey [16] = Setup:/Network/Service/[...]/Interface
      subKey [17] = Setup:/Network/Service/[...]/Proxies
      subKey [18] = Setup:/System
      subKey [19] = State:/IOKit/PowerManagement/CurrentSettings
      subKey [20] = State:/Network/Global/DNS
      subKey [21] = State:/Network/Global/IPv4
      subKey [22] = State:/Network/Global/Proxies
      subKey [23] = State:/Network/Interface
      subKey [24] = State:/Network/Interface/en0/IPv4
      subKey [25] = State:/Network/Interface/en0/IPv6
      subKey [26] = State:/Network/Interface/en0/Link
      subKey [27] = State:/Network/Interface/en1/AirPort
      subKey [28] = State:/Network/Interface/fw1/Link
      subKey [29] = State:/Network/Interface/lo0/IPv4
      subKey [30] = State:/Network/Interface/lo0/IPv6
      subKey [31] = State:/Network/Service/[...]/DHCP
      subKey [32] = State:/Network/Service/[...]/DNS
      subKey [33] = State:/Network/Service/[...]/IPv4
      subKey [34] = State:/Users/ConsoleUser
      subKey [35] = com.apple.BluetoothMenuExtraStatus
      subKey [36] = com.apple.DirectoryService.[...]:DirectoryNodeAdded
      subKey [37] = com.apple.DirectoryService.[...]:DirectoryNodeDeleted
    > show Setup:/Network/Service/[...]/IPv4
    <dictionary> {
      ConfigMethod : DHCP
    }
    > help
    
    Available commands:
    
     help                          : list available commands
     f.read file                   : process commands from file
     quit                          : quit
    
     d.init                        : initialize (empty) dictionary
     d.show                        : show dictionary contents
     d.add key [*#?] val [v2 ...]  : add information to dictionary
           (*=array, #=number, ?=boolean)
     d.remove key                  : remove key from dictionary
    
     list [pattern]                : list keys in data store
     add key ["temporary"]         : add key in data store w/current dict
     get key                       : get dict from data store w/key
     set key                         : set key in data store w/current dict
     show key ["pattern"]          : show values in data store w/key
     remove key                    : remove key from data store
     notify key                    : notify key in data store
    
     n.list ["pattern"]            : list notification keys
     n.add key ["pattern"]         : add notification key
     n.remove key ["pattern"]      : remove notification key
     n.changes                     : list changed keys
     n.watch [verbose]             : watch for changes
     n.cancel                      : cancel notification requests
    
    > quit


Debugging Root Binaries
-----------------------
If you are using SCF to modify system preferences, you'll quickly discover that your program needs to run as root (with an effective user ID of 0) to avoid the dreaded error 1003 (kSCStatusAccessError).  There are two simple ways to get around this during debugging.

o You can enable the root account, log out, and then log back in as root.  At that point all of the programs you run will run as root.  This approach has the advantage that it's very simple.  However, it's not particularly secure; I recommend you avoid this approach if your Mac OS X machine lives outside of a firewall.

For information on enabling the root account, see DTS Q&A 1013 "Mac OS X and root access".

  <http://developer.apple.com/qa/qa2001/qa1013.html>

o If you have administrative privileges, you can launch Xcode as root using "sudo":

$ # Prime sudo credentials 
$ sudo -v
Password:
$ # Run Xcode and don't wait for it
$ sudo /Developer/Applications/Xcode.app/Contents/MacOS/Xcode &
[1] 9760

o If you're familiar with command line GDB, you can just debug your program using that:

$ sudo gdb Desktop/MoreSCF/MoreSCF/MoreSCFTest/build/Debug/MoreSCFTest 

IMPORTANT: These techniques are fine for debugging but are not appropriate for your final product.  Ultimately you will need a better solution.  See the "Running with Privileges" section, above, for more information.


Using MoreSCF In Your Code
--------------------------
The correct way to use MoreSCF depends on the exact needs of your program.  The following sections explore this issue in detail.

Coding Conventions
- - - - - - - - -
MoreSCF is built as part of the DTS sample code library MoreIsBetter.  It only uses the Core Services framework, which makes it easy to use from both Carbon and Cocoa applications.  Making MoreSCF independent of Core Services would be tricky because MoreSCF needs to be able to locate the Modem Scripts folder which can only be done with Core Services APIs.

MoreSCF makes extensive use of asserts.  When you integrate MoreSCF into your build system you should ensure that "assert" maps to whatever assert mechanism you are using in your project.

MoreSCF's asserts act like comments for the exact function semantics.  Specifically, if you want to know whether NULL is legal for a particular parameter, look at the asserts at the top of the routine.

MoreSCF follows the Core Foundation (CF) coding convention in that routines with "Create" or "Copy" in the name return a reference which you must release, whereas other routines (most commonly with "Get" in the name) return a reference that you don't need to release.  However, unlike CF, MoreSCF returns OSStatus error codes from virtually all functions. W hen you call a MoreSCF routine that allocates an object, you get the result by passing the address of a variable as a parameter to the routine. You must initialize this variable to NULL before calling the routine. The value of the variable will be NULL if the routine returns an error.

Big Picture
- - - - - -
MoreSCF consists of a number of related modules.  As a rule I recommend that you use the highest level routines that will get the job done.  This section describes each of the MoreSCF modules, how they relate, and what you can do with them.

o MoreSCFCCLScanner -- This module contains a routine that a creates a list of CCLs (modem scripts) installed in the system and returns that list along with an indication of which CCL should be the default. An Internet setup assistant would use this routine to present the user with a list of CCLs to choose from if they are connecting via a modem.

It is unlikely that you would need to customize the routines in this module.

o MoreSCFPortScanner -- This module contains code that searches the I/O Registry for all possible network ports.  For each port it returns the information necessary to create an SCF service that uses the port.  This facility is crucial when you create a new set using SCF.

This is not as easy as it sounds.  The code is derived from code originally written by the engineer who wrote the Network preferences panel.  It contains many interesting heuristics to decide whether a port is suitable for networking and to determine its user visible name.

If you link this module into a GUI-based application you should install a port name callback (using MoreSCFSetPortNameCallback) so that you can localize the user visible names of the ports.

You should probably use the routines in this module unmodified unless you experience compatibility problems.

Note: If you're running on Mac OS X 10.4 or later, this module uses the high-level API provided by SCF (SCNetworkInterfaceCopyAll), which makes it much less error prone.

o MoreSCFDigest -- This module contains code that allows you to easily create a SCF entity from a C structure.  It takes care of many of the fiddly details of this process, such as converting IP addresses to strings, encoding PPP passwords, and so on.

In most cases you would use the routines from this module unmodified, although sometimes the routines provide a simplified view of certain preferences and you might want to override some of their default decisions.

o MoreSCF -- This module is layered on top of the previous two modules.  It provides a mid-level API for manipulating SCF preferences.  The module exports four categories of routines:

- trivial utilities, primarily to map SCF's error strategy into a CoreServices-based environment

- open/close routines, which provide a reference counted facility for opening and closing the SCF preferences; this is convenient because it ensures that changes are committed only at the end of a transaction

- dictionary-based routines, which provide basic access to the most important SCF preferences

- mid-level routines, for manipulating the SCF preferences in terms of common user operations (for example, creating a set, deactivating a service, modifying an entity)

I expect that you would use the routines from this module unmodified.  If you need to do complex SCF operations you'll probably find that either a) an appropriate routine is already provided in MoreSCFHelpers, or b) you can achieve the results you want by calling various routines exported by this module.

o MoreSCFHelpers -- This module is layered on top of MoreSCF and exports routines for doing very high-level operations using SCF, such as

- turning AppleTalk on and off (MoreSCSetAppleTalkActive),

- forcing a DHCP release (MoreSCDHCPRelease), and

- creating a new dialup set (or PPPoE) from preferences provided via a number of parameter blocks (MoreSCMakeNewDialupSet and MoreSCMakeNewPPPoESet).

You should treat these routines as sample code; if they don't meet your exact needs you should modify them appropriately.  For example, MoreSCMakeNewPPPoESet provides no way to create a PPPoE location for an AirPort interface, but it is simple to modify it to do so.

Getting Started
- - - - - - - -
This section describes the MoreSCF routines needed to do the most common high-level operations.

Opening, Closing, Locking
-  -  -  -  -  -  -  -  -
MoreSCF uses a single connection to SCF preferences for all of its work.  To support a flexible API MoreSCF references counts that reference.  The first time you call MoreSCOpen, MoreSCF creates a SCPreferencesRef and stores it in a global variable.  Every subsequent time you call the MoreSCOpen, it simply increments the reference count.  Every time you call MoreSCClose, it decrements the reference count.  When the reference count drops to zero, MoreSCF commits any changes you might have made, unlocks the preferences if you have locked them, and then closes the SCPreferencesRef.

The primary rationale for this approach is that I did not want clients of MoreSCF to be forced to call MoreSCOpen. Thus, each exported MoreSCF routine calls MoreSCOpen when it starts and MoreSCClose when it finishes.  This presented an interesting problem when MoreSCF routines called other MoreSCF routines.  I wanted all of the MoreSCF routines to share the same SCPreferencesRef (otherwise they wouldn't see each others changes until they committed them), however I didn't want to cache the SCPreferencesRef forever because that caused other problems with preference coherency.  My ultimate solution was to simply reference count the SCPreferencesRef.

Given the above there are some cases when you don't need to call MoreSCOpen at all.  Each MoreSCF API routine will call MoreSCOpen for you.  However, in most circumstances you should call MoreSCOpen and MoreSCClose. This has a number of advantages:

o When you call MoreSCOpen, MoreSCF creates an SCPreferencesRef.  This in turn holds a snapshot of the current preferences.  You can then make subsequent MoreSCF calls and be assured that you're seeing a coherent copy of the preferences.

o Calls to MoreSCF routines within a MoreSCOpen/MoreSCClose pair will be faster because they won't be continually creating and disposing of their connection to SCF preferences.

o If you're making changes to the preferences you generally need to call MoreSCOpen so that you can lock the preferences and ensure that your changes are coherent.

The standard calling sequence, used for the first two cases above, is shown below.

(void) MoreSCSetClient(CFSTR("MyClientName")); // optional

err = MoreSCOpen(false, false);                // no locking
if (err == noErr) {
    // use various MoreSCF routines in here
}
MoreSCClose(&err, false);                      // no changes
If you are making changes you would probably use the next sequence.

err = MoreSCOpen(true, true);                  // lock prefs
if (err == noErr) {
    // read preferences using MoreSCF routines
    // make decisions based on what you read
    // write preferences using MoreSCF routines
}
MoreSCClose(&err, true);                       // force commit

MoreSCF also provides a routine (MoreSCGetSCPreferencesRef) that allows you to access the underlying SCPreferencesRef.  This is useful in cases where you need to call SCF preferences routines that do things outside of the realm of MoreSCF (for example, calling SCPreferencesGetSignature).

Creating a New Dialup Set
-  -  -  -  -  -  -  -  -
Most people look at MoreSCF because they're writing an Internet setup assistant (ISA).  MoreSCF contains routines that specifically help you to do this.  However, before I discuss these routines I should stress one key point.

Apple strongly recommends that ISA developers create a new set (known as a "location" in the user interface) for their specific service.  This prevents your settings from overwriting the user's prized network setup and allows the user a quick escape (switching back to their previous location) if your setup assistant doesn't work properly.

If you're writing an ISA, the three keys routines are MoreSCFindSetByUserVisibleNameAndCopyID, MoreSCMakeNewDialupSet and MoreSCMakeNewPPPoESet.  The first routine lets you determine whether your ISA has already been run and created your service's location.  The other two let you create a new location with one active dialup or PPPoE service.  All of these routines are described in comments in "MoreSCFHelpers.h".  You can also look at the TestISP routine in "MoreSCFTest.c" for a very simple example of their use.

The above routines are very easy to use if you want to use the default modem (or Ethernet) port.  If you want to provide the user a list of modem ports to choose from, you should call the MoreSCCreatePortArray routine (declared in "MoreSCFPortScanner.h") to get the list of network ports and their associated user-visible names and then supply the BSD name of the port to MoreSCMakeNewDialupSet or MoreSCMakeNewPPPoESet.  For dialup you should also use MoreSCCreateCCLArray (from "MoreSCFCCLScanner.h") to build a list of CCLs (modem scripts) that the user can use for that modem.

Enumerating and Switching Sets
-  -  -  -  -  -  -  -  -  -
The routines to enumerate and switch sets are all declared in "MoreSCF.h".  You can use MoreSCCopySetIDs to get an array of set IDs, MoreSCCopyUserVisibleNameOfSet to get the user-visible name of a set given its set ID, and MoreSCSetCurrentSet to make a particular set the active set.

Manipulating Sets, Services, and Entities
-  -  -  -  -  -  -  -  -  -  -  -  -  -
MoreSCF exports routines to:

o enumerate, create, duplicate, and delete sets

o get and set properties of sets (the active set, user-visible name)
enumerate, create, duplicate, and delete services within a set

o get and set properties for services (active, user-visible name, BSD name)

o read, write, and delete entities within a service

o read, write, and delete global entities within a set

o get and set properties of an entity (active)

These routines are fairly well documented by the comments in the "MoreSCF.h" header file. Most of the routines are used somewhere within MoreSCF, which you can look at for an example of their use.

Caveats
-------
The following is a list of odd things you might encounter while working with MoreSCF and things I would improve within MoreSCF if I had the time.

o The Network preferences panel in Mac OS X 10.1.x does not correctly reflect changes made by other applications using SCF.  You will not see any MoreSCF changes in the Network panel until you quit and relaunch System Preferences.  The problem is in the UI; the changes do apply to the actual network stack.  This bug has been fixed on current versions of Mac OS X.

o MoreSCDeleteService lets you delete the last service for a hardware port within a set. This is bad because the Network preferences panel doesn't let you do this (in the Network panel you would inactivate rather than delete that port).  MoreSCDeleteService should enforce this restriction.  I know how to fix this but the issue has never been of sufficiently high priority for me to implement the fix.

o MoreSCCreateAirPortEntity isn't flexible enough to create all types of AirPort entities.  There are a number of keys that are described in "SCSchemaDefinitions.h" that can't be set by calling MoreSCCreateAirPortEntity.  I need to research what these keys do and how best to reflect them in MoreSCAirPortDigest <rdar://problem/3138423>.  See the comment in MoreSCCreateAirPortEntity for a list of the keys in question.

o I should implement a mutable version of MoreSCCopyEntities (MoreSCCopyEntitiesMutable).

o MoreSCCreateCCLArray (in "MoreSCFCCLScanner.c") contains a hardwired name for the "Apple Internal 56K Modem (v.90)" modem script.  If this script isn't present it chooses the first script in the first Modem Scripts folder.  This is the same behavior as the Network panel of System Preferences.  You can (and generally should) override this default when you create a new modem service.  You can do this using MoreSCSetDefaultCCL.  Ideally Apple should provide an intelligent modem detection library that can query the modem and determine the correct script.  As this currently isn't available, MoreSCF provides a routine to return the information necessary to build a modem scripts popup menu so that the user can choose the correct script by hand.

o Many of the functions tagged with "*** more testing needed" in the headers have been tested implicitly because other functions call them, however I should test them explicitly by adding more code to "MoreSCFTest.c".

o I have gone to great lengths to track down any reference count leaks in my use of the SCF preferences database.  However, it's possible that there are other non-database leaks in MoreSCF, particularly in my use of Core Foundation.

o When you open an SCPreferencesRef, SCF creates a coherent in-memory copy of the preferences database.  When you make changes to the SCPreferencesRef, you're actually making changes to the memory copy.  When you commit those changes, SCF writes the database to disk and notifies other users that the database has changed.  This sequence has important consequences for the design of MoreSCF.  I used to open one SCPreferencesRef and keep it open for the lifetime of the library in memory.  However, this architecture meant that, if someone else changed the database, clients of MoreSCF would never see that change.  My new design involves reference counting.  When the reference count drops to zero, MoreSCF closes its SCPreferencesRef.  The next time a client calls MoreSCOpen MoreSCF creates a new copy of the SCPreferencesRef and picks up any changes made by any other SCF clients.

o Another consequence of the above occurs when you attempt to commit your changes and the commit fails. The symptom you will see is that MoreSCClose will return an error. Because we only commit when the reference count drops to zero, an error from MoreSCClose indicates that we attempted to commit and failed (hence the changes aren't on disk) and we also closed the SCPreferencesRef (hence the changes are no longer in memory). When you next call MoreSCOpen you will get a fresh, coherent copy of the preferences from disk, including any changes made by other SCF clients.  In summary, the outermost MoreSCClose is a commit or rollback operation; if it returns noErr, the commit was successful; if it returns an error, the commit failed and we roll you back to the last coherent database state (which may not be the state that you last saw).


Credits and Version History
---------------------------
If you find any problems with this sample, mail <dts@apple.com> and I'll try to fix them up.

1.0d1 (Nov 2001) was released to a single developer for testing.

1.0d2 (Dec 2001) was released to small number of developers for testing.

1.0d3 (Dec 2001) was released to the same small number of developers.

1.0a1 (Jan 2002) was sent out for Apple internal review.

1.0b1 (Feb 2002) is the first widely released version.

1.0b2 (Aug 2002) is a fix to ensure compatibility with Mac OS X 10.2. The primary change is a workaround for <rdar://problem/3024328> in MakeNewSeAndCopyIDAndPath in "MoreSCF.c".  While I had the code open I also fixed some minor stuff, like changing the default PPP option values.

1.0b3 (Aug 2002) is a minor update to incorporate some engineering feedback about the previous change.

1.0b4 (Feb 2003) is a significant update that will only be distributed to a small number of people pending more testing.  Changes include:

o Overall
  - Reworked how the pre-compiled headers and C++ compatibility work.
  - Updated to latest MoreIsBetter coding standards.
  - Updated to the latest MoreCFQ code.
  - Added support for V.92 modem hold.
  - Fixed code that sets the default config method for IPv4 entities.
  - Updated to latest CodeWarrior and Project Builder.
o CCL Scanner
  - A new exported routine, MoreSCSetDefaultCCL.
  - Eliminated dependency on Launch Services.  I was only using it to test 
    for file visibility, but using it brings in all of Application Services.
o Port Scanner
  - Corrected a bug where some devices would cause MoreSCF to crash.
  - Now translates slot names into user friendly numbers, just like the 
    Mac OS X 10.2 Network preferences panel.
  - Now handles USB "Product Name" more like the Network preferences panel.
  - Fixed a bug related to the handling of the BSD name.
o Helpers
  - Reworked the code used to implement MoreSCMakeNewDialupSet to support 
    new features (MoreSCMakeNewPPPoESet) and the newly exported routine 
    (MoreSCMakeNewSingleServiceSet).

1.1 (Apr 2007) is another significant update.  Changes include:

o Adopt latest MoreIsBetter conventions (no CodeWarrior, Mach-O required, 10.2 and later required).
o MoreSCFPortScanner now uses a system-provided API (SCNetworkInterfaceCopyAll) if it's available.
o Support for Bluetooth, FireWire and IPv6.
o A large number of bug fixes and compatibility changes.

Share and Enjoy.

Apple Developer Technical Support
Core OS/Hardware

19 Apr 2007
