Check-in [1c1d95a764]
Overview
Comment:Merged in trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | remove-c11-atomics
Files: files | file ages | folders
SHA1:1c1d95a764aee834a7b3e1d3e2e462f49aa2dff2
User & Date: rkeene on 2020-03-31 13:41:47
Other Links: manifest | tags
Context
2020-03-31
14:19
Use a mutex (for now?) for closing idle sockets check-in: 158143b222 user: rkeene tags: remove-c11-atomics
13:41
Merged in trunk check-in: 1c1d95a764 user: rkeene tags: remove-c11-atomics
2018-05-03
20:08
Added support for not redirecting to index.html check-in: 879cdc86ce user: rkeene tags: trunk
2016-09-22
17:35
Started branch to replace C11 atomics with simpler (but hopefully lock-free) implementation check-in: c6f6825723 user: rkeene tags: remove-c11-atomics
Changes

Modified .fossil-settings/ignore-glob from [72ecff7281] to [3d8734b3a3].

1
2
3

filed
filed.o
filed-mime-types.h




>
1
2
3
4
filed
filed.o
filed-mime-types.h
compiled

Modified Makefile from [d6a72f7309] to [2fd19df44e].

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
CC = gcc
CFLAGS = -std=gnu11 -Wall -W -pthread -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE $(FILED_EXTRA_CFLAGS)
LDFLAGS = -pthread $(FILED_EXTRA_LDFLAGS)
LIBS = -lpthread $(FILED_EXTRA_LIBS)
MIMETYPES = /etc/httpd/mime.types

PREFIX = /usr/local
prefix = $(PREFIX)
bindir = $(prefix)/bin
mandir = $(prefix)/share/man



all: filed

filed: filed.o
	$(CC) $(CFLAGS) $(LDFLAGS) -o "$@" $^ $(LIBS)

filed.o: filed.c filed-mime-types.h

filed-mime-types.h: generate-mime-types mime.types
	./generate-mime-types "$(MIMETYPES)" > filed-mime-types.h.new || \
		./generate-mime-types mime.types > filed-mime-types.h.new
	mv filed-mime-types.h.new filed-mime-types.h

install: filed filed.1
	test -d "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1"
	test -d "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)"
	cp filed.1 "$(DESTDIR)$(mandir)/man1/"
	cp filed "$(DESTDIR)$(bindir)/"

clean:
	rm -f filed filed.o
	rm -f filed-mime-types.h.new

distclean: clean
	rm -f filed-mime-types.h

.PHONY: all install clean distclean

|








>
>






|

|
|
|


|


|










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
CC = gcc
CFLAGS = -I. -std=gnu11 -Wall -W -pthread -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE $(FILED_EXTRA_CFLAGS)
LDFLAGS = -pthread $(FILED_EXTRA_LDFLAGS)
LIBS = -lpthread $(FILED_EXTRA_LIBS)
MIMETYPES = /etc/httpd/mime.types

PREFIX = /usr/local
prefix = $(PREFIX)
bindir = $(prefix)/bin
mandir = $(prefix)/share/man
srcdir = .
vpath %.c $(srcdir)

all: filed

filed: filed.o
	$(CC) $(CFLAGS) $(LDFLAGS) -o "$@" $^ $(LIBS)

filed.o: $(srcdir)/filed.c filed-mime-types.h

filed-mime-types.h: $(srcdir)/generate-mime-types $(srcdir)/mime.types
	'$(srcdir)/generate-mime-types' '$(MIMETYPES)' > filed-mime-types.h.new || \
		'$(srcdir)/generate-mime-types' '$(srcdir)/mime.types' > filed-mime-types.h.new
	mv filed-mime-types.h.new filed-mime-types.h

install: filed $(srcdir)/filed.1
	test -d "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1"
	test -d "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)"
	cp '$(srcdir)/filed.1' "$(DESTDIR)$(mandir)/man1/"
	cp filed "$(DESTDIR)$(bindir)/"

clean:
	rm -f filed filed.o
	rm -f filed-mime-types.h.new

