amosavian / AMSMB2

Swift framework to connect SMB2/3 shares
GNU Lesser General Public License v2.1
251 stars 76 forks source link

Error code 12: Unknown address family :30. Only IPv4/IPv6 supported so far. #16

Closed Jeehut closed 5 years ago

Jeehut commented 5 years ago

I'm trying to use AMSMB2 to connect to my Synology server at home (which I'm regularly connecting to using my Mac via SMB). My app is running on an Apple TV with tvOS 12.0 and both on the simulator and on my Apple TV, I can find a service, but when calling the listShares method or the connectShare method I get the following error:

Error Domain=NSPOSIXErrorDomain Code=12 "Cannot allocate memory" UserInfo={NSLocalizedFailureReason=Error code 12: Unknown address family :30. Only IPv4/IPv6 supported so far.}

The Synology's discovered NetService is the name of the server, something like MyServer, so it's not an IP address. I also tried my Synology's IP-address, but that didn't work either.

You can find the code how I'm using AMSMB2 here on GitHub: https://github.com/Flinesoft/HomeCinema/blob/work/amsmb2/App/Sources/Networking/LocalNetworkConnector.swift

Any idea what might be the issue?

amosavian commented 5 years ago

You are absolutely abusing NetService class. YOU CAN'T PASS SERVICE NAME IN URL!. You must set a delegate for your NetService instance, then call .resolve(withTimeout:) method and in netServiceDidResolveAddress(_:) method in your delegate, you will get a dns which is usable to connect to your SMB Server.

Here is an example, which works on Playground:

import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

var services: [NetService] = []

class ServiceDelegate: NSObject, NetServiceDelegate {
    func netServiceDidResolveAddress(_ sender: NetService) {
        print(sender.hostName!)
        let domain = sender.hostName!.trimmingCharacters(in: CharacterSet(charactersIn: "."))
        let url = "smb://" + domain
        // Instantiate AMSMB2 object using `url`.
    }
}

let sd = ServiceDelegate()

class BrowserDelegate: NSObject, NetServiceBrowserDelegate {
    func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
        services.append(service)
        print(service.name, moreComing)
        service.delegate = sd
        service.resolve(withTimeout: 10)
    }
}

let d = BrowserDelegate()
let b = NetServiceBrowser()
b.delegate = d
b.searchForServices(ofType: "_smb._tcp", inDomain: "")
Jeehut commented 5 years ago

Oh, that explains why it wasn't working, thank you very much! I will try it as soon as I can and report.

There is no reason to shout tough. 😓 I'm new to the API and couldn't find good learning content on the web. So, please, be kind to me.

amosavian commented 5 years ago

That was emphesizing not shouting sorry

Jeehut commented 5 years ago

It's working now, thank you! 🎉

Jeehut commented 5 years ago

Oh no, it was all working three days ago, but I just wanted to start a new feature and the same code that was working a few days ago, isn't working anymore. It's showing the same error message as already posted before:

Error Domain=NSPOSIXErrorDomain Code=12 "Cannot allocate memory" UserInfo={NSLocalizedFailureReason=Error code 12: Unknown address family :30. Only IPv4/IPv6 supported so far.}

Here's the code (it follows your example above):

            let domain = service.hostName!.trimmingCharacters(in: CharacterSet(charactersIn: "."))
            let url = URL(string: "smb://\(domain)")!

            smbClient = AMSMB2(url: url, domain: service.domain, credential: credentials)
            smbClient?.listShares { [weak self] names, _, error in
                guard error == nil else {
                    // failure case
                    return
                }

                self?.smbShares = names
                // success handling
            }

You can find the full code here.

Looks like I'm running into this of libsmb2 instead of that line. As the error shows, the family of my device is 30, which should map to IPv6 (according to this document) as supported by libsmb2. So, could it be that HAVE_SOCKADDR_IN6 is not set in AMSMB2? Doesn't it support IPv6?

Do you have any other idea why this might fail?

Jeehut commented 5 years ago

Okay, I found a solution for the problem: Instead of using hostname on the NetService object (which was something like MyServer.local for me) I am now reading the IP address from the addresses property by passing the resolved NetService objec to this method:

    private func ipAddress(service: NetService) -> String {
        var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
        guard let data = service.addresses?.first else { return "" }
        data.withUnsafeBytes { (pointer: UnsafePointer<sockaddr>) -> Void in
            guard getnameinfo(pointer, socklen_t(data.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else { return }
        }

        return String(cString: hostname)
    }

In case anyone else comes across the same issue, you might want to try that, too. This still doesn't explain to me, why it was working a few days ago, but I hope it will work this way forever. :)

amosavian commented 5 years ago

You can instantiate AMSMB2 not only with IPs but also with domain names. I don't know what was the problem exactly.

Jeehut commented 5 years ago

Okay, that's weird. Probably a router configuration issue, don't you think? I've already seen that I can't connect to VPN tunnels which are specified by IP address, it only works for domains. This time, it's the other way around though, which is even weirder. ^^

I'm using a Fritz!Box 7xxx with nearly the default settings (only some WiFi configuration changed). Nothing blocked that I know of ... that only in case somebody else comes across this, too. Nothing that's your responsibility to fix or help with here. ;)

Thanks for trying to help, anyways. Much appreciated.