gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r31834 - in gnunet/src: conversation util


From: gnunet
Subject: [GNUnet-SVN] r31834 - in gnunet/src: conversation util
Date: Wed, 8 Jan 2014 15:14:41 +0100

Author: LRN
Date: 2014-01-08 15:14:41 +0100 (Wed, 08 Jan 2014)
New Revision: 31834

Added:
   gnunet/src/util/gnunet-helper-w32-console.c
   gnunet/src/util/gnunet-helper-w32-console.h
Modified:
   gnunet/src/conversation/gnunet-conversation.c
   gnunet/src/util/Makefile.am
Log:
Add console hackery for gnunet-conversation on W32

Modified: gnunet/src/conversation/gnunet-conversation.c
===================================================================
--- gnunet/src/conversation/gnunet-conversation.c       2014-01-08 14:14:37 UTC 
(rev 31833)
+++ gnunet/src/conversation/gnunet-conversation.c       2014-01-08 14:14:41 UTC 
(rev 31834)
@@ -29,15 +29,27 @@
 #include "gnunet_gnsrecord_lib.h"
 #include "gnunet_conversation_service.h"
 #include "gnunet_namestore_service.h"
+#ifdef WINDOWS
+#include "../util/gnunet-helper-w32-console.h"
+#endif
 
-
 /**
  * Maximum length allowed for the command line input.
  */
 #define MAX_MESSAGE_LENGTH 1024
 
+#define XSTRINGIFY(x) STRINGIFY(x)
 
+#define STRINGIFY(x) (#x)
+
+#ifdef WINDOWS
 /**
+ * Helper that reads the console for us.
+ */
+struct GNUNET_HELPER_Handle *stdin_hlp;
+#endif
+
+/**
  * Possible states of the phone.
  */
 enum PhoneState