distclean: clean
	rm -f filed-mime-types.h

.PHONY: all install clean distclean

Modified README from [280019e35b] to [dc3dfdd9b3].

70
71
72
73
74
75
76





77
78
79
80
81
82
83
84
        rather than call chroot() at startup.  This is less secure and slower
        and should be generally avoided -- however it may be necessary to do.
        In these cases the executable may be compiled with the
        FILED_FAKE_CHROOT C preprocessor macro defined and instead of calling
        chroot() all HTTP requests will have the root suffix specified as the
        argument to the "-r" or "--root" option prepended to them.






   5. MIME Types (MIMETYPES)
	For single-file convenience "filed" compiles the mapping of file
	extensions (the string in the filename following its last dot ("."))
	into the executable.  This mapping comes from a file in the format of
		type1   type1_extension1 type1_extension2...
		type2   type2_extension1 type2_extension2...
		...
	However it may not be desirable to include this mapping, or it may be







>
>
>
>
>
|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
        rather than call chroot() at startup.  This is less secure and slower
        and should be generally avoided -- however it may be necessary to do.
        In these cases the executable may be compiled with the
        FILED_FAKE_CHROOT C preprocessor macro defined and instead of calling
        chroot() all HTTP requests will have the root suffix specified as the
        argument to the "-r" or "--root" option prepended to them.

   5. Differing "index.html" handling (CFLAGS, -DFILED_DONT_REDIRECT_DIRECTORIES=1)
        Normally "filed" redirects users who request a directory to the
        index.html file in that directory so that no memory allocations are
        required;  This option lets the server generate the new path.

   6. MIME Types (MIMETYPES)
	For single-file convenience "filed" compiles the mapping of file
	extensions (the string in the filename following its last dot ("."))
	into the executable.  This mapping comes from a file in the format of
		type1   type1_extension1 type1_extension2...
		type2   type2_extension1 type2_extension2...
		...
	However it may not be desirable to include this mapping, or it may be

Added build/build-precompiled version [46b4f35d88].



































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
#! /usr/bin/env bash

# Ensure we are in the correct working directory
cd "$(dirname "$(which "$0")")/.." || exit 1

# Determine the version of Filed
version=''
eval "$(( grep '^# *define  *FILED_VERSION' filed.c; echo '|version=FILED_VERSION' ) | cpp -E | grep '^|' | sed 's@^|@@')"
if [ -z "${version}" ]; then
	echo "Unable to determine which version of Filed we are compiling.  Aborting." >&2

	exit 1
fi

# Cleanup
rm -rf workdir-buildPrecompiled-*

# Compile everything, all at once
idx=-1
for tryCompilerDir in "$(readlink -f ~/root/cross-compilers)" "$(readlink -f ~/devel/build-cc/TMP)"; do
	setup_cc="${tryCompilerDir}/setup-cc"

	platforms=(
		$("${setup_cc}" | tail -n +2)
	)

	for platform in "${platforms[@]}"; do
		idx=$[$idx + 1]
		(
			workdir="workdir-buildPrecompiled-${idx}-$(openssl rand 20 -hex)-platform-${platform}" || exit 1
			mkdir "${workdir}" || exit 1
			cd "${workdir}" || exit 1

			eval $("${setup_cc}" "${platform}")
			make_extra=(
				-f ../Makefile
				srcdir=..
				CC="${CC}"
			)

			case "${platform}" in
				*-musl-*|*-musl)
					make_extra=("${make_extra[@]}" FILED_EXTRA_LDFLAGS="-static")
					;;
			esac

			make "${make_extra[@]}"
		) &
	done
done

# Wait for that to get done
wait

# Rename the files into place
mkdir -p compiled
for binary in workdir-buildPrecompiled-*/filed; do
	platform="$(echo "${binary}" | sed 's@^.*-platform-@@;s@/.*$@@')"
	mv "${binary}" "compiled/filed-${version}-${platform}"
done

# Cleanup
rm -rf workdir-buildPrecompiled-*

exit 0

Modified filed.1 from [322827fb73] to [193b38d17e].

