├── 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 | 
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 | 
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\n400 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\n403 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\n404 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\n500 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\n501 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\n505 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\n400 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\n403 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\n404 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\n500 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\n501 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\n505 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 |
--------------------------------------------------------------------------------