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