Windows NT Systems Programming: Spring 2000

[ Home | Syllabus | Course Notes | Assignments | Search]


Version 3 Multiple Server main program

Concepts to be demonstrated:

FULL CODE HERE


Client Side

// ****
// verifyFolder - verifies then creates/opens message folder
bool CMsgFolder::verifyFolder(const char* name)
{
	DWORD nBytes;
	
	if(client_CreateDirectory(name,0)) {
		cout << "Created Directory:" <<  name << endl;
		if(!client_SetCurrentDirectory(name)) {
			cerr << "Could not set message folder" << name << GetLastError();
			return false;
		}
		// create "messages" file with magic cookie
		messages = client_CreateFile("messages",GENERIC_WRITE,0,0,CREATE_NEW,0,0);
		if(messages == INVALID_HANDLE_VALUE) {
			cerr << "Could not create messages file" << GetLastError();
			return false;
		}
		nextMsgNum = 0;
		return true;
	}
	else {
		if(!client_SetCurrentDirectory(name)) {
			cerr << "Could not set message folder" << name << GetLastError();
			return false;
		}
		// Now check if this folder contains a "messages" file with the magic cookie
		messages = client_CreateFile(
			"messages",
			GENERIC_READ|GENERIC_WRITE, // read then write this file
			0,0,
			OPEN_EXISTING,
			0,0);
		if(messages == INVALID_HANDLE_VALUE) {
			cerr << "Could not open messages file" << GetLastError();
			return false;
		}
		int cookie;
		if(!client_ReadFile(messages, (LPBYTE) &cookie, sizeof(cookie), &nBytes, NULL)) {
			cerr << "Could not read magic cookie!" << GetLastError();
			return false;
		}
		if(cookie != MAGIC_COOKIE) {
			cerr << "no magic cookie!\n";
			return false;
		}
		if(!client_ReadFile(messages, (LPBYTE) &nextMsgNum, sizeof(nextMsgNum), &nBytes, NULL)) {
			cerr << "Could not nMessages!" << GetLastError();
			return false;
		}
		
		// now read messages list
		if(!msgList.ReadListMsgs(messages)) {
			cerr << "Could not read message list\n";
			return false;
		}
		return true;
	}
	
}

//**********************************************
// Packet.cpp: implements several useful functions for
// communicating between clients and servers for version 2
// Does not support GetLastError between client and server

#include "packet.h"
#include <iostream.h>

SOCKET connect2server(const char* serverIP)
{
	SOCKADDR_IN serverSockAddr;
	SOCKET socket2server;
	WSADATA Data;
	int status;
	
	status=WSAStartup(MAKEWORD(1, 1), &Data);
	if (status != 0) {
		cerr << "ERROR: WSAStartup unsuccessful" << endl;
		return INVALID_SOCKET;
	}

	socket2server=socket(AF_INET, SOCK_STREAM, 0);
	if (socket2server == INVALID_SOCKET)
	{
		cerr << "ERROR: socket unsuccessful" << endl;
		status=WSACleanup();
		if (status == SOCKET_ERROR)
			cerr << "ERROR: WSACleanup unsuccessful" << endl;
		return INVALID_SOCKET;
	}

	serverSockAddr.sin_addr.s_addr=inet_addr(serverIP);
	serverSockAddr.sin_port=htons(PORT);
	serverSockAddr.sin_family=AF_INET;
	
		
	status=connect(socket2server,
		(LPSOCKADDR) &serverSockAddr,
		sizeof(serverSockAddr));
	if (status == SOCKET_ERROR)
	{
		cerr << "ERROR: connect unsuccessful" << endl;
		status=closesocket(socket2server);
		if (status == SOCKET_ERROR)
			cerr << "ERROR: closesocket unsuccessful"
			<< endl;
		status=WSACleanup();
		if (status == SOCKET_ERROR)
			cerr << "ERROR: WSACleanup unsuccessful"
			<< endl;
		return INVALID_SOCKET;
	}
	return socket2server;
	
}

//*****************************
//** client_CreateDirectory: simulates client side RPC for CreateDirectory
// does not support security parameter
// PRE: socket2server connection is open

