1 | /* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. |
2 | |
3 | This program is free software; you can redistribute it and/or modify |
4 | it under the terms of the GNU General Public License as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
15 | |
16 | #include "vio_priv.h" |
17 | |
18 | #ifdef _WIN32 |
19 | |
20 | /* |
21 | Disable posting IO completion event to the port. |
22 | In some cases (synchronous timed IO) we want to skip IOCP notifications. |
23 | */ |
24 | static void disable_iocp_notification(OVERLAPPED *overlapped) |
25 | { |
26 | HANDLE *handle = &(overlapped->hEvent); |
27 | *handle = ((HANDLE)((ULONG_PTR) *handle|1)); |
28 | } |
29 | |
30 | /* Enable posting IO completion event to the port */ |
31 | static void enable_iocp_notification(OVERLAPPED *overlapped) |
32 | { |
33 | HANDLE *handle = &(overlapped->hEvent); |
34 | *handle = (HANDLE)((ULONG_PTR) *handle & ~1); |
35 | } |
36 | |
37 | static size_t wait_overlapped_result(Vio *vio, int timeout) |
38 | { |
39 | size_t ret= (size_t) -1; |
40 | DWORD transferred, wait_status, timeout_ms; |
41 | |
42 | timeout_ms= timeout >= 0 ? timeout : INFINITE; |
43 | |
44 | /* Wait for the overlapped operation to be completed. */ |
45 | wait_status= WaitForSingleObject(vio->overlapped.hEvent, timeout_ms); |
46 | |
47 | /* The operation might have completed, attempt to retrieve the result. */ |
48 | if (wait_status == WAIT_OBJECT_0) |
49 | { |
50 | /* If retrieval fails, a error code will have been set. */ |
51 | if (GetOverlappedResult(vio->hPipe, &vio->overlapped, &transferred, FALSE)) |
52 | ret= transferred; |
53 | } |
54 | else |
55 | { |
56 | /* Error or timeout, cancel the pending I/O operation. */ |
57 | CancelIo(vio->hPipe); |
58 | |
59 | /* |
60 | If the wait timed out, set error code to indicate a |
61 | timeout error. Otherwise, wait_status is WAIT_FAILED |
62 | and extended error information was already set. |
63 | */ |
64 | if (wait_status == WAIT_TIMEOUT) |
65 | SetLastError(SOCKET_ETIMEDOUT); |
66 | } |
67 | |
68 | return ret; |
69 | } |
70 | |
71 | |
72 | size_t vio_read_pipe(Vio *vio, uchar *buf, size_t count) |
73 | { |
74 | DWORD transferred; |
75 | size_t ret= (size_t) -1; |
76 | DBUG_ENTER("vio_read_pipe" ); |
77 | |
78 | disable_iocp_notification(&vio->overlapped); |
79 | |
80 | /* Attempt to read from the pipe (overlapped I/O). */ |
81 | if (ReadFile(vio->hPipe, buf, (DWORD)count, &transferred, &vio->overlapped)) |
82 | { |
83 | /* The operation completed immediately. */ |
84 | ret= transferred; |
85 | } |
86 | /* Read operation is pending completion asynchronously? */ |
87 | else if (GetLastError() == ERROR_IO_PENDING) |
88 | ret= wait_overlapped_result(vio, vio->read_timeout); |
89 | |
90 | enable_iocp_notification(&vio->overlapped); |
91 | |
92 | DBUG_RETURN(ret); |
93 | } |
94 | |
95 | |
96 | size_t vio_write_pipe(Vio *vio, const uchar *buf, size_t count) |
97 | { |
98 | DWORD transferred; |
99 | size_t ret= (size_t) -1; |
100 | DBUG_ENTER("vio_write_pipe" ); |
101 | |
102 | disable_iocp_notification(&vio->overlapped); |
103 | /* Attempt to write to the pipe (overlapped I/O). */ |
104 | if (WriteFile(vio->hPipe, buf, (DWORD)count, &transferred, &vio->overlapped)) |
105 | { |
106 | /* The operation completed immediately. */ |
107 | ret= transferred; |
108 | } |
109 | /* Write operation is pending completion asynchronously? */ |
110 | else if (GetLastError() == ERROR_IO_PENDING) |
111 | ret= wait_overlapped_result(vio, vio->write_timeout); |
112 | |
113 | enable_iocp_notification(&vio->overlapped); |
114 | DBUG_RETURN(ret); |
115 | } |
116 | |
117 | |
118 | my_bool vio_is_connected_pipe(Vio *vio) |
119 | { |
120 | if (PeekNamedPipe(vio->hPipe, NULL, 0, NULL, NULL, NULL)) |
121 | return TRUE; |
122 | else |
123 | return (GetLastError() != ERROR_BROKEN_PIPE); |
124 | } |
125 | |
126 | |
127 | int vio_close_pipe(Vio *vio) |
128 | { |
129 | BOOL ret; |
130 | DBUG_ENTER("vio_close_pipe" ); |
131 | |
132 | CancelIo(vio->hPipe); |
133 | CloseHandle(vio->overlapped.hEvent); |
134 | DisconnectNamedPipe(vio->hPipe); |
135 | ret= CloseHandle(vio->hPipe); |
136 | |
137 | vio->type= VIO_CLOSED; |
138 | vio->hPipe= NULL; |
139 | vio->mysql_socket= MYSQL_INVALID_SOCKET; |
140 | |
141 | DBUG_RETURN(ret); |
142 | } |
143 | |
144 | #endif |
145 | |
146 | |