1c43e99fdSEd Maste /*
2c43e99fdSEd Maste * Copyright (c) 2009-2012 Niels Provos and Nick Mathewson
3c43e99fdSEd Maste *
4c43e99fdSEd Maste * Redistribution and use in source and binary forms, with or without
5c43e99fdSEd Maste * modification, are permitted provided that the following conditions
6c43e99fdSEd Maste * are met:
7c43e99fdSEd Maste * 1. Redistributions of source code must retain the above copyright
8c43e99fdSEd Maste * notice, this list of conditions and the following disclaimer.
9c43e99fdSEd Maste * 2. Redistributions in binary form must reproduce the above copyright
10c43e99fdSEd Maste * notice, this list of conditions and the following disclaimer in the
11c43e99fdSEd Maste * documentation and/or other materials provided with the distribution.
12c43e99fdSEd Maste * 3. The name of the author may not be used to endorse or promote products
13c43e99fdSEd Maste * derived from this software without specific prior written permission.
14c43e99fdSEd Maste *
15c43e99fdSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16c43e99fdSEd Maste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17c43e99fdSEd Maste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18c43e99fdSEd Maste * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19c43e99fdSEd Maste * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20c43e99fdSEd Maste * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21c43e99fdSEd Maste * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22c43e99fdSEd Maste * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23c43e99fdSEd Maste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24c43e99fdSEd Maste * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25c43e99fdSEd Maste */
26c43e99fdSEd Maste
27c43e99fdSEd Maste /**
28c43e99fdSEd Maste @file buffer_iocp.c
29c43e99fdSEd Maste
30c43e99fdSEd Maste This module implements overlapped read and write functions for evbuffer
31c43e99fdSEd Maste objects on Windows.
32c43e99fdSEd Maste */
33c43e99fdSEd Maste #include "event2/event-config.h"
34c43e99fdSEd Maste #include "evconfig-private.h"
35c43e99fdSEd Maste
36c43e99fdSEd Maste #include "event2/buffer.h"
37c43e99fdSEd Maste #include "event2/buffer_compat.h"
38c43e99fdSEd Maste #include "event2/util.h"
39c43e99fdSEd Maste #include "event2/thread.h"
40c43e99fdSEd Maste #include "util-internal.h"
41c43e99fdSEd Maste #include "evthread-internal.h"
42c43e99fdSEd Maste #include "evbuffer-internal.h"
43c43e99fdSEd Maste #include "iocp-internal.h"
44c43e99fdSEd Maste #include "mm-internal.h"
45c43e99fdSEd Maste
46c43e99fdSEd Maste #include <winsock2.h>
47*b50261e2SCy Schubert #include <winerror.h>
48c43e99fdSEd Maste #include <windows.h>
49c43e99fdSEd Maste #include <stdio.h>
50c43e99fdSEd Maste
51c43e99fdSEd Maste #define MAX_WSABUFS 16
52c43e99fdSEd Maste
53c43e99fdSEd Maste /** An evbuffer that can handle overlapped IO. */
54c43e99fdSEd Maste struct evbuffer_overlapped {
55c43e99fdSEd Maste struct evbuffer buffer;
56c43e99fdSEd Maste /** The socket that we're doing overlapped IO on. */
57c43e99fdSEd Maste evutil_socket_t fd;
58c43e99fdSEd Maste
59c43e99fdSEd Maste /** pending I/O type */
60c43e99fdSEd Maste unsigned read_in_progress : 1;
61c43e99fdSEd Maste unsigned write_in_progress : 1;
62c43e99fdSEd Maste
63c43e99fdSEd Maste /** The first pinned chain in the buffer. */
64c43e99fdSEd Maste struct evbuffer_chain *first_pinned;
65c43e99fdSEd Maste
66c43e99fdSEd Maste /** How many chains are pinned; how many of the fields in buffers
67c43e99fdSEd Maste * are we using. */
68c43e99fdSEd Maste int n_buffers;
69c43e99fdSEd Maste WSABUF buffers[MAX_WSABUFS];
70c43e99fdSEd Maste };
71c43e99fdSEd Maste
72c43e99fdSEd Maste /** Given an evbuffer, return the correponding evbuffer structure, or NULL if
73c43e99fdSEd Maste * the evbuffer isn't overlapped. */
74c43e99fdSEd Maste static inline struct evbuffer_overlapped *
upcast_evbuffer(struct evbuffer * buf)75c43e99fdSEd Maste upcast_evbuffer(struct evbuffer *buf)
76c43e99fdSEd Maste {
77c43e99fdSEd Maste if (!buf || !buf->is_overlapped)
78c43e99fdSEd Maste return NULL;
79c43e99fdSEd Maste return EVUTIL_UPCAST(buf, struct evbuffer_overlapped, buffer);
80c43e99fdSEd Maste }
81c43e99fdSEd Maste
82c43e99fdSEd Maste /** Unpin all the chains noted as pinned in 'eo'. */
83c43e99fdSEd Maste static void
pin_release(struct evbuffer_overlapped * eo,unsigned flag)84c43e99fdSEd Maste pin_release(struct evbuffer_overlapped *eo, unsigned flag)
85c43e99fdSEd Maste {
86c43e99fdSEd Maste int i;
87c43e99fdSEd Maste struct evbuffer_chain *next, *chain = eo->first_pinned;
88c43e99fdSEd Maste
89c43e99fdSEd Maste for (i = 0; i < eo->n_buffers; ++i) {
90c43e99fdSEd Maste EVUTIL_ASSERT(chain);
91c43e99fdSEd Maste next = chain->next;
92c43e99fdSEd Maste evbuffer_chain_unpin_(chain, flag);
93c43e99fdSEd Maste chain = next;
94c43e99fdSEd Maste }
95c43e99fdSEd Maste }
96c43e99fdSEd Maste
97c43e99fdSEd Maste void
evbuffer_commit_read_(struct evbuffer * evbuf,ev_ssize_t nBytes)98c43e99fdSEd Maste evbuffer_commit_read_(struct evbuffer *evbuf, ev_ssize_t nBytes)
99c43e99fdSEd Maste {
100c43e99fdSEd Maste struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf);
101c43e99fdSEd Maste struct evbuffer_chain **chainp;
102c43e99fdSEd Maste size_t remaining, len;
103c43e99fdSEd Maste unsigned i;
104c43e99fdSEd Maste
105c43e99fdSEd Maste EVBUFFER_LOCK(evbuf);
106c43e99fdSEd Maste EVUTIL_ASSERT(buf->read_in_progress && !buf->write_in_progress);
107c43e99fdSEd Maste EVUTIL_ASSERT(nBytes >= 0); /* XXXX Can this be false? */
108c43e99fdSEd Maste
109c43e99fdSEd Maste evbuffer_unfreeze(evbuf, 0);
110c43e99fdSEd Maste
111c43e99fdSEd Maste chainp = evbuf->last_with_datap;
112c43e99fdSEd Maste if (!((*chainp)->flags & EVBUFFER_MEM_PINNED_R))
113c43e99fdSEd Maste chainp = &(*chainp)->next;
114c43e99fdSEd Maste remaining = nBytes;
115c43e99fdSEd Maste for (i = 0; remaining > 0 && i < (unsigned)buf->n_buffers; ++i) {
116c43e99fdSEd Maste EVUTIL_ASSERT(*chainp);
117c43e99fdSEd Maste len = buf->buffers[i].len;
118c43e99fdSEd Maste if (remaining < len)
119c43e99fdSEd Maste len = remaining;
120c43e99fdSEd Maste (*chainp)->off += len;
121c43e99fdSEd Maste evbuf->last_with_datap = chainp;
122c43e99fdSEd Maste remaining -= len;
123c43e99fdSEd Maste chainp = &(*chainp)->next;
124c43e99fdSEd Maste }
125c43e99fdSEd Maste
126c43e99fdSEd Maste pin_release(buf, EVBUFFER_MEM_PINNED_R);
127c43e99fdSEd Maste
128c43e99fdSEd Maste buf->read_in_progress = 0;
129c43e99fdSEd Maste
130c43e99fdSEd Maste evbuf->total_len += nBytes;
131c43e99fdSEd Maste evbuf->n_add_for_cb += nBytes;
132c43e99fdSEd Maste
133c43e99fdSEd Maste evbuffer_invoke_callbacks_(evbuf);
134c43e99fdSEd Maste
135c43e99fdSEd Maste evbuffer_decref_and_unlock_(evbuf);
136c43e99fdSEd Maste }
137c43e99fdSEd Maste
138c43e99fdSEd Maste void
evbuffer_commit_write_(struct evbuffer * evbuf,ev_ssize_t nBytes)139c43e99fdSEd Maste evbuffer_commit_write_(struct evbuffer *evbuf, ev_ssize_t nBytes)
140c43e99fdSEd Maste {
141c43e99fdSEd Maste struct evbuffer_overlapped *buf = upcast_evbuffer(evbuf);
142c43e99fdSEd Maste
143c43e99fdSEd Maste EVBUFFER_LOCK(evbuf);
144c43e99fdSEd Maste EVUTIL_ASSERT(buf->write_in_progress && !buf->read_in_progress);
145c43e99fdSEd Maste evbuffer_unfreeze(evbuf, 1);
146c43e99fdSEd Maste evbuffer_drain(evbuf, nBytes);
147c43e99fdSEd Maste pin_release(buf,EVBUFFER_MEM_PINNED_W);
148c43e99fdSEd Maste buf->write_in_progress = 0;
149c43e99fdSEd Maste evbuffer_decref_and_unlock_(evbuf);
150c43e99fdSEd Maste }
151c43e99fdSEd Maste
152c43e99fdSEd Maste struct evbuffer *
evbuffer_overlapped_new_(evutil_socket_t fd)153c43e99fdSEd Maste evbuffer_overlapped_new_(evutil_socket_t fd)
154c43e99fdSEd Maste {
155c43e99fdSEd Maste struct evbuffer_overlapped *evo;
156c43e99fdSEd Maste
157c43e99fdSEd Maste evo = mm_calloc(1, sizeof(struct evbuffer_overlapped));
158c43e99fdSEd Maste if (!evo)
159c43e99fdSEd Maste return NULL;
160c43e99fdSEd Maste
161c43e99fdSEd Maste LIST_INIT(&evo->buffer.callbacks);
162c43e99fdSEd Maste evo->buffer.refcnt = 1;
163c43e99fdSEd Maste evo->buffer.last_with_datap = &evo->buffer.first;
164c43e99fdSEd Maste
165c43e99fdSEd Maste evo->buffer.is_overlapped = 1;
166c43e99fdSEd Maste evo->fd = fd;
167c43e99fdSEd Maste
168c43e99fdSEd Maste return &evo->buffer;
169c43e99fdSEd Maste }
170c43e99fdSEd Maste
171c43e99fdSEd Maste int
evbuffer_launch_write_(struct evbuffer * buf,ev_ssize_t at_most,struct event_overlapped * ol)172c43e99fdSEd Maste evbuffer_launch_write_(struct evbuffer *buf, ev_ssize_t at_most,
173c43e99fdSEd Maste struct event_overlapped *ol)
174c43e99fdSEd Maste {
175c43e99fdSEd Maste struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
176c43e99fdSEd Maste int r = -1;
177c43e99fdSEd Maste int i;
178c43e99fdSEd Maste struct evbuffer_chain *chain;
179c43e99fdSEd Maste DWORD bytesSent;
180c43e99fdSEd Maste
181c43e99fdSEd Maste if (!buf) {
182c43e99fdSEd Maste /* No buffer, or it isn't overlapped */
183c43e99fdSEd Maste return -1;
184c43e99fdSEd Maste }
185c43e99fdSEd Maste
186c43e99fdSEd Maste EVBUFFER_LOCK(buf);
187c43e99fdSEd Maste EVUTIL_ASSERT(!buf_o->read_in_progress);
188c43e99fdSEd Maste if (buf->freeze_start || buf_o->write_in_progress)
189c43e99fdSEd Maste goto done;
190c43e99fdSEd Maste if (!buf->total_len) {
191c43e99fdSEd Maste /* Nothing to write */
192c43e99fdSEd Maste r = 0;
193c43e99fdSEd Maste goto done;
194c43e99fdSEd Maste } else if (at_most < 0 || (size_t)at_most > buf->total_len) {
195c43e99fdSEd Maste at_most = buf->total_len;
196c43e99fdSEd Maste }
197c43e99fdSEd Maste evbuffer_freeze(buf, 1);
198c43e99fdSEd Maste
199c43e99fdSEd Maste buf_o->first_pinned = NULL;
200c43e99fdSEd Maste buf_o->n_buffers = 0;
201c43e99fdSEd Maste memset(buf_o->buffers, 0, sizeof(buf_o->buffers));
202c43e99fdSEd Maste
203c43e99fdSEd Maste chain = buf_o->first_pinned = buf->first;
204c43e99fdSEd Maste
205c43e99fdSEd Maste for (i=0; i < MAX_WSABUFS && chain; ++i, chain=chain->next) {
206c43e99fdSEd Maste WSABUF *b = &buf_o->buffers[i];
207c43e99fdSEd Maste b->buf = (char*)( chain->buffer + chain->misalign );
208c43e99fdSEd Maste evbuffer_chain_pin_(chain, EVBUFFER_MEM_PINNED_W);
209c43e99fdSEd Maste
210c43e99fdSEd Maste if ((size_t)at_most > chain->off) {
211c43e99fdSEd Maste /* XXXX Cast is safe for now, since win32 has no
212c43e99fdSEd Maste mmaped chains. But later, we need to have this
213c43e99fdSEd Maste add more WSAbufs if chain->off is greater than
214c43e99fdSEd Maste ULONG_MAX */
215c43e99fdSEd Maste b->len = (unsigned long)chain->off;
216c43e99fdSEd Maste at_most -= chain->off;
217c43e99fdSEd Maste } else {
218c43e99fdSEd Maste b->len = (unsigned long)at_most;
219c43e99fdSEd Maste ++i;
220c43e99fdSEd Maste break;
221c43e99fdSEd Maste }
222c43e99fdSEd Maste }
223c43e99fdSEd Maste
224c43e99fdSEd Maste buf_o->n_buffers = i;
225c43e99fdSEd Maste evbuffer_incref_(buf);
226c43e99fdSEd Maste if (WSASend(buf_o->fd, buf_o->buffers, i, &bytesSent, 0,
227c43e99fdSEd Maste &ol->overlapped, NULL)) {
228c43e99fdSEd Maste int error = WSAGetLastError();
229c43e99fdSEd Maste if (error != WSA_IO_PENDING) {
230c43e99fdSEd Maste /* An actual error. */
231c43e99fdSEd Maste pin_release(buf_o, EVBUFFER_MEM_PINNED_W);
232c43e99fdSEd Maste evbuffer_unfreeze(buf, 1);
233c43e99fdSEd Maste evbuffer_free(buf); /* decref */
234c43e99fdSEd Maste goto done;
235c43e99fdSEd Maste }
236c43e99fdSEd Maste }
237c43e99fdSEd Maste
238c43e99fdSEd Maste buf_o->write_in_progress = 1;
239c43e99fdSEd Maste r = 0;
240c43e99fdSEd Maste done:
241c43e99fdSEd Maste EVBUFFER_UNLOCK(buf);
242c43e99fdSEd Maste return r;
243c43e99fdSEd Maste }
244c43e99fdSEd Maste
245c43e99fdSEd Maste int
evbuffer_launch_read_(struct evbuffer * buf,size_t at_most,struct event_overlapped * ol)246c43e99fdSEd Maste evbuffer_launch_read_(struct evbuffer *buf, size_t at_most,
247c43e99fdSEd Maste struct event_overlapped *ol)
248c43e99fdSEd Maste {
249c43e99fdSEd Maste struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
250c43e99fdSEd Maste int r = -1, i;
251c43e99fdSEd Maste int nvecs;
252c43e99fdSEd Maste int npin=0;
253c43e99fdSEd Maste struct evbuffer_chain *chain=NULL, **chainp;
254c43e99fdSEd Maste DWORD bytesRead;
255c43e99fdSEd Maste DWORD flags = 0;
256c43e99fdSEd Maste struct evbuffer_iovec vecs[MAX_WSABUFS];
257c43e99fdSEd Maste
258c43e99fdSEd Maste if (!buf_o)
259c43e99fdSEd Maste return -1;
260c43e99fdSEd Maste EVBUFFER_LOCK(buf);
261c43e99fdSEd Maste EVUTIL_ASSERT(!buf_o->write_in_progress);
262c43e99fdSEd Maste if (buf->freeze_end || buf_o->read_in_progress)
263c43e99fdSEd Maste goto done;
264c43e99fdSEd Maste
265c43e99fdSEd Maste buf_o->first_pinned = NULL;
266c43e99fdSEd Maste buf_o->n_buffers = 0;
267c43e99fdSEd Maste memset(buf_o->buffers, 0, sizeof(buf_o->buffers));
268c43e99fdSEd Maste
269c43e99fdSEd Maste if (evbuffer_expand_fast_(buf, at_most, MAX_WSABUFS) == -1)
270c43e99fdSEd Maste goto done;
271c43e99fdSEd Maste evbuffer_freeze(buf, 0);
272c43e99fdSEd Maste
273c43e99fdSEd Maste nvecs = evbuffer_read_setup_vecs_(buf, at_most,
274c43e99fdSEd Maste vecs, MAX_WSABUFS, &chainp, 1);
275c43e99fdSEd Maste for (i=0;i<nvecs;++i) {
276c43e99fdSEd Maste WSABUF_FROM_EVBUFFER_IOV(
277c43e99fdSEd Maste &buf_o->buffers[i],
278c43e99fdSEd Maste &vecs[i]);
279c43e99fdSEd Maste }
280c43e99fdSEd Maste
281c43e99fdSEd Maste buf_o->n_buffers = nvecs;
282c43e99fdSEd Maste buf_o->first_pinned = chain = *chainp;
283c43e99fdSEd Maste
284c43e99fdSEd Maste npin=0;
285c43e99fdSEd Maste for ( ; chain; chain = chain->next) {
286c43e99fdSEd Maste evbuffer_chain_pin_(chain, EVBUFFER_MEM_PINNED_R);
287c43e99fdSEd Maste ++npin;
288c43e99fdSEd Maste }
289c43e99fdSEd Maste EVUTIL_ASSERT(npin == nvecs);
290c43e99fdSEd Maste
291c43e99fdSEd Maste evbuffer_incref_(buf);
292c43e99fdSEd Maste if (WSARecv(buf_o->fd, buf_o->buffers, nvecs, &bytesRead, &flags,
293c43e99fdSEd Maste &ol->overlapped, NULL)) {
294c43e99fdSEd Maste int error = WSAGetLastError();
295c43e99fdSEd Maste if (error != WSA_IO_PENDING) {
296c43e99fdSEd Maste /* An actual error. */
297c43e99fdSEd Maste pin_release(buf_o, EVBUFFER_MEM_PINNED_R);
298c43e99fdSEd Maste evbuffer_unfreeze(buf, 0);
299c43e99fdSEd Maste evbuffer_free(buf); /* decref */
300c43e99fdSEd Maste goto done;
301c43e99fdSEd Maste }
302c43e99fdSEd Maste }
303c43e99fdSEd Maste
304c43e99fdSEd Maste buf_o->read_in_progress = 1;
305c43e99fdSEd Maste r = 0;
306c43e99fdSEd Maste done:
307c43e99fdSEd Maste EVBUFFER_UNLOCK(buf);
308c43e99fdSEd Maste return r;
309c43e99fdSEd Maste }
310c43e99fdSEd Maste
311c43e99fdSEd Maste evutil_socket_t
evbuffer_overlapped_get_fd_(struct evbuffer * buf)312c43e99fdSEd Maste evbuffer_overlapped_get_fd_(struct evbuffer *buf)
313c43e99fdSEd Maste {
314c43e99fdSEd Maste struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
315c43e99fdSEd Maste return buf_o ? buf_o->fd : -1;
316c43e99fdSEd Maste }
317c43e99fdSEd Maste
318c43e99fdSEd Maste void
evbuffer_overlapped_set_fd_(struct evbuffer * buf,evutil_socket_t fd)319c43e99fdSEd Maste evbuffer_overlapped_set_fd_(struct evbuffer *buf, evutil_socket_t fd)
320c43e99fdSEd Maste {
321c43e99fdSEd Maste struct evbuffer_overlapped *buf_o = upcast_evbuffer(buf);
322c43e99fdSEd Maste EVBUFFER_LOCK(buf);
323c43e99fdSEd Maste /* XXX is this right?, should it cancel current I/O operations? */
324c43e99fdSEd Maste if (buf_o)
325c43e99fdSEd Maste buf_o->fd = fd;
326c43e99fdSEd Maste EVBUFFER_UNLOCK(buf);
327c43e99fdSEd Maste }
328