Search guides and the APICtrl K
  1. API reference
  2. System, devices and network

net.h

Networking: addresses, TCP and UDP sockets, URLs, and HTTP(S).

#include <sonore/net.h>
On this page

Design notes

IPAddress, MACAddress          parse, format, and list this machine's
StreamingSocket                TCP: connect, listen, accept, read, write
DatagramSocket                 UDP: bind, send, receive, broadcast,
                               multicast
URL                            RFC 3986: parse, components, percent-
                               encoding, parameters, relative resolution
WebInputStream                 an HTTP(S) request read as a stream:
                               headers, POST bodies, timeouts, redirects,
                               progress, cancellation
URL::downloadToFile            the common case, in one call

A plugin that talks to the network is doing something nobody asked for

That position has not changed (see the feature map's networking row): a plugin opening a socket by itself, in a process the user did not start, on a studio machine that may have no business reaching the internet, is the kind of thing users find in a firewall log and do not forgive. So nothing in the SDK calls any of this on its own -- it is here for the plugin that genuinely needs it and says so to its user (a content downloader, a licence check, an editor talking to a companion app), and for the standalone.

And the defaults lean shut: a listening socket binds the LOOPBACK address unless it is given another one, so a listener a plugin opened for its own helper process is not reachable from the café Wi-Fi the laptop is on -- the same fix osc.h's receiver had. The reference listens on every interface by default; pass "0.0.0.0" (or "::") to do that.

How each platform is reached

Windows: Winsock, WinHTTP and iphlpapi are LOADED, not linked, and their handful of structures are declared here rather than by <winsock2.h>. That is not squeamishness about a link line. A project that includes <windows.h> without WIN32_LEAN_AND_MEAN before this header has already pulled in the obsolete <winsock.h>, after which <winsock2.h> cannot be included at all -- a hundred redefinition errors, decided by somebody else's include order. Declaring the dozen layouts we use (fixed in the Windows ABI since Windows 2000, and checked against the real headers by a static_assert in system_test.cpp) makes this header compile in any order with anything. HTTPS is WinHTTP: the system's TLS, the system's proxy settings and certificate store.

macOS: BSD sockets, and NSURLSession for HTTP through the Objective-C runtime (no Objective-C++ needed, like the rest of the SDK's Cocoa code).

Linux: BSD sockets, and libcurl for HTTP, opened with dlopen. Every desktop distribution has libcurl; a plugin that LINKED it would refuse to load on the one that does not, instead of failing one download with a message saying which library was missing.

The parts that decide anything -- URL parsing and resolution, header parsing, redirect rules, address formatting -- are shared C++ and tested on every platform. What differs is the call at the bottom.

Redirects are followed HERE, not by the platform

WinHTTP, NSURLSession and libcurl each follow redirects by their own rules and report them differently. All three are told not to, and the loop in WebInputStream::connect() follows them identically everywhere: Location resolved with RFC 3986 against the URL that answered, 303 (and 301/302 after a POST) turned into a GET without its body, 307/308 repeated as they were, credentials dropped when the origin changes, at most numRedirectsToFollow hops -- after which the last 3xx is handed back as the response rather than an error, so a caller can see where it was going.

NEVER ON THE AUDIO THREAD

Everything here blocks: name lookup (getaddrinfo cannot be given a timeout), connecting, reading, writing. Use a thread of your own, or a worker the editor polls. cancel() and the timeouts are how a blocked call is brought back; getaddrinfo is the one call they cannot shorten.

Types 6

An IPv4 or IPv6 address.

Text in, RFC 4291 forms: dotted quads ("192.0.2.1", no leading zeros -- "010.0.0.1" is octal to some parsers and decimal to others, so it is refused rather than guessed), and IPv6 with "::" compression and an embedded IPv4 tail ("::ffff:192.0.2.1"). Brackets and zone suffixes ("%eth0") are not part of an address and are refused.

Text out, RFC 5952 for IPv6: lowercase, no leading zeros, the LONGEST run of two or more zero groups compressed (the first, on a tie), and an IPv4-mapped address written with its dotted tail. Two programs printing one address print the same string, which is what makes a string usable as a key.

A network adapter's hardware address: six bytes, written "aa-bb-cc-dd-ee-ff".

A TCP connection, or a listener that accepts them.

Blocking, like the reference's: read() and write() wait. Use waitUntilReady() with a timeout to wait for data without committing to a read, which is also how a reader thread stays stoppable. One thread may read while another writes. close() from another thread wakes a thread blocked in read(), which then returns 0 -- it must not read again.

Connected sockets have Nagle's algorithm OFF (TCP_NODELAY): every user of this in a plugin is exchanging small messages with a peer that answers, where Nagle plus delayed acknowledgement is a 40-200 ms stall per round trip.

A UDP socket: datagrams to and from anywhere, broadcast, multicast.

The socket is created when it is first needed -- by bindToPort, write or joinMulticast -- in the family that call implies, so the same object serves IPv4 and IPv6. bindToPort(port) binds the LOOPBACK (see the header); "0.0.0.0" or "::" hears the network, and is what broadcast and multicast reception need.

A datagram larger than the buffer handed to read() is cut to fit and the rest is lost, which is what UDP does; 65507 bytes always fits one.

A URL, held as its RFC 3986 components.

Parsing splits, it does not judge: any string becomes a URL whose components recompose to it (scheme and IPv6 host case aside), and isWellFormed() says whether it is a valid absolute URI. Components are kept as written -- still percent-encoded -- and the accessors that return DECODED text say so (getFileName, getParameterValues).

resolve() is RFC 3986 section 5.2 exactly, dot segments included, which is what a redirect's Location and a link in a downloaded page need.

class WebInputStream : public InputStream

An HTTP or HTTPS request whose response is read as an InputStream.

connect() sends the request and waits for the response's head, following redirects (see the header); read() then streams the body. Both are called by the first read if nobody called connect(). A response with an error status is still a response: connect() is true, getStatusCode() says 404, and the body is the server's explanation.

cancel() may be called from any thread, and brings a blocked connect() or read() back at once. A cancelled stream stays cancelled. The timeout (InputStreamOptions::connectionTimeoutMs) is kept the same way, by a deadline on a thread of the stream's own: the time to the response's head, and then the longest silence while reading -- whatever the platform library underneath would have done (see netdetail::Watchdog).

Blocking, so never on the audio thread.

↑↓ to move↵ to openEvery public name in the headers, and every guide