Project

General

Profile

RE: spawn-fcgi.exe does not appear to work in Windows ยป spawn-fcgi-win32.c

keathmilligan, 2009-01-21 15:15

 
1
#include <sys/types.h>
2
#include <sys/time.h>
3
#include <sys/stat.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include <errno.h>
7
#include <stdio.h>
8
#include <unistd.h>
9
#include <fcntl.h>
10
#include <getopt.h>
11
#include <ws2tcpip.h>
12

    
13
#define FCGI_LISTENSOCK_FILENO 0
14

    
15
#define UNIX_PATH_LEN 108
16

    
17
typedef unsigned short int sa_family_t;
18

    
19
struct sockaddr_un {
20
	sa_family_t	sun_family;              /* address family AF_LOCAL/AF_UNIX */
21
	char		sun_path[UNIX_PATH_LEN]; /* 108 bytes of socket address     */
22
};
23

    
24
/* Evaluates the actual length of `sockaddr_un' structure. */
25
#define SUN_LEN(p) ((size_t)(((struct sockaddr_un *) NULL)->sun_path) \
26
				   + strlen ((p)->sun_path))
27

    
28

    
29
int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned short port, const char *unixsocket, int fork_count, int child_count, int pid_fd, int nofork) {
30
	SOCKET fcgi_fd;
31
	int socket_type, rc = 0;
32

    
33
	struct sockaddr_un fcgi_addr_un;
34
	struct sockaddr_in fcgi_addr_in;
35
	struct sockaddr *fcgi_addr;
36

    
37
	socklen_t servlen;
38

    
39
    WORD  wVersion;
40
    WSADATA wsaData;
41

    
42
    if (child_count < 2) {
43
		child_count = 5;
44
	}
45

    
46
	if (child_count > 256) {
47
		child_count = 256;
48
	}
49

    
50

    
51
	if (unixsocket) {
52
		memset(&fcgi_addr, 0, sizeof(fcgi_addr));
53

    
54
		fcgi_addr_un.sun_family = AF_UNIX;
55
		strcpy(fcgi_addr_un.sun_path, unixsocket);
56

    
57
#ifdef SUN_LEN
58
		servlen = SUN_LEN(&fcgi_addr_un);
59
#else
60
		/* stevens says: */
61
		servlen = strlen(fcgi_addr_un.sun_path) + sizeof(fcgi_addr_un.sun_family);
62
#endif
63
		socket_type = AF_UNIX;
64
		fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
65
	} else {
66
		fcgi_addr_in.sin_family = AF_INET;
67
                if (addr != NULL) {
68
                        fcgi_addr_in.sin_addr.s_addr = inet_addr(addr);
69
                } else {
70
                        fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
71
                }
72
		fcgi_addr_in.sin_port = htons(port);
73
		servlen = sizeof(fcgi_addr_in);
74

    
75
		socket_type = AF_INET;
76
		fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
77
	}
78

    
79
    /*
80
     * Initialize windows sockets library.
81
     */
82
    wVersion = MAKEWORD(2,0);
83
    if (WSAStartup( wVersion, &wsaData )) {
84
		fprintf(stderr, "%s.%d: error %d starting Windows sockets\n",
85
			__FILE__, __LINE__, WSAGetLastError());
86
    }
87

    
88
	if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
89
		fprintf(stderr, "%s.%d\n",
90
			__FILE__, __LINE__);
91
		return -1;
92
	}
93

    
94
	if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
95
		/* server is not up, spawn in  */
96
		int val;
97

    
98
		if (unixsocket) unlink(unixsocket);
99

    
100
		close(fcgi_fd);
101

    
102
		/* reopen socket */
103
		if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
104
			fprintf(stderr, "%s.%d\n",
105
				__FILE__, __LINE__);
106
			return -1;
107
		}
108

    
109
		val = 1;
110
		if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, 	(const char*)&val, sizeof(val)) < 0) {
111
			fprintf(stderr, "%s.%d\n",
112
				__FILE__, __LINE__);
113
			return -1;
114
		}
115

    
116
		/* create socket */
117
		if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
118
			fprintf(stderr, "%s.%d: bind failed: %s\n",
119
				__FILE__, __LINE__,
120
				strerror(errno));
121
			return -1;
122
		}
123

    
124
		if (-1 == listen(fcgi_fd, 1024)) {
125
			fprintf(stderr, "%s.%d: fd = -1\n",
126
				__FILE__, __LINE__);
127
			return -1;
128
		}
129

    
130

    
131
		while (fork_count-- > 0) {
132

    
133
			PROCESS_INFORMATION pi;
134
			STARTUPINFO si;
135

    
136
			ZeroMemory(&si,sizeof(STARTUPINFO));
137
			si.cb = sizeof(STARTUPINFO);
138
			si.dwFlags = STARTF_USESTDHANDLES;
139
			si.hStdOutput = INVALID_HANDLE_VALUE;
140
			si.hStdInput  = (HANDLE)fcgi_fd;
141
			si.hStdError  = INVALID_HANDLE_VALUE;
142
			if (!CreateProcess(NULL,appPath,NULL,NULL,TRUE,	CREATE_NO_WINDOW,NULL,NULL,&si,&pi)) {
143
				fprintf(stderr, "%s.%d: CreateProcess failed\n",
144
					__FILE__, __LINE__);
145
				return -1;
146
			} else {
147
				fprintf(stdout, "%s.%d: child spawned successfully: PID: %lu\n",
148
					__FILE__, __LINE__,
149
					pi.dwProcessId);
150
				CloseHandle(pi.hThread);
151
			}
152

    
153
		}