1
2
3
4
5
6
7
8
9
.PU
.TH FILED 1 "17 Aug 2016" "filed 1.19"
.SH NAME
filed \- serve files over HTTP
.SH SYNOPSIS
.ll +10
.B filed
.RB [{ \-h | \-\-help }]
.RB [{ \-d | \-\-daemon }]

|







1
2
3
4
5
6
7
8
9
.PU
.TH FILED 1 "22 Sep 2016" "filed 1.21"
.SH NAME
filed \- serve files over HTTP
.SH SYNOPSIS
.ll +10
.B filed
.RB [{ \-h | \-\-help }]
.RB [{ \-d | \-\-daemon }]

Modified filed.c from [a92c173e7c] to [66294af131].

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
...
270
271
272
273
274
275
276


277
278
279
280
281
282
283
...
284
285
286
287
288
289
290
291
292





293
294



295

296
297
298
299
300
301
302
...
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
...
676
677
678
679
680
681
682

683
684
685
686
687
688
689
690
691


692
693
694
695
696
697
698
...
736
737
738
739
740
741
742

743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
....
1167
1168
1169
1170
1171
1172
1173

1174
1175
1176
1177
1178
1179
1180
1181
1182
....
1192
1193
1194
1195
1196
1197
1198

1199
1200
1201
1202
1203
1204
1205
....
1253
1254
1255
1256
1257
1258
1259














1260
1261
1262

1263
1264
1265
1266
1267
1268
1269
....
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <pwd.h>

/* Compile time constants */
#define FILED_VERSION "1.19"
#define FILED_SENDFILE_MAX 16777215
#define FILED_MAX_FAILURE_COUNT 30
#define FILED_DEFAULT_TYPE "application/octet-stream"
#define FILED_PATH_BUFFER_SIZE 1010

/* Default values */
#define PORT 80
................................................................................

	return(0);
}

