xref: /openssl/doc/designs/ddd/WINDOWS.md (revision ec36534c)
1Windows-related issues
2======================
3
4Supporting Windows introduces some complications due to some "fun" peculiarities
5of Windows's socket API.
6
7In general, Windows does not provide a poll(2) call. WSAPoll(2) was introduced
8in Vista and supposed to bring this functionality, but it had a bug in it which
9Microsoft refused to fix, making it rather pointless. However Microsoft has now
10finally fixed this bug in a build of Windows 10. So WSAPoll(2) is a viable
11method, but only on fairly new versions of Windows.
12
13Traditionally, polling has been done on windows using select(). However, this
14call works a little differently than on POSIX platforms. Whereas on POSIX
15platforms select() accepts a bitmask of FDs, on Windows select() accepts a
16structure which embeds a fixed-length array of socket handles. This is necessary
17because sockets are NT kernel handles on Windows and thus are not allocated
18contiguously like FDs. As such, Windows select() is actually very similar to
19POSIX poll(), making select() a viable option for polling on Windows.
20
21Neither select() nor poll() are, of course, high performance polling options.
22Windows does not provide anything like epoll or kqueue. For high performance
23network I/O, you are expected to use a Windows API called I/O Completion Ports
24(IOCP).
25
26Supporting these is a pain for applications designed around polling. The reason
27is that IOCPs are a higher-level interface; it is easy to build an IOCP-like
28interface on top of polling, but it is not really possible to build a
29polling-like interface on top of IOCPs.
30
31For this reason it's actually common for asynchronous I/O libraries to basically
32contain two separate implementations of their APIs internally, or at least a
33substantial chunk of their code (e.g. libuv, nanomsg). It turns out to be easier
34just to write a poll-based implementation of an I/O reactor and an IOCP-based
35implementation than try to overcome the impedence discontinuities.
36
37The difference between polling and IOCPs is that polling reports *readiness*
38whereas IOCPs report *completion of an operation*. For example, in the IOCP
39model, you make a read or write on a socket and an event is posted to the IOCP
40when the read or write is complete. This is a fundamentally different model and
41actually more similar to a high-level asynchronous I/O library such as libuv or
42so on.
43
44Evaluation of the existing demos and their applicability to Windows IOCP:
45
46- ddd-01-conn-blocking: Blocking example, use of IOCP is not applicable.
47
48- ddd-02-conn-nonblocking: Socket is managed by OpenSSL, and IOCP is not
49  supported.
50
51- ddd-03-fd-blocking: Blocking example, use of IOCP is not applicable.
52
53- ddd-04-fd-nonblocking: libssl is passed an FD with BIO_set_fd.
54
55  BIO_s_sock doesn't appear to support overlapped (that is, IOCP-based) I/O
56  as this requires use of special WSASend() and WSARecv() functions, rather
57  than standard send()/recv().
58
59  Since libssl already doesn't support IOCP for use of BIO_s_sock,
60  we might say here that any existing application using BIO_s_sock
61  obviously isn't trying to use IOCP, and therefore we don't need to
62  worry about the adapability of this example to IOCP.
63
64- ddd-05-mem-nonblocking: Since the application is in full control of passing
65  data from the memory BIO to the network, or vice versa, the application
66  can use IOCP if it wishes.
67
68  This is demonstrated in the following demo:
69
70- ddd-06-mem-uv: This demo uses a memory BIO and libuv. Since libuv supports
71  IOCP, it proves that a memory BIO can be used to support IOCP-based usage.
72
73Further, a cursory examination of code on GitHub seems to suggest that when
74people do use IOCP with libssl, they do it using memory BIOs passed to libssl.
75So ddd-05 and ddd-06 essentially demonstate this use case, especially ddd-06 as
76it uses IOCP internally on Windows.
77
78My conclusion here is that since libssl does not support IOCP in the first
79place, we don't need to be particularly worried about this. But in the worst
80case there are always workable solutions, as in demos 5 and 6.
81