// ===================================================
// Листинг 12. Сервер SPX
//
// Файл spxserv.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) {

// Используем сокет 0x4568

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

// Этот ECB мы будем использовать и для приема
// пакетов, и для их передачи.

	struct ECB RxECB;
	struct ECB ConnECB, LsECB;

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

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

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

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

	struct SPXParams Params;

	unsigned char ClientImmAddress[6];

	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("Ошибка при открытии сокета IPX\n");
		exit(-1);
	};

// Подготавливаем 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);
		printf("Для продолжения нажмите любую клавишу\n");
		getch();

		memcpy(ClientImmAddress, RxECB.ImmAddress,6);

// Подготавливаем ECB для передачи пакета
// Поле ImmAddress не заполняем, так как там
// уже находится адрес станции клиента.
// Это потому, что мы только что приняли от клиента
// пакет данных и при этом в ECB установился
// непосредственный адрес станции, которая
// отправила пакет

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

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

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

// Подготавливаем передаваемые данные

		strcpy(TxBuffer, "SPX SERVER *DEMO*");

// Передаем пакет обратно клиенту

		IPXSendPacket(&RxECB);

		printf("Связь с сервером установлена\n");
		printf("Создаем SPX-канал\n\n");

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

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

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

		memset(&LsECB, 0, sizeof(LsECB));
		LsECB.Socket            = IntSwap(SPXSocket);
		memcpy(LsECB.ImmAddress, ClientImmAddress,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, ClientImmAddress, 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);

// Ожидаем запрос на создание канала

		SPXListenForConnection(&ConnECB,0,0);

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

		if(ConnECB.CCode == 0) {
			printf("Канал %04.4X создан\n",
				(unsigned)ConnECB.ConnectionId);
		}

// Ожидаем прихода SPX-пакета от клиента

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

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

	IPXCloseSocket(&IPXSocket);
	IPXCloseSocket(&SPXSocket);
	exit(0);
}