154

    
155
	} else {
156
		fprintf(stderr, "%s.%d: socket is already used, can't spawn\n",
157
			__FILE__, __LINE__);
158
		return -1;
159
	}
160

    
161

    
162
	closesocket(fcgi_fd);
163

    
164
	return rc;
165
}
166

    
167

    
168
void show_version () {
169
	char *b = "spawn-fcgi-win32 - spawns fastcgi processes\n";
170
	write(1, b, strlen(b));
171
}
172

    
173
void show_help () {
174
	char *b =
175
"Usage: spawn-fcgi [options] -- <fcgiapp> [fcgi app arguments]\n"
176
"\n"
177
"spawn-fcgi-win32 - spawns fastcgi processes\n"
178
"\n"
179
"Options:\n"
180
" -f <fcgiapp> filename of the fcgi-application\n"
181
" -a <addr>    bind to ip address\n"
182
" -p <port>    bind to tcp-port\n"
183
" -s <path>    bind to unix-domain socket\n"
184
" -C <childs>  (PHP only) numbers of childs to spawn (default 5)\n"
185
" -F <childs>  numbers of childs to fork (default 1)\n"
186
" -P <path>    name of PID-file for spawed process\n"
187
" -n           no fork (for daemontools)\n"
188
" -v           show version\n"
189
" -h           show this help\n"
190
"(root only)\n"
191
" -c <dir>     chroot to directory\n"
192
" -u <user>    change to user-id\n"
193
" -g <group>   change to group-id\n"
194
;
195
	write(1, b, strlen(b));
196
}
197

    
198

    
199
int main(int argc, char **argv) {
200
	char *fcgi_app = NULL, *unixsocket = NULL, *pid_file = NULL,
201
                *addr = NULL;
202
	char **fcgi_app_argv = { NULL };
203
	unsigned short port = 0;
204
	int child_count = 5;
205
	int fork_count = 1;
206
	int pid_fd = -1;
207
	int nofork = 0;
208
	int o;
209
	struct sockaddr_un un;
210

    
211
	while (-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:F:s:P:"))) {
212
		switch(o) {
213
		case 'f': fcgi_app = optarg; break;
214
		case 'a': addr = optarg;/* ip addr */ break;
215
		case 'p': port = strtol(optarg, NULL, 10);/* port */ break;
216
		case 'C': child_count = strtol(optarg, NULL, 10);/*  */ break;
217
		case 'F': fork_count = strtol(optarg, NULL, 10);/*  */ break;
218
		case 's': unixsocket = optarg; /* unix-domain socket */ break;
219
		case 'n': nofork = 1; break;
220
		case 'P': pid_file = optarg; /* PID file */ break;
221
		case 'v': show_version(); return 0;
222
		case 'h': show_help(); return 0;
223
		default:
224
			show_help();
225
			return -1;
226
		}
227
	}
228

    
229
	if (optind < argc) {
230
		fcgi_app_argv = &argv[optind];
231
	}
232

    
233
	if ((fcgi_app == NULL && fcgi_app_argv == NULL) || (port == 0 && unixsocket == NULL)) {
234
		show_help();
235
		return -1;
236
	}
237

    
238
	if (unixsocket && port) {
239
		fprintf(stderr, "%s.%d: %s\n",
240
			__FILE__, __LINE__,
241
			"either a unix domain socket or a tcp-port, but not both\n");
242

    
243
		return -1;
244
	}
245

    
246
	if (unixsocket && strlen(unixsocket) > sizeof(un.sun_path) - 1) {
247
		fprintf(stderr, "%s.%d: %s\n",
248
			__FILE__, __LINE__,
249
			"path of the unix socket is too long\n");
250

    
251
		return -1;
252
	}
253

    
254
	if (pid_file &&
255
	    (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC)))) {
256
		struct stat st;
257
		if (errno != EEXIST) {
258
			fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
259
				__FILE__, __LINE__,
260
				pid_file, strerror(errno));
261

    
262
			return -1;
263
		}
264

    
265
		/* ok, file exists */
266

    
267
		if (0 != stat(pid_file, &st)) {
268
			fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
269
				__FILE__, __LINE__,
270
				pid_file, strerror(errno));
271

    
272
			return -1;
273
		}
274

    
275
		/* is it a regular file ? */
276

    
277
		if (!S_ISREG(st.st_mode)) {
278
			fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
279
				__FILE__, __LINE__,
280
				pid_file);
281

    
282
			return -1;
283
		}
284

    
285
		if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC))) {
286
			fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
287
				__FILE__, __LINE__,
288
				pid_file, strerror(errno));
289

    
290
			return -1;
291
		}
292
	}
293

    
294
    return fcgi_spawn_connection(fcgi_app, fcgi_app_argv, addr, port, unixsocket, fork_count, child_count, pid_fd, nofork);
295
}
    (1-1/1)