name_attach()

Зарегистрировать имя в пространстве имен и создать канал

Прототип:

#include <sys/iofunc.h>
#include <sys/dispatch.h>
name_attach_t * name_attach( dispatch_t *dpp,
const char *path,
unsigned flags );

Аргументы:

dpp
NULL, or a dispatch handle returned by dispatch_create() or dispatch_create_channel().
path
The path that you want to register under /dev/name/[local|global]/. This name shouldn't contain any .. characters or start with a leading slash /.
flags
Flags that affect the function's behavior:
NAME_FLAG_ATTACH_GLOBAL
attach the name globally instead of locally. See the gns utility.

Библиотека:

libc

Описание:

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 choose to pass a NULL as the dpp, name_attach() calls dispatch_create() and resmgr_attach() internally to create a channel, however, it doesn't set any channel flag by itself. The created channel will have the _NTO_CHF_DISCONNECT, _NTO_CHF_COID_DISCONNECT and _NTO_CHF_UNBLOCK flags set.

The name_attach() function puts the name path into the path namespace under /dev/name/[local|global]/path. The name is attached locally by default, or globally when you set NAME_FLAG_ATTACH_GLOBAL in the flags. You can see attached names in /dev/name/local and /dev/name/global directories.

The application that calls name_attach() receives an _IO_CONNECT message when name_open() is called. The application has to handle this message properly with a reply of an EOK to allow name_open() connect.

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.

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


Note: The gns utility must be started and running first before an application can call name_attach() to advertise (or attach) a service (i.e. represented by a path name) globally.

If an application attaches a service locally, then applications from another machine can't lookup this service through the gns utility. If an application attaches its services globally, then any machine that's on the network and is running the gns manager can access the services. 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. An application can attach a service globally only if the application has root privilege.


Возвращаемое значение:

A pointer to a filled-in name_attach_t structure.

Если возникла ошибка функция возвращает NULL, код ошибки записывается в errno.

Коды ошибок:

EBUSY
An error occurred when the function tried to create a channel; see ChannelCreate().
EEXIST
The specified path already exists.
EINVAL
Invalid arguments (i.e. a NULL or empty path, a path starts with a leading slash / or contains .. characters).
ENOMEM
Not enough free memory to complete the operation.
ENOTDIR
A component of the pathname wasn't a directory entry.

Примеры:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/dispatch.h>
#define ATTACH_POINT "myname"
/* We specify the header as being at least a pulse */
typedef struct _pulse msg_header_t;
/* Our real data comes after the header */
typedef struct _my_data {
msg_header_t hdr;
int data;
} my_data_t;
/*** Server Side of the code ***/
int server()
{
name_attach_t *attach;
my_data_t msg;
int 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.hdr.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.hdr.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;
}
/* name_open() sends a connect message, must EOK this */
if ( msg.hdr.type == _IO_CONNECT )
{
MsgReply( rcvid, EOK, NULL, 0 );
continue;
}
/* Some other IO message was received; reject it */
if ( msg.hdr.type > _IO_BASE && msg.hdr.type <= _IO_MAX )
{
MsgError( rcvid, ENOSYS );
continue;
}
/* A message (presumable ours) received, handle */
printf( "Server receive %d \n", msg.data );
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.hdr.type = 0x00;
msg.hdr.subtype = 0x00;
/* Do whatever work you wanted with server connection */
for ( msg.data = 0; msg.data < 5; msg.data++ )
{
printf( "Client sending %d \n", msg.data );
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;
}

Классификация:

ЗОСРВ «Нейтрино»

Точка остановки потока
Да
Обработчик прерываний
Нет
Обработчик сигналов
Нет
В потоке
Да

Предостережения:

As a server, you shouldn't assume that you're doing a MsgReceive() on a clean channel. В ЗОСРВ «Нейтрино» (и ЗОСРВ КПДА.00002-01), 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 of your messages should start with this header */
typedef struct _pulse msg_header_t;
/* Now your real data comes after this */
typedef struct _my_data {
msg_header_t hdr;
int data;
} my_data_t;

where:

hdr
Contains a type/subtype field as the first 4 bytes. This allows you to identify data which isn't destined for your server.
data
Specifies the receive data structure. The structure must be large enough to contain at least a pulse (which conveniently starts with the type/subtype field of most normal messages), because you'll receive a disconnect pulse when clients are detached.

Тематические ссылки:

name_attach_t, ChannelCreate(), dispatch_block(), dispatch_context_alloc(), dispatch_context_free(), dispatch_create(), dispatch_create_channel(), dispatch_destroy(), dispatch_handler(), dispatch_timeout(), dispatch_unblock(), MsgReceive(), name_detach(), name_open(), name_close(), _pulse, resmgr_attach()

gns в Справочнике по Утилитам




Предыдущий раздел: Описание API системной библиотеки