blob: b61bb3d70bbc10324c0a3d2f5d4ec62d3417f249 [file] [log] [blame]
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Starboard socket I/O. Starboard supports IPv4 and IPv6, TCP and UDP, server
// and client sockets. Some platforms may not support IPv6, some may not support
// listening sockets, and some may not support any kind of sockets at all (or
// only allow them in debug builds). Starboard ONLY supports non-blocking socket
// I/O, so all sockets are non-blocking at creation time.
// Note that, on some platforms, API calls on one end of a socket connection may
// not be instantaneously aware of manipulations on the socket at the other end
// of the connection, thus requiring use of either an SbSocketWaiter or
// spin-polling.
//
// TODO: For platforms that do not support sockets at all, they must
// support at least a high-level HTTP client API (to be defined later).
#ifndef STARBOARD_SOCKET_H_
#define STARBOARD_SOCKET_H_
#ifdef __cplusplus
#include <iomanip>
#include <iostream>
#endif
#include "starboard/export.h"
#include "starboard/time.h"
#include "starboard/types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Private structure representing a socket, which may or may not be connected or
// listening.
typedef struct SbSocketPrivate SbSocketPrivate;
// A handle to a socket.
typedef SbSocketPrivate* SbSocket;
// Enumeration of all Starboard socket operation results.
typedef enum SbSocketError {
// The operation succeeded. Yep.
kSbSocketOk = 0,
// The operation is blocked on I/O. Either try again "later," or be very
// clever and wait on it with a SbSocketWaiter.
kSbSocketPending,
// The operation failed for some reason.
//
// TODO: It's unclear if we actually care about why, so leaving the rest
// of this enumeration blank until it becomes clear that we do.
kSbSocketErrorFailed,
} SbSocketError;
// All possible IP socket types.
typedef enum SbSocketProtocol {
// The TCP/IP protocol, a reliable, stateful, streaming protocol.
kSbSocketProtocolTcp,
// The UDP/IP protocol, an unreliable, connectionless, discrete packet
// (datagram) protocol.
kSbSocketProtocolUdp,
} SbSocketProtocol;
// All possible address types.
typedef enum SbSocketAddressType {
// An IPv4 address, using only the first 4 entries of the address buffer.
kSbSocketAddressTypeIpv4,
// An IPv6 address, which uses 16 entries of the address buffer.
kSbSocketAddressTypeIpv6,
} SbSocketAddressType;
// Bits that can be set when calling SbSocketResolve to filter the results.
typedef enum SbSocketResolveFilter {
// No filters, include everything.
kSbSocketResolveFilterNone = 0,
// Include Ipv4 addresses.
kSbSocketResolveFilterIpv4 = 1 << 0,
// Include Ipv6 addresses.
kSbSocketResolveFilterIpv6 = 1 << 1,
} SbSocketResolveFilter;
// A representation of any possible supported address type.
typedef struct SbSocketAddress {
// The storage for the address. For IPv4, only the first 4 bytes make up the
// address. For IPv6, the entire buffer of 16 bytes is meaningful. An address
// of all zeros means that the address is unspecified.
uint8_t address[16];
// The type of address this represents (IPv4 vs IPv6).
SbSocketAddressType type;
// The port component of this socket address. If not specified, it will be
// zero, which is officially undefined.
int port;
} SbSocketAddress;
// The result of a host name resolution.
typedef struct SbSocketResolution {
// An array of addresses associated with the host name.
SbSocketAddress* addresses;
// The length of the |addresses| array.
int address_count;
} SbSocketResolution;
// Well-defined value for an invalid socket handle.
#define kSbSocketInvalid ((SbSocket)NULL)
// Returns whether the given socket handle is valid.
static SB_C_INLINE bool SbSocketIsValid(SbSocket socket) {
return socket != kSbSocketInvalid;
}
// Creates a new non-blocking socket for protocol |protocol| using address
// family |address_type|. Returns the newly created handle, if successful, or
// kSbSocketInvalid, if not. If unsuccessful, sets the last system error
// appropriately.
SB_EXPORT SbSocket SbSocketCreate(SbSocketAddressType address_type,
SbSocketProtocol protocol);
// Destroys |socket|. Flushes the socket, closes any connection that may be
// active on |socket|, and reclaims any resources associated with |socket|,
// including any registration with an SbSocketWaiter. Returns whether the
// destruction was successful. Even if this function returns false, you
// shouldn't be able to use the socket anymore.
SB_EXPORT bool SbSocketDestroy(SbSocket socket);
// Opens a connection of |socket|'s type to the host and port specified by
// |address|. Sets and returns the socket error if unable to bind to
// |local_address|.
SB_EXPORT SbSocketError SbSocketConnect(SbSocket socket,
const SbSocketAddress* address);
// Binds |socket| to a specific local interface and port specified by
// |local_address|, which must not be NULL. Port 0 means choose a port for me
// and IP address 0.0.0.0 means bind to all interfaces. Sets and returns the
// socket error if unable to bind to |local_address|.
SB_EXPORT SbSocketError SbSocketBind(SbSocket socket,
const SbSocketAddress* local_address);
// Causes |socket| to listen on |local_address|. Sets and returns the socket
// error if unable to listen for some reason.
SB_EXPORT SbSocketError SbSocketListen(SbSocket socket);
// Accepts a pending connection on |socket|, returning a new SbSocket
// representing that connection. Sets the error on |socket| and returns
// kSbSocketInvalid if unable to accept a new connection.
SB_EXPORT SbSocket SbSocketAccept(SbSocket socket);
// Returns whether |socket| is connected to anything. Invalid sockets are not
// connected.
SB_EXPORT bool SbSocketIsConnected(SbSocket socket);
// Returns whether |socket| is connected to anything, and whether it is
// receiving any data.
SB_EXPORT bool SbSocketIsConnectedAndIdle(SbSocket socket);
// Returns the last error set on |socket|. If |socket| is not valid, always
// returns kSbSocketErrorFailed.
SB_EXPORT SbSocketError SbSocketGetLastError(SbSocket socket);
// Clears the last error set on |socket|. Returns whether the socket error was
// cleared.
SB_EXPORT bool SbSocketClearLastError(SbSocket socket);
// Gets the address that this socket is bound to locally, if the socket is
// connected. Returns whether getting the address was successful.
SB_EXPORT bool SbSocketGetLocalAddress(SbSocket socket,
SbSocketAddress* out_address);
// Reads up to |data_size| bytes from |socket| into |out_data|. Also places the
// source address of the packet in |out_source|, if out_source is not NULL.
// Returns the number of bytes read, or a negative number on error.
// SbSocketGetLastError can provide the precise error encountered.
//
// Note that this function is NOT specified to (but MAY) make a best effort to
// read all data on all platforms, it just reads however many bytes are
// available conveniently. Can be run in a loop until pending to make it a
// best-effort read (but still only up to not blocking, unless you want to
// spin).
//
// The primary use of |out_source| is for receiving datagram packets from
// multiple sources on a UDP server socket. TCP has two endpoints connected
// persistently, so the address is unnecessary, but allowed.
SB_EXPORT int SbSocketReceiveFrom(SbSocket socket,
char* out_data,
int data_size,
SbSocketAddress* out_source);
// Writes up to |data_size| bytes of |data| to |destination| via
// |socket|. Returns the number of bytes written, or a negative number on
// error. SbSocketGetLastError can provide the precise error encountered.
// |destination| must be NULL for TCP connections, which can only have a single
// endpoint.
//
// Note that this function is NOT specified to (but MAY) make a best effort to
// write all data on all platforms, it just writes however many bytes that are
// conveniently. Can be run in a loop until pending to make it a best-effort
// write (but still only up to not blocking, unless you want to spin).
//
// The primary use of |destination| is to send datagram packets, which can go
// out to multiple sources from a single UDP server socket. TCP has two
// endpoints connected persistently, so |destination| cannot be set when sending
// to a TCP socket -- it will cause an error.
SB_EXPORT int SbSocketSendTo(SbSocket socket,
const char* data,
int data_size,
const SbSocketAddress* destination);
// Sets the SO_BROADCAST, or equivalent, option to |value| on |socket|. Returns
// whether the option was actually set.
//
// This option is only meaningful for UDP sockets, and will allow the socket to
// send to the broadcast address.
SB_EXPORT bool SbSocketSetBroadcast(SbSocket socket, bool value);
// Sets the SO_REUSEADDR, or equivalent, option to |value| on |socket|. Returns
// whether the option was actually set.
//
// This option allows a bound address to be reused if a socket isn't actively
// bound to it.
SB_EXPORT bool SbSocketSetReuseAddress(SbSocket socket, bool value);
// Sets SO_RCVBUF, or equivalent, option to |size| on |socket|.
SB_EXPORT bool SbSocketSetReceiveBufferSize(SbSocket socket, int32_t size);
// Sets SO_SNDBUF, or equivalent, option to |size| on |socket|.
SB_EXPORT bool SbSocketSetSendBufferSize(SbSocket socket, int32_t size);
// Sets the SO_KEEPALIVE, or equivalent, option to |value| on |socket|. If
// |value| is true, then |period| specifies the minimum time (SbTime is always
// in microseconds) between keep-alive packets, otherwise |period| is
// ignored. Returns whether the option was actually set.
SB_EXPORT bool SbSocketSetTcpKeepAlive(SbSocket socket,
bool value,
SbTime period);
// Sets the TCP_NODELAY, or equivalent, option to |value| on |socket|. Returns
// whether the option was actually set.
//
// This disables the Nagle algorithm for reducing the number of packets sent
// when converting from a stream to packets. Disabling Nagle will generally put
// the data for each Send call into its own packet, but does not guarantee that
// behavior.
SB_EXPORT bool SbSocketSetTcpNoDelay(SbSocket socket, bool value);
// Sets SO_WINSCALE, or equivalent, option to |value| on |socket|.
SB_EXPORT bool SbSocketSetTcpWindowScaling(SbSocket socket, bool value);
// Joins |socket| to an IP multicast group identified by |address|. The
// equivalent of IP_ADD_MEMBERSHIP.
SB_EXPORT bool SbSocketJoinMulticastGroup(SbSocket socket,
const SbSocketAddress* address);
// Gets the address of the local IPv4 network interface. Does not include
// loopback (or IPv6) addresses.
SB_EXPORT bool SbSocketGetLocalInterfaceAddress(SbSocketAddress* out_address);
// Synchronously resolves |hostname| into an SbSocketResolution, filtered by
// |filters|, which is a mask of SbSocketResolveFilter values. If no IP address
// family filter is specified in |filters|, all address families will be
// included, but if one is specified, only that address familiy will be
// included. Unrecognized filter bits are ignored. Returns NULL if unable to
// resolve |hostname|. The returned SbSocketResolution must be freed with
// SbSocketFreeResolution.
SB_EXPORT SbSocketResolution* SbSocketResolve(const char* hostname,
int filters);
// Frees a resolution allocated by SbSocketResolve.
SB_EXPORT void SbSocketFreeResolution(SbSocketResolution* resolution);
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef __cplusplus
// Let SbSocketAddresses be output to log streams.
inline std::ostream& operator<<(std::ostream& os,
const SbSocketAddress& address) {
if (address.type == kSbSocketAddressTypeIpv6) {
os << std::hex << "[";
const uint16_t* fields = reinterpret_cast<const uint16_t*>(address.address);
for (int i = 0; i < 8; ++i) {
if (i != 0) {
os << ":";
}
os << fields[i];
}
os << "]" << std::dec;
} else {
for (int i = 0; i < 4; ++i) {
if (i != 0) {
os << ".";
}
os << static_cast<int>(address.address[i]);
}
}
os << ":" << address.port;
return os;
}
#endif
#endif // STARBOARD_SOCKET_H_