bool client_CreateDirectory(LPCTSTR name, LPSECURITY_ATTRIBUTES dummy)
{
	PCKT_CREATE_DIRECTORY_IN pcktCD;
	PCKT_CREATE_DIRECTORY_OUT pcktCDout;
		
	if (!sendControl(socket2server, CREATE_DIRECTORY))
		return  false;
	memcpy(pcktCD.name, name, SIZE_NAME); // marshall string in to packet
	if(!sendPacket(socket2server, LPBYTE(&pcktCD), sizeof(pcktCD)))
		return false;
	if(!getPacket(socket2server, LPBYTE(&pcktCDout), sizeof(pcktCDout)))
		return false;
	if(pcktCDout.status != SUCCESS)
		return false;
	return pcktCDout.returnValue; // marshall return value
	
}


//*****************************
//** client_CreatFile: simulates client side RPC for CreateFile
// does not supprt share, security, attributes, and template file parameters
// PRE: socket2server connection is open

HANDLE client_CreateFile(LPCTSTR fileName, DWORD access, DWORD share, LPSECURITY_ATTRIBUTES dummy1, 
				  DWORD create, DWORD attributes, HANDLE templateFile)
{
	PCKT_CREATE_FILE_IN pcktCF;
	PCKT_CREATE_FILE_OUT pcktCFout;
		
	if (!sendControl(socket2server, CREATE_FILE))
		return  INVALID_HANDLE_VALUE;
	memcpy(pcktCF.fileName, fileName, SIZE_NAME);
	pcktCF.accessMode = access;
	pcktCF.createMode = create;
	if(!sendPacket(socket2server, LPBYTE(&pcktCF), sizeof(pcktCF)))
		return INVALID_HANDLE_VALUE;
	if(!getPacket(socket2server, LPBYTE(&pcktCFout), sizeof(pcktCFout)))
		return INVALID_HANDLE_VALUE;
	if(pcktCFout.status != SUCCESS)
		return INVALID_HANDLE_VALUE;
	return pcktCFout.fileHandle;
	
}
//***********************************
//** client_WriteFile: simulates client side RPC for WriteFile
// does not support overlapped parameter
// PRE: socket2server connection is open

bool client_WriteFile(HANDLE fileHandle, LPCVOID buffer, DWORD nBytes, LPDWORD nBytesOut, LPOVERLAPPED dummy)
{
	PCKT_WRITE_FILE_IN pcktWF;
	PCKT_WRITE_FILE_OUT pcktWFout;

	if (!sendControl(socket2server, WRITE_FILE))
		return false;
	pcktWF.fileHandle = fileHandle;
	memcpy(pcktWF.buffer, buffer, nBytes);
	pcktWF.nBytesIn = nBytes;
	if(!sendPacket(socket2server, LPBYTE(&pcktWF), sizeof(pcktWF)))
		return false;
	if(!getPacket(socket2server, LPBYTE(&pcktWFout), sizeof(pcktWFout)))
		return false;
	if(pcktWFout.status != SUCCESS)
		return false;
	*nBytesOut = pcktWFout.nBytesOut;
	return true;
}


//***** SetEndOfFile RPC section

//** sendControl - sends a network control word
// PRE: socket2server is ready for communications
// POST: sends "request" to socket2server
// on network failure - closes socket and cleans up TCP connection
bool sendControl(SOCKET socket2server, NET_CONTROL request)
{
	char* Ptr = (char*) &request;
	int numsnt = send(socket2server, Ptr, sizeof(request), 0);
	if (numsnt != sizeof(request)) {
		//		TRACE("Could not send request:%d", (int) WSAGetLastError());
		closesocket(socket2server);
		WSACleanup();
		return false;
	}
	return true;
}

//*************************************
//** getControl: receives a network control word

NET_CONTROL getControl(SOCKET socket2server)	
{
	NET_CONTROL reply;
	int numrcv = recv(socket2server, (char*) &reply, sizeof(reply),0);
	if(numrcv != sizeof(reply))
		return FAILURE;
	return reply;
}

//******************************************
//** sendPacket: sends packet to socket2server
bool sendPacket(SOCKET socket2server, LPBYTE packet, int size)
{
	int numsnt = send(socket2server, (char*) packet, size, 0);
	if (numsnt != size) {
		//TRACE("Could not send fileHandle:%d", (int) WSAGetLastError());
		closesocket(socket2server);
		WSACleanup();
		return false;
	}
	return true;
}


