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