🟨 Synchronous socket networking and DNS lookup
Socket library allows creating TCP / UDP sockets and using them as client or server and resolving DNS.
It can be used standalone if synchronous networking is preferred or as a companion to Async for creation of non-blocking socket descriptors.
Features
Status
🟨 MVP
Simple synchronous TCP client / server workflow is supported, but it would need better testing.
Description
SocketDescriptor
It also allow querying inheritability and changing it (and blocking mode)
Example (extracted from unit test):
bool isInheritable;
SocketDescriptor socket;
SC_TEST_EXPECT(socket.create(SocketFlags::AddressFamilyIPV4, SocketFlags::SocketStream, SocketFlags::ProtocolTcp,
SocketFlags::NonBlocking, SocketFlags::NonInheritable));
isInheritable = false;
SC_TEST_EXPECT(socket.create(SocketFlags::AddressFamilyIPV4, SocketFlags::SocketStream, SocketFlags::ProtocolTcp,
SocketFlags::Blocking, SocketFlags::NonInheritable));
isInheritable = false;
SC_TEST_EXPECT(socket.create(SocketFlags::AddressFamilyIPV4, SocketFlags::SocketStream, SocketFlags::ProtocolTcp,
SocketFlags::Blocking, SocketFlags::Inheritable));
isInheritable = false;
#define SC_TEST_EXPECT(e)
Records a test expectation (eventually aborting or breaking o n failed test)
Definition: Testing.h:113
SocketServer
Example:
SocketDescriptor serverSocket;
SocketServer server(serverSocket);
constexpr int tcpPort = 5050;
const StringView serverAddress = "::1";
SocketIPAddress nativeAddress;
SC_TRY(nativeAddress.fromAddressPort(serverAddress, tcpPort));
SocketFlags::AddressFamily family = nativeAddress.getAddressFamily();
SC_TRY(serverSocket.create(family));
SC_TRY(server.bind(nativeAddress));
SocketDescriptor acceptedClientSocket;
SC_TRY(server.accept(family, acceptedClientSocket));
SC_TRY(acceptedClientSocket.isValid());
#define SC_TRY(expression)
Checks the value of the given expression and if failed, returns this value to caller.
Definition: Result.h:48
SocketClient
The socket client can be obtained via SC::SocketServer::accept or connected to an endpoint through SC::SocketClient::connect.
Example (accepted client from server, doing a synchronous read):
SocketDescriptor acceptedClientSocket;
SC_TRY(server.accept(family, acceptedClientSocket));
SC_TRY(acceptedClientSocket.isValid());
char buf[256];
SocketClient acceptedClient(acceptedClientSocket);
Span<char> readData;
SC_TRY(acceptedClient.read({buf, sizeof(buf)}, readData));
SC_TRY(acceptedClient.readWithTimeout({buf, sizeof(buf)}, readData, 10_sec));
SC_TRY(acceptedClientSocket.close());
Example (connecting client to server, doing two synchronous writes):
SocketDescriptor clientSocket;
SocketClient client(clientSocket);
SC_TRY(clientSocket.create(family));
SC_TRY(client.connect(serverAddress, tcpPort));
const int testValue = 1;
char buf[1] = {testValue};
SC_TRY(client.write({buf, sizeof(buf)}));
buf[0]++;
SC_TRY(client.write({buf, sizeof(buf)}));
SocketIPAddress
Example:
SocketDNS
Example:
char buffer[256] = {0};
SpanString ipAddress = buffer;
SC_TEST_EXPECT(StringView(ipAddress.text,
true, StringEncoding::Ascii) ==
"127.0.0.1");
Roadmap
🟩 Usable
- Add UDP specific socket operations
🟦 Complete Features:
💡 Unplanned Features: