Browse Source

PyFCGI now handles fcgi socket creation

Add a -l --listen option to set the socket path or address:port
Fix a bug using thread safe functions from libfcgi
Yann Weber 4 years ago
parent
commit
f685f83369
7 changed files with 70 additions and 11 deletions
  1. 3
    3
      README
  2. 9
    4
      docs/man/man1/pyfcgi.1
  3. 16
    1
      include/conf.h
  4. 4
    0
      src/conf.c
  5. 4
    1
      src/main.c
  6. 18
    2
      src/pyworker.c
  7. 16
    0
      src/responder.c

+ 3
- 3
README View File

@@ -9,10 +9,10 @@ Building & running pyfcgi :
9 9
 	$ ./configure
10 10
 	$ make
11 11
 	# To run foo_pep333.entrypoint() PEP333 application
12
-	$ spawn-fcgi -d . -n -p 9000 -a 127.0.0.1 -- src/pyfcgi -S -e foo_pep333 -E entrypoint
12
+	$ src/pyfcgi -l '127.0.0.1:9000' -S -e foo_pep333 -E entrypoint
13 13
 or
14 14
 	# To run foo.entrypoint() sending to FCGI python stdout
15
-	$ spawn-fcgi -d . -n -p 9000 -a 127.0.0.1 -- src/pyfcgi -S -e foo -E entrypoint -A
15
+	$ src/pyfcgi -l '127.0.0.1:9000' -S -e foo -E entrypoint -A
16 16
 
17 17
 
18 18
 configure script determine python flags, libs & includes paths using
@@ -23,7 +23,7 @@ Example : linking against a debug build of python :
23 23
 ---------
24 24
 	$ ./configure PYTHON_CONFIG_PATH=/usr/bin/python3dm-config --enable-debug
25 25
 	$ make clean && make
26
-	$ valgrind --log-file=/tmp/val.log --trace-children=yes spawn-fcgi -d . -n -p 9000 -a 127.0.0.1 -- src/pyfcgi -S -e foo_pep333 -E entrypoint -L '/tmp/foo.log;0xff;{datetime} {msg} {ident}'
26
+	$ valgrind --log-file=/tmp/val.log --trace-children=yes src/pyfcgi -S -e foo_pep333 -E entrypoint -L '/tmp/foo.log;0xff;{datetime} {msg} {ident}'
27 27
 
28 28
 logging to file example :
29 29
 -------------------------

+ 9
- 4
docs/man/man1/pyfcgi.1 View File

@@ -1,4 +1,4 @@
1
-.TH "pyfcgi" 1 "Sat Aug 24 2019" "Version 0.0.1" "PyFCGI" \" -*- nroff -*-
1
+.TH "pyfcgi" 1 "Mon Oct 28 2019" "Version 0.0.1" "PyFCGI" \" -*- nroff -*-
2 2
 .ad l
3 3
 .nh
4 4
 .SH NAME
@@ -24,11 +24,16 @@ Display help and exit
24 24
 Display pyfcgi and Python version and exit 
25 25
 .RE
26 26
 .PP
27
-\fB-c --config=FILE\fP
27
+\fB-C --config=FILE\fP
28 28
 .RS 4
29 29
 load a configuration file 
30 30
 .RE
31 31
 .PP
32
+\fB-l --listen=SOCK_PATH\fP
33
+.RS 4
34
+fcgi listen socket path\&. For TCP socket use 'IPv4:PORT' syntax ( '127\&.0\&.0\&.1:9000' by default) 
35
+.RE
36
+.PP
32 37
 \fB-e --pymodule=MODULE_NAME\fP
33 38
 .RS 4
34 39
 python entrypoint module name 
@@ -134,11 +139,11 @@ unix with HOST a valid PATH
134 139
 .PP
135 140
 To run foo_pep333\&.entrypoint() PEP333 application :
136 141
 .PP
137
-spawn-fcgi -d \&. -n -p 9000 -a 127\&.0\&.0\&.1 -- src/pyfcgi -S \\ -e foo_pep333 -E entrypoint
142
+spawn-fcgi -d \&. -n -p 9000 -a 127\&.0\&.0\&.1 -- src/pyfcgi -S -e foo_pep333 -E entrypoint
138 143
 .PP
139 144
 Logfile example :
140 145
 .PP
