Check-in [565d4b51c2]
Overview
Comment:Updated to cache file descriptors
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:565d4b51c2cd0fa96ef28afea971a0e52feaaa15
User & Date: rkeene on 2014-02-05 08:49:33
Other Links: manifest | tags
Context
2014-02-05
09:01
Added support for a "no logging" compile-time option (for now) and updated to support sendfile restarts check-in: c7e703e4e5 user: rkeene tags: trunk
08:49
Updated to cache file descriptors check-in: 565d4b51c2 user: rkeene tags: trunk
2014-02-04
12:02
Check sendfile() output and log check-in: 16b1aecd99 user: rkeene tags: trunk
Changes

Modified filed.c from [8a849d733e] to [af10919239].

21
22
23
24
25
26
27


28
29
30
31
32
33
34




35
36



37



















38
39
40
41
42
43
44
..
77
78
79
80
81
82
83

84
85
86


87
88
89
90
91
92
93
..
97
98
99
100
101
102
103
104

























105
106
107
108


109
110
111













112
113


114
115





116
117
118
119
120
121

122
123
124
125























126
127
128
129
130
131
132
...
194
195
196
197
198
199
200

201
202
203
204
205
206
207
...
241
242
243
244
245
246
247

248
249
250
251
252
253
254
255
...
335
336
337
338
339
340
341

342
343
344
345
346
347
348
...
353
354
355
356
357
358
359
360





361
362
363
364
365
366
367
/* Arguments for worker threads */
struct filed_worker_thread_args {
	int fd;
};

/* File information */
struct filed_fileinfo {


	int fd;
	size_t len;
	char *lastmod;
	char lastmod_b[64];
	char *type;
};





/* Initialize process */
static void filed_init(void) {



	mlockall(MCL_CURRENT | MCL_FUTURE);



















}

/* Listen on a particular address/port */
static int filed_listen(const char *address, unsigned int port) {
	struct sockaddr_in6 addr;
	int pton_ret, bind_ret, listen_ret;
	int fd;
................................................................................
/* Initialize logging thread */
static int filed_logging_thread_init(void) {
	/* XXX:TODO: Unimplemented */
	return(0);
}

/* Log a message */

static void filed_log_msg(const char *buffer) {
	/* XXX:TODO: Unimplemented */
	buffer = buffer;


	return;
}

/* Format time per RFC2616 */
static char *filed_format_time(char *buffer, size_t buffer_len, const time_t timeinfo) {
	struct tm timeinfo_tm, *timeinfo_tm_p;

................................................................................
	}

	buffer[buffer_len - 1] = '\0';
	buffer_len = strftime(buffer, buffer_len - 1, "%a, %d %b %Y %H:%M:%S GMT", timeinfo_tm_p);

	return(buffer);
}


























/* Open a file and return file information */
static struct filed_fileinfo *filed_open_file(const char *path, struct filed_fileinfo *buffer) {
	/* XXX:TODO: Cache file descriptors */



	off_t len;
	int fd;














	fd = open(path, O_RDONLY);
	if (fd < 0) {


		return(NULL);
	}






	len = lseek(fd, 0, SEEK_END);
	lseek(fd, 0, SEEK_SET);

	buffer->fd = fd;
	buffer->len = len;


	/* XXX:TODO: Determine */
	buffer->type = "text/plain";
	buffer->lastmod = filed_format_time(buffer->lastmod_b, sizeof(buffer->lastmod_b), time(NULL) - 30);
























	return(buffer);
}

/* Process an HTTP request and return the path requested */
static char *filed_get_http_request(FILE *fp, char *buffer, size_t buffer_len) {
	char *method, *path;
................................................................................
	);
}

/* Handle a single request from a client */
static void filed_handle_client(int fd) {
	struct filed_fileinfo *fileinfo, fileinfo_b;
	ssize_t sendfile_ret;

	char *path, path_b[1010];
	char *date_current, date_current_b[64];
	FILE *fp;

	/* Determine current time */
	date_current = filed_format_time(date_current_b, sizeof(date_current_b), time(NULL));

................................................................................
		);
		fflush(fp);

		filed_log_msg("PROCESS_REPLY_COMPLETE FD=... STATUS=200");

		filed_log_msg("SEND_START IFD=... OFD=... BYTES=...");


		sendfile_ret = sendfile(fd, fileinfo->fd, NULL, fileinfo->len);
		if (sendfile_ret < 0 || ((size_t) sendfile_ret) != fileinfo->len) {
			filed_log_msg("SEND_COMPLETE STATUS=ERROR IFD=... OFD=... BYTES=... BYTES_SENT=...");
		} else {
			filed_log_msg("SEND_COMPLETE STATUS=OK IFD=... OFD=... BYTES=...");
		}

		close(fileinfo->fd);
