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  }
65  while ((wr > 0) && (total < size));
66  if (wr <= 0)
68  "Failed to write to stdout: %s\n",
69  strerror(errno));
70  return (total == size) ? GNUNET_OK : GNUNET_SYSERR;
71 }
72 
73 
83 static int
84 write_message(int output,
85  uint16_t message_type,
86  const char *data,
87  size_t data_length)
88 {
89  struct GNUNET_MessageHeader hdr;
90 
91 #if 0
92  fprintf(stderr,
93  "Helper sends %u-byte message of type %u\n",
94  (unsigned int)(sizeof(struct GNUNET_MessageHeader) + data_length),
95  (unsigned int)message_type);
96 #endif
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;
103  return GNUNET_OK;
104 }
105 
106 
115 static int
116 read_events(HANDLE console, int output_stream)
117 {
118  DWORD rr;
119  BOOL b;
120  INPUT_RECORD *buf;
121  DWORD i;
122  int result;
123 
124  result = GNUNET_SYSERR;
125  buf = malloc(sizeof(INPUT_RECORD) * buffer_size);
126  if (NULL == buf)
127  return result;
128  b = TRUE;
129  rr = 1;
130  while (TRUE == b && 0 < rr)
131  {
132  rr = 0;
133  b = ReadConsoleInput(console, buf, buffer_size, &rr);
134  if (FALSE == b && ERROR_SUCCESS != GetLastError())
135  break;
136  for (i = 0; i < rr; i++)
137  {
138  int r;
139  r = write_message(output_stream,
141  (const char *)&buf[i],
142  sizeof(INPUT_RECORD));
143  if (GNUNET_OK != r)
144  break;
145  }
146  if (rr + 1 != i)
147  break;
148  }
149  return result;
150 }
151 
152 
161 static int
162 read_chars(HANDLE console, int output_stream)
163 {
164  DWORD rr;
165  BOOL b;
166  wchar_t *buf;
167  char *small_ubuf;
168  char *large_ubuf;
169  char *ubuf;
170  int conv;
171  int r;
172  int result;
173 
174  result = GNUNET_SYSERR;
175  buf = malloc(sizeof(wchar_t) * buffer_size);
176  if (NULL == buf)
177  return result;
178  small_ubuf = malloc(sizeof(char) * buffer_size * 2);
179  if (NULL == small_ubuf)
180  {
181  free(buf);
182  return result;
183  }
184  b = TRUE;
185  rr = 1;
186  while (TRUE == b)
187  {
188  large_ubuf = NULL;
189  rr = 0;
190  b = ReadConsoleW(console, buf, buffer_size, &rr, NULL);
191  if (FALSE == b && ERROR_SUCCESS != GetLastError())
192  break;
193  if (0 == rr)
194  continue;
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).
200  */
201  conv = WideCharToMultiByte(CP_UTF8, 0, buf, rr, small_ubuf, 0, NULL, FALSE);
202  if (0 == conv || 0xFFFD == conv)
203  continue;
204  if (conv <= buffer_size * 2 - 1)
205  {
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)
209  continue;
210  ubuf = small_ubuf;
211  }
212  else
213  {
214  large_ubuf = malloc(conv + 1);
215  if (NULL == large_ubuf)
216  continue;
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)
220  {
221  free(large_ubuf);
222  large_ubuf = NULL;
223  continue;
224  }
225  ubuf = large_ubuf;
226  }
227  r = write_message(output_stream,
229  ubuf,
230  conv + 1);
231  if (large_ubuf)
232  free(large_ubuf);
233  if (GNUNET_OK != r)
234  break;
235  }
236  free(small_ubuf);
237  free(buf);
238  return result;
239 }
240 
241 
242 DWORD WINAPI
243 watch_parent(LPVOID param)
244 {
245  WaitForSingleObject(parent_handle, INFINITE);
246  ExitProcess(1);
247  return 0;
248 }
249 
260 int
261 main(int argc,
262  char *const *argv)
263 {
264  HANDLE os_stdin;
265  DWORD parent_pid;
266 
267  /* We're using stdout to communicate binary data back to the parent; use
268  * binary mode.
269  */
270  _setmode(1, _O_BINARY);
271 
272  if (argc != 4)
273  {
274  fprintf(stderr,
275  "Usage: gnunet-helper-w32-console <chars|events> <buffer size> <parent pid>\n");
276  return 2;
277  }
278 
279  if (0 == strcmp(argv[1], "chars"))
280  chars = GNUNET_YES;
281  else if (0 == strcmp(argv[1], "events"))
282  chars = GNUNET_NO;
283  else
284  return 3;
285 
286  buffer_size = strtoul(argv[2], NULL, 10);
287  if (buffer_size <= 0)
288  return 4;
289 
290  parent_pid = (DWORD)strtoul(argv[3], NULL, 10);
291  if (parent_pid == 0)
292  return 5;
293  parent_handle = OpenProcess(SYNCHRONIZE, FALSE, parent_pid);
294  if (NULL == parent_handle)
295  return 6;
296 
297  CreateThread(NULL, 0, watch_parent, NULL, 0, NULL);
298 
299  if (0 == AttachConsole(ATTACH_PARENT_PROCESS))
300  {
301  if (ERROR_ACCESS_DENIED != GetLastError())
302  return 5;
303  }
304 
305  /* Helper API overrides stdin, so we just attach to the console that we
306  * inherited. If we did.
307  */
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)
311  return 1;
312 
313  if (GNUNET_NO == chars)
314  return read_events(os_stdin, 1);
315  else
316  return read_chars(os_stdin, 1);
317 }
318 
319 /* 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:66
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.