141
-spawn-fcgi -d \&. -n -p 9000 -a 127\&.0\&.0\&.1 -- src/pyfcgi -S \\ -e foo_pep333 -E entrypoint \\ -L '/tmp/foo\&.log;0xff;{datetime} {msg} {ident}'
146
+spawn-fcgi -d \&. -n -p 9000 -a 127\&.0\&.0\&.1 -- src/pyfcgi -S -e foo_pep333 -E entrypoint -L '/tmp/foo\&.log;0xff;{datetime} {msg} {ident}'
142 147
 .SH "AUTHOR"
143 148
 .PP
144 149
 Written by Yann Weber <yann.weber@member.fsf.org>

+ 16
- 1
include/conf.h View File

@@ -74,12 +74,16 @@ pyfcgi_conf_t PyFCGI_conf;
74 74
 /**@ingroup ret_status */
75 75
 #define PYFCGI_FATAL 128
76 76
 
77
+/**@brief Backlog argument for socket creation */
78
+#define PYFCGI_SOCK_BACKLOG 100
79
+
77 80
 #define PYFCGI_NAME "spawn-fcgi [OPTIONS] -- pyfcgi"
78 81
 
79
-#define PYFCGI_SHORT_OPT "Ce:E:Aw:W:m:ft:L:SPs:vVh"
82
+#define PYFCGI_SHORT_OPT "C:l:e:E:Aw:W:m:ft:L:SPs:vVh"
80 83
 
81 84
 #define PYFCGI_LONG_OPT { \
82 85
 	{"config", required_argument, 0, 'C'},\
86
+	{"listen", required_argument, 0, 'l'},\
83 87
 	{"pymodule", required_argument, 0, 'e'},\
84 88
 	{"pyapp", required_argument, 0, 'E'},\
85 89
 	{"alt-io", no_argument, 0, 'A'},\
@@ -100,6 +104,7 @@ pyfcgi_conf_t PyFCGI_conf;
100 104
 
101 105
 #define PYFCGI_OPT_HELP {\
102 106
 	{"Load options from configuration file", "CONFIG"},\
107
+	{"Listen socket path (a path for UNIX socket or a 'IPV4:PORT' string)", "SOCK_PATH"},\
103 108
 	{"Search application function in given python module", "MODULE_NAME"},\
104 109
 	{"Python application entrypoint function name", "FUNC_NAME"},\
105 110
 	{"Use stdout to communicate with web server instead of entrypoint return as specified in PEP 333", NULL},\
