GNUnet  0.10.x
gnunet-helper-w32-console.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2014 GNUnet e.V.
4 
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.
9 
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.
14 
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/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 
28 #include "platform.h"
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_common.h"
32 
33 static unsigned long buffer_size;
34 
35 static int chars;
36 
37 static HANDLE parent_handle;
38 
47 static int
48 write_all (int output,
49  const void *buf,
50  size_t size)
51 {
52  const char *cbuf = buf;
53  size_t total;
54  ssize_t wr;
55 
56  total = 0;
57  do
58  {
59  wr = write (output,
60  &cbuf[total],
61  size - total);
62  if (wr > 0)
63  total += wr;
64  } while ( (wr > 0) && (total < size) );
65  if (wr <= 0)
67  "Failed to write to stdout: %s\n",
68  strerror (errno));
69  return (total == size) ? GNUNET_OK : GNUNET_SYSERR;
70 }
71 
72 
82 static int
83 write_message (int output,
84  uint16_t message_type,
85  const char *data,
86  size_t data_length)
87 {
88  struct GNUNET_MessageHeader hdr;
89 
90 #if 0
91  fprintf (stderr,
92  "Helper sends %u-byte message of type %u\n",
93  (unsigned int) (sizeof (struct GNUNET_MessageHeader) + data_length),
94  (unsigned int) message_type);
95 #endif
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)))
99  return GNUNET_SYSERR;
100  if (GNUNET_OK != write_all (output, data, data_length))
101  return GNUNET_SYSERR;
102  return GNUNET_OK;
103 }
104 
105 
114 static int
115 read_events (HANDLE console, int output_stream)
116 {
117  DWORD rr;
118  BOOL b;
119  INPUT_RECORD *buf;
120  DWORD i;
121  int result;
122 
123  result = GNUNET_SYSERR;
124  buf = malloc (sizeof (INPUT_RECORD) * buffer_size);
125  if (NULL == buf)
126  return result;
127  b = TRUE;
128  rr = 1;
129  while (TRUE == b && 0 < rr)
130  {
131  rr = 0;
132  b = ReadConsoleInput (console, buf, buffer_size, &rr);
133  if (FALSE == b && ERROR_SUCCESS != GetLastError ())
134  break;
135  for (i = 0; i < rr; i++)
136  {
137  int r;
138  r = write_message (output_stream,
140  (const char *) &buf[i],
141  sizeof (INPUT_RECORD));
142  if (GNUNET_OK != r)
143  break;
144  }
145  if (rr + 1 != i)
146  break;
147  }
148  return result;
149 }
150 
151 
160 static int
161 read_chars (HANDLE console, int output_stream)
162 {
163  DWORD rr;
164  BOOL b;
165  wchar_t *buf;
166  char *small_ubuf;
167  char *large_ubuf;
168  char *ubuf;
169  int conv;
170  int r;
171  int result;
172 
173  result = GNUNET_SYSERR;
174  buf = malloc (sizeof (wchar_t) * buffer_size);
175  if (NULL == buf)
176  return result;
177  small_ubuf = malloc (sizeof (char) * buffer_size * 2);
178  if (NULL == small_ubuf)
179  {
180  free (buf);
181  return result;
182  }
183  b = TRUE;
184  rr = 1;
185  while (TRUE == b)
186  {
187  large_ubuf = NULL;
188  rr = 0;
189  b = ReadConsoleW (console, buf, buffer_size, &rr, NULL);
190  if (FALSE == b && ERROR_SUCCESS != GetLastError ())
191  break;
192  if (0 == rr)
193  continue;
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).
199  */
200  conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, 0, NULL, FALSE);
201  if (0 == conv || 0xFFFD == conv)
202  continue;
203  if (conv <= buffer_size * 2 - 1)
204  {
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)
208  continue;
209  ubuf = small_ubuf;
210  }
211  else
212  {
213  large_ubuf = malloc (conv + 1);
214  if (NULL == large_ubuf)
215  continue;
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)
219  {
220  free (large_ubuf);
221  large_ubuf = NULL;
222  continue;
223  }
224  ubuf = large_ubuf;
225  }
226  r = write_message (output_stream,
228  ubuf,
229  conv + 1);
230  if (large_ubuf)
231  free (large_ubuf);
232  if (GNUNET_OK != r)
233  break;
234  }
235  free (small_ubuf);
236  free (buf);
237  return result;
238 }
239 
240 
241 DWORD WINAPI
242 watch_parent (LPVOID param)
243 {
244  WaitForSingleObject (parent_handle, INFINITE);
245  ExitProcess (1);
246  return 0;
247 }
248 
259 int
260 main (int argc,
261  char *const *argv)
262 {
263  HANDLE os_stdin;
264  DWORD parent_pid;
265  /* We're using stdout to communicate binary data back to the parent; use
266  * binary mode.
267  */
268  _setmode (1, _O_BINARY);
269 
270  if (argc != 4)
271  {
272  fprintf (stderr,
273  "Usage: gnunet-helper-w32-console <chars|events> <buffer size> <parent pid>\n");
274  return 2;
275  }
276 
277  if (0 == strcmp (argv[1], "chars"))
278  chars = GNUNET_YES;
279  else if (0 == strcmp (argv[1], "events"))
280  chars = GNUNET_NO;
281  else
282  return 3;
283 
284  buffer_size = strtoul (argv[2], NULL, 10);
285  if (buffer_size <= 0)
286  return 4;
287 
288  parent_pid = (DWORD) strtoul (argv[3], NULL, 10);
289  if (parent_pid == 0)
290  return 5;
291  parent_handle = OpenProcess (SYNCHRONIZE, FALSE, parent_pid);
292  if (NULL == parent_handle)
293  return 6;
294 
295  CreateThread (NULL, 0, watch_parent, NULL, 0, NULL);
296 
297  if (0 == AttachConsole (ATTACH_PARENT_PROCESS))
298  {
299  if (ERROR_ACCESS_DENIED != GetLastError ())
300  return 5;
301  }
302 
303  /* Helper API overrides stdin, so we just attach to the console that we
304  * inherited. If we did.
305  */
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)
309  return 1;
310 
311  if (GNUNET_NO == chars)
312  return read_events (os_stdin, 1);
313  else
314  return read_chars (os_stdin, 1);
315 
316 }
317 
318 /* end of gnunet-helper-w32-console.c */
static GstElement * conv
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
cryptographic primitives for GNUnet
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT
Input event from the console.
int main(int argc, char *const *argv)
Main function of the helper process to extract meta data.
static char buf[2048]
static int result
Global testing status.
#define GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS
Chars from the console.
static int write_message(int output, uint16_t message_type, const char *data, size_t data_length)
Write message to the master process.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static int write_all(int output, const void *buf, size_t size)
Write size bytes from buf into output.
static unsigned int size
Size of the "table".
Definition: peer.c:67
static int output_stream
File descriptor we use for IPC with the parent.
static int read_events(HANDLE console, int output_stream)
Main function of the helper process.
static unsigned long buffer_size
static int read_chars(HANDLE console, int output_stream)
Main function of the helper process.
#define GNUNET_log(kind,...)
Header for all communications.
#define GNUNET_YES
Definition: gnunet_common.h:80
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
static HANDLE parent_handle
DWORD WINAPI watch_parent(LPVOID param)
static int chars
uint32_t data
The data value.