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
52 const char *cbuf = buf;
65 while ((wr > 0) && (total < size));
67 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
68 "Failed to write to stdout: %s\n",
70 return (total == size) ? GNUNET_OK : GNUNET_SYSERR;
75 * Write message to the master process.
77 * @param output the descriptor to write into
78 * @param message_type message type to use
79 * @param data data to append, NULL for none
80 * @param data_length number of bytes in @a data
81 * @return #GNUNET_SYSERR to stop scanning (the pipe was broken somehow)
84 write_message(int output,
85 uint16_t message_type,
89 struct GNUNET_MessageHeader hdr;
93 "Helper sends %u-byte message of type %u\n",
94 (unsigned int)(sizeof(struct GNUNET_MessageHeader) + data_length),
95 (unsigned int)message_type);
97 hdr.type = htons(message_type);
98 hdr.size = htons(sizeof(struct GNUNET_MessageHeader) + data_length);
99 if (GNUNET_OK != write_all(output, &hdr, sizeof(hdr)))
100 return GNUNET_SYSERR;
101 if (GNUNET_OK != write_all(output, data, data_length))
102 return GNUNET_SYSERR;
108 * Main function of the helper process. Reads input events from console,
109 * writes messages, into stdout.
111 * @param console a handle to a console to read from
112 * @param output_stream a stream to write messages to
113 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
116 read_events(HANDLE console, int output_stream)
124 result = GNUNET_SYSERR;
125 buf = malloc(sizeof(INPUT_RECORD) * buffer_size);
130 while (TRUE == b && 0 < rr)
133 b = ReadConsoleInput(console, buf, buffer_size, &rr);
134 if (FALSE == b && ERROR_SUCCESS != GetLastError())
136 for (i = 0; i < rr; i++)
139 r = write_message(output_stream,
140 GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT,
141 (const char *)&buf[i],
142 sizeof(INPUT_RECORD));
154 * Main function of the helper process. Reads chars from console,
155 * writes messages, into stdout.
157 * @param console a handle to a console to read from
158 * @param output_stream a stream to write messages to
159 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
162 read_chars(HANDLE console, int output_stream)
174 result = GNUNET_SYSERR;
175 buf = malloc(sizeof(wchar_t) * buffer_size);
178 small_ubuf = malloc(sizeof(char) * buffer_size * 2);
179 if (NULL == small_ubuf)
190 b = ReadConsoleW(console, buf, buffer_size, &rr, NULL);
191 if (FALSE == b && ERROR_SUCCESS != GetLastError())
195 /* Caveat: if the UTF-16-encoded string is longer than BUFFER_SIZE,
196 * there's a possibility that we will read up to a word that constitutes
197 * a part of a multi-byte UTF-16 codepoint. Converting that to UTF-8
198 * will either drop invalid word (flags == 0) or bail out because of it
199 * (flags == WC_ERR_INVALID_CHARS).
201 conv = WideCharToMultiByte(CP_UTF8, 0, buf, rr, small_ubuf, 0, NULL, FALSE);
202 if (0 == conv || 0xFFFD == conv)
204 if (conv <= buffer_size * 2 - 1)
206 memset(small_ubuf, 0, buffer_size * 2);
207 conv = WideCharToMultiByte(CP_UTF8, 0, buf, rr, small_ubuf, buffer_size * 2 - 1, NULL, FALSE);
208 if (0 == conv || 0xFFFD == conv)
214 large_ubuf = malloc(conv + 1);
215 if (NULL == large_ubuf)
217 memset(large_ubuf, 0, conv + 1);
218 conv = WideCharToMultiByte(CP_UTF8, 0, buf, rr, large_ubuf, conv, NULL, FALSE);
219 if (0 == conv || 0xFFFD == conv)
227 r = write_message(output_stream,
228 GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS,
243 watch_parent(LPVOID param)
245 WaitForSingleObject(parent_handle, INFINITE);
251 * Main function of the helper process to extract meta data.
253 * @param argc should be 3
254 * @param argv [0] our binary name
255 * [1] name of the file or directory to process
256 * [2] "-" to disable extraction, NULL for defaults,
257 * otherwise custom plugins to load from LE
258 * @return 0 on success
267 /* We're using stdout to communicate binary data back to the parent; use
270 _setmode(1, _O_BINARY);
275 "Usage: gnunet-helper-w32-console <chars|events> <buffer size> <parent pid>\n");
279 if (0 == strcmp(argv[1], "chars"))
281 else if (0 == strcmp(argv[1], "events"))
286 buffer_size = strtoul(argv[2], NULL, 10);
287 if (buffer_size <= 0)
290 parent_pid = (DWORD)strtoul(argv[3], NULL, 10);
293 parent_handle = OpenProcess(SYNCHRONIZE, FALSE, parent_pid);
294 if (NULL == parent_handle)
297 CreateThread(NULL, 0, watch_parent, NULL, 0, NULL);
299 if (0 == AttachConsole(ATTACH_PARENT_PROCESS))
301 if (ERROR_ACCESS_DENIED != GetLastError())
305 /* Helper API overrides stdin, so we just attach to the console that we
306 * inherited. If we did.
308 os_stdin = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
309 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
310 if (INVALID_HANDLE_VALUE == os_stdin)
313 if (GNUNET_NO == chars)
314 return read_events(os_stdin, 1);
316 return read_chars(os_stdin, 1);
319 /* end of gnunet-helper-w32-console.c */