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.
17 * @file src/util/gnunet-helper-w32-console.c
18 * @brief Does blocking reads from the console, writes the results
19 * into stdout, turning blocking console I/O into non-blocking
20 * pipe I/O. For W32 only.
24 #include "gnunet_crypto_lib.h"
25 #include "gnunet_common.h"
26 #include "gnunet-helper-w32-console.h"
28 static unsigned long buffer_size;
32 static HANDLE parent_handle;
35 * Write @a size bytes from @a buf into @a output.
37 * @param output the descriptor to write into
38 * @param buf buffer with data to write
39 * @param size number of bytes to write
40 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
43 write_all (int output,
47 const char *cbuf = buf;
59 } while ( (wr > 0) && (total < size) );
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
62 "Failed to write to stdout: %s\n",
64 return (total == size) ? GNUNET_OK : GNUNET_SYSERR;
69 * Write message to the master process.
71 * @param output the descriptor to write into
72 * @param message_type message type to use
73 * @param data data to append, NULL for none
74 * @param data_length number of bytes in @a data
75 * @return #GNUNET_SYSERR to stop scanning (the pipe was broken somehow)
78 write_message (int output,
79 uint16_t message_type,
83 struct GNUNET_MessageHeader hdr;
87 "Helper sends %u-byte message of type %u\n",
88 (unsigned int) (sizeof (struct GNUNET_MessageHeader) + data_length),
89 (unsigned int) message_type);
91 hdr.type = htons (message_type);
92 hdr.size = htons (sizeof (struct GNUNET_MessageHeader) + data_length);
93 if (GNUNET_OK != write_all (output, &hdr, sizeof (hdr)))
95 if (GNUNET_OK != write_all (output, data, data_length))
102 * Main function of the helper process. Reads input events from console,
103 * writes messages, into stdout.
105 * @param console a handle to a console to read from
106 * @param output_stream a stream to write messages to
107 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
110 read_events (HANDLE console, int output_stream)
118 result = GNUNET_SYSERR;
119 buf = malloc (sizeof (INPUT_RECORD) * buffer_size);
124 while (TRUE == b && 0 < rr)
127 b = ReadConsoleInput (console, buf, buffer_size, &rr);
128 if (FALSE == b && ERROR_SUCCESS != GetLastError ())
130 for (i = 0; i < rr; i++)
133 r = write_message (output_stream,
134 GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT,
135 (const char *) &buf[i],
136 sizeof (INPUT_RECORD));
148 * Main function of the helper process. Reads chars from console,
149 * writes messages, into stdout.
151 * @param console a handle to a console to read from
152 * @param output_stream a stream to write messages to
153 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
156 read_chars (HANDLE console, int output_stream)
168 result = GNUNET_SYSERR;
169 buf = malloc (sizeof (wchar_t) * buffer_size);
172 small_ubuf = malloc (sizeof (char) * buffer_size * 2);
173 if (NULL == small_ubuf)
184 b = ReadConsoleW (console, buf, buffer_size, &rr, NULL);
185 if (FALSE == b && ERROR_SUCCESS != GetLastError ())
189 /* Caveat: if the UTF-16-encoded string is longer than BUFFER_SIZE,
190 * there's a possibility that we will read up to a word that constitutes
191 * a part of a multi-byte UTF-16 codepoint. Converting that to UTF-8
192 * will either drop invalid word (flags == 0) or bail out because of it
193 * (flags == WC_ERR_INVALID_CHARS).
195 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, 0, NULL, FALSE);
196 if (0 == conv || 0xFFFD == conv)
198 if (conv <= buffer_size * 2 - 1)
200 memset (small_ubuf, 0, buffer_size * 2);
201 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, buffer_size * 2 - 1, NULL, FALSE);
202 if (0 == conv || 0xFFFD == conv)
208 large_ubuf = malloc (conv + 1);
209 if (NULL == large_ubuf)
211 memset (large_ubuf, 0, conv + 1);
212 conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, large_ubuf, conv, NULL, FALSE);
213 if (0 == conv || 0xFFFD == conv)
221 r = write_message (output_stream,
222 GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS,
237 watch_parent (LPVOID param)
239 WaitForSingleObject (parent_handle, INFINITE);
245 * Main function of the helper process to extract meta data.
247 * @param argc should be 3
248 * @param argv [0] our binary name
249 * [1] name of the file or directory to process
250 * [2] "-" to disable extraction, NULL for defaults,
251 * otherwise custom plugins to load from LE
252 * @return 0 on success
260 /* We're using stdout to communicate binary data back to the parent; use
263 _setmode (1, _O_BINARY);
268 "Usage: gnunet-helper-w32-console <chars|events> <buffer size> <parent pid>\n");
272 if (0 == strcmp (argv[1], "chars"))
274 else if (0 == strcmp (argv[1], "events"))
279 buffer_size = strtoul (argv[2], NULL, 10);
280 if (buffer_size <= 0)
283 parent_pid = (DWORD) strtoul (argv[3], NULL, 10);
286 parent_handle = OpenProcess (SYNCHRONIZE, FALSE, parent_pid);
287 if (NULL == parent_handle)
290 CreateThread (NULL, 0, watch_parent, NULL, 0, NULL);
292 if (0 == AttachConsole (ATTACH_PARENT_PROCESS))
294 if (ERROR_ACCESS_DENIED != GetLastError ())
298 /* Helper API overrides stdin, so we just attach to the console that we
299 * inherited. If we did.
301 os_stdin = CreateFile ("CONIN$", GENERIC_READ | GENERIC_WRITE,
302 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
303 if (INVALID_HANDLE_VALUE == os_stdin)
306 if (GNUNET_NO == chars)
307 return read_events (os_stdin, 1);
309 return read_chars (os_stdin, 1);
313 /* end of gnunet-helper-w32-console.c */