|
44 | 44 | #include <fcntl.h>
|
45 | 45 | #ifdef PHP_WIN32
|
46 | 46 | #include <windows.h>
|
47 |
| -#include <winsock.h> |
| 47 | +#include <winsock2.h> |
48 | 48 | #define O_RDONLY _O_RDONLY
|
49 | 49 | #include "win32/param.h"
|
50 | 50 | #include "win32/winutil.h"
|
@@ -821,6 +821,160 @@ static int stream_array_emulate_read_fd_set(zval *stream_array TSRMLS_DC)
|
821 | 821 | }
|
822 | 822 | /* }}} */
|
823 | 823 |
|
| 824 | +#ifdef PHP_WIN32 |
| 825 | +/* Win32 select() will only work with sockets, so we roll our own implementation that will |
| 826 | + * get the OS file handle from regular fd's and sockets and then use WaitForMultipleObjects(). |
| 827 | + * This implementation is not as feature-full as posix select, but it works for our purposes |
| 828 | + */ |
| 829 | +static int php_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv) |
| 830 | +{ |
| 831 | + HANDLE *handles; |
| 832 | + DWORD ms, waitret; |
| 833 | + DWORD ms_total; |
| 834 | + int i, f, s, fd_count = 0, sock_count = 0; |
| 835 | + int retval; |
| 836 | + fd_set ard, awr, aex; /* active fd sets */ |
| 837 | + long sock_events; |
| 838 | + |
| 839 | + for (i = 0; i < max_fd; i++) { |
| 840 | + if (FD_ISSET(i, rfds) || FD_ISSET(i, wfds) || FD_ISSET(i, efds)) { |
| 841 | + if (_get_osfhandle(i) == 0xffffffff) { |
| 842 | + /* it is a socket */ |
| 843 | + sock_count++; |
| 844 | + } else { |
| 845 | + fd_count++; |
| 846 | + } |
| 847 | + } |
| 848 | + } |
| 849 | + |
| 850 | + if (fd_count + sock_count == 0) { |
| 851 | + return 0; |
| 852 | + } |
| 853 | + |
| 854 | + handles = (HANDLE*)emalloc((fd_count + sock_count) * sizeof(HANDLE)); |
| 855 | + |
| 856 | + /* populate the events and handles arrays */ |
| 857 | + f = 0; |
| 858 | + s = 0; |
| 859 | + for (i = 0; i < max_fd; i++) { |
| 860 | + if (FD_ISSET(i, rfds) || FD_ISSET(i, wfds) || FD_ISSET(i, efds)) { |
| 861 | + long h = _get_osfhandle(i); |
| 862 | + if (h == 0xFFFFFFFF) { |
| 863 | + HANDLE evt; |
| 864 | + long evt_flags = 0; |
| 865 | + |
| 866 | + if (FD_ISSET(i, rfds)) { |
| 867 | + evt_flags |= FD_READ|FD_CONNECT|FD_ACCEPT|FD_CLOSE; |
| 868 | + } |
| 869 | + if (FD_ISSET(i, wfds)) { |
| 870 | + evt_flags |= FD_WRITE; |
| 871 | + } |
| 872 | + if (FD_ISSET(i, efds)) { |
| 873 | + evt_flags |= FD_OOB; |
| 874 | + } |
| 875 | + |
| 876 | + evt = WSACreateEvent(); |
| 877 | + WSAEventSelect(i, evt, evt_flags); |
| 878 | + |
| 879 | + handles[fd_count + s] = evt; |
| 880 | + s++; |
| 881 | + } else { |
| 882 | + handles[f++] = (HANDLE)h; |
| 883 | + } |
| 884 | + } |
| 885 | + } |
| 886 | + |
| 887 | + /* calculate how long we need to wait in milliseconds */ |
| 888 | + if (tv == NULL) { |
| 889 | + ms_total = INFINITE; |
| 890 | + } else { |
| 891 | + ms_total = tv->tv_sec * 1000; |
| 892 | + ms_total += tv->tv_usec / 1000; |
| 893 | + } |
| 894 | + |
| 895 | + waitret = MsgWaitForMultipleObjects(fd_count + sock_count, handles, FALSE, ms_total, QS_ALLEVENTS); |
| 896 | + |
| 897 | + if (waitret == WAIT_TIMEOUT) { |
| 898 | + retval = 0; |
| 899 | + } else if (waitret == 0xFFFFFFFF) { |
| 900 | + retval = -1; |
| 901 | + } else { |
| 902 | + |
| 903 | + FD_ZERO(&ard); |
| 904 | + FD_ZERO(&awr); |
| 905 | + FD_ZERO(&aex); |
| 906 | + |
| 907 | + f = 0; |
| 908 | + retval = 0; |
| 909 | + for (i = 0; i < max_fd; i++) { |
| 910 | + if (FD_ISSET(i, rfds) || FD_ISSET(i, wfds) || FD_ISSET(i, efds)) { |
| 911 | + if (f >= fd_count) { |
| 912 | + /* socket event */ |
| 913 | + HANDLE evt = handles[f]; |
| 914 | + |
| 915 | + if (WAIT_OBJECT_0 == WaitForSingleObject(evt, 0)) { |
| 916 | + /* check for various signal states */ |
| 917 | + if (FD_ISSET(i, rfds)) { |
| 918 | + WSAEventSelect(i, evt, FD_READ|FD_CONNECT|FD_ACCEPT|FD_CLOSE); |
| 919 | + if (WAIT_OBJECT_0 == WaitForSingleObject(evt, 0)) { |
| 920 | + FD_SET(i, &ard); |
| 921 | + } |
| 922 | + } |
| 923 | + if (FD_ISSET(i, wfds)) { |
| 924 | + WSAEventSelect(i, evt, FD_WRITE); |
| 925 | + if (WAIT_OBJECT_0 == WaitForSingleObject(evt, 0)) { |
| 926 | + FD_SET(i, &awr); |
| 927 | + } |
| 928 | + } |
| 929 | + if (FD_ISSET(i, efds)) { |
| 930 | + WSAEventSelect(i, evt, FD_OOB); |
| 931 | + if (WAIT_OBJECT_0 == WaitForSingleObject(evt, 0)) { |
| 932 | + FD_SET(i, &aex); |
| 933 | + } |
| 934 | + } |
| 935 | + retval++; |
| 936 | + } |
| 937 | + |
| 938 | + WSACloseEvent(evt); |
| 939 | + |
| 940 | + } else { |
| 941 | + if (WAIT_OBJECT_0 == WaitForSingleObject(handles[f], 0)) { |
| 942 | + if (FD_ISSET(i, rfds)) { |
| 943 | + FD_SET(i, &ard); |
| 944 | + } |
| 945 | + if (FD_ISSET(i, wfds)) { |
| 946 | + FD_SET(i, &awr); |
| 947 | + } |
| 948 | + if (FD_ISSET(i, efds)) { |
| 949 | + FD_SET(i, &aex); |
| 950 | + } |
| 951 | + retval++; |
| 952 | + } |
| 953 | + |
| 954 | + } |
| 955 | + f++; |
| 956 | + } |
| 957 | + } |
| 958 | + |
| 959 | + if (rfds) { |
| 960 | + *rfds = ard; |
| 961 | + } |
| 962 | + if (wfds) { |
| 963 | + *wfds = awr; |
| 964 | + } |
| 965 | + if (efds) { |
| 966 | + *efds = aex; |
| 967 | + } |
| 968 | + } |
| 969 | + |
| 970 | + efree(handles); |
| 971 | + |
| 972 | + return retval; |
| 973 | +} |
| 974 | +#else |
| 975 | +#define php_select(m, r, w, e, t) select(m, r, w, e, t) |
| 976 | +#endif |
| 977 | + |
824 | 978 | /* {{{ proto int stream_select(array &read_streams, array &write_streams, array &except_streams, int tv_sec[, int tv_usec])
|
825 | 979 | Runs the select() system call on the sets of streams with a timeout specified by tv_sec and tv_usec */
|
826 | 980 | PHP_FUNCTION(stream_select)
|
@@ -867,11 +1021,11 @@ PHP_FUNCTION(stream_select)
|
867 | 1021 | }
|
868 | 1022 | }
|
869 | 1023 |
|
870 |
| - retval = select(max_fd+1, &rfds, &wfds, &efds, tv_p); |
| 1024 | + retval = php_select(max_fd+1, &rfds, &wfds, &efds, tv_p); |
871 | 1025 |
|
872 | 1026 | if (retval == -1) {
|
873 |
| - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s", |
874 |
| - errno, strerror(errno)); |
| 1027 | + php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s (max_fd=%d)", |
| 1028 | + errno, strerror(errno), max_fd); |
875 | 1029 | RETURN_FALSE;
|
876 | 1030 | }
|
877 | 1031 |
|
|
0 commit comments