wmem: allow wmem_destroy_list to ignore a NULL list.
[metze/wireshark/wip.git] / wsutil / ws_pipe.c
1 /* ws_pipe.c
2  *
3  * Routines for handling pipes.
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11
12 #include <config.h>
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #ifdef _WIN32
19 #include <windows.h>
20 #include <io.h>
21 #include <fcntl.h> /* for _O_BINARY */
22 #include <wsutil/win32-utils.h>
23 #else
24 #include <unistd.h>
25 #ifdef HAVE_SYS_SELECT_H
26 #include <sys/select.h>
27 #endif
28 #endif
29
30 #include <glib.h>
31 #include <log.h>
32
33 #ifdef __linux__
34 #define HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
35 #include <fcntl.h>
36 #include <sys/syscall.h>        /* for syscall and SYS_getdents64 */
37 #include <wsutil/file_util.h>   /* for ws_open -> open to pacify checkAPIs.pl */
38 #endif
39
40 #include "wsutil/filesystem.h"
41 #include "wsutil/ws_pipe.h"
42
43 #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
44 struct linux_dirent64 {
45     guint64        d_ino;    /* 64-bit inode number */
46     guint64        d_off;    /* 64-bit offset to next structure */
47     unsigned short d_reclen; /* Size of this dirent */
48     unsigned char  d_type;   /* File type */
49     char           d_name[]; /* Filename (null-terminated) */
50 };
51
52 /* Async-signal-safe string to integer conversion. */
53 static gint
54 filename_to_fd(const char *p)
55 {
56     char c;
57     int fd = 0;
58     const int cutoff = G_MAXINT / 10;
59     const int cutlim = G_MAXINT % 10;
60
61     if (*p == '\0')
62         return -1;
63
64     while ((c = *p++) != '\0') {
65         if (!g_ascii_isdigit(c))
66             return -1;
67         c -= '0';
68
69         /* Check for overflow. */
70         if (fd > cutoff || (fd == cutoff && c > cutlim))
71             return -1;
72
73         fd = fd * 10 + c;
74     }
75
76     return fd;
77 }
78
79 static void
80 close_non_standard_fds_linux(gpointer user_data _U_)
81 {
82     /*
83      * GLib 2.14.2 and newer (up to at least GLib 2.58.1) on Linux with multiple
84      * threads can deadlock in the child process due to use of opendir (which
85      * is not async-signal-safe). To avoid this, disable the broken code path
86      * and manually close file descriptors using async-signal-safe code only.
87      * Use CLOEXEC to allow reporting of execve errors to the parent via a pipe.
88      * https://gitlab.gnome.org/GNOME/glib/issues/1014
89      * https://gitlab.gnome.org/GNOME/glib/merge_requests/490
90      */
91     int dir_fd = ws_open("/proc/self/fd", O_RDONLY | O_DIRECTORY);
92     if (dir_fd >= 0) {
93         char buf[4096];
94         int nread, fd;
95         struct linux_dirent64 *de;
96
97         while ((nread = (int) syscall(SYS_getdents64, dir_fd, buf, sizeof(buf))) > 0) {
98             for (int pos = 0; pos < nread; pos += de->d_reclen) {
99                 de = (struct linux_dirent64 *)(buf + pos);
100                 fd = filename_to_fd(de->d_name);
101                 if (fd > STDERR_FILENO && fd != dir_fd) {
102                     /* Close all other (valid) file descriptors above stderr. */
103                     fcntl(fd, F_SETFD, FD_CLOEXEC);
104                 }
105             }
106         }
107
108         close(dir_fd);
109     } else {
110         /* Slow fallback in case /proc is not mounted */
111         for (int fd = STDERR_FILENO + 1; fd < getdtablesize(); fd++) {
112             fcntl(fd, F_SETFD, FD_CLOEXEC);
113         }
114     }
115 }
116 #endif
117
118 gboolean ws_pipe_spawn_sync(const gchar *working_directory, const gchar *command, gint argc, gchar **args, gchar **command_output)
119 {
120     gboolean status = FALSE;
121     gboolean result = FALSE;
122     gchar **argv = NULL;
123     gint cnt = 0;
124     gchar *local_output = NULL;
125 #ifdef _WIN32
126
127 #define BUFFER_SIZE 16384
128
129     GString *winargs = g_string_sized_new(200);
130     gchar *quoted_arg;
131
132     STARTUPINFO info;
133     PROCESS_INFORMATION processInfo;
134
135     SECURITY_ATTRIBUTES sa;
136     HANDLE child_stdout_rd = NULL;
137     HANDLE child_stdout_wr = NULL;
138     HANDLE child_stderr_rd = NULL;
139     HANDLE child_stderr_wr = NULL;
140 #else
141     gint exit_status = 0;
142 #endif
143
144     argv = (gchar **) g_malloc0(sizeof(gchar *) * (argc + 2));
145     GString *spawn_string = g_string_new("");
146
147 #ifdef _WIN32
148     argv[0] = g_strescape(command, NULL);
149 #else
150     argv[0] = g_strdup(command);
151 #endif
152
153     for (cnt = 0; cnt < argc; cnt++)
154     {
155         argv[cnt + 1] = args[cnt];
156         g_string_append_printf(spawn_string, " %s", args[cnt]);
157     }
158     argv[argc + 1] = NULL;
159
160     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "spawn params: %s", spawn_string->str);
161     g_string_free(spawn_string, TRUE);
162
163     guint64 start_time = g_get_monotonic_time();
164
165 #ifdef _WIN32
166
167     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
168     sa.bInheritHandle = TRUE;
169     sa.lpSecurityDescriptor = NULL;
170
171     if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
172     {
173         g_free(argv[0]);
174         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
175         return FALSE;
176     }
177
178     if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
179     {
180         CloseHandle(child_stdout_rd);
181         CloseHandle(child_stdout_wr);
182         g_free(argv[0]);
183         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
184         return FALSE;
185     }
186
187     /* convert args array into a single string */
188     /* XXX - could change sync_pipe_add_arg() instead */
189     /* there is a drawback here: the length is internally limited to 1024 bytes */
190     for (cnt = 0; argv[cnt] != 0; cnt++) {
191         if (cnt != 0) g_string_append_c(winargs, ' ');    /* don't prepend a space before the path!!! */
192         quoted_arg = protect_arg(argv[cnt]);
193         g_string_append(winargs, quoted_arg);
194         g_free(quoted_arg);
195     }
196
197     memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
198     memset(&info, 0, sizeof(STARTUPINFO));
199
200     info.cb = sizeof(STARTUPINFO);
201     info.hStdError = child_stderr_wr;
202     info.hStdOutput = child_stdout_wr;
203     info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
204     info.wShowWindow = SW_HIDE;
205
206     if (win32_create_process(NULL, winargs->str, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
207     {
208         gchar* buffer = (gchar*)g_malloc(BUFFER_SIZE);
209         DWORD dw;
210         DWORD bytes_read;
211         DWORD bytes_avail;
212         GString *output_string = g_string_new(NULL);
213
214         for (;;)
215         {
216             /* Keep peeking at pipes every 100 ms. */
217             dw = WaitForSingleObject(processInfo.hProcess, 100000);
218             if (dw == WAIT_OBJECT_0)
219             {
220                 /* Process finished. Nothing left to do here. */
221                 break;
222             }
223             else if (dw != WAIT_TIMEOUT)
224             {
225                 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForSingleObject returned 0x%08X. Error %d", dw, GetLastError());
226                 break;
227             }
228
229             if (PeekNamedPipe(child_stdout_rd, NULL, 0, NULL, &bytes_avail, NULL))
230             {
231                 if (bytes_avail > 0)
232                 {
233                     bytes_avail = min(bytes_avail, BUFFER_SIZE);
234                     if (ReadFile(child_stdout_rd, &buffer[0], bytes_avail, &bytes_read, NULL))
235                     {
236                         g_string_append_len(output_string, buffer, bytes_read);
237                     }
238                 }
239             }
240
241             /* Discard the stderr data just like non-windows version of this function does. */
242             if (PeekNamedPipe(child_stderr_rd, NULL, 0, NULL, &bytes_avail, NULL))
243             {
244                 if (bytes_avail > 0)
245                 {
246                     bytes_avail = min(bytes_avail, BUFFER_SIZE);
247                     ReadFile(child_stderr_rd, &buffer[0], bytes_avail, &bytes_read, NULL);
248                 }
249             }
250         }
251
252         /* At this point the process is finished but there might still be unread data in the pipe. */
253         while (PeekNamedPipe(child_stdout_rd, NULL, 0, NULL, &bytes_avail, NULL))
254         {
255             if (bytes_avail == 0)
256             {
257                 /* Pipe is drained. */
258                 break;
259             }
260             bytes_avail = min(bytes_avail, BUFFER_SIZE);
261             if (ReadFile(child_stdout_rd, &buffer[0], BUFFER_SIZE, &bytes_read, NULL))
262             {
263                 g_string_append_len(output_string, buffer, bytes_read);
264             }
265         }
266
267         g_free(buffer);
268
269         status = GetExitCodeProcess(processInfo.hProcess, &dw);
270         if (status && dw != 0)
271         {
272             status = FALSE;
273         }
274
275         local_output = g_string_free(output_string, FALSE);
276
277         CloseHandle(child_stdout_rd);
278         CloseHandle(child_stdout_wr);
279         CloseHandle(child_stderr_rd);
280         CloseHandle(child_stderr_wr);
281
282         CloseHandle(processInfo.hProcess);
283         CloseHandle(processInfo.hThread);
284     }
285     else
286         status = FALSE;
287 #else
288
289     GSpawnFlags flags = (GSpawnFlags)0;
290     GSpawnChildSetupFunc child_setup = NULL;
291 #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
292     flags = (GSpawnFlags)(flags | G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
293     child_setup = close_non_standard_fds_linux;
294 #endif
295     status = g_spawn_sync(working_directory, argv, NULL,
296                           flags, child_setup, NULL, &local_output, NULL, &exit_status, NULL);
297
298     if (status && exit_status != 0)
299         status = FALSE;
300 #endif
301
302     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "%s finished in %.3fms", argv[0], (g_get_monotonic_time() - start_time) / 1000.0);
303
304     if (status)
305     {
306         if (local_output != NULL) {
307             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "spawn output: %s", local_output);
308             if (command_output != NULL)
309                 *command_output = g_strdup(local_output);
310         }
311         result = TRUE;
312     }
313
314     g_free(local_output);
315     g_free(argv[0]);
316     g_free(argv);
317
318     return result;
319 }
320
321 void ws_pipe_init(ws_pipe_t *ws_pipe)
322 {
323     if (!ws_pipe) return;
324     memset(ws_pipe, 0, sizeof(ws_pipe_t));
325     ws_pipe->pid = WS_INVALID_PID;
326 }
327
328 GPid ws_pipe_spawn_async(ws_pipe_t *ws_pipe, GPtrArray *args)
329 {
330     GPid pid = WS_INVALID_PID;
331     GString *spawn_args;
332     gint cnt = 0;
333     gchar **tmp = NULL;
334
335     gchar *quoted_arg;
336
337 #ifdef _WIN32
338     STARTUPINFO info;
339     PROCESS_INFORMATION processInfo;
340
341     SECURITY_ATTRIBUTES sa;
342     HANDLE child_stdin_rd = NULL;
343     HANDLE child_stdin_wr = NULL;
344     HANDLE child_stdout_rd = NULL;
345     HANDLE child_stdout_wr = NULL;
346     HANDLE child_stderr_rd = NULL;
347     HANDLE child_stderr_wr = NULL;
348
349     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
350     sa.bInheritHandle = TRUE;
351     sa.lpSecurityDescriptor = NULL;
352
353     if (!CreatePipe(&child_stdin_rd, &child_stdin_wr, &sa, 0))
354     {
355         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdin handle");
356         return FALSE;
357     }
358
359     if (!CreatePipe(&child_stdout_rd, &child_stdout_wr, &sa, 0))
360     {
361         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stdout handle");
362         return FALSE;
363     }
364
365     if (!CreatePipe(&child_stderr_rd, &child_stderr_wr, &sa, 0))
366     {
367         CloseHandle(child_stdout_rd);
368         CloseHandle(child_stdout_wr);
369         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Could not create stderr handle");
370         return FALSE;
371     }
372
373     spawn_args = g_string_sized_new(200);
374
375     /* convert args array into a single string */
376     /* XXX - could change sync_pipe_add_arg() instead */
377     /* there is a drawback here: the length is internally limited to 1024 bytes */
378     for (tmp = (gchar **)args->pdata, cnt = 0; *tmp && **tmp; ++cnt, ++tmp) {
379         if (cnt != 0) g_string_append_c(spawn_args, ' ');    /* don't prepend a space before the path!!! */
380         quoted_arg = protect_arg(*tmp);
381         g_string_append(spawn_args, quoted_arg);
382         g_free(quoted_arg);
383     }
384
385     memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
386     memset(&info, 0, sizeof(STARTUPINFO));
387
388     info.cb = sizeof(STARTUPINFO);
389     info.hStdInput = child_stdin_rd;
390     info.hStdError = child_stderr_wr;
391     info.hStdOutput = child_stdout_wr;
392     info.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
393     info.wShowWindow = SW_HIDE;
394
395     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "async spawn params: %s", spawn_args->str);
396     if (win32_create_process(NULL, spawn_args->str, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &info, &processInfo))
397     {
398         ws_pipe->stdin_fd = _open_osfhandle((intptr_t)(child_stdin_wr), _O_BINARY);
399         ws_pipe->stdout_fd = _open_osfhandle((intptr_t)(child_stdout_rd), _O_BINARY);
400         ws_pipe->stderr_fd = _open_osfhandle((intptr_t)(child_stderr_rd), _O_BINARY);
401         ws_pipe->threadId = processInfo.hThread;
402         pid = processInfo.hProcess;
403     }
404 #else
405
406     spawn_args = g_string_sized_new(200);
407
408     /* convert args array into a single string */
409     /* XXX - could change sync_pipe_add_arg() instead */
410     /* there is a drawback here: the length is internally limited to 1024 bytes */
411     for (tmp = (gchar **)args->pdata, cnt = 0; *tmp && **tmp; ++cnt, ++tmp) {
412         if (cnt != 0) g_string_append_c(spawn_args, ' ');    /* don't prepend a space before the path!!! */
413         quoted_arg = g_shell_quote(*tmp);
414         g_string_append(spawn_args, quoted_arg);
415         g_free(quoted_arg);
416     }
417
418     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "async spawn params: %s", spawn_args->str);
419
420     GError *error = NULL;
421     GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD;
422     GSpawnChildSetupFunc child_setup = NULL;
423 #ifdef HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG
424     flags = (GSpawnFlags)(flags | G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
425     child_setup = close_non_standard_fds_linux;
426 #endif
427     gboolean spawned = g_spawn_async_with_pipes(NULL, (gchar **)args->pdata, NULL,
428                              flags, child_setup, NULL,
429                              &pid, &ws_pipe->stdin_fd, &ws_pipe->stdout_fd, &ws_pipe->stderr_fd, &error);
430     if (!spawned) {
431         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Error creating async pipe: %s", error->message);
432         g_free(error->message);
433     }
434 #endif
435
436     g_string_free(spawn_args, TRUE);
437
438     ws_pipe->pid = pid;
439
440     return pid;
441 }
442
443 void ws_pipe_close(ws_pipe_t * ws_pipe)
444 {
445     if (ws_pipe->pid != WS_INVALID_PID) {
446 #ifdef _WIN32
447         TerminateProcess(ws_pipe->pid, 0);
448 #endif
449         g_spawn_close_pid(ws_pipe->pid);
450         ws_pipe->pid = WS_INVALID_PID;
451     }
452 }
453
454 #ifdef _WIN32
455
456 typedef struct
457 {
458     HANDLE pipeHandle;
459     OVERLAPPED ol;
460     BOOL pendingIO;
461 } PIPEINTS;
462
463 gboolean
464 ws_pipe_wait_for_pipe(HANDLE * pipe_handles, int num_pipe_handles, HANDLE pid)
465 {
466     PIPEINTS pipeinsts[3];
467     DWORD dw, cbRet;
468     HANDLE handles[4];
469     int error_code;
470     int num_waiting_to_connect = 0;
471     int num_handles = num_pipe_handles + 1; // PID handle is also added to list of handles.
472
473     SecureZeroMemory(pipeinsts, sizeof(pipeinsts));
474
475     if (num_pipe_handles == 0 || num_pipe_handles > 3)
476     {
477         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Invalid number of pipes given as argument.");
478         return FALSE;
479     }
480
481     for (int i = 0; i < num_pipe_handles; ++i)
482     {
483         pipeinsts[i].pipeHandle = pipe_handles[i];
484         pipeinsts[i].ol.Pointer = 0;
485         pipeinsts[i].ol.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
486         pipeinsts[i].pendingIO = FALSE;
487         handles[i] = pipeinsts[i].ol.hEvent;
488         BOOL connected = ConnectNamedPipe(pipeinsts[i].pipeHandle, &pipeinsts[i].ol);
489         if (connected)
490         {
491             error_code = GetLastError();
492             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
493             return FALSE;
494         }
495
496         switch (GetLastError())
497         {
498         case ERROR_IO_PENDING:
499             num_waiting_to_connect++;
500             pipeinsts[i].pendingIO = TRUE;
501             break;
502
503         case ERROR_PIPE_CONNECTED:
504             if (SetEvent(pipeinsts[i].ol.hEvent))
505             {
506                 break;
507             } // Fallthrough if this fails.
508
509         default:
510             error_code = GetLastError();
511             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe failed with %d \n.", error_code);
512             return FALSE;
513         }
514     }
515
516     // Store pid of extcap process so it can be monitored in case it fails before the pipes has connceted.
517     handles[num_pipe_handles] = pid;
518
519     while(num_waiting_to_connect > 0)
520     {
521         dw = WaitForMultipleObjects(num_handles, handles, FALSE, 30000);
522         int idx = dw - WAIT_OBJECT_0;
523         if (dw == WAIT_TIMEOUT)
524         {
525             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds.");
526             return FALSE;
527         }
528         // If index points to our handles array
529         else if (idx >= 0 && idx < num_handles)
530         {
531             if (idx < num_pipe_handles)  // Index of pipe handle
532             {
533                 if (pipeinsts[idx].pendingIO)
534                 {
535                     BOOL success = GetOverlappedResult(
536                         pipeinsts[idx].pipeHandle, // handle to pipe
537                         &pipeinsts[idx].ol,        // OVERLAPPED structure
538                         &cbRet,                    // bytes transferred
539                         FALSE);                    // do not wait
540
541                     if (!success)
542                     {
543                         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Error %d \n.", GetLastError());
544                         return FALSE;
545                     }
546                     else
547                     {
548                         pipeinsts[idx].pendingIO = FALSE;
549                         CloseHandle(pipeinsts[idx].ol.hEvent);
550                         num_waiting_to_connect--;
551                     }
552                 }
553             }
554             else // Index of PID
555             {
556                 // Fail since index of 'pid' indicates that the pid of the extcap process has terminated.
557                 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe.");
558                 return FALSE;
559             }
560         }
561         else
562         {
563             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
564             return FALSE;
565         }
566     }
567
568     return TRUE;
569 }
570 #endif
571
572 gboolean
573 ws_pipe_data_available(int pipe_fd)
574 {
575 #ifdef _WIN32 /* PeekNamedPipe */
576     HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd);
577     DWORD bytes_avail;
578
579     if (hPipe == INVALID_HANDLE_VALUE)
580     {
581         return FALSE;
582     }
583
584     if (! PeekNamedPipe(hPipe, NULL, 0, NULL, &bytes_avail, NULL))
585     {
586         return FALSE;
587     }
588
589     if (bytes_avail > 0)
590     {
591         return TRUE;
592     }
593     return FALSE;
594 #else /* select */
595     fd_set rfds;
596     struct timeval timeout;
597
598     FD_ZERO(&rfds);
599     FD_SET(pipe_fd, &rfds);
600     timeout.tv_sec = 0;
601     timeout.tv_usec = 0;
602
603     if (select(pipe_fd + 1, &rfds, NULL, NULL, &timeout) > 0)
604     {
605         return TRUE;
606     }
607
608     return FALSE;
609 #endif
610 }
611
612 gboolean
613 ws_read_string_from_pipe(ws_pipe_handle read_pipe, gchar *buffer,
614                          size_t buffer_size)
615 {
616     size_t total_bytes_read;
617     size_t buffer_bytes_remaining;
618 #ifdef _WIN32
619     DWORD bytes_to_read;
620     DWORD bytes_read;
621     DWORD bytes_avail;
622 #else
623     size_t bytes_to_read;
624     ssize_t bytes_read;
625 #endif
626     int ret = FALSE;
627
628     if (buffer_size == 0)
629     {
630         /* XXX - provide an error string */
631         return FALSE;
632     }
633
634     total_bytes_read = 0;
635     for (;;)
636     {
637         /* Leave room for the terminating NUL. */
638         buffer_bytes_remaining = buffer_size - total_bytes_read - 1;
639         if (buffer_bytes_remaining == 0)
640         {
641             /* The string won't fit in the buffer. */
642             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Buffer too small (%zd).", buffer_size);
643             break;
644         }
645
646 #ifdef _WIN32
647         /*
648          * XXX - is there some reason why we do this before reading?
649          *
650          * If we're not trying to do UN*X-style non-blocking I/O,
651          * where we don't block if there isn't data available to
652          * read right now, I'm not sure why we do this.
653          *
654          * If we *are* trying to do UN*X-style non-blocking I/O,
655          * 1) we're presumably in an event loop waiting for,
656          * among other things, input to be available on the
657          * pipe, in which case we should be doing "overlapped"
658          * I/O and 2) we need to accumulate data until we have
659          * a complete string, rather than just saying "OK, here's
660          * the string".)
661          */
662         if (!PeekNamedPipe(read_pipe, NULL, 0, NULL, &bytes_avail, NULL))
663         {
664             break;
665         }
666         if (bytes_avail == 0)
667         {
668             ret = TRUE;
669             break;
670         }
671
672         /*
673          * Truncate this to whatever fits in a DWORD.
674          */
675         if (buffer_bytes_remaining > 0x7fffffff)
676         {
677             bytes_to_read = 0x7fffffff;
678         }
679         else
680         {
681             bytes_to_read = (DWORD)buffer_bytes_remaining;
682         }
683         if (!ReadFile(read_pipe, &buffer[total_bytes_read], bytes_to_read,
684             &bytes_read, NULL))
685         {
686             /* XXX - provide an error string */
687             break;
688         }
689 #else
690         /*
691          * Check if data is available before doing a blocking I/O read.
692          *
693          * XXX - this means that if part of the string, but not all of
694          * the string, has been written to the pipe, this will just
695          * return, as the string, the part that's been written as of
696          * this point.
697          *
698          * Pipes, on UN*X, are like TCP connections - there are *no*
699          * message boundaries, they're just byte streams.  Either 1)
700          * precisely *one* string can be sent on this pipe, and the
701          * sending side must be closed after the string is written to
702          * the pipe, so that an EOF indicates the end of the string
703          * or 2) the strings must either be preceded by a length indication
704          * or must be terminated with an end-of-string indication (such
705          * as a '\0'), so that we can determine when one string ends and
706          * another string begins.
707          */
708         if (!ws_pipe_data_available(read_pipe)) {
709             ret = TRUE;
710             break;
711         }
712
713         bytes_to_read = buffer_bytes_remaining;
714         bytes_read = read(read_pipe, &buffer[total_bytes_read], bytes_to_read);
715         if (bytes_read == -1)
716         {
717             /* XXX - provide an error string */
718             break;
719         }
720 #endif
721         if (bytes_read == 0)
722         {
723             ret = TRUE;
724             break;
725         }
726
727         total_bytes_read += bytes_read;
728     }
729
730     buffer[total_bytes_read] = '\0';
731     return ret;
732 }
733
734 /*
735  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
736  *
737  * Local variables:
738  * c-basic-offset: 4
739  * tab-width: 8
740  * indent-tabs-mode: nil
741  * End:
742  *
743  * vi: set shiftwidth=4 tabstop=8 expandtab:
744  * :indentSize=4:tabSize=8:noTabs=true:
745  */