aboutsummaryrefslogtreecommitdiff
path: root/src/vpn
diff options
context:
space:
mode:
authorChristian Fuchs <christian.fuchs@cfuchs.net>2013-01-10 11:54:16 +0000
committerChristian Fuchs <christian.fuchs@cfuchs.net>2013-01-10 11:54:16 +0000
commit7c9dad282dc26d582da100d34a463d6aec13fbce (patch)
tree7166288d5247b6fe7ab6db8c059e8419534d26b0 /src/vpn
parent4216ae8f09c0b6ec6d46e09cba6cb680df63bf14 (diff)
downloadgnunet-7c9dad282dc26d582da100d34a463d6aec13fbce.tar.gz
gnunet-7c9dad282dc26d582da100d34a463d6aec13fbce.zip
as discussed, vpn-helper-windows will only function if stdin/stdout are
handed down as pipes. helper will reopen stdin and stdout in overlapped mode. ReOpenFile requires WinXPSP2 or Win2003SP1.
Diffstat (limited to 'src/vpn')
-rw-r--r--src/vpn/gnunet-helper-vpn-windows.c161
1 files changed, 120 insertions, 41 deletions
diff --git a/src/vpn/gnunet-helper-vpn-windows.c b/src/vpn/gnunet-helper-vpn-windows.c
index 08aad624a..f7000e8fa 100644
--- a/src/vpn/gnunet-helper-vpn-windows.c
+++ b/src/vpn/gnunet-helper-vpn-windows.c
@@ -144,13 +144,12 @@ static char device_guid[256];
144 */ 144 */
145struct io_facility 145struct io_facility
146{ 146{
147 DWORD handle_type;
148 HANDLE handle; 147 HANDLE handle;
149 148
150 BOOL path_open; // BOOL is winbool, NOT boolean! 149 BOOL path_open; // BOOL is winbool, NOT boolean!
151 int facility_state; 150 int facility_state;
152 BOOL status; 151 BOOL status;
153 152
154 OVERLAPPED overlapped; 153 OVERLAPPED overlapped;
155 DWORD buffer_size; 154 DWORD buffer_size;
156 unsigned char buffer[MAX_SIZE]; 155 unsigned char buffer[MAX_SIZE];
@@ -164,7 +163,8 @@ struct io_facility
164#define IOSTATE_QUEUED 1 /* overlapped I/O has been queued */ 163#define IOSTATE_QUEUED 1 /* overlapped I/O has been queued */
165#define IOSTATE_WAITING 3 /* overlapped I/O has finished, but is waiting for it's write-partner */ 164#define IOSTATE_WAITING 3 /* overlapped I/O has finished, but is waiting for it's write-partner */
166 165
167#if WINVER < 0x0600 166// ReOpenFile is only available as of XP SP2 and 2003 SP1
167WINBASEAPI HANDLE WINAPI ReOpenFile (HANDLE, DWORD, DWORD, DWORD);
168 168
169/** 169/**
170 * inet_pton() wrapper for WSAStringToAddress() 170 * inet_pton() wrapper for WSAStringToAddress()
@@ -203,7 +203,6 @@ inet_pton (int af, const char *src, void *dst)
203 } 203 }
204 return 0; 204 return 0;
205} 205}
206#endif
207 206
208/** 207/**
209 * Wrapper for executing a shellcommand in windows. 208 * Wrapper for executing a shellcommand in windows.
@@ -705,39 +704,96 @@ attempt_std_in (struct io_facility * std_in,
705 struct io_facility * tap_write) 704 struct io_facility * tap_write)
706{ 705{
707 706
708 // We could use PeekConsoleInput() or WaitForSingleObject()
709 // however, the interwebs states that WaitForSingleObject with filehandles
710 // might misbehave on some windows (unspecified which ones!).
711 // unfortunately, peekconsoleinput () just waits for KEYPRESS-event, which would never happen on a pipe or a file
712
713 // See:
714 // http://www.cplusplus.com/forum/windows/28837/
715 // http://stackoverflow.com/questions/4551644/using-overlapped-io-for-console-input
716 // http://cygwin.com/ml/cygwin/2012-05/msg00322.html
717
718 // possible soltion?
719 // http://stackoverflow.com/questions/3661106/overlapped-readfileex-on-child-process-redirected-stdout-never-fires
720
721 // we may read from STDIN, and no job was active
722 if (IOSTATE_READY == std_in->facility_state) 707 if (IOSTATE_READY == std_in->facility_state)
723 { 708 {
709 if (!ResetEvent (std_in->overlapped.hEvent))
710 {
711 return FALSE;
712 }
713/* std_in->status = ReadFile (std_in->handle,
714 &std_in->buffer[MAX_SIZE],
715 MAX_SIZE,
716 &std_in->buffer_size,
717 &std_in->overlapped);
718*/
719 /* Check how the task is handled */
720 if (std_in->status)
721 {/* async event processed immediately*/
724 722
723 /* reset event manually*/
724 if (!SetEvent (std_in->overlapped.hEvent))
725 return FALSE;
726
727 /* we successfully read something from the TAP and now need to
728 * send it our via STDOUT. Is that possible at the moment? */
729 if (IOSTATE_READY == tap_write->facility_state && 0 < std_in->buffer_size)
730 { /* hand over this buffers content */
731 memcpy (tap_write->buffer,
732 std_in->buffer,
733 MAX_SIZE);
734 tap_write->buffer_size = std_in->buffer_size;
735 tap_write->facility_state = IOSTATE_READY;
736 }
737 else if (0 < std_in->buffer_size)
738 { /* If we have have read our buffer, wait for our write-partner*/
739 std_in->facility_state = IOSTATE_WAITING;
740 // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
741 }
742 }
743 else /* operation was either queued or failed*/
744 {
745 int err = GetLastError ();
746 if (ERROR_IO_PENDING == err)
747 { /* operation queued */
748 std_in->facility_state = IOSTATE_QUEUED;
749 }
750 else
751 { /* error occurred, let the rest of the elements finish */
752 std_in->path_open = FALSE;
753 std_in->facility_state = IOSTATE_FAILED;
754 }
755 }
725 } 756 }
726 // we must complete a previous read from stdin, before doing more work 757 // We are queued and should check if the read has finished
727 else if (IOSTATE_QUEUED == std_in->facility_state) 758 else if (IOSTATE_QUEUED == std_in->facility_state)
728 { 759 {
729 // there is some data to be read from STDIN! 760 // there was an operation going on already, check if that has completed now.
730 /* if (PeekConsoleInput(stdin_handle, 761 std_in->status = GetOverlappedResult (std_in->handle,
731 &std_in->buffer[MAX_SIZE], 762 &std_in->overlapped,
732 MAX_SIZE, 763 &std_in->buffer_size,
733 &std_in->buffer_size)){ 764 FALSE);
734 765 if (std_in->status)
735 766 {/* successful return for a queued operation */
736 767 if (!ResetEvent (std_in->overlapped.hEvent))
737 }*/ 768 return FALSE;
738 // else { // nothing to do, try again next time }
739 }
740 769
770 /* we successfully read something from the TAP and now need to
771 * send it our via STDOUT. Is that possible at the moment? */
772 if (IOSTATE_READY == tap_write->facility_state && 0 < std_in->buffer_size)
773 { /* hand over this buffers content */
774 memcpy (tap_write->buffer,
775 std_in->buffer,
776 MAX_SIZE);
777 tap_write->buffer_size = std_in->buffer_size;
778 tap_write->facility_state = IOSTATE_READY;
779 std_in->facility_state = IOSTATE_READY;
780 }
781 else if (0 < std_in->buffer_size)
782 { /* If we have have read our buffer, wait for our write-partner*/
783 std_in->facility_state = IOSTATE_WAITING;
784 // TODO: shall we attempt to fill our buffer or should we wait for our write-partner to finish?
785 }
786 }
787 else
788 { /* operation still pending/queued or failed? */
789 int err = GetLastError ();
790 if (ERROR_IO_INCOMPLETE != err && ERROR_IO_PENDING != err)
791 { /* error occurred, let the rest of the elements finish */
792 std_in->path_open = FALSE;
793 std_in->facility_state = IOSTATE_FAILED;
794 }
795 }
796 }
741 return TRUE; 797 return TRUE;
742} 798}
743 799
@@ -863,13 +919,12 @@ attempt_std_out (struct io_facility * std_out,
863 */ 919 */
864static boolean 920static boolean
865initialize_io_facility (struct io_facility * elem, 921initialize_io_facility (struct io_facility * elem,
866 BOOL initial_state, 922 BOOL initial_state,
867 BOOL signaled) 923 BOOL signaled)
868{ 924{
869 925
870 elem->path_open = TRUE; 926 elem->path_open = TRUE;
871 elem->status = initial_state; 927 elem->status = initial_state;
872 elem->handle_type = 0;
873 elem->handle = INVALID_HANDLE_VALUE; 928 elem->handle = INVALID_HANDLE_VALUE;
874 elem->facility_state = 0; 929 elem->facility_state = 0;
875 elem->buffer_size = 0; 930 elem->buffer_size = 0;
@@ -897,6 +952,9 @@ run (HANDLE tap_handle)
897 /* IO-Facility for writing to stdout */ 952 /* IO-Facility for writing to stdout */
898 struct io_facility std_out; 953 struct io_facility std_out;
899 954
955 HANDLE parent_std_in_handle = GetStdHandle (STD_INPUT_HANDLE);
956 HANDLE parent_std_out_handle = GetStdHandle (STD_OUTPUT_HANDLE);
957
900 /* tun up: */ 958 /* tun up: */
901 /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn 959 /* we do this HERE and not beforehand (in init_tun()), in contrast to openvpn
902 * to remove the need to flush the arp cache, handle DHCP and wrong IPs. 960 * to remove the need to flush the arp cache, handle DHCP and wrong IPs.
@@ -915,8 +973,6 @@ run (HANDLE tap_handle)
915 goto teardown; 973 goto teardown;
916 974
917 /* Handles for STDIN and STDOUT */ 975 /* Handles for STDIN and STDOUT */
918 std_in.handle = GetStdHandle (STD_INPUT_HANDLE);
919 std_out.handle = GetStdHandle (STD_OUTPUT_HANDLE);
920 tap_read.handle = tap_handle; 976 tap_read.handle = tap_handle;
921 tap_write.handle = tap_handle; 977 tap_write.handle = tap_handle;
922 978
@@ -925,11 +981,34 @@ run (HANDLE tap_handle)
925 * This part is a problem, because in windows we need to handle files, 981 * This part is a problem, because in windows we need to handle files,
926 * pipes and the console differently. 982 * pipes and the console differently.
927 */ 983 */
928 std_in.handle_type = GetFileType (std_in.handle); 984 if (FILE_TYPE_PIPE != GetFileType (parent_std_in_handle) ||
929 std_out.handle_type = GetFileType (std_out.handle); 985 FILE_TYPE_PIPE != GetFileType (parent_std_out_handle))
930 /* the tap handle is always a file, but we still set this for consistency */ 986 {
931 tap_read.handle_type = FILE_TYPE_DISK; 987 fprintf (stderr, "Fatal: stdin/stdout must be pipes!\n");
932 tap_write.handle_type = FILE_TYPE_DISK; 988 goto teardown;
989 }
990
991 std_in.handle = ReOpenFile (parent_std_in_handle,
992 GENERIC_READ,
993 FILE_SHARE_WRITE | FILE_SHARE_READ,
994 FILE_FLAG_OVERLAPPED);
995
996 if (INVALID_HANDLE_VALUE == std_in.handle)
997 {
998 fprintf (stderr, "Fatal: Could not reopen stdin for in overlapped mode!\n");
999 goto teardown;
1000 }
1001
1002 std_out.handle = ReOpenFile (parent_std_out_handle,
1003 GENERIC_WRITE,
1004 FILE_SHARE_READ,
1005 FILE_FLAG_OVERLAPPED);
1006
1007 if (INVALID_HANDLE_VALUE == std_out.handle)
1008 {
1009 fprintf (stderr, "Fatal: Could not reopen stdout for in overlapped mode!\n");
1010 goto teardown;
1011 }
933 1012
934 //openvpn 1013 //openvpn
935 // Set Device to Subnet-Mode? 1014 // Set Device to Subnet-Mode?