// ===================================================
// Листинг 13. Клиент SPX
//
// Файл spxclien.c
//
// (C) A. Frolov, 1993
// ===================================================

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <mem.h>
#include <string.h>
#include "ipx.h"
#include "spx.h"

// Максимальный размер буфера данных

#define BUFFER_SIZE 512

void main(void) {

// Будем работать с сокетом 0x4567

	static unsigned IPXSocket = 0x4567;
	static unsigned SPXSocket = 0x4568;

// ECB для приема и передачи пакетов

	struct ECB RxECB, TxECB;
	struct ECB ConnECB, LsECB, SndECB;

// Заголовки принимаемых и передаваемых пакетов

	struct IPX_HEADER RxHeader, TxHeader;
	struct SPX_HEADER ConnHeader, LsHeader, SndHeader;

// Буфера для принимаемых и передаваемых данных

	unsigned char RxBuffer[BUFFER_SIZE];
	unsigned char TxBuffer[BUFFER_SIZE];

	struct SPXParams Params;

	unsigned char ServerImmAddress[6];
	unsigned MyConnID, ConnID;
	unsigned rc;


	printf("\n*Клиент SPX*, (C) Фролов А., 1993\n\n");

// Проверяем наличие драйвера IPX и определяем
// адрес точки входа его API

	if(ipx_init() != 0xff) {
		printf("IPX не загружен!\n"); exit(-1);
	}

	if( SPXCheckSPXInstallation(&Params) != 0xFF) {
		printf("SPX не загружен!\n"); exit(-1);
	}

// Открываем сокет, на котором мы будем
// принимать и передавать пакеты

	if(IPXOpenSocket(SHORT_LIVED, &IPXSocket)) {
		printf("Ошибка при открытии сокета\n");
		exit(-1);
	};

// Открываем сокет для протокола SPX

	if(IPXOpenSocket(SHORT_LIVED, &SPXSocket)) {
		printf("Ошибка при открытии сокета SPX\n");
		exit(-1);
	};

// Подготавливаем ECB для передачи пакета

	memset(&TxECB, 0, sizeof(TxECB));

	TxECB.Socket            = IntSwap(IPXSocket);
	TxECB.FragmentCnt       = 2;
	TxECB.Packet[0].Address = &TxHeader;
	TxECB.Packet[0].Size    = sizeof(TxHeader);
	TxECB.Packet[1].Address = TxBuffer;
	TxECB.Packet[1].Size    = BUFFER_SIZE;

// Пакет предназначен всем станциям данной сети

	memset(TxECB.ImmAddress, 0xff, 6);

// Подготавливаем заголовок пакета

	TxHeader.PacketType = 4;
	memset(TxHeader.DestNetwork, 0, 4);
	memset(TxHeader.DestNode, 0xff, 6);
	TxHeader.DestSocket = IntSwap(IPXSocket);

// Записываем передаваемые данные

	strcpy(TxBuffer, "CLIENT *DEMO*");

// Передаем пакет всем станциям в данной сети

	IPXSendPacket(&TxECB);

// Подготавливаем ECB для приема пакета от сервера

	memset(&RxECB, 0, sizeof(RxECB));
	RxECB.Socket            = IntSwap(IPXSocket);
	RxECB.FragmentCnt       = 2;
	RxECB.Packet[0].Address = &RxHeader;
	RxECB.Packet[0].Size    = sizeof(RxHeader);
	RxECB.Packet[1].Address = RxBuffer;
	RxECB.Packet[1].Size    = BUFFER_SIZE;

	IPXListenForPacket(&RxECB);

	printf("Ожидание ответа от сервера\n");
	printf("Для отмены нажмите любую клавишу\n");

// Ожидаем прихода ответа от сервера

	while(RxECB.InUse) {
		IPXRelinquishControl();
		if(kbhit()) {
			getch();
			RxECB.CCode = 0xfe;
			break;
		}
	}
	if(RxECB.CCode == 0) {
		printf("Принят ответ от сервера '%s'\n", RxBuffer);
	}

// Копируем сетевой адрес сервера

	memcpy(ServerImmAddress, RxECB.ImmAddress, 6);

// Подготавливаем ECB для приема пакета

	memset(&LsECB, 0, sizeof(LsECB));
	LsECB.Socket            = IntSwap(SPXSocket);
	memcpy(LsECB.ImmAddress, ServerImmAddress,6);
	LsECB.FragmentCnt       = 2;
	LsECB.Packet[0].Address = &LsHeader;
	LsECB.Packet[0].Size    = sizeof(LsHeader);
	LsECB.Packet[1].Address = RxBuffer;
	LsECB.Packet[1].Size    = BUFFER_SIZE;

	SPXListenForSequencedPacket(&LsECB);

// Подготавливаем заголовок пакета

	ConnHeader.PacketType = 5;
	ConnHeader.TransportControl = 0;
	memset(ConnHeader.DestNetwork, 0, 4);
	memcpy(ConnHeader.DestNode, ServerImmAddress, 6);
	ConnHeader.DestSocket = IntSwap(SPXSocket);

	memset(&ConnECB, 0, sizeof(ConnECB));
	ConnECB.Socket = IntSwap(SPXSocket);
	ConnECB.FragmentCnt       = 1;
	ConnECB.Packet[0].Address = &ConnHeader;
	ConnECB.Packet[0].Size    = sizeof(ConnHeader);

// Устанавливаем SPX-канал с сервером

	rc = SPXEstablishConnection(&ConnECB, &MyConnID, 0, 0);

	printf("Ожидание SPX-соединения с сервером\n");
	printf("Для отмены нажмите любую клавишу\n");

	if(rc == 0) {
		while(ConnECB.InUse) {
			IPXRelinquishControl();
			if(kbhit()) {
				getch();
				ConnECB.CCode = 0xfe;
				break;
			}
		}
	}

// Копируем идентификатор канала для
// передачи пакета в сервер

	memcpy(&ConnID, &(ConnHeader.SourceConnID), 2);

	printf("Канал с сервером установлен, ConnID=%d\n",
		IntSwap(ConnID));

// Подготавливаем ECB для передачи SPX-пакета

	memset(&SndECB, 0, sizeof(SndECB));

	SndECB.Socket            = IntSwap(SPXSocket);
	SndECB.FragmentCnt       = 2;
	SndECB.Packet[0].Address = &SndHeader;
	SndECB.Packet[0].Size    = sizeof(SndHeader);
	SndECB.Packet[1].Address = TxBuffer;
	SndECB.Packet[1].Size    = BUFFER_SIZE;

	memcpy(SndECB.ImmAddress, ServerImmAddress, 6);

// Подготавливаем заголовок пакета

	SndHeader.PacketType = 5;
	memset(SndHeader.DestNetwork, 0, 4);
	memcpy(SndHeader.DestNode, ServerImmAddress, 6);
	SndHeader.DestSocket = IntSwap(SPXSocket);
	SndHeader.TransportControl = 0;
	SndHeader.DataStreamType = 1;

// Записываем передаваемые данные

	strcpy(TxBuffer, "SPX/CLIENT *DEMO*");

// Передаем SPX-пакет

	SPXSendSequencedPacket(&SndECB, ConnID);

// Закрываем сокеты

	IPXCloseSocket(&IPXSocket);
	IPXCloseSocket(&SPXSocket);

	exit(0);
}