bool getPacket(SOCKET socket2server, LPBYTE packet, int size)
{
	int numrcv = recv(socket2server, (char*) packet, size,0);
	if(numrcv != size)
		return false;
	return true;
}

Server Side

//***********************************************
// Simple Message Filer (Version3): SERVER SIDE
// This implementation introduces a multi-client server solution
// each client is serviced by a separate thread
// Uses "file locking" to prevent simulataneous access to a message folder
// Message folder naming structure is flat at the present time
// there is no authentification or security provided
// Basically the server implements remote versions of
// the following procedure calls (a home built RPC)
//		CreateDirectory
//		SetCurrentDirectory
//		SetFilePointer
//		CreateFile
//		ReadFile
//		WriteFile
//		CloseHandle
// This RPC DOES NOT preserve GetLastError state
//
//		PACKET FORMATS:
// Requests consist of two packets.
// First packet is request type (which of the four procedure calls to do)
// Second Packet is the argument list for the procedure call
// Response Packet is 
//	Status (Success/Failure of RPC)
//	Return arguments
//	The type and values of the request and reply packets are defined in "packets.h"

//	AUTHOR: chris wild
//	DATE: September 6, 1997
//*************************************************




#include "packet.h"	// packet formats and constants
#include <iostream.h>
#include <windows.h>
#include <process.h> // for locking file?

// Prototype to thread call
VOID  talkToClient(VOID *  cs);

int main()
{
// . . .
	DWORD threadID;
	HANDLE clientThread; 
	
	serverSocket = getServerSocket(); // contains the "listen" API
	
	while (true) {
		// accept a connection from a client
		clientSocket=accept(serverSocket,
			(LPSOCKADDR) &clientSockAddr,
			&addrLen);
//. . .spawn a thread to handle this client.
		clientThread = CreateThread  (0, // no child process cannot inherit
			0, // gives same stack space as parent thread
			(LPTHREAD_START_ROUTINE) talkToClient,
			(VOID *) clientSocket, // Pass in one parameter
			 0,  // Put into ready Q
			&threadID);  // system wide thread ID
// . . .
	}
	
}


VOID talkToClient(VOID *cs)
{
	SOCKET socket2client=(SOCKET)cs; 
	NET_CONTROL request;

	while(TRUE) // loop until killed
	{
		request = getControl(socket2client);
		if (request == FAILURE) {
			shutdown(socket2client, 2);  // 2 shutdown send and receive
			closesocket(socket2client);
			ExitThread(0); 
		}
		switch (request)
		{
		case CREATE_DIRECTORY:
           		SetCurrentDirectory(ParentDir);  
			server_CreateDirectory(socket2client);
			break;
		case SET_CURRENT_DIRECTORY:
			strcpy(CurrPath, server_SetCurrentDirectory(socket2client));
			setFlg = 1;
			break;
			
		case CREATE_FILE:
			server_CreateFile(socket2client);
			break;
		case READ_FILE:
			server_ReadFile(socket2client);
			break;
		case WRITE_FILE:
			server_WriteFile(socket2client);
			break;
		case SET_FILE_POINTER:
			server_SetFilePointer(socket2client);
			break;
		case CLOSE_HANDLE:
			server_CloseHandle(socket2client);
			break;
		case DELETE_FILE:
			server_DeleteFile(socket2client);
			break;
		case SET_END_OF_FILE:
			server_SetEndOfFile(socket2client);
			break;
		
		default:
			;
			// ignore and hope you get back into sync
		}
		
	}
}


//****************
// getServerSocket: sets up a server socket to listen on a known port