................................................................................
	return(0);
}

/* Run process */
int main(int argc, char **argv) {
	int port = PORT, thread_count = THREAD_COUNT;
	const char *bind_addr = BIND_ADDR;

	int fd;

	/* Ignore */
	argc = argc;
	argv = argv;

	/* Create listening socket */
................................................................................
		return(1);
	}

	/* Become a daemon */
	/* XXX:TODO: Become a daemon */

	/* Initialize */
	filed_init();






	/* Create logging thread */
	/* XXX:TODO: Check for errors */
	filed_logging_thread_init();

	/* Create worker threads */
	/* XXX:TODO: Check for errors */







>
>







>
>
>
>

|
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>


<
>
>







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


<
<
>
>



>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
|
|
>
>
>
>
>




|
|
>

|
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







 







>
|







 







>







 







|
>
>
>
>
>







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
...
105
106
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
122
123
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161


162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
...
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
/* Arguments for worker threads */
struct filed_worker_thread_args {
	int fd;
};

/* File information */
struct filed_fileinfo {
	pthread_mutex_t mutex;
	char *path;
	int fd;
	size_t len;
	char *lastmod;
	char lastmod_b[64];
	char *type;
};

/* Global variables */
struct filed_fileinfo *filed_fileinfo_fdcache;
unsigned int filed_fileinfo_fdcache_size = 8192;

/* Initialize process */
static int filed_init(void) {
	unsigned int idx;
	int mutex_init_ret;

	mlockall(MCL_CURRENT | MCL_FUTURE);

	filed_fileinfo_fdcache = malloc(sizeof(*filed_fileinfo_fdcache) * filed_fileinfo_fdcache_size);
	if (filed_fileinfo_fdcache == NULL) {
		return(1);
	}

	for (idx = 0; idx < filed_fileinfo_fdcache_size; idx++) {
		mutex_init_ret = pthread_mutex_init(&filed_fileinfo_fdcache[idx].mutex, NULL);
		if (mutex_init_ret != 0) {
			return(1);
		}

		filed_fileinfo_fdcache[idx].path = strdup("");
		filed_fileinfo_fdcache[idx].fd = -1;
		filed_fileinfo_fdcache[idx].lastmod = "";
		filed_fileinfo_fdcache[idx].type = "";
	}

	return(0);
}

/* Listen on a particular address/port */
static int filed_listen(const char *address, unsigned int port) {
	struct sockaddr_in6 addr;
	int pton_ret, bind_ret, listen_ret;
	int fd;
................................................................................
/* Initialize logging thread */
static int filed_logging_thread_init(void) {
	/* XXX:TODO: Unimplemented */
	return(0);
}

/* Log a message */
#define filed_log_msg_debug(x, ...) { fprintf(stderr, x, __VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); }
static void filed_log_msg(const char *buffer) {
	/* XXX:TODO: Unimplemented */

	fprintf(stderr, "%s\n", buffer);

	return;
}

/* Format time per RFC2616 */
static char *filed_format_time(char *buffer, size_t buffer_len, const time_t timeinfo) {
	struct tm timeinfo_tm, *timeinfo_tm_p;

................................................................................
	}

	buffer[buffer_len - 1] = '\0';
	buffer_len = strftime(buffer, buffer_len - 1, "%a, %d %b %Y %H:%M:%S GMT", timeinfo_tm_p);

	return(buffer);
}

/* hash */
static unsigned int filed_hash(const unsigned char *value, unsigned int modulus) {
	unsigned char curr;
	unsigned int retval;

	retval = modulus - 1;

	while ((curr = *value)) {
		if (curr < 32) {
			curr = 255 - curr;
		} else {
			curr -= 32;
		}

		retval <<= 5;
		retval += curr;

		value++;
	}

	retval = retval % modulus;

	return(retval);
}

/* Open a file and return file information */
static struct filed_fileinfo *filed_open_file(const char *path, struct filed_fileinfo *buffer) {


