NSFileHandle creation hangs

Since I can't use DO* for communication, I have tried the old-fashionated way with pipes: the server would create and read one; the client would write to the server pipe, create its own back-pipe, and the server would respond by writing to the client's back-pipe.


The server pipe (created precisely the same way as the client one, using same code quoted below to create and read the pipe) works like a charm.


At the client side, the code looks like this:


ppath=... the path to the server pipe ...
pipe=[NSFileHandle fileHandleForWritingAtPath:ppath]; // works perfectly; if the following code is commented out, can write through it to the server and it gets the data all right
ppath=[ppath stringByAppendingPathExtension:[NSString stringWithFormat:@"%lu",(unsigned long)getpid()]];
mkfifo(ppath.fileSystemRepresentation,0644); // never fails
NSFileHandle *fh=[NSFileHandle fileHandleForReadingAtPath:ppath]; // HANGS UP!


The file handle creation hangs in open, like this:


* frame #0: 0x0000000100951ad2 libsystem_kernel.dylib`__open + 10
frame #1: 0x00007fff7a19be65 Foundation`_NSOpenFileDescriptor + 21
frame #2: 0x00007fff7a19bca8 Foundation`-[NSConcreteFileHandle initWithURL:flags:createMode:error:] + 118
frame #3: 0x00007fff7a19bc00 Foundation`-[NSConcreteFileHandle initWithPath:flags:createMode:error:] + 110
frame #4: 0x00007fff7a1e8b3c Foundation`+[NSFileHandle fileHandleForReadingAtPath:] + 50


Does anybody see what I am doing wrong and why this fails? (This I am testing on my development machine, 10.12.3 / 16D32).


Thanks a lot,

OC


* https://forums.developer.apple.com/message/216129#216129

Hello OCS1,

You are mixing up your terminology. You can use pipes with FIFOs, but they are not equivalent. I have some questions...

1) What is the type of "pipe"? It looks like it is an NSFileHandle, not an NSPipe. Don't call it a pipe if it isn't.

2) You are opening a file handle for writing at a path, then attempting to create a MKFO at that path. It seems like that should fail because you've already created a file at that path.

3) You wouldn't know if mkfifo failed because you aren't checking result codes.

4) Why is the client creating the FIFO anyway? Shouldn't the serve do that?

5) While you can use FIFOs (aka named pipes), that is not the same as, or as efficient as, just using pipes.

6) There are lots more ways to communicate than FIFOs.

7) Never use NSFileHandle. They WILL throw Objective-C exceptions.

8) I'm not sure about what architecture you are targeting here. While macOS supports many different schools of client/server talk, you shouldn't mix schools. Pick one paradigm and stay with it. Maybe don't pick one from the 1970s.

John, thanks a lot!


> 1) What is the type of "pipe"? It looks like it is an NSFileHandle, not an NSPipe. Don't call it a pipe if it isn't.


Well I thought a “fifo” (the thing created by the mkfifo service) was a “named pipe” years before NSPipe has been ever designed. Anyway, whatever the proper name is, this is the API I tried to use 🙂


Correct me please if I am wrong, but I don't know how would I use NSPipe to communicate betwixt a server a client; my understanding was they serve in different cases (e.g., to pipe a standard output from a process I have launched programmatically). As always, I might be missing something.


How would I “just use pipes” (re your comment No 5) in this case? Can you please point me to some code sample somewhere?


> 2) You are opening a file handle for writing at a path, then attempting to create a MKFO at that path


I am not; check please the line 03. The path I am opening a writing handle is the path of the server {fifo, named pipe, whatever you want to call the thing}. Then, I append the PID of the client to the end of the path to get a unique name, and create another {fifo...} for the client in there.


> 3) You wouldn't know if mkfifo failed because you aren't checking result codes


Of course I am. In the real code, there's lots of logs, error checking etc., which I have naturally removed so that the code presented is concise and intelligible, without obscuring boilerplate. That's why I have added the comment that it never fails, for it does not.


> 4) Why is the client creating the FIFO anyway?


To gen answers from the server. The communication is duplex; first the client sends a request to the server (through its {fifo...} using the local "pipe" file handle, created at the line 02 — this works perfectly.


Part of the request is the path to the client {fifo...}, created at the line 04; the server is presumed to write its reponse to there, and the client would read it. Alas this part does not work, for the creation of the read handle for this {fifo...} hangs.


> 6) There are lots more ways to communicate than FIFOs


Absolutely; my first choice were Distributed Objects, which are ways more convenient. Alas, they do not work for me, see please the link at the bottom of my original message.


While I could e.g., establish a socket-level communication, it is darn complex for such a simple task. I considered the {fifos...} about the 2nd easiest after DOs. Might, of course, be missing something.


> 7) Never use NSFileHandle


What?!? :-O I am using the thing for 20-odd years without much problems, and so far I believed they are the first option for most streams in Cocoa. After all, the aforementioned NSPipe is filehandle-based; so is NSTask etc.?!?


> 8) I'm not sure about what architecture you are targeting here. While macOS supports many different schools of client/server talk, you shouldn't mix schools. Pick one paradigm and stay with it. Maybe don't pick one from the 1970s


Well in my experience, technologies of '70s tend to work pretty well; often much better than today's ones. Anyway those {fifos...} were not my first option, but as written above, alas, there's a weird problem with Distributed Objects, which always are the first option for all server/client communication. 10.8+ there's XPC, but since I target a Mac OS X 10.6 Server, that would not help much. While I could use sockets of low-level Mach APIs, I would rather keep high-level for my task, which is (should be) pretty simple and not too demanding as for efficiency.


Thanks again,

OC

NSFileHandle creation hangs
 
 
Q