From bcde4b6fa4492beda3b590466872fbdeb33f3973 Mon Sep 17 00:00:00 2001
From: Kevin Lu <[EMAIL REDACTED]>
Date: Thu, 9 Mar 2023 06:12:13 +1300
Subject: [PATCH] Allow binding a TCP server to a specific interface (#74)
---
SDL_net.h | 41 +++++++++++++++++++++++++++++++++++++++++
SDLnetTCP.c | 50 ++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/SDL_net.h b/SDL_net.h
index ab6fcb6..983e290 100644
--- a/SDL_net.h
+++ b/SDL_net.h
@@ -207,6 +207,45 @@ extern DECLSPEC int SDLCALL SDLNet_GetLocalAddresses(IPaddress *addresses, int m
typedef struct _TCPsocket *TCPsocket;
+/**
+ * Open a server TCP network socket.
+ *
+ * If `ip->host` is INADDR_NONE or INADDR_ANY, the socket is bound to
+ * all interfaces, otherwise it is bound to the specified interface.
+ * The address passed in should already be swapped to network byte order
+ * (addresses returned from SDLNet_ResolveHost() are already in the
+ * correct form).
+ *
+ * \param ip The address to host a server on.
+ * \returns the newly created socket, or NULL if there was an error.
+ *
+ * \since This function is available since SDL_net 2.4.0.
+ *
+ * \sa SDLNet_TCP_Close
+ * \sa SDLNet_TCP_OpenClient
+ * \sa SDLNet_TCP_Open
+ */
+extern DECLSPEC TCPsocket SDLCALL SDLNet_TCP_OpenServer(IPaddress *ip);
+
+/**
+ * Open a client TCP network socket.
+ *
+ * Attempt a TCP connection to the remote host and port.
+ * The address passed in should already be swapped to network byte order
+ * (addresses returned from SDLNet_ResolveHost() are already in the
+ * correct form).
+ *
+ * \param ip The address to open a connection to.
+ * \returns the newly created socket, or NULL if there was an error.
+ *
+ * \since This function is available since SDL_net 2.4.0.
+ *
+ * \sa SDLNet_TCP_Close
+ * \sa SDLNet_TCP_OpenServer
+ * \sa SDLNet_TCP_Open
+ */
+extern DECLSPEC TCPsocket SDLCALL SDLNet_TCP_OpenClient(IPaddress *ip);
+
/**
* Open a TCP network socket.
*
@@ -222,6 +261,8 @@ typedef struct _TCPsocket *TCPsocket;
* \since This function is available since SDL_net 2.0.0.
*
* \sa SDLNet_TCP_Close
+ * \sa SDLNet_TCP_OpenServer
+ * \sa SDLNet_TCP_OpenClient
*/
extern DECLSPEC TCPsocket SDLCALL SDLNet_TCP_Open(IPaddress *ip);
diff --git a/SDLnetTCP.c b/SDLnetTCP.c
index 3e4802c..1907ccb 100644
--- a/SDLnetTCP.c
+++ b/SDLnetTCP.c
@@ -36,12 +36,13 @@ struct _TCPsocket {
int sflag;
};
-/* Open a TCP network socket
- If 'remote' is NULL, this creates a local server socket on the given port,
- otherwise a TCP connection to the remote host and port is attempted.
+/* Open a TCP network socket.
+ If `openAsClient` is nonzero, this creates a local server socket
+ on the given port, otherwise a TCP connection to the remote host
+ and port is attempted.
The newly created socket is returned, or NULL if there was an error.
*/
-TCPsocket SDLNet_TCP_Open(IPaddress *ip)
+static TCPsocket SDLNet_TCP_OpenInternal(IPaddress *ip, int openAsClient)
{
TCPsocket sock;
struct sockaddr_in sock_addr;
@@ -59,9 +60,8 @@ TCPsocket SDLNet_TCP_Open(IPaddress *ip)
SDLNet_SetError("Couldn't create socket");
goto error_return;
}
-
- /* Connect to remote, or bind locally, as appropriate */
- if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) ) {
+
+ if (openAsClient) {
/* ######### Connecting to remote */
SDL_memset(&sock_addr, 0, sizeof(sock_addr));
@@ -81,7 +81,8 @@ TCPsocket SDLNet_TCP_Open(IPaddress *ip)
/* ########## Binding locally */
SDL_memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
- sock_addr.sin_addr.s_addr = INADDR_ANY;
+ sock_addr.sin_addr.s_addr = (ip->host == INADDR_NONE) ?
+ INADDR_ANY : ip->host;
sock_addr.sin_port = ip->port;
/*
@@ -156,6 +157,39 @@ TCPsocket SDLNet_TCP_Open(IPaddress *ip)
return(NULL);
}
+/* Open a server TCP network socket.
+ If `ip->host` is INADDR_NONE or INADDR_ANY, the socket is bound to
+ all interfaces, otherwise it is bound to the specified interface.
+ The newly created socket is returned, or NULL if there was an error.
+*/
+TCPsocket SDLNet_TCP_OpenServer(IPaddress *ip)
+{
+ return SDLNet_TCP_OpenInternal(ip, 0);
+}
+
+/* Open a client TCP network socket.
+ Attempt a TCP connection to the remote host and port.
+ The newly created socket is returned, or NULL if there was an error.
+*/
+TCPsocket SDLNet_TCP_OpenClient(IPaddress *ip)
+{
+ return SDLNet_TCP_OpenInternal(ip, 1);
+}
+
+/* Open a client or server TCP network socket.
+ If `ip->host` is INADDR_NONE or INADDR_ANY, this creates a local server
+ socket on the given port, otherwise a TCP connection to the remote host
+ and port is attempted.
+ The newly created socket is returned, or NULL if there was an error.
+*/
+TCPsocket SDLNet_TCP_Open(IPaddress *ip)
+{
+ return SDLNet_TCP_OpenInternal(
+ ip,
+ (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY)
+ );
+}
+
/* Accept an incoming connection on the given server socket.
The newly created socket is returned, or NULL if there was an error.
*/