diff options
author | Christian Fuchs <christian.fuchs@cfuchs.net> | 2013-01-10 11:54:16 +0000 |
---|---|---|
committer | Christian Fuchs <christian.fuchs@cfuchs.net> | 2013-01-10 11:54:16 +0000 |
commit | 7c9dad282dc26d582da100d34a463d6aec13fbce (patch) | |
tree | 7166288d5247b6fe7ab6db8c059e8419534d26b0 /src/vpn | |
parent | 4216ae8f09c0b6ec6d46e09cba6cb680df63bf14 (diff) | |
download | gnunet-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.c | 161 |
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 | */ |
145 | struct io_facility | 145 | struct 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 |
167 | WINBASEAPI 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 | */ |
864 | static boolean | 920 | static boolean |
865 | initialize_io_facility (struct io_facility * elem, | 921 | initialize_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? |