├── Makefile ├── README.md ├── pics ├── UML.JPG └── cache.png ├── proxy_parse.c ├── proxy_parse.h ├── proxy_server_with_cache.c └── proxy_server_without_cache.c /Makefile: -------------------------------------------------------------------------------- 1 | CC=g++ 2 | CFLAGS= -g -Wall 3 | 4 | all: proxy 5 | 6 | proxy: proxy_server_with_cache.c 7 | $(CC) $(CFLAGS) -o proxy_parse.o -c proxy_parse.c -lpthread 8 | $(CC) $(CFLAGS) -o proxy.o -c proxy_server_with_cache.c -lpthread 9 | $(CC) $(CFLAGS) -o proxy proxy_parse.o proxy.o -lpthread 10 | 11 | clean: 12 | rm -f proxy *.o 13 | 14 | tar: 15 | tar -cvzf ass1.tgz proxy_server_with_cache.c README Makefile proxy_parse.c proxy_parse.h 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Multi Threaded Proxy Server with and without Cache

2 | 3 | This project is implemented using `C` and Parsing of HTTP referred from Proxy Server 4 | 5 | 6 | ## Index 7 | 8 | - [Project Theory](https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient#project-theory) 9 | - [How to Run](https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient#How-to-Run) 10 | - [Demo](https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient#Demo) 11 | - [Contributing](https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient#contributing) 12 | 13 | ## Project Theory 14 | 15 | [[Back to top]](https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient#index) 16 | 17 | ##### Introduction 18 | 19 | ##### Basic Working Flow of the Proxy Server: 20 | ![](https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient/blob/main/pics/UML.JPG) 21 | 22 | ##### How did we implement Multi-threading? 23 | - Used Semaphore instead of Condition Variables and pthread_join() and pthread_exit() function. 24 | - pthread_join() requires us to pass the thread id of the the thread to wait for. 25 | - Semaphore’s sem_wait() and sem_post() doesn’t need any parameter. So it is a better option. 26 | 27 | 28 | ##### Motivation/Need of Project 29 | - To Understand → 30 | - The working of requests from our local computer to the server. 31 | - The handling of multiple client requests from various clients. 32 | - Locking procedure for concurrency. 33 | - The concept of cache and its different functions that might be used by browsers. 34 | - Proxy Server do → 35 | - It speeds up the process and reduces the traffic on the server side. 36 | - It can be used to restrict user from accessing specific websites. 37 | - A good proxy will change the IP such that the server wouldn’t know about the client who sent the request. 38 | - Changes can be made in Proxy to encrypt the requests, to stop anyone accessing the request illegally from your client. 39 | 40 | ##### OS Component Used ​ 41 | - Threading 42 | - Locks 43 | - Semaphore 44 | - Cache (LRU algorithm is used in it) 45 | 46 | ##### Limitations ​ 47 | - If a URL opens multiple clients itself, then our cache will store each client’s response as a separate element in the linked list. So, during retrieval from the cache, only a chunk of response will be send and the website will not open 48 | - Fixed size of cache element, so big websites may not be stored in cache. 49 | 50 | ##### How this project can be extended? ​ 51 | - This code can be implemented using multiprocessing that can speed up the process with parallelism. 52 | - We can decide which type of websites should be allowed by extending the code. 53 | - We can implement requests like POST with this code. 54 | 55 | 56 | # Note :- 57 | - Code is well commented. For any doubt you can refer to the comments. 58 | 59 | 60 | ## How to Run 61 | 62 | ```bash 63 | $ git clone https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient.git 64 | $ cd MultiThreadedProxyServerClient 65 | $ make all 66 | $ ./proxy 67 | ``` 68 | `Open http://localhost:port/https://www.cs.princeton.edu/` 69 | 70 | # Note: 71 | - This code can only be run in Linux Machine. Please disable your browser cache. 72 | - To run the proxy without cache Change the name of the file (`proxy_server_with_cache.c to proxy_server_without_cache.c`) MakeFile. 73 | 74 | ## Demo 75 | ![](https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient/blob/main/pics/cache.png) 76 | - When website is opened for the first time (`url not found`) then cache will be miss. 77 | - Then if you again open that website again then `Data is retrieved from the cache` will be printed. 78 | 79 | ## Contributing 80 | 81 | [[Back to top]](https://github.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient#index) 82 | 83 | Feel free to add some useful. You can see `How this code can be extended`. Use ideas from there and feel free to fork and CHANGE. 84 | 85 | #### Enjoy CODE and pull requests are highly appreciated. 86 | -------------------------------------------------------------------------------- /pics/UML.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient/6d46097a01a11dd672795bb9381612ea3bbcdb01/pics/UML.JPG -------------------------------------------------------------------------------- /pics/cache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lovepreet-Singh-LPSK/MultiThreadedProxyServerClient/6d46097a01a11dd672795bb9381612ea3bbcdb01/pics/cache.png -------------------------------------------------------------------------------- /proxy_parse.c: -------------------------------------------------------------------------------- 1 | /* 2 | proxy_parse.c -- a HTTP Request Parsing Library. 3 | COS 461 4 | */ 5 | 6 | #include "proxy_parse.h" 7 | 8 | #define DEFAULT_NHDRS 8 9 | #define MAX_REQ_LEN 65535 10 | #define MIN_REQ_LEN 4 11 | 12 | static const char *root_abs_path = "/"; 13 | 14 | /* private function declartions */ 15 | int ParsedRequest_printRequestLine(struct ParsedRequest *pr, 16 | char * buf, size_t buflen, 17 | size_t *tmp); 18 | size_t ParsedRequest_requestLineLen(struct ParsedRequest *pr); 19 | 20 | /* 21 | * debug() prints out debugging info if DEBUG is set to 1 22 | * 23 | * parameter format: same as printf 24 | * 25 | */ 26 | void debug(const char * format, ...) { 27 | va_list args; 28 | if (DEBUG) { 29 | va_start(args, format); 30 | vfprintf(stderr, format, args); 31 | va_end(args); 32 | } 33 | } 34 | 35 | 36 | /* 37 | * ParsedHeader Public Methods 38 | */ 39 | 40 | /* Set a header with key and value */ 41 | int ParsedHeader_set(struct ParsedRequest *pr, 42 | const char * key, const char * value) 43 | { 44 | struct ParsedHeader *ph; 45 | ParsedHeader_remove (pr, key); 46 | 47 | if (pr->headerslen <= pr->headersused+1) { 48 | pr->headerslen = pr->headerslen * 2; 49 | pr->headers = 50 | (struct ParsedHeader *)realloc(pr->headers, 51 | pr->headerslen * sizeof(struct ParsedHeader)); 52 | if (!pr->headers) 53 | return -1; 54 | } 55 | 56 | ph = pr->headers + pr->headersused; 57 | pr->headersused += 1; 58 | 59 | ph->key = (char *)malloc(strlen(key)+1); 60 | memcpy(ph->key, key, strlen(key)); 61 | ph->key[strlen(key)] = '\0'; 62 | 63 | ph->value = (char *)malloc(strlen(value)+1); 64 | memcpy(ph->value, value, strlen(value)); 65 | ph->value[strlen(value)] = '\0'; 66 | 67 | ph->keylen = strlen(key)+1; 68 | ph->valuelen = strlen(value)+1; 69 | return 0; 70 | } 71 | 72 | 73 | /* get the parsedHeader with the specified key or NULL */ 74 | struct ParsedHeader* ParsedHeader_get(struct ParsedRequest *pr, 75 | const char * key) 76 | { 77 | size_t i = 0; 78 | struct ParsedHeader * tmp; 79 | while(pr->headersused > i) 80 | { 81 | tmp = pr->headers + i; 82 | if(tmp->key && key && strcmp(tmp->key, key) == 0) 83 | { 84 | return tmp; 85 | } 86 | i++; 87 | } 88 | return NULL; 89 | } 90 | 91 | /* remove the specified key from parsedHeader */ 92 | int ParsedHeader_remove(struct ParsedRequest *pr, const char *key) 93 | { 94 | struct ParsedHeader *tmp; 95 | tmp = ParsedHeader_get(pr, key); 96 | if(tmp == NULL) 97 | return -1; 98 | 99 | free(tmp->key); 100 | free(tmp->value); 101 | tmp->key = NULL; 102 | return 0; 103 | } 104 | 105 | 106 | /* modify the header with given key, giving it a new value 107 | * return 1 on success and 0 if no such header found 108 | * 109 | int ParsedHeader_modify(struct ParsedRequest *pr, const char * key, 110 | const char *newValue) 111 | { 112 | struct ParsedHeader *tmp; 113 | tmp = ParsedHeader_get(pr, key); 114 | if(tmp != NULL) 115 | { 116 | if(tmp->valuelen < strlen(newValue)+1) 117 | { 118 | tmp->valuelen = strlen(newValue)+1; 119 | tmp->value = (char *) realloc(tmp->value, 120 | tmp->valuelen * sizeof(char)); 121 | } 122 | strcpy(tmp->value, newValue); 123 | return 1; 124 | } 125 | return 0; 126 | } 127 | */ 128 | 129 | /* 130 | ParsedHeader Private Methods 131 | */ 132 | 133 | void ParsedHeader_create(struct ParsedRequest *pr) 134 | { 135 | pr->headers = 136 | (struct ParsedHeader *)malloc(sizeof(struct ParsedHeader)*DEFAULT_NHDRS); 137 | pr->headerslen = DEFAULT_NHDRS; 138 | pr->headersused = 0; 139 | } 140 | 141 | 142 | size_t ParsedHeader_lineLen(struct ParsedHeader * ph) 143 | { 144 | if(ph->key != NULL) 145 | { 146 | return strlen(ph->key)+strlen(ph->value)+4; 147 | } 148 | return 0; 149 | } 150 | 151 | size_t ParsedHeader_headersLen(struct ParsedRequest *pr) 152 | { 153 | if (!pr || !pr->buf) 154 | return 0; 155 | 156 | size_t i = 0; 157 | int len = 0; 158 | while(pr->headersused > i) 159 | { 160 | len += ParsedHeader_lineLen(pr->headers + i); 161 | i++; 162 | } 163 | len += 2; 164 | return len; 165 | } 166 | 167 | int ParsedHeader_printHeaders(struct ParsedRequest * pr, char * buf, 168 | size_t len) 169 | { 170 | char * current = buf; 171 | struct ParsedHeader * ph; 172 | size_t i = 0; 173 | 174 | if(len < ParsedHeader_headersLen(pr)) 175 | { 176 | debug("buffer for printing headers too small\n"); 177 | return -1; 178 | } 179 | 180 | while(pr->headersused > i) 181 | { 182 | ph = pr->headers+i; 183 | if (ph->key) { 184 | memcpy(current, ph->key, strlen(ph->key)); 185 | memcpy(current+strlen(ph->key), ": ", 2); 186 | memcpy(current+strlen(ph->key) +2 , ph->value, 187 | strlen(ph->value)); 188 | memcpy(current+strlen(ph->key) +2+strlen(ph->value) , 189 | "\r\n", 2); 190 | current += strlen(ph->key)+strlen(ph->value)+4; 191 | } 192 | i++; 193 | } 194 | memcpy(current, "\r\n",2); 195 | return 0; 196 | } 197 | 198 | 199 | void ParsedHeader_destroyOne(struct ParsedHeader * ph) 200 | { 201 | if(ph->key != NULL) 202 | { 203 | free(ph->key); 204 | ph->key = NULL; 205 | free(ph->value); 206 | ph->value = NULL; 207 | ph->keylen = 0; 208 | ph->valuelen = 0; 209 | } 210 | } 211 | 212 | void ParsedHeader_destroy(struct ParsedRequest * pr) 213 | { 214 | size_t i = 0; 215 | while(pr->headersused > i) 216 | { 217 | ParsedHeader_destroyOne(pr->headers + i); 218 | i++; 219 | } 220 | pr->headersused = 0; 221 | 222 | free(pr->headers); 223 | pr->headerslen = 0; 224 | } 225 | 226 | 227 | int ParsedHeader_parse(struct ParsedRequest * pr, char * line) 228 | { 229 | char * key; 230 | char * value; 231 | char * index1; 232 | char * index2; 233 | 234 | index1 = index(line, ':'); 235 | if(index1 == NULL) 236 | { 237 | debug("No colon found\n"); 238 | return -1; 239 | } 240 | key = (char *)malloc((index1-line+1)*sizeof(char)); 241 | memcpy(key, line, index1-line); 242 | key[index1-line]='\0'; 243 | 244 | index1 += 2; 245 | index2 = strstr(index1, "\r\n"); 246 | value = (char *) malloc((index2-index1+1)*sizeof(char)); 247 | memcpy(value, index1, (index2-index1)); 248 | value[index2-index1] = '\0'; 249 | 250 | ParsedHeader_set(pr, key, value); 251 | free(key); 252 | free(value); 253 | return 0; 254 | } 255 | 256 | /* 257 | ParsedRequest Public Methods 258 | */ 259 | 260 | void ParsedRequest_destroy(struct ParsedRequest *pr) 261 | { 262 | if(pr->buf != NULL) 263 | { 264 | free(pr->buf); 265 | } 266 | if (pr->path != NULL) { 267 | free(pr->path); 268 | } 269 | if(pr->headerslen > 0) 270 | { 271 | ParsedHeader_destroy(pr); 272 | } 273 | free(pr); 274 | } 275 | 276 | struct ParsedRequest* ParsedRequest_create() 277 | { 278 | struct ParsedRequest *pr; 279 | pr = (struct ParsedRequest *)malloc(sizeof(struct ParsedRequest)); 280 | if (pr != NULL) 281 | { 282 | ParsedHeader_create(pr); 283 | pr->buf = NULL; 284 | pr->method = NULL; 285 | pr->protocol = NULL; 286 | pr->host = NULL; 287 | pr->path = NULL; 288 | pr->version = NULL; 289 | pr->buf = NULL; 290 | pr->buflen = 0; 291 | } 292 | return pr; 293 | } 294 | 295 | /* 296 | Recreate the entire buffer from a parsed request object. 297 | buf must be allocated 298 | */ 299 | int ParsedRequest_unparse(struct ParsedRequest *pr, char *buf, 300 | size_t buflen) 301 | { 302 | if (!pr || !pr->buf) 303 | return -1; 304 | 305 | size_t tmp; 306 | if (ParsedRequest_printRequestLine(pr, buf, buflen, &tmp) < 0) 307 | return -1; 308 | if (ParsedHeader_printHeaders(pr, buf+tmp, buflen-tmp) < 0) 309 | return -1; 310 | return 0; 311 | } 312 | 313 | /* 314 | Recreate the headers from a parsed request object. 315 | buf must be allocated 316 | */ 317 | int ParsedRequest_unparse_headers(struct ParsedRequest *pr, char *buf, 318 | size_t buflen) 319 | { 320 | if (!pr || !pr->buf) 321 | return -1; 322 | 323 | if (ParsedHeader_printHeaders(pr, buf, buflen) < 0) 324 | return -1; 325 | return 0; 326 | } 327 | 328 | 329 | /* Size of the headers if unparsed into a string */ 330 | size_t ParsedRequest_totalLen(struct ParsedRequest *pr) 331 | { 332 | if (!pr || !pr->buf) 333 | return 0; 334 | return ParsedRequest_requestLineLen(pr)+ParsedHeader_headersLen(pr); 335 | } 336 | 337 | 338 | /* 339 | Parse request buffer 340 | 341 | Parameters: 342 | parse: ptr to a newly created ParsedRequest object 343 | buf: ptr to the buffer containing the request (need not be NUL terminated) 344 | and the trailing \r\n\r\n 345 | buflen: length of the buffer including the trailing \r\n\r\n 346 | 347 | Return values: 348 | -1: failure 349 | 0: success 350 | */ 351 | int 352 | ParsedRequest_parse(struct ParsedRequest * parse, const char *buf, 353 | int buflen) 354 | { 355 | char *full_addr; 356 | char *saveptr; 357 | char *index; 358 | char *currentHeader; 359 | 360 | if (parse->buf != NULL) { 361 | debug("parse object already assigned to a request\n"); 362 | return -1; 363 | } 364 | 365 | if (buflen < MIN_REQ_LEN || buflen > MAX_REQ_LEN) { 366 | debug("invalid buflen %d", buflen); 367 | return -1; 368 | } 369 | 370 | /* Create NUL terminated tmp buffer */ 371 | char *tmp_buf = (char *)malloc(buflen + 1); /* including NUL */ 372 | memcpy(tmp_buf, buf, buflen); 373 | tmp_buf[buflen] = '\0'; 374 | 375 | index = strstr(tmp_buf, "\r\n\r\n"); 376 | if (index == NULL) { 377 | debug("invalid request line, no end of header\n"); 378 | free(tmp_buf); 379 | return -1; 380 | } 381 | 382 | /* Copy request line into parse->buf */ 383 | index = strstr(tmp_buf, "\r\n"); 384 | if (parse->buf == NULL) { 385 | parse->buf = (char *) malloc((index-tmp_buf)+1); 386 | parse->buflen = (index-tmp_buf)+1; 387 | } 388 | memcpy(parse->buf, tmp_buf, index-tmp_buf); 389 | parse->buf[index-tmp_buf] = '\0'; 390 | 391 | /* Parse request line */ 392 | parse->method = strtok_r(parse->buf, " ", &saveptr); 393 | if (parse->method == NULL) { 394 | debug( "invalid request line, no whitespace\n"); 395 | free(tmp_buf); 396 | free(parse->buf); 397 | parse->buf = NULL; 398 | return -1; 399 | } 400 | if (strcmp (parse->method, "GET")) { 401 | debug( "invalid request line, method not 'GET': %s\n", 402 | parse->method); 403 | free(tmp_buf); 404 | free(parse->buf); 405 | parse->buf = NULL; 406 | return -1; 407 | } 408 | 409 | full_addr = strtok_r(NULL, " ", &saveptr); 410 | 411 | if (full_addr == NULL) { 412 | debug( "invalid request line, no full address\n"); 413 | free(tmp_buf); 414 | free(parse->buf); 415 | parse->buf = NULL; 416 | return -1; 417 | } 418 | 419 | parse->version = full_addr + strlen(full_addr) + 1; 420 | 421 | if (parse->version == NULL) { 422 | debug( "invalid request line, missing version\n"); 423 | free(tmp_buf); 424 | free(parse->buf); 425 | parse->buf = NULL; 426 | return -1; 427 | } 428 | if (strncmp (parse->version, "HTTP/", 5)) { 429 | debug( "invalid request line, unsupported version %s\n", 430 | parse->version); 431 | free(tmp_buf); 432 | free(parse->buf); 433 | parse->buf = NULL; 434 | return -1; 435 | } 436 | 437 | 438 | parse->protocol = strtok_r(full_addr, "://", &saveptr); 439 | if (parse->protocol == NULL) { 440 | debug( "invalid request line, missing host\n"); 441 | free(tmp_buf); 442 | free(parse->buf); 443 | parse->buf = NULL; 444 | return -1; 445 | } 446 | 447 | const char *rem = full_addr + strlen(parse->protocol) + strlen("://"); 448 | size_t abs_uri_len = strlen(rem); 449 | 450 | parse->host = strtok_r(NULL, "/", &saveptr); 451 | if (parse->host == NULL) { 452 | debug( "invalid request line, missing host\n"); 453 | free(tmp_buf); 454 | free(parse->buf); 455 | parse->buf = NULL; 456 | return -1; 457 | } 458 | 459 | if (strlen(parse->host) == abs_uri_len) { 460 | debug("invalid request line, missing absolute path\n"); 461 | free(tmp_buf); 462 | free(parse->buf); 463 | parse->buf = NULL; 464 | return -1; 465 | } 466 | 467 | parse->path = strtok_r(NULL, " ", &saveptr); 468 | if (parse->path == NULL) { // replace empty abs_path with "/" 469 | int rlen = strlen(root_abs_path); 470 | parse->path = (char *)malloc(rlen + 1); 471 | strncpy(parse->path, root_abs_path, rlen + 1); 472 | } else if (strncmp(parse->path, root_abs_path, strlen(root_abs_path)) == 0) { 473 | debug("invalid request line, path cannot begin " 474 | "with two slash characters\n"); 475 | free(tmp_buf); 476 | free(parse->buf); 477 | parse->buf = NULL; 478 | parse->path = NULL; 479 | return -1; 480 | } else { 481 | // copy parse->path, prefix with a slash 482 | char *tmp_path = parse->path; 483 | int rlen = strlen(root_abs_path); 484 | int plen = strlen(parse->path); 485 | parse->path = (char *)malloc(rlen + plen + 1); 486 | strncpy(parse->path, root_abs_path, rlen); 487 | strncpy(parse->path + rlen, tmp_path, plen + 1); 488 | } 489 | 490 | parse->host = strtok_r(parse->host, ":", &saveptr); 491 | parse->port = strtok_r(NULL, "/", &saveptr); 492 | 493 | if (parse->host == NULL) { 494 | debug( "invalid request line, missing host\n"); 495 | free(tmp_buf); 496 | free(parse->buf); 497 | free(parse->path); 498 | parse->buf = NULL; 499 | parse->path = NULL; 500 | return -1; 501 | } 502 | 503 | if (parse->port != NULL) { 504 | int port = strtol (parse->port, (char **)NULL, 10); 505 | if (port == 0 && errno == EINVAL) { 506 | debug("invalid request line, bad port: %s\n", parse->port); 507 | free(tmp_buf); 508 | free(parse->buf); 509 | free(parse->path); 510 | parse->buf = NULL; 511 | parse->path = NULL; 512 | return -1; 513 | } 514 | } 515 | 516 | 517 | /* Parse headers */ 518 | int ret = 0; 519 | currentHeader = strstr(tmp_buf, "\r\n")+2; 520 | while (currentHeader[0] != '\0' && 521 | !(currentHeader[0] == '\r' && currentHeader[1] == '\n')) { 522 | 523 | //debug("line %s %s", parse->version, currentHeader); 524 | 525 | if (ParsedHeader_parse(parse, currentHeader)) { 526 | ret = -1; 527 | break; 528 | } 529 | 530 | currentHeader = strstr(currentHeader, "\r\n"); 531 | if (currentHeader == NULL || strlen (currentHeader) < 2) 532 | break; 533 | 534 | currentHeader += 2; 535 | } 536 | free(tmp_buf); 537 | return ret; 538 | } 539 | 540 | /* 541 | ParsedRequest Private Methods 542 | */ 543 | 544 | size_t ParsedRequest_requestLineLen(struct ParsedRequest *pr) 545 | { 546 | if (!pr || !pr->buf) 547 | return 0; 548 | 549 | size_t len = 550 | strlen(pr->method) + 1 + strlen(pr->protocol) + 3 + 551 | strlen(pr->host) + 1 + strlen(pr->version) + 2; 552 | if(pr->port != NULL) 553 | { 554 | len += strlen(pr->port)+1; 555 | } 556 | /* path is at least a slash */ 557 | len += strlen(pr->path); 558 | return len; 559 | } 560 | 561 | int ParsedRequest_printRequestLine(struct ParsedRequest *pr, 562 | char * buf, size_t buflen, 563 | size_t *tmp) 564 | { 565 | char * current = buf; 566 | 567 | if(buflen < ParsedRequest_requestLineLen(pr)) 568 | { 569 | debug("not enough memory for first line\n"); 570 | return -1; 571 | } 572 | memcpy(current, pr->method, strlen(pr->method)); 573 | current += strlen(pr->method); 574 | current[0] = ' '; 575 | current += 1; 576 | 577 | memcpy(current, pr->protocol, strlen(pr->protocol)); 578 | current += strlen(pr->protocol); 579 | memcpy(current, "://", 3); 580 | current += 3; 581 | memcpy(current, pr->host, strlen(pr->host)); 582 | current += strlen(pr->host); 583 | if(pr->port != NULL) 584 | { 585 | current[0] = ':'; 586 | current += 1; 587 | memcpy(current, pr->port, strlen(pr->port)); 588 | current += strlen(pr->port); 589 | } 590 | /* path is at least a slash */ 591 | memcpy(current, pr->path, strlen(pr->path)); 592 | current += strlen(pr->path); 593 | 594 | current[0] = ' '; 595 | current += 1; 596 | 597 | memcpy(current, pr->version, strlen(pr->version)); 598 | current += strlen(pr->version); 599 | memcpy(current, "\r\n", 2); 600 | current +=2; 601 | *tmp = current-buf; 602 | return 0; 603 | } 604 | 605 | -------------------------------------------------------------------------------- /proxy_parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * proxy_parse.h -- a HTTP Request Parsing Library. 3 | * 4 | * Written by: Matvey Arye 5 | * For: COS 518 6 | * 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #ifndef PROXY_PARSE 18 | #define PROXY_PARSE 19 | 20 | #define DEBUG 1 21 | 22 | /* 23 | ParsedRequest objects are created from parsing a buffer containing a HTTP 24 | request. The request buffer consists of a request line followed by a number 25 | of headers. Request line fields such as method, protocol etc. are stored 26 | explicitly. Headers such as 'Content-Length' and their values are maintained 27 | in a linked list. Each node in this list is a ParsedHeader and contains a 28 | key-value pair. 29 | 30 | The buf and buflen fields are used internally to maintain the parsed request 31 | line. 32 | */ 33 | struct ParsedRequest { 34 | char *method; 35 | char *protocol; 36 | char *host; 37 | char *port; 38 | char *path; 39 | char *version; 40 | char *buf; 41 | size_t buflen; 42 | struct ParsedHeader *headers; 43 | size_t headersused; 44 | size_t headerslen; 45 | }; 46 | 47 | /* 48 | ParsedHeader: any header after the request line is a key-value pair with the 49 | format "key:value\r\n" and is maintained in the ParsedHeader linked list 50 | within ParsedRequest 51 | */ 52 | struct ParsedHeader { 53 | char * key; 54 | size_t keylen; 55 | char * value; 56 | size_t valuelen; 57 | }; 58 | 59 | 60 | /* Create an empty parsing object to be used exactly once for parsing a single 61 | * request buffer */ 62 | struct ParsedRequest* ParsedRequest_create(); 63 | 64 | /* Parse the request buffer in buf given that buf is of length buflen */ 65 | int ParsedRequest_parse(struct ParsedRequest * parse, const char *buf, 66 | int buflen); 67 | 68 | /* Destroy the parsing object. */ 69 | void ParsedRequest_destroy(struct ParsedRequest *pr); 70 | 71 | /* 72 | Retrieve the entire buffer from a parsed request object. buf must be an 73 | allocated buffer of size buflen, with enough space to write the request 74 | line, headers and the trailing \r\n. buf will not be NUL terminated by 75 | unparse(). 76 | */ 77 | int ParsedRequest_unparse(struct ParsedRequest *pr, char *buf, 78 | size_t buflen); 79 | 80 | /* 81 | Retrieve the entire buffer with the exception of request line from a parsed 82 | request object. buf must be an allocated buffer of size buflen, with enough 83 | space to write the headers and the trailing \r\n. buf will not be NUL 84 | terminated by unparse(). If there are no headers, the trailing \r\n is 85 | unparsed. 86 | */ 87 | int ParsedRequest_unparse_headers(struct ParsedRequest *pr, char *buf, 88 | size_t buflen); 89 | 90 | /* Total length including request line, headers and the trailing \r\n*/ 91 | size_t ParsedRequest_totalLen(struct ParsedRequest *pr); 92 | 93 | /* Length including headers, if any, and the trailing \r\n but excluding the 94 | * request line. 95 | */ 96 | size_t ParsedHeader_headersLen(struct ParsedRequest *pr); 97 | 98 | /* Set, get, and remove null-terminated header keys and values */ 99 | int ParsedHeader_set(struct ParsedRequest *pr, const char * key, 100 | const char * value); 101 | struct ParsedHeader* ParsedHeader_get(struct ParsedRequest *pr, 102 | const char * key); 103 | int ParsedHeader_remove (struct ParsedRequest *pr, const char * key); 104 | 105 | /* debug() prints out debugging info if DEBUG is set to 1 */ 106 | void debug(const char * format, ...); 107 | 108 | /* Example usage: 109 | 110 | const char *c = 111 | "GET http://www.google.com:80/index.html/ HTTP/1.0\r\nContent-Length:" 112 | " 80\r\nIf-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT\r\n\r\n"; 113 | 114 | int len = strlen(c); 115 | //Create a ParsedRequest to use. This ParsedRequest 116 | //is dynamically allocated. 117 | ParsedRequest *req = ParsedRequest_create(); 118 | if (ParsedRequest_parse(req, c, len) < 0) { 119 | printf("parse failed\n"); 120 | return -1; 121 | } 122 | 123 | printf("Method:%s\n", req->method); 124 | printf("Host:%s\n", req->host); 125 | 126 | // Turn ParsedRequest into a string. 127 | // Friendly reminder: Be sure that you need to 128 | // dynamically allocate string and if you 129 | // do, remember to free it when you are done. 130 | // (Dynamic allocation wasn't necessary here, 131 | // but it was used as an example.) 132 | int rlen = ParsedRequest_totalLen(req); 133 | char *b = (char *)malloc(rlen+1); 134 | if (ParsedRequest_unparse(req, b, rlen) < 0) { 135 | printf("unparse failed\n"); 136 | return -1; 137 | } 138 | b[rlen]='\0'; 139 | // print out b for text request 140 | free(b); 141 | 142 | 143 | // Turn the headers from the request into a string. 144 | rlen = ParsedHeader_headersLen(req); 145 | char buf[rlen+1]; 146 | if (ParsedRequest_unparse_headers(req, buf, rlen) < 0) { 147 | printf("unparse failed\n"); 148 | return -1; 149 | } 150 | buf[rlen] ='\0'; 151 | //print out buf for text headers only 152 | 153 | // Get a specific header (key) from the headers. A key is a header field 154 | // such as "If-Modified-Since" which is followed by ":" 155 | struct ParsedHeader *r = ParsedHeader_get(req, "If-Modified-Since"); 156 | printf("Modified value: %s\n", r->value); 157 | 158 | // Remove a specific header by name. In this case remove 159 | // the "If-Modified-Since" header. 160 | if (ParsedHeader_remove(req, "If-Modified-Since") < 0){ 161 | printf("remove header key not work\n"); 162 | return -1; 163 | } 164 | 165 | // Set a specific header (key) to a value. In this case, 166 | //we set the "Last-Modified" key to be set to have as 167 | //value a date in February 2014 168 | 169 | if (ParsedHeader_set(req, "Last-Modified", " Wed, 12 Feb 2014 12:43:31 GMT") < 0){ 170 | printf("set header key not work\n"); 171 | return -1; 172 | 173 | } 174 | 175 | // Check the modified Header key value pair 176 | r = ParsedHeader_get(req, "Last-Modified"); 177 | printf("Last-Modified value: %s\n", r->value); 178 | 179 | // Call destroy on any ParsedRequests that you 180 | // create once you are done using them. This will 181 | // free memory dynamically allocated by the proxy_parse library. 182 | ParsedRequest_destroy(req); 183 | */ 184 | 185 | #endif 186 | 187 | -------------------------------------------------------------------------------- /proxy_server_with_cache.c: -------------------------------------------------------------------------------- 1 | #include "proxy_parse.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define MAX_BYTES 4096 //max allowed size of request/response 20 | #define MAX_CLIENTS 400 //max number of client requests served at a time 21 | #define MAX_SIZE 200*(1<<20) //size of the cache 22 | #define MAX_ELEMENT_SIZE 10*(1<<20) //max size of an element in cache 23 | 24 | typedef struct cache_element cache_element; 25 | 26 | struct cache_element{ 27 | char* data; //data stores response 28 | int len; //length of data i.e.. sizeof(data)... 29 | char* url; //url stores the request 30 | time_t lru_time_track; //lru_time_track stores the latest time the element is accesed 31 | cache_element* next; //pointer to next element 32 | }; 33 | 34 | cache_element* find(char* url); 35 | int add_cache_element(char* data,int size,char* url); 36 | void remove_cache_element(); 37 | 38 | int port_number = 8080; // Default Port 39 | int proxy_socketId; // socket descriptor of proxy server 40 | pthread_t tid[MAX_CLIENTS]; //array to store the thread ids of clients 41 | sem_t seamaphore; //if client requests exceeds the max_clients this seamaphore puts the 42 | //waiting threads to sleep and wakes them when traffic on queue decreases 43 | //sem_t cache_lock; 44 | pthread_mutex_t lock; //lock is used for locking the cache 45 | 46 | 47 | cache_element* head; //pointer to the cache 48 | int cache_size; //cache_size denotes the current size of the cache 49 | 50 | int sendErrorMessage(int socket, int status_code) 51 | { 52 | char str[1024]; 53 | char currentTime[50]; 54 | time_t now = time(0); 55 | 56 | struct tm data = *gmtime(&now); 57 | strftime(currentTime,sizeof(currentTime),"%a, %d %b %Y %H:%M:%S %Z", &data); 58 | 59 | switch(status_code) 60 | { 61 | case 400: snprintf(str, sizeof(str), "HTTP/1.1 400 Bad Request\r\nContent-Length: 95\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n400 Bad Request\n

