├── makefile ├── README.md ├── Help ├── Queue.h ├── Queue.cpp └── CustomHttpd.cpp /makefile: -------------------------------------------------------------------------------- 1 | Proj1: CustomHttpd.cpp Queue.cpp Queue.h 2 | g++ CustomHttpd.cpp Queue.cpp -o myhttpd -lpthread 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Custom-httpd 2 | ============ 3 | 4 | Emulation of a web server by way of an interface (using C sockets) for receiving HTTP/1.0 requests and a thread-pool to serve the requests based on a couple of scheduling algorithms (FCFS and SJF). 5 | 6 | 7 | Compilation: Type 'make' on the terminal. 8 | 9 | Executable name: myhttpd 10 | 11 | Notes: 12 | 13 | 1) A file named "sys.log" will be created in the current directory. It contains the trace of every operation performed by the web server. 14 | 2) Compilation may display some warnings on the terminal. 15 | -------------------------------------------------------------------------------- /Help: -------------------------------------------------------------------------------- 1 | OPTIONS: 2 | −d : Enter debugging mode. That is, do not daemonize, only accept one connection at a time and enable logging to stdout. Without this option, the web server should run as a daemon process in the background. 3 | −h : Print a usage summary with all options and exit. 4 | −l file : Log all requests to the given file. See LOGGING for details. 5 | −p port : Listen on the given port. If not provided, myhttpd will listen on port 8080. 6 | −r dir : Set the root directory for the http server to dir. 7 | −t time : Set the queuing time to time seconds. The default should be 60 seconds. 8 | −n threadnum: Set number of threads waiting ready in the execution thread pool to threadnum. The default should be 4 execution threads. 9 | −s sched : Set the scheduling policy. It can be either FCFS or SJF. The default will be FCFS. 10 | -------------------------------------------------------------------------------- /Queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Queue.h 3 | * 4 | * Created on: Oct 25, 2013 5 | * Author: subhranil 6 | */ 7 | #include 8 | #include 9 | 10 | #ifndef QUEUE_H_ 11 | #define QUEUE_H_ 12 | 13 | struct task; 14 | 15 | typedef struct Node 16 | { 17 | void* data; 18 | struct Node* next; 19 | } Node; 20 | 21 | //class Queue { 22 | //protected: 23 | // 24 | // Node *mHead; 25 | // Node *mTail; 26 | // int mNumberOfElements; 27 | //public: 28 | // Queue(); 29 | // virtual ~Queue(); 30 | // Node* start(); 31 | // bool isEmpty(); 32 | // virtual void enQueue(void*); 33 | // Node *deQueue(); 34 | // static Node* iterate(Node* head); 35 | // 36 | //}; 37 | // 38 | // 39 | // 40 | //class PriorityQueue: public Queue 41 | //{ 42 | //public: 43 | // PriorityQueue(); 44 | // void enQueue(void* task); 45 | //}; 46 | 47 | typedef struct Queue 48 | { 49 | Node *mHead; 50 | Node *mTail; 51 | int mNumberOfElements; 52 | //public: 53 | // Queue(); 54 | // virtual ~Queue(); 55 | // Node* start(); 56 | // bool isEmpty(); 57 | // virtual void enQueue(void*); 58 | // Node *deQueue(); 59 | // static Node* iterate(Node* head); 60 | } Queue; 61 | 62 | Queue* initialiseQueue(); 63 | void enQueue(Queue*,void*); 64 | Node* deQueue(Queue*); 65 | //static Node* iterate(Queue,Node* head); 66 | 67 | #endif /* QUEUE_H_ */ 68 | 69 | 70 | -------------------------------------------------------------------------------- /Queue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Queue.cpp 3 | * 4 | * Created on: Oct 25, 2013 5 | * Author: subhranil 6 | */ 7 | 8 | #include "Queue.h" 9 | 10 | //Queue::Queue() { 11 | // // TODO Auto-generated constructor stub 12 | // mHead=NULL; 13 | // mTail=NULL; 14 | // mNumberOfElements=0; 15 | // 16 | //} 17 | 18 | //Queue::~Queue() { 19 | // // TODO Auto-generated destructor stub 20 | //} 21 | // 22 | //bool Queue::isEmpty() 23 | //{ 24 | // return (mHead!=NULL); 25 | //} 26 | //void Queue::enQueue(void* data) 27 | //{ 28 | // 29 | // Node *newNode=(Node*)malloc(sizeof(Node)); 30 | // newNode->data=data; 31 | // newNode->next=NULL; 32 | // if(mTail) //starting condition 33 | // mTail->next=newNode; 34 | // mTail=newNode; 35 | // mNumberOfElements++; 36 | // if(!mHead) //starting condition 37 | // mHead=mTail; 38 | // 39 | //} 40 | 41 | //Node* Queue::start() 42 | //{ 43 | // return mHead; 44 | //} 45 | //Node* Queue::iterate(Node* it) 46 | //{ 47 | // static Node* head=NULL; 48 | // head=(it!=NULL)?it:head; 49 | // if(head==NULL) 50 | // return NULL; 51 | // Node* temp=head; 52 | // head=head->next; 53 | // return temp; 54 | // 55 | // 56 | //} 57 | 58 | //Node* Queue::deQueue() 59 | //{ 60 | // if(!mHead) //empty check 61 | // return NULL; 62 | // 63 | // Node* temp=mHead; 64 | // mHead=mHead->next; 65 | // mNumberOfElements--; 66 | // return mHead; 67 | // 68 | //} 69 | 70 | Queue* initialiseQueue() 71 | { 72 | Queue* newQ=(Queue*)malloc(sizeof(Queue)); 73 | newQ->mHead=NULL; 74 | newQ->mTail=NULL; 75 | newQ->mNumberOfElements=0; 76 | return newQ; 77 | } 78 | void enQueue(Queue* q,void* data) 79 | { 80 | Node *newNode=(Node*)malloc(sizeof(Node)); 81 | newNode->data=data; 82 | newNode->next=NULL; 83 | if(q->mTail) //starting condition 84 | q->mTail->next=newNode; 85 | q->mTail=newNode; 86 | q->mNumberOfElements++; 87 | if(!q->mHead) //starting condition 88 | q->mHead=q->mTail; 89 | } 90 | Node* deQueue(Queue* q) 91 | { 92 | if(!q->mHead) //empty check 93 | return NULL; 94 | 95 | Node* temp=q->mHead; 96 | q->mHead=q->mHead->next; 97 | q->mNumberOfElements--; 98 | if(!q->mHead) 99 | q->mTail=NULL; 100 | return temp; 101 | } 102 | bool isEmpty(Queue*q) 103 | { 104 | return (q->mHead!=NULL); 105 | } 106 | -------------------------------------------------------------------------------- /CustomHttpd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * CustomHttpd.cpp 3 | * 4 | * Created on: Oct 22, 2013 5 | * Author: subhranil 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include"Queue.h" 27 | 28 | 29 | 30 | bool gRunInDebug=false; 31 | char gUserLogFile[1024]=""; 32 | char gSystemLogFile[1024]="sys.log"; 33 | int gListeningPort=8080; 34 | char gDirectoryRoot[1024]=""; 35 | int gNumberOfThreads=4; 36 | int gQueingTime=60; 37 | char gSchedulingAlgo[5]="FCFS"; 38 | int gListeningSocketId; 39 | 40 | static pthread_mutex_t taskListUpdateLock=PTHREAD_MUTEX_INITIALIZER; 41 | static pthread_mutex_t freeListUpdateLock=PTHREAD_MUTEX_INITIALIZER; 42 | 43 | typedef struct sockaddr_in SocketAddressInfo; 44 | 45 | typedef struct task 46 | { 47 | char fileName[1024]; 48 | long long int fileSize; 49 | int requestingConnectionId; 50 | char remoteIP[32]; 51 | char queingTime[100]; 52 | char executionTime[100]; 53 | char request[100]; 54 | char reqType[6]; 55 | int status; 56 | } Task; 57 | 58 | typedef struct WorkerThread 59 | { 60 | int threadId; 61 | void *task; 62 | void* delegatePool; 63 | pthread_t thread; 64 | // sem_t assignmentSem; 65 | // sem_t completionSem; 66 | }WorkerThread; 67 | 68 | typedef struct threadPool 69 | { 70 | WorkerThread **mThreadList; // array of worker threads(ptrs) 71 | Queue* avaliableThreads; // shared b/w worker threads and scheduler thread/ 72 | Queue* taskList; // could be priority queue as well handle accordingly.Shared b/w queuing thread and scheduler thread 73 | int numberOfThreads; 74 | int schType; 75 | sem_t taskCompletion; 76 | sem_t* taskAssignment; 77 | 78 | } CustomThreadPool; 79 | 80 | 81 | //Necessary function declarations 82 | void* workerRoutine(void *ptr); 83 | void taskDidComplete(WorkerThread* ptr , CustomThreadPool* pool); // called on worker thread 84 | char* getLocalIP(); 85 | long long int getFileSize(char* fileName); 86 | char * getCurrentGMTTime(); 87 | char *replaceTildeInPath(char* path); 88 | 89 | 90 | 91 | char* generatePermissionErrorHTML(char *file,int port) 92 | { 93 | char baseHTML[600]="403 Forbidden

