Формат блока ECB
Формат блока ECB представлен на рис. 3.
Рис. 3. Формат блока ECB
Блок ECB состоит из фиксированной части размером 36 байт и массива дескрипторов, описывающих отдельные фрагменты передаваемого или принимаемого пакета данных. Приведем структуру, которую вы можете использовать для описания блока ECB в программах, составленных на языке Си:
struct ECB { void far *Link; void far (*ESRAddress)(void); unsigned char InUse; unsigned char CCode; unsigned int Socket; unsigned int ConnectionId; unsigned int RrestOfWorkspace; unsigned char DriverWorkspace[12]; unsigned char ImmAddress[6]; unsigned int FragmentCnt; struct { void far *Address; unsigned int Size; } Packet[2]; };
Рассмотрим назначение отдельных полей блока ECB.
Поле Link предназначено для организации списков, состоящих из блоков ECB. Драйвер IPX использует это поле для объединения переданных ему блоков ECB в списки, записывая в него полный адрес в формате [сегмент:смещение]. После того, как IPX выполнит выданную ему команду и закончит все операции над блоком ECB, программа может распоряжаться полем Link по своему усмотрению. В частности, она может использовать это поле для организации списков или очередей свободных или готовых для чтения блоков ECB.
Поле ESRAddress содержит полный адрес программного модуля (в формате [сегмент:смещение]), который получает управление при завершении процесса чтения или передачи пакета IPX. Этот модуль называется программой обслуживания события ESR (Event Service Routine). Если ваша программа не использует ESR, она должна записать в поле ESRAddress нулевое значение. В этом случае о завершении выполнения операции чтения или передачи можно узнать по изменению содержимого поля InUse.
Поле InUse, как мы только что заметили, может служить индикатором завершения операции приема или передачи пакета. Перед тем как вызвать функцию IPX, программа записывает в поле InUse нулевое значение. Пока опе-
рация передачи данных, связанная с данным ECB, не завершилась, поле InUse содержит ненулевые значения:
FFh | ECB используется для передачи пакета данных; |
FEh | ECB используется для приема пакета данных, предназначенного программе с определенным сокетом; |
FDh | ECB используется функциями асинхронного управления событиями AES (Asynchronous Event Sheduler), ECB находится в состоянии ожидания истечения заданного временного интервала; |
FBh | пакет данных принят или передан, но ECB находится во внутренней очереди IPX в ожидании завершения обработки. |
Программа может постоянно опрашивать поле InUse, ожидая завершения процесса передачи или приема данных. Как только в этом поле окажется нулевое значение, программа может считать, что запрошенная функция выполнена. Результат выполнения можно получить в поле CCode.
Поле CCode после выполнения функции IPX (после того, как в поле InUse будет нулевое значение) содержит код результата выполнения.
Если с данным ECB была связана команда приема пакета, в поле CCode могут находиться следующие значения:
00 | пакет был принят без ошибок; |
FFh | указанный в ECB сокет не был предварительно открыт программой; |
FDh | переполнение пакета: либо поле количества фрагментов в пакете FragmentCnt равно нулю, либо буферы, описанные дескрипторами фрагментов, имеют недостаточный размер для записи принятого пакета; |
FCh | запрос на прием данного пакета был отменен специальной функцией драйвера IPX. |
00 | пакет был передан без ошибок (что, кстати, не означает, что пакет был доставлен по назначению и успешно принят станцией-адресатом, так как протокол IPX не обеспечивает гарантированной доставки пакетов); |
FFh | пакет невозможно передать физически из-за неисправности в сетевом адаптере или в сети; |
FEh | пакет невозможно доставить по назначению, так как станция с указанным адресом не существует или неисправна; |
FDh | сбойный: либо имеет длину меньше 30 байт, либо первый фрагмент пакета по размеру меньше размера стандартного заголовка пакета IPX, либо поле количества фрагментов в пакете FragmentCnt равно нулю; |
FCh | запрос на передачу данного пакета был отменен специальной функцией драйвера IPX. |
Поле Socket содержит номер сокета, связанный с данным ECB. Если ECB используется для приема, это поле содержит номер сокета, на котором выполняется прием пакета. Если же ECB используется для передачи, это поле содержит номер сокета передающей программы (но не номер сокета той программы, которая должна получить пакет).
Поле IPXWorkspace зарезервировано для использования драйвером IPX. Ваша программа не должна инициализировать или изменять содержимое этого поля, пока обработка ECB не завершена.
Поле DriverWorkspace зарезервировано для использования драйвером сетевого адаптера. Ваша программа не должна инициализировать или изменять содержимое этого поля, так же как и поля IPXWorkspace, пока обработка ECB не завершена.
Поле ImmAddress (Immediate Address - непосредственный адрес) содержит адрес узла в сети, в который будет направлен пакет. Если пакет передается в пределах одной сети, поле ImmAddress будет содержать адрес станции-получателя (такой же, как и в заголовке пакета IPX). Если же пакет предназначен для другой сети и будет проходить через мост, поле ImmAddress будет содержать адрес этого моста в сети, из которой передается пакет.
Поле FragmentCnt содержит количество фрагментов, на которые надо разбить принятый пакет, или из которых надо собрать передаваемый пакет. В простейшем случае весь пакет, состоящий из заголовка и данных, может представлять собой непрерывный массив. Однако часто удобнее хранить отдельно
данные и заголовок пакета. Механизм фрагментации позволяет вам избежать пересылок данных или непроизводительных потерь памяти. Вы можете указать отдельные буферы для приема данных и заголовка пакета. Если сами принимаемые данные имеют какую-либо структуру, вы можете рассредоточить отдельные блоки по соответствующим буферам.
Значение, записанное вами в поле FragmentCnt, не должно быть равно нулю. Если в этом поле записано значение 1, весь пакет вместе с заголовком записывается в один общий буфер.
Сразу вслед за полем FragmentCnt располагаются дескрипторы фрагментов, состоящие из указателя в формате [сегмент:смещение] на фрагмент Address и поля размера фрагмента Size.
Если программе надо разбить принятый пакет на несколько частей, она должна установить в поле FragmentCnt значение, равное количеству требуемых фрагментов. Затем для каждого фрагмента необходимо создать дескриптор, в котором указать адрес буфера и размер фрагмента. Аналогичные действия выполняются и при сборке пакета перед передачей из нескольких фрагментов.
Отметим, что самый первый фрагмент не должен быть короче 30 байт, так как там должен поместиться заголовок пакета IPX.