Шрифт:
struct T_ok_ack {
long PRIM_type; /* T_OK_ACK */
long CORRECT_prim; /* корректный примитив */
};
Ожидание завершения установления соединения
46-65
Сообщение T_OK_ACK
, полученное нами на предыдущем этапе, указывает лишь на то, что соединение успешно начало устанавливаться. Теперь нам нужно дождаться сообщения T_CONN_CON
, указывающего на то, что другой конец соединения подтверждает получение запроса на соединение.
struct T_conn_con {
long PRIM_type; /* T_CONN_CON */
long RES_length; /* длина адреса собеседника */
long RES_offset; /* смещение адреса собеседника */
long OPT_length; /* длина параметра */
long OPT_offset; /* смещение параметра */
/* далее следуют адрес протокола и параметры собеседника */
};
Мы снова вызываем функцию
getmsg
, но ожидаемое нами сообщение посылается как сообщение типа M_PROTO
, а не как сообщение M_PCPROTO
, поэтому мы обнуляем флаги. Если мы получаем сообщение T_CONN_CON
, значит, соединение установлено, и мы возвращаемся, но если соединение не было установлено (по причине того, что процесс собеседника не запущен, истекло время ожидания или еще по какой-либо причине), то вместо этого вверх по потоку отправляется сообщение T_DISCON_IND
:
struct T_discon_ind {
long PRIM_type; /* T_DISCON_IND */
long DISCON_reason; /* причина разрыва соединения */
long SEQ_number; /* порядковый номер */
};
Мы можем посмотреть, какие ошибки могут быть возвращены поставщиком. Сначала мы задаем IP-адрес узла, на котором не запущен сервер времени и даты:
solaris26 % tpi_daytime 192.168.1.10
tpi_connect2: T_DISCON_IND from conn (146)
Код 146 соответствует ошибке
ECONNREFUSED
. Затем мы задаем IP-адрес, который не связан с Интернетом:
solaris26 % tpi_daytime 192.3.4.5
tpi_connect2: T_DISCON_IND from conn (145)
На этот раз возвращается ошибка
ETIMEDOUT
. Но если мы снова запустим нашу программу, задавая тот же самый IP-адрес, то получим другую ошибку:
solaris26 % tpi_daytime 192.3.4.5
tpi_connect2: T_DISCON_IND from conn (148)
На этот раз мы получаем ошибку
EHOSTUNREACH
. Различие в том, что в первый раз не было возвращено сообщение ICMP о недоступности узла, а во второй раз мы получили это сообщение. Следующая функция, которую мы рассмотрим, — это
tpi_read
, показанная в листинге 31.5. Она считывает данные из потока. Листинг 31.5. Функция tpi_read: считывание данных из потока
//streams/tpi_read.c
1 #include "tpi_daytime.h"
2 ssize_t
3 tpi_read(int fd, void *buf, size_t len)
4 {
5 struct strbuf ctlbuf;
6 struct strbuf datbuf;
7 union T_primitives rcvbuf;
8 int flags;
9 ctlbuf maxlen = sizeof(union T_primitives);
10 ctlbuf.buf = (char*)&rcvbuf;
11 datbuf.maxlen = len;
12 datbuf.buf = buf;
13 datbuf.len = 0;
14 flags = 0;
15 Getmsg(fd, &ctlbuf, &datbuf, &flags);
16 if (ctlbuf.len >= (int)sizeof(long)) {
17 if (rcvbuf.type == T_DATA_IND)