SOCKET getServerSocket()
{
	WSADATA Data;
	SOCKADDR_IN serverSockAddr;
	SOCKET serverSocket;
	int addrLen=sizeof(SOCKADDR_IN);
		
	int status;
	
	status=WSAStartup(MAKEWORD(1, 1), &Data);	// ONLY REQUIRES VERSION 1.1 OF DLL
	if (status != 0) {
		cerr << "ERROR: WSAStartup unsuccessful" 
			<< endl;
		ExitProcess(1);
	}
	
	memset(&serverSockAddr, 0, sizeof(serverSockAddr));
	serverSockAddr.sin_port=htons(PORT);
	serverSockAddr.sin_family=AF_INET;
	serverSockAddr.sin_addr.s_addr=htonl(INADDR_ANY);
	
	serverSocket=socket(AF_INET, SOCK_STREAM, 0);
	if (serverSocket == INVALID_SOCKET) {
		cerr << "ERROR: socket unsuccessful" << endl;
		ExitProcess(1);
	}
	
	status=bind(serverSocket, 
		(LPSOCKADDR) &serverSockAddr,
		sizeof(serverSockAddr));
	if (status == SOCKET_ERROR) {
		cerr << "ERROR: bind unsuccessful" << endl;
		ExitProcess(1);
	}
	
	status=listen(serverSocket, 1);
	if (status == SOCKET_ERROR) {
		cerr << "ERROR: listen unsuccessful" << endl;
		ExitProcess(1);
	}
	return serverSocket;
}

void server_CreateDirectory(SOCKET socket2client)
{
	PCKT_CREATE_DIRECTORY_IN pcktCDin;
	PCKT_CREATE_DIRECTORY_OUT pcktCDout;
	
	if(!getPacket(socket2client, LPBYTE(&pcktCDin), sizeof(pcktCDin)))
	{
		cout << "Could not get CREATE_DIRECTORY packet" << endl;
		pcktCDout.status = FAILURE;
		sendPacket(socket2client, (LPBYTE) &pcktCDout, sizeof(pcktCDout));
		closesocket(socket2client);
		WSACleanup();
		ExitProcess(1);
	}
	if(CreateDirectory(pcktCDin.name,0)) {
		pcktCDout.status = SUCCESS;
		pcktCDout.returnValue = true;
	}
	else {
		pcktCDout.status = SUCCESS;
		pcktCDout.returnValue = false;
	}

	if(!sendPacket(socket2client, LPBYTE(&pcktCDout), sizeof (pcktCDout))) {
		cout << "Could not send CREATE_DIRECTORY" << endl;
		closesocket(socket2client);
		WSACleanup();
		ExitProcess(1);
	}

}


void server_CreateFile(SOCKET socket2client)
{
	PCKT_CREATE_FILE_IN pcktCFin;
	PCKT_CREATE_FILE_OUT pcktCFout;
	HANDLE fileHandle;
	
	if(!getPacket(socket2client, LPBYTE(&pcktCFin), sizeof(pcktCFin)))
	{
		cout << "Could not get CREATE_FILE packet" << endl;
		pcktCFout.status = FAILURE;
		sendPacket(socket2client, (LPBYTE) &pcktCFout, sizeof(pcktCFout));
		closesocket(socket2client);
		WSACleanup();
		ExitProcess(1);
	}
	fileHandle = CreateFile(pcktCFin.fileName, pcktCFin.accessMode,0,0, pcktCFin.createMode,0,0);
	pcktCFout.status = SUCCESS;
	pcktCFout.fileHandle = fileHandle; // send handle back
	if(!sendPacket(socket2client, LPBYTE(&pcktCFout), sizeof (pcktCFout))) {
		cout << "Could not get CREATE_FILE" << endl;
		closesocket(socket2client);
		WSACleanup();
		ExitProcess(1);
	}
}


void server_WriteFile(SOCKET socket2client)
{
	PCKT_WRITE_FILE_IN pcktWFin;
	PCKT_WRITE_FILE_OUT pcktWFout;
	
	
	if(!getPacket(socket2client, LPBYTE(&pcktWFin), sizeof(pcktWFin)))
	{
		cout << "Could not get READ_FILE packet" << endl;
		pcktWFout.status = FAILURE;
		sendPacket(socket2client, LPBYTE(&pcktWFout), sizeof(pcktWFout));
		closesocket(socket2client);
		WSACleanup();
		ExitProcess(1);
	}
	if(WriteFile(pcktWFin.fileHandle, pcktWFin.buffer,  
		pcktWFin.nBytesIn,&(pcktWFout.nBytesOut),0))
		pcktWFout.status = SUCCESS;
	else
		pcktWFout.status = FAILURE;
	if(!sendPacket(socket2client, LPBYTE(&pcktWFout), sizeof (pcktWFout))) {
		cout << "Could not READ_FILE" << endl;
		closesocket(socket2client);
		WSACleanup();
		ExitProcess(1);
	}
}



Copyright chris wild 1999/2000.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: February 24, 2000.