name_attach()

QNX SDP8.0C Library ReferenceAPIDeveloper

Register a name in the pathname space and create a channel

Synopsis:

#include <sys/iofunc.h>
#include <sys/dispatch.h>

name_attach_t * name_attach( dispatch_t * dpp,
                             const char * path,
                             unsigned flags );

Arguments:

dpp
NULL, or a dispatch handle returned by a successful call to dispatch_create() or dispatch_create_channel().
path
The path that you want to register under /dev/name/local/. This name shouldn't contain any path components consisting of .. or start with a leading slash (/).
flags
Currently not used.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The name_attach(), name_close(), name_detach(), and name_open() functions provide the basic pathname-to-server-connection mapping, without having to become a full resource manager.

Note:
In order to create a public channel (i.e., without _NTO_CHF_PRIVATE set), your process needs the PROCMGR_AID_PUBLIC_CHANNEL ability enabled. For more information, see procmgr_ability().

If you've already created a dispatch structure, pass it in as the dpp. If you provide your own dpp, set flags to NAME_FLAG_DETACH_SAVEDPP when calling name_detach(); otherwise, your dpp is detached and destroyed automatically.

If you pass NULL as the dpp, name_attach() creates a dispatch structure and a channel. The channel will be created with the _NTO_CHF_COID_DISCONNECT, _NTO_CHF_UNBLOCK, and _NTO_CHF_DISCONNECT flags set, and you will need to handle the generated pulses correctly. See ChannelCreate() for details.

The name_attach() function puts the name path into the pathname space under /dev/name/local/path. This pathname space is unprivileged, meaning your process doesn't need the PROCMGR_AID_PATHSPACE ability, unlike with pathmgr_symlink() and resmgr_attach().

If the receive buffer that the server provides isn't large enough to hold a pulse, then MsgReceive() returns -1 with errno set to EFAULT.

name_attach_t

The name_attach() function returns a pointer to a name_attach_t structure that looks like this:

typedef struct _name_attach {
    dispatch_t* dpp;
    int         chid;
    int         mntid;
    int         zero[2];
} name_attach_t;

The members include:

dpp
The dispatch handle used in the creation of this connection.
chid
The channel ID used for MsgReceive() directly.
mntid
the mount ID for this name.

The information that's generally required by a server using these services is the chid.

Note:
An application can attach a service locally, only if there isn't another application that's attached locally to the same service. There's no credential restriction for applications that are attached as local services.

Returns:

A pointer to a filled-in name_attach_t structure, or NULL if the call fails (errno is set).

Errors:

EAGAIN
One of the following occurred:
  • The process can't allocate a new kernel channel object.
  • The process exceeded its maximum allowed number of channels.
  • The number of channels created by the process is greater than the limit specified for RLIMIT_CHANNELS_NP (see prlimit()).
EEXIST
The specified path already exists.
EINVAL
An argument was invalid. For example, the path argument was NULL, the path was empty, it started with a leading slash (/), or it contained .. components.
ENOMEM
There wasn't enough free memory to complete the operation.
ENOTDIR
A component of the pathname wasn't a directory entry.
EPERM
The calling process doesn't have the required permission; see procmgr_ability().

Examples:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/dispatch.h>

#define ATTACH_POINT "myname"

/* All your messages should start with a type field */
typedef struct _my_data
{
	uint16_t type;
	int value;
} my_data_t;

typedef union recv_buf
{
	uint16_t type; // all messages start with a type
	struct _pulse pulse;
	my_data_t data;
} my_recv_buf_t;

/*** Server Side of the code ***/
int server() {
   name_attach_t *attach;
   my_recv_buf_t msg;
   rcvid_t rcvid;

   /* Create a local name (/dev/name/local/...) */
   if ((attach = name_attach(NULL, ATTACH_POINT, 0)) == NULL) {
       return EXIT_FAILURE;
   }

   /* Do your MsgReceive's here now with the chid */
   while (1) {
       rcvid = MsgReceive(attach->chid, &msg, sizeof(msg), NULL);

       if (rcvid == -1) {/* Error condition, exit */
           break;
       }

       if (rcvid == 0) {/* Pulse received */
           switch (msg.pulse.code) {
           case _PULSE_CODE_DISCONNECT:
               /*
                * A client disconnected all its connections (called
                * name_close() for each name_open() of our name) or
                * terminated
                */
               ConnectDetach(msg.pulse.scoid);
               break;
           case _PULSE_CODE_UNBLOCK:
               /*
                * REPLY blocked client wants to unblock (was hit by
                * a signal or timed out).  It's up to you if you
                * reply now or later.
                */
               break;
           default:
               /*
                * A pulse sent by one of your processes or a
                * _PULSE_CODE_COIDDEATH or _PULSE_CODE_THREADDEATH
                * from the kernel?
                */
               break;
           }
           continue;
       }
       /* A system message was received, reject it. */
       if (msg.type <= _IO_MAX ) {
           MsgError( rcvid, ENOSYS );
           continue;
       }

       /* A message (presumable ours) received, handle */
       printf("Server receive %d \n", msg.data.value);
       MsgReply(rcvid, EOK, 0, 0);

   }

   /* Remove the name from the space */
   name_detach(attach, 0);

   return EXIT_SUCCESS;
}


/*** Client Side of the code ***/
int client() {
    my_data_t msg;
    int server_coid;

    if ((server_coid = name_open(ATTACH_POINT, 0)) == -1) {
        return EXIT_FAILURE;
    }

    /* We would have pre-defined data to stuff here */
    msg.type = (_IO_MAX+5);

    /* Do whatever work you wanted with server connection */
    for (msg.value=0; msg.value < 5; msg.value++) {
        printf("Client sending %d \n", msg.value);
        if (MsgSend(server_coid, &msg, sizeof(msg), NULL, 0) == -1) {
            break;
        }
    }

    /* Close the connection */
    name_close(server_coid);
    return EXIT_SUCCESS;
}

int main(int argc, char **argv) {
    int ret;

    if (argc < 2) {
        printf("Usage %s -s | -c \n", argv[0]);
        ret = EXIT_FAILURE;
    }
    else if (strcmp(argv[1], "-c") == 0) {
        printf("Running Client ... \n");
        ret = client();   /* see name_open() for this code */
    }
    else if (strcmp(argv[1], "-s") == 0) {
        printf("Running Server ... \n");
        ret = server();   /* see name_attach() for this code */
    }
    else {
        printf("Usage %s -s | -c \n", argv[0]);
        ret = EXIT_FAILURE;
    }
    return ret;
}

Classification:

QNX OS

Safety:
Cancellation pointYes
Signal handlerNo
ThreadNo

Caveats:

As a server, you shouldn't assume that you're doing a MsgReceive() on a clean channel. Anyone can create a random message and send it to a process or a channel.

We recommend that you do the following to assure that you're playing safely with others in the system:

#include <sys/neutrino.h>

/* All your messages should start with a type field */
typedef struct _my_data { 
        uint16_t  type; 
        int       data; 
} my_data_t;

typedef union recv_buf { 
        struct _pulse  pulse; 
        my_data_t      msg; 
} my_recv_buf_t;

where:

type
Is a messsage type, and you should not use message types in the reserved system range 0 to _IO_MAX (0 to 511).
my_recv_buf_t
Is the receive buffer, and it must be large enough to contain at least a pulse because you'll receive a disconnect pulse when clients are detached.
Page updated: