UNIX: разработка сетевых приложений
Часть 364 из 399 Информация о книге
33 err_quit("tpi_connect: bad length from getmsg");34 switch (rcvbuf.type) {35 case T_OK_ACK:36 break;37 case T_ERROR_ACK:38 if (ctlbuf.len < (int)sizeof(struct T_error_ack))39 err_quit("tpi_connect: bad length for T_ERROR_ACK");40 error_ack = (struct T_error_ack*)&rcvbuf;41 err_quit("tpi_connect: T_ERROR_ACK from conn %d, %d)",42 error_ack->TLI_error, error_ack->UNIX_error);43 default:44 err_quit("tpi connect, unexpected message type: &d", rcvbuf.type);45 }46 ctlbuf.maxlen = sizeof(conn_con);47 ctlbuf.len = 0;48 ctlbuf.buf = (char*)&conn_con;49 flags = 0;50 Getmsg(fd, &ctlbuf, NULL, &flags);51 if (ctlbuf.len < (int)sizeof(long))52 err_quit("tpi_connect2: bad length from getmsg");53 switch (conn_con.msg_hdr.PRIM_type) {54 case T_CONN_CON:55 break;56 case T_DISCON_IND:57 if (ctlbuf.len < (int)sizeof(struct T_discon_ind))58 err_quit("tpi_connect2: bad length for T_DISCON_IND");59 discon_ind = (struct T_discon_ind*)&conn_con.msg_hdr;60 err_quit("tpi_connect2: T_DISCON_IND from conn (%d)",61 discon_ind->DISCON_reason);62 default:63 err_quit("tpi_connect2: unexpected message type. %d",64 conn_con.msg_hdr PRIM_type);65 }66 }Заполнение структуры запроса и отправка поставщикуВ TPI определена структура18-26, содержащая адрес протокола и параметры для соединения:T_conn_reqstruct T_conn_req {long PRIM_type; /* T_CONN_REQ */long DEST_length; /* длина адреса получателя */long DEST_offset; /* смещение адреса получателя */long OPT_length; /* длина параметров */long OPT_offset; /* смещение параметров *//* затем следуют адреса протокола и параметры соединения */};Как и в случае функции
, мы определяем свою собственную структуру с именемtpi_bind, которая включает в себя структуруconn_req, а также содержит место для адреса протокола. Мы заполняем структуруT_conn_req, обнуляя поляconn_reqиOPT_length. Мы вызываем функциюOPT_offsetтолько с управляющей информацией и флагом 0 для отправки сообщения типаputmsgвниз по потоку.M_PROTOЧтение ответаМы вызываем функцию27-45, ожидая получить в ответ либо сообщениеgetmsg, если было начато установление соединения, либо сообщениеT_OK_ACK(которые мы уже показывали выше). В случае ошибки мы завершаем выполнение программы. Поскольку мы не знаем, сообщение какого типа мы получим, то определяем объединение с именемT_ERROR_ACKдля приема всех возможных запросов и ответов и размещаем это объединение в памяти как входной буфер для управляющей информации при вызове функцииT_primitives.getmsgstruct T_ok_ack {long PRIM_type; /* T_OK_ACK */long CORRECT_prim; /* корректный примитив */};Ожидание завершения установления соединенияСообщение46-65, полученное нами на предыдущем этапе, указывает лишь на то, что соединение успешно начало устанавливаться. Теперь нам нужно дождаться сообщенияT_OK_ACK, указывающего на то, что другой конец соединения подтверждает получение запроса на соединение.T_CONN_CONstruct 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_INDstruct T_discon_ind {long PRIM_type; /* T_DISCON_IND */