NSMessagePort/NSSocketPort & Distributed Objects

  • Greetings,

    I've returned, once again, to my client/daemon communications conundrum.

    I'm desperately seeking example code that successfully uses
    either NSMessagePort or NSSocketPort using a local domain socket
    to create an NSConnection.

    If you somehow missed my hundred-odd whiny posts in the past,
    let me recap: My project has several daemon and client processes
    that communicate using distributed objects. Because of Mach
    namespace issues, it's impossible for some processes to "see"
    either the clients or daemons.

    This technote
    (<http://developer.apple.com/technotes/tn2005/tn2083.html>),
    kindly provided by Dave Camp, strongly suggests that using Mach
    ports to communicate with daemons is bad. If you need
    interprocess communications that gets around problems like
    namespaces one should use BSD sockets. It provides some Core
    Foundation example code that uses local (AF_UNIX) sockets.

    "Great!" I say to myself. I'll just replace the default NSPort
    stuff with either NSMessagePort or NSSockPort created from an
    AF_UNIX socket and I'll be back in business. However, after over
    a day of experimentation I have yet to get this to work.

    I can't even remember all of the combinations that I've tried,
    but in the end I get one of four results: The client can't
    see/connect to the server, the client connects but hangs when it
    calls [NSConnection rootProxy], the client crashes with a bad
    address when it calls rootProxy, the client throws some kind of
    connection exception when it calls rootProxy.

    What's shocking -- and a little scary -- is that I can find
    virtually NO working code examples using DO via NSMessagePort or
    NSSocketPort using local sockets. A search of
    developer.apple.com's example source turns up zero hits. Even a
    code.Google search doesn't turn up much. I was able to find a
    thread on the list from 2005 titled "NSSocketPort vs. AF_UNIX"
    that implies that someone got this to work, but there wasn't
    enough code to reproduce it.

    Any pointers would be greatly appreciated.

    --
    James Bucanek
  • A year or so ago when I was working on a Cocoa project I created a
    database server (using SQLite) and then clients that connected to it
    via distributed objects, which is shared over a Bonjour service. The
    basic cycle is:

    1. On a computer, one launches the server application which starts
    sharing a Bonjour D-O services that clients can connect to
    2. A user opens the client application and a list of all the
    computers broadcasting the Bonjour service shows up, to one of which
    the user connects
    3. The D-O is shared

    As I stated above, the code is a year old and isn't necessarily a
    great piece of Cocoa work, but it's completely functional and it has
    been deployed without issues.

    You can find the code in my Git repository here:
    http://www.bluestatic.org/git/?p=Tindex.git;a=tree

    The files of interest to you would be:
    Server/DatabaseServer.m: The server side of the D-O using NSSocketPort
    Client/AppController.m: The Bonjour/discovery portion of the connection
    Client/ClientController.m: The -init: method shows how to get the
    proxied object

    While this may not be exactly what you're looking for, it is a
    functional example of D-O using NSSocketPort.

    - Robert Sesek

    On Sep 15, 2007, at 15:35, James Bucanek wrote:

    > Greetings,
    >
    > I've returned, once again, to my client/daemon communications
    > conundrum.
    >
    > I'm desperately seeking example code that successfully uses either
    > NSMessagePort or NSSocketPort using a local domain socket to create
    > an NSConnection.
    >
    > If you somehow missed my hundred-odd whiny posts in the past, let
    > me recap: My project has several daemon and client processes that
    > communicate using distributed objects. Because of Mach namespace
    > issues, it's impossible for some processes to "see" either the
    > clients or daemons.
    >
    > This technote (<http://developer.apple.com/technotes/tn2005/
    > tn2083.html>), kindly provided by Dave Camp, strongly suggests that
    > using Mach ports to communicate with daemons is bad. If you need
    > interprocess communications that gets around problems like
    > namespaces one should use BSD sockets. It provides some Core
    > Foundation example code that uses local (AF_UNIX) sockets.
    >
    > "Great!" I say to myself. I'll just replace the default NSPort
    > stuff with either NSMessagePort or NSSockPort created from an
    > AF_UNIX socket and I'll be back in business. However, after over a
    > day of experimentation I have yet to get this to work.
    >
    > I can't even remember all of the combinations that I've tried, but
    > in the end I get one of four results: The client can't see/connect
    > to the server, the client connects but hangs when it calls
    > [NSConnection rootProxy], the client crashes with a bad address
    > when it calls rootProxy, the client throws some kind of connection
    > exception when it calls rootProxy.
    >
    > What's shocking -- and a little scary -- is that I can find
    > virtually NO working code examples using DO via NSMessagePort or
    > NSSocketPort using local sockets. A search of developer.apple.com's
    > example source turns up zero hits. Even a code.Google search
    > doesn't turn up much. I was able to find a thread on the list from
    > 2005 titled "NSSocketPort vs. AF_UNIX" that implies that someone
    > got this to work, but there wasn't enough code to reproduce it.
    >
    > Any pointers would be greatly appreciated.
    >
    > --
    > James Bucanek
    >
  • James Bucanek <mailto:<subscriber...> wrote (Saturday,
    September 15, 2007 12:35 PM -0700):
    > I'm desperately seeking example code that successfully uses either
    > NSMessagePort or NSSocketPort using a local domain socket to create an
    > NSConnection.

    Shockingly, I never found any code examples which demonstrate
    this, and the documentation of NSSocketPort is maddeningly vague.

    But it turns out that I was at the Zoo this morning with a
    laptop and couple of hours to kill (long story), and managed to
    stumble around blindly until I found a solution.

    So, for anyone who's interested you can download my
    DOConnectionTest project. It creates a DO connection between two
    processes using named sockets (files).

    <http://www.twilightandbarking.com/FTP/public/Software/Cocoa/DOConnectionTes
    tBSDSocket.zip
    >

    For anyone who's interested in trying this, there are a few
    things to note:

    sockaddr_un.sun_len must be set to sizeof(struct sockaddr_un)
    not SUN_LEN(&address) as you would think. Failing to do this
    will cause NSSocketPort to ignore you.

    [NSSocketPort
    initWithProtocolFamily:socketType:protocol:address:] is what you
    need to call from the server. It will create the socket file
    (via bind). If the socket file already exists, this call fails
    and returns nil.

    [NSSocketPort
    initRemoteWithProtocolFamily:socketType:protocol:address:] is
    what you need to call from the client. It expects to connect
    with an already existing the socket. Oddly, it will return a
    socket even if the named socket file doesn't exist. I don't know
    if, after creating the Port, you eventually create the file the
    connection will work or not. I ultimately gated my code so that
    it first tests to see if the pipe file exists. This avoids
    creating a connection that immediately throws an exception.

    NSSocketPort/NSConnection takes care of all of the
    bind()/listen()/connect() calls and it adds the port to the run
    loop. So don't try to do this yourself or nothing will work.

    It appears that NSSocketPort does not, however, destroy the
    socket/pipe file once the NSSocketPort is invalidated. You'll
    have to do this yourself. Currently, I'm adding code to catch
    the port's NSPortDidBecomeInvalidNotification and delete the
    socket file.

    NSSocketPortNameServer does NOT work with AF_UNIX addresses at
    all. There are no usable name server registration services in
    this scenario. (The "names" of the connections are being managed
    by the file system, so a name server would be superfluous anyway
    -- although it would be nice because it would make the code more consistent.)

    Hope this helps someone else. And if anyone wants to know why I
    went to all of this trouble, I can answer that question next Friday...

    James
    --
    James Bucanek
  • James Bucanek <mailto:<subscriber...> wrote (Thursday,
    October 18, 2007 10:09 PM -0700):
    > It appears that NSSocketPort does not, however, destroy the
    > socket/pipe file once the NSSocketPort is invalidated. You'll have to
    > do this yourself. Currently, I'm adding code to catch the port's
    > NSPortDidBecomeInvalidNotification and delete the socket file.

    I can now confirm that this is true. You must delete the socket
    file created by NSSocketPort once you are done with the connection.

    Also, [NSConnection invalidate'] does not (immediately)
    invalidate the port, so it never fires the
    NSPortDidBecomeInvalidNotification. At least not in my test
    program, that terminates the instant it invalidates the
    connection. To get that notification to fire, I had to call
    [[connection receivePort] invalidate].

    --
    James Bucanek
previous month september 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Go to today