zwopple / PocketSocket

Objective-C websocket library for building things that work in realtime on iOS and OS X.
Other
414 stars 129 forks source link

Support IPv6 in PSWebSocketServer #50

Open snej opened 8 years ago

snej commented 8 years ago

Apple just announced that starting in June 2016, apps that don't support IPv6-only networks will be rejected from the App Stores. "If your app uses IPv4-specific APIs or hard-coded IP addresses, you will need to make some changes."

There is some code in PSWebSocketServer.m that constructs an IPv4 sockaddr_in from a hostname, which is then used to bind a listening socket using CFSocket.

I don't know a lot about POSIX networking APIs, so I'm not sure if this code will fail in the default case where there's no hostname given, but I'm pretty sure it will fail if a hostname is given, since it won't be able to resolve to an IPv4 address.

snej commented 8 years ago

I think the best solution is to use CFHost to do the hostname resolution — it will return the IP address(es) already wrapped in NSData, in the form that CFSocket wants them. It'll probably be less code, too.

robertjpayne commented 8 years ago

@snej It'll be interesting to see how they enforce this, but yea I think CFHost will have to be the way it's done. I'll take a look into exactly what this may entail.

NightIsland commented 8 years ago

@robertjpayne Is there any progress on this issue? I'm currently looking to make a decision on which web socket library to use for a major new telecoms company project, and the "approvability" will definitely make a difference as to which I choose.

robertjpayne commented 8 years ago

@NightIsland are you looking to use the Server or Client code? The client code is IPv6 ready, the server code was never really intended much for App Store apps and is the questionable piece.

I doubt Apple will be scanning for ipv4 API's as they are still very valid, rather they probably turn off ipv4 DNS while they test your app.

robertjpayne commented 8 years ago

So looking at this right now, I currently take an IPv4 address and CFHost isn't really helpful here as that is more around DNS queries.

The main reason I locked the server code to IPv4 is because hardly anyone is going to IPv6 solely and you'd need to create two servers one for IPv4 and one for IPv6 to get both connections.

To avoid that I'll have to rejig a bit of the internal code to accept an ipv4 and ipv6 address for binding/listening on.

robertjpayne commented 8 years ago

@snej There isn't really an issue with the clients is there? At least from your end? The issue is solely the server that is hardcoded to IPv4.

NightIsland commented 8 years ago

Ah, I wasn't certain whether the mentioned code was used by any part of the client or just within the server - you're right that it's only the client that I'll be using.

I appreciate your rapid response: I'm going to use PocketSocket for our new app on this basis.

snej commented 8 years ago

Right, the issue is only with the server/listener code.

I currently take an IPv4 address and CFHost isn't really helpful here as that is more around DNS queries.

I'm assuming CFHost will resolve numeric hostnames. But a better approach may be inet_pton, which sounds like it does the same job as inet_addr but supports both IPv6 and IPv4. You'd probably have to call it with both AF_INET and then AF_INET6 and use the result for which it succeeds.

     The inet_pton() function converts a presentation format address (that is,
     printable form as held in a character string) to network format (usually
     a struct in_addr or some other internal binary representation, in network
     byte order).  It returns 1 if the address was valid for the specified
     address family, or 0 if the address was not parseable in the specified
     address family, or -1 if some system error occurred (in which case errno
     will have been set).  This function is presently valid for AF_INET and
     AF_INET6.
robertjpayne commented 8 years ago

@snej for server code there really isn't a need to resolve addresses, since you're binding to a interface and port, just a need to convert the string address to the in_addr structure.

The problem with supporting ipv4 and ipv6 simultaneously is you have to run two sockets and listen for connections on either.

Alternatively I may use something like NSSetService which has the added bonus of being discoverable from clients that support bonjour.

snej commented 8 years ago

:+1: for NSNetService.

JoydeWang commented 8 years ago

I use server code. I wanna know how to fix this issue

afbytes commented 8 years ago

I made it able to listen on both IPv4 and IPv6 address by changing several lines of code. I paste the code here since it's just a simple change without respect to allow user to specify an address on which listens.

The changes on method "initWithHost" (briefly, add "6" to each line):

        struct sockaddr_in6 addr;
        memset(&addr, 0, sizeof(addr)); // this line is not modified
        addr.sin6_len = sizeof(addr);
        addr.sin6_family = AF_INET6;
        addr.sin6_addr = in6addr_any; // the parameter "host" is ignored
        addr.sin6_port = htons(port);

The change in method "connect":

    _socket = CFSocketCreate(kCFAllocatorDefault,
                             PF_INET6,  // only this line, appending a "6"

Tested on both OSX 10.10 and iPhone 5s.

robertjpayne commented 8 years ago

@afbytes any chance you'd be willing to PR this? I just don't have time at the moment to implement it myself.

robertjpayne commented 8 years ago

Is anyone getting app store rejections on the basis of IPV6 support in server code? My gut feeling says Apple doesn't test device to device and thus a server only listening on IPV4 wont make a huge difference right now.

afbytes commented 8 years ago

I created a pull-request just now. According to my test, it works in these ways when the "host" parameter is:

snej commented 8 years ago

Yes, people are getting App Store rejections:

"I have a client with two CBL lite apps on the store. One was just approved and the other was rejected due to sync failing to start on Apple's IPv6 network. I've been able to replicate the issue by creating a local ad-hoc network with Internet Sharing and NAT 64 enabled." *

snej commented 8 years ago

The PR is https://github.com/zwopple/PocketSocket/pull/53, but it needs a fix (as noted in my line comment) to declare an instance variable properly, otherwise it may behave incorrectly if multiple listeners are opened.

asabino commented 8 years ago

Hi! Any news about this? Are apps using the server code having any trouble on the app aprovation? I'm interested to use the Server code from PocketSocket, but I need to know if this is really an issue for app aprovation. Thanks

kisileno commented 8 years ago

@asabino I have the macOS app which uses PocketSocket as a server. It is binding only one port at localhost and everything is fine, app was approved. You just need to select proper app sandbox permissions,