name_attach()
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.
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. If this pathname is protected by a security policy, then your process needs the PROCMGR_AID_PATHSPACE ability. For more information, refer to procmgr_ability() and the System Security Guide.
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.
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:
| Safety: | |
|---|---|
| Cancellation point | Yes | 
| Signal handler | No | 
| Thread | No | 
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.
