annotate win64-msvc/include/kj/async-io.h @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 0f2d93caa50c
children
rev   line source
Chris@63 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
Chris@63 2 // Licensed under the MIT License:
Chris@63 3 //
Chris@63 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
Chris@63 5 // of this software and associated documentation files (the "Software"), to deal
Chris@63 6 // in the Software without restriction, including without limitation the rights
Chris@63 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Chris@63 8 // copies of the Software, and to permit persons to whom the Software is
Chris@63 9 // furnished to do so, subject to the following conditions:
Chris@63 10 //
Chris@63 11 // The above copyright notice and this permission notice shall be included in
Chris@63 12 // all copies or substantial portions of the Software.
Chris@63 13 //
Chris@63 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Chris@63 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Chris@63 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Chris@63 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Chris@63 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Chris@63 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Chris@63 20 // THE SOFTWARE.
Chris@63 21
Chris@63 22 #ifndef KJ_ASYNC_IO_H_
Chris@63 23 #define KJ_ASYNC_IO_H_
Chris@63 24
Chris@63 25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
Chris@63 26 #pragma GCC system_header
Chris@63 27 #endif
Chris@63 28
Chris@63 29 #include "async.h"
Chris@63 30 #include "function.h"
Chris@63 31 #include "thread.h"
Chris@63 32 #include "time.h"
Chris@63 33
Chris@63 34 struct sockaddr;
Chris@63 35
Chris@63 36 namespace kj {
Chris@63 37
Chris@63 38 #if _WIN32
Chris@63 39 class Win32EventPort;
Chris@63 40 #else
Chris@63 41 class UnixEventPort;
Chris@63 42 #endif
Chris@63 43
Chris@63 44 class NetworkAddress;
Chris@63 45 class AsyncOutputStream;
Chris@63 46
Chris@63 47 // =======================================================================================
Chris@63 48 // Streaming I/O
Chris@63 49
Chris@63 50 class AsyncInputStream {
Chris@63 51 // Asynchronous equivalent of InputStream (from io.h).
Chris@63 52
Chris@63 53 public:
Chris@63 54 virtual Promise<size_t> read(void* buffer, size_t minBytes, size_t maxBytes);
Chris@63 55 virtual Promise<size_t> tryRead(void* buffer, size_t minBytes, size_t maxBytes) = 0;
Chris@63 56
Chris@63 57 Promise<void> read(void* buffer, size_t bytes);
Chris@63 58
Chris@63 59 virtual Maybe<uint64_t> tryGetLength();
Chris@63 60 // Get the remaining number of bytes that will be produced by this stream, if known.
Chris@63 61 //
Chris@63 62 // This is used e.g. to fill in the Content-Length header of an HTTP message. If unknown, the
Chris@63 63 // HTTP implementation may need to fall back to Transfer-Encoding: chunked.
Chris@63 64 //
Chris@63 65 // The default implementation always returns null.
Chris@63 66
Chris@63 67 virtual Promise<uint64_t> pumpTo(
Chris@63 68 AsyncOutputStream& output, uint64_t amount = kj::maxValue);
Chris@63 69 // Read `amount` bytes from this stream (or to EOF) and write them to `output`, returning the
Chris@63 70 // total bytes actually pumped (which is only less than `amount` if EOF was reached).
Chris@63 71 //
Chris@63 72 // Override this if your stream type knows how to pump itself to certain kinds of output
Chris@63 73 // streams more efficiently than via the naive approach. You can use
Chris@63 74 // kj::dynamicDowncastIfAvailable() to test for stream types you recognize, and if none match,
Chris@63 75 // delegate to the default implementation.
Chris@63 76 //
Chris@63 77 // The default implementation first tries calling output.tryPumpFrom(), but if that fails, it
Chris@63 78 // performs a naive pump by allocating a buffer and reading to it / writing from it in a loop.
Chris@63 79
Chris@63 80 Promise<Array<byte>> readAllBytes();
Chris@63 81 Promise<String> readAllText();
Chris@63 82 // Read until EOF and return as one big byte array or string.
Chris@63 83 };
Chris@63 84
Chris@63 85 class AsyncOutputStream {
Chris@63 86 // Asynchronous equivalent of OutputStream (from io.h).
Chris@63 87
Chris@63 88 public:
Chris@63 89 virtual Promise<void> write(const void* buffer, size_t size) = 0;
Chris@63 90 virtual Promise<void> write(ArrayPtr<const ArrayPtr<const byte>> pieces) = 0;
Chris@63 91
Chris@63 92 virtual Maybe<Promise<uint64_t>> tryPumpFrom(
Chris@63 93 AsyncInputStream& input, uint64_t amount = kj::maxValue);
Chris@63 94 // Implements double-dispatch for AsyncInputStream::pumpTo().
Chris@63 95 //
Chris@63 96 // This method should only be called from within an implementation of pumpTo().
Chris@63 97 //
Chris@63 98 // This method examines the type of `input` to find optimized ways to pump data from it to this
Chris@63 99 // output stream. If it finds one, it performs the pump. Otherwise, it returns null.
Chris@63 100 //
Chris@63 101 // The default implementation always returns null.
Chris@63 102 };
Chris@63 103
Chris@63 104 class AsyncIoStream: public AsyncInputStream, public AsyncOutputStream {
Chris@63 105 // A combination input and output stream.
Chris@63 106
Chris@63 107 public:
Chris@63 108 virtual void shutdownWrite() = 0;
Chris@63 109 // Cleanly shut down just the write end of the stream, while keeping the read end open.
Chris@63 110
Chris@63 111 virtual void abortRead() {}
Chris@63 112 // Similar to shutdownWrite, but this will shut down the read end of the stream, and should only
Chris@63 113 // be called when an error has occurred.
Chris@63 114
Chris@63 115 virtual void getsockopt(int level, int option, void* value, uint* length);
Chris@63 116 virtual void setsockopt(int level, int option, const void* value, uint length);
Chris@63 117 // Corresponds to getsockopt() and setsockopt() syscalls. Will throw an "unimplemented" exception
Chris@63 118 // if the stream is not a socket or the option is not appropriate for the socket type. The
Chris@63 119 // default implementations always throw "unimplemented".
Chris@63 120
Chris@63 121 virtual void getsockname(struct sockaddr* addr, uint* length);
Chris@63 122 virtual void getpeername(struct sockaddr* addr, uint* length);
Chris@63 123 // Corresponds to getsockname() and getpeername() syscalls. Will throw an "unimplemented"
Chris@63 124 // exception if the stream is not a socket. The default implementations always throw
Chris@63 125 // "unimplemented".
Chris@63 126 //
Chris@63 127 // Note that we don't provide methods that return NetworkAddress because it usually wouldn't
Chris@63 128 // be useful. You can't connect() to or listen() on these addresses, obviously, because they are
Chris@63 129 // ephemeral addresses for a single connection.
Chris@63 130 };
Chris@63 131
Chris@63 132 struct OneWayPipe {
Chris@63 133 // A data pipe with an input end and an output end. (Typically backed by pipe() system call.)
Chris@63 134
Chris@63 135 Own<AsyncInputStream> in;
Chris@63 136 Own<AsyncOutputStream> out;
Chris@63 137 };
Chris@63 138
Chris@63 139 struct TwoWayPipe {
Chris@63 140 // A data pipe that supports sending in both directions. Each end's output sends data to the
Chris@63 141 // other end's input. (Typically backed by socketpair() system call.)
Chris@63 142
Chris@63 143 Own<AsyncIoStream> ends[2];
Chris@63 144 };
Chris@63 145
Chris@63 146 class ConnectionReceiver {
Chris@63 147 // Represents a server socket listening on a port.
Chris@63 148
Chris@63 149 public:
Chris@63 150 virtual Promise<Own<AsyncIoStream>> accept() = 0;
Chris@63 151 // Accept the next incoming connection.
Chris@63 152
Chris@63 153 virtual uint getPort() = 0;
Chris@63 154 // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't
Chris@63 155 // specify a port when constructing the NetworkAddress -- one will have been assigned
Chris@63 156 // automatically.
Chris@63 157
Chris@63 158 virtual void getsockopt(int level, int option, void* value, uint* length);
Chris@63 159 virtual void setsockopt(int level, int option, const void* value, uint length);
Chris@63 160 // Same as the methods of AsyncIoStream.
Chris@63 161 };
Chris@63 162
Chris@63 163 // =======================================================================================
Chris@63 164 // Datagram I/O
Chris@63 165
Chris@63 166 class AncillaryMessage {
Chris@63 167 // Represents an ancillary message (aka control message) received using the recvmsg() system
Chris@63 168 // call (or equivalent). Most apps will not use this.
Chris@63 169
Chris@63 170 public:
Chris@63 171 inline AncillaryMessage(int level, int type, ArrayPtr<const byte> data);
Chris@63 172 AncillaryMessage() = default;
Chris@63 173
Chris@63 174 inline int getLevel() const;
Chris@63 175 // Originating protocol / socket level.
Chris@63 176
Chris@63 177 inline int getType() const;
Chris@63 178 // Protocol-specific message type.
Chris@63 179
Chris@63 180 template <typename T>
Chris@63 181 inline Maybe<const T&> as();
Chris@63 182 // Interpret the ancillary message as the given struct type. Most ancillary messages are some
Chris@63 183 // sort of struct, so this is a convenient way to access it. Returns nullptr if the message
Chris@63 184 // is smaller than the struct -- this can happen if the message was truncated due to
Chris@63 185 // insufficient ancillary buffer space.
Chris@63 186
Chris@63 187 template <typename T>
Chris@63 188 inline ArrayPtr<const T> asArray();
Chris@63 189 // Interpret the ancillary message as an array of items. If the message size does not evenly
Chris@63 190 // divide into elements of type T, the remainder is discarded -- this can happen if the message
Chris@63 191 // was truncated due to insufficient ancillary buffer space.
Chris@63 192
Chris@63 193 private:
Chris@63 194 int level;
Chris@63 195 int type;
Chris@63 196 ArrayPtr<const byte> data;
Chris@63 197 // Message data. In most cases you should use `as()` or `asArray()`.
Chris@63 198 };
Chris@63 199
Chris@63 200 class DatagramReceiver {
Chris@63 201 // Class encapsulating the recvmsg() system call. You must specify the DatagramReceiver's
Chris@63 202 // capacity in advance; if a received packet is larger than the capacity, it will be truncated.
Chris@63 203
Chris@63 204 public:
Chris@63 205 virtual Promise<void> receive() = 0;
Chris@63 206 // Receive a new message, overwriting this object's content.
Chris@63 207 //
Chris@63 208 // receive() may reuse the same buffers for content and ancillary data with each call.
Chris@63 209
Chris@63 210 template <typename T>
Chris@63 211 struct MaybeTruncated {
Chris@63 212 T value;
Chris@63 213
Chris@63 214 bool isTruncated;
Chris@63 215 // True if the Receiver's capacity was insufficient to receive the value and therefore the
Chris@63 216 // value is truncated.
Chris@63 217 };
Chris@63 218
Chris@63 219 virtual MaybeTruncated<ArrayPtr<const byte>> getContent() = 0;
Chris@63 220 // Get the content of the datagram.
Chris@63 221
Chris@63 222 virtual MaybeTruncated<ArrayPtr<const AncillaryMessage>> getAncillary() = 0;
Chris@63 223 // Ancilarry messages received with the datagram. See the recvmsg() system call and the cmsghdr
Chris@63 224 // struct. Most apps don't need this.
Chris@63 225 //
Chris@63 226 // If the returned value is truncated, then the last message in the array may itself be
Chris@63 227 // truncated, meaning its as<T>() method will return nullptr or its asArray<T>() method will
Chris@63 228 // return fewer elements than expected. Truncation can also mean that additional messages were
Chris@63 229 // available but discarded.
Chris@63 230
Chris@63 231 virtual NetworkAddress& getSource() = 0;
Chris@63 232 // Get the datagram sender's address.
Chris@63 233
Chris@63 234 struct Capacity {
Chris@63 235 size_t content = 8192;
Chris@63 236 // How much space to allocate for the datagram content. If a datagram is received that is
Chris@63 237 // larger than this, it will be truncated, with no way to recover the tail.
Chris@63 238
Chris@63 239 size_t ancillary = 0;
Chris@63 240 // How much space to allocate for ancillary messages. As with content, if the ancillary data
Chris@63 241 // is larger than this, it will be truncated.
Chris@63 242 };
Chris@63 243 };
Chris@63 244
Chris@63 245 class DatagramPort {
Chris@63 246 public:
Chris@63 247 virtual Promise<size_t> send(const void* buffer, size_t size, NetworkAddress& destination) = 0;
Chris@63 248 virtual Promise<size_t> send(ArrayPtr<const ArrayPtr<const byte>> pieces,
Chris@63 249 NetworkAddress& destination) = 0;
Chris@63 250
Chris@63 251 virtual Own<DatagramReceiver> makeReceiver(
Chris@63 252 DatagramReceiver::Capacity capacity = DatagramReceiver::Capacity()) = 0;
Chris@63 253 // Create a new `Receiver` that can be used to receive datagrams. `capacity` specifies how much
Chris@63 254 // space to allocate for the received message. The `DatagramPort` must outlive the `Receiver`.
Chris@63 255
Chris@63 256 virtual uint getPort() = 0;
Chris@63 257 // Gets the port number, if applicable (i.e. if listening on IP). This is useful if you didn't
Chris@63 258 // specify a port when constructing the NetworkAddress -- one will have been assigned
Chris@63 259 // automatically.
Chris@63 260
Chris@63 261 virtual void getsockopt(int level, int option, void* value, uint* length);
Chris@63 262 virtual void setsockopt(int level, int option, const void* value, uint length);
Chris@63 263 // Same as the methods of AsyncIoStream.
Chris@63 264 };
Chris@63 265
Chris@63 266 // =======================================================================================
Chris@63 267 // Networks
Chris@63 268
Chris@63 269 class NetworkAddress {
Chris@63 270 // Represents a remote address to which the application can connect.
Chris@63 271
Chris@63 272 public:
Chris@63 273 virtual Promise<Own<AsyncIoStream>> connect() = 0;
Chris@63 274 // Make a new connection to this address.
Chris@63 275 //
Chris@63 276 // The address must not be a wildcard ("*"). If it is an IP address, it must have a port number.
Chris@63 277
Chris@63 278 virtual Own<ConnectionReceiver> listen() = 0;
Chris@63 279 // Listen for incoming connections on this address.
Chris@63 280 //
Chris@63 281 // The address must be local.
Chris@63 282
Chris@63 283 virtual Own<DatagramPort> bindDatagramPort();
Chris@63 284 // Open this address as a datagram (e.g. UDP) port.
Chris@63 285 //
Chris@63 286 // The address must be local.
Chris@63 287
Chris@63 288 virtual Own<NetworkAddress> clone() = 0;
Chris@63 289 // Returns an equivalent copy of this NetworkAddress.
Chris@63 290
Chris@63 291 virtual String toString() = 0;
Chris@63 292 // Produce a human-readable string which hopefully can be passed to Network::parseAddress()
Chris@63 293 // to reproduce this address, although whether or not that works of course depends on the Network
Chris@63 294 // implementation. This should be called only to display the address to human users, who will
Chris@63 295 // hopefully know what they are able to do with it.
Chris@63 296 };
Chris@63 297
Chris@63 298 class Network {
Chris@63 299 // Factory for NetworkAddress instances, representing the network services offered by the
Chris@63 300 // operating system.
Chris@63 301 //
Chris@63 302 // This interface typically represents broad authority, and well-designed code should limit its
Chris@63 303 // use to high-level startup code and user interaction. Low-level APIs should accept
Chris@63 304 // NetworkAddress instances directly and work from there, if at all possible.
Chris@63 305
Chris@63 306 public:
Chris@63 307 virtual Promise<Own<NetworkAddress>> parseAddress(StringPtr addr, uint portHint = 0) = 0;
Chris@63 308 // Construct a network address from a user-provided string. The format of the address
Chris@63 309 // strings is not specified at the API level, and application code should make no assumptions
Chris@63 310 // about them. These strings should always be provided by humans, and said humans will know
Chris@63 311 // what format to use in their particular context.
Chris@63 312 //
Chris@63 313 // `portHint`, if provided, specifies the "standard" IP port number for the application-level
Chris@63 314 // service in play. If the address turns out to be an IP address (v4 or v6), and it lacks a
Chris@63 315 // port number, this port will be used. If `addr` lacks a port number *and* `portHint` is
Chris@63 316 // omitted, then the returned address will only support listen() and bindDatagramPort()
Chris@63 317 // (not connect()), and an unused port will be chosen each time one of those methods is called.
Chris@63 318
Chris@63 319 virtual Own<NetworkAddress> getSockaddr(const void* sockaddr, uint len) = 0;
Chris@63 320 // Construct a network address from a legacy struct sockaddr.
Chris@63 321 };
Chris@63 322
Chris@63 323 // =======================================================================================
Chris@63 324 // I/O Provider
Chris@63 325
Chris@63 326 class AsyncIoProvider {
Chris@63 327 // Class which constructs asynchronous wrappers around the operating system's I/O facilities.
Chris@63 328 //
Chris@63 329 // Generally, the implementation of this interface must integrate closely with a particular
Chris@63 330 // `EventLoop` implementation. Typically, the EventLoop implementation itself will provide
Chris@63 331 // an AsyncIoProvider.
Chris@63 332
Chris@63 333 public:
Chris@63 334 virtual OneWayPipe newOneWayPipe() = 0;
Chris@63 335 // Creates an input/output stream pair representing the ends of a one-way pipe (e.g. created with
Chris@63 336 // the pipe(2) system call).
Chris@63 337
Chris@63 338 virtual TwoWayPipe newTwoWayPipe() = 0;
Chris@63 339 // Creates two AsyncIoStreams representing the two ends of a two-way pipe (e.g. created with
Chris@63 340 // socketpair(2) system call). Data written to one end can be read from the other.
Chris@63 341
Chris@63 342 virtual Network& getNetwork() = 0;
Chris@63 343 // Creates a new `Network` instance representing the networks exposed by the operating system.
Chris@63 344 //
Chris@63 345 // DO NOT CALL THIS except at the highest levels of your code, ideally in the main() function. If
Chris@63 346 // you call this from low-level code, then you are preventing higher-level code from injecting an
Chris@63 347 // alternative implementation. Instead, if your code needs to use network functionality, it
Chris@63 348 // should ask for a `Network` as a constructor or method parameter, so that higher-level code can
Chris@63 349 // chose what implementation to use. The system network is essentially a singleton. See:
Chris@63 350 // http://www.object-oriented-security.org/lets-argue/singletons
Chris@63 351 //
Chris@63 352 // Code that uses the system network should not make any assumptions about what kinds of
Chris@63 353 // addresses it will parse, as this could differ across platforms. String addresses should come
Chris@63 354 // strictly from the user, who will know how to write them correctly for their system.
Chris@63 355 //
Chris@63 356 // With that said, KJ currently supports the following string address formats:
Chris@63 357 // - IPv4: "1.2.3.4", "1.2.3.4:80"
Chris@63 358 // - IPv6: "1234:5678::abcd", "[1234:5678::abcd]:80"
Chris@63 359 // - Local IP wildcard (covers both v4 and v6): "*", "*:80"
Chris@63 360 // - Symbolic names: "example.com", "example.com:80", "example.com:http", "1.2.3.4:http"
Chris@63 361 // - Unix domain: "unix:/path/to/socket"
Chris@63 362
Chris@63 363 struct PipeThread {
Chris@63 364 // A combination of a thread and a two-way pipe that communicates with that thread.
Chris@63 365 //
Chris@63 366 // The fields are intentionally ordered so that the pipe will be destroyed (and therefore
Chris@63 367 // disconnected) before the thread is destroyed (and therefore joined). Thus if the thread
Chris@63 368 // arranges to exit when it detects disconnect, destruction should be clean.
Chris@63 369
Chris@63 370 Own<Thread> thread;
Chris@63 371 Own<AsyncIoStream> pipe;
Chris@63 372 };
Chris@63 373
Chris@63 374 virtual PipeThread newPipeThread(
Chris@63 375 Function<void(AsyncIoProvider&, AsyncIoStream&, WaitScope&)> startFunc) = 0;
Chris@63 376 // Create a new thread and set up a two-way pipe (socketpair) which can be used to communicate
Chris@63 377 // with it. One end of the pipe is passed to the thread's start function and the other end of
Chris@63 378 // the pipe is returned. The new thread also gets its own `AsyncIoProvider` instance and will
Chris@63 379 // already have an active `EventLoop` when `startFunc` is called.
Chris@63 380 //
Chris@63 381 // TODO(someday): I'm not entirely comfortable with this interface. It seems to be doing too
Chris@63 382 // much at once but I'm not sure how to cleanly break it down.
Chris@63 383
Chris@63 384 virtual Timer& getTimer() = 0;
Chris@63 385 // Returns a `Timer` based on real time. Time does not pass while event handlers are running --
Chris@63 386 // it only updates when the event loop polls for system events. This means that calling `now()`
Chris@63 387 // on this timer does not require a system call.
Chris@63 388 //
Chris@63 389 // This timer is not affected by changes to the system date. It is unspecified whether the timer
Chris@63 390 // continues to count while the system is suspended.
Chris@63 391 };
Chris@63 392
Chris@63 393 class LowLevelAsyncIoProvider {
Chris@63 394 // Similar to `AsyncIoProvider`, but represents a lower-level interface that may differ on
Chris@63 395 // different operating systems. You should prefer to use `AsyncIoProvider` over this interface
Chris@63 396 // whenever possible, as `AsyncIoProvider` is portable and friendlier to dependency-injection.
Chris@63 397 //
Chris@63 398 // On Unix, this interface can be used to import native file descriptors into the async framework.
Chris@63 399 // Different implementations of this interface might work on top of different event handling
Chris@63 400 // primitives, such as poll vs. epoll vs. kqueue vs. some higher-level event library.
Chris@63 401 //
Chris@63 402 // On Windows, this interface can be used to import native HANDLEs into the async framework.
Chris@63 403 // Different implementations of this interface might work on top of different event handling
Chris@63 404 // primitives, such as I/O completion ports vs. completion routines.
Chris@63 405 //
Chris@63 406 // TODO(port): Actually implement Windows support.
Chris@63 407
Chris@63 408 public:
Chris@63 409 // ---------------------------------------------------------------------------
Chris@63 410 // Unix-specific stuff
Chris@63 411
Chris@63 412 enum Flags {
Chris@63 413 // Flags controlling how to wrap a file descriptor.
Chris@63 414
Chris@63 415 TAKE_OWNERSHIP = 1 << 0,
Chris@63 416 // The returned object should own the file descriptor, automatically closing it when destroyed.
Chris@63 417 // The close-on-exec flag will be set on the descriptor if it is not already.
Chris@63 418 //
Chris@63 419 // If this flag is not used, then the file descriptor is not automatically closed and the
Chris@63 420 // close-on-exec flag is not modified.
Chris@63 421
Chris@63 422 #if !_WIN32
Chris@63 423 ALREADY_CLOEXEC = 1 << 1,
Chris@63 424 // Indicates that the close-on-exec flag is known already to be set, so need not be set again.
Chris@63 425 // Only relevant when combined with TAKE_OWNERSHIP.
Chris@63 426 //
Chris@63 427 // On Linux, all system calls which yield new file descriptors have flags or variants which
Chris@63 428 // set the close-on-exec flag immediately. Unfortunately, other OS's do not.
Chris@63 429
Chris@63 430 ALREADY_NONBLOCK = 1 << 2
Chris@63 431 // Indicates that the file descriptor is known already to be in non-blocking mode, so the flag
Chris@63 432 // need not be set again. Otherwise, all wrap*Fd() methods will enable non-blocking mode
Chris@63 433 // automatically.
Chris@63 434 //
Chris@63 435 // On Linux, all system calls which yield new file descriptors have flags or variants which
Chris@63 436 // enable non-blocking mode immediately. Unfortunately, other OS's do not.
Chris@63 437 #endif
Chris@63 438 };
Chris@63 439
Chris@63 440 #if _WIN32
Chris@63 441 typedef uintptr_t Fd;
Chris@63 442 // On Windows, the `fd` parameter to each of these methods must be a SOCKET, and must have the
Chris@63 443 // flag WSA_FLAG_OVERLAPPED (which socket() uses by default, but WSASocket() wants you to specify
Chris@63 444 // explicitly).
Chris@63 445 #else
Chris@63 446 typedef int Fd;
Chris@63 447 // On Unix, any arbitrary file descriptor is supported.
Chris@63 448 #endif
Chris@63 449
Chris@63 450 virtual Own<AsyncInputStream> wrapInputFd(Fd fd, uint flags = 0) = 0;
Chris@63 451 // Create an AsyncInputStream wrapping a file descriptor.
Chris@63 452 //
Chris@63 453 // `flags` is a bitwise-OR of the values of the `Flags` enum.
Chris@63 454
Chris@63 455 virtual Own<AsyncOutputStream> wrapOutputFd(Fd fd, uint flags = 0) = 0;
Chris@63 456 // Create an AsyncOutputStream wrapping a file descriptor.
Chris@63 457 //
Chris@63 458 // `flags` is a bitwise-OR of the values of the `Flags` enum.
Chris@63 459
Chris@63 460 virtual Own<AsyncIoStream> wrapSocketFd(Fd fd, uint flags = 0) = 0;
Chris@63 461 // Create an AsyncIoStream wrapping a socket file descriptor.
Chris@63 462 //
Chris@63 463 // `flags` is a bitwise-OR of the values of the `Flags` enum.
Chris@63 464
Chris@63 465 virtual Promise<Own<AsyncIoStream>> wrapConnectingSocketFd(
Chris@63 466 Fd fd, const struct sockaddr* addr, uint addrlen, uint flags = 0) = 0;
Chris@63 467 // Create an AsyncIoStream wrapping a socket and initiate a connection to the given address.
Chris@63 468 // The returned promise does not resolve until connection has completed.
Chris@63 469 //
Chris@63 470 // `flags` is a bitwise-OR of the values of the `Flags` enum.
Chris@63 471
Chris@63 472 virtual Own<ConnectionReceiver> wrapListenSocketFd(Fd fd, uint flags = 0) = 0;
Chris@63 473 // Create an AsyncIoStream wrapping a listen socket file descriptor. This socket should already
Chris@63 474 // have had `bind()` and `listen()` called on it, so it's ready for `accept()`.
Chris@63 475 //
Chris@63 476 // `flags` is a bitwise-OR of the values of the `Flags` enum.
Chris@63 477
Chris@63 478 virtual Own<DatagramPort> wrapDatagramSocketFd(Fd fd, uint flags = 0);
Chris@63 479
Chris@63 480 virtual Timer& getTimer() = 0;
Chris@63 481 // Returns a `Timer` based on real time. Time does not pass while event handlers are running --
Chris@63 482 // it only updates when the event loop polls for system events. This means that calling `now()`
Chris@63 483 // on this timer does not require a system call.
Chris@63 484 //
Chris@63 485 // This timer is not affected by changes to the system date. It is unspecified whether the timer
Chris@63 486 // continues to count while the system is suspended.
Chris@63 487 };
Chris@63 488
Chris@63 489 Own<AsyncIoProvider> newAsyncIoProvider(LowLevelAsyncIoProvider& lowLevel);
Chris@63 490 // Make a new AsyncIoProvider wrapping a `LowLevelAsyncIoProvider`.
Chris@63 491
Chris@63 492 struct AsyncIoContext {
Chris@63 493 Own<LowLevelAsyncIoProvider> lowLevelProvider;
Chris@63 494 Own<AsyncIoProvider> provider;
Chris@63 495 WaitScope& waitScope;
Chris@63 496
Chris@63 497 #if _WIN32
Chris@63 498 Win32EventPort& win32EventPort;
Chris@63 499 #else
Chris@63 500 UnixEventPort& unixEventPort;
Chris@63 501 // TEMPORARY: Direct access to underlying UnixEventPort, mainly for waiting on signals. This
Chris@63 502 // field will go away at some point when we have a chance to improve these interfaces.
Chris@63 503 #endif
Chris@63 504 };
Chris@63 505
Chris@63 506 AsyncIoContext setupAsyncIo();
Chris@63 507 // Convenience method which sets up the current thread with everything it needs to do async I/O.
Chris@63 508 // The returned objects contain an `EventLoop` which is wrapping an appropriate `EventPort` for
Chris@63 509 // doing I/O on the host system, so everything is ready for the thread to start making async calls
Chris@63 510 // and waiting on promises.
Chris@63 511 //
Chris@63 512 // You would typically call this in your main() loop or in the start function of a thread.
Chris@63 513 // Example:
Chris@63 514 //
Chris@63 515 // int main() {
Chris@63 516 // auto ioContext = kj::setupAsyncIo();
Chris@63 517 //
Chris@63 518 // // Now we can call an async function.
Chris@63 519 // Promise<String> textPromise = getHttp(*ioContext.provider, "http://example.com");
Chris@63 520 //
Chris@63 521 // // And we can wait for the promise to complete. Note that you can only use `wait()`
Chris@63 522 // // from the top level, not from inside a promise callback.
Chris@63 523 // String text = textPromise.wait(ioContext.waitScope);
Chris@63 524 // print(text);
Chris@63 525 // return 0;
Chris@63 526 // }
Chris@63 527 //
Chris@63 528 // WARNING: An AsyncIoContext can only be used in the thread and process that created it. In
Chris@63 529 // particular, note that after a fork(), an AsyncIoContext created in the parent process will
Chris@63 530 // not work correctly in the child, even if the parent ceases to use its copy. In particular
Chris@63 531 // note that this means that server processes which daemonize themselves at startup must wait
Chris@63 532 // until after daemonization to create an AsyncIoContext.
Chris@63 533
Chris@63 534 // =======================================================================================
Chris@63 535 // inline implementation details
Chris@63 536
Chris@63 537 inline AncillaryMessage::AncillaryMessage(
Chris@63 538 int level, int type, ArrayPtr<const byte> data)
Chris@63 539 : level(level), type(type), data(data) {}
Chris@63 540
Chris@63 541 inline int AncillaryMessage::getLevel() const { return level; }
Chris@63 542 inline int AncillaryMessage::getType() const { return type; }
Chris@63 543
Chris@63 544 template <typename T>
Chris@63 545 inline Maybe<const T&> AncillaryMessage::as() {
Chris@63 546 if (data.size() >= sizeof(T)) {
Chris@63 547 return *reinterpret_cast<const T*>(data.begin());
Chris@63 548 } else {
Chris@63 549 return nullptr;
Chris@63 550 }
Chris@63 551 }
Chris@63 552
Chris@63 553 template <typename T>
Chris@63 554 inline ArrayPtr<const T> AncillaryMessage::asArray() {
Chris@63 555 return arrayPtr(reinterpret_cast<const T*>(data.begin()), data.size() / sizeof(T));
Chris@63 556 }
Chris@63 557
Chris@63 558 } // namespace kj
Chris@63 559
Chris@63 560 #endif // KJ_ASYNC_IO_H_