APPENDIX C

Appendix C contains the code listing for the server program. A description of this program can be found in Chapter 5.

//****************************************************************

// Author: Hu Imm Lee

// Filename: server.h

// File Created: February 11, 1998

//

// Comments:

// Contains the global settings for the server.

// Include this file before everything else.

//

//****************************************************************

// system start codes

#define PACK_START_CODE 0x000001ba

#define SYSTEM_HEADER_START_CODE 0x000001bb

#define ISO_11172_END_CODE 0x000001b9

// video start codes

#define PICTURE_START_CODE 0x00000100

#define SEQUENCE_HEADER_CODE 0x000001b3

#define SEQUENCE_END_CODE 0x000001b7

#define GROUP_START_CODE 0x000001b8

#define DEFAULT_VID_BITRATE 565000 // in bits per second

#define DEFAULT_FRAMERATE 29.97 // Broadcast rate NTSC (fps)

// frame/packet types

#define CONTROL 0

#define I_FRAME 1

#define P_FRAME 2

#define B_FRAME 3

#define HEADER 4

// packet controls

#define RESPONSE 6 // response from a retransmission request

#define RETRANS 7 // retransmission request

#define TERMINAL 8 // signal to end a transmission

#define PINGREQ 9 // request a ping service

#define PINGRES 10 // respond to a ping

#define INVALID 0 // indicates that packet not control type

// TCP packet headers

#define REQUEST 5 // requesting a connection

#define RATE 11

// TEMPORARILY hard-coded:

// UDP-related stuff

#define MYUDPPORT 8080

#define MYTCPPORT 8181

#define MYPINGPORT 8282

#define MAXPAYLOAD 2048 // UDP packet's payload max 2K

#define DEFAULT_BUFSIZE 100 // retransmission buffer

typedef struct UDP_packet {

WORD seqnum; // NOTE: need to reinitialize seqnum if seqnum >= 2^16-1

WORD pkt_type;

WORD control;

WORD f_parts[2]; // f_parts[0] = order of frame pkt

//f_parts[1] = total number of pkts per frame

WORD pl_size; // payload size

BYTE payload[MAXPAYLOAD];

} UDP_PACKET;

typedef struct TCP_packet {

int pkt_type;

double data;

struct sockaddr_in udpclientaddr;

} TCP_PACKET;

typedef struct PING_packet {

WORD pkt_type;

WORD seqnum;

WORD control;

DWORD timestamp;

} PING_PACKET;

typedef struct Dummy {

int seqnum;

int pkt_type;

BYTE payload[MAXPAYLOAD];

} DUMMY_PACKET;

struct StreamNode {

UDP_PACKET NodeItem;

struct StreamNode* pNextNode;

}; // Node used in PacketStream

//****************************************************************

// Author: Hu Imm Lee

// Filename: main.cpp

//

// The main function along with its threads

//****************************************************************

#include <windows.h>

#include <stdio.h>

#include <math.h>

#include "server.h"

#include "MPEGparser.h"

#include "NetInterface.h"

#include "PacketStream.h"

#include "RetransmissionBuffer.h"

#include "SystemUtility.h"

long vid_bitrate = DEFAULT_VID_BITRATE;

double framerate = DEFAULT_FRAMERATE;

HANDLE gh_packetizer;

HANDLE gh_packetsender;

HANDLE gh_retransmitter;

HANDLE gh_pingServer;

char g_filename[20]; // name of MPEG file (input)

int curpkt_id;

int oldpkt_id = -1;

int packets = 0; // tracks # of packets sent

extern enum M_Choice {

M_FILE,

M_STREAM,

M_NONE

};

void PrintWin32Error(char *);

void choose();

DWORD __stdcall packetsenderThread(LPVOID);

DWORD __stdcall packetizerThread(LPVOID);

DWORD __stdcall retransmissionThread(LPVOID);

DWORD __stdcall pingServerThread(LPVOID);

DWORD __stdcall TerminationThread(LPVOID);

NetInterface* pNetI = new NetInterface();

RetransmissionBuffer* pRetBuf = new RetransmissionBuffer(DEFAULT_BUFSIZE);

MPEGparser* pMpeg = NULL;