400 Bad Rqeuest

\n", currentTime); 62 | printf("400 Bad Request\n"); 63 | send(socket, str, strlen(str), 0); 64 | break; 65 | 66 | case 403: snprintf(str, sizeof(str), "HTTP/1.1 403 Forbidden\r\nContent-Length: 112\r\nContent-Type: text/html\r\nConnection: keep-alive\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n403 Forbidden\n

403 Forbidden


Permission Denied\n", currentTime); 67 | printf("403 Forbidden\n"); 68 | send(socket, str, strlen(str), 0); 69 | break; 70 | 71 | case 404: snprintf(str, sizeof(str), "HTTP/1.1 404 Not Found\r\nContent-Length: 91\r\nContent-Type: text/html\r\nConnection: keep-alive\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n404 Not Found\n

404 Not Found

\n", currentTime); 72 | printf("404 Not Found\n"); 73 | send(socket, str, strlen(str), 0); 74 | break; 75 | 76 | case 500: snprintf(str, sizeof(str), "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 115\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n500 Internal Server Error\n

500 Internal Server Error

\n", currentTime); 77 | //printf("500 Internal Server Error\n"); 78 | send(socket, str, strlen(str), 0); 79 | break; 80 | 81 | case 501: snprintf(str, sizeof(str), "HTTP/1.1 501 Not Implemented\r\nContent-Length: 103\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n404 Not Implemented\n

