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-1335 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 */
disable_iocp_notification(OVERLAPPED * overlapped)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 */
enable_iocp_notification(OVERLAPPED * overlapped)31 static void enable_iocp_notification(OVERLAPPED *overlapped)
32 {
33 HANDLE *handle = &(overlapped->hEvent);
34 *handle = (HANDLE)((ULONG_PTR) *handle & ~1);
35 }
36
wait_overlapped_result(Vio * vio,int timeout)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
vio_read_pipe(Vio * vio,uchar * buf,size_t count)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 if (vio->shutdown_flag)
79 return ret;
80
81 disable_iocp_notification(&vio->overlapped);
82
83 /* Attempt to read from the pipe (overlapped I/O). */
84 if (ReadFile(vio->hPipe, buf, (DWORD)count, &transferred, &vio->overlapped))
85 {
86 /* The operation completed immediately. */
87 ret= transferred;
88 }
89 /* Read operation is pending completion asynchronously? */
90 else if (GetLastError() == ERROR_IO_PENDING)
91 {
92 if (vio->shutdown_flag)
93 CancelIo(vio->hPipe);
94 ret= wait_overlapped_result(vio, vio->read_timeout);
95 }
96 enable_iocp_notification(&vio->overlapped);
97
98 DBUG_RETURN(ret);
99 }
100
101
vio_write_pipe(Vio * vio,const uchar * buf,size_t count)102 size_t vio_write_pipe(Vio *vio, const uchar *buf, size_t count)
103 {
104 DWORD transferred;
105 size_t ret= (size_t) -1;
106 DBUG_ENTER("vio_write_pipe");
107
108 if (vio->shutdown_flag == SHUT_RDWR)
109 return ret;
110 disable_iocp_notification(&vio->overlapped);
111 /* Attempt to write to the pipe (overlapped I/O). */
112 if (WriteFile(vio->hPipe, buf, (DWORD)count, &transferred, &vio->overlapped))
113 {
114 /* The operation completed immediately. */
115 ret= transferred;
116 }
117 /* Write operation is pending completion asynchronously? */
118 else if (GetLastError() == ERROR_IO_PENDING)
119 {
120 if (vio->shutdown_flag == SHUT_RDWR)
121 CancelIo(vio->hPipe);
122 ret= wait_overlapped_result(vio, vio->write_timeout);
123 }
124 enable_iocp_notification(&vio->overlapped);
125 DBUG_RETURN(ret);
126 }
127
128
vio_is_connected_pipe(Vio * vio)129 my_bool vio_is_connected_pipe(Vio *vio)
130 {
131 if (PeekNamedPipe(vio->hPipe, NULL, 0, NULL, NULL, NULL))
132 return TRUE;
133 else
134 return (GetLastError() != ERROR_BROKEN_PIPE);
135 }
136
137
vio_close_pipe(Vio * vio)138 int vio_close_pipe(Vio *vio)
139 {
140 BOOL ret;
141 DBUG_ENTER("vio_close_pipe");
142
143 CloseHandle(vio->overlapped.hEvent);
144 ret= CloseHandle(vio->hPipe);
145
146 vio->type= VIO_CLOSED;
147 vio->hPipe= NULL;
148 vio->mysql_socket= MYSQL_INVALID_SOCKET;
149
150 DBUG_RETURN(ret);
151 }
152
153 /* return number of bytes readable from pipe.*/
vio_pending_pipe(Vio * vio)154 uint vio_pending_pipe(Vio *vio)
155 {
156 DWORD bytes;
157 return PeekNamedPipe(vio->hPipe, NULL, 0, NULL, &bytes, NULL) ? bytes : 0;
158 }
159 #endif
160
161