2 This file is part of GNUnet.
3 Copyright (C) 2014 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file src/util/gnunet-helper-w32-console.c
23 * @brief Does blocking reads from the console, writes the results
24 * into stdout, turning blocking console I/O into non-blocking
25 * pipe I/O. For W32 only.
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_common.h"
31 #include "gnunet-helper-w32-console.h"
33 static unsigned long buffer_size;
37 static HANDLE parent_handle;
40 * Write @a size bytes from @a buf into @a output.
42 * @param output the descriptor to write into
43 * @param buf buffer with data to write
44 * @param size number of bytes to write
45 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
48 write_all (int output,
52 const char *cbuf = buf;
64 } while ( (wr > 0) && (total < size) );
66 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
67 "Failed to write to stdout: %s\n",
69 return (total == size) ? GNUNET_OK : GNUNET_SYSERR;
74 * Write message to the master process.
76 * @param output the descriptor to write into
77 * @param message_type message type to use
78 * @param data data to append, NULL for none
79 * @param data_length number of bytes in @a data
80 * @return #GNUNET_SYSERR to stop scanning (the pipe was broken somehow)
83 write_message (int output,
84 uint16_t message_type,
88 struct GNUNET_MessageHeader hdr;
92 "Helper sends %u-byte message of type %u\n",
93 (unsigned int) (sizeof (struct GNUNET_MessageHeader) + data_length),
94 (unsigned int) message_type);
96 hdr.type = htons (message_type);
97 hdr.size = htons (sizeof (struct GNUNET_MessageHeader) + data_length);
98 if (GNUNET_OK != write_all (output, &hdr, sizeof (hdr)))
100 if (GNUNET_OK != write_all (output, data, data_length))
101 return GNUNET_SYSERR;
107 * Main function of the helper process. Reads input events from console,
108 * writes messages, into stdout.
110 * @param console a handle to a console to read from
111 * @param output_stream a stream to write messages to
112 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
115 read_events (HANDLE console, int output_stream)
123 result = GNUNET_SYSERR;
124 buf = malloc (sizeof (INPUT_RECORD) * buffer_size);
129 while (TRUE == b && 0 < rr)
132 b = ReadConsoleInput (console, buf, buffer_size, &rr);
133 if (FALSE == b && ERROR_SUCCESS != GetLastError ())
135 for (i = 0; i < rr; i++)
138 r = write_message (output_stream,
139 GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT,
140 (const char *) &buf[i],
141 sizeof (INPUT_RECORD));
153 * Main function of the helper process. Reads chars from console,
154 * writes messages, into stdout.
156 * @param console a handle to a console to read from
157 * @param output_stream a stream to write messages to
158 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
161 read_chars (HANDLE console, int output_stream)
173 result = GNUNET_SYSERR;
174 buf = malloc (sizeof (wchar_t) * buffer_size);
177 small_ubuf = malloc (sizeof (char) * buffer_size * 2);
178 if (NULL == small_ubuf)
189 b = ReadConsoleW (console, buf, buffer_size, &rr, NULL);
190 if (FALSE == b && ERROR_SUCCESS != GetLastError ())
194 /* Caveat: if the UTF-16-encoded string is longer than BUFFER_SIZE,
195 * there's a possibility that we will read up to a word that constitutes
196 * a part of a multi-byte UTF-16 codepoint. Converting that to UTF-8
197 * will either drop invalid word (flags == 0) or bail out because of it
198 * (flags == WC_ERR_INVALID_CHARS).
200 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, 0, NULL, FALSE);
201 if (0 == conv || 0xFFFD == conv)
203 if (conv <= buffer_size * 2 - 1)
205 memset (small_ubuf, 0, buffer_size * 2);
206 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, buffer_size * 2 - 1, NULL, FALSE);
207 if (0 == conv || 0xFFFD == conv)
213 large_ubuf = malloc (conv + 1);
214 if (NULL == large_ubuf)
216 memset (large_ubuf, 0, conv + 1);
217 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, large_ubuf, conv, NULL, FALSE);
218 if (0 == conv || 0xFFFD == conv)
226 r = write_message (output_stream,
227 GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS,
242 watch_parent (LPVOID param)
244 WaitForSingleObject (parent_handle, INFINITE);
250 * Main function of the helper process to extract meta data.
252 * @param argc should be 3
253 * @param argv [0] our binary name
254 * [1] name of the file or directory to process
255 * [2] "-" to disable extraction, NULL for defaults,
256 * otherwise custom plugins to load from LE
257 * @return 0 on success
265 /* We're using stdout to communicate binary data back to the parent; use
268 _setmode (1, _O_BINARY);
273 "Usage: gnunet-helper-w32-console <chars|events> <buffer size> <parent pid>\n");
277 if (0 == strcmp (argv[1], "chars"))
279 else if (0 == strcmp (argv[1], "events"))
284 buffer_size = strtoul (argv[2], NULL, 10);
285 if (buffer_size <= 0)
288 parent_pid = (DWORD) strtoul (argv[3], NULL, 10);
291 parent_handle = OpenProcess (SYNCHRONIZE, FALSE, parent_pid);
292 if (NULL == parent_handle)
295 CreateThread (NULL, 0, watch_parent, NULL, 0, NULL);
297 if (0 == AttachConsole (ATTACH_PARENT_PROCESS))
299 if (ERROR_ACCESS_DENIED != GetLastError ())
303 /* Helper API overrides stdin, so we just attach to the console that we
304 * inherited. If we did.
306 os_stdin = CreateFile ("CONIN$", GENERIC_READ | GENERIC_WRITE,
307 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
308 if (INVALID_HANDLE_VALUE == os_stdin)
311 if (GNUNET_NO == chars)
312 return read_events (os_stdin, 1);
314 return read_chars (os_stdin, 1);
318 /* end of gnunet-helper-w32-console.c */