@@ -997,6 +1009,13 @@
 do_stop_task (void *cls,
              const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+#ifdef WINDOWS
+  if (NULL != stdin_hlp)
+  {
+    GNUNET_HELPER_stop (stdin_hlp, GNUNET_NO);
+    stdin_hlp = NULL;
+  }
+#endif
   if (NULL != call)
   {
     GNUNET_CONVERSATION_call_stop (call);
@@ -1027,7 +1046,61 @@
   phone_state = PS_ERROR;
 }
 
+static void
+handle_command_string (char *message, size_t str_len)
+{
+  size_t i;
+  const char *ptr;
 
+  if (0 == str_len)
+    return;
+  if (message[str_len - 1] == '\n')
+    message[str_len - 1] = '\0';
+  if (message[str_len - 2] == '\r')
+    message[str_len - 2] = '\0';
+  if (0 == strlen (message))
+    return;
+  i = 0;
+  while ((NULL != commands[i].command) &&
+        (0 != strncasecmp (commands[i].command, message,
+                            strlen (commands[i].command))))
+    i++;
+  ptr = &message[strlen (commands[i].command)];
+  while (isspace ((int) *ptr))
+    ptr++;
+  if ('\0' == *ptr)
+    ptr = NULL;
+  commands[i].Action (ptr);
+}
+
+
+#ifdef WINDOWS
+int
+console_reader_chars (void *cls, void *client,
+    const struct GNUNET_MessageHeader *message)
+{
+  char *chars;
+  size_t str_size;
+  switch (ntohs (message->type))
+  {
+  case GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS:
+    chars = (char *) &message[1];
+    str_size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
+    if (chars[str_size - 1] != '\0')
+      return GNUNET_SYSERR;
+    /* FIXME: is it ok that we pass part of a const struct to
+     * this function that may mangle the contents?
+     */
+    handle_command_string (chars, str_size - 1);
+    break;
+  default:
+    GNUNET_break (0);
+    break;
+  }
+  return GNUNET_OK;
+}
+#endif
+
 /**
  * Task to handle commands from the terminal.
  *
@@ -1039,8 +1112,6 @@
                const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   char message[MAX_MESSAGE_LENGTH + 1];
-  const char *ptr;
-  size_t i;
 
   handle_cmd_task =
     GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
@@ -1050,23 +1121,7 @@
   memset (message, 0, MAX_MESSAGE_LENGTH + 1);
   if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin))
     return;
-  if (0 == strlen (message))
-    return;
-  if (message[strlen (message) - 1] == '\n')
-    message[strlen (message) - 1] = '\0';
-  if (0 == strlen (message))
-    return;
-  i = 0;
-  while ((NULL != commands[i].command) &&
-        (0 != strncasecmp (commands[i].command, message,
-                            strlen (commands[i].command))))
-    i++;
-  ptr = &message[strlen (commands[i].command)];
-  while (isspace ((int) *ptr))
-    ptr++;
-  if ('\0' == *ptr)
-    ptr = NULL;
-  commands[i].Action (ptr);
+  handle_command_string (message, strlen (message));
 }
 
 
@@ -1144,6 +1199,30 @@
   id = GNUNET_IDENTITY_connect (cfg,
                                 &identity_cb,
                                 NULL);
+#ifdef WINDOWS
+  if (stdin_fh == NULL)
+  {
+    static char cpid[64];
+    static char *args[] = {"gnunet-helper-w32-console.exe", "chars",
+        XSTRINGIFY (MAX_MESSAGE_LENGTH), cpid, NULL};
+    snprintf (cpid, 64, "%d", GetCurrentProcessId ());
+    stdin_hlp = GNUNET_HELPER_start (
+        GNUNET_NO,
+       "gnunet-helper-w32-console",
+       args,
+       console_reader_chars,
+       NULL,
+       NULL);
+    if (NULL == stdin_hlp)
+    {
+      FPRINTF (stderr,
+               "%s",
+               _("Failed to start gnunet-helper-w32-console\n"));
+      return;
+    }
+  }
+  else
+#endif
   handle_cmd_task =
     GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI,
                                        &handle_command, NULL);
@@ -1171,13 +1250,22 @@
      1, &GNUNET_GETOPT_set_uint, &line},
     GNUNET_GETOPT_OPTION_END
   };
+  int ret;
+#ifndef WINDOWS
   int flags;
-  int ret;
-
   flags = fcntl (0, F_GETFL, 0);
   flags |= O_NONBLOCK;
   fcntl (0, F_SETFL, flags);
   stdin_fh = GNUNET_DISK_get_handle_from_int_fd (0);
+#else
+  if (FILE_TYPE_CHAR == GetFileType ((HANDLE) _get_osfhandle (0)))
+  {
+    stdin_fh = NULL;
+  }
+  else
+    stdin_fh = GNUNET_DISK_get_handle_from_int_fd (0);
+#endif
+
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
     return 2;
   ret = GNUNET_PROGRAM_run (argc, argv,

Modified: gnunet/src/util/Makefile.am
===================================================================
--- gnunet/src/util/Makefile.am 2014-01-08 14:14:37 UTC (rev 31833)
+++ gnunet/src/util/Makefile.am 2014-01-08 14:14:41 UTC (rev 31834)
@@ -25,6 +25,7 @@
   -lcomdlg32 -lgdi32 -liphlpapi
 WINLIB = libgnunetutilwin.la
 W32CAT = w32cat
+W32CONSOLEHELPER = gnunet-helper-w32-console
 endif
 
 if !MINGW
@@ -38,6 +39,14 @@
 
 w32cat_SOURCES = w32cat.c
 
+gnunet_helper_w32_console_SOURCES = \
+  gnunet-helper-w32-console.c \
+  gnunet-helper-w32-console.h
+gnunet_helper_w32_console_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+gnunet_helper_w32_console_DEPENDENCIES = \
+ libgnunetutil.la
+
 noinst_PROGRAMS = \
  gnunet-config-diff \
  $(W32CAT) \
@@ -126,7 +135,8 @@
 
 
 libexec_PROGRAMS = \
- gnunet-service-resolver
+ gnunet-service-resolver \
+ $(W32CONSOLEHELPER)
 
 bin_SCRIPTS =\
  gnunet-qr

Added: gnunet/src/util/gnunet-helper-w32-console.c
===================================================================
--- gnunet/src/util/gnunet-helper-w32-console.c                         (rev 0)
+++ gnunet/src/util/gnunet-helper-w32-console.c 2014-01-08 14:14:41 UTC (rev 
31834)
@@ -0,0 +1,318 @@
+/*
+     This file is part of GNUnet.
+     (C) 2014 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file src/util/gnunet-helper-w32-console.c
+ * @brief Does blocking reads from the console, writes the results
+ *        into stdout, turning blocking console I/O into non-blocking
+ *        pipe I/O. For W32 only.
+ * @author LRN
+ */
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_common.h"
+#include "gnunet-helper-w32-console.h"
+
+static unsigned long buffer_size;
+
+static int chars;
+
+static HANDLE parent_handle;
+
+/**
+ * Write @a size bytes from @a buf into @a output.
+ *
+ * @param output the descriptor to write into
+ * @param buf buffer with data to write
+ * @param size number of bytes to write
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+write_all (int output, 
+           const void *buf,
+          size_t size)
+{
+  const char *cbuf = buf;
+  size_t total;
+  ssize_t wr;
+
+  total = 0;
+  do
+  {
+    wr = write (output,
+               &cbuf[total],
+               size - total);
+    if (wr > 0)
+      total += wr;
+  } while ( (wr > 0) && (total < size) );
+  if (wr <= 0)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Failed to write to stdout: %s\n",
+               strerror (errno));
+  return (total == size) ? GNUNET_OK : GNUNET_SYSERR;
+}
+
+
+/**
+ * Write message to the master process.
+ *
+ * @param output the descriptor to write into
+ * @param message_type message type to use
+ * @param data data to append, NULL for none
+ * @param data_length number of bytes in @a data
+ * @return #GNUNET_SYSERR to stop scanning (the pipe was broken somehow)
+ */
+static int
+write_message (int output,
+               uint16_t message_type,
+              const char *data,
+              size_t data_length)
+{
+  struct GNUNET_MessageHeader hdr;
+
+#if 0
+  fprintf (stderr,
+          "Helper sends %u-byte message of type %u\n",
+          (unsigned int) (sizeof (struct GNUNET_MessageHeader) + data_length),
+          (unsigned int) message_type);
+#endif
+  hdr.type = htons (message_type);
+  hdr.size = htons (sizeof (struct GNUNET_MessageHeader) + data_length);
+  if (GNUNET_OK != write_all (output, &hdr, sizeof (hdr)))
+    return GNUNET_SYSERR;
+  if (GNUNET_OK != write_all (output, data, data_length))
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Main function of the helper process. Reads input events from console,
+ * writes messages, into stdout.
+ *
+ * @param console a handle to a console to read from
+ * @param output_stream a stream to write messages to
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+read_events (HANDLE console, int output_stream)
+{
+  DWORD rr;
+  BOOL b;
+  INPUT_RECORD *buf;
+  DWORD i;
+  int result;
+
+  result = GNUNET_SYSERR;
+  buf = malloc (sizeof (INPUT_RECORD) * buffer_size);
+  if (NULL == buf)
+    return result;
+  b = TRUE;
+  rr = 1;
+  while (TRUE == b && 0 < rr)
+  {
+    rr = 0;
+    b = ReadConsoleInput (console, buf, buffer_size, &rr);
+    if (FALSE == b && ERROR_SUCCESS != GetLastError ())
+      break;
+    for (i = 0; i < rr; i++)
+    {
+      int r;
+      r = write_message (output_stream,
+                         GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT,
+                         (const char *) &buf[i],
+                         sizeof (INPUT_RECORD));
+      if (GNUNET_OK != r)
+        break;
+    }
+    if (rr + 1 != i)
+      break;
+  }
+  return result;
+}
+
+
+/**
+ * Main function of the helper process. Reads chars from console,
+ * writes messages, into stdout.
+ *
+ * @param console a handle to a console to read from
+ * @param output_stream a stream to write messages to
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+read_chars (HANDLE console, int output_stream)
+{
+  DWORD rr;
+  BOOL b;
+  wchar_t *buf;
+  char *small_ubuf;
+  char *large_ubuf;
+  char *ubuf;
+  int conv;
+  int r;
+  int result;
+
+  result = GNUNET_SYSERR;
+  buf = malloc (sizeof (wchar_t) * buffer_size);
+  if (NULL == buf)
+    return result;
+  small_ubuf = malloc (sizeof (char) * buffer_size * 2);
+  if (NULL == small_ubuf)
+  {
+    free (buf);
+    return result;
+  }
+  b = TRUE;
+  rr = 1;
+  while (TRUE == b)
+  {
+    large_ubuf = NULL;
+    rr = 0;
+    b = ReadConsoleW (console, buf, buffer_size, &rr, NULL);
+    if (FALSE == b && ERROR_SUCCESS != GetLastError ())
+      break;
+    if (0 == rr)
+      continue;
+    /* Caveat: if the UTF-16-encoded string is longer than BUFFER_SIZE,
+     * there's a possibility that we will read up to a word that constitutes
+     * a part of a multi-byte UTF-16 codepoint. Converting that to UTF-8
+     * will either drop invalid word (flags == 0) or bail out because of it
+     * (flags == WC_ERR_INVALID_CHARS).
+     */
+    conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, 0, NULL, 
FALSE);
+    if (0 == conv || 0xFFFD == conv)
+      continue;
+    if (conv <= buffer_size * 2 - 1)
+    {
+      memset (small_ubuf, 0, buffer_size * 2);
+      conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, small_ubuf, buffer_size 
* 2 - 1, NULL, FALSE);
+      if (0 == conv || 0xFFFD == conv)
+        continue;
+      ubuf = small_ubuf;
+    }
+    else
+    {
+      large_ubuf = malloc (conv + 1);
+      if (NULL == large_ubuf)
+        continue;
+      memset (large_ubuf, 0, conv + 1);
+      conv = WideCharToMultiByte (CP_UTF8, 0, buf, rr, large_ubuf, conv, NULL, 
FALSE);
+      if (0 == conv || 0xFFFD == conv)
+      {
+        free (large_ubuf);
+        large_ubuf = NULL;
+        continue;
+      }
+      ubuf = large_ubuf;
+    }
+    r = write_message (output_stream,
+                       GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS,
+                       ubuf,
+                       conv + 1);
+    if (large_ubuf)
+      free (large_ubuf);
+    if (GNUNET_OK != r)
+      break;
+  }
+  free (small_ubuf);
+  free (buf);
+  return result;
+}
+
+
+DWORD WINAPI
+watch_parent (LPVOID param)
+{
+  WaitForSingleObject (parent_handle, INFINITE);
+  ExitProcess (1);
+  return 0;
+}
+
+/**
+ * Main function of the helper process to extract meta data.
+ *
+ * @param argc should be 3
+ * @param argv [0] our binary name
+ *             [1] name of the file or directory to process
+ *             [2] "-" to disable extraction, NULL for defaults,
+ *                 otherwise custom plugins to load from LE
+ * @return 0 on success
+ */
+int
+main (int argc,
+      char *const *argv)
+{
+  HANDLE os_stdin;
+  DWORD parent_pid;
+  /* We're using stdout to communicate binary data back to the parent; use
+   * binary mode.
+   */
+  _setmode (1, _O_BINARY);
+
+  if (argc != 4)
+  {
+    fprintf (stderr,
+        "Usage: gnunet-helper-w32-console <chars|events> <buffer size> <parent 
pid>\n");
+    return 2;
+  }
+
+  if (0 == strcmp (argv[1], "chars"))
+    chars = GNUNET_YES;
+  else if (0 == strcmp (argv[1], "events"))
+    chars = GNUNET_NO;
+  else
+    return 3;
+
+  buffer_size = strtoul (argv[2], NULL, 10);
+  if (buffer_size <= 0)
+    return 4;
+
+  parent_pid = (DWORD) strtoul (argv[3], NULL, 10);
+  if (parent_pid == 0)
+    return 5;
+  parent_handle = OpenProcess (SYNCHRONIZE, FALSE, parent_pid);
+  if (NULL == parent_handle)
+    return 6;
+
+  CreateThread (NULL, 0, watch_parent, NULL, 0, NULL);
+
+  if (0 == AttachConsole (ATTACH_PARENT_PROCESS))
+  {
+    if (ERROR_ACCESS_DENIED != GetLastError ())
+      return 5;
+  }
+
+  /* Helper API overrides stdin, so we just attach to the console that we
+   * inherited. If we did.
+   */
+  os_stdin = CreateFile ("CONIN$", GENERIC_READ | GENERIC_WRITE,
+      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
+  if (INVALID_HANDLE_VALUE == os_stdin)
+    return 1;
+
+  if (GNUNET_NO == chars)
+    return read_events (os_stdin, 1);
+  else
+    return read_chars (os_stdin, 1);
+
+}
+
+/* end of gnunet-helper-w32-console.c */


Property changes on: gnunet/src/util/gnunet-helper-w32-console.c
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: gnunet/src/util/gnunet-helper-w32-console.h
===================================================================
--- gnunet/src/util/gnunet-helper-w32-console.h                         (rev 0)
+++ gnunet/src/util/gnunet-helper-w32-console.h 2014-01-08 14:14:41 UTC (rev 
31834)
@@ -0,0 +1,72 @@
+/*
+     This file is part of GNUnet.
+     (C) 2014 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @author LRN
+ * @file src/util/gnunet-helper-w32-console.h
+ */
+#ifndef GNUNET_HELPER_W32_CONSOLE_H
+#define GNUNET_HELPER_W32_CONSOLE_H
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_common.h"
+
+/**
+ * Input event from the console
+ */
+#define GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT 60000
+
+/**
+ * Chars from the console
+ */
+#define GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS 60001
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * This is just a dump of the INPUT_RECORD structure.
+ */
+struct GNUNET_W32_CONSOLE_input
+{
+  /**
+   * Type:  GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_INPUT
+   */
+  struct GNUNET_MessageHeader header;
+
+  INPUT_RECORD input_record GNUNET_PACKED;
+};
+
+/**
+ * A header, followed by UTF8-encoded, 0-terminated string
+ */
+struct GNUNET_W32_CONSOLE_chars
+{
+  /**
+   * Type:  GNUNET_MESSAGE_TYPE_W32_CONSOLE_HELPER_CHARS
+   */
+  struct GNUNET_MessageHeader header;
+
+  /* followed by a string */
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+#endif


Property changes on: gnunet/src/util/gnunet-helper-w32-console.h
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property



reply via email to

[Prev in Thread] Current Thread [Next in Thread]