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