* Should we print (interesting|debug) messages that can happen during
* normal operation?
*/
-#define DEBUG GNUNET_NO
+//#define DEBUG GNUNET_YES
/**
* Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
*/
static char device_guid[256];
+
+/**
+ * Possible states of an IO facility.
+ */
+enum IO_State
+{
+
+ /**
+ * overlapped I/O is ready for work
+ */
+ IOSTATE_READY = 0,
+
+ /**
+ * overlapped I/O has been queued
+ */
+ IOSTATE_QUEUED,
+
+ /**
+ * overlapped I/O has finished, but is waiting for it's write-partner
+ */
+ IOSTATE_WAITING,
+
+ /**
+ * there is a full buffer waiting
+ */
+ IOSTATE_RESUME,
+
+ /**
+ * Operlapped IO states for facility objects
+ * overlapped I/O has failed, stop processing
+ */
+ IOSTATE_FAILED
+
+};
+
+
/**
* A IO Object + read/writebuffer + buffer-size for windows asynchronous IO handling
*/
struct io_facility
{
/**
- * The mode the state machine associated with this object is in. IOSTATE_*
+ * The mode the state machine associated with this object is in.
*/
- int facility_state;
+ enum IO_State facility_state;
/**
* If the path is open or blocked in general (used for quickly checking)
DWORD buffer_size_written;
};
-/**
- * Operlapped IO states for facility objects
- * overlapped I/O has failed, stop processing
- */
-#define IOSTATE_FAILED -1
-/**
- * overlapped I/O is ready for work
- */
-#define IOSTATE_READY 0
-/**
- * overlapped I/O has been queued
- */
-#define IOSTATE_QUEUED 1
-/**
- * overlapped I/O has finished, but is waiting for it's write-partner
- */
-#define IOSTATE_WAITING 3
-
/**
* ReOpenFile is only available as of XP SP2 and 2003 SP1
*/
{
FILE *pipe;
- if (NULL == command ||
- NULL == (pipe = _popen (command, "rt")))
+ if ( (NULL == command) ||
+ (NULL == (pipe = _popen (command, "rt"))) )
return EINVAL;
-#ifdef TESTING
+#ifdef DEBUG
fprintf (stderr, "DEBUG: Command output: \n");
char output[LINE_LEN];
while (NULL != fgets (output, sizeof (output), pipe))
*
* @return: TRUE if setup was successful, else FALSE
*/
-static boolean
+static BOOL
setup_interface ()
{
/*
*
* @return: TRUE if destruction was successful, else FALSE
*/
-static boolean
+static BOOL
remove_interface ()
{
SP_REMOVEDEVICE_PARAMS remove;
*
* @return: TRUE if we were able to lookup the interface's name, else FALSE
*/
-static boolean
+static BOOL
resolve_interface_name ()
{
SP_DEVINFO_LIST_DETAIL_DATA device_details;
DWORD len;
int i = 0;
int retrys;
- boolean retval = FALSE;
+ BOOL retval = FALSE;
char adapter[] = INTERFACE_REGISTRY_LOCATION;
/* We can obtain the PNP instance ID from our setupapi handle */
}
-static boolean
+/**
+ * Determines the version of the installed TAP32 driver and checks if it's sufficiently new for GNUNET
+ *
+ * @param handle the handle to our tap device
+ * @return TRUE if the version is sufficient, else FALSE
+ */
+static BOOL
check_tapw32_version (HANDLE handle)
{
ULONG version[3];
if (DeviceIoControl (handle, TAP_WIN_IOCTL_GET_VERSION,
&version, sizeof (version),
&version, sizeof (version), &len, NULL))
- {
fprintf (stderr, "INFO: TAP-Windows Driver Version %d.%d %s\n",
(int) version[0],
(int) version[1],
(version[2] ? "(DEBUG)" : ""));
- }
- if (version[0] != TAP_WIN_MIN_MAJOR || version[1] < TAP_WIN_MIN_MINOR)
- {
+ if (version[0] != TAP_WIN_MIN_MAJOR || version[1] < TAP_WIN_MIN_MINOR){
fprintf (stderr, "FATAL: This version of gnunet requires a TAP-Windows driver that is at least version %d.%d!\n",
TAP_WIN_MIN_MAJOR,
TAP_WIN_MIN_MINOR);
return FALSE;
}
+
return TRUE;
}
char device_path[256];
HANDLE handle;
- if (!setup_interface ())
+ if (! setup_interface ())
{
errno = ENODEV;
return INVALID_HANDLE_VALUE;
* @param handle the handle to our TAP device
* @return True if the operation succeeded, else false
*/
-static boolean
+static BOOL
tun_up (HANDLE handle)
{
ULONG status = TRUE;
* @param output_facility output pipe or file to hand over data to.
* @return false if an event reset was impossible (OS error), else true
*/
-static boolean
+static BOOL
attempt_read_tap (struct io_facility * input_facility,
struct io_facility * output_facility)
{
+ struct GNUNET_MessageHeader * hdr;
+ unsigned short size;
+ BOOL status;
+
switch (input_facility->facility_state)
{
case IOSTATE_READY:
- {
- BOOL status; // BOOL is winbool, NOT boolean!
+ {
if (!ResetEvent (input_facility->overlapped.hEvent))
{
return FALSE;
}
+
+ input_facility->buffer_size = 0;
status = ReadFile (input_facility->handle,
- input_facility->buffer + sizeof (struct GNUNET_MessageHeader),
+ input_facility->buffer,
sizeof (input_facility->buffer) - sizeof (struct GNUNET_MessageHeader),
&input_facility->buffer_size,
&input_facility->overlapped);
if ((IOSTATE_READY == output_facility->facility_state ||
IOSTATE_WAITING == output_facility->facility_state)
&& 0 < input_facility->buffer_size)
- { /* hand over this buffers content */
- memcpy (output_facility->buffer,
+ { /* hand over this buffers content and apply message header for gnunet */
+ hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
+ size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
+
+ memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
input_facility->buffer,
- sizeof (input_facility->buffer));
- output_facility->buffer_size = input_facility->buffer_size;
+ input_facility->buffer_size);
+
+ output_facility->buffer_size = size;
+ hdr->size = htons (size);
+ hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
output_facility->facility_state = IOSTATE_READY;
}
else if (0 < input_facility->buffer_size)
// We are queued and should check if the read has finished
case IOSTATE_QUEUED:
{
- BOOL status; // BOOL is winbool, NOT boolean!
-
// there was an operation going on already, check if that has completed now.
status = GetOverlappedResult (input_facility->handle,
&input_facility->overlapped,
if ((IOSTATE_READY == output_facility->facility_state ||
IOSTATE_WAITING == output_facility->facility_state)
&& 0 < input_facility->buffer_size)
- { /* hand over this buffers content */
- memcpy (output_facility->buffer,
+ { /* hand over this buffers content and apply message header for gnunet */
+ hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
+ size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
+
+ memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
input_facility->buffer,
input_facility->buffer_size);
- output_facility->buffer_size = input_facility->buffer_size;
+
+ output_facility->buffer_size = size;
+ hdr->size = htons(size);
+ hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
output_facility->facility_state = IOSTATE_READY;
input_facility->facility_state = IOSTATE_READY;
}
}
}
return TRUE;
+ case IOSTATE_RESUME:
+ hdr = (struct GNUNET_MessageHeader *) output_facility->buffer;
+ size = input_facility->buffer_size + sizeof (struct GNUNET_MessageHeader);
+
+ memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
+ input_facility->buffer,
+ input_facility->buffer_size);
+
+ output_facility->buffer_size = size;
+ hdr->size = htons (size);
+ hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
+ output_facility->facility_state = IOSTATE_READY;
+ input_facility->facility_state = IOSTATE_READY;
+ return TRUE;
default:
return TRUE;
}
* @param output_facility output pipe or file to hand over data to.
* @return false if an event reset was impossible (OS error), else true
*/
-static boolean
+static BOOL
attempt_read_stdin (struct io_facility * input_facility,
struct io_facility * output_facility)
{
+ struct GNUNET_MessageHeader * hdr;
+ BOOL status;
switch (input_facility->facility_state)
{
case IOSTATE_READY:
{
- BOOL status; // BOOL is winbool, NOT boolean!
if (!ResetEvent (input_facility->overlapped.hEvent))
- {
- return FALSE;
- }
+ return FALSE;
+ input_facility->buffer_size = 0;
status = ReadFile (input_facility->handle,
input_facility->buffer,
sizeof (input_facility->buffer),
&input_facility->overlapped);
/* Check how the task is handled */
- if (status && (0 < input_facility->buffer_size))
+ if (status && (sizeof (struct GNUNET_MessageHeader) < input_facility->buffer_size))
{/* async event processed immediately*/
- struct GNUNET_MessageHeader *hdr;
+ hdr = (struct GNUNET_MessageHeader *) input_facility->buffer;
/* reset event manually*/
if (!SetEvent (input_facility->overlapped.hEvent))
return FALSE;
- hdr = (struct GNUNET_MessageHeader *) input_facility->buffer;
if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER ||
ntohs (hdr->size) > sizeof (input_facility->buffer))
{
input_facility->facility_state = IOSTATE_READY;
return TRUE;
}
- //if (ntohs (hdr->size) > input_facility->buffer_size );
+ if (ntohs (hdr->size) > input_facility->buffer_size);
// TODO: add support for partial read
/* we successfully read something from the TAP and now need to
* send it our via STDOUT. Is that possible at the moment? */
- if (IOSTATE_READY == output_facility->facility_state ||
- IOSTATE_WAITING == output_facility->facility_state)
- { /* hand over this buffers content */
- memcpy (output_facility->buffer,
- input_facility->buffer,
- sizeof (input_facility->buffer));
- output_facility->buffer_size = input_facility->buffer_size;
- output_facility->facility_state = IOSTATE_READY;
- }
- else if (0 < input_facility->buffer_size)
- { /* If we have have read our buffer, wait for our write-partner*/
- input_facility->facility_state = IOSTATE_WAITING;
+ if (sizeof (struct GNUNET_MessageHeader) < input_facility->buffer_size)
+ {
+ if (IOSTATE_READY == output_facility->facility_state ||
+ IOSTATE_WAITING == output_facility->facility_state)
+ {
+ /* hand over this buffers content and strip gnunet message header */
+ memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
+ input_facility->buffer,
+ input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader));
+ output_facility->buffer_size = input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader);
+ output_facility->facility_state = IOSTATE_READY;
+
+ }
+ else if (IOSTATE_QUEUED == output_facility->facility_state)
+ /* If we have have read our buffer, wait for our write-partner*/
+ input_facility->facility_state = IOSTATE_WAITING;
// TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
}
-
- input_facility->facility_state = IOSTATE_READY;
}
else if (status && 0 >= input_facility->buffer_size)
{
// We are queued and should check if the read has finished
case IOSTATE_QUEUED:
{
- BOOL status; // BOOL is winbool, NOT boolean!
-
// there was an operation going on already, check if that has completed now.
status = GetOverlappedResult (input_facility->handle,
&input_facility->overlapped,
FALSE);
if (status)
{/* successful return for a queued operation */
+ hdr = (struct GNUNET_MessageHeader *) input_facility->buffer;
+
if (!ResetEvent (input_facility->overlapped.hEvent))
return FALSE;
+
+ if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER ||
+ ntohs (hdr->size) > sizeof (input_facility->buffer))
+ {
+ fprintf (stderr, "WARNING: Protocol violation, got GNUnet Message type %h, size %h!\n", ntohs (hdr->type), ntohs (hdr->size));
+ input_facility->facility_state = IOSTATE_READY;
+ return TRUE;
+ }
+ if (ntohs (hdr->size) > input_facility->buffer_size );
+ // TODO: add support for partial read
/* we successfully read something from the TAP and now need to
* send it our via STDOUT. Is that possible at the moment? */
if ((IOSTATE_READY == output_facility->facility_state ||
IOSTATE_WAITING == output_facility->facility_state)
- && 0 < input_facility->buffer_size)
- { /* hand over this buffers content */
- memcpy (output_facility->buffer,
+ && sizeof(struct GNUNET_MessageHeader) < input_facility->buffer_size)
+ { /* hand over this buffers content and strip gnunet message header */
+ memcpy (output_facility->buffer + sizeof(struct GNUNET_MessageHeader),
input_facility->buffer,
- input_facility->buffer_size);
- output_facility->buffer_size = input_facility->buffer_size;
+ input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader));
+ output_facility->buffer_size = input_facility->buffer_size - sizeof(struct GNUNET_MessageHeader);
output_facility->facility_state = IOSTATE_READY;
input_facility->facility_state = IOSTATE_READY;
}
- else if (0 < input_facility->buffer_size)
+ else if (sizeof(struct GNUNET_MessageHeader) < input_facility->buffer_size)
{ /* If we have have read our buffer, wait for our write-partner*/
input_facility->facility_state = IOSTATE_WAITING;
// TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
}
+ else if (sizeof(struct GNUNET_MessageHeader) >= input_facility->buffer_size)
+ input_facility->facility_state = IOSTATE_READY;
}
else
{ /* operation still pending/queued or failed? */
}
}
return TRUE;
+ case IOSTATE_RESUME: /* Our buffer was filled already but our write facility was busy. */
+ memcpy (output_facility->buffer + sizeof (struct GNUNET_MessageHeader),
+ input_facility->buffer,
+ input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader));
+ output_facility->buffer_size = input_facility->buffer_size - sizeof (struct GNUNET_MessageHeader);
+ output_facility->facility_state = IOSTATE_READY;
+ input_facility->facility_state = IOSTATE_READY;
+ return TRUE;
default:
return TRUE;
}
}
-
/**
* Attempts to write to an output facility (tap or named pipe) in overlapped mode.
*
* @param input_facility input named pipe or file to work with.
* @return false if an event reset was impossible (OS error), else true
*/
-static boolean
+static BOOL
attempt_write (struct io_facility * output_facility,
struct io_facility * input_facility)
{
- if (IOSTATE_READY == output_facility->facility_state
- && output_facility->buffer_size > 0)
+ BOOL status;
+
+ switch (output_facility->facility_state)
{
- BOOL status; // BOOL is winbool, NOT boolean!
+ case IOSTATE_READY:
if (!ResetEvent (output_facility->overlapped.hEvent))
- {
- return FALSE;
- }
+ return FALSE;
+ output_facility->buffer_size_written = 0;
status = WriteFile (output_facility->handle,
output_facility->buffer,
output_facility->buffer_size,
&output_facility->buffer_size_written,
&output_facility->overlapped);
- /* Check how the task is handled */
+ /* Check how the task was handled */
if (status &&
output_facility->buffer_size_written == output_facility->buffer_size)
{/* async event processed immediately*/
/* we successfully wrote something and now need to reset our reader */
if (IOSTATE_WAITING == input_facility->facility_state)
- input_facility->facility_state = IOSTATE_READY;
+ input_facility->facility_state = IOSTATE_RESUME;
else if (IOSTATE_FAILED == input_facility->facility_state)
output_facility->path_open = FALSE;
}
fprintf (stderr, "FATAL: Write to handle failed, exiting!\n");
}
}
-
- }
- else if (IOSTATE_QUEUED == output_facility->facility_state)
- {
- BOOL status; // BOOL is winbool, NOT boolean!
+ return TRUE;
+ case IOSTATE_QUEUED:
// there was an operation going on already, check if that has completed now.
status = GetOverlappedResult (output_facility->handle,
&output_facility->overlapped,
/* we successfully wrote something and now need to reset our reader */
if (IOSTATE_WAITING == input_facility->facility_state)
- input_facility->facility_state = IOSTATE_READY;
+ input_facility->facility_state = IOSTATE_RESUME;
else if (IOSTATE_FAILED == input_facility->facility_state)
output_facility->path_open = FALSE;
}
fprintf (stderr, "FATAL: Write to handle failed, exiting!\n");
}
}
+ default:
+ return TRUE;
}
-
- return TRUE;
}
* @param signaled if the hEvent created should default to signaled or not
* @return true on success, else false
*/
-static boolean
+static BOOL
initialize_io_facility (struct io_facility * elem,
int initial_state,
BOOL signaled)
{
-
elem->path_open = TRUE;
elem->handle = INVALID_HANDLE_VALUE;
elem->facility_state = initial_state;
tap_read.handle = tap_handle;
tap_write.handle = tap_handle;
+#ifdef DEBUG_TO_CONSOLE
+ /* Debug output to console STDIN/STDOUT*/
+ std_in.handle = parent_std_in_handle;
+ std_out.handle = parent_std_out_handle;
+#else
+
/*
* Find out the types of our handles.
* This part is a problem, because in windows we need to handle files,
fprintf (stderr, "FATAL: Could not reopen stdout for in overlapped mode, has to be a named pipe!\n");
goto teardown;
}
-
+#endif
+
while (std_out.path_open || tap_write.path_open)
{
/* perform READ from stdin if possible */
- if (std_in.path_open && tap_write.path_open && (!attempt_read_stdin (&std_in, &tap_write)))
+ if (std_in.path_open && (!attempt_read_stdin (&std_in, &tap_write)))
break;
/* perform READ from tap if possible */
- if (tap_read.path_open && std_out.path_open && (!attempt_read_tap (&tap_read, &std_out)))
+ if (tap_read.path_open && (!attempt_read_tap (&tap_read, &std_out)))
break;
/* perform WRITE to tap if possible */
*
* @param argc must be 6
* @param argv 0: binary name (gnunet-helper-vpn)
- * 1: tunnel interface name (gnunet-vpn)
+ * 1: tunnel interface prefix (gnunet-vpn)
* 2: IPv6 address (::1), "-" to disable
* 3: IPv6 netmask length in bits (64), ignored if #2 is "-"
* 4: IPv4 address (1.2.3.4), "-" to disable
char hwid[LINE_LEN];
HANDLE handle;
int global_ret = 0;
- boolean have_ip4 = FALSE;
- boolean have_ip6 = FALSE;
+ BOOL have_ip4 = FALSE;
+ BOOL have_ip6 = FALSE;
if (6 != argc)
{
- fprintf (stderr, "FATAL: must supply 5 arguments!\n");
+ fprintf (stderr, "FATAL: must supply 5 arguments!\nUsage:\ngnunet-helper-vpn <if name prefix> <address6 or \"-\"> <netbits6> <address4 or \"-\"> <netmask4>\n", argv[0]);
return 1;
}