Если оболочка не загружена, завершаем
Листинг 4
Функции для программы SLIST.CPP // Файл slist!\sap.cpp // // (C) A. Frolov, 1993 // ===================================================
#include <stdlib.h>
#include <stdio.h>
#include <mem.h>
#include <string.h>
#include <dos.h>
#include "sap.hpp"
// ==================================================== // Конструктор класса SLIST // ====================================================
SLIST::SLIST(int ServiceType) {
// Проверяем наличие сетевой оболочки и определяем ее версию
MajorVersion = 0;
asm push si GetNetWareShellVersion(&MajorVersion, &MinorVersion, &Revision);
asm pop si
// Если оболочка не загружена, завершаем работу // программы с сообщением об ошибке
if(MajorVersion == 0) { printf("\nОболочка NetWare не загружена\n");
errno = 0xff; return; }
// Проверяем тип SAP-запроса
if (ServiceType != 1 && ServiceType != 3) { errno = NOT_SUPPORTED; return; } // Запоминаем тип запроса
QueryType = ServiceType;
// Инициализируем драйвер протокола IPX
IPXInitialize();
// Открываем короткоживущий динамический сокет
SrcSocket = 0x00; errno = IPXOpenSocket(&SrcSocket, SHORT_LIVED);
// Заполняем таблицу имен серверов нулями
memset(ServerName,0,sizeof(ServerName));
// Подготавливаем блоки ECB для приема // пакетов от SAP-протокола
for(int i=0;i<MAX_SERVERS;i++) {
// Заполняем блок ECB
ReceiveSAPPacket(&Query[i]);
// Ставим в очередь на прием пакета
IPXListenForPacket(&Query[i].theECB);
}
// Если не было ошибок, посылаем запрос
if (!errno) { SendSAPPacket();
// Ждем примерно одну секунду
sleep(1);
// Переписываем имена серверов и другую информацию
GetServersName();
GetServersInfo();
} }
// ==================================================== // Деструктор класса SLIST // ====================================================
SLIST::~SLIST() {
// Отменяем ожидающие блоки ECB
for(int i=0;i<MAX_SERVERS;i++) { IPXCancelEvent(&Query[i].theECB);
}
// Закрываем сокет
IPXCloseSocket(SrcSocket);
}
// ==================================================== // Посылка SAP-запроса // ==================================================== void SLIST::SendSAPPacket(void) {
// Сбрасываем поле inUseFlag и ESRAddress, устанавливаем тип пакета 0
SendPacket.theECB.inUseFlag = 0; SendPacket.theECB.ESRAddress = 0; SendPacket.SAPq.packetType = 0;
// SAP-пакет состоит из одного фрагмента. Записываем в ECB // количество фрагментов, адрес и размер буфера
SendPacket.theECB.fragmentCount = 1; SendPacket.theECB.fragmentDescriptor[0].address = &SendPacket.SAPq; SendPacket.theECB.fragmentDescriptor[0].size = sizeof(SAPQueryPacket);
// Записываем в ECB номер своего сокета
SendPacket.theECB.socketNumber = SrcSocket;
// Устанавливаем адрес назначения - все станции в текущей сети, // сокет SAP_SOCKET. Устанавливаем поле непосредственного адреса
memset(SendPacket.SAPq.destination.network, '\x00', 4);
memset(SendPacket.SAPq.destination.node, '\xFF', 6);
SendPacket.SAPq.destination.socket = IntSwap(SAP_SOCKET);
memset(SendPacket.theECB.immediateAddress, '\xFF', 6);
// Устанавливаем свой адрес в заголовке запроса
IPXGetInternetworkAddress(SendPacket.SAPq.source.network);
SendPacket.SAPq.source.socket = IntSwap(SrcSocket);
// Заполняем передаваемый пакет. Устанавливаем тип запроса // и тип сервера
SendPacket.SAPq.queryType = IntSwap(QueryType);
SendPacket.SAPq.serverType = IntSwap(0x0004);
// Посылаем SAP-пакет
IPXSendPacket(&SendPacket.theECB);
// Ожидаем завершения процесса передачи пакета
while (SendPacket.theECB.inUseFlag) IPXRelinquishControl();
// Сохраняем код возврата
errno = SendPacket.theECB.completionCode; }
// ==================================================== // Прием SAP-пакетов // ====================================================
void SLIST::ReceiveSAPPacket(RECEIVE_PACKET *Query) {
// Сбрасываем поле inUseFlag и ESRAddress
Query->
theECB.inUseFlag = 0; Query->
theECB.ESRAddress = 0; // Записываем в ECB количество фрагментов, адрес и размер буфера
Query->
theECB.fragmentCount = 1; Query->
theECB.fragmentDescriptor[0].address = &Query->
SB; Query->
theECB.fragmentDescriptor[0].size = sizeof(Query->
SB);
// Устанавливаем в ECB свой номер сокета
Query->
theECB.socketNumber = SrcSocket; }
// ==================================================== // Процедура переписывает имена серверов из тех // блоков ECB, для которых пришли пакеты // ====================================================
void SLIST::GetServersName(void) {
for(int i=0,j=0; i<MAX_SERVERS; i++) { if(!Query[i].theECB.inUseFlag) { strcpy(ServerName[j],Query[i].SB.ServerName);
j++; } } }
// ==================================================== // Процедура получает информацию о серверах // ====================================================
void SLIST::GetServersInfo(void) {
// Получаем номера каналов первичного сервера // и сервера по умолчанию
PrimaryConnID = GetPrimaryConnectionID();
DefaultConnID = GetDefaultConnectionID();
// Цикл по всем обнаруженным в сети активным серверам
for(int i=0; i<MAX_SERVERS; i++) { if(ServerName[i][0]) {
// Получаем номер канала сервера
errno = GetConnectionID(ServerName[i], &ConnID[i]);
// Если канала нет, создаем его, подключаясь к серверу
if(errno) { AttachToFileServer(ServerName[i], &ConnID[i]);
}
// Делаем текущий сервер предпочтительным, так как // именно к нему должны поступать запросы
errno = SetPreferredConnectionID(ConnID[i]);
// Получаем информацию о текущем сервере
if(!errno) errno = GetServerInformation(sizeof(ServerInfo[i]), &ServerInfo[i]);
// Получаем серийный номер и номер приложения
SerialNumber[i]=ApplicationNumber[i]=0L; errno = GetNetworkSerialNumber(&SerialNumber[i], &ApplicationNumber[i]);
errno = 0; } } }
// ============================================================ // Процедура распечатывает имена и другую информацию о серверах // ============================================================
void SLIST::PrintServersName(void) {
// Цикл по всем обнаруженным в сети активным серверам
for(int i=0; i<MAX_SERVERS; i++) { if(ServerName[i][0]) {
// Выводим имя сервера
printf("%s",ServerInfo[i].serverName);
// Если номер канала текущего сервера совпадает с // номером канала первичного сервера, выводим строку "\t[Primary]"
if(ConnID[i] == PrimaryConnID) printf("\t[Primary]");
else printf("\t[ ]");
// Если номер канала текущего сервера совпадает с // номером канала сервера по умолчанию, выводим строку " [Default]"
if(ConnID[i] == DefaultConnID) printf(" [Default]");
else printf(" [ ]");
// Выводим версию сетевой операционной системы, // работающей на текущем сервере
printf(" v.%d.%d, ", ServerInfo[i].netwareVersion, ServerInfo[i].netwareSubVersion);
// Для подключенных серверов выводим серийный // номер и номер приложения
if(SerialNumber[i] != 0L) printf("s/n %08.8lX/%04.4X", SerialNumber[i], ApplicationNumber[i]);
else printf("- Not Logged In -");
// Выводим номер канала, используемого для связи с текущим сервером
printf("\tConnID: %d,",ConnID[i]);
// Выводим максимальное число каналов, поддерживаемых // сервером, и количество используемых каналов
printf(" (%d-%d)\n", ServerInfo[i].maxConnectionsSupported, ServerInfo[i].connectionsInUse);
} } }
Файл sap.hpp содержит все определения констант и описания структур, необходимые для программы SLIST. В частности, в этом файле описан класс SLIST.
// ===================================================
Содержание Назад Вперед