/* Initialize process */
static int filed_init(unsigned int cache_size) {
	static int called = 0;


	ssize_t read_ret = 0;
	unsigned int random_value = 0;
	int cache_ret;
	int random_fd;

	if (called) {
		return(0);
................................................................................
	}

	called = 1;

	/* Attempt to lock all memory to physical RAM (but don't care if we can't) */
	mlockall(MCL_CURRENT | MCL_FUTURE);

	/* Ignore SIGPIPE */
	signal(SIGPIPE, SIG_IGN);






	/* Handle SIGHUP to release all caches */



	signal(SIGHUP, filed_signal_handler);


	/* Initialize cache structure */
	cache_ret = filed_init_cache(cache_size);
	if (cache_ret != 0) {
		return(cache_ret);
	}

................................................................................
#define filed_sockettimeout_close(x) /**/
#else
time_t filed_sockettimeout_time;
struct {
	time_t expiration_time;
	pthread_t thread_id;
	int valid;
}* filed_sockettimeout_sockstatus;
long filed_sockettimeout_sockstatus_length;
int filed_sockettimeout_devnull_fd;

static int filed_sockettimeout_sockfd_in_range(int sockfd) {
	if (sockfd < 3) {
		return(0);
	}
................................................................................

	atomic_store(&filed_sockettimeout_sockstatus[sockfd].valid, false);

	return;
}

static void *filed_sockettimeout_thread(void *arg) {

	time_t now, expiration_time;
	pthread_t thread_id;
	long idx;
	int count;
	int valid;

	while (1) {
		for (count = 0; count < 10; count++) {
			usleep(30000000);



			now = time(NULL);

			atomic_store(&filed_sockettimeout_time, now);
		}

		for (idx = 0; idx < filed_sockettimeout_sockstatus_length; idx++) {
................................................................................
	long maxfd, idx;

	maxfd = sysconf(_SC_OPEN_MAX);
	if (maxfd <= 0) {
		maxfd = 4096;
	}


	filed_sockettimeout_sockstatus = malloc(sizeof(*filed_sockettimeout_sockstatus) * maxfd);
	if (filed_sockettimeout_sockstatus == NULL) {
		return(-1);
	}

	for (idx = 0; idx < maxfd; idx++) {
		filed_sockettimeout_sockstatus[idx].valid = false;
	}

	filed_sockettimeout_sockstatus_length = maxfd;
	filed_sockettimeout_devnull_fd = open("/dev/null", O_RDWR);
	if (filed_sockettimeout_devnull_fd < 0) {
		return(-1);
	}

	return(0);
}
................................................................................

	fclose(fp);

	return;
}

/* Return a redirect to index.html */

static void filed_redirect_index(FILE *fp, const char *date_current, const char *path, struct filed_log_entry *log) {
	int http_code = 301;
	fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: 0\r\nConnection: close\r\nLocation: %s\r\n\r\n",
		http_code,
		date_current,
		date_current,
		"index.html"
	);

................................................................................
	fclose(fp);

	return;

	/* Currently unused: path */
	path = path;
}


/* Convert an enum representing the "Connection" header value to a string */
static const char *filed_connection_str(int connection_value) {
	switch (connection_value) {
		case FILED_CONNECTION_CLOSE:
			return("close");
		case FILED_CONNECTION_KEEP_ALIVE:
................................................................................

	path = request->path;
	strcpy(log->buffer, path);
	log->method = request->method;

	/* If the requested path is a directory, redirect to index page */
	if (request->type == FILED_REQUEST_TYPE_DIRECTORY) {














		filed_redirect_index(fp, date_current, path, log);

		return(FILED_CONNECTION_CLOSE);

	}

	fileinfo = filed_open_file(path, &request->fileinfo, options);
	if (fileinfo == NULL) {
		filed_error_page(fp, date_current, 404, request->method, "open_failed", log);

		return(FILED_CONNECTION_CLOSE);
................................................................................

		return(5);
	}

	/* Wait for threads to exit */
	/* XXX:TODO: Monitor thread usage */
	while (1) {
		sleep(60);
	}

	/* Return in failure */
	return(2);
}







|







 







>
>







 







|
|
>
>
>
>
>


>
>
>
|
>







 







|







 







>








|
>
>







 







>
|








<







 







>

|







 







>







 







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



>







 







|





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
...
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
...
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766

767
768
769
770
771
772
773
....
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
....
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
....
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
....
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <pwd.h>

/* Compile time constants */
#define FILED_VERSION "1.21"
#define FILED_SENDFILE_MAX 16777215
#define FILED_MAX_FAILURE_COUNT 30
#define FILED_DEFAULT_TYPE "application/octet-stream"
#define FILED_PATH_BUFFER_SIZE 1010

/* Default values */
#define PORT 80
................................................................................

	return(0);
}

/* Initialize process */
static int filed_init(unsigned int cache_size) {
	static int called = 0;
	struct sigaction signal_handler_info;
	sigset_t signal_handler_mask;
	ssize_t read_ret = 0;
	unsigned int random_value = 0;
	int cache_ret;
	int random_fd;

	if (called) {
		return(0);
................................................................................
	}

	called = 1;

	/* Attempt to lock all memory to physical RAM (but don't care if we can't) */
	mlockall(MCL_CURRENT | MCL_FUTURE);

	/* Establish signal handlers */
	/* SIGPIPE should interrupt system calls */
	sigfillset(&signal_handler_mask);
	signal_handler_info.sa_handler = filed_signal_handler;
	signal_handler_info.sa_mask = signal_handler_mask;
	signal_handler_info.sa_flags = SA_RESTART;
	sigaction(SIGPIPE, &signal_handler_info, NULL);

	/* Handle SIGHUP to release all caches */
	sigfillset(&signal_handler_mask);
	signal_handler_info.sa_handler = filed_signal_handler;
	signal_handler_info.sa_mask = signal_handler_mask;
	signal_handler_info.sa_flags = 0;
	sigaction(SIGHUP, &signal_handler_info, NULL);

	/* Initialize cache structure */
	cache_ret = filed_init_cache(cache_size);
	if (cache_ret != 0) {
		return(cache_ret);
	}

................................................................................
#define filed_sockettimeout_close(x) /**/
#else
time_t filed_sockettimeout_time;
struct {
	time_t expiration_time;
	pthread_t thread_id;
	int valid;
} *filed_sockettimeout_sockstatus;
long filed_sockettimeout_sockstatus_length;
int filed_sockettimeout_devnull_fd;

static int filed_sockettimeout_sockfd_in_range(int sockfd) {
	if (sockfd < 3) {
		return(0);
	}
................................................................................

	atomic_store(&filed_sockettimeout_sockstatus[sockfd].valid, false);

	return;
}

static void *filed_sockettimeout_thread(void *arg) {
	struct timespec sleep_time;
	time_t now, expiration_time;
	pthread_t thread_id;
	long idx;
	int count;
	int valid;

	while (1) {
		for (count = 0; count < 10; count++) {
			sleep_time.tv_sec = 30;
			sleep_time.tv_nsec = 0;
			nanosleep(&sleep_time, NULL);

			now = time(NULL);

			atomic_store(&filed_sockettimeout_time, now);
		}

		for (idx = 0; idx < filed_sockettimeout_sockstatus_length; idx++) {
................................................................................
	long maxfd, idx;

	maxfd = sysconf(_SC_OPEN_MAX);
	if (maxfd <= 0) {
		maxfd = 4096;
	}

	filed_sockettimeout_sockstatus_length = maxfd;
	filed_sockettimeout_sockstatus = malloc(sizeof(*filed_sockettimeout_sockstatus) * filed_sockettimeout_sockstatus_length);
	if (filed_sockettimeout_sockstatus == NULL) {
		return(-1);
	}

	for (idx = 0; idx < maxfd; idx++) {
		filed_sockettimeout_sockstatus[idx].valid = false;
	}


	filed_sockettimeout_devnull_fd = open("/dev/null", O_RDWR);
	if (filed_sockettimeout_devnull_fd < 0) {
		return(-1);
	}

	return(0);
}
................................................................................

	fclose(fp);

	return;
}

/* Return a redirect to index.html */
#ifndef FILED_DONT_REDIRECT_DIRECTORIES
static void filed_redirect_index(FILE *fp, const char *date_current, const char *path, struct filed_log_entry *log) {
	int http_code = 302;
	fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: 0\r\nConnection: close\r\nLocation: %s\r\n\r\n",
		http_code,
		date_current,
		date_current,
		"index.html"
	);

................................................................................
	fclose(fp);

	return;

	/* Currently unused: path */
	path = path;
}
#endif

/* Convert an enum representing the "Connection" header value to a string */
static const char *filed_connection_str(int connection_value) {
	switch (connection_value) {
		case FILED_CONNECTION_CLOSE:
			return("close");
		case FILED_CONNECTION_KEEP_ALIVE:
................................................................................

	path = request->path;
	strcpy(log->buffer, path);
	log->method = request->method;

	/* If the requested path is a directory, redirect to index page */
	if (request->type == FILED_REQUEST_TYPE_DIRECTORY) {
#ifdef FILED_DONT_REDIRECT_DIRECTORIES
		char localpath[8192];
		int snprintf_ret;

		snprintf_ret = snprintf(localpath, sizeof(localpath), "%s/index.html", path);

		if (snprintf_ret <= 0 || snprintf_ret > (sizeof(localpath) - 1)) {
			filed_error_page(fp, date_current, 500, request->method, "path_format", log);

			return(FILED_CONNECTION_CLOSE);
		}

		path = localpath;
#else
		filed_redirect_index(fp, date_current, path, log);

		return(FILED_CONNECTION_CLOSE);
#endif
	}

	fileinfo = filed_open_file(path, &request->fileinfo, options);
	if (fileinfo == NULL) {
		filed_error_page(fp, date_current, 404, request->method, "open_failed", log);

		return(FILED_CONNECTION_CLOSE);
................................................................................

		return(5);
	}

	/* Wait for threads to exit */
	/* XXX:TODO: Monitor thread usage */
	while (1) {
		sleep(86400);
	}

	/* Return in failure */
	return(2);
}