void main() {

// instantiating PacketStream class

PacketStream* pStream = new PacketStream();

HANDLE h_packetizer; // thread packetizer's handle (unsigned long)

DWORD packetizerThreadId; // packetizer's id

LPDWORD lpExitCode_packetizer = new DWORD;

HANDLE h_packetsender; // thread packetsender's handle

DWORD packetsenderThreadId; // packetsender's id

LPDWORD lpExitCode_packetsender = new DWORD;

HANDLE h_retransmitter; // thread retransmitter's handle

DWORD retransmissionThreadId; // retransmitter's id

LPDWORD lpExitCode_retransmitter = new DWORD;

HANDLE h_pingServer; // thread retransmitter's handle

DWORD pingServerThreadId; // retransmitter's id

LPDWORD lpExitCode_pingServer = new DWORD;

BOOL done = FALSE;

printf("TIMER-CONTROLLED SERVER BEGINS: \n");

// initialize network settings before starting up the threads

if (!pNetI->net_init()) {

delete pNetI;

return; // return if failed to initialize

}

// start the packetizer thread

h_packetizer = CreateThread(

NULL, // security

0, // stack size

packetizerThread, // thread routine

(LPVOID) pStream, // pointer to PacketStream class

CREATE_SUSPENDED, // suspend thread to prevent filling up

// the packet stream before a client connects

&packetizerThreadId); // thread id

if (h_packetizer == NULL) {

printf("MAIN: ERR[%d] on CreateThread(packetizer)\n",

GetLastError());

PrintWin32Error("CreateThread: packetizerThread");

exit(0);

}

else gh_packetizer = h_packetizer; // assign to a global handle

// start the packetsender thread

h_packetsender = CreateThread(

NULL,

0,

packetsenderThread,

(LPVOID) pStream, //** NOTE: both threads share one resource,

// the PacketStream class

0, // run immediately

&packetsenderThreadId);

if (h_packetsender == NULL) {

printf("MAIN: ERR[%d] on CreateThread(packetsender)\n",

GetLastError());

PrintWin32Error("CreateThread: packetsenderThread");

exit(0);

}

else gh_packetsender = h_packetsender; // assign to a global handle

h_retransmitter = CreateThread(

NULL,

0,

retransmissionThread,

NULL,

0, // run immediately

&retransmissionThreadId);

if (h_retransmitter == NULL) {

printf("MAIN: ERR[%d] on CreateThread(retransmission)\n",

GetLastError());

PrintWin32Error("CreateThread: retransmissionThread");

exit(0);

}

else

gh_retransmitter = h_retransmitter; // assign to a global handle

h_pingServer = CreateThread(

NULL,

0,

pingServerThread,

NULL,

0, // run immediately

&pingServerThreadId);

if (h_pingServer == NULL) {

printf("MAIN: ERR[%d] on CreateThread(pingServer)\n",

GetLastError());

PrintWin32Error("CreateThread: pingServerThread");

exit(0);

}

else

gh_pingServer = h_pingServer; // assign to a global handle

// wait for all threads to finish

while (!done) {

if (GetExitCodeThread(gh_packetizer, lpExitCode_packetizer)

== 0) {

printf("GetExitCodeThread(packetizer) ERR[%d]\n",

GetLastError() );

break;

}

if (GetExitCodeThread(gh_packetsender,

lpExitCode_packetsender) == 0) {

printf("GetExitCodeThread(packetsender) ERR[%d]\n",

GetLastError() );

break;

}

if (GetExitCodeThread(gh_retransmitter,

lpExitCode_retransmitter) == 0) {

PrintWin32Error("GetExitCodeThread(retransmitter)");

break;

}

if (GetExitCodeThread(gh_pingServer, lpExitCode_pingServer)

== 0) {

PrintWin32Error("GetExitCodeThread(pingServer)");

break;

}

if ( (*lpExitCode_packetizer != STILL_ACTIVE) &&

(*lpExitCode_packetsender != STILL_ACTIVE) &&

(*lpExitCode_retransmitter != STILL_ACTIVE)

done = TRUE;

}

}

void PrintWin32Error(char *pszErrorString) {

LPVOID lpMsgBuf;

printf("Error: returned from [%s]\n", pszErrorString);

if (FormatMessage(

FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

NULL,

GetLastError(),

MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

(LPSTR)&lpMsgBuf,

0,

NULL))

printf("Error Message: %s\n", lpMsgBuf);

}

//****************************************************************

// CHOOSE

// accesory to let user input an option

//****************************************************************

void choose() {

int option;

begin:

printf("\n************************************************\n");

printf("Choose an input option (by number):\n");

printf("1. File\n2. Capture board\n");

printf("Choose: ");

scanf("%d", &option);

printf("**************************************************\n");

switch (option) {

case 1:

// get user input for MPEG file to stream

printf("Enter MPEG filename \".mpg\": ");

scanf("%s", &g_filename);

pMpeg = new MPEGparser(M_FILE);

break;

case 2:

pMpeg = new MPEGparser(M_STREAM);

break;

default:

printf("Incorrect input choice. Please try again\n\n");

goto begin;

}

}

//****************************************************************

// PACKET SENDER THREAD -

// Thread Routine, called by CreateThread in main()

// Syntax

// + CreateThread(NULL,

// 0,

// packetsenderThread, // this routine

// pSystem. // pointer to PacketStream class object

// 0,

// &dwThreadId);

// + lpdwThreadParam = pStream

//****************************************************************

DWORD __stdcall packetsenderThread(LPVOID lpdwThreadParam) {

// PacketStream stuff

PacketStream* pStream = (PacketStream*) lpdwThreadParam;

BOOL Success;

UDP_PACKET* pFrontpkt = new UDP_PACKET;

LPDWORD lpExitCode_packetizer = new DWORD;

double inv_transmit_rate; //inverse packet rate

printf("\nPacket Sender Thread running\n");

// determine transmission rate (seconds per packet)

inv_transmit_rate = 1/framerate * 1000;

printf("inversed transmission rate: %ld millisec/pkt\n",

(DWORD)inv_transmit_rate);

char choice;

printf("\t Change transmission rate? \n\t1 for yes\n");

scanf("%c", &choice);

if (choice == '1') {

printf("Enter (in pkt/sec) float value: ");

scanf("%lf", &framerate);

inv_transmit_rate = (double)1/(double)framerate * 1000;

printf("inversed transmission rate: %ld millisec/pkt\n",

(DWORD)inv_transmit_rate);

}

// wait for client connection request

if (!pNetI->WaitForRequest() ) {

delete pNetI;

return (0); // if not OK

}

// send transmission rate to client

TCP_PACKET rate_pkt;

ZeroMemory(&rate_pkt, sizeof(TCP_PACKET));

rate_pkt.pkt_type = RATE;

rate_pkt.data = framerate;

pNetI->tcpsend(&rate_pkt);

// resume execution of packetizerThread after WaitForRequest falls thru

if ( ResumeThread(gh_packetizer) == 0xffffffff ) {

printf("packetsenderThread: ResumeThread fail ERR[%d]\n",

GetLastError() );

return (0);

}

printf("PacketSender: ResumeThread on packetizer success\n");

// check that packetizer thread has/ has not exited

if ( ! GetExitCodeThread(gh_packetizer, lpExitCode_packetizer) ) {

printf("ExitCode Error %d\n", GetLastError() );

return (0);

}

// if packet stream is not empty, send

// if packetizer thread is still active (packet stream may be empty)

// wait for it

while ( !pStream->StreamIsEmpty() ||

(*lpExitCode_packetizer==STILL_ACTIVE) ) {

// while there is something to send

if ( !pStream->StreamIsEmpty() ) { // if there's something to send

pStream->GetFrontPacket(*pFrontpkt, Success);

if (!Success)

break; // failure to retrieve packet from stream

pStream->RemovePacket(Success); // pop off the Q front

if (!Success)

break;

pRetBuf->add(pFrontpkt); // add the packet into the

// retransmission buffer

if ( !pNetI->sendpacket(pFrontpkt) ) // send the packet

break; // get out of loop if sendpacket fails

}

// check packetizer's thread status

if ( ! GetExitCodeThread(gh_packetizer, lpExitCode_packetizer) )

break;

// sleep for a duration of 'transmit_rate'

// to provide a constant transmission rate

Sleep((DWORD)inv_transmit_rate); // in milliseconds

}

// disconnect transmission

pNetI->Disconnect();

printf("packetsender exiting...\n");

return (0);

}

//****************************************************************

// PACKETIZER THREAD -

// Thread Routine, called by CreateThread in main()

// to packetize the MPEG stream

// Syntax

// + CreateThread(NULL, //security

// 0, //stack size

// packetizerThread, // this routine

// pStream, // pointer to PacketStream class object

// CREATE_SUSPENDED, // run immediately

// &dwThreadId) // Thread Id

//

// + lpdwThreadParam = pStream

// + Thread is CREATED SUSPENDED; resumption of

// execution is determined by the packetsender thread

//

// effects

// + opens a file stream (via MPEGparser)

// + this routine will pack non-pictures in packets of type

// HEADER, increment the packet sequence number

// for each packet produced, stuff the packet's payload

// one byte after another

// + pictures are packed differently than the non-pictures,

// because the frame types are different and hence, the

// packet type would also be different

// + all packets are added onto the packet stream once they

// have been made

//

// note

// + seqnum ranges from 0 to (2^16 - 1) [=65535]

//

//****************************************************************

DWORD __stdcall packetizerThread(LPVOID lpdwThreadParam) {

unsigned int dw; // used to store DWord read from MPEG stream

BYTE bw; // byte word used to manipulate picture type

WORD ptype; // stores picture-type

int pict_idx, pict_size; // manipulates packetization of picture

int f_pkt_order; // stores value of current pkt's order within a picture

int f_pkt_total; // stores total number of pkts within a picture

UDP_PACKET* pCurrentpkt = new UDP_PACKET; // packet-related

WORD seqnum = 0;

int payload_index = 0;

choose(); // choose MPEG I/O option & then instantiate MPEGparser class

// instantiating the SystemUtility class

SystemUtility* pSysUtil = new SystemUtility();

// PacketStream stuff

PacketStream* pStream = (PacketStream*) lpdwThreadParam;

BOOL Success;

printf("\nPacketizer Thread running\n");

// start packetizing and putting packets into packet stream

printf("packetizerThread: making packets ...\n");

ZeroMemory(pCurrentpkt, sizeof(UDP_PACKET)); // prepare packet

pCurrentpkt->control = INVALID;

// the big loop

while (!pMpeg->endofplayout()) {

dw = pMpeg->nextbits(32);

if (dw != PICTURE_START_CODE) {

// not a picture (maybe a system header)

// make the packet

pCurrentpkt->seqnum = seqnum; //** sometimes

pCurrentpkt->pkt_type = HEADER; //** redundant

//** is this a problem?

pCurrentpkt->payload[payload_index] =

pMpeg->getbits(8);

payload_index++;

// add to packet stream if

// (a) payload full

// or

// (b) next 32bits = picture_start_code (looking ahead)

// otherwise, continue stuffing the payload

if ( (payload_index >= MAXPAYLOAD) ||

(pMpeg->nextbits(32) ==

PICTURE_START_CODE) ) {

// assign the size of that packet

pCurrentpkt->pl_size =

(payload_index >= MAXPAYLOAD) ?

MAXPAYLOAD : payload_index;

// add to stream

pStream->AddPacket(*pCurrentpkt, Success);

// prepare for next iteration

delete pCurrentpkt;

pCurrentpkt = new UDP_PACKET;

ZeroMemory(pCurrentpkt,

sizeof(UDP_PACKET));

pCurrentpkt->control = INVALID;

if ( !pSysUtil->checkoverflow(&seqnum) )

seqnum = 0; // if seqnum = 65535, don't

// increment

else seqnum++;

payload_index = 0;

}

}

else { // if it's a picture

pict_size = pMpeg->getpict();

// manipulate byte to determine picture-type value

bw = pMpeg->pFrame[5];

bw >>= 3;

ptype = (WORD) bw & 0x0007;

// test case to see if bit manipulation is correct or not

if ( (ptype != I_FRAME) && (ptype != P_FRAME) &&

(ptype != B_FRAME) ) {

printf("ptype: Invalid pkt_type\n");

}

// proceed otherwise

// first pkt of frame-type "ptype"

pCurrentpkt->f_parts[0] = f_pkt_order = 1;

// determine the total number of pkts that constitute a frame

pCurrentpkt->f_parts[1] = f_pkt_total =

( (pict_size % MAXPAYLOAD)==0 ) ?

pict_size/MAXPAYLOAD :

(pict_size/MAXPAYLOAD)+1;

// stuff picture into packet(s)

for (pict_idx = 0; pict_idx < pict_size; pict_idx++) {

if (payload_index < MAXPAYLOAD) {

// stuff till MAXPAYLOAD is reached

pCurrentpkt->payload[payload_index] =

pMpeg->pFrame[pict_idx];

payload_index++;

}

else { // picture can't fit into one packet

// so fill in the rest of the current packet load

pCurrentpkt->seqnum = seqnum;

pCurrentpkt->pkt_type = ptype;

pCurrentpkt->pl_size = payload_index;

// add current pkt to stream

pStream->AddPacket(*pCurrentpkt,

Success);

delete pCurrentpkt;

// create a fresh packet for next portion of

// picture

pCurrentpkt = new UDP_PACKET;

ZeroMemory(pCurrentpkt,

sizeof(UDP_PACKET));

pCurrentpkt->control = INVALID;

// now, prepare for next packet load-in (of

// the same pict) ...

if ( !pSysUtil->checkoverflow(&seqnum) )

// if seqnum = 65535, don't increment

seqnum = 0; else seqnum++;

payload_index = 0;

f_pkt_order++;

pCurrentpkt->f_parts[0] = f_pkt_order;

pCurrentpkt->f_parts[1] = f_pkt_total;

// array correction, pict_idx should not

// increment yet because

// pFrame[pict_idx] has not been read!

pict_idx--;

}

}

// after packetizing a frame, prepare to ship out

pCurrentpkt->seqnum = seqnum;

pCurrentpkt->pkt_type = ptype;

pCurrentpkt->pl_size = payload_index;

// send out final packet of the frame

pStream->AddPacket(*pCurrentpkt, Success);

delete pCurrentpkt;

//prepare a fresh packet

pCurrentpkt = new UDP_PACKET;

ZeroMemory(pCurrentpkt, sizeof(UDP_PACKET));

pCurrentpkt->control = INVALID;

if ( !pSysUtil->checkoverflow(&seqnum) )

seqnum = 0; // if seqnum = 65535, don't increment

else seqnum++;

payload_index = 0;

} // end picture-type packets

} // end of playout

// finished

pCurrentpkt->seqnum = seqnum;

pCurrentpkt->pkt_type = CONTROL;

pCurrentpkt->control = TERMINAL;

ZeroMemory(&pCurrentpkt->payload, MAXPAYLOAD);

pStream->AddPacket(*pCurrentpkt, Success); // add terminating packet to

// stream

pMpeg->~MPEGparser();

delete pCurrentpkt;

pCurrentpkt = NULL;

printf("packetizerThread: Exiting\n");

return (0);

}

//****************************************************************

// RETRANSMISSION THREAD -

// This thread deals with the retransmission of a requested packet

// It needs an ACK from the client to know that it isn't needed

// anymore

// effects

// + thread stops if client sends a TERMINAL pkt to end the session

// + thread can't depend on packetsender thread's termination to

// stop itself because the client may still want to request for

// retransmission (will need to be modified once a TCP dialog

// thread is set up)

//

// resources

// + NetInterface (pNetI)

// + RetransmissionBuffer (pRetBuf)

//

//****************************************************************

DWORD __stdcall retransmissionThread(LPVOID lpdwThreadParam) {

UDP_PACKET packet;

BOOL success;

UDP_PACKET requestedpkt;

printf("retransmissionThread started ...\n");

do {

success = pNetI->recvpacket(packet);

// get "message" from packet

if (success) {

if (packet.control == RETRANS) {

printf("\nretransmitter: requesting pkt[%d]\n",

packet.seqnum);

// retrieve requested video pkt from buffer and send

if ( pRetBuf->retrieve(requestedpkt,

packet.seqnum) ) {

requestedpkt.pkt_type = CONTROL;

requestedpkt.control = RETRANS;

if (requestedpkt.seqnum != packet.seqnum)

printf("\n\tBUFFER FAILURE!\n");

else {

printf("\n\tRetransmitting

pkt[%d]\n", requestedpkt.seqnum);

pNetI->sendpacket(&requestedpkt);

}

} // don't send if failed to find video packet in buffer

}

}

else break;

} while (packet.control != TERMINAL);

// end loop if packet received calls for session termination

printf("retransmitter exiting...\n");

return(0);

}

//****************************************************************

// PINGSERVICETHREAD

// Listen for incoming PING packets

// This thread should eventually incorporate other requests not

// directly related to video packet transmissions (i.e. controls)

//

//****************************************************************

DWORD __stdcall pingServerThread(LPVOID lpdwThreadParam) {

PING_PACKET packet;

do {

pNetI->recvping(packet);

if (packet.control == PINGREQ) {

// send back the packet

packet.control = PINGRES;

pNetI->sendping(&packet);

}

} while (1);

return (0);

}

//****************************************************************

// Author: Hu Imm Lee

// Filename: MPEGio.h

// File Created: March 10, 1998

//

// Comments: Contains class prototype of MPEGio

//

//****************************************************************

#include <mtruid.h> // MPEGator sdk includes

#include <mtrif.h>

class MPEGio {

private:

int filedesc;

PSTR pFileBuf;

int fptr; // pointer to track current location of data in pFileBuf

unsigned long FileBufSize;

IMtrCapture *pCapture; // MPEGator capture object, the COM interface pointer

MTRSTREAMPTR mtrstream_info;

PSTR pStreamBuf; // MPEGator stream buffer pointer

int sptr;

int streamBufSize;

MTRCAPINFO capInfo;

public:

MPEGio(const char* filename); // constructor for file streaming

MPEGio(); // constructor for real-time streaming w/ the encoder board

~MPEGio(); // destructor

int readfile(void*, int);

void startcapture(); // fire up the encoder

void stopcapture();

int readstream(void*, int);

void checkstream(int);

void getcaptureinfo();

void printStatus(int); // hardware status

char *formatMtrError(HRESULT);

protected:

long openfile(const char *); // handles input from file

void closefile();

int openstream(); // handles input from encoder

void closestream();

};

//****************************************************************

// Author: Hu Imm Lee

// Filename: MPEGio.cpp

// File Created: March 10, 1998

// Last Modified: March 16, 1998

//

// Comments: Contains implementation of the MPEGio class

// The MPEGio class provides 2 options to access MPEG stream,

// from

// a) file

// b) real-time encoder

//

//****************************************************************

#include <windows.h>

#include <initguid.h>

#include <stdio.h>

#include <io.h>

#include <fcntl.h>

#include <sys/stat.h>

#include <sys/types.h>

#include "MPEGio.h"

extern long vid_bitrate;

//****************************************************************

// MPEGio CLASS IMPLEMENTATION BELOW

//****************************************************************

//****************************************************************

// CONSTRUCTOR

// initializes for file stream input

//****************************************************************

MPEGio::MPEGio(const char* filename):pCapture(NULL),filedesc(0),fptr(0),pStreamBuf(NULL) {

printf("MPEGio:opening file [%s]\n", filename);

FileBufSize = openfile(filename);

if (FileBufSize <= 0)

printf("openfile encountered error\n");

}

//****************************************************************

// CONSTRUCTOR

// initializes for real-time encoder stream input

//****************************************************************

MPEGio::MPEGio():pCapture(NULL),filedesc(0),fptr(0),pStreamBuf(NULL) {

if (openstream() < 0)

printf("MPEGio failed to initialize\n");

}

// destructor

MPEGio::~MPEGio() {

if (pCapture != NULL)

closestream();

if (filedesc != 0)

closefile();

}

//****************************************************************

// OPENFILE

// input:

// name of file containing MPEG video

// effects:

// + opens file containing MPEG stream (assigns 'filedesc' to

// the file descriptor)

// + read data into buffer (pFileBuf)

// return:

// + 0 if successful

// + -1 if error occurred

//****************************************************************

long MPEGio::openfile(const char *name) {

struct _stat statBuf; // buffer to store fstat info (like file size)

unsigned long filesize; // size of file

int nread = 0, totalread = 0; // # bytes read

// open file

filedesc = _open(name, _O_RDONLY | _O_BINARY);

if (filedesc < 0) {

printf("\nMPEGparser.openstream: _open ERRNO[%d] on file

%s\n", errno, name);

return -1;

}

// get file size info

if ( _fstat(filedesc, &statBuf) < 0 )

printf("_fstat ERRNO[%d]\n", errno);

filesize = statBuf.st_size;

printf("filesize: %d\n", filesize);

// allocate enough storage space for incoming MPEG filestream

pFileBuf = (PSTR) malloc(filesize);

// read the file but do some error prevention, in case it's not completely

// read

while ( nread < filesize ) {

if ( (nread = _read(filedesc, pFileBuf, filesize)) < 0 ) {

printf("MPEGio::readfile ERR[%d]\n", errno);

return -1;

}

totalread += nread;

}

return totalread; //filesize;

}

void MPEGio::closefile() {

_close(filedesc);

}

//****************************************************************

// READFILE

// read directly from pFileBuf --> into buffer

//

// input:

// + pointer to the buffer to write to

// + bufsize -- size of the buffer

//

// effects:

// + assumes that buffer already allocated to memory

// elsewhere

// + corrects fptr as it "reads" along

// + deallocate whatever data already read?? (no)

//

// return:

// + 0 if there's no more to read

// + total bytes read

//

//****************************************************************

int MPEGio::readfile(void* buffer, int bufsize) {

int oldptr = fptr;

if ( (FileBufSize <= 0) && (pFileBuf == NULL) ) {

free(pFileBuf);

pFileBuf == NULL;

return 0; // no more to read

}

if (bufsize <= FileBufSize) // check that you don't read more than you

// have

memcpy(buffer, &pFileBuf[fptr], bufsize);

else {

memcpy(buffer, &pFileBuf[fptr], FileBufSize);

bufsize = FileBufSize;

}

fptr += bufsize;

FileBufSize -= bufsize;

return bufsize;

}

//****************************************************************

// OPENSTREAM

//

// opens the video stream ... real-time capture by the encoder board

//

// effects:

// + initializes the encoder board using OLE

// + opens the internal channel and prepares the encoder for

// upcoming video capture

//

// returns:

// + 0 if success

// + -1 if failure

//

//****************************************************************

int MPEGio::openstream() {

HRESULT Handle;

CoInitialize(NULL); // initialize the COM library

Handle = CoCreateInstance(

CLSID_MtrMe, // class identifier

NULL,

CLSCTX_SERVER, // context for running executable code

IID_IMtrCapture, // interface identifier

(void **)&pCapture ); // ptr to storage of interface pointer

if (FAILED(Handle)) {

printf("Can't create COM interface for MPEGator\n");

printf("%s\n", formatMtrError(Handle));

return -1;

}

// open INTERNAL channel for realtime MPEG capture & prepare the

// hardware for the upcoming video capture ...

if (pCapture->Open() == S_FALSE) {

pCapture->Release();

return -1;

}

pCapture->DlgParam(NULL); // MPEG parameters compound dialog

{

IVMpegSetup* pM_VidSetup;

pCapture->GetVMpegSetup(&pM_VidSetup);

vid_bitrate = pM_VidSetup->get_Bitrate();

printf("video bitrate : %ld\n", vid_bitrate);

pM_VidSetup->Release();

}

return 0; // zero status for success

}

void MPEGio::startcapture() {

// open/create an output stream

pCapture->OpenStreamEx();

pCapture->Start();

}

void MPEGio::stopcapture() {

pCapture->Stop();

}

void MPEGio::closestream() {

if ( (pCapture->GetCapInfo(&capInfo) == S_OK) &&

(capInfo.state != MTRSTAT_STOP) ) {

printf("Stopping capture\n");

pCapture->Stop(); // stop the video capture if not already

// done so

}

pCapture->CloseStreamEx(); // close capturing process &

// its associated stream

pCapture->Close();

pCapture->Release();

CoUninitialize(); // uninitialize the COM video capture object

}

//****************************************************************

// READSTREAM

// Read from the encoded stream, the requested amount (bytes) or

// however much available

//

// input:

// + buffer = the buffer that it writes to

// + bufsize = size of buffer in bytes (amount of bytes to

// read into)

//

// effects:

// + store/load a chunk of data pointed by pStreamBuf

// + keep a pointer (sptr) that tracks where it should next

// read the buffer (pStreamBuf)

//

// return:

// + total bytes actually read, if success

// + 0, if nothing read

// + -1, if failure to obtain encoder's stream pointer

//

//****************************************************************

int MPEGio::readstream(void* buffer, int bufsize) {

if ( (pStreamBuf == NULL) && (streamBufSize <= 0) ) { // empty buffer

WaitForSingleObject(pCapture->GetWaitHandle(), 100); // mutex

if ( pCapture->StreamGetPtr(&mtrstream_info, TRUE)

== S_FALSE ) {

printf("IMtrCapture.StreamGetPtr() failed\n");

return -1;

}

if (mtrstream_info.isUsed) {

streamBufSize = mtrstream_info.actualSize; // in bytes

pStreamBuf = (PSTR) malloc(streamBufSize);

// copy from encoder's buffer to MY buffer (pStreamBuf)

memcpy(pStreamBuf, mtrstream_info.bufferPtr,

mtrstream_info.actualSize);

sptr = 0;

}

else return 0;

// release current buffer before fetching the next chunk of data

pCapture->StreamReleasePtr(&mtrstream_info);

}

// check that you don't read more than you have

if (bufsize <= streamBufSize)

memcpy(buffer, &pStreamBuf[sptr], bufsize);

// if amount (bytes) requested is more than what the buffer has,

// return only as much as it's got

else {

memcpy(buffer, &pStreamBuf[sptr], streamBufSize);

bufsize = streamBufSize;

}

sptr += bufsize;

streamBufSize -= bufsize;

if (streamBufSize == 0) {

free(pStreamBuf);

pStreamBuf = NULL;

}

return bufsize;

}

// test function

void MPEGio::checkstream(int fd) {

WaitForSingleObject(pCapture->GetWaitHandle(), 100); // mutex

if ( pCapture->StreamGetPtr(&mtrstream_info, TRUE) == S_FALSE )

printf("IMtrCapture.StreamGetPtr() failed\n");

if (mtrstream_info.isUsed)

_write(fd, mtrstream_info.bufferPtr, mtrstream_info.actualSize);

pCapture->StreamReleasePtr(&mtrstream_info); // release current buffer before fetching the next chunk of data

}

//****************************************************************

// GETCAPTUREINFO

// to print information about the encoder's state, etc

//****************************************************************

void MPEGio::getcaptureinfo() {

HRESULT status;

status = pCapture->GetCapInfo(&capInfo);

if (status == S_FALSE)

printf("getcaptureinfo failure\n");

else {

printf("frames captured: %d\n", capInfo.framesProcessed);

printf("clock ticks elapsed(1 Hz per tick): %d\n", capInfo.numClockTics);

printf("Encoder state:\t");

printStatus(capInfo.state);

}

}

//****************************************************************

// PRINTSTATUS

// accessory to print state of encoder (hardware)

//****************************************************************

void MPEGio::printStatus(int state) {

if (state == MTRSTAT_IDLE)

printf("Hardware is idle\n");

else if (state == MTRSTAT_PROCESS)

printf("Hardward is busy capturing\n");

else if (state == MTRSTAT_ERROR)

printf("Error occurred\n");

else if (state == MTRSTAT_STOP)

printf("Capture process has stopped\n");

else if (state == MTRSTAT_PAUSE)

printf("Capture process has paused\n");

else printf("Status undetermined at this point of time\n");

}

char *MPEGio::formatMtrError(HRESULT handle) {

char *mesg = NULL;

DWORD msgLen;

/* get the text description for that error number from the system */

msgLen = FormatMessage(

FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,

0,

(DWORD) handle,

MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),

(LPTSTR) &mesg,

512,

0);

if(msgLen > 0)

printf("Error %x: %s\n", handle, mesg);

else

printf("Error %x\n", handle);

return mesg;

}

//****************************************************************

// Author: Hu Imm Lee

// Filename: MPEGparser.h

// File Created: February 11, 1998

//

// Comments: Contains class definition for MPEGparser

//****************************************************************

#include "MPEGio.h"

extern enum M_Choice;

// MPEG parsing class

class MPEGparser {

public:

//constructor and destructor

MPEGparser(M_Choice);

~MPEGparser();

// file handling routine

int openstream(const char *name); // ## INVALIDATED by MPEGio

// class methods

BOOL endofplayout();

void closestream(); // ## INVALIDATED by MPEGio class methods

// parsing routines

int getbits_file(int n); // reads directly from file (original procedure)

int getbits(int n);

int getbits_(int n); // reads from buffer

int getbits_mtr(int n); // read from buffer created by encoder

int nextbits_file(int);

int nextbits(int n);

int nextbits_(int n);

int nextbits_mtr(int);

void nextstartcode_file();

void nextstartcode();

void nextstartcode_();

void nextstartcode_mtr();

// other useful routines

int getbitrate();

int getpict_file();

int getpict();

int getpict_();

int getpict_mtr();

// public variable

BYTE *pFrame;

private:

unsigned int curBits;

int bit_ptr;

BYTE byteword;

// file I/O stuff

BOOL end_of_file;

int fd;

MPEGio* mpegIO;

M_Choice mode; // mode of input, whether it's a file or a real-time stream

unsigned int capturelen; // run-time length of the video capture

// (via encoder)

unsigned int elapsetime;

};

//****************************************************************

// Author: Hu Imm Lee

// Filename: MPEGparser.cpp

// File Created: February 11, 1998

//

// Comments: Contains implementation of the MPEGparser class

//

//****************************************************************

#include <stdio.h>

#include <windows.h>

#include <io.h>

#include <fcntl.h>

#include "MPEGparser.h"

#include "server.h"

extern char g_filename[];

enum M_Choice {

M_FILE,

M_STREAM,

M_NONE }; // choose either file mode, encoder mode or neither

//****************************************************************

// MPEGPARSER CLASS IMPLEMENTATION BELOW

// - used by packetizer thread -

//****************************************************************

MPEGparser::MPEGparser(M_Choice choice):curBits(0x00000000),bit_ptr(0),end_of_file(FALSE),pFrame(NULL),

capturelen(0), elapsetime(0) {

if (choice == M_FILE)

mpegIO = new MPEGio(g_filename);

else if (choice == M_STREAM) {

mpegIO = new MPEGio();

printf("Enter the length of video to capture

(in units of seconds): ");

scanf("%d", &capturelen);

elapsetime = GetTickCount() + (capturelen*1000);

mpegIO->startcapture();

}

else mpegIO = NULL;

mode = choice;

}

//****************************************************************

// DESTRUCTOR

// implicitly close relevant I/O, whether file or encoder stream

//****************************************************************

MPEGparser::~MPEGparser() {

if (mpegIO != NULL) {

mpegIO->~MPEGio();

mpegIO = NULL;

}

}

int MPEGparser::openstream(const char *name) {

// open file

fd = _open(name, _O_RDONLY | _O_BINARY);

if (fd < 0) {

printf("\nMPEGparser.openstream: _open ERRNO[%d] on file %s\n", errno, name);

return -1;

}

else return fd;

}

BOOL MPEGparser::endofplayout() {

if ( (mode == M_STREAM) && (elapsetime <= GetTickCount()) )

return (end_of_file = TRUE);

return end_of_file;

}

void MPEGparser::closestream() {

_close(fd);

}

//****************************************************************

// GETBITS_FILE -- ##Invalidated by GETBITS and GETBITS_MTR##

// MPEG parsing method

// input

// n = number of bits to be read from MPEG stream

// fd = file descriptor from which MPEG stream is to be read

// effects

// + reads n bits fr FILE data stream and corrects the stream

// pointer, bit_ptr

// returns

// + value of the first n bits read

// + -1 if error occurred

//

// (CLASS GLOBAL) bitptr = "virtual" pointer to MPEG stream

// points to curBits

// (CLASS GLOBAL) curBits = 32-bit unsigned int containing

// the first 32-bits of the MPEG stream (the remaining MPEG

// stream can be pointed to by the file descriptor

//****************************************************************

int MPEGparser::getbits_file(int n) {

unsigned int value;

int nread;

// if bits are in the buffer, no need to read fr stream if

// remaining bits > than n

if (bit_ptr >= n) {

value = curBits >> (bit_ptr-n);

// keep remaining bits, after reading value

curBits &= ~( 0xffffffff << (bit_ptr-n) );

bit_ptr -= n;

return value;

}

while (bit_ptr < n) {

// manipulate data stream into 'big-endian' order

// -- reading data into unsigned int's won't work on Intel x86s

nread = _read(fd, (BYTE *)&byteword, sizeof(BYTE));

if (nread == 0) {

printf("EOF\n");

end_of_file = TRUE;

return -1;

}

else if (nread < 0) {

printf("read err: %d\n", errno);

exit(0);

}

bit_ptr += 8;

curBits = (curBits << 8) | byteword;

}

//extract value

value = curBits >> (bit_ptr-n);

// re-adjust pointer in curBits

curBits &= ~( 0xffffffff << (bit_ptr-n) );

bit_ptr -= n;

return value;

}

//****************************************************************

// GETBITS

//

//****************************************************************

int MPEGparser::getbits(int n) {

if (mode == M_FILE)

return getbits_(n);

else if (mode == M_STREAM)

return getbits_mtr(n);

return getbits_file(n); // old method

}

int MPEGparser::getbits_(int n) {

unsigned int value;

int nread;

if (bit_ptr >= n) {

value = curBits >> (bit_ptr-n);

// keep remaining bits, after reading value

curBits &= ~( 0xffffffff << (bit_ptr-n) );

bit_ptr -= n;

return value;

}

while (bit_ptr < n) {

// manipulate data stream into 'big-endian' order

// -- reading data into unsigned int's won't work on Intel x86s

nread = mpegIO->readfile((BYTE *)&byteword, sizeof(BYTE));

if (nread == 0) {

printf("EOF\n");

end_of_file = TRUE;

return -1;

}

bit_ptr += 8;

curBits = (curBits << 8) | byteword;

}

//extract value

value = curBits >> (bit_ptr-n);

// re-adjust pointer in curBits

curBits &= ~( 0xffffffff << (bit_ptr-n) );

bit_ptr -= n;

return value;

}

//****************************************************************

// GETBITS_MTR

//

//****************************************************************

int MPEGparser::getbits_mtr(int n) {

unsigned int value;

int nread;

if (bit_ptr >= n) {

value = curBits >> (bit_ptr-n);

// keep remaining bits, after reading value

curBits &= ~( 0xffffffff << (bit_ptr-n) );

bit_ptr -= n;

return value;

}

while (bit_ptr < n) {

// manipulate data stream into 'big-endian' order

// -- reading data into unsigned int's won't work on Intel x86s

nread = mpegIO->readstream((BYTE *)&byteword,

sizeof(BYTE));

if (nread == 0) {

printf("EOF\n");

end_of_file = TRUE;

return -1;

}

else if (nread < 0) {

//printf("read err: %d\n", errno);

exit(0);

}

bit_ptr += 8;

curBits = (curBits << 8) | byteword;

}

//extract value

value = curBits >> (bit_ptr-n);

// re-adjust pointer in curBits

curBits &= ~( 0xffffffff << (bit_ptr-n) );

bit_ptr -= n;

return value;

}

//****************************************************************

// nextbits_file - ##Superceded by NEXTBITS and NEXTBITS_MTR##

// MPEG parsing method

// input

// n = number of bits from MPEG stream to read

// * n no greater than 32

// fd = the file descriptor from which to read

// 'sniffs' bits at data stream

// effect

// + does not correct the bit_ptr

// + bit_ptr is corrected only if n > size(curBits)

// returns

// + value of first n bits

// + -1 on EOF or read error

//****************************************************************

int MPEGparser::nextbits_file(int n) {

int value, nread;

while (bit_ptr < n) {

// do byte-aligned read until size(curBits) >= n

nread = _read(fd, (BYTE *)&byteword, sizeof(BYTE));

if (nread == 0) {

printf("\nMPEGparser.nextbits: EOF\n");

end_of_file = TRUE;

return -1;

}

else if (nread < 0) {

printf("read err: %d\n", errno);

return -1;

}

bit_ptr += 8;

curBits = (curBits << 8) | byteword;

}

// no need to read fr data stream

value = curBits >> bit_ptr-n;

return value;

}

//****************************************************************

// NEXTBITS

// obtains the next n bits from stream using MPEGio::readfile

// procedure

//

// input

// n = number of bits from MPEG stream to read

// * n no greater than 32

//

// effect

// + 'sniffs' bits at data stream, does not correct the bit_ptr

// + bit_ptr is corrected only if n > size(curBits)

// returns

// + value of first n bits

// + -1 on EOF or read error

//****************************************************************

int MPEGparser::nextbits(int n) {

if (mode == M_FILE)

return nextbits_(n);

else if (mode == M_STREAM)

return nextbits_mtr(n);

return nextbits_file(n);

}

int MPEGparser::nextbits_(int n) {

int value, nread;

while (bit_ptr < n) {

// do byte-aligned read until size(curBits) >= n

nread = mpegIO->readfile((BYTE *)&byteword, sizeof(BYTE));

if (nread == 0) {

printf("\nMPEGparser.nextbits: EOF\n");

end_of_file = TRUE;

return -1;

}

bit_ptr += 8;

curBits = (curBits << 8) | byteword;

}

// no need to read fr data stream

value = curBits >> bit_ptr-n;

return value;

}

//****************************************************************

// NEXTBITS_MTR

// obtains the next n bits from encoder stream

// using MPEGio::readstream procedure

//

// input

// n = number of bits from MPEG stream to read

// * n no greater than 32

//

// effect

// + 'sniffs' bits at data stream, does not correct the bit_ptr

// + bit_ptr is corrected only if n > size(curBits)

// returns

// + value of first n bits

// + -1 on EOF or read error

//****************************************************************

int MPEGparser::nextbits_mtr(int n) {

int value, nread;

while (bit_ptr < n) {

// do byte-aligned read until size(curBits) >= n

nread = mpegIO->readstream((BYTE *)&byteword,

sizeof(BYTE));

if (nread == 0) {

printf("\nMPEGparser.nextbits: EOF\n");

end_of_file = TRUE;

return -1;

}

bit_ptr += 8;

curBits = (curBits << 8) | byteword;

}

// no need to read fr data stream

value = curBits >> bit_ptr-n;

return value;

}

//****************************************************************

// nextstartcode_file -

// searches for the 24-bit start-code 0x000001

// effects

// + moves stream pointer, bit_ptr, to beginning of start-code

// on return,

// it is required to call getbits(32) to retrieve the start-code

//****************************************************************

void MPEGparser::nextstartcode_file() {

int align_mode;

// check for byte-alignment

align_mode = bit_ptr % 8;

if (align_mode != 0) // not byte-aligned

bit_ptr -= align_mode;

while (!end_of_file && (nextbits_file(24) != 0x000001)) {

getbits_file(8); // skip a byte till 0x000001 is found

}

return;

}

void MPEGparser::nextstartcode() {

if (mode == M_FILE)

nextstartcode_();

else if (mode == M_STREAM)

nextstartcode_mtr();

else nextstartcode_file();

}

void MPEGparser::nextstartcode_() {

int align_mode;

// check for byte-alignment

align_mode = bit_ptr % 8;

if (align_mode != 0) // not byte-aligned

bit_ptr -= align_mode;

while (!end_of_file && (nextbits_ (24) != 0x000001)) {

getbits_(8); // skip a byte till 0x000001 is found

}

return;

}

void MPEGparser::nextstartcode_mtr() {

int align_mode;

// check for byte-alignment

align_mode = bit_ptr % 8;

if (align_mode != 0) // not byte-aligned

bit_ptr -= align_mode;

while (!end_of_file && (nextbits_mtr(24) != 0x000001)) {

getbits_mtr(8); // skip a byte till 0x000001 is found

}

return;

}

//****************************************************************

// getbitrate -

// procedure to obtain encoding bitrate in video sequence header

//

// returns

// + value of bitrate

// + -1 if error occured

//****************************************************************

int MPEGparser::getbitrate() {

DWORD dw;

WORD picWidth = 0x0000, picHeight = 0x0000;

int frameRate = 0x00000000, bitRate = 0x00000000;

// begin by linear search for the video sequence header

nextstartcode();

dw = getbits(32);

while ( (dw != SEQUENCE_HEADER_CODE) && !endofplayout() ) {

nextstartcode();

dw = getbits(32);

}

// end search because it's probably found the header already

// start looking for bitrate

// get rid of the next 32 bits because they're impertinent information

picWidth = getbits(12);

printf("picWidth: %d\n", picWidth);

picHeight = getbits(12);

printf("picHeight: %d\n", picHeight);

getbits(4); // pel_aspect ratio

frameRate = getbits(4);

printf("frameRate: %d fps\n", frameRate);

bitRate = getbits(18);

printf("bitRate: %d\n", bitRate);

printf("True bitrate: %d bits/sec\n", bitRate*400);

return bitRate;

}

//****************************************************************

// getpict -

// stores a frame into array pointed to by pframe, assume that

// front of MPEG stream begins with picture_start_code

//

// returns

// + size of frame

// + -1 if error occured

//****************************************************************

int MPEGparser::getpict() {

if (mode == M_FILE)

return getpict_();

else if (mode == M_STREAM)

return getpict_mtr();

return getpict_file(); // old

}

int MPEGparser::getpict_() {

int i = 0, f_size;

int byte_idx;

DWORD dw;

dw = getbits_(32);

// check that dw = PICTURE_START_CODE

if (dw != PICTURE_START_CODE) {

printf("first 32bits not PICTURE_START_CODE! Returning\n");

return -1;

}

// put picture_start_code into *pframe

for (byte_idx=32; byte_idx != 0; byte_idx -= 8) {

pFrame = (BYTE *)realloc(pFrame, i+1); // is realloc expensive ??

pFrame[i] = (BYTE) 0xff & (dw >> (byte_idx-8));

i++;

}

// allocate picture into an array of BYTES

// and then find its size

while ( (nextbits_(32) != PICTURE_START_CODE) &&

(nextbits_(32) != GROUP_START_CODE) && !endofplayout() ) {

pFrame = (BYTE *)realloc(pFrame, i+1); // is realloc expensive ??

pFrame[i] = getbits_(8);

i++;

}

f_size = i;

return f_size;

}

int MPEGparser::getpict_file() {

int i = 0, f_size;

int byte_idx;

DWORD dw;

dw = getbits_file(32);

// check that dw = PICTURE_START_CODE

if (dw != PICTURE_START_CODE) {

printf("first 32bits not PICTURE_START_CODE! Returning\n");

return -1;

}

// put picture_start_code into *pframe

for (byte_idx=32; byte_idx != 0; byte_idx -= 8) {

pFrame = (BYTE *)realloc(pFrame, i+1); // is realloc expensive ??

pFrame[i] = (BYTE) 0xff & (dw >> (byte_idx-8));

i++;

}

// allocate picture into an array of BYTES

// and then find its size

while ( (nextbits_file(32) != PICTURE_START_CODE) &&

(nextbits_file(32) != GROUP_START_CODE) && !endofplayout() ) {

pFrame = (BYTE *)realloc(pFrame, i+1); // is realloc expensive ??

pFrame[i] = getbits_file(8);

i++;

}

f_size = i;

return f_size;

}

int MPEGparser::getpict_mtr() {

int i = 0, f_size;

int byte_idx;

DWORD dw;

dw = getbits_mtr(32);

// check that dw = PICTURE_START_CODE

if (dw != PICTURE_START_CODE) {

printf("first 32bits not PICTURE_START_CODE! Returning\n");

return -1;

}

// put picture_start_code into *pframe

for (byte_idx=32; byte_idx != 0; byte_idx -= 8) {

pFrame = (BYTE *)realloc(pFrame, i+1); // is realloc expensive ??

pFrame[i] = (BYTE) 0xff & (dw >> (byte_idx-8));

i++;

}

// allocate picture into an array of BYTES

// and then find its size

while ( (nextbits_mtr(32) != PICTURE_START_CODE) &&

(nextbits_mtr(32) != GROUP_START_CODE) && !endofplayout() ) {

pFrame = (BYTE *)realloc(pFrame, i+1); // is realloc expensive ??

pFrame[i] = getbits_mtr(8);

i++;

}

f_size = i;

return f_size;

}

//****************************************************************

// Author: Hu Imm Lee

// Filename: NetInterface.h

// File Created: February 11, 1998

//

// Comments: Contains class definition for server NetInterface

//****************************************************************

struct UDP_packet;

typedef struct UDP_packet UDP_PACKET;

// network interface class

class NetInterface {

public:

// constructor and destructor

NetInterface();

~NetInterface();

BOOL net_init();

BOOL WaitForRequest();

BOOL sendpacket(UDP_PACKET* pPacket);

BOOL recvpacket(UDP_PACKET& packet);

BOOL tcpsend(TCP_PACKET* pPacket);

BOOL tcprecv(TCP_PACKET& packet);

BOOL sendping(PING_PACKET* pPacket);

BOOL recvping(PING_PACKET& packet);

void Disconnect();

SOCKET udpd;

SOCKET tcpd;

SOCKET pingd;

SOCKET client_tcpd;

struct sockaddr_in tcpclientaddr;

struct sockaddr_in udpclientaddr; // contains addr to send to for video packets

struct sockaddr_in pingclientaddr; // addr to send to for other services //(modified each time by recvpacket()

};

//**********************************************************************

// Author: Hu Imm Lee

// Filename: NetInterface.cpp

// File Created: February 11, 1998

//

// Comments: Contains implementation of the NetInterface class

//

//**********************************************************************

#include <stdio.h>

#include <windows.h>

#include "server.h"

#include "NetInterface.h"

extern void PrintWin32Error(char *);

extern int curpkt_id, oldpkt_id;

//**********************************************************************

// NETWORK INTERFACE CLASS IMPLEMENTATION BELOW

// - used by packet sender thread -

//**********************************************************************

NetInterface::NetInterface() {

WSADATA WsaData;

WORD wVersionRequested;

int err;

wVersionRequested = MAKEWORD(1,1);

if ( (err = WSAStartup(wVersionRequested, &WsaData)) != 0 ) {

printf("Could not find WinSock 1.1 DLL\n");

exit(0);

}

}

NetInterface::~NetInterface() {

closesocket(udpd);

closesocket(tcpd);

closesocket(pingd);

WSACleanup();

}

//****************************************************************

// NET_INIT

// initializes the network interface

// effects

// + creates UDP socket and allocates handle to

// NetInterface::udpd

// + binds UDP socket to a "well-known" port

// returns

// + TRUE if UDP socket successfully created and binded

// + FALSE on failure

//****************************************************************

BOOL NetInterface::net_init() {

struct sockaddr_in udpaddr; // udp

int optval, optlen = sizeof(optval);

struct sockaddr_in tcpaddr; // tcp

struct sockaddr_in pingaddr; // ping

// ** UDP/IP SETUP ** //

// make udp socket

if ( (udpd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))

== INVALID_SOCKET ) {

printf("UDP socket error [%d]\n", WSAGetLastError() );

return FALSE;

}

// udp bind

memset( (char *)&udpaddr, 0x00, sizeof(udpaddr) );

udpaddr.sin_family = AF_INET;

udpaddr.sin_port = htons(MYUDPPORT);

udpaddr.sin_addr.s_addr = htonl(INADDR_ANY);

if ( bind(udpd, (struct sockaddr *)&udpaddr, sizeof(udpaddr))

== SOCKET_ERROR ) {

printf("UDP bind error [%d]\n", WSAGetLastError() );

return FALSE;

}

// increase SO_SNDBUF buffer size -- no effect!

if ( getsockopt(udpd, SOL_SOCKET, SO_SNDBUF, (char *)&optval,

&optlen) == SOCKET_ERROR ) {

printf("UDP getsockopt error [%d]\n", WSAGetLastError() );

return FALSE;

}

optval = optval * 10;

if ( setsockopt(udpd, SOL_SOCKET, SO_SNDBUF, (char *)&optval,

optlen) == SOCKET_ERROR ) {

printf("UDP setsockopt error [%d]\n", WSAGetLastError() );

return FALSE;

}

// check to confirm new SO_SNDBUF buffer size

getsockopt(udpd, SOL_SOCKET, SO_SNDBUF, (char *)&optval,

&optlen);

printf("UDP so_sndbuf set to %d\n", optval);

// ** TCP/IP SETUP ** //

if ( (tcpd = socket(AF_INET, SOCK_STREAM, 0))

== INVALID_SOCKET ) {

printf("TCP socket error [%d]\n", WSAGetLastError() );

return FALSE;

}

// tcp bind

ZeroMemory( (char *)&tcpaddr, sizeof(tcpaddr) );

tcpaddr.sin_family = AF_INET;

tcpaddr.sin_port = htons(MYTCPPORT);

tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY);

if ( bind(tcpd, (struct sockaddr *)&tcpaddr, sizeof(tcpaddr))

== SOCKET_ERROR ) {

//printf("TCP bind error [%d]\n", WSAGetLastError() );

PrintWin32Error("TCP bind");

return FALSE;

}

// tcp listen

if ( listen(tcpd, SOMAXCONN) == SOCKET_ERROR ) {

printf("TCP listen error [%d]\n", WSAGetLastError() );

return FALSE;

}

// ** PING SERVICES SETUP ** //

if ( (pingd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) ==

INVALID_SOCKET ) {

printf("PING socket error [%d]\n", WSAGetLastError() );

return FALSE;

}

// ping bind

memset( (char *)&pingaddr, 0x00, sizeof(pingaddr) );

pingaddr.sin_family = AF_INET;

pingaddr.sin_port = htons(MYPINGPORT);

pingaddr.sin_addr.s_addr = htonl(INADDR_ANY);

if ( bind(pingd, (struct sockaddr *)&pingaddr, sizeof(pingaddr)) ==

SOCKET_ERROR ) {

printf("PING bind error [%d]\n", WSAGetLastError() );

return FALSE;

}

return TRUE;

}

//****************************************************************

// WAITFORREQUEST -

// effects

// method blocks until a udp packet is received

// returns

// FALSE if encountered either

// a) a recv error

// b) wrong packet type received

// TRUE is successful

//****************************************************************

BOOL NetInterface::WaitForRequest() {

int nrecv;

TCP_PACKET* pTcppkt = new TCP_PACKET;

int* pclnaddrsize = new int(sizeof(tcpclientaddr));

int addrlen = sizeof(struct sockaddr_in);

// accept a TCP client connection

if ( (client_tcpd = accept(tcpd, (struct sockaddr *)&tcpclientaddr,

pclnaddrsize)) == SOCKET_ERROR ) {

printf("\nNetInterface.WaitForRequest: accept ERRNO[%d]\n",

WSAGetLastError() );

return FALSE;

}

// receive a TCP request pkt

nrecv = recv(client_tcpd, (char *)pTcppkt, sizeof(*pTcppkt), 0);

if (nrecv == SOCKET_ERROR) {

printf("\nNetInterface.WaitForRequest: recv ERRNO[%d]\n",

WSAGetLastError() );

return FALSE;

}

// check if it's a valid packet received

if (pTcppkt->pkt_type != REQUEST) {

printf("\nNot a request packet [type %d]. Hmmmm ...\n",

pTcppkt->pkt_type);

return FALSE;

}

else {

// get client's udp connection address

getpeername(client_tcpd, (struct sockaddr *)&udpclientaddr,

&addrlen);

// get client UDP port #

udpclientaddr.sin_port = pTcppkt->udpclientaddr.sin_port;

delete pTcppkt;

pTcppkt = NULL;

delete pclnaddrsize;

return TRUE;

}

}

//****************************************************************

// RECVPACKET -

// receives a datagram via UDP

//****************************************************************

BOOL NetInterface::recvpacket(UDP_PACKET& packet) {

int nrecv;

struct sockaddr_in address;

int fromlen = sizeof(struct sockaddr_in);

nrecv = recvfrom( udpd, (char *)&packet, sizeof(packet), 0,

(struct sockaddr *)&address, &fromlen );

if (nrecv == SOCKET_ERROR) {

printf("NetInterface::recvpacket : recvfrom ERR[%d]\n",

WSAGetLastError() );

return FALSE;

}

else return TRUE;

}

//****************************************************************

// SENDPACKET -

// effects

// sends a datagram via UDP

// returns

// + TRUE is successful

// + FALSE is failure

//****************************************************************

BOOL NetInterface::sendpacket(UDP_PACKET* pPacket) {

int nsend;

curpkt_id = pPacket->seqnum;

oldpkt_id = curpkt_id;

nsend = sendto( udpd, (char *)pPacket, sizeof(*pPacket), 0,

(struct sockaddr *)&udpclientaddr, sizeof(udpclientaddr) );

if (nsend == SOCKET_ERROR) {

printf("NetInterface::sendpacket : sendto ERR[%d]\n",

WSAGetLastError() );

return FALSE;

}

else if (nsend != sizeof(*pPacket)) {

printf("NetInterface::sendpacket : sendto incomplete\n");

return FALSE;

}

else {

printf("\rsent pkt [%d] ", pPacket->seqnum);

return TRUE;

}

}

//****************************************************************

// TCPSEND -

// sends packet via TCP

//****************************************************************

BOOL NetInterface::tcpsend(TCP_PACKET* pPacket) {

int nsend;

nsend = send( NetInterface::client_tcpd, (char *)pPacket,

sizeof(TCP_PACKET), 0);

if (nsend == SOCKET_ERROR) {

printf("NetInterface::tcpsend ERR[%d]\n", WSAGetLastError() );

return FALSE;

}

return TRUE;

}

//****************************************************************

// TCPRECV -

// receives packet via TCP

//****************************************************************

BOOL NetInterface::tcprecv(TCP_PACKET& packet) {

int nrecv;

nrecv = recv( NetInterface::client_tcpd, (char *)&packet,

sizeof(TCP_PACKET), 0);

if (nrecv == SOCKET_ERROR) {

printf("NetInterface::tcprecv ERR[%d]\n", WSAGetLastError() );

return FALSE;

}

return TRUE;

}

//****************************************************************

// SENDPING -

// to send a packet for services like PING

// (in case the client requesting such service is different from

// the one that's receiving the video packets)

//

// effects

// sends a datagram via UDP using pingclientaddr

// returns

// + TRUE is successful

// + FALSE is failure

//

// CAUTION:

// server cannot initiate a PING if pingclientaddr has no value

//****************************************************************

BOOL NetInterface::sendping(PING_PACKET* pPacket) {

int nsend;

nsend = sendto( pingd, (char *)pPacket, sizeof(PING_PACKET), 0,

(struct sockaddr *)&pingclientaddr, sizeof(struct sockaddr_in) );

if (nsend == SOCKET_ERROR) {

printf("NetInterface::sendping : sendto ERR[%d]\n",

WSAGetLastError() );

return FALSE;

}

else if (nsend != sizeof(*pPacket)) {

printf("NetInterface::sendping: sendto incomplete\n");

return FALSE;

}

else {

return TRUE;

}

}

//****************************************************************

// RECVPING -

// receives a PING datagram via UDP

//****************************************************************

BOOL NetInterface::recvping(PING_PACKET& packet) {

int nrecv;

struct sockaddr_in address;

int fromlen = sizeof(struct sockaddr_in);

nrecv = recvfrom( pingd, (char *)&packet, sizeof(packet), 0,

(struct sockaddr *)&address, &fromlen );

pingclientaddr = address;

if (nrecv == SOCKET_ERROR) {

printf("NetInterface::recvping : recvfrom ERR[%d]\n",

WSAGetLastError() );

return FALSE;

}

else return TRUE;

}

//****************************************************************

// DISCONNECT -

// effects

// + sends a TERMINAL pkt via TCP to the client to indicate

// end of transmission

//****************************************************************

void NetInterface::Disconnect() {

int nsend;

TCP_PACKET* pTCPpkt = new TCP_PACKET;

pTCPpkt->pkt_type = TERMINAL;

ZeroMemory( (char *)&pTCPpkt->udpclientaddr,

sizeof(struct sockaddr_in) );

nsend = send(client_tcpd, (char *)pTCPpkt, sizeof(*pTCPpkt), 0);

if (nsend == SOCKET_ERROR)

printf("\nNetInterface.Disconnect : send error [%d]\n",

WSAGetLastError() );

}

//****************************************************************

// Author: Hu Imm Lee

// Filename: PacketStream.h

// File Created: February 11, 1998

//

// Comments: Contains prototype for PacketStream class

//

//****************************************************************

typedef struct UDP_packet UDP_PACKET;

// packet stream class (a circular pointer-based queue)

class PacketStream {

public:

// constructor and destructor

PacketStream();

~PacketStream();

BOOL StreamIsEmpty();

void AddPacket(UDP_PACKET NewPacket, BOOL& Status);

void GetFrontPacket(UDP_PACKET& FrontPacket, BOOL& Status);

void RemovePacket(BOOL& Status);

private:

struct StreamNode* pRear;

LPCRITICAL_SECTION lpCriticalSection;

};

//****************************************************************

// Author: Hu Imm Lee

// Filename: PacketStream.cpp

// File Created: February 11, 1998

//

// Comments: Contains implementation of PacketStream class

//

//****************************************************************

#include <stdio.h>

#include <windows.h>

#include "server.h"

#include "PacketStream.h"

extern int packets;

//****************************************************************

// PACKET STREAM CLASS IMPLEMENTATION

// - shared by packetizer and packetsender threads -

//****************************************************************

PacketStream::PacketStream():pRear(NULL) {

// create critical section object to synchronize sharing of the stream

// esp for AddPacket and RemovePacket

lpCriticalSection = new CRITICAL_SECTION;

InitializeCriticalSection(lpCriticalSection);

}

PacketStream::~PacketStream() {

DeleteCriticalSection(lpCriticalSection); // release the CS object

}

//****************************************************************

// STREAM IS EMPTY -

// returns

// TRUE if stream (queue) is empty

// FALSE if stream is not empty

//****************************************************************

BOOL PacketStream::StreamIsEmpty() {

if (pRear == NULL)

return TRUE;

else return FALSE;

}

//****************************************************************

// ADD PACKET -

// Add packet to the back of the queue

// effects

// + critical section, so routine has to first take ownership

// before proceeding

// + allocates a new node into the stream

// + alters the rear pointer to point to new node (containing

// new packet

//****************************************************************

void PacketStream::AddPacket(UDP_PACKET NewPacket, BOOL& Status) {

__try {

// request for ownership to cs object

// if cs obj has already been owned, it blocks till obj is released

EnterCriticalSection(lpCriticalSection);

// create new node

struct StreamNode* pRearNew = new struct StreamNode;

Status = boolean(pRearNew != NULL);

if (Status) {

pRearNew->NodeItem = NewPacket;

// inserting new packet node into stream

if (StreamIsEmpty())

// first node points to itself

pRearNew->pNextNode = pRearNew;

else {

// insertion into non-empty stream

pRearNew->pNextNode = pRear->pNextNode;

pRear->pNextNode = pRearNew;

}

pRear = pRearNew; // new node is now at rear

}

packets++;

}

__finally {

// release ownership of cs obj when done

LeaveCriticalSection(lpCriticalSection);

}

}

//****************************************************************

// GET FRONT PACKET -

// Retrieve packet at front of stream

// effects

// + NIL (doesn't alter the stream)

//****************************************************************

void PacketStream::GetFrontPacket(UDP_PACKET& FrontPacket, BOOL& Status) {

// request for ownership to cs object

// if cs obj has already been owned, it blocks till obj is released

EnterCriticalSection(lpCriticalSection);

Status = boolean(!StreamIsEmpty());

if (Status) // stream isn't empty

FrontPacket = pRear->pNextNode->NodeItem;

LeaveCriticalSection(lpCriticalSection);

}

//****************************************************************

// REMOVE PACKET -

// Removes front node of stream

// effects

// + critical section, so routine has to first take ownership

// before proceeding

// + change rear pointer to point to second node of stream

// + front node is deallocated

//****************************************************************

void PacketStream::RemovePacket(BOOL& Status) {

__try {

// request for ownership to cs object

// if cs obj has already been owned, it blocks till obj is released

EnterCriticalSection(lpCriticalSection);

Status = boolean(!StreamIsEmpty());

if (Status) { // stream is not empty

struct StreamNode* pFront = pRear->pNextNode;

if (pFront == pRear)

pRear = NULL; // if only one node in stream

else

pRear->pNextNode = pFront->pNextNode;

pFront->pNextNode = NULL;

delete pFront;

}

}

__finally {

// release ownership of CS obj when done

LeaveCriticalSection(lpCriticalSection);

}

}

//****************************************************************

// Author: Hu Imm Lee

// Filename: RetransmissionBuffer.h

// File Created: February 11, 1998

//

// Comments: Contains class definition for RetransmissionBuffer

//

//****************************************************************

typedef struct UDP_packet UDP_PACKET;

// Retransmission Buffer class (a fixed-size circular queue)

class RetransmissionBuffer {

public:

// constructor and destructor

RetransmissionBuffer(int minbufsize);

~RetransmissionBuffer();

void add(UDP_PACKET* pNewPacket);

BOOL retrieve(UDP_PACKET& RequestedPacket, int seqnum);

private:

static int buffsize;

static UDP_PACKET* pBuf; // ptr to circular array

//int iFront; // index to front of buffer

static int iRear; // index to rear of buffer

};

//**********************************************************************

// Author: Hu Imm Lee

// Filename: RetransmissionBuffer.cpp

// File Created: February 11, 1998

//

// Comments: Contains implementation of RetransmissionBuffer class

//

//**********************************************************************

#include <stdio.h>

#include <windows.h>

#include <math.h>

#include "server.h"

#include "RetransmissionBuffer.h"

//**********************************************************************

// Retransmission Buffer Class Implementation Below

//**********************************************************************

int RetransmissionBuffer::buffsize = 0;

UDP_PACKET* RetransmissionBuffer::pBuf = NULL;

int RetransmissionBuffer::iRear = 0;

RetransmissionBuffer::RetransmissionBuffer(int minbufsize) {

// rear starts off pointing to the front because buffer is empty

// make the buffer size divisible by 8 because the udp

// packet's seqnum is a max of 2^16 - 1, i.e., 2 bytes long

// for example: if minbufsize is 14, then buffsize should be 16

RetransmissionBuffer::buffsize = (int) ceil((double)minbufsize/8) * 8;

printf("RetransmissionBuffer initialization:\n\tbuffsize is: %d\n", RetransmissionBuffer::buffsize);

// make empty circular buffer here

RetransmissionBuffer::pBuf = new UDP_PACKET[RetransmissionBuffer::buffsize]; // an empty fixed size array

}

RetransmissionBuffer::~RetransmissionBuffer() {

delete RetransmissionBuffer::pBuf;

RetransmissionBuffer::pBuf = NULL;

}

// It doesn't matter if the buffer is empty or not

//**********************************************************************

// ADD -

// effects

// + each packet is assigned a "slot"

// + OVERWRITES the "older" packets which have already expired

// (located at the front of the buffer)

//

//**********************************************************************

void RetransmissionBuffer::add(UDP_PACKET* pNewPacket) {

int index = pNewPacket->seqnum % buffsize;

pBuf[index] = *pNewPacket;

}

//****************************************************************

// RETRIEVE -

// effects

// + reads the packet from pBuf containing packet with

// seqnum

// + causes NO effect on pBuf's index pointer

//

// the algorithm searches for a match for the requested packet by

// elegantly calculating the exact place within pBuf that it should

// be located.

//

// returns

// + TRUE if packet was found

// + FALSE if not found

//****************************************************************

BOOL RetransmissionBuffer::retrieve(UDP_PACKET& RequestedPacket, int seqnum) {

int index; // indicates where to find the packet in pBuf

UDP_PACKET packet;

printf("RetransmissionBuffer:: retrieve\n\trequesting pkt[%d]\n",

seqnum);

index = seqnum % buffsize;

printf("\tLooking into index %d\n", index);

packet = RetransmissionBuffer::pBuf[index];

printf("\tFound pkt[%d] in buffer\n", packet.seqnum);

if (packet.seqnum == seqnum) { // check that it's the right packet

RequestedPacket = packet;

return TRUE;

}

else return FALSE; // failure if requested packet has already expired

}

//****************************************************************

// Filename: SystemUtility.h

// Comments: Contains class definition for SystemUtility

//****************************************************************

// system interface class

class SystemUtility {

public:

// constructor and destructor

SystemUtility();

~SystemUtility();

BOOL checkoverflow(LPWORD pN);

};

//**********************************************************************

// Filename: SystemUtility.cpp

// Comments: Contains implementation of SystemUtility class

//**********************************************************************

#include <stdio.h>

#include <windows.h>

#include <math.h>

#include "SystemUtility.h"

//****************************************************************

// SYSTEM UTILITY CLASS IMPLEMENTATION BELOW

//****************************************************************

SystemUtility::SystemUtility() {

}

SystemUtility::~SystemUtility() {

}

//****************************************************************

// CHECK OVERFLOW -

// avoids overflow in a 16bit unsigned int

// returns

// + FALSE if *pN is about to overflow

// + TRUE if still OK

//

//****************************************************************

BOOL SystemUtility::checkoverflow(LPWORD pN) {

WORD max;

// [2 ^ (# bytes x 8bi