6

I have some logic which works by creating a Unix Domain Socket and doesn't have any issues when run within a normal app. However, when I run this for an app extension I get a -1 with errno = 48 ("Address already in use") from the bind().

NSArray *applicationSupportDirectoryPaths = 
NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
                                    NSUserDomainMask, YES);

int fd = socket(AF_UNIX, SOCK_STREAM, 0); // returns a non-zero value

NSString *loc = [applicationSupportDirectoryPaths[0] stringByAppendingPathComponent:@"usd"];
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX   ;
strncpy(addr.sun_path, [loc UTF8String], sizeof(addr.sun_path)-1);
int bindres = bind(fd, (struct sockaddr*)&addr, sizeof(addr)); // returns -1, error is 48

The location returned for the library directory is:

/var/mobile/Containers/Data/PluginKitPlugin/A8110BA2-5AE7-42C1-84DA-2A9B303C7277/Library/

I think the reason this is failing is because this is some special location, as compared to the library directory for an app.

If anyone has any ideas why this is happening or any workarounds, I appreciate it.

UPDATE: I tried with the caches directory (NSCachesDirectory), but now I get errno 3 (no such process).

Locksleyu
  • 5,192
  • 8
  • 52
  • 77
  • First guess is address really is in use. iOS might instantiate/kill extensions on demand, so the socket bound in the previous call might be not released when the next call is performed. Why would you need a domain socket listener in extension code? – Alex Skalozub Feb 03 '16 at 20:49
  • Looks like you were right. Originally I had thought this wasn't the problem, but there was a second issue in my code masking the real problem. I think I got it figured out now. – Locksleyu Feb 04 '16 at 14:01
  • I want to give you (Alex Skalozub) the +50 reputation, but not sure how. Maybe you should post a full answer with the same comment as your comment? Or we can let an admin deal with it. – Locksleyu Feb 04 '16 at 14:01

3 Answers3

3

First guess is address really is in use.

iOS might instantiate/kill extensions on demand, so the socket bound in the previous call might be not released when the next call is performed.

Alex Skalozub
  • 2,511
  • 16
  • 15
  • Thanks! It was this plus a combination of another issue that was making triage difficult, but I got it figured out now! – Locksleyu Feb 05 '16 at 12:54
0

I think you should first release the first object and then call the next one.

0

If you want the new socket to be bound forcibly, you can use SO_REUSEADDR socket option.

You can use setsockopt() as below to set SO_REUSEADDR.

int reuse = 1;

if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
{
    perror("setsockopt(SO_REUSEADDR) failed");
}