	struct filed_fileinfo *cache;
	unsigned int cache_idx;
	off_t len;
	int fd;

	cache_idx = filed_hash((const unsigned char *) path, filed_fileinfo_fdcache_size);

	cache = &filed_fileinfo_fdcache[cache_idx];

	filed_log_msg_debug("Locking mutex for idx: %lu", (unsigned long) cache_idx);

	pthread_mutex_lock(&cache->mutex);

	filed_log_msg_debug("Completed locking mutex for idx: %lu", (unsigned long) cache_idx);

	if (strcmp(path, cache->path) != 0) {
		filed_log_msg_debug("Cache miss for idx: %lu: OLD \"%s\", NEW \"%s\"", (unsigned long) cache_idx, cache->path, path);

		fd = open(path, O_RDONLY);
		if (fd < 0) {
			pthread_mutex_unlock(&cache->mutex);

			return(NULL);
		}

		free(cache->path);
		if (cache->fd >= 0) {
			close(cache->fd);
		}

		len = lseek(fd, 0, SEEK_END);
		lseek(fd, 0, SEEK_SET);

		cache->fd = fd;
		cache->len = len;
		cache->path = strdup(path);

		/* XXX:TODO: Determine */
		cache->type = "text/plain";

		cache->lastmod = filed_format_time(cache->lastmod_b, sizeof(cache->lastmod_b), time(NULL) - 30);
	} else {
		filed_log_msg_debug("Cache hit for idx: %lu: PATH \"%s\"", (unsigned long) cache_idx, path);
	}

	/*
	 * We have to make a duplicate FD, because once we release the cache
	 * mutex, the file descriptor may be closed
	 */
	fd = dup(cache->fd);
	if (fd < 0) {
		pthread_mutex_unlock(&cache->mutex);

		return(NULL);
	}

	buffer->fd = fd;
	buffer->len = cache->len;
	buffer->type = cache->type;
	memcpy(buffer->lastmod_b, cache->lastmod_b, sizeof(buffer->lastmod_b));
	buffer->lastmod = buffer->lastmod_b + (cache->lastmod - cache->lastmod_b);

	pthread_mutex_unlock(&cache->mutex);

	return(buffer);
}

/* Process an HTTP request and return the path requested */
static char *filed_get_http_request(FILE *fp, char *buffer, size_t buffer_len) {
	char *method, *path;
................................................................................
	);
}

/* Handle a single request from a client */
static void filed_handle_client(int fd) {
	struct filed_fileinfo *fileinfo, fileinfo_b;
	ssize_t sendfile_ret;
	off_t sendfile_offset;
	char *path, path_b[1010];
	char *date_current, date_current_b[64];
	FILE *fp;

	/* Determine current time */
	date_current = filed_format_time(date_current_b, sizeof(date_current_b), time(NULL));

................................................................................
		);
		fflush(fp);

		filed_log_msg("PROCESS_REPLY_COMPLETE FD=... STATUS=200");

		filed_log_msg("SEND_START IFD=... OFD=... BYTES=...");

		sendfile_offset = 0;
		sendfile_ret = sendfile(fd, fileinfo->fd, &sendfile_offset, fileinfo->len);
		if (sendfile_ret < 0 || ((size_t) sendfile_ret) != fileinfo->len) {
			filed_log_msg("SEND_COMPLETE STATUS=ERROR IFD=... OFD=... BYTES=... BYTES_SENT=...");
		} else {
			filed_log_msg("SEND_COMPLETE STATUS=OK IFD=... OFD=... BYTES=...");
		}

		close(fileinfo->fd);
................................................................................
	return(0);
}

/* Run process */
int main(int argc, char **argv) {
	int port = PORT, thread_count = THREAD_COUNT;
	const char *bind_addr = BIND_ADDR;
	int init_ret;
	int fd;

	/* Ignore */
	argc = argc;
	argv = argv;

	/* Create listening socket */
................................................................................
		return(1);
	}

	/* Become a daemon */
	/* XXX:TODO: Become a daemon */

	/* Initialize */
	init_ret = filed_init();
	if (init_ret != 0) {
		perror("filed_init");

		return(3);
	}

	/* Create logging thread */
	/* XXX:TODO: Check for errors */
	filed_logging_thread_init();

	/* Create worker threads */
	/* XXX:TODO: Check for errors */