Читаем Операционная система UNIX полностью

 if (okack->PRIM_type == T_OK_ACK) {

  /* Если подтверждение положительное, подготовимся к получению

     согласия удаленного пользователя на установление связи

     (примитив T_CONN_CON) */

  free(ack.buf);

  if (recvcall != NULL) {

   addr = recvcall->addr;

   opt = recvcall->opt;

   udata = recvcall->udata;

   confirm.len = sizeof(struct T_conn_con) + addr.len + opt.len;

   confirm.maxlen =

    sizeof(struct T_conn_con) + addr.maxlen + opt.maxlen;

   buf = (char*)malloc(confirm.maxlen);

   confirm.buf = buf;

   m_data.len = udata.len;

   m_data.maxlen = udata.maxlen;

   m_data.buf = udata.buf;

   /* Получим примитив T_CONN_CON */

   getmsg(fd, &confirm, &m_data, &flags);

   free(buf);

   conncon = (struct T_conn_con*)confirm.buf;

   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. При использовании протокола UDP все данные будут передаваться с помощью примитивов 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. Для преобразования этих сообщений в примитивы TPI служит дополнительный модуль timod(7M), встраиваемый в поток между головным и транспортным модулями. На рис. 6.33 показано местоположение модуля timod(7M) и схематически отображены его функции.

Рис. 6.33. Архитектура доступа к транспортным услугам

Перейти на страницу:

Похожие книги