1 
2 //          Copyright 2018 - 2021 Michael D. Parker
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          http://www.boost.org/LICENSE_1_0.txt)
6 
7 module bindbc.sdl.net;
8 
9 import bindbc.sdl.config;
10 static if(bindSDLNet):
11 
12 import bindbc.sdl.config;
13 import bindbc.sdl.bind.sdlversion : SDL_version;
14 
15 enum SDLNetSupport {
16     noLibrary,
17     badLibrary,
18     sdlNet200 = 200,
19     sdlNet201 = 201,
20 }
21 
22 enum ubyte SDL_NET_MAJOR_VERSION = 2;
23 enum ubyte SDL_NET_MINOR_VERSION = 0;
24 
25 version(SDL_Net_201) {
26     enum sdlNetSupport = SDLNetSupport.sdlNet201;
27     enum SDL_NET_PATCHLEVEL = 1;
28 }
29 else {
30     enum sdlNetSupport = SDLNetSupport.sdlNet200;
31     enum SDL_NET_PATCHLEVEL = 0;
32 }
33 
34 alias SDLNet_Version = SDL_version;
35 
36 @nogc nothrow void SDL_NET_VERSION(SDL_version* X) {
37     X.major = SDL_NET_MAJOR_VERSION;
38     X.minor = SDL_NET_MINOR_VERSION;
39     X.patch = SDL_NET_PATCHLEVEL;
40 }
41 
42 struct IPaddress {
43     uint host;
44     ubyte port;
45 }
46 
47 enum {
48     INADDR_ANY = 0x00000000,
49     INADDR_NONE = 0xFFFFFFFF,
50     INADDR_LOOPBACK = 0x7f000001,
51     INADDR_BROADCAST = 0xFFFFFFFF,
52 }
53 
54 alias TCPsocket = void*;
55 
56 enum SDLNET_MAX_UDPCHANNELS = 32;
57 enum SDLNET_MAX_UDPADRESSES = 4;
58 
59 alias UDPsocket = void*;
60 
61 struct UDPpacket {
62     int channel;
63     ubyte* data;
64     int len;
65     int maxlen;
66     int status;
67     IPaddress address;
68 }
69 
70 struct _SDLNet_SocketSet;
71 alias _SDLNet_SocketSet* SDLNet_SocketSet;
72 
73 struct _SDLNet_GenericSocket {
74     int ready;
75 }
76 alias SDLNet_GenericSocket = _SDLNet_GenericSocket*;
77 
78 @nogc nothrow {
79     int SDLNet_TCP_AddSocket(SDLNet_SocketSet set,void* sock) {
80         return SDLNet_AddSocket(set,cast(SDLNet_GenericSocket)sock);
81     }
82     alias SDLNet_UDP_AddSocket = SDLNet_TCP_AddSocket;
83 
84     int SDLNet_TCP_DelSocket(SDLNet_SocketSet set,void* sock) {
85         return SDLNet_DelSocket(set,cast(SDLNet_GenericSocket)sock);
86     }
87     alias SDLNet_UDP_DelSocket = SDLNet_TCP_DelSocket;
88 
89     bool SDLNet_SocketReady(void* sock) {
90         return sock && (cast(SDLNet_GenericSocket)sock).ready != 0;
91     }
92 }
93 
94 static if(staticBinding) {
95     extern(C) @nogc nothrow {
96         const(SDLNet_Version)* SDLNet_Linked_Version();
97         int SDLNet_Init();
98         void SDLNet_Quit();
99         int SDLNet_ResolveHost(IPaddress* address, const(char)* host, ushort port);
100         const(char)* SDLNet_ResolveIP(const(IPaddress)* ip);
101         int SDLNet_GetLocalAddresses(IPaddress* addresses, int maxcount);
102         TCPsocket SDLNet_TCP_Open(IPaddress* ip);
103         TCPsocket SDLNet_TCP_Accept(TCPsocket server);
104         IPaddress* SDLNet_TCP_GetPeerAddress(TCPsocket sock);
105         int SDLNet_TCP_Send(TCPsocket sock, const(void)* data, int len);
106         int SDLNet_TCP_Recv(TCPsocket sock, void* data, int len);
107         void SDLNet_TCP_Close(TCPsocket sock);
108         UDPpacket* SDLNet_AllocPacket(int size);
109         int SDLNet_ResizePacket(UDPpacket* packet, int newsize);
110         void SDLNet_FreePacket(UDPpacket* packet);
111         UDPpacket** SDLNet_AllocPacketV(int howmany, int size);
112         void SDLNet_FreePacketV(UDPpacket** packetV);
113         UDPsocket SDLNet_UDP_Open(ushort port);
114         void SDLNet_UDP_SetPacketLoss(UDPsocket sock, int percent);
115         int SDLNet_UDP_Bind(UDPsocket sock, int channel, const(IPaddress)* address);
116         void SDLNet_UDP_Unbind(UDPsocket sock, int channel);
117         IPaddress* SDLNet_UDP_GetPeerAddress(UDPsocket sock, int channel);
118         int SDLNet_UDP_SendV(UDPsocket sock, UDPpacket** packets, int npackets);
119         int SDLNet_UDP_Send(UDPsocket sock, int channel, UDPpacket* packet);
120         int SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket** packets);
121         int SDLNet_UDP_Recv(UDPsocket sock, UDPpacket* packet);
122         void SDLNet_UDP_Close(UDPsocket sock);
123         SDLNet_SocketSet SDLNet_AllocSocketSet(int maxsockets);
124         int SDLNet_AddSocket(SDLNet_SocketSet set, SDLNet_GenericSocket sock);
125         int SDLNet_DelSocket(SDLNet_SocketSet set, SDLNet_GenericSocket sock);
126         int SDLNet_CheckSockets(SDLNet_SocketSet set, uint timeout);
127         void SDLNet_FreeSocketSet(SDLNet_SocketSet set);
128         void SDLNet_SetError(const(char)* fmt, ...);
129         const(char)* SDLNet_GetError();
130     }
131 }
132 else {
133     import bindbc.loader;
134 
135     extern(C) @nogc nothrow {
136         alias pSDLNet_Linked_Version = const(SDLNet_Version)* function();
137         alias pSDLNet_Init = int function();
138         alias pSDLNet_Quit = void function();
139         alias pSDLNet_ResolveHost = int function(IPaddress* address, const(char)* host, ushort port);
140         alias pSDLNet_ResolveIP = const(char)* function(const(IPaddress)* ip);
141         alias pSDLNet_GetLocalAddresses = int function(IPaddress* addresses, int maxcount);
142         alias pSDLNet_TCP_Open = TCPsocket function(IPaddress* ip);
143         alias pSDLNet_TCP_Accept = TCPsocket function(TCPsocket server);
144         alias pSDLNet_TCP_GetPeerAddress = IPaddress* function(TCPsocket sock);
145         alias pSDLNet_TCP_Send = int function(TCPsocket sock, const(void)* data, int len);
146         alias pSDLNet_TCP_Recv = int function(TCPsocket sock, void* data, int len);
147         alias pSDLNet_TCP_Close = void function(TCPsocket sock);
148         alias pSDLNet_AllocPacket = UDPpacket* function(int size);
149         alias pSDLNet_ResizePacket = int function(UDPpacket* packet, int newsize);
150         alias pSDLNet_FreePacket = void function(UDPpacket* packet);
151         alias pSDLNet_AllocPacketV = UDPpacket** function(int howmany, int size);
152         alias pSDLNet_FreePacketV = void function(UDPpacket** packetV);
153         alias pSDLNet_UDP_Open = UDPsocket function(ushort port);
154         alias pSDLNet_UDP_SetPacketLoss = void function(UDPsocket sock, int percent);
155         alias pSDLNet_UDP_Bind = int function(UDPsocket sock, int channel, const(IPaddress)* address);
156         alias pSDLNet_UDP_Unbind = void function(UDPsocket sock, int channel);
157         alias pSDLNet_UDP_GetPeerAddress = IPaddress* function(UDPsocket sock, int channel);
158         alias pSDLNet_UDP_SendV = int function(UDPsocket sock, UDPpacket** packets, int npackets);
159         alias pSDLNet_UDP_Send = int function(UDPsocket sock, int channel, UDPpacket* packet);
160         alias pSDLNet_UDP_RecvV = int function(UDPsocket sock, UDPpacket** packets);
161         alias pSDLNet_UDP_Recv = int function(UDPsocket sock, UDPpacket* packet);
162         alias pSDLNet_UDP_Close = void function(UDPsocket sock);
163         alias pSDLNet_AllocSocketSet = SDLNet_SocketSet function(int maxsockets);
164         alias pSDLNet_AddSocket = int function(SDLNet_SocketSet set, SDLNet_GenericSocket sock);
165         alias pSDLNet_DelSocket = int function(SDLNet_SocketSet set, SDLNet_GenericSocket sock);
166         alias pSDLNet_CheckSockets = int function(SDLNet_SocketSet set, uint timeout);
167         alias pSDLNet_FreeSocketSet = void function(SDLNet_SocketSet set);
168         alias pSDLNet_SetError = void function(const(char)* fmt, ...);
169         alias pSDLNet_GetError = const(char)* function();
170     }
171 
172     __gshared {
173         pSDLNet_Linked_Version SDLNet_Linked_Version;
174         pSDLNet_Init SDLNet_Init;
175         pSDLNet_Quit SDLNet_Quit;
176         pSDLNet_ResolveHost SDLNet_ResolveHost;
177         pSDLNet_ResolveIP SDLNet_ResolveIP;
178         pSDLNet_GetLocalAddresses SDLNet_GetLocalAddresses;
179         pSDLNet_TCP_Open SDLNet_TCP_Open;
180         pSDLNet_TCP_Accept SDLNet_TCP_Accept;
181         pSDLNet_TCP_GetPeerAddress SDLNet_TCP_GetPeerAddress;
182         pSDLNet_TCP_Send SDLNet_TCP_Send;
183         pSDLNet_TCP_Recv SDLNet_TCP_Recv;
184         pSDLNet_TCP_Close SDLNet_TCP_Close;
185         pSDLNet_AllocPacket SDLNet_AllocPacket;
186         pSDLNet_ResizePacket SDLNet_ResizePacket;
187         pSDLNet_FreePacket SDLNet_FreePacket;
188         pSDLNet_AllocPacketV SDLNet_AllocPacketV;
189         pSDLNet_FreePacketV SDLNet_FreePacketV;
190         pSDLNet_UDP_Open SDLNet_UDP_Open;
191         pSDLNet_UDP_SetPacketLoss SDLNet_UDP_SetPacketLoss;
192         pSDLNet_UDP_Bind SDLNet_UDP_Bind;
193         pSDLNet_UDP_Unbind SDLNet_UDP_Unbind;
194         pSDLNet_UDP_GetPeerAddress SDLNet_UDP_GetPeerAddress;
195         pSDLNet_UDP_SendV SDLNet_UDP_SendV;
196         pSDLNet_UDP_Send SDLNet_UDP_Send;
197         pSDLNet_UDP_RecvV SDLNet_UDP_RecvV;
198         pSDLNet_UDP_Recv SDLNet_UDP_Recv;
199         pSDLNet_UDP_Close SDLNet_UDP_Close;
200         pSDLNet_AllocSocketSet SDLNet_AllocSocketSet;
201         pSDLNet_AddSocket SDLNet_AddSocket;
202         pSDLNet_DelSocket SDLNet_DelSocket;
203         pSDLNet_CheckSockets SDLNet_CheckSockets;
204         pSDLNet_FreeSocketSet SDLNet_FreeSocketSet;
205         pSDLNet_SetError SDLNet_SetError;
206         pSDLNet_GetError SDLNet_GetError;
207     }
208 
209     private {
210         SharedLib lib;
211         SDLNetSupport loadedVersion;
212     }
213 
214 @nogc nothrow:
215     void unloadSDLNet()
216     {
217         if(lib != invalidHandle) {
218             lib.unload();
219         }
220     }
221 
222     SDLNetSupport loadedSDLNetVersion() { return loadedVersion; }
223 
224     bool isSDLNetLoaded()
225     {
226         return  lib != invalidHandle;
227     }
228 
229 
230     SDLNetSupport loadSDLNet()
231     {
232         version(Windows) {
233             const(char)[][1] libNames = ["SDL2_net.dll"];
234         }
235         else version(OSX) {
236             const(char)[][6] libNames = [
237                 "libSDL2_net.dylib",
238                 "/usr/local/lib/libSDL2_net.dylib",
239                 "../Frameworks/SDL2_net.framework/SDL2_net",
240                 "/Library/Frameworks/SDL2_net.framework/SDL2_net",
241                 "/System/Library/Frameworks/SDL2_net.framework/SDL2_net",
242                 "/opt/local/lib/libSDL2_net.dylib"
243             ];
244         }
245         else version(Posix) {
246             const(char)[][6] libNames = [
247                 "libSDL2_net.so",
248                 "/usr/local/lib/libSDL2_net.so",
249                 "libSDL2-2.0_net.so",
250                 "/usr/local/lib/libSDL2-2.0_net.so",
251                 "libSDL2-2.0_net.so.0",
252                 "/usr/local/lib/libSDL2-2.0_net.so.0"
253             ];
254         }
255         else static assert(0, "bindbc-sdl is not yet supported on this platform.");
256 
257         SDLNetSupport ret;
258         foreach(name; libNames) {
259             ret = loadSDLNet(name.ptr);
260             if(ret != SDLNetSupport.noLibrary) break;
261         }
262         return ret;
263     }
264 
265     SDLNetSupport loadSDLNet(const(char)* libName)
266     {
267         lib = load(libName);
268         if(lib == invalidHandle) {
269             return SDLNetSupport.noLibrary;
270         }
271 
272         auto errCount = errorCount();
273         loadedVersion = SDLNetSupport.badLibrary;
274 
275         lib.bindSymbol(cast(void**)&SDLNet_Linked_Version,"SDLNet_Linked_Version");
276         lib.bindSymbol(cast(void**)&SDLNet_Init,"SDLNet_Init");
277         lib.bindSymbol(cast(void**)&SDLNet_Quit,"SDLNet_Quit");
278         lib.bindSymbol(cast(void**)&SDLNet_ResolveHost,"SDLNet_ResolveHost");
279         lib.bindSymbol(cast(void**)&SDLNet_ResolveIP,"SDLNet_ResolveIP");
280         lib.bindSymbol(cast(void**)&SDLNet_GetLocalAddresses,"SDLNet_GetLocalAddresses");
281         lib.bindSymbol(cast(void**)&SDLNet_TCP_Open,"SDLNet_TCP_Open");
282         lib.bindSymbol(cast(void**)&SDLNet_TCP_Accept,"SDLNet_TCP_Accept");
283         lib.bindSymbol(cast(void**)&SDLNet_TCP_GetPeerAddress,"SDLNet_TCP_GetPeerAddress");
284         lib.bindSymbol(cast(void**)&SDLNet_TCP_Send,"SDLNet_TCP_Send");
285         lib.bindSymbol(cast(void**)&SDLNet_TCP_Recv,"SDLNet_TCP_Recv");
286         lib.bindSymbol(cast(void**)&SDLNet_TCP_Close,"SDLNet_TCP_Close");
287         lib.bindSymbol(cast(void**)&SDLNet_AllocPacket,"SDLNet_AllocPacket");
288         lib.bindSymbol(cast(void**)&SDLNet_ResizePacket,"SDLNet_ResizePacket");
289         lib.bindSymbol(cast(void**)&SDLNet_FreePacket,"SDLNet_FreePacket");
290         lib.bindSymbol(cast(void**)&SDLNet_AllocPacketV,"SDLNet_AllocPacketV");
291         lib.bindSymbol(cast(void**)&SDLNet_FreePacketV,"SDLNet_FreePacketV");
292         lib.bindSymbol(cast(void**)&SDLNet_UDP_Open,"SDLNet_UDP_Open");
293         lib.bindSymbol(cast(void**)&SDLNet_UDP_SetPacketLoss,"SDLNet_UDP_SetPacketLoss");
294         lib.bindSymbol(cast(void**)&SDLNet_UDP_Bind,"SDLNet_UDP_Bind");
295         lib.bindSymbol(cast(void**)&SDLNet_UDP_Unbind,"SDLNet_UDP_Unbind");
296         lib.bindSymbol(cast(void**)&SDLNet_UDP_GetPeerAddress,"SDLNet_UDP_GetPeerAddress");
297         lib.bindSymbol(cast(void**)&SDLNet_UDP_SendV,"SDLNet_UDP_SendV");
298         lib.bindSymbol(cast(void**)&SDLNet_UDP_Send,"SDLNet_UDP_Send");
299         lib.bindSymbol(cast(void**)&SDLNet_UDP_RecvV,"SDLNet_UDP_RecvV");
300         lib.bindSymbol(cast(void**)&SDLNet_UDP_Recv,"SDLNet_UDP_Recv");
301         lib.bindSymbol(cast(void**)&SDLNet_UDP_Close,"SDLNet_UDP_Close");
302         lib.bindSymbol(cast(void**)&SDLNet_AllocSocketSet,"SDLNet_AllocSocketSet");
303         lib.bindSymbol(cast(void**)&SDLNet_AddSocket,"SDLNet_AddSocket");
304         lib.bindSymbol(cast(void**)&SDLNet_DelSocket,"SDLNet_DelSocket");
305         lib.bindSymbol(cast(void**)&SDLNet_CheckSockets,"SDLNet_CheckSockets");
306         lib.bindSymbol(cast(void**)&SDLNet_FreeSocketSet,"SDLNet_FreeSocketSet");
307         lib.bindSymbol(cast(void**)&SDLNet_SetError,"SDLNet_SetError");
308         lib.bindSymbol(cast(void**)&SDLNet_GetError,"SDLNet_GetError");
309 
310         if(errorCount() == errCount) loadedVersion = sdlNetSupport;
311 
312         return loadedVersion;
313     }
314 }