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 или дескриптор диспетчера, возвращаемый dispatch_create() или dispatch_create_channel().
path
Путь, который необходимо зарегистрировать в /dev/name/[local|global]/. Данный путь не должен содержать символов .. или начинаться с /.
flags
Флаги, влияющие на поведение функции:
NAME_FLAG_ATTACH_GLOBAL
Зарегистрировать имя глобально, а не локально. Смотрите утилиту gns.

Библиотека:

libc

Описание:

Функции name_attach(), name_close(), name_detach() и name_open() предоставляют базовое отображение путь к файлу - соединение с сервером без необходимости использования полноценного менеджера ресурсов.

Если структура диспетчера уже создана, следует передать ее как dpp. Если предоставляется собственная dpp, следует установить flags в NAME_FLAG_DETACH_SAVEDPP при вызове name_detach(); в противном случае, dpp отключается и разрушается автоматически.

Если передать NULL в качестве dpp, name_attach() вызывает dispatch_create() и resmgr_attach() для создания канала, но никаких флагов канала не устанавливает. Созданный канал будет иметь установленные флаги _NTO_CHF_DISCONNECT, _NTO_CHF_COID_DISCONNECT и _NTO_CHF_UNBLOCK.

Функция name_attach() помещает имя path в пространство имен /dev/name/[local|global]/path. Имя регистрируется локально по умолчанию или глобально, если в flags установлен NAME_FLAG_ATTACH_GLOBAL. Зарегистрированные имена можно увидеть в директориях /dev/name/local и /dev/name/global.

Приложение, вызывающее name_attach(), получает сообщение _IO_CONNECT при вызове name_open(). Приложение должно корректно обработать это сообщение с ответом EOK, чтобы разрешить соединение name_open().

Если буфер приема, предоставляемый сервером, недостаточно велик для получения импульса, MsgReceive() возвращает -1 с установкой errno в EFAULT.

Информация, обычно требуемая серверу для использования вышеупомянутых сервисов - name_attach_t::chid.


Note: Утилита gns должна быть запущена до вызова приложением name_attach() для глобального объявления или регистрации службы.

Если приложение подключает службу локально, то приложения на других машинах не смогут искать эту службу с помощью утилиты gns. Если приложение подключает службы глобально, то любая машина в сети с запущенным менеджером gns может получить доступ к службе. Приложение может подключать службу локально только в том случае, если нет другого приложения, подключенного локально к той же службе. Ограничений по разрешениям для приложений, подключенных как локальные службы, нет. Приложение может подключить службу глобально только если имеет привилегии суперпользователя.


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

Указатель на заполненную структуру name_attach_t.

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

Коды ошибок:

EBUSY
Ошибка возникла при попытке функции создать канал; смотрите ChannelCreate().
EEXIST
Указанный путь уже существует.
EINVAL
Некорректные аргументы (то есть NULL или пустая строка в качестве пути, либо путь, начинающийся с / или содержащий символы ..).
ENOMEM
Недостаточно свободной памяти для завершения операции.
ENOTDIR
Часть имени пути не является директорией.

Примеры:

#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;
/*** Серверный код ***/
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;
}
/*** Клиентский код ***/
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;
}

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

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

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

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

Не следует предполагать, что сервер выполняет MsgReceive() для чистого канала. В ЗОСРВ «Нейтрино» (и ЗОСРВ КПДА.00002-01) любой может создать случайное сообщение и отправить его процессу или каналу.

Рекомендуется сделать следующее, чтобы убедиться в безопасном взаимодействии с другими членами системы:

#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;

где:

hdr
Первые 4 байта интерпретируются как поле типа/подтипа. Это позволяет идентифицировать данные, которые не предназначены для данного сервера.
data
Определяет структуру приема данных. Структура должна быть достаточно большой, чтобы содержать хотя бы импульс (который обычно начинается с поля типа/подтипа для большинства обычных сообщений), так как при отсоединении клиента серверу придет импульс отключения.

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

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(), struct _pulse, resmgr_attach()

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




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