-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcache-record.c
More file actions
99 lines (83 loc) · 3.2 KB
/
cache-record.c
File metadata and controls
99 lines (83 loc) · 3.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//
// Created by dran on 4/5/22.
//
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "cache-record.h"
#define SUCCESS 0
#define FAIL 1
#define URL_MAX_LENGTH 2048
cache_table_t* cache_table_create() {
cache_table_t* created;
created = malloc(sizeof(cache_table_t));
created->content = NULL;
pthread_mutex_init(&(created->mutex), NULL);
return created;
}
cache_record_t* cache_record_create(char* name) {
cache_record_t* created;
created = malloc(sizeof(cache_record_t));
strcpy(created->name, name);
created->expiration_time = time(NULL) + CACHE_TTL;
created->write_in_progress = 1;
created->readers = 0;
pthread_mutex_init(&(created->mutex), NULL);
return created;
}
cache_record_t* cache_record_get_or_create(cache_table_t* table, char* url, enum action_status* status_ret) {
char hash_command[URL_MAX_LENGTH + 256];
FILE* hash_return;
char hash_buffer[CACHE_HASH_LENGTH];
cache_record_t* record;
record = NULL;
if (strlen(url) > URL_MAX_LENGTH) {
*status_ret = unavailable;
return record; // unable to process url longer than 2048 bytes
}
sprintf(hash_command, "echo \"%s\" | md5sum", url); // TODO: this looks like a remote code execution vulnerability. find out for sure
// is this a valid url? : " | echo nasty-command" maybe as hexadecimal?
// printf("executing command in shell:\n%s\n", hash_command);
hash_return = popen(hash_command, "r");
fgets(hash_buffer, 32, hash_return);
hash_buffer[32] = '\0';
fclose(hash_return);
pthread_mutex_lock(&(table->mutex));
HASH_FIND_STR(table->content, hash_buffer, record);
if (record == NULL) {
// new cache record is created, it should be filled with actual data
record = cache_record_create(hash_buffer);
HASH_ADD_STR(table->content, name, record);
*status_ret = should_write;
pthread_mutex_unlock(&(table->mutex));
return record;
}
pthread_mutex_lock(&(record->mutex));
if (record->expiration_time < time(NULL) && !record->readers && !record->write_in_progress) {
// if cache is stale and no one else is updating it, update it and reset TTL
*status_ret = should_write;
record->write_in_progress = 1;
record->expiration_time = time(NULL) + CACHE_TTL;
} else if (record->expiration_time > time(NULL) && !record->write_in_progress) {
// if cache is fresh enough and no writer is currently updating it, reading is ok
*status_ret = should_read;
record->readers++;
} else {
// cache is expired, don't read.
// someone else is still using cache (I hope they started before expiration), don't update
// someone else is already updating it, don't update
*status_ret = unavailable;
}
pthread_mutex_unlock(&(record->mutex));
pthread_mutex_unlock(&(table->mutex));
return record;
}
void cache_record_close(cache_record_t* record, enum action_status status) {
pthread_mutex_lock(&(record->mutex));
if (status == should_write) {
record->write_in_progress = 0;
} else if (status == should_read) {
record->readers--;
}
pthread_mutex_unlock(&(record->mutex));
}