501 Not Implemented

\n", currentTime); 82 | printf("501 Not Implemented\n"); 83 | send(socket, str, strlen(str), 0); 84 | break; 85 | 86 | case 505: snprintf(str, sizeof(str), "HTTP/1.1 505 HTTP Version Not Supported\r\nContent-Length: 125\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n505 HTTP Version Not Supported\n

505 HTTP Version Not Supported

\n", currentTime); 87 | printf("505 HTTP Version Not Supported\n"); 88 | send(socket, str, strlen(str), 0); 89 | break; 90 | 91 | default: return -1; 92 | 93 | } 94 | return 1; 95 | } 96 | 97 | int connectRemoteServer(char* host_addr, int port_num) 98 | { 99 | // Creating Socket for remote server --------------------------- 100 | 101 | int remoteSocket = socket(AF_INET, SOCK_STREAM, 0); 102 | 103 | if( remoteSocket < 0) 104 | { 105 | printf("Error in Creating Socket.\n"); 106 | return -1; 107 | } 108 | 109 | // Get host by the name or ip address provided 110 | 111 | struct hostent *host = gethostbyname(host_addr); 112 | if(host == NULL) 113 | { 114 | fprintf(stderr, "No such host exists.\n"); 115 | return -1; 116 | } 117 | 118 | // inserts ip address and port number of host in struct `server_addr` 119 | struct sockaddr_in server_addr; 120 | 121 | bzero((char*)&server_addr, sizeof(server_addr)); 122 | server_addr.sin_family = AF_INET; 123 | server_addr.sin_port = htons(port_num); 124 | 125 | bcopy((char *)host->h_addr,(char *)&server_addr.sin_addr.s_addr,host->h_length); 126 | 127 | // Connect to Remote server ---------------------------------------------------- 128 | 129 | if( connect(remoteSocket, (struct sockaddr*)&server_addr, (socklen_t)sizeof(server_addr)) < 0 ) 130 | { 131 | fprintf(stderr, "Error in connecting !\n"); 132 | return -1; 133 | } 134 | // free(host_addr); 135 | return remoteSocket; 136 | } 137 | 138 | 139 | int handle_request(int clientSocket, ParsedRequest *request, char *tempReq) 140 | { 141 | char *buf = (char*)malloc(sizeof(char)*MAX_BYTES); 142 | strcpy(buf, "GET "); 143 | strcat(buf, request->path); 144 | strcat(buf, " "); 145 | strcat(buf, request->version); 146 | strcat(buf, "\r\n"); 147 | 148 | size_t len = strlen(buf); 149 | 150 | if (ParsedHeader_set(request, "Connection", "close") < 0){ 151 | printf("set header key not work\n"); 152 | } 153 | 154 | if(ParsedHeader_get(request, "Host") == NULL) 155 | { 156 | if(ParsedHeader_set(request, "Host", request->host) < 0){ 157 | printf("Set \"Host\" header key not working\n"); 158 | } 159 | } 160 | 161 | if (ParsedRequest_unparse_headers(request, buf + len, (size_t)MAX_BYTES - len) < 0) { 162 | printf("unparse failed\n"); 163 | //return -1; // If this happens Still try to send request without header 164 | } 165 | 166 | int server_port = 80; // Default Remote Server Port 167 | if(request->port != NULL) 168 | server_port = atoi(request->port); 169 | 170 | int remoteSocketID = connectRemoteServer(request->host, server_port); 171 | 172 | if(remoteSocketID < 0) 173 | return -1; 174 | 175 | int bytes_send = send(remoteSocketID, buf, strlen(buf), 0); 176 | 177 | bzero(buf, MAX_BYTES); 178 | 179 | bytes_send = recv(remoteSocketID, buf, MAX_BYTES-1, 0); 180 | char *temp_buffer = (char*)malloc(sizeof(char)*MAX_BYTES); //temp buffer 181 | int temp_buffer_size = MAX_BYTES; 182 | int temp_buffer_index = 0; 183 | 184 | while(bytes_send > 0) 185 | { 186 | bytes_send = send(clientSocket, buf, bytes_send, 0); 187 | 188 | for(int i=0;i 0) 254 | { 255 | len = strlen(buffer); 256 | //loop until u find "\r\n\r\n" in the buffer 257 | if(strstr(buffer, "\r\n\r\n") == NULL) 258 | { 259 | bytes_send_client = recv(socket, buffer + len, MAX_BYTES - len, 0); 260 | } 261 | else{ 262 | break; 263 | } 264 | } 265 | 266 | // printf("--------------------------------------------\n"); 267 | // printf("%s\n",buffer); 268 | // printf("----------------------%d----------------------\n",strlen(buffer)); 269 | 270 | char *tempReq = (char*)malloc(strlen(buffer)*sizeof(char)+1); 271 | //tempReq, buffer both store the http request sent by client 272 | for (int i = 0; i < strlen(buffer); i++) 273 | { 274 | tempReq[i] = buffer[i]; 275 | } 276 | 277 | //checking for the request in cache 278 | struct cache_element* temp = find(tempReq); 279 | 280 | if( temp != NULL){ 281 | //request found in cache, so sending the response to client from proxy's cache 282 | int size=temp->len/sizeof(char); 283 | int pos=0; 284 | char response[MAX_BYTES]; 285 | while(posdata[pos]; 289 | pos++; 290 | } 291 | send(socket,response,MAX_BYTES,0); 292 | } 293 | printf("Data retrived from the Cache\n\n"); 294 | printf("%s\n\n",response); 295 | // close(socketNew); 296 | // sem_post(&seamaphore); 297 | // return NULL; 298 | } 299 | 300 | 301 | else if(bytes_send_client > 0) 302 | { 303 | len = strlen(buffer); 304 | //Parsing the request 305 | ParsedRequest* request = ParsedRequest_create(); 306 | 307 | //ParsedRequest_parse returns 0 on success and -1 on failure.On success it stores parsed request in 308 | // the request 309 | if (ParsedRequest_parse(request, buffer, len) < 0) 310 | { 311 | printf("Parsing failed\n"); 312 | } 313 | else 314 | { 315 | bzero(buffer, MAX_BYTES); 316 | if(!strcmp(request->method,"GET")) 317 | { 318 | 319 | if( request->host && request->path && (checkHTTPversion(request->version) == 1) ) 320 | { 321 | bytes_send_client = handle_request(socket, request, tempReq); // Handle GET request 322 | if(bytes_send_client == -1) 323 | { 324 | sendErrorMessage(socket, 500); 325 | } 326 | 327 | } 328 | else 329 | sendErrorMessage(socket, 500); // 500 Internal Error 330 | 331 | } 332 | else 333 | { 334 | printf("This code doesn't support any method other than GET\n"); 335 | } 336 | 337 | } 338 | //freeing up the request pointer 339 | ParsedRequest_destroy(request); 340 | 341 | } 342 | 343 | else if( bytes_send_client < 0) 344 | { 345 | perror("Error in receiving from client.\n"); 346 | } 347 | else if(bytes_send_client == 0) 348 | { 349 | printf("Client disconnected!\n"); 350 | } 351 | 352 | shutdown(socket, SHUT_RDWR); 353 | close(socket); 354 | free(buffer); 355 | sem_post(&seamaphore); 356 | 357 | sem_getvalue(&seamaphore,&p); 358 | printf("Semaphore post value:%d\n",p); 359 | free(tempReq); 360 | return NULL; 361 | } 362 | 363 | 364 | int main(int argc, char * argv[]) { 365 | 366 | int client_socketId, client_len; // client_socketId == to store the client socket id 367 | struct sockaddr_in server_addr, client_addr; // Address of client and server to be assigned 368 | 369 | sem_init(&seamaphore,0,MAX_CLIENTS); // Initializing seamaphore and lock 370 | pthread_mutex_init(&lock,NULL); // Initializing lock for cache 371 | 372 | 373 | if(argc == 2) //checking whether two arguments are received or not 374 | { 375 | port_number = atoi(argv[1]); 376 | } 377 | else 378 | { 379 | printf("Too few arguments\n"); 380 | exit(1); 381 | } 382 | 383 | printf("Setting Proxy Server Port : %d\n",port_number); 384 | 385 | //creating the proxy socket 386 | proxy_socketId = socket(AF_INET, SOCK_STREAM, 0); 387 | 388 | if( proxy_socketId < 0) 389 | { 390 | perror("Failed to create socket.\n"); 391 | exit(1); 392 | } 393 | 394 | int reuse =1; 395 | if (setsockopt(proxy_socketId, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) 396 | perror("setsockopt(SO_REUSEADDR) failed\n"); 397 | 398 | bzero((char*)&server_addr, sizeof(server_addr)); 399 | server_addr.sin_family = AF_INET; 400 | server_addr.sin_port = htons(port_number); // Assigning port to the Proxy 401 | server_addr.sin_addr.s_addr = INADDR_ANY; // Any available adress assigned 402 | 403 | // Binding the socket 404 | if( bind(proxy_socketId, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0 ) 405 | { 406 | perror("Port is not free\n"); 407 | exit(1); 408 | } 409 | printf("Binding on port: %d\n",port_number); 410 | 411 | // Proxy socket listening to the requests 412 | int listen_status = listen(proxy_socketId, MAX_CLIENTS); 413 | 414 | if(listen_status < 0 ) 415 | { 416 | perror("Error while Listening !\n"); 417 | exit(1); 418 | } 419 | 420 | int i = 0; // Iterator for thread_id (tid) and Accepted Client_Socket for each thread 421 | int Connected_socketId[MAX_CLIENTS]; // This array stores socket descriptors of connected clients 422 | 423 | // Infinite Loop for accepting connections 424 | while(1) 425 | { 426 | 427 | bzero((char*)&client_addr, sizeof(client_addr)); // Clears struct client_addr 428 | client_len = sizeof(client_addr); 429 | 430 | // Accepting the connections 431 | client_socketId = accept(proxy_socketId, (struct sockaddr*)&client_addr,(socklen_t*)&client_len); // Accepts connection 432 | if(client_socketId < 0) 433 | { 434 | fprintf(stderr, "Error in Accepting connection !\n"); 435 | exit(1); 436 | } 437 | else{ 438 | Connected_socketId[i] = client_socketId; // Storing accepted client into array 439 | } 440 | 441 | // Getting IP address and port number of client 442 | struct sockaddr_in* client_pt = (struct sockaddr_in*)&client_addr; 443 | struct in_addr ip_addr = client_pt->sin_addr; 444 | char str[INET_ADDRSTRLEN]; // INET_ADDRSTRLEN: Default ip address size 445 | inet_ntop( AF_INET, &ip_addr, str, INET_ADDRSTRLEN ); 446 | printf("Client is connected with port number: %d and ip address: %s \n",ntohs(client_addr.sin_port), str); 447 | //printf("Socket values of index %d in main function is %d\n",i, client_socketId); 448 | pthread_create(&tid[i],NULL,thread_fn, (void*)&Connected_socketId[i]); // Creating a thread for each client accepted 449 | i++; 450 | } 451 | close(proxy_socketId); // Close socket 452 | return 0; 453 | } 454 | 455 | cache_element* find(char* url){ 456 | 457 | // Checks for url in the cache if found returns pointer to the respective cache element or else returns NULL 458 | cache_element* site=NULL; 459 | //sem_wait(&cache_lock); 460 | int temp_lock_val = pthread_mutex_lock(&lock); 461 | printf("Remove Cache Lock Acquired %d\n",temp_lock_val); 462 | if(head!=NULL){ 463 | site = head; 464 | while (site!=NULL) 465 | { 466 | if(!strcmp(site->url,url)){ 467 | printf("LRU Time Track Before : %ld", site->lru_time_track); 468 | printf("\nurl found\n"); 469 | // Updating the time_track 470 | site->lru_time_track = time(NULL); 471 | printf("LRU Time Track After : %ld", site->lru_time_track); 472 | break; 473 | } 474 | site=site->next; 475 | } 476 | } 477 | else { 478 | printf("\nurl not found\n"); 479 | } 480 | //sem_post(&cache_lock); 481 | temp_lock_val = pthread_mutex_unlock(&lock); 482 | printf("Remove Cache Lock Unlocked %d\n",temp_lock_val); 483 | return site; 484 | } 485 | 486 | void remove_cache_element(){ 487 | // If cache is not empty searches for the node which has the least lru_time_track and deletes it 488 | cache_element * p ; // Cache_element Pointer (Prev. Pointer) 489 | cache_element * q ; // Cache_element Pointer (Next Pointer) 490 | cache_element * temp; // Cache element to remove 491 | //sem_wait(&cache_lock); 492 | int temp_lock_val = pthread_mutex_lock(&lock); 493 | printf("Remove Cache Lock Acquired %d\n",temp_lock_val); 494 | if( head != NULL) { // Cache != empty 495 | for (q = head, p = head, temp =head ; q -> next != NULL; 496 | q = q -> next) { // Iterate through entire cache and search for oldest time track 497 | if(( (q -> next) -> lru_time_track) < (temp -> lru_time_track)) { 498 | temp = q -> next; 499 | p = q; 500 | } 501 | } 502 | if(temp == head) { 503 | head = head -> next; /*Handle the base case*/ 504 | } else { 505 | p->next = temp->next; 506 | } 507 | cache_size = cache_size - (temp -> len) - sizeof(cache_element) - 508 | strlen(temp -> url) - 1; //updating the cache size 509 | free(temp->data); 510 | free(temp->url); // Free the removed element 511 | free(temp); 512 | } 513 | //sem_post(&cache_lock); 514 | temp_lock_val = pthread_mutex_unlock(&lock); 515 | printf("Remove Cache Lock Unlocked %d\n",temp_lock_val); 516 | } 517 | 518 | int add_cache_element(char* data,int size,char* url){ 519 | // Adds element to the cache 520 | // sem_wait(&cache_lock); 521 | int temp_lock_val = pthread_mutex_lock(&lock); 522 | printf("Add Cache Lock Acquired %d\n", temp_lock_val); 523 | int element_size=size+1+strlen(url)+sizeof(cache_element); // Size of the new element which will be added to the cache 524 | if(element_size>MAX_ELEMENT_SIZE){ 525 | //sem_post(&cache_lock); 526 | // If element size is greater than MAX_ELEMENT_SIZE we don't add the element to the cache 527 | temp_lock_val = pthread_mutex_unlock(&lock); 528 | printf("Add Cache Lock Unlocked %d\n", temp_lock_val); 529 | // free(data); 530 | // printf("--\n"); 531 | // free(url); 532 | return 0; 533 | } 534 | else 535 | { while(cache_size+element_size>MAX_SIZE){ 536 | // We keep removing elements from cache until we get enough space to add the element 537 | remove_cache_element(); 538 | } 539 | cache_element* element = (cache_element*) malloc(sizeof(cache_element)); // Allocating memory for the new cache element 540 | element->data= (char*)malloc(size+1); // Allocating memory for the response to be stored in the cache element 541 | strcpy(element->data,data); 542 | element -> url = (char*)malloc(1+( strlen( url )*sizeof(char) )); // Allocating memory for the request to be stored in the cache element (as a key) 543 | strcpy( element -> url, url ); 544 | element->lru_time_track=time(NULL); // Updating the time_track 545 | element->next=head; 546 | element->len=size; 547 | head=element; 548 | cache_size+=element_size; 549 | temp_lock_val = pthread_mutex_unlock(&lock); 550 | printf("Add Cache Lock Unlocked %d\n", temp_lock_val); 551 | //sem_post(&cache_lock); 552 | // free(data); 553 | // printf("--\n"); 554 | // free(url); 555 | return 1; 556 | } 557 | return 0; 558 | } 559 | -------------------------------------------------------------------------------- /proxy_server_without_cache.c: -------------------------------------------------------------------------------- 1 | #include "proxy_parse.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | 35 | 36 | 37 | #define MAX_BYTES 4096 //max allowed size of request/response 38 | 39 | #define MAX_CLIENTS 400 //max number of client requests served at a time 40 | 41 | #define MAX_SIZE 200*(1<<20) //size of the cache 42 | 43 | #define MAX_ELEMENT_SIZE 10*(1<<20) //max size of an element in cache 44 | 45 | 46 | 47 | typedef struct cache_element cache_element; 48 | 49 | 50 | 51 | struct cache_element{ 52 | 53 | char* data; //data stores response 54 | 55 | int len; //length of data i.e.. sizeof(data)... 56 | 57 | char* url; //url stores the request 58 | 59 | time_t lru_time_track; //lru_time_track stores the latest time the element is accesed 60 | 61 | cache_element* next; //pointer to next element 62 | 63 | }; 64 | 65 | pthread_mutex_t lock; //lock is used for locking the cache 66 | 67 | 68 | 69 | cache_element* find(char* url); 70 | 71 | int add_cache_element(char* data,int size,char* url); 72 | 73 | void remove_cache_element(); 74 | 75 | 76 | 77 | int port_number = 8080; // Default Port 78 | 79 | int proxy_socketId; // socket descriptor of proxy server 80 | 81 | pthread_t tid[MAX_CLIENTS]; //array to store the thread ids of clients 82 | 83 | sem_t seamaphore; //if client requests exceeds the max_clients this seamaphore puts the 84 | 85 | //waiting threads to sleep and wakes them when traffic on queue decreases 86 | 87 | //sem_t cache_lock; 88 | 89 | 90 | 91 | 92 | 93 | cache_element* head; //pointer to the cache 94 | 95 | int cache_size=0; //cache_size denotes the current size of the cache 96 | 97 | 98 | 99 | int sendErrorMessage(int socket, int status_code) 100 | 101 | { 102 | 103 | char str[1024]; 104 | 105 | char currentTime[50]; 106 | 107 | time_t now = time(0); 108 | 109 | 110 | 111 | struct tm data = *gmtime(&now); 112 | 113 | strftime(currentTime,sizeof(currentTime),"%a, %d %b %Y %H:%M:%S %Z", &data); 114 | 115 | 116 | 117 | switch(status_code) 118 | 119 | { 120 | 121 | case 400: snprintf(str, sizeof(str), "HTTP/1.1 400 Bad Request\r\nContent-Length: 95\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n400 Bad Request\n

400 Bad Rqeuest

\n", currentTime); 122 | 123 | printf("400 Bad Request\n"); 124 | 125 | send(socket, str, strlen(str), 0); 126 | 127 | break; 128 | 129 | 130 | 131 | case 403: snprintf(str, sizeof(str), "HTTP/1.1 403 Forbidden\r\nContent-Length: 112\r\nContent-Type: text/html\r\nConnection: keep-alive\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n403 Forbidden\n

403 Forbidden


Permission Denied\n", currentTime); 132 | 133 | printf("403 Forbidden\n"); 134 | 135 | send(socket, str, strlen(str), 0); 136 | 137 | break; 138 | 139 | 140 | 141 | case 404: snprintf(str, sizeof(str), "HTTP/1.1 404 Not Found\r\nContent-Length: 91\r\nContent-Type: text/html\r\nConnection: keep-alive\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n404 Not Found\n

404 Not Found

\n", currentTime); 142 | 143 | printf("404 Not Found\n"); 144 | 145 | send(socket, str, strlen(str), 0); 146 | 147 | break; 148 | 149 | 150 | 151 | case 500: snprintf(str, sizeof(str), "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 115\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n500 Internal Server Error\n

500 Internal Server Error

\n", currentTime); 152 | 153 | //printf("500 Internal Server Error\n"); 154 | 155 | send(socket, str, strlen(str), 0); 156 | 157 | break; 158 | 159 | 160 | 161 | case 501: snprintf(str, sizeof(str), "HTTP/1.1 501 Not Implemented\r\nContent-Length: 103\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n404 Not Implemented\n

501 Not Implemented

\n", currentTime); 162 | 163 | printf("501 Not Implemented\n"); 164 | 165 | send(socket, str, strlen(str), 0); 166 | 167 | break; 168 | 169 | 170 | 171 | case 505: snprintf(str, sizeof(str), "HTTP/1.1 505 HTTP Version Not Supported\r\nContent-Length: 125\r\nConnection: keep-alive\r\nContent-Type: text/html\r\nDate: %s\r\nServer: VaibhavN/14785\r\n\r\n505 HTTP Version Not Supported\n

505 HTTP Version Not Supported

\n", currentTime); 172 | 173 | printf("505 HTTP Version Not Supported\n"); 174 | 175 | send(socket, str, strlen(str), 0); 176 | 177 | break; 178 | 179 | 180 | 181 | default: return -1; 182 | 183 | 184 | 185 | } 186 | 187 | return 1; 188 | 189 | } 190 | 191 | 192 | 193 | int connectRemoteServer(char* host_addr, int port_num) 194 | 195 | { 196 | 197 | // Creating Socket for remote server --------------------------- 198 | 199 | 200 | 201 | int remoteSocket = socket(AF_INET, SOCK_STREAM, 0); 202 | 203 | 204 | 205 | if( remoteSocket < 0) 206 | 207 | { 208 | 209 | printf("Error in Creating Socket.\n"); 210 | 211 | return -1; 212 | 213 | } 214 | 215 | 216 | 217 | // Get host by the name or ip address provided 218 | 219 | 220 | 221 | struct hostent *host = gethostbyname(host_addr); 222 | 223 | if(host == NULL) 224 | 225 | { 226 | 227 | fprintf(stderr, "No such host exists.\n"); 228 | 229 | return -1; 230 | 231 | } 232 | 233 | 234 | 235 | // inserts ip address and port number of host in struct `server_addr` 236 | 237 | struct sockaddr_in server_addr; 238 | 239 | 240 | 241 | bzero((char*)&server_addr, sizeof(server_addr)); 242 | 243 | server_addr.sin_family = AF_INET; 244 | 245 | server_addr.sin_port = htons(port_num); 246 | 247 | 248 | 249 | bcopy((char *)host->h_addr,(char *)&server_addr.sin_addr.s_addr,host->h_length); 250 | 251 | 252 | 253 | // Connect to Remote server ---------------------------------------------------- 254 | 255 | 256 | 257 | if( connect(remoteSocket, (struct sockaddr*)&server_addr, (socklen_t)sizeof(server_addr)) < 0 ) 258 | 259 | { 260 | 261 | fprintf(stderr, "Error in connecting !\n"); 262 | 263 | return -1; 264 | 265 | } 266 | 267 | 268 | 269 | return remoteSocket; 270 | 271 | } 272 | 273 | 274 | 275 | 276 | 277 | int handle_request(int clientSocket, struct ParsedRequest *request, char *buf, char *tempReq) 278 | 279 | { 280 | 281 | strcpy(buf, "GET "); 282 | 283 | strcat(buf, request->path); 284 | 285 | strcat(buf, " "); 286 | 287 | strcat(buf, request->version); 288 | 289 | strcat(buf, "\r\n"); 290 | 291 | 292 | 293 | size_t len = strlen(buf); 294 | 295 | 296 | 297 | if (ParsedHeader_set(request, "Connection", "close") < 0){ 298 | 299 | printf("set header key not work\n"); 300 | 301 | } 302 | 303 | 304 | 305 | if(ParsedHeader_get(request, "Host") == NULL) 306 | 307 | { 308 | 309 | if(ParsedHeader_set(request, "Host", request->host) < 0){ 310 | 311 | printf("Set \"Host\" header key not working\n"); 312 | 313 | } 314 | 315 | } 316 | 317 | 318 | 319 | if (ParsedRequest_unparse_headers(request, buf + len, (size_t)MAX_BYTES - len) < 0) { 320 | 321 | printf("unparse failed\n"); 322 | 323 | //return -1; // If this happens Still try to send request without header 324 | 325 | } 326 | 327 | 328 | 329 | int server_port = 80; // Default Remote Server Port 330 | 331 | if(request->port != NULL) 332 | 333 | server_port = atoi(request->port); 334 | 335 | 336 | 337 | int remoteSocketID = connectRemoteServer(request->host, server_port); 338 | 339 | 340 | 341 | if(remoteSocketID < 0) 342 | 343 | return -1; 344 | 345 | 346 | 347 | int bytes_send = send(remoteSocketID, buf, strlen(buf), 0); 348 | 349 | 350 | 351 | bzero(buf, MAX_BYTES); 352 | 353 | 354 | 355 | bytes_send = recv(remoteSocketID, buf, MAX_BYTES-1, 0); 356 | 357 | char* temp_buffer = (char*)malloc(sizeof(char)*MAX_BYTES); //temp buffer 358 | 359 | int temp_buffer_size = MAX_BYTES; 360 | 361 | int temp_buffer_index = 0; 362 | 363 | 364 | 365 | while(bytes_send > 0) 366 | 367 | { 368 | 369 | bytes_send = send(clientSocket, buf, bytes_send, 0); 370 | 371 | 372 | 373 | for(int i=0;i 0) 494 | 495 | { 496 | 497 | len = strlen(buffer); 498 | 499 | //loop until u find "\r\n\r\n" in the buffer 500 | 501 | if(strstr(buffer, "\r\n\r\n") == NULL) 502 | 503 | { 504 | 505 | bytes_send_client = recv(socket, buffer + len, MAX_BYTES - len, 0); 506 | 507 | } 508 | 509 | else{ 510 | 511 | break; 512 | 513 | } 514 | 515 | } 516 | 517 | 518 | 519 | char *tempReq = (char*)malloc(strlen(buffer)*sizeof(char)+10); 520 | 521 | //tempReq, buffer both store the http request sent by client 522 | 523 | for (int i = 0; i < strlen(buffer); i++) 524 | 525 | { 526 | 527 | tempReq[i] = buffer[i]; 528 | 529 | } 530 | 531 | 532 | 533 | //checking for the request in cache 534 | 535 | struct cache_element* temp = find(tempReq); 536 | 537 | 538 | 539 | if( temp != NULL){ 540 | 541 | //request found in cache, so sending the response to client from proxy's cache 542 | 543 | int size=temp->len/sizeof(char); 544 | 545 | int pos=0; 546 | 547 | char response[MAX_BYTES]; 548 | 549 | while(posdata[pos]; 556 | 557 | pos++; 558 | 559 | } 560 | 561 | send(socket,response,MAX_BYTES,0); 562 | 563 | } 564 | 565 | printf("Data retrived from the Cache\n\n"); 566 | 567 | printf("%s\n\n",response); 568 | 569 | //return NULL; 570 | 571 | } 572 | 573 | 574 | 575 | 576 | 577 | else if(bytes_send_client > 0) 578 | 579 | { 580 | 581 | len = strlen(buffer); 582 | 583 | //Parsing the request 584 | 585 | struct ParsedRequest* request = ParsedRequest_create(); 586 | 587 | 588 | 589 | //ParsedRequest_parse returns 0 on success and -1 on failure.On success it stores parsed request in 590 | 591 | // the request 592 | 593 | if (ParsedRequest_parse(request, buffer, len) < 0) 594 | 595 | { 596 | 597 | printf("Parsing failed\n"); 598 | 599 | } 600 | 601 | else 602 | 603 | { 604 | 605 | bzero(buffer, MAX_BYTES); 606 | 607 | if(!strcmp(request->method,"GET")) 608 | 609 | { 610 | 611 | 612 | 613 | if( request->host && request->path && (checkHTTPversion(request->version) == 1) ) 614 | 615 | { 616 | 617 | bytes_send_client = handle_request(socket, request, buffer, tempReq); // Handle GET request 618 | 619 | if(bytes_send_client == -1) 620 | 621 | { 622 | 623 | sendErrorMessage(socket, 500); 624 | 625 | } 626 | 627 | 628 | 629 | } 630 | 631 | else 632 | 633 | sendErrorMessage(socket, 500); // 500 Internal Error 634 | 635 | 636 | 637 | } 638 | 639 | else 640 | 641 | { 642 | 643 | printf("This code doesn't support any method other than GET\n"); 644 | 645 | } 646 | 647 | 648 | 649 | } 650 | 651 | //freeing up the request pointer 652 | 653 | ParsedRequest_destroy(request); 654 | 655 | 656 | 657 | } 658 | 659 | else if( bytes_send_client < 0) 660 | 661 | { 662 | 663 | perror("Error in receiving from client.\n"); 664 | 665 | } 666 | 667 | else if(bytes_send_client == 0) 668 | 669 | { 670 | 671 | printf("Client disconnected!\n"); 672 | 673 | } 674 | 675 | 676 | 677 | shutdown(socket, SHUT_RDWR); 678 | 679 | close(socket); 680 | 681 | free(buffer); 682 | 683 | sem_post(&seamaphore); 684 | 685 | sem_getvalue(&seamaphore,&p); 686 | 687 | printf("Semaphore post value:%d\n",p); 688 | 689 | return NULL; 690 | 691 | } 692 | 693 | 694 | 695 | 696 | 697 | int main(int argc, char * argv[]) { 698 | 699 | //printf("\n%d\n",MAX_SIZE); 700 | 701 | //printf("\n%d\n",MAX_ELEMENT_SIZE); 702 | 703 | 704 | 705 | int client_socketId, client_len; // client_socketId == to store the client socket id 706 | 707 | struct sockaddr_in server_addr, client_addr; // Address of client and server to be assigned 708 | 709 | 710 | 711 | sem_init(&seamaphore,0,MAX_CLIENTS); // seamaphore and lock 712 | 713 | pthread_mutex_init(&lock,NULL); // Initializing lock for cache 714 | 715 | 716 | 717 | if(argc == 2) //checking whether two arguments are received or not 718 | 719 | { 720 | 721 | port_number = atoi(argv[1]); 722 | 723 | } 724 | 725 | else 726 | 727 | { 728 | 729 | printf("Too few arguments\n"); 730 | 731 | exit(1); 732 | 733 | } 734 | 735 | 736 | 737 | printf("Setting Proxy Server Port : %d\n",port_number); 738 | 739 | 740 | 741 | //creating the proxy socket 742 | 743 | proxy_socketId = socket(AF_INET, SOCK_STREAM, 0); 744 | 745 | 746 | 747 | if( proxy_socketId < 0) 748 | 749 | { 750 | 751 | perror("Failed to create socket.\n"); 752 | 753 | exit(1); 754 | 755 | } 756 | 757 | 758 | 759 | int reuse =1; 760 | 761 | if (setsockopt(proxy_socketId, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0) 762 | 763 | perror("setsockopt(SO_REUSEADDR) failed\n"); 764 | 765 | 766 | 767 | bzero((char*)&server_addr, sizeof(server_addr)); 768 | 769 | server_addr.sin_family = AF_INET; 770 | 771 | server_addr.sin_port = htons(port_number); // Assigning port to the Proxy 772 | 773 | server_addr.sin_addr.s_addr = INADDR_ANY; // Any available adress assigned 774 | 775 | 776 | 777 | // Binding the socket 778 | 779 | if( bind(proxy_socketId, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0 ) 780 | 781 | { 782 | 783 | perror("Port is not free\n"); 784 | 785 | exit(1); 786 | 787 | } 788 | 789 | printf("Binding on port: %d\n",port_number); 790 | 791 | 792 | 793 | // Proxy socket listening to the requests 794 | 795 | int listen_status = listen(proxy_socketId, MAX_CLIENTS); 796 | 797 | 798 | 799 | if(listen_status < 0 ) 800 | 801 | { 802 | 803 | perror("Error while Listening !\n"); 804 | 805 | exit(1); 806 | 807 | } 808 | 809 | 810 | 811 | int i = 0; // Iterator for thread_id (tid) and Accepted Client_Socket for each thread 812 | 813 | int Connected_socketId[MAX_CLIENTS]; // This array stores socket descriptors of connected clients 814 | 815 | 816 | 817 | // Infinite Loop for accepting connections 818 | 819 | while(1) 820 | 821 | { 822 | 823 | 824 | 825 | bzero((char*)&client_addr, sizeof(client_addr)); // Clears struct client_addr 826 | 827 | client_len = sizeof(client_addr); 828 | 829 | 830 | 831 | // Accepting the connections 832 | 833 | client_socketId = accept(proxy_socketId, (struct sockaddr*)&client_addr,(socklen_t*)&client_len); // Accepts connection 834 | 835 | if(client_socketId < 0) 836 | 837 | { 838 | 839 | fprintf(stderr, "Error in Accepting connection !\n"); 840 | 841 | exit(1); 842 | 843 | } 844 | 845 | else{ 846 | 847 | Connected_socketId[i] = client_socketId; // Storing accepted client into array 848 | 849 | } 850 | 851 | 852 | 853 | // Getting IP address and port number of client 854 | 855 | struct sockaddr_in* client_pt = (struct sockaddr_in*)&client_addr; 856 | 857 | struct in_addr ip_addr = client_pt->sin_addr; 858 | 859 | char str[INET_ADDRSTRLEN]; // INET_ADDRSTRLEN: Default ip address size 860 | 861 | inet_ntop( AF_INET, &ip_addr, str, INET_ADDRSTRLEN ); 862 | 863 | //printf("Client is connected with port number: %d and ip address: %s \n",ntohs(client_addr.sin_port), str); 864 | 865 | //printf("Socket values of index %d in main function is %d\n",i, client_socketId); 866 | 867 | pthread_create(&tid[i],NULL,thread_fn, (void*)&Connected_socketId[i]); // Creating a thread for each client accepted 868 | 869 | i++; 870 | 871 | } 872 | 873 | close(proxy_socketId); // Close socket 874 | 875 | return 0; 876 | 877 | } 878 | 879 | 880 | 881 | cache_element* find(char* url){ 882 | 883 | 884 | 885 | // Checks for url in the cache if found returns pointer to the respective cache element or else returns NULL 886 | 887 | cache_element* site=NULL; 888 | 889 | int temp_lock_val = pthread_mutex_lock(&lock); 890 | 891 | printf("Find Cache Lock Acquired %d\n",temp_lock_val); 892 | 893 | if(head!=NULL){ 894 | 895 | site=head; 896 | 897 | while (site!=NULL) 898 | 899 | { 900 | 901 | if(!strcmp(site->url,url)){ 902 | 903 | printf("\nurl found\n"); 904 | 905 | // Updating the time_track 906 | 907 | site->lru_time_track=time(NULL); 908 | 909 | break; 910 | 911 | } 912 | 913 | site=site->next; 914 | 915 | } 916 | 917 | } 918 | 919 | else { 920 | 921 | printf("\nurl not found\n"); 922 | 923 | } 924 | 925 | //sem_post(&cache_lock); 926 | 927 | temp_lock_val = pthread_mutex_unlock(&lock); 928 | 929 | printf("Find Cache Lock Unlocked %d\n",temp_lock_val); 930 | 931 | return site; 932 | 933 | } 934 | 935 | 936 | 937 | void remove_cache_element(){ 938 | 939 | // If cache is not empty searches for the node which has the least lru_time_track and deletes it 940 | 941 | cache_element * p ; // Cache_element Pointer (Prev. Pointer) 942 | 943 | cache_element * q ; // Cache_element Pointer (Next Pointer) 944 | 945 | cache_element * temp ; // Cache element to remove 946 | 947 | //sem_wait(&cache_lock); 948 | 949 | int temp_lock_val = pthread_mutex_lock(&lock); 950 | 951 | printf("Remove Cache Lock Acquired %d\n",temp_lock_val); 952 | 953 | if( head != NULL) { // Cache != empty 954 | 955 | for (q = head, p = head, temp =head ; q -> next != NULL; 956 | 957 | q = q -> next) { // Iterate through entire cache and search for oldest time track 958 | 959 | if(( (q -> next) -> lru_time_track) < (temp -> lru_time_track)) { 960 | 961 | temp = q -> next; 962 | 963 | p = q; 964 | 965 | } 966 | 967 | } 968 | 969 | if(temp == head) { 970 | 971 | head = head -> next; /*Handle the base case*/ 972 | 973 | } else { 974 | 975 | p->next = temp->next; 976 | 977 | } 978 | 979 | cache_size = cache_size - (temp -> len) - sizeof(cache_element) - 980 | 981 | strlen(temp -> url) - 1; //updating the cache size 982 | 983 | free(temp->data); 984 | 985 | free(temp->url); 986 | 987 | free(temp); // Free the removed element 988 | 989 | } 990 | 991 | //sem_post(&cache_lock); 992 | 993 | temp_lock_val = pthread_mutex_unlock(&lock); 994 | 995 | printf("Remove Cache Lock Unlocked %d\n",temp_lock_val); 996 | 997 | } 998 | 999 | 1000 | 1001 | int add_cache_element(char* data,int size,char* url){ 1002 | 1003 | // Adds element to the cache 1004 | 1005 | // sem_wait(&cache_lock); 1006 | 1007 | printf("\nurl:%s\n",url); 1008 | 1009 | printf("\ndata:%s\n",data); 1010 | 1011 | int ret=0; 1012 | 1013 | int temp_lock_val = pthread_mutex_lock(&lock); 1014 | 1015 | printf("Add Cache Lock Acquired %d\n", temp_lock_val); 1016 | 1017 | int element_size=size+1+strlen(url)+sizeof(cache_element); // Size of the new element which will be added to the cache 1018 | 1019 | /*if(element_size>MAX_ELEMENT_SIZE){ 1020 | 1021 | //sem_post(&cache_lock); 1022 | 1023 | // If element size is greater than MAX_ELEMENT_SIZE we don't add the element to the cache 1024 | 1025 | temp_lock_val = pthread_mutex_unlock(&lock); 1026 | 1027 | printf("Add Cache Lock Unlocked %d\n", temp_lock_val); 1028 | 1029 | return 0; 1030 | 1031 | }*/ 1032 | 1033 | if(element_size<=MAX_ELEMENT_SIZE) 1034 | 1035 | { while(cache_size+element_size>MAX_SIZE){ 1036 | 1037 | // We keep removing elements from cache until we get enough space to add the element 1038 | 1039 | remove_cache_element(); 1040 | 1041 | } 1042 | 1043 | cache_element* element = (cache_element*) malloc(sizeof(cache_element)); // Allocating memory for the new cache element 1044 | 1045 | element->data= (char*)malloc(size+10); // Allocating memory for the response to be stored in the cache element 1046 | 1047 | strcpy(element->data,data); 1048 | 1049 | element -> url = (char*)malloc(10+( strlen( url )*sizeof(char) )); // Allocating memory for the request to be stored in the cache element (as a key) 1050 | 1051 | strcpy( element -> url, url ); 1052 | 1053 | element->lru_time_track=time(NULL); // Updating the time_track 1054 | 1055 | element->next=head; 1056 | 1057 | element->len=size; 1058 | 1059 | head=element; 1060 | 1061 | cache_size+=element_size; 1062 | 1063 | //sem_post(&cache_lock); 1064 | 1065 | ret= 1; 1066 | 1067 | } 1068 | 1069 | temp_lock_val = pthread_mutex_unlock(&lock); 1070 | 1071 | printf("Add Cache Lock Unlocked %d\n", temp_lock_val); 1072 | 1073 | free(url); 1074 | 1075 | free(data); 1076 | 1077 | printf("\ncache size:%d\n",cache_size); 1078 | 1079 | return ret; 1080 | 1081 | } 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | --------------------------------------------------------------------------------