Литмир - Электронная Библиотека
Содержание  
A
A

// "базовая часть" команды devctl(), конкретный код команды будет

// формироваться динамически на основе этой части, но исходя

// из фактической длины блока передаваемых данных

const unsigned int DCMD_CMD = 1,

 DCMD_SRR = _POSIX_DEVDIR_TOFROM + (_DCMD_NET << 8) + DCMD_CMD;

// структура ответов менеджера ресурса по запросу read()

struct result {

 pid_t pid;

 int chid;

 uint64_t cps;

 result(void) {

  pid = getpid();

  // если уж возвращать, то и служебную информацию ;)

  cps = SYSPAGE_ENTRY(qtime)->cycles_per_sec;

 }

}

// завершение с извещением кода причины

inline void exit(const char *msg) {

 cout << '\r';

 perror(msg);

 exit(EXIT_FAILURE);

}

В этой части каких-либо комментариев заслуживает разве что структура

result
. Наш сервер устроен «наоборот»: информационный обмен данными он осуществляет по запросу
devctl()
, запрос
read()
нам «не нужен», и мы используем его только для возврата информации (PID + CHID) об автономном канале обмена сообщениями. Заодно мы передаем в поле cps этой структуры значение тактовой частоты процессора сервера, что позволяет знать, «с кем мы имеем дело» при экспериментах в сети.

Теперь мы вполне готовы написать код сервера. Этот сервер ( файл srv.cc), в отличие от традиционных, имеет два независимых канала подключения: как менеджер ресурсов и как сервер простого обмена сообщениями. Как менеджер он по запросу

read()
возвращает адресные компоненты (PID, CHID) для обмена сообщениями (ND клиент должен восстановить самостоятельно). По запросу
devctl()
, а также по запросу по автономному каналу обмена сообщениями сервер просто ретранслирует обратно полученный от клиента блок данных (в каком-то смысле по обоим каналам обмена наш сервер является «зеркалом», отражающим данные).

Сервер запросов

result data;

//---------------------------------------------------------

// реализация обработчика read()

static int readfunc(resmgr_context_t *ctp, io_read_t *msg,

 iofunc_ocb_t *ocb) {

 int sts = iofunc_read_verify(ctp, msg, ocb, NULL);

 if (sts != EOK) return sts;

 // возвращать одни и те же статические данные...

 MsgReply(ctp->rcvid, sizeof(result), &data, sizeof(result));

 return _RESMGR_NOREPLY;

}

//---------------------------------------------------------

// реализация обработчика devctl.

static int devctlfunc(resmgr_context_t *ctp, io_devctl_t *msg,

 iofunc_ocb_t *ocb) {

 int sts = iofunc_devctl_default(ctp, msg, ocb);

 if (sts != _RESMGR_DEFAULT) return sts;

 // разбор динамически создаваемого кода devctl(),

 // извлечение из него длины принятого блока

 unsigned int nbytes = (msg->i.dcmd - DCMD_SRR) >> 16;

 msg->o.nbytes = nbytes;

 // и тут же ретрансляция блока назад

 return _RESMGR_PTR(ctp, &msg->i, sizeof(msg->i) + nbytes);

}

//---------------------------------------------------------

// установка однопоточного менеджера, выполняемая

// в отдельном потоке

static void* install(void* data) {

 dispatch_t *dpp;

 if ((dpp = dispatch_create()) == NULL)

  exit("dispatch allocate");

 resmgr_attr_t resmgr_attr;

 memset(&resmgr_attr, 0, sizeof(resmgr_attr));

 resmgr_attr.nparts_max = 1;

 resmgr_attr.msg_max_size = 2048;

 static resmgr_connect_funcs_t connect_funcs;

 static resmgr_io_funcs_t io_funcs;

 iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs,

  _RESMGR_IO_NFUNCS, &io_funcs);

 // определяем обработку, отличную от обработки по умолчанию,

 // только для двух команд: read() & devctl()

 io_funcs.read = &readfunc;

 io_funcs.devctl = &devctlfunc;

 static iofunc_attr_t attr;

 iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0);

 // связываем менеджер с его префиксным именем

 if (resmgr_attach(dpp, &resmgr_attr, DEVNAME,

  _FTYPE_ANY, 0, &connect_funcs, &io_funcs, &attr) == -1)

  exit("prefix attach");

 dispatch_context_t* ctp = dispatch_context_alloc(dpp);

 while (true) {

  if ((ctp = dispatch_block(ctp)) == NULL)

91
{"b":"155449","o":1}