// ===========================================================
// File: Server.cpp
//
// Implementation of the Server class. Server handles all
// request from Com and Client. It is responsible to
// simultanously service them both while handling and
// maintaining multiple list/queues. By servicing both a
// console and user program, it simulates the activities of
// a simple multi-process virtual OS.
// ===========================================================
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include "Pcib.h"
#include "List.h"
#include "Semaphore.h"
#include "Message.h"
#include "Server.h"
// ===========================================================
// Identifier: Server()
//
// Comments: Server default constructor. Creates two
// structure, an active list and semaphore(s)
// ===========================================================
Server::Server()
{
this->ActiveList = new List;
for (int i = 0; i < MAX_SEM; i++)
{
this->Sem[i] = new Semaphore;
this->Sem[i]->semId = i;
}
}
// ===========================================================
// Identifier: ~Server()
//
// Comments: Server destructor. Prevents memory leak
// ===========================================================
Server::~Server()
{
delete this->ActiveList;
this->ActiveList = NULL;
for (int i = 0; i < MAX_SEM; i++)
{
delete this->Sem[i];
this->Sem[i] = NULL;
}
}
// ===========================================================
// Identifier: LsCommand(const ComMsg)
//
// Parameter: m1 -- Communication message
//
// Comments: List the informations in the active queue.
// Also can list information of all semaphores
// (authorize queue & waiting queue) depending
// if a semaphore option is present.
// ===========================================================
void Server::LsCommand(const ComMsg m1)
{
cout << "Active List:\n";
this->DisplayList(this->ActiveList->head);
if (m1.option == 's')
{
for (int i = 0; i < MAX_SEM; i++)
{
cout << "Sem ID: " << i;
if (!this->Sem[i]->AuthorizedList->IsEmpty() ||
!this->Sem[i]->WaitingList->IsEmpty())
{
cout << "\tOccupied";
cout << "\nSem Key: " << this->Sem[i]->semKey;
cout << "\nSem Value: " << this->Sem[i]->semValue;
cout << "\n\n";
cout << "Authorized List:\n";
this->DisplayList(this->Sem[i]->AuthorizedList->head);
cout << "Waiting List:\n";
this->DisplayList(this->Sem[i]->WaitingList->head);
}
else
cout << "\tFree\n";
}
}
}
// ===========================================================
// Identifier: ExitCommand()
//
// Comments: Calls Server destructor and cleans up all
// list/queues to prevent memory leak
// ===========================================================
void Server::ExitCommand()
{
this->~Server();
}
// ===========================================================
// Identifier: bool GetSemId(const int)
//
// Parameter: semKey -- semaphore key
//
// Comments: Gets the semaphore Id by providing a key
//
// Returns: semId -- the semaphore Id
// ===========================================================
int Server::GetSemId(const int semKey)
{
int semId = -1;
for (int i = 0; i < MAX_SEM; i++)
{
if (semKey == this->Sem[i]->semKey)
{
semId = this->Sem[i]->semId;
break;
}
}
return semId;
}
// ===========================================================
// Identifier: bool Verify(const int, const int)
//
// Parameter: semId -- semaphore ID
// pid -- process ID
//
// Comments: Verifies the semdId and PID.
// This is usually called by semaphore actions.
//
// Returns: true if valid, false otherwise
// ===========================================================
bool Server::Verify(const int semId, const int pid)
{
if (semId < 0 || semId > MAX_SEM - 1)
return false;
else
return this->Sem[semId]->AuthorizedList->ContainPid(pid);
}
// ===========================================================
// Identifier: bool NewKey(const int)
//
// Parameter: semKey -- semaphore key
//
// Comments: Test if semaphore key already exist
//
// Returns: true if exist, false otherwise
// ===========================================================
bool Server::NewKey(const int semKey)
{
bool newKey = false;
for (int i = 0; i < MAX_SEM; i++)
{
if (semKey != this->Sem[i]->semKey)
newKey = true;
else
{
newKey = false;
break;
}
}
return newKey;
}
// ===========================================================
// Identifier: bool FreeSem(int&)
//
// Parameter: &newSem -- new Semaphore ID
//
// Comments: Test if there is a free semaphore. If there
// is, then give newSem a new semId. The new
// semaphore is returned by reference.
//
// Returns: true if free semaphore exist, false otherwise
// newSem is set to new Semaphore, otherwise -1
// ===========================================================
bool Server::FreeSem(int &newSem)
{
bool freeSem = false;
newSem = -1;
for (int i = 0; i < MAX_SEM; i++)
{
if (this->Sem[i]->AuthorizedList->IsEmpty())
{
newSem = i;
freeSem = true;
break;
}
}
return freeSem;
}
// ===========================================================
// Identifier: Insert(const int, const int, const ComMsg)
//
// Parameter: pid -- process ID
// pipeId -- pipe ID
// m1 -- communication message
//
// Comments: Inserts a new PCIB into the active list.
// If there is the option of creating a log file,
// method will do so with the file name equal
// to the process ID. All initial informations
// are recording into the file. Later, the file
// will append relevant informations about
// system call tracing.
// ===========================================================
void Server::Insert(const int pid, const int pipeId, const ComMsg m1)
{
PCIB pcib;
pcib.PID = pid;
pcib.timeStamp = time(NULL);
memcpy(pcib.execFile, m1.execName, EXE_LENGTH);
pcib.pipeId = pipeId;
if (m1.option == LOG_OPTION)
{
char buff[256];
memset(buff, '\0', sizeof(buff));
char *time = ctime(&pcib.timeStamp);
sprintf(pcib.logFileName, "%d", pid);
fstream out(pcib.logFileName, ios::app);
sprintf(buff, "Timestamp: %s", time);
sprintf(buff, "%sExecutable: %s\n", buff, pcib.execFile);
sprintf(buff, "%sProcess PID: %d\n", buff, pcib.PID);
sprintf(buff, "%sPipe ID: %d\n\n", buff, pcib.pipeId);
sprintf(buff, "%sSemaphore Request Log...\n\n", buff);
out.write(buff, sizeof(buff));
out.close();
}
this->ActiveList->Insert(pcib);
}
// ===========================================================
// Identifier: DisplayList(pNode)
//
// Parameter: pNode -- also pPCIB, a pointer to PCIB
//
// Comments: Displays all PCIB information in the current
// list. If list is empty, nothing will be
// displayed.
// ===========================================================
void Server::DisplayList(pNode curr)
{
if (curr != NULL)
{
cout << "PID\tEXEC FILE\tTIME STAMP\tLOG FILE\n";
while (curr != NULL)
{
cout << curr->PID << "\t";
cout << curr->execFile << "\t\t";
cout << curr->timeStamp << "\t";
if (curr->logFileName[0] != '\0')
cout << curr->logFileName << "\n";
else
cout << "N/A\n";
curr = curr->next;
}
}
else
cout << "Empty.\n";
cout << endl;
}
// ===========================================================
// Identifier: ReplyMsg SemAction(const RequestMsg)
//
// Parameter: m2 -- request message
//
// Comments: Determines the action (purpose) of the
// semaphore and calls the appropriate method
// to service it.
//
// Returns: m3 -- reply message
// ===========================================================
ReplyMsg Server::SemAction(const RequestMsg m2)
{
ReplyMsg m3;
switch (m2.purpose)
{
case GET_SEM: {m3 = this->getSem(m2); } break;
case SIGNAL_SEM: {m3 = this->sinalSem(m2); } break;
case WAIT_SEM: {m3 = this->waitSem(m2); } break;
case RELEASE_SEM: {m3 = this->releaseSem(m2); } break;
case VS_EXIT: { this->vsexit(m2); } break;
}
return m3;
}
// ===========================================================
// Identifier: ReplyMsg getSem(const RequestMsg)
//
// Parameter: m2 -- request message
//
// Comments: Gets a new semaphore. If it is a new key
// (or maybe already an existing one) and there
// is a free semaphore. Method will issue a
// semaphore by inserting the pcib into the
// authorized list.
//
// Returns: m3 -- reply message, 0 success, -1 fail
// ===========================================================
ReplyMsg Server::getSem(const RequestMsg m2)
{
int newSem = -1;
ReplyMsg m3;
m3.returnValue = -1;
PCIB pcib;
pcib.PID = m2.PID;
pcib.timeStamp = m2.timeStamp;
this->ActiveList->InsertTimeStamp(m2.PID, m2.timeStamp);
if (this->NewKey(m2.semKey) && this->FreeSem(newSem))
{
this->Sem[newSem]->semKey = m2.semKey;
this->Sem[newSem]->semValue = m2.semInitValue;
this->Sem[newSem]->AuthorizedList->Insert(pcib);
m3.returnValue = 0;
}
else if (!this->NewKey(m2.semKey))
{
newSem = this->GetSemId(m2.semKey);
this->Sem[newSem]->AuthorizedList->Insert(pcib);
m3.returnValue = 0;
}
m3.semId = newSem;
return m3;
}
// ===========================================================
// Identifier: ReplyMsg sinalSem(const RequestMsg)
//
// Parameter: m2 -- request message
//
// Comments: Verifies the semId and PID. If such
// semaphore exist, increment the semValue.
// This process may wake-up a process in
// the waiting queue.
//
// Returns: m3 -- reply message, 0 success, -1 fail
// ===========================================================
ReplyMsg Server::sinalSem(const RequestMsg m2)
{
ReplyMsg m3;
m3.semId = m2.semId;
m3.returnValue = -1;
this->ActiveList->InsertTimeStamp(m2.PID, m2.timeStamp);
if (this->Verify(m2.semId, m2.PID))
{
m3.returnValue = 0;
this->Sem[m2.semId]->semValue++;
if (this->Sem[m2.semId]->semValue <= 0)
{
PCIB pcib = this->Sem[m2.semId]->WaitingList->Dequeue();
this->ActiveList->Insert(pcib);
if (pcib.pipeId != -1)
write(pcib.pipeId, &m3, sizeof(m3));
}
}
return m3;
}
// ===========================================================
// Identifier: ReplyMsg waitSem(const RequestMsg)
//
// Parameter: m2 -- request message
//
// Comments: Verifies the semId and PID. If such
// semaphore exist, decrement the semValue.
// This process may prempt a process in
// the active queue.
//
// Returns: m3 -- reply message, 0 success, -1 fail
// ===========================================================
ReplyMsg Server::waitSem(const RequestMsg m2)
{
ReplyMsg m3;
m3.semId = m2.semId;
m3.returnValue = -1;
this->ActiveList->InsertTimeStamp(m2.PID, m2.timeStamp);
if (this->Verify(m2.semId, m2.PID))
{
this->Sem[m2.semId]->semValue--;
if (this->Sem[m2.semId]->semValue < 0)
{
PCIB pcib = this->ActiveList->Delete(m2.PID);
this->Sem[m2.semId]->WaitingList->Insert(pcib);
}
else
m3.returnValue = 0;
}
return m3;
}
// ===========================================================
// Identifier: ReplyMsg releaseSem(const RequestMsg)
//
// Parameter: m2 -- request message
//
// Comments: Verifies the semId and PID. If such
// semaphore exist, delete the process from
// the authorized list and release (cancel)
// a semaphore.
//
// Returns: m3 -- reply message, 0 success, -1 fail
// ===========================================================
ReplyMsg Server::releaseSem(const RequestMsg m2)
{
ReplyMsg m3;
m3.semId = m2.semId;
m3.returnValue = -1;
this->ActiveList->InsertTimeStamp(m2.PID, m2.timeStamp);
if (this->Verify(m2.semId, m2.PID))
{
this->Sem[m2.semId]->AuthorizedList->Delete(m2.PID);
m3.returnValue = 0;
}
return m3;
}
// ===========================================================
// Identifier: vsexit(const RequestMsg)
//
// Parameter: m2 -- request message
//
// Comments: Deletes the process from existence in all
// list and semaphore. Resource is returned to
// Server.
// ===========================================================
void Server::vsexit(const RequestMsg m2)
{
PCIB pcib = this->ActiveList->Delete(m2.PID);
close(pcib.pipeId);
for (int i = 0; i < MAX_SEM; i++)
{
pcib = this->Sem[i]->AuthorizedList->Delete(m2.PID);
close(pcib.pipeId);
pcib = this->Sem[i]->WaitingList->Delete(m2.PID);
close(pcib.pipeId);
}
}