@@ -176,6 +181,12 @@ struct pyfcgi_context_s {
176 181
 	/**@brief Stores parent process PID */
177 182
 	pid_t ppid;
178 183
 
184
+	/**@brief Returned by FCGX_OpenSocket for responder process */
185
+	int fcgi_socket;
186
+
187
+	/**@brief Request information (local to each worker) */
188
+	FCGX_Request fcgi_request;
189
+
179 190
 	/**@brief Stores the watchdog timer */
180 191
 	timer_t wd_timer;
181 192
 	/**@brief Security timer sending a sigkill */
@@ -215,6 +226,10 @@ struct pyfcgi_conf_s
215 226
 	/** @brief Stores pidfile path */
216 227
 	char *pidfile;
217 228
 
229
+	/**@brief Stores the socket path argument
230
+	 * @ingroup conf_glob
231
+	 * Can be a file path for a UNIX socket or IPv4:PORT string */
232
+	char *sock_path;
218 233
 	/**@brief Entrypoint module name
219 234
 	 * @ingroup conf_glob */
220 235
 	char *py_entrymod;

+ 4
- 0
src/conf.c View File

@@ -40,6 +40,7 @@ void print_version(int fd)
40 40
 void default_conf()
41 41
 {
42 42
 	memset(&PyFCGI_conf, 0, sizeof(pyfcgi_conf_t));
43
+	PyFCGI_conf.sock_path = "127.0.0.1:9000";
43 44
 	PyFCGI_conf.context.pid = getpid();
44 45
 	PyFCGI_conf.min_wrk = 1;
45 46
 	PyFCGI_conf.max_wrk = 5;
@@ -72,6 +73,9 @@ int parse_args(int argc, char *argv[])
72 73
 			case 'C':
73 74
 				dprintf(2, "Config parser not yet implemented :'(\n");
74 75
 				exit(1);
76
+			case 'l':
77
+				PyFCGI_conf.sock_path = strdup(optarg);
78
+				break;
75 79
 			case 'e':
76 80
 				PyFCGI_conf.py_entrymod = strdup(optarg);
77 81
 				break;

+ 4
- 1
src/main.c View File

@@ -362,8 +362,11 @@ if ($programname contains 'pyfcgi') then {
362 362
  * Display help and exit
363 363
  * @par -V --version
364 364
  * Display pyfcgi and Python version and exit
365
- * @par -c --config=FILE
365
+ * @par -C --config=FILE
366 366
  * load a configuration file
367
+ * @par -l --listen=SOCK_PATH
368
+ * fcgi listen socket path. For TCP socket use "IPv4:PORT" syntax (
369
+ * "127.0.0.1:9000" by default)
367 370
  * @par -e --pymodule=MODULE_NAME
368 371
  * python entrypoint module name
369 372
  * @par -E --pyapp=FUNC_NAME

+ 18
- 2
src/pyworker.c View File

@@ -46,6 +46,7 @@ int work333(int wrk_id)
46 46
 	int count, pipe_out[2], pipe_err[2];
47 47
 	int max_reqs;
48 48
 	struct timeval start, stop;
49
+	FCGX_Request *request;
49 50
 
50 51
 	max_reqs = PyFCGI_conf.max_reqs;
51 52
 
@@ -72,13 +73,28 @@ int work333(int wrk_id)
72 73
 
73 74
 	start_response = get_start_response();
74 75
 
76
+	// Initialise FCGI request
77
+	request = &(PyFCGI_conf.context.fcgi_request);
78
+	if(FCGX_InitRequest(request, PyFCGI_conf.context.fcgi_socket,
79
+		FCGI_FAIL_ACCEPT_ON_INTR) == -1)
80
+	{
81
+		pyfcgi_log(LOG_ALERT, "Unable to init FCGI request");
82
+		exit(PYFCGI_FATAL);
83
+	}
84
+
75 85
 	_worker_idle = 0;
76 86
 	worker_set_idle();
77 87
 	// requests accepting loop
78 88
 	count = 0;
79 89
 	while ((!count || count != max_reqs) &&
80
-		FCGX_Accept(&in_stream, &out_stream, &err_stream, &envp) >= 0)
90
+		FCGX_Accept_r(request) == 0)
81 91
 	{
92
+		
93
+		in_stream = request->in;
94
+		out_stream = request->out;
95
+		err_stream = request->err;
96
+		envp = request->envp;
97
+
82 98
 		pyfcgi_wd_arm();
83 99
 		sem_post(PyFCGI_SEM(SEM_WREQS).sem); // increment request counter discarding OF
84 100
 		gettimeofday(&start, NULL);
@@ -136,7 +152,7 @@ int work333(int wrk_id)
136 152
 		FCGX_FClose(out_stream);
137 153
 		FCGX_FClose(in_stream);
138 154
 		FCGX_FClose(err_stream);
139
-		FCGI_Finish();
155
+		FCGX_Finish_r(request);
140 156
 
141 157
 		gettimeofday(&stop, NULL);
142 158
 		stop.tv_sec = stop.tv_sec - start.tv_sec;

+ 16
- 0
src/responder.c View File

@@ -92,6 +92,22 @@ void init_context()
92 92
 	}
93 93
 	bzero(PyFCGI_conf.context.wrk_pids,
94 94
 		sizeof(pid_t) * (PyFCGI_conf.max_wrk + 1));
95
+	
96
+	// Open FCGI listen socket
97
+	PyFCGI_conf.context.fcgi_socket = FCGX_OpenSocket(PyFCGI_conf.sock_path,
98
+		PYFCGI_SOCK_BACKLOG);
99
+	if(PyFCGI_conf.context.fcgi_socket == -1)
100
+	{
101
+		pyfcgi_log(LOG_ALERT, "Unable to open socket : '%s'",
102
+			PyFCGI_conf.sock_path);
103
+		clean_exit(PYFCGI_FATAL);
104
+	}
105
+	if(FCGX_Init() != 0)
106
+	{
107
+		pyfcgi_log(LOG_ALERT, "Unable to init libfcgi");
108
+		clean_exit(PYFCGI_FATAL);
109
+	}
110
+	pyfcgi_log(LOG_INFO, "Listening on %s", PyFCGI_conf.sock_path);
95 111
 }
96 112
 
97 113
 int responder_loop()

Loading…
Cancel
Save