From b3d8586dc867da9a21877395d506eb1ab312527f Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 12:15:31 +0900
Subject: [PATCH 01/12] Add extern "C" to header section for mixed C/C++
project
---
sts_net.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/sts_net.h b/sts_net.h
index 4229245..d2636bb 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -49,6 +49,9 @@
#endif // STS_NET_PACKET_SIZE
#endif // STS_NET_NO_PACKETS
+#ifdef __cplusplus
+extern "C" {
+#endif
////////////////////////////////////////////////////////////////////////////////
//
@@ -179,6 +182,11 @@ int sts_net_receive_packet(sts_net_socket_t* socket);
// drops the packet after you used it
void sts_net_drop_packet(sts_net_socket_t* socket);
#endif // STS_NET_NO_PACKETS
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // __INCLUDED__STS_NET_H__
From ae3ed60f9ef740093b608dcc23536d0dee211df4 Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 12:17:26 +0900
Subject: [PATCH 02/12] Add optional define STS_NET_NO_ERRORSTRINGS to remove
error strings from build
---
sts_net.h | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/sts_net.h b/sts_net.h
index d2636bb..3f5de3d 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -82,8 +82,11 @@ typedef struct {
//
// General API
//
+
+#ifndef STS_NET_NO_ERRORSTRINGS
// Get the last error from sts_net (can be called even before sts_net_init)
const char* sts_net_get_last_error();
+#endif
// Initialized the sts_net library. You have to call this before any other function (except sts_net_get_last_error)
int sts_net_init();
@@ -233,6 +236,7 @@ typedef int socklen_t;
#endif // sts__memset
+#ifndef STS_NET_NO_ERRORSTRINGS
static const char* sts_net__error_message = "";
@@ -242,6 +246,14 @@ static int sts_net__set_error(const char* message) {
}
+const char *sts_net_get_last_error() {
+ return sts_net__error_message;
+}
+#else
+#define sts_net__set_error(m) -1
+#endif
+
+
void sts_net_reset_socket(sts_net_socket_t* socket) {
socket->fd = INVALID_SOCKET;
socket->ready = 0;
@@ -258,11 +270,6 @@ int sts_net_is_socket_valid(sts_net_socket_t* socket) {
}
-const char *sts_net_get_last_error() {
- return sts_net__error_message;
-}
-
-
int sts_net_init() {
#ifdef _WIN32
WSADATA wsa_data;
From 83f27e9400496d34b7cd1ac6e918d4183d08214e Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 12:20:25 +0900
Subject: [PATCH 03/12] Define _WINSOCK_DEPRECATED_NO_WARNINGS to remove build
warnings
---
sts_net.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/sts_net.h b/sts_net.h
index 3f5de3d..20d7183 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -210,6 +210,7 @@ void sts_net_drop_packet(sts_net_socket_t* socket);
#include // NULL and possibly memcpy, memset
#ifdef _WIN32
+#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include
#include
typedef int socklen_t;
From 3821f1d7d702296387e5adec0c73a7d24077fb53 Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 12:44:30 +0900
Subject: [PATCH 04/12] Added sts_net_gethostname function to query the host
name (or ip address) of a connected client (or the listen interface of a
server)
---
sts_net.h | 45 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/sts_net.h b/sts_net.h
index 20d7183..367923b 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -143,6 +143,12 @@ int sts_net_remove_socket_from_set(sts_net_socket_t* socket, sts_net_set_t* set)
// >0 amount of sockets with activity
int sts_net_check_socket_set(sts_net_set_t* set, const float timeout);
+// Read the connected hostname of a socket into out buffer
+// Supply 1 to want_only_ip if instead of the resolved host name only the ip address is needed
+// out_port can be supplied as NULL if you're not interested in the connected port number
+// Returns the length of what was written into out_host or -1 on error (sets out_host empty string)
+int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size, int want_only_ip, int* out_port);
+
////////////////////////////////////////////////////////////////////////////////
//
@@ -478,6 +484,42 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
}
+int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size, int want_only_ip, int* out_port) {
+ struct sockaddr_in sin;
+ struct in_addr in;
+ struct hostent* hostEntry;
+ char* host;
+ socklen_t sinLength;
+ int addrLen;
+
+ if (out_size) out_host[0] = '\0';
+
+ if (socket->fd == INVALID_SOCKET) {
+ return sts_net__set_error("Cannot get host name of closed socket");
+ }
+
+ sinLength = sizeof(struct sockaddr_in);
+ if (getsockname(socket->fd, (struct sockaddr *)&sin, &sinLength) == -1) {
+ return sts_net__set_error("Error while getting host name of socket");
+ }
+
+ if (out_port) *out_port = sin.sin_port;
+
+ in.s_addr = sin.sin_addr.s_addr;
+ hostEntry = (want_only_ip ? NULL : gethostbyaddr((char*)&in, sizeof(in), AF_INET));
+ host = (hostEntry ? hostEntry->h_name : inet_ntoa(in));
+ if (host == NULL) {
+ return sts_net__set_error("Error while getting host name of socket");
+ }
+ addrLen = strlen(host);
+ if (addrLen >= out_size) {
+ return sts_net__set_error("Provided buffer is too small for host name");
+ }
+ memcpy(out_host, host, addrLen + 1);
+ return addrLen;
+}
+
+
#ifndef STS_NET_NO_PACKETS
int sts_net_refill_packet_data(sts_net_socket_t* socket) {
if (socket->ready) return 0;
@@ -562,7 +604,8 @@ int main(int argc, char *argv[]) {
if (clients[i].fd == INVALID_SOCKET) {
if (sts_net_accept_socket(&server, &clients[i]) < 0) panic(sts_net_get_last_error());
if (sts_net_add_socket_to_set(&clients[i], &set) < 0) panic(sts_net_get_last_error());
- puts("Client connected!");
+ sts_net_gethostname(&clients[i], buffer, sizeof(buffer), 1, NULL);
+ printf("Client connected '%s'!\n", buffer);
break;
}
}
From e9ce5df69fee577499e685d910d61d47a99157e1 Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 12:51:35 +0900
Subject: [PATCH 05/12] Fix build error when compiling against C89 standard
---
sts_net.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sts_net.h b/sts_net.h
index 367923b..2bbf034 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -522,8 +522,9 @@ int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size,
#ifndef STS_NET_NO_PACKETS
int sts_net_refill_packet_data(sts_net_socket_t* socket) {
+ int received;
if (socket->ready) return 0;
- int received = sts_net_recv(socket, &socket->data[socket->received], STS_NET_PACKET_SIZE - socket->received);
+ received = sts_net_recv(socket, &socket->data[socket->received], STS_NET_PACKET_SIZE - socket->received);
if (received < 0) return -1;
socket->received += received;
return 1;
From 96ff41664c424f0075f8a2f5ed25d997b94be625 Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 14:10:32 +0900
Subject: [PATCH 06/12] Fix memcpy to use sts__ macro in sts_net_gethostname
---
sts_net.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sts_net.h b/sts_net.h
index 2bbf034..1388718 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -515,7 +515,7 @@ int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size,
if (addrLen >= out_size) {
return sts_net__set_error("Provided buffer is too small for host name");
}
- memcpy(out_host, host, addrLen + 1);
+ sts__memcpy(out_host, host, addrLen + 1);
return addrLen;
}
From a9392b7433faeb5e98076d58d981ffaf136c7957 Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 14:13:06 +0900
Subject: [PATCH 07/12] Added sts_net_enumerate_interfaces to get a list of
interface names and ip-addresses of the host machine
---
sts_net.h | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/sts_net.h b/sts_net.h
index 1388718..379d4d3 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -149,6 +149,18 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout);
// Returns the length of what was written into out_host or -1 on error (sets out_host empty string)
int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size, int want_only_ip, int* out_port);
+#ifndef STS_NET_NO_ENUMERATEINTERFACES
+typedef struct {
+ char interface_name[48], address[47], IsIPV6;
+} sts_net_interfaceinfo_t;
+
+// Get a list of interface names and ip-addresses of the host machine
+// The supplied table needs to be allocated memory of size tablesize * sizeof(sts_net_interfaceinfo_t)
+// Boolean parametrs want_ipv4 and want_ipv6 can be set to 0 or 1
+// The function returns the max number of table entries (can be more than tablesize)
+// You can supply NULL as table and 0 as tablesize to query for the count of entries.
+int sts_net_enumerate_interfaces(sts_net_interfaceinfo_t* table, int tablesize, int want_ipv4, int want_ipv6);
+#endif // STS_NET_NO_ENUMERATEINTERFACES
////////////////////////////////////////////////////////////////////////////////
//
@@ -221,6 +233,10 @@ void sts_net_drop_packet(sts_net_socket_t* socket);
#include
typedef int socklen_t;
#pragma comment(lib, "Ws2_32.lib")
+#ifndef STS_NET_NO_ENUMERATEINTERFACES
+#include
+#pragma comment(lib, "iphlpapi.lib")
+#endif
#else
#include
#include
@@ -232,6 +248,9 @@ typedef int socklen_t;
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define closesocket(fd) close(fd)
+#ifndef STS_NET_NO_ENUMERATEINTERFACES
+#include
+#endif
#endif
@@ -519,6 +538,62 @@ int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size,
return addrLen;
}
+#ifndef STS_NET_NO_ENUMERATEINTERFACES
+int sts_net_enumerate_interfaces(sts_net_interfaceinfo_t* table, int tablesize, int want_ipv4, int want_ipv6) {
+ void* sinaddr;
+ struct sockaddr* addr;
+ int family, ifnamelen, totalcount = 0;
+
+#if _WIN32
+ DWORD size;
+ PIP_ADAPTER_ADDRESSES adapter_addresses, aa;
+ PIP_ADAPTER_UNICAST_ADDRESS ua;
+
+ if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &size) != ERROR_BUFFER_OVERFLOW || !size) return 0;
+ adapter_addresses = (PIP_ADAPTER_ADDRESSES)HeapAlloc(GetProcessHeap(), 0, size);
+ if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, adapter_addresses, &size) != ERROR_SUCCESS) { free(adapter_addresses); return 0; }
+
+ for (aa = adapter_addresses; aa; aa = aa->Next) {
+ if (aa->OperStatus != IfOperStatusUp) continue;
+ for (ua = aa->FirstUnicastAddress; ua; ua = ua->Next) {
+ addr = ua->Address.lpSockaddr;
+#else
+ struct ifaddrs *ifAddrStruct, *ifa;
+ getifaddrs(&ifAddrStruct);
+ for (ifa = ifAddrStruct; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr) {
+ addr = ifa->ifa_addr;
+#endif
+ family = addr->sa_family;
+ if (family == AF_INET) { if (!want_ipv4) continue; }
+ else if (family == AF_INET6) { if (!want_ipv6) continue; }
+ else continue;
+ totalcount++;
+ if (!tablesize) continue;
+ if (family == AF_INET) { sinaddr = &((struct sockaddr_in*)addr)->sin_addr; table->IsIPV6 = 0; }
+ else { sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr; table->IsIPV6 = 1; }
+#if _WIN32
+ ifnamelen = WideCharToMultiByte(CP_UTF8, 0, aa->FriendlyName, -1, table->interface_name, sizeof(table->interface_name) - 1, 0, 0);
+ if (!ifnamelen) ifnamelen = sizeof(table->interface_name) - 1;
+#else
+ ifnamelen = strlen(ifa->ifa_name);
+ if (ifnamelen >= sizeof(table->interface_name)) ifnamelen = sizeof(table->interface_name) - 1;
+ sts__memcpy(table->interface_name, ifa->ifa_name, ifnamelen);
+#endif
+ table->interface_name[ifnamelen] = '\0';
+ inet_ntop(family, sinaddr, table->address, sizeof(table->address));
+ tablesize--;
+ table++;
+ }
+ }
+#if _WIN32
+ HeapFree(GetProcessHeap(), 0, adapter_addresses);
+#else
+ if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
+#endif
+ return totalcount;
+}
+#endif // STS_NET_NO_ENUMERATEINTERFACES
#ifndef STS_NET_NO_PACKETS
int sts_net_refill_packet_data(sts_net_socket_t* socket) {
From 47a53d4b23152915c691ec11ee9a8ae4efc6a4df Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 14:30:35 +0900
Subject: [PATCH 08/12] Improved socket opening and socket sets - Split
sts_net_open_socket into sts_net_listen (server) and sts_net_connect (client)
- Changed socket set to contain sockets not user managed pointer to sockets -
Added sts_net_get_available_socket_from_set which returns a socket for
accepting - Added sts_net_drop_socket which can be used to drop a new
connection if no socket is available - Removed sts_net_add_socket_to_set and
sts_net_remove_socket_from_set as it is now automatic! - Updated example
---
sts_net.h | 206 ++++++++++++++++++++++++++++++------------------------
1 file changed, 116 insertions(+), 90 deletions(-)
diff --git a/sts_net.h b/sts_net.h
index 379d4d3..aeb9eca 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -70,7 +70,7 @@ typedef struct {
typedef struct {
- sts_net_socket_t* sockets[STS_NET_SET_SOCKETS];
+ sts_net_socket_t sockets[STS_NET_SET_SOCKETS];
} sts_net_set_t;
@@ -106,9 +106,12 @@ void sts_net_reset_socket(sts_net_socket_t* socket);
// Check if the socket structure contains a "valid" socket.
int sts_net_is_socket_valid(sts_net_socket_t* socket);
-// Open a (TCP) socket. If you provide "host" sts_net will try to connect to a remove host.
-// Pass NULL for host and you'll have a server socket.
-int sts_net_open_socket(sts_net_socket_t* socket, const char* host, const char* service);
+// Open a (TCP) client socket
+int sts_net_connect(sts_net_socket_t* socket, const char* host, int port);
+
+// Open a (TCP) server socket
+// Supply NULL as bind_host to listen on any address
+int sts_net_listen(sts_net_socket_t* socket, int port, const char* bind_address);
// Closes the socket.
void sts_net_close_socket(sts_net_socket_t* socket);
@@ -116,6 +119,9 @@ void sts_net_close_socket(sts_net_socket_t* socket);
// Try to accept a connection from the given server socket.
int sts_net_accept_socket(sts_net_socket_t* listen_socket, sts_net_socket_t* remote_socket);
+// Instead of accept, drop an incoming connection from the given server socket
+int sts_net_drop_socket(sts_net_socket_t* listen_socket);
+
// Send data to the socket.
int sts_net_send(sts_net_socket_t* socket, const void* data, int length);
@@ -126,12 +132,8 @@ int sts_net_recv(sts_net_socket_t* socket, void* data, int length);
// Initialized a socket set.
void sts_net_init_socket_set(sts_net_set_t* set);
-// Add a socket to the socket set.
-int sts_net_add_socket_to_set(sts_net_socket_t* socket, sts_net_set_t* set);
-
-// Remove a socket from the socket set. You have to remove the socket from a set manually.
-// sts_net_close_socket WILL NOT DO THAT!
-int sts_net_remove_socket_from_set(sts_net_socket_t* socket, sts_net_set_t* set);
+// Get an available socket from the set (returns NULL if none available)
+sts_net_socket_t* sts_net_get_available_socket_from_set(sts_net_set_t* set);
// Checks for activity on all sockets in the given socket set. If you want to peek for events
// pass 0.0f to the timeout.
@@ -316,56 +318,76 @@ void sts_net_shutdown() {
}
-int sts_net_open_socket(sts_net_socket_t* sock, const char* host, const char* service) {
- struct addrinfo hints;
- struct addrinfo *res = NULL, *r = NULL;
+static int sts_net__resolvehost(struct sockaddr_in* sin, const char* host, int port) {
+ sts__memset(sin, 0, sizeof(struct sockaddr_in));
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ sin->sin_addr.s_addr = (host ? inet_addr(host) : INADDR_ANY);
+ if (sin->sin_addr.s_addr == INADDR_NONE) {
+ struct hostent *hostent = gethostbyname(host);
+ if (hostent)
+ sts__memcpy(&sin->sin_addr.s_addr, hostent->h_addr, hostent->h_length);
+ else
+ return -1;
+ }
+ return 0;
+}
+
+
+int sts_net_connect(sts_net_socket_t* sock, const char* host, int port) {
int fd = INVALID_SOCKET;
+ struct sockaddr_in sin;
sts_net_reset_socket(sock);
- sts__memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- if (host != NULL) {
+ if (sts_net__resolvehost(&sin, host, port)) {
+ return sts_net__set_error("Cannot resolve hostname");
+ }
+
// try to connect to remote host
- if (getaddrinfo(host, service, &hints, &res) != 0) return sts_net__set_error("Cannot resolve hostname");
- for (r = res; r; r = r->ai_next) {
- fd = (int)socket(r->ai_family, r->ai_socktype, r->ai_protocol);
- if (fd == INVALID_SOCKET) continue;
- if (connect(fd, r->ai_addr, (int)r->ai_addrlen) == 0) break;
- closesocket(fd);
+ fd = (int)socket(PF_INET, SOCK_STREAM, 0);
+ if (connect(fd, (const struct sockaddr *)&sin, sizeof(sin))) {
+ return sts_net__set_error("Could not create socket");
}
- freeaddrinfo(res);
- if (!r) return sts_net__set_error("Cannot connect to host");
+
sock->fd = fd;
- } else {
+ return 0;
+}
+
+
+int sts_net_listen(sts_net_socket_t* sock, int port, const char* bind_address) {
+ int fd = INVALID_SOCKET;
+ struct sockaddr_in sin;
+
+ sts_net_reset_socket(sock);
+
// listen for connection (start server)
- hints.ai_flags = AI_PASSIVE;
- if (getaddrinfo(NULL, service, &hints, &res) != 0) return sts_net__set_error("Cannot resolve hostname");
- fd = (int)socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ fd = (int)socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd == INVALID_SOCKET) {
- freeaddrinfo(res);
return sts_net__set_error("Could not create socket");
}
+
#ifndef _WIN32
{
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
}
#endif // _WIN32
- if (bind(fd, res->ai_addr, (int)res->ai_addrlen) == SOCKET_ERROR) {
- freeaddrinfo(res);
+
+ if (sts_net__resolvehost(&sin, bind_address, port)) {
+ return sts_net__set_error("Cannot resolve bind address");
+ }
+
+ if (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) {
closesocket(fd);
return sts_net__set_error("Could not bind to port");
}
- freeaddrinfo(res);
if (listen(fd, STS_NET_BACKLOG) == SOCKET_ERROR) {
closesocket(fd);
return sts_net__set_error("Could not listen to socket");
}
sock->server = 1;
sock->fd = fd;
- }
return 0;
}
@@ -399,6 +421,29 @@ int sts_net_accept_socket(sts_net_socket_t* listen_socket, sts_net_socket_t* rem
}
+int sts_net_drop_socket(sts_net_socket_t* listen_socket) {
+ int fd;
+ struct sockaddr_in sock_addr;
+ socklen_t sock_alen;
+
+ if (!listen_socket->server) {
+ return sts_net__set_error("Cannot drop incoming connection on client socket");
+ }
+ if (listen_socket->fd == INVALID_SOCKET) {
+ return sts_net__set_error("Cannot drop incoming connection on closed socket");
+ }
+
+ sock_alen = sizeof(sock_addr);
+ listen_socket->ready = 0;
+ fd = (int)accept(listen_socket->fd, (struct sockaddr*)&sock_addr, &sock_alen);
+ if (fd == INVALID_SOCKET) {
+ return sts_net__set_error("Accept failed");
+ }
+ closesocket(fd);
+ return 0;
+}
+
+
int sts_net_send(sts_net_socket_t* socket, const void* data, int length) {
if (socket->server) {
return sts_net__set_error("Cannot send on server socket");
@@ -433,38 +478,19 @@ int sts_net_recv(sts_net_socket_t* socket, void* data, int length) {
void sts_net_init_socket_set(sts_net_set_t* set) {
int i;
for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- set->sockets[i] = NULL;
- }
-}
-
-
-int sts_net_add_socket_to_set(sts_net_socket_t *socket, sts_net_set_t *set) {
- int i;
- if (socket->fd == INVALID_SOCKET) {
- return sts_net__set_error("Cannot add closed socket to set");
- }
- for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (!set->sockets[i]) {
- set->sockets[i] = socket;
- return 0;
- }
+ set->sockets[i].ready = 0;
+ set->sockets[i].fd = INVALID_SOCKET;
}
- return sts_net__set_error("Socket set is full");
}
-int sts_net_remove_socket_from_set(sts_net_socket_t *socket, sts_net_set_t *set) {
+sts_net_socket_t* sts_net_get_available_socket_from_set(sts_net_set_t* set) {
int i;
- if (socket->fd == INVALID_SOCKET) {
- return sts_net__set_error("Cannot remove closed socket from set");
- }
for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (set->sockets[i] == socket) {
- set->sockets[i] = NULL;
- return 0;
- }
+ if (set->sockets[i].fd == INVALID_SOCKET)
+ return &set->sockets[i];
}
- return sts_net__set_error("Socket not found in set");
+ return NULL;
}
@@ -473,13 +499,19 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
struct timeval tv;
int i, max_fd, result;
+ //static assertion to make sure STS_NET_SET_SOCKETS fits into FD_SETSIZE
+ typedef char static_assert_set_size_too_large[(STS_NET_SET_SOCKETS <= FD_SETSIZE)?1:-1];
FD_ZERO(&fds);
for (i = 0, max_fd = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (set->sockets[i]) {
- FD_SET(set->sockets[i]->fd, &fds);
- if (set->sockets[i]->fd > max_fd) {
- max_fd = set->sockets[i]->fd;
+ if (set->sockets[i].fd != INVALID_SOCKET) {
+ #ifdef _WIN32
+ FD_SET((SOCKET)set->sockets[i].fd, &fds);
+ #else
+ FD_SET(set->sockets[i].fd, &fds);
+ #endif
+ if (set->sockets[i].fd > max_fd) {
+ max_fd = set->sockets[i].fd;
}
}
}
@@ -490,15 +522,15 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
result = select(max_fd + 1, &fds, NULL, NULL, &tv);
if (result > 0) {
for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (set->sockets[i]) {
- if (FD_ISSET(set->sockets[i]->fd, &fds)) {
- set->sockets[i]->ready = 1;
+ if (set->sockets[i].fd != INVALID_SOCKET) {
+ if (FD_ISSET(set->sockets[i].fd, &fds)) {
+ set->sockets[i].ready = 1;
}
}
- }
+ }
} else if (result == SOCKET_ERROR) {
sts_net__set_error("Error on select()");
- }
+ }
return result;
}
@@ -654,52 +686,46 @@ void panic(const char* msg) {
int main(int argc, char *argv[]) {
int i, j, bytes;
sts_net_set_t set;
- sts_net_socket_t server;
- sts_net_socket_t clients[STS_NET_SET_SOCKETS];
+ sts_net_socket_t *server, *client;
char buffer[256];
(void)(argc);
(void)(argv);
- for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- clients[i].ready = 0;
- clients[i].fd = INVALID_SOCKET;
- }
-
sts_net_init();
- if (sts_net_open_socket(&server, NULL, "4040") < 0) panic(sts_net_get_last_error());
sts_net_init_socket_set(&set);
- if (sts_net_add_socket_to_set(&server, &set) < 0) panic(sts_net_get_last_error());
+ server = &set.sockets[0];
+ if (sts_net_listen(server, 4040, NULL) < 0) panic(sts_net_get_last_error());
while(1) {
puts("Waiting...");
if (sts_net_check_socket_set(&set, 0.5) < 0) panic(sts_net_get_last_error());
// check server
- if (server.ready) {
- for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (clients[i].fd == INVALID_SOCKET) {
- if (sts_net_accept_socket(&server, &clients[i]) < 0) panic(sts_net_get_last_error());
- if (sts_net_add_socket_to_set(&clients[i], &set) < 0) panic(sts_net_get_last_error());
- sts_net_gethostname(&clients[i], buffer, sizeof(buffer), 1, NULL);
+ if (server->ready) {
+ client = sts_net_get_available_socket_from_set(&set);
+ if (client) {
+ if (sts_net_accept_socket(server, client) < 0) panic(sts_net_get_last_error());
+ sts_net_gethostname(client, buffer, sizeof(buffer), 1, NULL);
printf("Client connected '%s'!\n", buffer);
- break;
}
+ else {
+ sts_net_drop_socket(server);
+ puts("Connection set full, client dropped");
}
}
// check clients
for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (clients[i].ready) {
+ if (set.sockets[i].ready) {
memset(buffer, 0, sizeof(buffer));
- bytes = sts_net_recv(&clients[i], buffer, sizeof(buffer) - 1);
+ bytes = sts_net_recv(&set.sockets[i], buffer, sizeof(buffer) - 1);
if (bytes <= 0) {
- if (sts_net_remove_socket_from_set(&clients[i], &set) < 0) panic(sts_net_get_last_error());
- sts_net_close_socket(&clients[i]);
+ sts_net_close_socket(&set.sockets[i]);
puts("Client disconnected");
} else {
// broadcast
for (j = 0; j < STS_NET_SET_SOCKETS; ++j) {
- if (clients[j].fd != INVALID_SOCKET) {
- if (sts_net_send(&clients[j], buffer, bytes) < 0) panic(sts_net_get_last_error());
+ if (set.sockets[j].fd != INVALID_SOCKET && set.sockets[j].server == 0) {
+ if (sts_net_send(&set.sockets[j], buffer, bytes) < 0) panic(sts_net_get_last_error());
}
}
printf("Broadcast: %s\n", buffer);
From 287d17535da1ab6c1bb99952bc8f79758c619de1 Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Fri, 7 Apr 2017 14:31:57 +0900
Subject: [PATCH 09/12] Added sts_net_check_socket to check just a single
socket
---
sts_net.h | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/sts_net.h b/sts_net.h
index aeb9eca..4b43712 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -145,6 +145,9 @@ sts_net_socket_t* sts_net_get_available_socket_from_set(sts_net_set_t* set);
// >0 amount of sockets with activity
int sts_net_check_socket_set(sts_net_set_t* set, const float timeout);
+// Check for activity on a single socket. Parameters and return value see above.
+int sts_net_check_socket(sts_net_socket_t* socket, const float timeout);
+
// Read the connected hostname of a socket into out buffer
// Supply 1 to want_only_ip if instead of the resolved host name only the ip address is needed
// out_port can be supplied as NULL if you're not interested in the connected port number
@@ -535,6 +538,34 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
}
+int sts_net_check_socket(sts_net_socket_t* socket, const float timeout) {
+ fd_set fds;
+ struct timeval tv;
+ int result;
+
+ if (socket->fd == INVALID_SOCKET) {
+ return sts_net__set_error("Cannot check a closed socket");
+ }
+
+ FD_ZERO(&fds);
+ #ifdef _WIN32
+ FD_SET((SOCKET)socket->fd, &fds);
+ #else
+ FD_SET(socket->fd, &fds);
+ #endif
+
+ tv.tv_sec = (int)timeout;
+ tv.tv_usec = (int)((timeout - (float)tv.tv_sec) * 1000000.0f);
+ result = select(socket->fd + 1, &fds, NULL, NULL, &tv);
+ if (result > 0) {
+ socket->ready = 1;
+ } else if (result == SOCKET_ERROR) {
+ sts_net__set_error("Error on select()");
+ }
+ return result;
+}
+
+
int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size, int want_only_ip, int* out_port) {
struct sockaddr_in sin;
struct in_addr in;
From ad4c1e825b84edae338e68d4c5697f2b2e96cb6f Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Sun, 9 Apr 2017 21:37:30 +0900
Subject: [PATCH 10/12] Fixed some more compile warnings on stricter warning
levels
---
sts_net.h | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/sts_net.h b/sts_net.h
index 4b43712..8a35107 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -4,6 +4,12 @@
written 2017 by Sebastian Steinhauer
VERSION HISTORY
+ 0.07s (2017-04-07) build warning fixes
+ split sts_net_open_socket into connect/listen
+ added sts_net_gethostname
+ added sts_net_enumerate_interfaces
+ added sts_net_drop_socket
+ changed socket set usage (see new example code)
0.07 (2017-02-24) added checks for a valid socket in every function
return 0 for an empty socket set
0.06 (2017-01-14) fixed warnings when compiling on Windows 64-bit
@@ -324,7 +330,7 @@ void sts_net_shutdown() {
static int sts_net__resolvehost(struct sockaddr_in* sin, const char* host, int port) {
sts__memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
- sin->sin_port = htons(port);
+ sin->sin_port = htons((short)port);
sin->sin_addr.s_addr = (host ? inet_addr(host) : INADDR_ANY);
if (sin->sin_addr.s_addr == INADDR_NONE) {
struct hostent *hostent = gethostbyname(host);
@@ -503,7 +509,11 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
int i, max_fd, result;
//static assertion to make sure STS_NET_SET_SOCKETS fits into FD_SETSIZE
- typedef char static_assert_set_size_too_large[(STS_NET_SET_SOCKETS <= FD_SETSIZE)?1:-1];
+ typedef char static_assert_set_size_too_large[(STS_NET_SET_SOCKETS <= FD_SETSIZE)?1:-1]
+ #ifndef _MSC_VER
+ __attribute__((unused))
+ #endif
+ ;
FD_ZERO(&fds);
for (i = 0, max_fd = 0; i < STS_NET_SET_SOCKETS; ++i) {
@@ -532,8 +542,8 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
}
}
} else if (result == SOCKET_ERROR) {
- sts_net__set_error("Error on select()");
- }
+ return sts_net__set_error("Error on select()");
+ }
return result;
}
@@ -560,7 +570,7 @@ int sts_net_check_socket(sts_net_socket_t* socket, const float timeout) {
if (result > 0) {
socket->ready = 1;
} else if (result == SOCKET_ERROR) {
- sts_net__set_error("Error on select()");
+ return sts_net__set_error("Error on select()");
}
return result;
}
@@ -593,7 +603,7 @@ int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size,
if (host == NULL) {
return sts_net__set_error("Error while getting host name of socket");
}
- addrLen = strlen(host);
+ addrLen = (int)strlen(host);
if (addrLen >= out_size) {
return sts_net__set_error("Provided buffer is too small for host name");
}
@@ -640,7 +650,7 @@ int sts_net_enumerate_interfaces(sts_net_interfaceinfo_t* table, int tablesize,
if (!ifnamelen) ifnamelen = sizeof(table->interface_name) - 1;
#else
ifnamelen = strlen(ifa->ifa_name);
- if (ifnamelen >= sizeof(table->interface_name)) ifnamelen = sizeof(table->interface_name) - 1;
+ if (ifnamelen >= (int)sizeof(table->interface_name)) ifnamelen = sizeof(table->interface_name) - 1;
sts__memcpy(table->interface_name, ifa->ifa_name, ifnamelen);
#endif
table->interface_name[ifnamelen] = '\0';
From 6fada02fb4c5e3f12e5aafff1fbb395e8a54184a Mon Sep 17 00:00:00 2001
From: Bernhard Schelling
Date: Mon, 19 Jun 2017 02:00:25 +0900
Subject: [PATCH 11/12] fix possible missing ptrdiff_t on non-windows platforms
fix source formatting
---
sts_net.h | 93 ++++++++++++++++++++++++++++---------------------------
1 file changed, 47 insertions(+), 46 deletions(-)
diff --git a/sts_net.h b/sts_net.h
index 8a35107..1ea662e 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -248,6 +248,7 @@ typedef int socklen_t;
#include
#pragma comment(lib, "iphlpapi.lib")
#endif
+#define STS_INVALID_SOCKET (int)(ptrdiff_t)INVALID_SOCKET
#else
#include
#include
@@ -256,9 +257,9 @@ typedef int socklen_t;
#include
#include
#include
-#define INVALID_SOCKET -1
-#define SOCKET_ERROR -1
-#define closesocket(fd) close(fd)
+#define STS_INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define closesocket(fd) close(fd)
#ifndef STS_NET_NO_ENUMERATEINTERFACES
#include
#endif
@@ -292,7 +293,7 @@ const char *sts_net_get_last_error() {
void sts_net_reset_socket(sts_net_socket_t* socket) {
- socket->fd = INVALID_SOCKET;
+ socket->fd = STS_INVALID_SOCKET;
socket->ready = 0;
socket->server = 0;
#ifndef STS_NET_NO_PACKETS
@@ -303,7 +304,7 @@ void sts_net_reset_socket(sts_net_socket_t* socket) {
int sts_net_is_socket_valid(sts_net_socket_t* socket) {
- return socket->fd != INVALID_SOCKET;
+ return socket->fd != STS_INVALID_SOCKET;
}
@@ -344,7 +345,7 @@ static int sts_net__resolvehost(struct sockaddr_in* sin, const char* host, int p
int sts_net_connect(sts_net_socket_t* sock, const char* host, int port) {
- int fd = INVALID_SOCKET;
+ int fd = STS_INVALID_SOCKET;
struct sockaddr_in sin;
sts_net_reset_socket(sock);
@@ -353,34 +354,34 @@ int sts_net_connect(sts_net_socket_t* sock, const char* host, int port) {
return sts_net__set_error("Cannot resolve hostname");
}
- // try to connect to remote host
+ // try to connect to remote host
fd = (int)socket(PF_INET, SOCK_STREAM, 0);
if (connect(fd, (const struct sockaddr *)&sin, sizeof(sin))) {
return sts_net__set_error("Could not create socket");
- }
+ }
- sock->fd = fd;
+ sock->fd = fd;
return 0;
}
int sts_net_listen(sts_net_socket_t* sock, int port, const char* bind_address) {
- int fd = INVALID_SOCKET;
+ int fd = STS_INVALID_SOCKET;
struct sockaddr_in sin;
sts_net_reset_socket(sock);
- // listen for connection (start server)
+ // listen for connection (start server)
fd = (int)socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (fd == INVALID_SOCKET) {
- return sts_net__set_error("Could not create socket");
- }
+ if (fd == STS_INVALID_SOCKET) {
+ return sts_net__set_error("Could not create socket");
+ }
#ifndef _WIN32
- {
- int yes = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
- }
+ {
+ int yes = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
+ }
#endif // _WIN32
if (sts_net__resolvehost(&sin, bind_address, port)) {
@@ -388,21 +389,21 @@ int sts_net_listen(sts_net_socket_t* sock, int port, const char* bind_address) {
}
if (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) {
- closesocket(fd);
- return sts_net__set_error("Could not bind to port");
- }
- if (listen(fd, STS_NET_BACKLOG) == SOCKET_ERROR) {
- closesocket(fd);
- return sts_net__set_error("Could not listen to socket");
- }
- sock->server = 1;
- sock->fd = fd;
+ closesocket(fd);
+ return sts_net__set_error("Could not bind to port");
+ }
+ if (listen(fd, STS_NET_BACKLOG) == SOCKET_ERROR) {
+ closesocket(fd);
+ return sts_net__set_error("Could not listen to socket");
+ }
+ sock->server = 1;
+ sock->fd = fd;
return 0;
}
void sts_net_close_socket(sts_net_socket_t* socket) {
- if (socket->fd != INVALID_SOCKET) closesocket(socket->fd);
+ if (socket->fd != STS_INVALID_SOCKET) closesocket(socket->fd);
sts_net_reset_socket(socket);
}
@@ -414,7 +415,7 @@ int sts_net_accept_socket(sts_net_socket_t* listen_socket, sts_net_socket_t* rem
if (!listen_socket->server) {
return sts_net__set_error("Cannot accept on client socket");
}
- if (listen_socket->fd == INVALID_SOCKET) {
+ if (listen_socket->fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Cannot accept on closed socket");
}
@@ -423,7 +424,7 @@ int sts_net_accept_socket(sts_net_socket_t* listen_socket, sts_net_socket_t* rem
remote_socket->ready = 0;
remote_socket->server = 0;
remote_socket->fd = (int)accept(listen_socket->fd, (struct sockaddr*)&sock_addr, &sock_alen);
- if (remote_socket->fd == INVALID_SOCKET) {
+ if (remote_socket->fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Accept failed");
}
return 0;
@@ -438,14 +439,14 @@ int sts_net_drop_socket(sts_net_socket_t* listen_socket) {
if (!listen_socket->server) {
return sts_net__set_error("Cannot drop incoming connection on client socket");
}
- if (listen_socket->fd == INVALID_SOCKET) {
+ if (listen_socket->fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Cannot drop incoming connection on closed socket");
}
sock_alen = sizeof(sock_addr);
listen_socket->ready = 0;
fd = (int)accept(listen_socket->fd, (struct sockaddr*)&sock_addr, &sock_alen);
- if (fd == INVALID_SOCKET) {
+ if (fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Accept failed");
}
closesocket(fd);
@@ -457,7 +458,7 @@ int sts_net_send(sts_net_socket_t* socket, const void* data, int length) {
if (socket->server) {
return sts_net__set_error("Cannot send on server socket");
}
- if (socket->fd == INVALID_SOCKET) {
+ if (socket->fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Cannot send on closed socket");
}
if (send(socket->fd, (const char*)data, length, 0) != length) {
@@ -472,7 +473,7 @@ int sts_net_recv(sts_net_socket_t* socket, void* data, int length) {
if (socket->server) {
return sts_net__set_error("Cannot receive on server socket");
}
- if (socket->fd == INVALID_SOCKET) {
+ if (socket->fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Cannot receive on closed socket");
}
socket->ready = 0;
@@ -488,7 +489,7 @@ void sts_net_init_socket_set(sts_net_set_t* set) {
int i;
for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
set->sockets[i].ready = 0;
- set->sockets[i].fd = INVALID_SOCKET;
+ set->sockets[i].fd = STS_INVALID_SOCKET;
}
}
@@ -496,7 +497,7 @@ void sts_net_init_socket_set(sts_net_set_t* set) {
sts_net_socket_t* sts_net_get_available_socket_from_set(sts_net_set_t* set) {
int i;
for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (set->sockets[i].fd == INVALID_SOCKET)
+ if (set->sockets[i].fd == STS_INVALID_SOCKET)
return &set->sockets[i];
}
return NULL;
@@ -517,7 +518,7 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
FD_ZERO(&fds);
for (i = 0, max_fd = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (set->sockets[i].fd != INVALID_SOCKET) {
+ if (set->sockets[i].fd != STS_INVALID_SOCKET) {
#ifdef _WIN32
FD_SET((SOCKET)set->sockets[i].fd, &fds);
#else
@@ -535,12 +536,12 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
result = select(max_fd + 1, &fds, NULL, NULL, &tv);
if (result > 0) {
for (i = 0; i < STS_NET_SET_SOCKETS; ++i) {
- if (set->sockets[i].fd != INVALID_SOCKET) {
+ if (set->sockets[i].fd != STS_INVALID_SOCKET) {
if (FD_ISSET(set->sockets[i].fd, &fds)) {
set->sockets[i].ready = 1;
}
}
- }
+ }
} else if (result == SOCKET_ERROR) {
return sts_net__set_error("Error on select()");
}
@@ -553,7 +554,7 @@ int sts_net_check_socket(sts_net_socket_t* socket, const float timeout) {
struct timeval tv;
int result;
- if (socket->fd == INVALID_SOCKET) {
+ if (socket->fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Cannot check a closed socket");
}
@@ -586,7 +587,7 @@ int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size,
if (out_size) out_host[0] = '\0';
- if (socket->fd == INVALID_SOCKET) {
+ if (socket->fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Cannot get host name of closed socket");
}
@@ -725,10 +726,10 @@ void panic(const char* msg) {
int main(int argc, char *argv[]) {
- int i, j, bytes;
- sts_net_set_t set;
+ int i, j, bytes;
+ sts_net_set_t set;
sts_net_socket_t *server, *client;
- char buffer[256];
+ char buffer[256];
(void)(argc);
(void)(argv);
@@ -748,7 +749,7 @@ int main(int argc, char *argv[]) {
if (sts_net_accept_socket(server, client) < 0) panic(sts_net_get_last_error());
sts_net_gethostname(client, buffer, sizeof(buffer), 1, NULL);
printf("Client connected '%s'!\n", buffer);
- }
+ }
else {
sts_net_drop_socket(server);
puts("Connection set full, client dropped");
@@ -765,7 +766,7 @@ int main(int argc, char *argv[]) {
} else {
// broadcast
for (j = 0; j < STS_NET_SET_SOCKETS; ++j) {
- if (set.sockets[j].fd != INVALID_SOCKET && set.sockets[j].server == 0) {
+ if (set.sockets[j].fd != STS_INVALID_SOCKET && set.sockets[j].server == 0) {
if (sts_net_send(&set.sockets[j], buffer, bytes) < 0) panic(sts_net_get_last_error());
}
}
From 43f73d2da67cc7bc753db9266e00f3d29a6cbc1f Mon Sep 17 00:00:00 2001
From: Bernhard Schelling <[email protected]>
Date: Sat, 23 May 2020 04:49:31 +0900
Subject: [PATCH 12/12] added basic udp functionality (sts_net_udp_*) added
want_local_name to sts_net_gethostname added share_port option to
sts_net_listen
---
sts_net.h | 252 ++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 215 insertions(+), 37 deletions(-)
diff --git a/sts_net.h b/sts_net.h
index 1ea662e..03c6d41 100644
--- a/sts_net.h
+++ b/sts_net.h
@@ -4,12 +4,15 @@
written 2017 by Sebastian Steinhauer
VERSION HISTORY
- 0.07s (2017-04-07) build warning fixes
- split sts_net_open_socket into connect/listen
- added sts_net_gethostname
- added sts_net_enumerate_interfaces
- added sts_net_drop_socket
- changed socket set usage (see new example code)
+ 0.07s2 (2020-05-23) added basic udp functionality (sts_net_udp_*)
+ added want_local_name to sts_net_gethostname
+ added share_port option to sts_net_listen
+ 0.07s1 (2017-04-07) build warning fixes
+ split sts_net_open_socket into connect/listen
+ added sts_net_gethostname
+ added sts_net_enumerate_interfaces
+ added sts_net_drop_socket
+ changed socket set usage (see new example code)
0.07 (2017-02-24) added checks for a valid socket in every function
return 0 for an empty socket set
0.06 (2017-01-14) fixed warnings when compiling on Windows 64-bit
@@ -57,7 +60,7 @@
#ifdef __cplusplus
extern "C" {
-#endif
+#endif // __cplusplus
////////////////////////////////////////////////////////////////////////////////
//
@@ -92,7 +95,7 @@ typedef struct {
#ifndef STS_NET_NO_ERRORSTRINGS
// Get the last error from sts_net (can be called even before sts_net_init)
const char* sts_net_get_last_error();
-#endif
+#endif // STS_NET_NO_ERRORSTRINGS
// Initialized the sts_net library. You have to call this before any other function (except sts_net_get_last_error)
int sts_net_init();
@@ -116,8 +119,9 @@ int sts_net_is_socket_valid(sts_net_socket_t* socket);
int sts_net_connect(sts_net_socket_t* socket, const char* host, int port);
// Open a (TCP) server socket
-// Supply NULL as bind_host to listen on any address
-int sts_net_listen(sts_net_socket_t* socket, int port, const char* bind_address);
+// Supply NULL as bind_address to listen on any address
+// Set share_port to 0 to block multiple sockets listening on the same port
+int sts_net_listen(sts_net_socket_t* socket, int port, const char* bind_address, int share_port);
// Closes the socket.
void sts_net_close_socket(sts_net_socket_t* socket);
@@ -158,7 +162,30 @@ int sts_net_check_socket(sts_net_socket_t* socket, const float timeout);
// Supply 1 to want_only_ip if instead of the resolved host name only the ip address is needed
// out_port can be supplied as NULL if you're not interested in the connected port number
// Returns the length of what was written into out_host or -1 on error (sets out_host empty string)
-int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size, int want_only_ip, int* out_port);
+// Supply 1 to want_local_name if you want the name of the local side not the remote peer name
+int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size, int want_only_ip, int* out_port, int want_local_name);
+
+// Open a UDP client socket
+int sts_net_udp_open(sts_net_socket_t* socket);
+
+// Set UDP multicast TTL (time to live, after how many hops on the network the packet will not be re-sent/broadcast)
+int sts_net_udp_set_multicast_ttl(sts_net_socket_t* socket, int ttl);
+
+// Join UDP socket to a multi cast address
+int sts_net_udp_join_multicast(sts_net_socket_t* socket, const char* multicast_host);
+
+// Bind UDP socket to a port
+// Supply NULL as bind_address to listen on any address
+// Set share_port to 0 to block multiple sockets listening on the same port
+int sts_net_udp_bind(sts_net_socket_t* socket, int port, const char* bind_address, int share_port);
+
+// Receive data from a bound UDP socket
+// ip (if not NULL) will be filled with 4 ip parts of sender (must be unsigned char[4])
+// port (if not NULL) will be filled with the senders port number
+int sts_net_udp_recv_from(sts_net_socket_t* socket, void* data, int length, unsigned char* ip, int* port);
+
+// Send data through a UDP socket
+int sts_net_udp_send(sts_net_socket_t* socket, const char* host, int port, const void* data, int length);
#ifndef STS_NET_NO_ENUMERATEINTERFACES
typedef struct {
@@ -217,7 +244,7 @@ void sts_net_drop_packet(sts_net_socket_t* socket);
#ifdef __cplusplus
}
-#endif
+#endif // __cplusplus
#endif // __INCLUDED__STS_NET_H__
@@ -247,7 +274,8 @@ typedef int socklen_t;
#ifndef STS_NET_NO_ENUMERATEINTERFACES
#include
#pragma comment(lib, "iphlpapi.lib")
-#endif
+#endif // STS_NET_NO_ENUMERATEINTERFACES
+#include // ptrdiff_t
#define STS_INVALID_SOCKET (int)(ptrdiff_t)INVALID_SOCKET
#else
#include
@@ -262,9 +290,14 @@ typedef int socklen_t;
#define closesocket(fd) close(fd)
#ifndef STS_NET_NO_ENUMERATEINTERFACES
#include
-#endif
-#endif
+#endif // STS_NET_NO_ENUMERATEINTERFACES
+#endif // _WIN32
+#ifdef MSG_NOSIGNAL
+#define STS_SEND_FLAG MSG_NOSIGNAL
+#else
+#define STS_SEND_FLAG 0
+#endif // MSG_NOSIGNAL
#ifndef sts__memcpy
#define sts__memcpy memcpy
@@ -289,9 +322,19 @@ const char *sts_net_get_last_error() {
}
#else
#define sts_net__set_error(m) -1
-#endif
+#endif // STS_NET_NO_ERRORSTRINGS
+int sts_net__create_socket(int type) {
+ int fd = (int)socket(AF_INET, type, 0), yes = 1;
+ if (fd != STS_INVALID_SOCKET) {
+ #ifdef SO_NOSIGPIPE
+ setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(yes));
+ #endif // SO_NOSIGPIPE
+ }
+ return fd;
+}
+
void sts_net_reset_socket(sts_net_socket_t* socket) {
socket->fd = STS_INVALID_SOCKET;
socket->ready = 0;
@@ -345,7 +388,7 @@ static int sts_net__resolvehost(struct sockaddr_in* sin, const char* host, int p
int sts_net_connect(sts_net_socket_t* sock, const char* host, int port) {
- int fd = STS_INVALID_SOCKET;
+ int fd;
struct sockaddr_in sin;
sts_net_reset_socket(sock);
@@ -355,8 +398,8 @@ int sts_net_connect(sts_net_socket_t* sock, const char* host, int port) {
}
// try to connect to remote host
- fd = (int)socket(PF_INET, SOCK_STREAM, 0);
- if (connect(fd, (const struct sockaddr *)&sin, sizeof(sin))) {
+ fd = sts_net__create_socket(SOCK_STREAM);
+ if (fd == STS_INVALID_SOCKET || connect(fd, (const struct sockaddr *)&sin, sizeof(sin))) {
return sts_net__set_error("Could not create socket");
}
@@ -365,25 +408,23 @@ int sts_net_connect(sts_net_socket_t* sock, const char* host, int port) {
}
-int sts_net_listen(sts_net_socket_t* sock, int port, const char* bind_address) {
- int fd = STS_INVALID_SOCKET;
+int sts_net_listen(sts_net_socket_t* sock, int port, const char* bind_address, int share_port) {
+ int fd;
struct sockaddr_in sin;
sts_net_reset_socket(sock);
// listen for connection (start server)
- fd = (int)socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ fd = sts_net__create_socket(SOCK_STREAM);
if (fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Could not create socket");
}
-#ifndef _WIN32
- {
+ if (share_port) {
int yes = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
}
-#endif // _WIN32
-
+
if (sts_net__resolvehost(&sin, bind_address, port)) {
return sts_net__set_error("Cannot resolve bind address");
}
@@ -461,7 +502,7 @@ int sts_net_send(sts_net_socket_t* socket, const void* data, int length) {
if (socket->fd == STS_INVALID_SOCKET) {
return sts_net__set_error("Cannot send on closed socket");
}
- if (send(socket->fd, (const char*)data, length, 0) != length) {
+ if (send(socket->fd, (const char*)data, length, STS_SEND_FLAG) != length) {
return sts_net__set_error("Cannot send data");
}
return 0;
@@ -513,7 +554,7 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
typedef char static_assert_set_size_too_large[(STS_NET_SET_SOCKETS <= FD_SETSIZE)?1:-1]
#ifndef _MSC_VER
__attribute__((unused))
- #endif
+ #endif // _MSC_VER
;
FD_ZERO(&fds);
@@ -523,7 +564,7 @@ int sts_net_check_socket_set(sts_net_set_t* set, const float timeout) {
FD_SET((SOCKET)set->sockets[i].fd, &fds);
#else
FD_SET(set->sockets[i].fd, &fds);
- #endif
+ #endif // _WIN32
if (set->sockets[i].fd > max_fd) {
max_fd = set->sockets[i].fd;
}
@@ -563,7 +604,7 @@ int sts_net_check_socket(sts_net_socket_t* socket, const float timeout) {
FD_SET((SOCKET)socket->fd, &fds);
#else
FD_SET(socket->fd, &fds);
- #endif
+ #endif // _WIN32
tv.tv_sec = (int)timeout;
tv.tv_usec = (int)((timeout - (float)tv.tv_sec) * 1000000.0f);
@@ -577,7 +618,7 @@ int sts_net_check_socket(sts_net_socket_t* socket, const float timeout) {
}
-int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size, int want_only_ip, int* out_port) {
+int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size, int want_only_ip, int* out_port, int want_local_name) {
struct sockaddr_in sin;
struct in_addr in;
struct hostent* hostEntry;
@@ -592,7 +633,7 @@ int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size,
}
sinLength = sizeof(struct sockaddr_in);
- if (getsockname(socket->fd, (struct sockaddr *)&sin, &sinLength) == -1) {
+ if ((want_local_name ? getsockname : getpeername)(socket->fd, (struct sockaddr *)&sin, &sinLength) == -1) {
return sts_net__set_error("Error while getting host name of socket");
}
@@ -612,6 +653,143 @@ int sts_net_gethostname(sts_net_socket_t* socket, char* out_host, int out_size,
return addrLen;
}
+
+int sts_net_udp_open(sts_net_socket_t* sock) {
+ int fd;
+
+ sts_net_reset_socket(sock);
+
+ fd = sts_net__create_socket(SOCK_DGRAM);
+ if (fd == STS_INVALID_SOCKET) {
+ return sts_net__set_error("Could not create socket");
+ }
+
+ sock->fd = fd;
+ return 0;
+}
+
+
+int sts_net_udp_set_multicast_ttl(sts_net_socket_t* socket, int ttl) {
+ if (socket->fd == STS_INVALID_SOCKET) {
+ return sts_net__set_error("Cannot set ttl on closed socket");
+ }
+ if (socket->server) {
+ return sts_net__set_error("Cannot set ttl on server ocket");
+ }
+ if (setsockopt(socket->fd, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(int)) < 0) {
+ return sts_net__set_error("Set TTL option failed");
+ }
+ return 0;
+}
+
+
+int sts_net_udp_join_multicast(sts_net_socket_t* socket, const char* multicast_host) {
+ struct sockaddr_in sin;
+ struct ip_mreq mreq;
+
+ if (sts_net__resolvehost(&sin, multicast_host, 0)) {
+ return sts_net__set_error("Cannot resolve hostname");
+ }
+
+ mreq.imr_interface.s_addr = INADDR_ANY;
+ mreq.imr_multiaddr = sin.sin_addr;
+ if (setsockopt(socket->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) {
+ return sts_net__set_error("Multicast add membership failed");
+ }
+ return 0;
+}
+
+
+int sts_net_udp_bind(sts_net_socket_t* socket, int port, const char* bind_address, int share_port) {
+ struct sockaddr_in sin;
+
+ if (socket->fd == STS_INVALID_SOCKET) {
+ return sts_net__set_error("Cannot bind on closed socket");
+ }
+ if (socket->server) {
+ return sts_net__set_error("Cannot bind on server socket");
+ }
+
+ if (share_port) {
+ int yes = 1;
+ setsockopt(socket->fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
+ }
+
+ if (sts_net__resolvehost(&sin, bind_address, port)) {
+ return sts_net__set_error("Cannot resolve bind address");
+ }
+
+ if (bind(socket->fd, (struct sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) {
+ return sts_net__set_error("Could not bind to port");
+ }
+
+ return 0;
+}
+
+
+int sts_net_udp_recv_from(sts_net_socket_t* socket, void* data, int length, unsigned char* ip, int* port) {
+ struct sockaddr_in sin;
+ socklen_t fromlen = sizeof(sin);
+ int result;
+
+ if (socket->server) {
+ return sts_net__set_error("Cannot receive on server socket");
+ }
+ if (socket->fd == STS_INVALID_SOCKET) {
+ return sts_net__set_error("Cannot receive on closed socket");
+ }
+ socket->ready = 0;
+ result = recvfrom(socket->fd, (char*)data, length, 0, (struct sockaddr*)&sin, &fromlen);
+ if (result < 0) {
+ return sts_net__set_error("Cannot receive data");
+ }
+
+ if (ip) {
+ sts__memcpy(ip, &sin.sin_addr, 4);
+ }
+ if (port) {
+ *port = ntohs(sin.sin_port);
+ }
+
+ return result;
+}
+
+int sts_net_udp_send(sts_net_socket_t* socket, const char* host, int port, const void* data, int length)
+{
+ struct sockaddr_in sin;
+ #ifdef _WIN32
+ WSABUF bufs[] = { { (ULONG)length, (CHAR*)data } };
+ DWORD sent;
+ #else
+ struct msghdr mhdr;
+ struct iovec iovs[] = { { (void*)data, (size_t)length } };
+ #endif // _WIN32
+
+ if (socket->fd == STS_INVALID_SOCKET) {
+ return sts_net__set_error("Cannot send on closed socket");
+ }
+ if (socket->server) {
+ return sts_net__set_error("Cannot send on server socket");
+ }
+ if (sts_net__resolvehost(&sin, host, port)) {
+ return sts_net__set_error("Cannot resolve hostname");
+ }
+
+ #ifdef _WIN32
+ if (WSASendTo((SOCKET)socket->fd, bufs, (DWORD)1, &sent, 0, (struct sockaddr*)&sin, sizeof(sin), NULL, NULL) == SOCKET_ERROR) {
+ #else
+ mhdr.msg_name = & sin;
+ mhdr.msg_namelen = sizeof (struct sockaddr_in);
+ mhdr.msg_iov = iovs;
+ mhdr.msg_iovlen = (int)1;
+ if ((int)sendmsg(socket->fd, &mhdr, STS_SEND_FLAG) == -1) {
+ #endif // _WIN32
+ return sts_net__set_error("Cannot send data");
+ }
+
+ return 0;
+}
+
#ifndef STS_NET_NO_ENUMERATEINTERFACES
int sts_net_enumerate_interfaces(sts_net_interfaceinfo_t* table, int tablesize, int want_ipv4, int want_ipv6) {
void* sinaddr;
@@ -637,7 +815,7 @@ int sts_net_enumerate_interfaces(sts_net_interfaceinfo_t* table, int tablesize,
for (ifa = ifAddrStruct; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr) {
addr = ifa->ifa_addr;
-#endif
+#endif // _WIN32
family = addr->sa_family;
if (family == AF_INET) { if (!want_ipv4) continue; }
else if (family == AF_INET6) { if (!want_ipv6) continue; }
@@ -653,7 +831,7 @@ int sts_net_enumerate_interfaces(sts_net_interfaceinfo_t* table, int tablesize,
ifnamelen = strlen(ifa->ifa_name);
if (ifnamelen >= (int)sizeof(table->interface_name)) ifnamelen = sizeof(table->interface_name) - 1;
sts__memcpy(table->interface_name, ifa->ifa_name, ifnamelen);
-#endif
+#endif // _WIN32
table->interface_name[ifnamelen] = '\0';
inet_ntop(family, sinaddr, table->address, sizeof(table->address));
tablesize--;
@@ -664,7 +842,7 @@ int sts_net_enumerate_interfaces(sts_net_interfaceinfo_t* table, int tablesize,
HeapFree(GetProcessHeap(), 0, adapter_addresses);
#else
if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
-#endif
+#endif // _WIN32
return totalcount;
}
#endif // STS_NET_NO_ENUMERATEINTERFACES
@@ -737,7 +915,7 @@ int main(int argc, char *argv[]) {
sts_net_init();
sts_net_init_socket_set(&set);
server = &set.sockets[0];
- if (sts_net_listen(server, 4040, NULL) < 0) panic(sts_net_get_last_error());
+ if (sts_net_listen(server, 4040, NULL, 0) < 0) panic(sts_net_get_last_error());
while(1) {
puts("Waiting...");
@@ -747,7 +925,7 @@ int main(int argc, char *argv[]) {
client = sts_net_get_available_socket_from_set(&set);
if (client) {
if (sts_net_accept_socket(server, client) < 0) panic(sts_net_get_last_error());
- sts_net_gethostname(client, buffer, sizeof(buffer), 1, NULL);
+ sts_net_gethostname(client, buffer, sizeof(buffer), 1, NULL, 0);
printf("Client connected '%s'!\n", buffer);
}
else {