]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ipc_win32.cc
RFC2616 obsoleted by RFC 7230 et al
[thirdparty/squid.git] / src / ipc_win32.cc
CommitLineData
b5d712b5 1/*
b5d712b5 2 * DEBUG: section 54 Windows Interprocess Communication
1b52df9a 3 * AUTHOR: Andrey Shorin <tolsty@tushino.com>
4 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
b5d712b5 5 *
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
8 *
9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
26ac0430 22 *
b5d712b5 23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
26ac0430 27 *
b5d712b5 28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
31 *
32 */
33
582c2af2 34#include "squid.h"
8a01b99e 35#include "cache_cf.h"
b5d712b5 36#include "comm.h"
c4ad1349 37#include "fd.h"
b5d712b5 38#include "fde.h"
a13c93d1
C
39#include "ip/Address.h"
40#include "rfc1738.h"
4d5904f7 41#include "SquidConfig.h"
96097880 42#include "SquidIpc.h"
b5d712b5 43#include "SquidTime.h"
a8e49d54 44#include "tools.h"
b5d712b5 45
1a30fdf5 46#include <cerrno>
b5d712b5 47#ifndef _MSWSOCK_
48#include <mswsock.h>
49#endif
50#include <process.h>
51
26ac0430 52struct ipc_params {
b5d712b5 53 int type;
54 int crfd;
55 int cwfd;
b7ac5457 56 Ip::Address local_addr;
cc192b50 57 struct addrinfo PS;
b5d712b5 58 const char *prog;
59 char **args;
60};
61
26ac0430 62struct thread_params {
b5d712b5 63 int type;
64 int rfd;
65 int send_fd;
66 const char *prog;
67 pid_t pid;
68};
69
70static unsigned int __stdcall ipc_thread_1(void *params);
71static unsigned int __stdcall ipc_thread_2(void *params);
72
73static const char *ok_string = "OK\n";
74static const char *err_string = "ERR\n";
75static const char *shutdown_string = "$shutdown\n";
76
77static const char *hello_string = "hi there\n";
78#define HELLO_BUF_SZ 32
79static char hello_buf[HELLO_BUF_SZ];
80
81static int
82ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
83{
84 if (prfd >= 0)
85 comm_close(prfd);
86
87 if (prfd != pwfd)
88 if (pwfd >= 0)
89 comm_close(pwfd);
90
91 if (crfd >= 0)
92 comm_close(crfd);
93
94 if (crfd != cwfd)
95 if (cwfd >= 0)
96 comm_close(cwfd);
97
98 return -1;
99}
100
101static void
102PutEnvironment()
103{
104#if HAVE_PUTENV
105 char *env_str;
106 int tmp_s;
62493678
AJ
107 env_str = (char *)xcalloc((tmp_s = strlen(Debug::debugOptions) + 32), 1);
108 snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Debug::debugOptions);
b5d712b5 109 putenv(env_str);
110#endif
111}
112
113pid_t
b7ac5457 114ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc)
b5d712b5 115{
116 unsigned long thread;
117
118 struct ipc_params params;
119 int opt;
120 int optlen = sizeof(opt);
121 DWORD ecode = 0;
122 pid_t pid;
123
b7ac5457 124 Ip::Address tmp_addr;
cc192b50 125 struct addrinfo *aiCS = NULL;
126 struct addrinfo *aiPS = NULL;
b5d712b5 127
b5d712b5 128 int crfd = -1;
129 int prfd = -1;
130 int cwfd = -1;
131 int pwfd = -1;
b5d712b5 132 int x;
133
134 requirePathnameExists(name, prog);
135
136 if (rfd)
137 *rfd = -1;
138
139 if (wfd)
140 *wfd = -1;
141
142 if (hIpc)
143 *hIpc = NULL;
144
145 if (WIN32_OS_version != _WIN_OS_WINNT) {
146 getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
147 opt = opt & ~(SO_SYNCHRONOUS_NONALERT | SO_SYNCHRONOUS_ALERT);
148 setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, sizeof(opt));
149 }
150
151 if (type == IPC_TCP_SOCKET) {
152 crfd = cwfd = comm_open(SOCK_STREAM,
153 IPPROTO_TCP,
154 local_addr,
b5d712b5 155 COMM_NOCLOEXEC,
156 name);
157 prfd = pwfd = comm_open(SOCK_STREAM,
158 IPPROTO_TCP, /* protocol */
159 local_addr,
b5d712b5 160 0, /* blocking */
161 name);
162 } else if (type == IPC_UDP_SOCKET) {
163 crfd = cwfd = comm_open(SOCK_DGRAM,
164 IPPROTO_UDP,
165 local_addr,
b5d712b5 166 COMM_NOCLOEXEC,
167 name);
168 prfd = pwfd = comm_open(SOCK_DGRAM,
169 IPPROTO_UDP,
170 local_addr,
171 0,
b5d712b5 172 name);
173 } else if (type == IPC_FIFO) {
fa84c01d 174 debugs(54, DBG_CRITICAL, "ipcCreate: " << prog << ": use IPC_TCP_SOCKET instead of IP_FIFO on Windows");
b5d712b5 175 assert(0);
176 } else {
177 assert(IPC_NONE);
178 }
179
bf8fe701 180 debugs(54, 3, "ipcCreate: prfd FD " << prfd);
181 debugs(54, 3, "ipcCreate: pwfd FD " << pwfd);
182 debugs(54, 3, "ipcCreate: crfd FD " << crfd);
183 debugs(54, 3, "ipcCreate: cwfd FD " << cwfd);
b5d712b5 184
185 if (WIN32_OS_version != _WIN_OS_WINNT) {
186 getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
187 opt = opt | SO_SYNCHRONOUS_NONALERT;
188 setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen);
189 }
190
191 if (crfd < 0) {
fa84c01d 192 debugs(54, DBG_CRITICAL, "ipcCreate: Failed to create child FD.");
b5d712b5 193 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
194 }
195
196 if (pwfd < 0) {
fa84c01d 197 debugs(54, DBG_CRITICAL, "ipcCreate: Failed to create server FD.");
b5d712b5 198 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
199 }
200
cc192b50 201// AYJ: these flags should be neutral, but if not IPv6 version needs adding
b5d712b5 202 if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
b5d712b5 203
4dd643d5 204 Ip::Address::InitAddrInfo(aiPS);
cc192b50 205
206 if (getsockname(pwfd, aiPS->ai_addr, &(aiPS->ai_addrlen) ) < 0) {
fa84c01d 207 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
4dd643d5 208 Ip::Address::FreeAddrInfo(aiPS);
b5d712b5 209 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
210 }
211
cc192b50 212 tmp_addr = *aiPS;
4dd643d5 213 Ip::Address::FreeAddrInfo(aiPS);
cc192b50 214
215 debugs(54, 3, "ipcCreate: FD " << pwfd << " sockaddr " << tmp_addr );
b5d712b5 216
4dd643d5 217 Ip::Address::InitAddrInfo(aiCS);
cc192b50 218
219 if (getsockname(crfd, aiCS->ai_addr, &(aiCS->ai_addrlen) ) < 0) {
fa84c01d 220 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
4dd643d5 221 Ip::Address::FreeAddrInfo(aiCS);
b5d712b5 222 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
223 }
224
4dd643d5 225 tmp_addr.setEmpty();
cc192b50 226 tmp_addr = *aiCS;
4dd643d5 227 Ip::Address::FreeAddrInfo(aiCS);
cc192b50 228
229 debugs(54, 3, "ipcCreate: FD " << crfd << " sockaddr " << tmp_addr );
b5d712b5 230 }
231
232 if (type == IPC_TCP_SOCKET) {
233 if (listen(crfd, 1) < 0) {
e0236918 234 debugs(54, DBG_IMPORTANT, "ipcCreate: listen FD " << crfd << ": " << xstrerror());
b5d712b5 235 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
236 }
237
bf8fe701 238 debugs(54, 3, "ipcCreate: FD " << crfd << " listening...");
b5d712b5 239 }
240
241 /* flush or else we get dup data if unbuffered_logs is set */
242 logsFlush();
243
244 params.type = type;
245
246 params.crfd = crfd;
247
248 params.cwfd = cwfd;
249
cc192b50 250 params.PS = *aiPS;
26ac0430 251
cc192b50 252 params.local_addr = local_addr;
b5d712b5 253
254 params.prog = prog;
255
256 params.args = (char **) args;
257
258 thread = _beginthreadex(NULL, 0, ipc_thread_1, &params, 0, NULL);
259
260 if (thread == 0) {
e0236918 261 debugs(54, DBG_IMPORTANT, "ipcCreate: _beginthread: " << xstrerror());
b5d712b5 262 return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
263 }
264
b7ac5457 265 /* NP: tmp_addr was left with eiether empty or aiCS in Ip::Address format */
c8407295 266 if (comm_connect_addr(pwfd, tmp_addr) == Comm::ERROR) {
b5d712b5 267 CloseHandle((HANDLE) thread);
268 return ipcCloseAllFD(prfd, pwfd, -1, -1);
269 }
270
271 memset(hello_buf, '\0', HELLO_BUF_SZ);
272 x = recv(prfd, (void *)hello_buf, HELLO_BUF_SZ - 1, 0);
273
274 if (x < 0) {
fa84c01d
FC
275 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed");
276 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
b5d712b5 277 CloseHandle((HANDLE) thread);
278 return ipcCloseAllFD(prfd, pwfd, -1, -1);
279 } else if (strcmp(hello_buf, hello_string)) {
fa84c01d
FC
280 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: hello read test failed");
281 debugs(54, DBG_CRITICAL, "--> read returned " << x);
282 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'");
b5d712b5 283 CloseHandle((HANDLE) thread);
284 return ipcCloseAllFD(prfd, pwfd, -1, -1);
285 }
286
287 x = send(pwfd, (const void *)ok_string, strlen(ok_string), 0);
288
289 if (x < 0) {
fa84c01d
FC
290 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: OK write test failed");
291 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
b5d712b5 292 CloseHandle((HANDLE) thread);
293 return ipcCloseAllFD(prfd, pwfd, -1, -1);
294 }
295
296 memset(hello_buf, '\0', HELLO_BUF_SZ);
297 x = recv(prfd, (void *)hello_buf, HELLO_BUF_SZ - 1, 0);
298
299 if (x < 0) {
fa84c01d
FC
300 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: OK read test failed");
301 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
b5d712b5 302 CloseHandle((HANDLE) thread);
303 return ipcCloseAllFD(prfd, pwfd, -1, -1);
304 } else if (!strcmp(hello_buf, err_string)) {
fa84c01d
FC
305 debugs(54, DBG_CRITICAL, "ipcCreate: PARENT: OK read test failed");
306 debugs(54, DBG_CRITICAL, "--> read returned " << x);
307 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'");
b5d712b5 308 CloseHandle((HANDLE) thread);
309 return ipcCloseAllFD(prfd, pwfd, -1, -1);
310 }
311
312 hello_buf[x] = '\0';
313 pid = atol(hello_buf);
933dd095 314 commUnsetFdTimeout(prfd);
b5d712b5 315 commSetNonBlocking(prfd);
316 commSetNonBlocking(pwfd);
317 commSetCloseOnExec(prfd);
318 commSetCloseOnExec(pwfd);
319
320 if (rfd)
321 *rfd = prfd;
322
323 if (wfd)
324 *wfd = pwfd;
325
be4d35dc
FC
326 fd_table[prfd].flags.ipc = true;
327 fd_table[pwfd].flags.ipc = true;
328 fd_table[crfd].flags.ipc = true;
329 fd_table[cwfd].flags.ipc = true;
b5d712b5 330
331 if (Config.sleep_after_fork) {
332 /* XXX emulation of usleep() */
333 DWORD sl;
334 sl = Config.sleep_after_fork / 1000;
335
336 if (sl == 0)
337 sl = 1;
338
339 Sleep(sl);
340 }
341
342 if (GetExitCodeThread((HANDLE) thread, &ecode) && ecode == STILL_ACTIVE) {
343 if (hIpc)
344 *hIpc = (HANDLE) thread;
345
346 return pid;
347 } else {
348 CloseHandle((HANDLE) thread);
349 return ipcCloseAllFD(prfd, pwfd, -1, -1);
350 }
351}
352
353static int
354ipcSend(int cwfd, const char *buf, int len)
355{
356 int x;
357
358 x = send(cwfd, (const void *)buf, len, 0);
359
360 if (x < 0) {
fa84c01d
FC
361 debugs(54, DBG_CRITICAL, "sendto FD " << cwfd << ": " << xstrerror());
362 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed");
b5d712b5 363 }
364
365 return x;
366}
367
368static unsigned int __stdcall
369ipc_thread_1(void *in_params)
370{
371 int t1, t2, t3, retval = -1;
26ac0430
AJ
372 int p2c[2] = {-1, -1};
373 int c2p[2] = {-1, -1};
b5d712b5 374 HANDLE hProcess = NULL, thread = NULL;
375 pid_t pid = -1;
376
377 struct thread_params thread_params;
378 ssize_t x;
cc192b50 379 int fd = -1;
b5d712b5 380 char *str;
381 STARTUPINFO si;
382 PROCESS_INFORMATION pi;
383 long F;
384 int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1;
385 char *prog = NULL, *buf1 = NULL;
386
b7ac5457
AJ
387 Ip::Address PS_ipc;
388 Ip::Address CS_ipc;
cc192b50 389 struct addrinfo *aiPS_ipc = NULL;
390 struct addrinfo *aiCS_ipc = NULL;
b5d712b5 391
392 struct ipc_params *params = (struct ipc_params *) in_params;
393 int type = params->type;
394 int crfd = params->crfd;
395 int cwfd = params->cwfd;
396 char **args = params->args;
397
b7ac5457
AJ
398 Ip::Address PS = params->PS;
399 Ip::Address local_addr = params->local_addr;
26ac0430 400
b5d712b5 401 buf1 = (char *)xcalloc(1, 8192);
402 strcpy(buf1, params->prog);
403 prog = strtok(buf1, w_space);
404
405 if ((str = strrchr(prog, '/')))
406 prog = ++str;
407
408 if ((str = strrchr(prog, '\\')))
409 prog = ++str;
410
411 prog = xstrdup(prog);
412
413 if (type == IPC_TCP_SOCKET) {
bf8fe701 414 debugs(54, 3, "ipcCreate: calling accept on FD " << crfd);
b5d712b5 415
416 if ((fd = accept(crfd, NULL, NULL)) < 0) {
fa84c01d 417 debugs(54, DBG_CRITICAL, "ipcCreate: FD " << crfd << " accept: " << xstrerror());
b5d712b5 418 goto cleanup;
419 }
420
bf8fe701 421 debugs(54, 3, "ipcCreate: CHILD accepted new FD " << fd);
b5d712b5 422 comm_close(crfd);
423 snprintf(buf1, 8191, "%s CHILD socket", prog);
424 fd_open(fd, FD_SOCKET, buf1);
425 fd_table[fd].flags.ipc = 1;
426 cwfd = crfd = fd;
427 } else if (type == IPC_UDP_SOCKET) {
c8407295 428 if (comm_connect_addr(crfd, params->PS) == Comm::ERROR)
b5d712b5 429 goto cleanup;
430 }
431
432 x = send(cwfd, (const void *)hello_string, strlen(hello_string) + 1, 0);
433
434 if (x < 0) {
fa84c01d
FC
435 debugs(54, DBG_CRITICAL, "sendto FD " << cwfd << ": " << xstrerror());
436 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: hello write test failed");
b5d712b5 437 goto cleanup;
438 }
439
440 PutEnvironment();
441 memset(buf1, '\0', sizeof(buf1));
442 x = recv(crfd, (void *)buf1, 8191, 0);
443
444 if (x < 0) {
fa84c01d
FC
445 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: OK read test failed");
446 debugs(54, DBG_CRITICAL, "--> read: " << xstrerror());
b5d712b5 447 goto cleanup;
448 } else if (strcmp(buf1, ok_string)) {
fa84c01d
FC
449 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: OK read test failed");
450 debugs(54, DBG_CRITICAL, "--> read returned " << x);
451 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(hello_buf) << "'");
b5d712b5 452 goto cleanup;
453 }
454
455 /* assign file descriptors to child process */
456 if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
fa84c01d 457 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: pipe: " << xstrerror());
b5d712b5 458 ipcSend(cwfd, err_string, strlen(err_string));
459 goto cleanup;
460 }
461
462 if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
fa84c01d 463 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: pipe: " << xstrerror());
b5d712b5 464 ipcSend(cwfd, err_string, strlen(err_string));
465 goto cleanup;
466 }
467
468 if (type == IPC_UDP_SOCKET) {
469 snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1L);
cc192b50 470 crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, buf1);
b5d712b5 471
472 if (crfd_ipc < 0) {
fa84c01d 473 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: Failed to create child FD for " << prog << ".");
b5d712b5 474 ipcSend(cwfd, err_string, strlen(err_string));
475 goto cleanup;
476 }
477
478 snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1L);
cc192b50 479 prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, buf1);
b5d712b5 480
481 if (pwfd_ipc < 0) {
fa84c01d 482 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: Failed to create server FD for " << prog << ".");
b5d712b5 483 ipcSend(cwfd, err_string, strlen(err_string));
484 goto cleanup;
485 }
486
4dd643d5 487 Ip::Address::InitAddrInfo(aiPS_ipc);
b5d712b5 488
cc192b50 489 if (getsockname(pwfd_ipc, aiPS_ipc->ai_addr, &(aiPS_ipc->ai_addrlen)) < 0) {
fa84c01d 490 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
b5d712b5 491 ipcSend(cwfd, err_string, strlen(err_string));
4dd643d5 492 Ip::Address::FreeAddrInfo(aiPS_ipc);
b5d712b5 493 goto cleanup;
494 }
495
cc192b50 496 PS_ipc = *aiPS_ipc;
4dd643d5 497 Ip::Address::FreeAddrInfo(aiPS_ipc);
cc192b50 498
499 debugs(54, 3, "ipcCreate: FD " << pwfd_ipc << " sockaddr " << PS_ipc);
bf8fe701 500
4dd643d5 501 Ip::Address::InitAddrInfo(aiCS_ipc);
b5d712b5 502
cc192b50 503 if (getsockname(crfd_ipc, aiCS_ipc->ai_addr, &(aiCS_ipc->ai_addrlen)) < 0) {
fa84c01d 504 debugs(54, DBG_CRITICAL, "ipcCreate: getsockname: " << xstrerror());
b5d712b5 505 ipcSend(cwfd, err_string, strlen(err_string));
4dd643d5 506 Ip::Address::FreeAddrInfo(aiCS_ipc);
b5d712b5 507 goto cleanup;
508 }
509
cc192b50 510 CS_ipc = *aiCS_ipc;
4dd643d5 511 Ip::Address::FreeAddrInfo(aiCS_ipc);
cc192b50 512
513 debugs(54, 3, "ipcCreate: FD " << crfd_ipc << " sockaddr " << CS_ipc);
b5d712b5 514
c8407295 515 if (comm_connect_addr(pwfd_ipc, CS_ipc) == Comm::ERROR) {
b5d712b5 516 ipcSend(cwfd, err_string, strlen(err_string));
517 goto cleanup;
518 }
519
520 fd = crfd;
521
c8407295 522 if (comm_connect_addr(crfd_ipc, PS_ipc) == Comm::ERROR) {
b5d712b5 523 ipcSend(cwfd, err_string, strlen(err_string));
524 goto cleanup;
525 }
526 } /* IPC_UDP_SOCKET */
527
528 t1 = dup(0);
529
530 t2 = dup(1);
531
532 t3 = dup(2);
533
534 dup2(c2p[0], 0);
535
536 dup2(p2c[1], 1);
537
538 dup2(fileno(debug_log), 2);
539
540 close(c2p[0]);
541
542 close(p2c[1]);
543
544 commUnsetNonBlocking(fd);
545
546 memset(&si, 0, sizeof(STARTUPINFO));
547
548 si.cb = sizeof(STARTUPINFO);
549
550 si.hStdInput = (HANDLE) _get_osfhandle(0);
551
552 si.hStdOutput = (HANDLE) _get_osfhandle(1);
553
554 si.hStdError = (HANDLE) _get_osfhandle(2);
555
556 si.dwFlags = STARTF_USESTDHANDLES;
557
558 /* Make sure all other valid handles are not inerithable */
95dc7ff4 559 for (x = 3; x < Squid_MaxFD; ++x) {
b5d712b5 560 if ((F = _get_osfhandle(x)) == -1)
561 continue;
562
563 SetHandleInformation((HANDLE) F, HANDLE_FLAG_INHERIT, 0);
564 }
565
566 *buf1 = '\0';
567 strcpy(buf1 + 4096, params->prog);
568 str = strtok(buf1 + 4096, w_space);
569
570 do {
571 strcat(buf1, str);
572 strcat(buf1, " ");
573 } while ((str = strtok(NULL, w_space)));
574
575 x = 1;
576
577 while (args[x]) {
f412b2d6
FC
578 strcat(buf1, args[x]);
579 ++x;
b5d712b5 580 strcat(buf1, " ");
581 }
582
583 if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW,
584 NULL, NULL, &si, &pi)) {
585 pid = pi.dwProcessId;
586 hProcess = pi.hProcess;
587 } else {
588 pid = -1;
979f3ae6 589 x = GetLastError();
b5d712b5 590 }
591
592 dup2(t1, 0);
593 dup2(t2, 1);
594 dup2(t3, 2);
595 close(t1);
596 close(t2);
597 close(t3);
598
599 if (pid == -1) {
600 errno = x;
fa84c01d 601 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << params->prog << ": " << xstrerror());
bf8fe701 602
b5d712b5 603 ipcSend(cwfd, err_string, strlen(err_string));
604 goto cleanup;
605 }
606
607 if (type == IPC_UDP_SOCKET) {
608 WSAPROTOCOL_INFO wpi;
609
610 memset(&wpi, 0, sizeof(wpi));
611
612 if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) {
fa84c01d 613 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: WSADuplicateSocket: " << xstrerror());
bf8fe701 614
b5d712b5 615 ipcSend(cwfd, err_string, strlen(err_string));
616 goto cleanup;
617 }
618
619 x = write(c2p[1], (const char *) &wpi, sizeof(wpi));
620
621 if (x < (ssize_t)sizeof(wpi)) {
fa84c01d
FC
622 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: write FD " << c2p[1] << ": " << xstrerror());
623 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
bf8fe701 624
b5d712b5 625 ipcSend(cwfd, err_string, strlen(err_string));
626 goto cleanup;
627 }
628
629 x = read(p2c[0], buf1, 8192);
630
631 if (x < 0) {
fa84c01d
FC
632 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: read FD " << p2c[0] << ": " << xstrerror());
633 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
bf8fe701 634
b5d712b5 635 ipcSend(cwfd, err_string, strlen(err_string));
636 goto cleanup;
637 } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
fa84c01d
FC
638 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
639 debugs(54, DBG_CRITICAL, "--> read returned " << x);
b5d712b5 640 buf1[x] = '\0';
fa84c01d 641 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(buf1) << "'");
b5d712b5 642 ipcSend(cwfd, err_string, strlen(err_string));
643 goto cleanup;
644 }
645
646 x = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc));
647
648 if (x < (ssize_t)sizeof(PS_ipc)) {
fa84c01d
FC
649 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: write FD " << c2p[1] << ": " << xstrerror());
650 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
bf8fe701 651
b5d712b5 652 ipcSend(cwfd, err_string, strlen(err_string));
653 goto cleanup;
654 }
655
656 x = read(p2c[0], buf1, 8192);
657
658 if (x < 0) {
fa84c01d
FC
659 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: read FD " << p2c[0] << ": " << xstrerror());
660 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
bf8fe701 661
b5d712b5 662 ipcSend(cwfd, err_string, strlen(err_string));
663 goto cleanup;
664 } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
fa84c01d
FC
665 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: " << prog << ": socket exchange failed");
666 debugs(54, DBG_CRITICAL, "--> read returned " << x);
b5d712b5 667 buf1[x] = '\0';
fa84c01d 668 debugs(54, DBG_CRITICAL, "--> got '" << rfc1738_escape(buf1) << "'");
b5d712b5 669 ipcSend(cwfd, err_string, strlen(err_string));
670 goto cleanup;
671 }
672
673 x = send(pwfd_ipc, (const void *)ok_string, strlen(ok_string), 0);
674 x = recv(prfd_ipc, (void *)(buf1 + 200), 8191 - 200, 0);
675 assert((size_t) x == strlen(ok_string)
676 && !strncmp(ok_string, buf1 + 200, strlen(ok_string)));
677 } /* IPC_UDP_SOCKET */
678
679 snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, (long int) pid);
680
681 fd_note(fd, buf1);
682
683 if (prfd_ipc != -1) {
684 snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid);
685 fd_note(crfd_ipc, buf1);
686 snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid);
687 fd_note(prfd_ipc, buf1);
688 }
689
690 /* else { IPC_TCP_SOCKET */
691 /* commSetNoLinger(fd); */
692 /* } */
693 thread_params.prog = prog;
694
695 thread_params.send_fd = cwfd;
696
697 thread_params.pid = pid;
698
699 if ((thread_params.type = type) == IPC_TCP_SOCKET)
700 thread_params.rfd = p2c[0];
701 else
702 thread_params.rfd = prfd_ipc;
703
6ca34f6f 704 thread = (HANDLE)_beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL);
b5d712b5 705
706 if (!thread) {
fa84c01d 707 debugs(54, DBG_CRITICAL, "ipcCreate: CHILD: _beginthreadex: " << xstrerror());
b5d712b5 708 ipcSend(cwfd, err_string, strlen(err_string));
709 goto cleanup;
710 }
711
712 snprintf(buf1, 8191, "%ld\n", (long int) pid);
713
714 if (-1 == ipcSend(cwfd, buf1, strlen(buf1)))
715 goto cleanup;
716
26ac0430 717 debugs(54, 2, "ipc(" << prog << "," << pid << "): started successfully");
b5d712b5 718
719 /* cycle */
720 for (;;) {
721 x = recv(crfd, (void *)buf1, 8192, 0);
722
723 if (x <= 0) {
bf8fe701 724 debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes received from parent. Exiting...");
b5d712b5 725 break;
726 }
727
728 buf1[x] = '\0';
729
730 if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) {
bf8fe701 731 debugs(54, 3, "ipc(" << prog << "," << pid << "): request for shutdown received from parent. Exiting...");
732
b5d712b5 733 TerminateProcess(hProcess, 0);
734 break;
735 }
736
bf8fe701 737 debugs(54, 5, "ipc(" << prog << "," << pid << "): received from parent: " << rfc1738_escape_unescaped(buf1));
b5d712b5 738
739 if (type == IPC_TCP_SOCKET)
740 x = write(c2p[1], buf1, x);
741 else
742 x = send(pwfd_ipc, (const void *)buf1, x, 0);
743
744 if (x <= 0) {
bf8fe701 745 debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes written to " << prog << ". Exiting...");
746
b5d712b5 747 break;
748 }
749 }
750
751 retval = 0;
752
753cleanup:
754
755 if (c2p[1] != -1)
756 close(c2p[1]);
757
758 if (fd_table[crfd].flags.open)
759 ipcCloseAllFD(-1, -1, crfd, cwfd);
760
761 if (prfd_ipc != -1) {
762 send(crfd_ipc, (const void *)shutdown_string, strlen(shutdown_string), 0);
763 shutdown(crfd_ipc, SD_BOTH);
764 shutdown(prfd_ipc, SD_BOTH);
765 }
766
767 ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc);
768
769 if (hProcess && WAIT_OBJECT_0 !=
770 WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) {
771
772 getCurrentTime();
fa84c01d 773 debugs(54, DBG_CRITICAL, "ipc(" << prog << "," << pid << "): WARNING: " << prog <<
bf8fe701 774 " didn't exit in " << (type == IPC_UDP_SOCKET ? 12 : 5) << " seconds.");
775
b5d712b5 776 }
777
778 if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) {
779 getCurrentTime();
fa84c01d 780 debugs(54, DBG_CRITICAL, "ipc(" << prog << "," << pid << "): WARNING: ipc_thread_2 didn't exit in 3 seconds.");
bf8fe701 781
b5d712b5 782 }
783
784 getCurrentTime();
785
786 if (!retval)
bf8fe701 787 debugs(54, 2, "ipc(" << prog << "," << pid << "): normal exit");
b5d712b5 788
789 if (buf1)
790 xfree(buf1);
791
792 if (prog)
793 xfree(prog);
794
795 if (thread)
796 CloseHandle(thread);
797
798 if (hProcess)
799 CloseHandle(hProcess);
800
801 if (p2c[0] != -1)
802 close(p2c[0]);
803
804 return retval;
805}
806
807static unsigned int __stdcall
808ipc_thread_2(void *in_params)
809{
810 int x;
811
812 struct thread_params *params = (struct thread_params *) in_params;
813 int type = params->type;
814 int rfd = params->rfd;
815 int send_fd = params->send_fd;
816 char *prog = xstrdup(params->prog);
817 pid_t pid = params->pid;
818 char *buf2 = (char *)xcalloc(1, 8192);
819
820 for (;;) {
821 if (type == IPC_TCP_SOCKET)
822 x = read(rfd, buf2, 8192);
823 else
824 x = recv(rfd, (void *)buf2, 8192, 0);
825
826 if ((x <= 0 && type == IPC_TCP_SOCKET) ||
827 (x < 0 && type == IPC_UDP_SOCKET)) {
bf8fe701 828 debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes read from " << prog << ". Exiting...");
829
b5d712b5 830 break;
831 }
832
833 buf2[x] = '\0';
834
835 if (type == IPC_UDP_SOCKET && !strcmp(buf2, shutdown_string)) {
bf8fe701 836 debugs(54, 3, "ipc(" << prog << "," << pid << "): request for shutdown received. Exiting...");
837
b5d712b5 838 break;
839 }
840
841 if (x >= 2) {
842 if ((buf2[x - 1] == '\n') && (buf2[x - 2] == '\r')) {
843 buf2[x - 2] = '\n';
844 buf2[x - 1] = '\0';
5e263176 845 --x;
b5d712b5 846 }
847 }
848
bf8fe701 849 debugs(54, 5, "ipc(" << prog << "," << pid << "): received from child : " << rfc1738_escape_unescaped(buf2));
850
b5d712b5 851 x = send(send_fd, (const void *)buf2, x, 0);
852
853 if ((x <= 0 && type == IPC_TCP_SOCKET) ||
854 (x < 0 && type == IPC_UDP_SOCKET)) {
bf8fe701 855 debugs(54, 3, "ipc(" << prog << "," << pid << "): " << x << " bytes sent to parent. Exiting...");
856
b5d712b5 857 break;
858 }
859 }
860
861 xfree(prog);
862 xfree(buf2);
863 return 0;
864}