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