Using NSNetService class to make an SMB tcp ip connection to a folder shared on windows machine

7.4k views Asked by At

I have been trying to figure out a way to access my windows shared folder using iPhone. The desired functionality is part of bigger enterprise app I am building. Here is someone who has already asked a similar question but no luck - Does iOS support file operations via SMB?

Now, I have found apple developer tutorial called "SimpleNetworkStreams" which employs NSNetService to use x-SNSUpload protocol over tcp by setting type of NSNetService instance to protocol x-SNSUpload._tcp

Here is how they have done it -

self.netService = [[[NSNetService alloc] initWithDomain:@"local." type:@"_x-SNSUpload._tcp." name:@"Test"] autorelease];

So if I just replace _x-SNSUpload._tcp with _smb._tcp and run SMB server on my macbook. I run following set of commands to start SMB on my macbook

dns-sd -R Test _smb._tcp. "" 12345

nc -l 12345 > tmp.png

Then I am able to transfer a picture in my iPhone to my macbook's root directory. I was hoping to do the same with shared folder on windows machine.

The name of the share folder is "test sharing". I have explicitly shared my 'test sharing' folder in my windows machine with full control to everyone. The complete details of code is put below (after Update)

If I directly type in "smb:\\10.212.19.121" on my browser I am able to access my shared folder. It opens the finder application and gives me an option to mount the "temp sharing" folder.


Update - lot of redundant text taken out from above and better details on how SimpleNetworkStreams work and what I have tweaked is put below.

The code is taken from - SimpleNetworkStreams -

  1. Open the stream of type NSInputStream for the file we want to send
//Open a stream for the file we're going to send

//filepath is a NSString with path to the file on iPhone

self.fileStream = [NSInputStream inputStreamWithFileAtPath:filepath]; 

assert(self.fileStream != nil); 

[self.fileStream open];
  1. As how apple documentation says

"you can either create an NSNetService object directly (if you know the exact host and port information) or you can use an NSNetServiceBrowser object to browse for services. "

An object of NSNetService is instantiated for the server which hosts SMB server

// Open a stream to the server, finding the server via Bonjour.  Then configure 
// the stream for async operation.

//here's the tweak.
//original code looked like - 
//self.netService = [[[NSNetService alloc] initWithDomain:@"local." type:@"_x-SNSUpload._tcp." name:@"Test"] autorelease];

self.netService = [[[NSNetService alloc] initWithDomain:@"10.212.19.121" type:@"_smb._tcp." name:@"lanmanserver"] autorelease];

assert(self.netService != nil);

NSDictionary *newDict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:@"domain\\username",@"password",@"C:\\Documents and Settings\\username\\Desktop\\test%20sharing",nil] forKeys:[NSArray arrayWithObjects:@"u",@"p",@"path",nil]];

[self.netService setTXTRecordData:[NSNetService dataFromTXTRecordDictionary:newDict]];
 

Get the output stream object of type NSOutputStream into self.networkStream.

success = [self.netService getInputStream:NULL outputStream:&output];
assert(success);

self.networkStream = output;

[output release];

self.networkStream.delegate = self;
[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[self.networkStream open];

and then the NSOutputStream delegate catches NSStreamEventHasSpaceAvailable where we buffer in the input file and then write that buffer to our NSOutputStream object i.e. networkStream

bytesWritten = [self.networkStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];
2

There are 2 answers

7
Matthias Bauch On BEST ANSWER

I think you misunderstood NSNetservice. NSNetService can be used to publish Bonjour Information about network services in your network. It doesn't create a server for you, it just tells the clients that there is a server with the service available. Even if there is no such server it will tell the client that there is one.

Try bonjour browser to see what NSNetService does. All the entries you will see are published NSNetServices.
Or you could publish a service with the type _afpovertcp._tcp. and watch the sidebar in finder to get an idea how NSNetServices are used.


dns-sd -R Test _smb._tcp. "" 12345
nc -l 12345 > tmp.png

These lines have absolutely nothing to do with SMB. Just because you are advertising your service as SMB doesn't mean that your server actually understands SMB.
And nc (aka netcat) does exactly what its name suggests. It dumps everything you send to it into your file. Not SMB, not at all.

And using TXTRecords for Authentication is a bad idea, everybody who is connected to your network will get the TXTRecords.

To make a long story short, NSNetServices won't help you with creating SMB connections. Once you are done with the SMB Server you can use NSNetServices to tell clients in your network that there is a SMB Server. But it won't help you in creating this server.

1
Amit On

Have you tried: self.netService = [[[NSNetService alloc] initWithDomain:@"10.212.19.121" type:@"_smb._tcp.local" name:@"lanmanserver"] autorelease];