if (conncon->PRIM_type == T_CONN_CON) {
/* Если это действительно согласие, заполним
структуру rcvcall для пользователя TLI */
addr.len = conncon->OPT_length;
opt.len = conncon->OPT_length;
memcpy(addr.buf, conncon+conncon->RES_offset, addr.len);
memcpy(opt.buf, conncon+conncon->OPT_offset, opt.len);
free(confirm.buf);
/* Все закончилось удачно — возвращаем 0 */
return 0;
}
} else {
/* В случае отказа мы готовы обработать примитив
T_DISCON_IND */
...
return -1;
}
} else {
/* Если получен примитив T_ERROR_ACK — обработаем его */
errack = (struct T_error_ack*)ack.buf;
...
return -1;
}
}
Подобным образом реализовано большинство функций TLI. Заметим, что в конкретном случае использования транспортного протокола TCP прием и передача данных осуществляются в виде потока, не содержащего каких-либо логических записей. В этом случае не требуется формирование примитивов типа
T_DATA_REQ
T_DATA_IND
T_EXDATA_REQ
T_EXDATA_IND
T_UNITDATA_REQ
T_UNITDATA_IND
Описанная реализация программного интерфейса TLI имеет один существенный недостаток — операции функций не являются атомарными. Другими словами, выполнение функции t_connect(3N) может быть прервано другими процессами, которые могут также связываться с удаленным узлом. Это возможно, поскольку выполнение значительной части операций происходит в режиме задачи. Если для функции t_connect(3N) нарушение атомарности допустимо, то ряд функций, таких, например, как связывание (t_bind(3N)), получение информации (t_open(3N), t_getinfo(3N)) и установка или получение опций протокола (t_optmgmt(3N)) должны быть защищены от возможного нарушения целостности данных по причине прерывания операции. Единственным способом гарантировать атомарность является перевод выполнения критических участков (например, между отправлением примитива и получением подтверждения от поставщика транспортных услуг) в режим ядра. Для этого подсистема STREAMS предлагает механизм обмена управляющими командами с помощью вызова ioctl(2).
Однако с помощью ioctl(2), как было показано в разделе "Подсистема STREAMS" главы 5, можно формировать лишь сообщения типа
M_IOCTL
Рис. 6.33. Архитектура доступа к транспортным услугам
Для всех сообщений STREAMS, за исключением сообщений
M_IOCTL
ioctl(fd, I_STR, ...)
M_IOCTL
При этом вызов ioctl(2) имеет следующий формат:
#include <sys/stropts.h>
struct strioctl my_strioctl
...
strioctl.ic_cmd = cmd;
strioctl.ic_timeout = INFTIM;
strioctl.ic_len = size;
strioctl.ic_dp = (char*)buf;
ioctl(fd, I_STR, &my_strioctl);
При вызове ioctl(2) поле
size
cmd
buf
size
Модуль timod(7M) служит для обработки следующих команд cmd:
Значение cmd | Обработка модулем timod(7M) |
---|---|
TI_BIND | Команда преобразуется в примитив T_BIND_REQ buf T_BIND_ACK |
TI_UNBIND | Команда преобразуется в примитив T_UNBIND_REQ buf T_OK_ACK |
TI_GETINFO | Команда преобразуется в примитив T_INFO_REQ buf T_INFO_ACK |
TI_OPTMGMT | Команда преобразуется в примитив T_OPTMT_REQ buf T_OPTMGMT_ACK |
Интерфейс DLPI
DLPI определяет интерфейс между протоколами уровня канала данных (data link layer) модели OSI, называемыми поставщиками услуг уровня канала данных и протоколами сетевого уровня, называемыми пользователями услуг уровня канала данных. В качестве примера пользователей услуг уровня канала данных можно привести такие протоколы, как IP, IPX или CLNS. С другой стороны, поставщик услуг уровня канала данных непосредственно взаимодействует с различными сетевыми устройствами, обеспечивающими передачу данных по сетям различной архитектуры (например, Ethernet, FDDI или ATM) и использующими различные физические среды передачи.