Forbidden

You don't have permission to access this URL on this server.


Myhttpd service at Port %d
"; 94 | char newHTML[650]; 95 | sprintf(newHTML,baseHTML,port); 96 | return newHTML; 97 | } 98 | char *generateMissingErrorHTML(char *file, int port) 99 | { 100 | char baseHTML[600]="404 Not Found

Not Found

The requested URL was not found on this server.


Myhttpd service at Port %d
"; 101 | char newHTML[650]; 102 | sprintf(newHTML,baseHTML,port); 103 | return newHTML; 104 | } 105 | 106 | 107 | static pthread_mutex_t writeLock=PTHREAD_MUTEX_INITIALIZER; 108 | static void* writeLog(char* str,char* outputFile) 109 | { 110 | 111 | pthread_mutex_lock(&writeLock); 112 | //return; 113 | char *finalStr; 114 | if(strcmp(outputFile,gUserLogFile)==0) 115 | { 116 | finalStr=(char*)malloc(strlen(str)); 117 | strcpy(finalStr,str); 118 | 119 | 120 | }else 121 | { 122 | finalStr=(char*)malloc(strlen(str)+30); 123 | time_t ltime; 124 | ltime=time(0); //current time 125 | char timestampStr[50]; 126 | struct tm currTime; 127 | localtime_r(<ime,&currTime); 128 | strftime(timestampStr,50,"%Y-%m-%d %H:%M:%S",(const struct tm*)&currTime); 129 | sprintf(finalStr,"[%s]:%s",timestampStr,str); 130 | } 131 | int writefd=open(outputFile,O_WRONLY|O_CREAT| O_EXCL, S_IRUSR | S_IWUSR | S_IROTH); 132 | if(writefd<0) 133 | { 134 | if(errno==EEXIST) 135 | { 136 | //printf("file already exists"); 137 | writefd=open(outputFile,O_WRONLY); 138 | //printf("error in open%d",errno); 139 | } 140 | 141 | } 142 | lseek(writefd,0,SEEK_END); 143 | write(writefd,finalStr,strlen(finalStr)); 144 | close(writefd); 145 | //if(finalStr) 146 | //{ free(finalStr); 147 | // finalStr=NULL; 148 | //} 149 | pthread_mutex_unlock(&writeLock); 150 | } 151 | 152 | 153 | WorkerThread* initializeWorker(int id,CustomThreadPool* del) // same logic as class init 154 | { 155 | WorkerThread* w=(WorkerThread*)malloc(sizeof(WorkerThread)); 156 | w->threadId=id; 157 | w->task=NULL; 158 | //w->completionSem=*Completionsem; 159 | //w->assignmentSem=*assignSem; 160 | w->delegatePool=del; 161 | pthread_create(&w->thread,NULL,workerRoutine,(void*)w); 162 | return w; 163 | } 164 | 165 | char* getContentType(char *filename) 166 | { 167 | const char *dot = strrchr(filename, '.'); 168 | dot++; 169 | 170 | char type[30]=""; 171 | if(strcmp(dot,"jpg")==0||strcmp(dot,"jpeg")==0||strcmp(dot,"gif")==0||strcmp(dot,"png")==0) 172 | sprintf(type,"image/%s",dot); 173 | else if(strcmp(dot,"css")==0||strcmp(dot,"html")==0) 174 | sprintf(type,"text/%s",dot); 175 | 176 | //printf("%s-->%s\n",filename,type); 177 | return type; 178 | } 179 | 180 | 181 | 182 | void executeTask(void *task) 183 | { 184 | Task *t=(Task*)task; 185 | char statusStr[10]; 186 | struct stat st; 187 | 188 | char *fileBuffer=NULL; 189 | char serverName[50]="myHttpd"; 190 | char cType[30]="text/html"; 191 | char modTimeHeader[100]=""; 192 | 193 | int retValue=stat(t->fileName,&st); 194 | long long int dataSize=0; 195 | if(retValue==-1) 196 | { 197 | if(errno==ENOENT) //file does not exist 198 | { 199 | t->status=404; 200 | strcpy(statusStr,"Not Found"); 201 | char *mssg=generateMissingErrorHTML(t->fileName,gListeningPort); 202 | fileBuffer=(char*)malloc(strlen(mssg)); 203 | strcpy(fileBuffer,mssg); 204 | dataSize=strlen(fileBuffer); 205 | } 206 | } 207 | else //stat works fine 208 | { 209 | if(S_ISDIR(st.st_mode)) // handle for dictionary 210 | { 211 | //check if it has index.html 212 | char newpath[100]; 213 | sprintf(newpath,"%sindex.html",t->fileName); 214 | if(access(newpath,F_OK)==0) 215 | { 216 | strcpy(t->fileName,newpath); 217 | executeTask(t); 218 | return; 219 | } 220 | 221 | DIR *dir; 222 | fileBuffer=(char*)malloc(5000); 223 | strcpy(fileBuffer,""); 224 | //char mssg[5000]; 225 | struct dirent *enumerator; 226 | if ((dir = opendir (t->fileName))!= NULL) 227 | { 228 | while ((enumerator = readdir (dir)) != NULL) 229 | { 230 | if(enumerator->d_name[0]=='.') 231 | continue; 232 | char path[100]; 233 | struct stat s; 234 | sprintf(path,"%s%s",t->fileName,enumerator->d_name); 235 | int ret=stat(path,&s); 236 | if(ret==0) 237 | { 238 | //time_t modTimeValue=(time_t)s.st_mtim; 239 | char modTime[50]; 240 | 241 | struct tm *ltime=localtime((time_t*)&(s.st_mtim)); 242 | strftime(modTime,50,"%Y-%m-%d %H:%M:%S",ltime); 243 | sprintf(fileBuffer,"%s\n",fileBuffer,enumerator->d_name,enumerator->d_name,modTime,(s.st_size/1024)); 244 | } 245 | 246 | } 247 | closedir (dir); 248 | sprintf(fileBuffer,"%s
FileNameMod. DateSize
%s%s%ldK
\n",fileBuffer); 249 | dataSize=strlen(fileBuffer); 250 | t->status=200; 251 | strcpy(statusStr,"OK"); 252 | } 253 | else 254 | { 255 | t->status=403; 256 | strcpy(statusStr,"Forbidden"); 257 | char *mssg=generatePermissionErrorHTML(t->fileName,gListeningPort);//PERMISSION_ERROR(t->fileName,serverName,gListeningPort); 258 | fileBuffer=(char*)malloc(strlen(mssg)); 259 | strcpy(fileBuffer,mssg); 260 | dataSize=strlen(fileBuffer); 261 | } 262 | 263 | } 264 | else // file .. rest of the code comes here 265 | { 266 | int fileDesc=open(t->fileName,O_RDONLY); 267 | if(fileDesc<0) 268 | { 269 | if(errno ==EACCES) //403 case 270 | { 271 | t->status=403; 272 | strcpy(statusStr,"Forbidden"); 273 | char *mssg=generatePermissionErrorHTML(t->fileName,gListeningPort); 274 | fileBuffer=(char*)malloc(strlen(mssg)); 275 | strcpy(fileBuffer,mssg); 276 | dataSize=strlen(fileBuffer); 277 | } 278 | } 279 | else // all is well !! add to buffer 280 | { 281 | strcpy(cType,getContentType(t->fileName)); 282 | 283 | if(strcmp(t->reqType,"GET")==0) 284 | { 285 | fileBuffer=(char*)malloc(t->fileSize); 286 | dataSize=read(fileDesc,fileBuffer,t->fileSize); 287 | if(dataSize<=0) // this should not happen. 288 | { 289 | //printf("Unable to read"); 290 | 291 | } 292 | } 293 | else 294 | dataSize=getFileSize(t->fileName); 295 | t->status=200; 296 | strcpy(statusStr,"OK"); 297 | // fetch the mod time for the header 298 | 299 | struct tm ltime; 300 | gmtime_r((time_t*)&(st.st_mtim),<ime); 301 | strftime(modTimeHeader,50,"%a, %e %b %Y %H:%M:%S %Z",<ime); 302 | } 303 | } 304 | } 305 | strcpy(t->executionTime,getCurrentGMTTime()); 306 | 307 | // create the date header value in the apache format 308 | char dateHeader[100]=""; 309 | time_t currTime; 310 | time(&currTime); 311 | struct tm ltime; 312 | gmtime_r(&currTime,<ime); 313 | strftime(dateHeader,100,"%a, %e %b %Y %H:%M:%S %Z",<ime); 314 | //convertIntoGMT() 315 | try 316 | { 317 | 318 | //handle get and head requests accordingly 319 | 320 | char *response=NULL; 321 | if(strcmp(t->reqType,"GET")==0) 322 | { 323 | response=(char*)malloc(dataSize+5000); 324 | sprintf(response,"HTTP/1.0 %d %s\nDate:%s\nServer:%s\nLast-Modified:%s\nContent-Type:%s\nContent-Length:%lld\n\n",t->status,statusStr,dateHeader,serverName,modTimeHeader,cType,dataSize); 325 | int headerLen=strlen(response); 326 | memcpy(response+headerLen,fileBuffer,dataSize); 327 | send(t->requestingConnectionId,response,(headerLen+dataSize),0); 328 | } 329 | else 330 | { 331 | response=(char*)malloc(5000); 332 | sprintf(response,"HTTP/1.0 %d %s\nDate:%s\nServer:%s\nLast-Modified:%s\nContent-Type:%s\nContent-Length:%lld\n\n",t->status,statusStr,dateHeader,serverName,modTimeHeader,cType,dataSize); 333 | send(t->requestingConnectionId,response,strlen(response),0); 334 | 335 | } 336 | close(t->requestingConnectionId); 337 | 338 | 339 | //Log into user logfile 340 | 341 | char buffer[500]; 342 | sprintf(buffer,"%s - [%s] [%s] \"%s\" %d %lld\n",t->remoteIP,t->queingTime,t->executionTime,t->request,t->status,dataSize); 343 | if(gRunInDebug) 344 | printf("%s",buffer); 345 | else 346 | { 347 | if(strlen(gUserLogFile)!=0) 348 | writeLog(buffer,gUserLogFile); 349 | } 350 | // if(fileBuffer) 351 | // free(fileBuffer); 352 | // if(response) 353 | //free(response); 354 | } 355 | catch(...) 356 | { 357 | printf("exception caught.\n"); 358 | } 359 | } 360 | 361 | 362 | void* workerRoutine(void *ptr) // static method , ptr will contain instance of WorkerThread* 363 | { 364 | WorkerThread *obj=(WorkerThread*)ptr; 365 | while(1) 366 | { 367 | //pthread_mutex_lock(&obj->assignmentLock); 368 | 369 | sem_wait(&(((CustomThreadPool*)(obj->delegatePool))->taskAssignment[obj->threadId] )); 370 | executeTask((Task*)(obj->task)); 371 | 372 | 373 | 374 | taskDidComplete(obj,(CustomThreadPool*)obj->delegatePool); 375 | //((CustomThreadPool*)(obj->delegate))->taskDidComplete(obj); 376 | 377 | sem_post(&(((CustomThreadPool*)(obj->delegatePool))->taskCompletion)); 378 | //pthread_mutex_unlock(&obj->completionLock); 379 | } 380 | 381 | } 382 | 383 | void assignTask(WorkerThread *worker,Task* t) 384 | { 385 | //if(worker->task) 386 | //free(worker->task); 387 | 388 | worker->task=t; 389 | } 390 | 391 | // this is hard coded only for task type data.. can be extended by generalization 392 | void priorityEnQueue(Queue* q,void *task) // will be used only for SJF 393 | { 394 | //Task * data=(Task*)task; 395 | Node* temp=(Node*)malloc(sizeof(Node)); 396 | temp->data=task; 397 | if(q->mHead==NULL) // empty list 398 | { 399 | q->mHead=temp; 400 | q->mTail=temp; 401 | q->mHead->next=NULL; 402 | q->mNumberOfElements++; 403 | 404 | } 405 | else if(((Task*)(temp->data))->fileSize<((Task*)(q->mHead->data))->fileSize) // add at the beginning 406 | { 407 | temp->next=q->mHead; 408 | q->mHead=temp; 409 | q->mNumberOfElements++; 410 | 411 | } 412 | else 413 | { 414 | Node* ptr=q->mHead; 415 | while(ptr->next) 416 | { 417 | // insert node at location where data>ptr->data->filesize &&datadata->filesize 418 | if(((Task*)(temp->data))->fileSize>=((Task*)(ptr->data))->fileSize&&((Task*)(temp->data))->fileSize<((Task*)(ptr->data))->fileSize) //insert here 419 | { 420 | 421 | temp->next=ptr->next; 422 | ptr->next=temp; 423 | q->mNumberOfElements++; 424 | return; 425 | } 426 | else 427 | ptr=ptr->next; 428 | } 429 | //append at the end 430 | ptr->next=temp; 431 | temp->next=NULL; 432 | q->mTail=temp; 433 | q->mNumberOfElements++; 434 | 435 | } 436 | } 437 | 438 | CustomThreadPool* initializeThreadPool(int numThreads,int sch) // same logic as class init 439 | { 440 | CustomThreadPool *pool=(CustomThreadPool*)malloc(sizeof(CustomThreadPool)); 441 | pool->mThreadList=(WorkerThread**)malloc(sizeof(WorkerThread*)*numThreads); 442 | pool->taskAssignment=(sem_t*)malloc(sizeof(sem_t)*numThreads); 443 | pool->schType=sch; 444 | pool->avaliableThreads=initialiseQueue(); 445 | sem_init(&pool->taskCompletion,0,numThreads); 446 | //ADD ALL THE THREADS TO THE AVAILABLE Q 447 | for(int i=0;itaskAssignment[i],0,0); 450 | pool->mThreadList[i]= initializeWorker(i,pool); 451 | enQueue(pool->avaliableThreads,pool->mThreadList[i]); 452 | 453 | } 454 | pool->taskList=initialiseQueue(); 455 | //if(sch==0)//FCFS 456 | //pool->taskList=new Queue(); 457 | //else //SJF 458 | //pool->taskList=new PriorityQueue(); 459 | 460 | return pool; 461 | } 462 | 463 | void addTask(CustomThreadPool*pool,Task* t) //called on the queuing thread that receives http requests 464 | { 465 | pthread_mutex_lock(&taskListUpdateLock); //mutual exclusion 466 | if(pool->schType==0) 467 | enQueue(pool->taskList,t); 468 | else 469 | priorityEnQueue(pool->taskList,t); 470 | //printf("task added to %u\n",pool->taskList); 471 | fflush(stdout); 472 | writeLog("Task added\n",gSystemLogFile); 473 | pthread_mutex_unlock(&taskListUpdateLock); 474 | 475 | } 476 | 477 | static void* scheduler(void* ptr) // the STATIC function must run an infinite loop waiting for a semaphore that is dec everytime a thread is allocated and inc when the thread gets free 478 | { 479 | CustomThreadPool *obj=(CustomThreadPool*)ptr; 480 | //printf("Starting wait on scheduler thread\n"); 481 | writeLog("Starting wait on scheduler thread\n",gSystemLogFile); 482 | sleep(gQueingTime); 483 | //printf("Wait over. starting with scheduling\n"); 484 | writeLog("Wait over. starting with scheduling\n",gSystemLogFile); 485 | while(1) 486 | { 487 | 488 | pthread_mutex_lock(&taskListUpdateLock); 489 | 490 | // Loop over the qu to display 491 | if(obj->taskList->mHead==NULL) 492 | { 493 | pthread_mutex_unlock(&taskListUpdateLock); 494 | continue; 495 | //printf("No tasks in Q.\n"); 496 | //writeLog("No tasks in Q.\n",gSystemLogFile); 497 | } 498 | else 499 | { 500 | writeLog("Tasks queue details:****************************************\n",gSystemLogFile); 501 | char mssg[5000]=""; 502 | for(Node* n=obj->taskList->mHead;n!=NULL;n=n->next) 503 | { 504 | Task* itTask=(Task*)(n->data); 505 | sprintf(mssg,"%s%s--->%lld--->%s--->%s ------>%s---->%s--->%d\n",mssg,itTask->fileName,itTask->fileSize,itTask->remoteIP,itTask->queingTime,itTask->executionTime,itTask->request,itTask->status); 506 | } 507 | sprintf(mssg,"%s******************************************************\n",mssg); 508 | writeLog(mssg,gSystemLogFile); 509 | } 510 | // End of log writing 511 | Node *n=deQueue(obj->taskList); 512 | Task* t=NULL; 513 | if(n!=NULL) 514 | { 515 | t=(Task*)(n->data); 516 | n->data=NULL; 517 | n->next=NULL; 518 | //t=(Task*)malloc(sizeof(Task)); 519 | //memcpy(t,n->data,sizeof(Task)); 520 | 521 | free(n); 522 | n=NULL; 523 | } 524 | 525 | 526 | pthread_mutex_unlock(&taskListUpdateLock); 527 | 528 | if(t==NULL) 529 | continue; 530 | //assign this task to the next available thread 531 | // pthread_mutex_lock(&freeListUpdateLock); 532 | // if(avaliableThreads->isEmpty()) 533 | // { 534 | // pthread_mutex_unlock(&freeListUpdateLock); 535 | // pthread_mutex_lock(&taskCompletionLock); 536 | // } 537 | 538 | //Logger::writeLog("Waiting on task completion.\n",gSystemLogFile); 539 | sem_wait(&(obj->taskCompletion)); 540 | 541 | pthread_mutex_lock(&freeListUpdateLock); 542 | 543 | // print the contents of threadQ 544 | 545 | writeLog("Available thread details:\n",gSystemLogFile); 546 | char mssg[5000]; 547 | for(Node* n=obj->avaliableThreads->mHead;n!=NULL;n=n->next) 548 | { 549 | WorkerThread *w=(WorkerThread*)(n->data); 550 | sprintf(mssg,"%s%d---->",mssg,w->threadId); 551 | } 552 | sprintf(mssg,"%s\n",mssg); 553 | writeLog(mssg,gSystemLogFile); 554 | // end pf logging 555 | 556 | n=deQueue(obj->avaliableThreads); 557 | WorkerThread* worker=NULL; 558 | if(n!=NULL) 559 | { 560 | //worker=(WorkerThread*)malloc(sizeof(WorkerThread)); 561 | //memcpy(worker,n->data,sizeof(WorkerThread)); 562 | worker=(WorkerThread*)(n->data); 563 | n->data=NULL; 564 | n->next=NULL; 565 | free(n); 566 | n=NULL; 567 | } 568 | 569 | //WorkerThread* worker=(WorkerThread*)(deQueue(obj->avaliableThreads)->data); 570 | assignTask(worker,t); 571 | 572 | sprintf(mssg,"Assigning task:%s--->%lld to thread id:%d\n\n",t->fileName,t->fileSize,worker->threadId); 573 | writeLog(mssg,gSystemLogFile); 574 | 575 | pthread_mutex_unlock(&freeListUpdateLock); 576 | //pthread_mutex_unlock(&taskAssignmentLock[worker->threadId]); 577 | sem_post(&(obj->taskAssignment[worker->threadId])); 578 | } 579 | } 580 | 581 | void taskDidComplete(WorkerThread* ptr , CustomThreadPool* pool) // called on worker thread 582 | { 583 | pthread_mutex_lock(&freeListUpdateLock); 584 | free(ptr->task); 585 | ptr->task=NULL; 586 | enQueue(pool->avaliableThreads,ptr); 587 | pthread_mutex_unlock(&freeListUpdateLock); 588 | } 589 | 590 | 591 | void displayHelp() 592 | { 593 | int fd=open("Help",O_RDONLY); 594 | char buffer[2000]; 595 | int n=read(fd,buffer,2000); 596 | buffer[n]=0; 597 | printf("%s",buffer); 598 | close(fd); 599 | } 600 | 601 | void parseShellArguments(int argc,char *argv[]) 602 | { 603 | int index=1; 604 | try 605 | { 606 | while(indextm_mday,gmTime->tm_mon,(gmTime->tm_year+1900),gmTime->tm_hour,gmTime->tm_min,gmTime->tm_sec); 686 | return gmtTime; 687 | } 688 | 689 | 690 | long long int getFileSize(char* fileName) 691 | { 692 | //change to add further errorhandling otpions 693 | struct stat fileDetails; 694 | int rValue=stat(fileName,&fileDetails); 695 | return (rValue==0)?fileDetails.st_size:0; 696 | } 697 | 698 | char *replaceTildeInPath(char* path) 699 | { 700 | if(path[0]=='/'&&path[1]=='~') // valid case 701 | { 702 | path+=2; 703 | char username[32]; 704 | int index=0; 705 | while(*path!='/') 706 | { 707 | username[index]=*path; 708 | index++; 709 | path++; 710 | } 711 | username[index]=0; 712 | char newPath[100]; 713 | sprintf(newPath,"/home/%s/myhttpd%s",username,path); 714 | return newPath; 715 | } 716 | else 717 | return path; 718 | } 719 | 720 | char* getLocalIP() 721 | { 722 | SocketAddressInfo *socketAddress; // this structure basically stores info about the socket address 723 | socketAddress=(SocketAddressInfo*)malloc(sizeof(SocketAddressInfo)); 724 | socketAddress->sin_family=AF_INET; 725 | socketAddress->sin_port=htons(53); 726 | inet_pton(socketAddress->sin_family,"8.8.8.8",&(socketAddress->sin_addr)); 727 | 728 | //create a socket for connecting to server 729 | int socketId=socket(AF_INET,SOCK_DGRAM,0); 730 | if(socketId==-1) 731 | { 732 | printf("Error in creating socket"); 733 | return ""; 734 | } 735 | int retConnect=connect(socketId,(struct sockaddr*)socketAddress,sizeof(SocketAddressInfo)); 736 | if(retConnect<0) 737 | { 738 | printf("connection with peer failed with error : %d",retConnect); 739 | return ""; 740 | } 741 | 742 | SocketAddressInfo localAddressInfo; 743 | socklen_t len=sizeof(localAddressInfo); 744 | getsockname(socketId,(struct sockaddr*)&localAddressInfo,&len); 745 | char buffer[32]; 746 | inet_ntop(AF_INET,&localAddressInfo.sin_addr,buffer,sizeof(buffer)); 747 | return buffer; 748 | } 749 | 750 | 751 | static void* handleSocketBehaviour(void* pool) 752 | { 753 | //printf("Waiting for incoming requests.\n"); 754 | writeLog("Waiting for incoming requests.\n",gSystemLogFile); 755 | while(1) 756 | { 757 | SocketAddressInfo peerInfo; 758 | socklen_t addrSize=(socklen_t)sizeof(peerInfo); 759 | int confd=accept(gListeningSocketId,(struct sockaddr*)&peerInfo,&addrSize); 760 | getpeername(confd,(struct sockaddr*)&peerInfo,&addrSize); 761 | char clientIP[32]; 762 | strcpy(clientIP,inet_ntoa(peerInfo.sin_addr)); 763 | char request[5002]; 764 | read(confd,&request,5000); 765 | //printf("%s",request); 766 | //fflush(stdout); 767 | char *reqType;//=(char*)malloc(5); 768 | char* path;//=(char*)malloc(5000); 769 | 770 | // Generate the task from the request info 771 | Task* newTask=(Task*)malloc(sizeof(Task)); 772 | 773 | //Patch logic to fetch the frst line and store in newTask->request 774 | int i=0; 775 | while(1) 776 | { 777 | if(request[i]=='\n') 778 | break; 779 | newTask->request[i]=request[i]; 780 | i++; 781 | } 782 | newTask->request[i-1]=0; 783 | 784 | 785 | //sprintf(newTask->request,"%s",request); 786 | //strcpy(newTask->request,request); 787 | parseHTTPRequest(request,&reqType,&path); 788 | if(path==NULL) 789 | continue; 790 | 791 | if(!strcmp(reqType,"GET")) 792 | { 793 | char fullPath[5000]; 794 | strcpy(fullPath,gDirectoryRoot); 795 | if(path) // for HEAD request 796 | sprintf(fullPath,"%s%s",fullPath,replaceTildeInPath(path)); 797 | long long int fileSize=getFileSize(fullPath); 798 | //if(fileSize>0) 799 | //{ 800 | strcpy(newTask->fileName,fullPath); 801 | newTask->fileSize=fileSize; 802 | newTask->requestingConnectionId=confd; 803 | //strcpy(newTask->request,request); 804 | strcpy(newTask->remoteIP,clientIP); 805 | strcpy(newTask->queingTime,getCurrentGMTTime()); 806 | strcpy(newTask->reqType,"GET"); 807 | //} 808 | //change handle for errors 809 | 810 | } 811 | else if(!strcmp(reqType,"HEAD")) 812 | { 813 | 814 | char fullPath[5000]; 815 | strcpy(fullPath,gDirectoryRoot); 816 | if(path) // for HEAD request 817 | sprintf(fullPath,"%s%s",fullPath,replaceTildeInPath(path)); 818 | 819 | strcpy(newTask->fileName,fullPath); 820 | newTask->fileSize=0; 821 | newTask->requestingConnectionId=confd; 822 | strcpy(newTask->remoteIP,clientIP); 823 | strcpy(newTask->queingTime,getCurrentGMTTime()); 824 | strcpy(newTask->reqType,"HEAD"); 825 | 826 | } 827 | //sync 828 | if(gRunInDebug) 829 | executeTask(newTask); 830 | else 831 | addTask((CustomThreadPool*)pool,newTask); 832 | //executeTask(newTask); 833 | //free(reqType); 834 | //free(path); 835 | } 836 | 837 | } 838 | 839 | void openSocket() 840 | { 841 | char destIP[32]; 842 | strcpy(destIP,getLocalIP()); 843 | //int mainSocket; 844 | // defining the address for the main socket 845 | SocketAddressInfo *socketAddress; // this structure basically stores info about the socket address 846 | socketAddress=(SocketAddressInfo*)malloc(sizeof(SocketAddressInfo)); 847 | socketAddress->sin_family=AF_INET; 848 | socketAddress->sin_addr.s_addr=htons(INADDR_ANY); 849 | //inet_pton(socketAddress->sin_family,destIP,&(socketAddress->sin_addr)); 850 | socketAddress->sin_port=htons(gListeningPort); 851 | 852 | //create a socket for accepting incoming connections 853 | gListeningSocketId=socket(AF_INET,SOCK_STREAM,0); 854 | if(gListeningSocketId==-1) 855 | { 856 | printf("Error in creating socket"); 857 | exit(0); 858 | } 859 | // bind the spcket to the addressinfo 860 | if(bind(gListeningSocketId,(struct sockaddr*)socketAddress,sizeof(SocketAddressInfo))==-1) 861 | { 862 | printf("%d",errno); 863 | printf("Error in binding socket IP address"); 864 | exit(0); 865 | } 866 | 867 | // listen for incoming connections 868 | if(listen(gListeningSocketId,100)==-1) 869 | { 870 | printf("Error in listening"); 871 | exit(0); 872 | } 873 | } 874 | 875 | int main(int argc,char *argv[]) 876 | { 877 | 878 | getcwd(gDirectoryRoot,1024); 879 | parseShellArguments(argc,argv); 880 | 881 | remove(gUserLogFile); 882 | remove(gSystemLogFile); 883 | openSocket(); 884 | if(gRunInDebug) 885 | { 886 | handleSocketBehaviour(NULL); 887 | exit(0); 888 | } 889 | else 890 | { 891 | pid_t pid; 892 | 893 | pid = fork(); 894 | if(pid<0) 895 | exit(EXIT_FAILURE); 896 | 897 | if(pid>0) // kill the parent process 898 | exit(0); 899 | else 900 | { 901 | close(STDIN_FILENO); 902 | close(STDOUT_FILENO); 903 | close(STDERR_FILENO); 904 | } 905 | 906 | } 907 | 908 | 909 | 910 | pthread_t queuingThread,schedulingThread; 911 | static CustomThreadPool* threadPool=initializeThreadPool(gNumberOfThreads,(strcmp(gSchedulingAlgo,"FCFS")==0?0:1)); 912 | //CustomThreadPool threadPool(gNumberOfThreads,(strcmp(gSchedulingAlgo,"FCFS")==0?0:1)); 913 | pthread_create(&queuingThread,NULL,&handleSocketBehaviour,threadPool); 914 | pthread_create(&schedulingThread,NULL,&scheduler,threadPool); 915 | //printf("thread id:%u",schedulingThread); 916 | 917 | //void* val1,*val2; 918 | //while(1) 919 | 920 | pthread_join(queuingThread,NULL); 921 | pthread_join(schedulingThread,NULL); 922 | 923 | } 924 | --------------------------------------------------------------------------------