Problem mounting server, on error it blocks continuing

This is not so much a question as FYI. :smiley: In Lion, when you try to mount a volume and it’s not available, a dialog box appears and warns that the volume can’t be found. This dialog completely blocks all code running on the main thread, even if you use try or timeouts.
I found this because at my office we have 8 server volumes needed to do work, and servers sometimes crap out or go offline. My apps that run processes continually have a full-stop roadblock under Lion. In Snow Leopard, attempting to mount a volume that did not exist would not produce any dialog message, it just quietly didn’t work. Now, the process NetAuthAgent displays this dialog. I’ve found no way to handle it in single threaded AS scripts or Objective-C code.

A solution that I have found that works for me is this. It requires some multithreading.
My application is ASOC and Objective-C.
My main AppDelegate is ASOC.
I have added some other classes that are 100% Objective-C. I call them Helpers and they do things that are easier for me to write in ObjC than messing around with ASOC’s cumbersome syntax of calling native ObjC code. Plus, I am not sure how I pass a @selector object from ASOC to ObjC, and that’s required to do this.

-In the ASOC AppDelegate, I previously called a class method of the ObjC class to mount the volumes. But now I must do something to call a new thread that won’t block the main thread. So…
-In the ObjC class, I have an instance method (starts with minus -) that mounts a server volume. It used to be a class method but that has to change as you’ll see.
-In the ObjC class, I created a new class method (+ plus) like “+(void)doSomethingOnThread”. This method then allocs/inits an instance of it’s own class. I need an instance because of what happens next.
-Then I tell the new instance of the class to performSelectorInBackground: withObject:
-The selector I give to that method is the instance method to mount a volume. (You can’t pass it a class method.)
-So back in the ASOC code, I do a simple call to the ObjC class to do the class method of “+(void)doSomethingOnThread” or whatever you called it. (Making it a class method means I don’t have to alloc/init things in ASOC or do “current application’s blahblahblah”.)
-If it works, then the volume mounts. If it doesn’t and there is an error, the message shows up and blocks the background thread, not the main ObjC thread and thus not the ASOC AppDelegate either.
-In the ASOC file, I have code that will GUI script the NetAuthAgent to AXPress it’s button. This can be called periodically or just after you tried to mount the volume.

I’m pretty sure you can just pass it as a string.

As a followup, I’m told by Apple that a framework is available in ML10.8 that is called NetFS that will do this with making the UI box optional. I don’t have ML yet so I can not verify this. My 10.7 does not show that my Objective-C code is deprecated (FSMountServerVolumeSync) but it may be in ML.

The File Manager is deprecated in 10.8, along with lots of other legacy Carbon stuff. It looks like NetFS not only allows a no-UI option, but it also offers an async function, NetFSMountURLAsync.

In 10.7 (and luckily still in 10.8, eventhough it’s deprecated) you can use FSMountServerVolumeAsync() which will call a callback function that is declared like this:
void OnDiskUnmounted(DADiskRef disk, DADissenterRef dissenter, void context ){ if (dissenter !=0){/ your code*/}

You also can test the availability of a local network volume by testing if the correspondent NSHost has a valid ip address:
NSString * address = [[NSHost hostWithName:@“host”] address];
NSArray * comp = [address componentsSeparatedByString:@“.”];
if ([comp count] == 4) {
NSIndexSet *indexes = [comp indexesOfObjectsPassingTest:
^BOOL (id str, NSUInteger ind, BOOL *stop) {
BOOL valid = NO;
if (([str integerValue] > 0 && [str integerValue] <= 255) || [str isEqualToString:@“0”]) {valid = YES;}
return valid;}];
if ([indexes count] == 4) {isIP = YES;}

Unfortunately I have not yet managed to get NetFSMountURLAsync() to work… I have searched the net but everything I found was this not very optimistic thread:
Is there anybody who has worked with NetFSMountURLAsync() ?

FSMountServerVolumeAsync() uses a block for the callback, for example

CFURLRef volumeURL = (__bridge CFURLRef)[NSURL URLWithString:@"afp://myServer.local/myVolume"];
AsyncRequestID requestID = NULL;
dispatch_queue_t queue = dispatch_get_current_queue();
NetFSMountURLAsync(volumeURL, NULL, CFSTR("username"),
                    CFSTR("password"), NULL, NULL,
                    queue, ^(int status, AsyncRequestID requestID, CFArrayRef mountpoints) {
                        NSLog(@"mounted: %d - %@", status, (__bridge NSArray *)mountpoints);

the returned AsyncRequestID is used to be able to cancel the mount request with NetFSMountURLCancel(requestID)

Thank you for the hints!
I got it working know and it’s doing the job that FSMountServerVolumeAsync() has done before.

Unfortunately I still have some problems with

  • the mount_options:
    I haven’t managed to set the mount_options or the open_options… Taken from netfs.h, line 346, I’ve tried to suppress authentification dialog :
NSMutableDictionary * mountOptions = [NSMutableDictionary dictionary];
[mountOptions setObject:@"NoUI" forKey:@"kNAUIOptionKey"]; // 
CFMutableDictionaryRef mount_options = (CFMutableDictionaryRef) mountOptions;
  • the error code:

I do not know how to read the error code of ‘status’ in the block-statement… It’s 0 on succesful mount. But how do get information on the kind of error?

the defined value of kNAUIOptionKey is “UIOption” so you should pass the unquoted keys casted to NSString

[mountOptions setObject:(NSString *)kNAUIOptionNoUI forKey:(NSString *)kNAUIOptionKey];

The error codes aren’t documented (as far as I know), maybe they are the same as in old FileManager

Thank you again for your answer!
I missed the definition of UIOption values… Unfortunately kNAUIOptionNoUI does not suppress the authentication dialog when no password is saved and neither does kNAUIOptionForceUI force the dialog when a password is saved… This could be a bug as stated in the thread I mentioned… The good news are that NetFSMountURLAsync(), in contrast to FSMountServerVolumeAsync, does query the keychain itself!

I also tried to set kNetFSSoftMountKey like this (I couldn’t find a value definition here):
[mountOptions setValue:0 forKey:(NSString *)kNetFSSoftMountKey];
This had no effect…

I also checked if the error code is identical to the file manager result codes. This is not the case.
Maybe one day there will be better documentation…

At least when you press cancel in the dialog you get error -128 (which is ironically equal to AppleScript “user cancelled” error)