1 
2 //          Copyright Michael D. Parker 2018.
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        bindbc.sdl.bind.sdlstdinc;
14 import bindbc.sdl.bind.sdlversion : SDL_version;
15 
16 enum SDLNetSupport {
17     noLibrary,
18     badLibrary,
19     sdlNet200 = 200,
20     sdlNet201 = 201,
21 }
22 
23 enum ubyte SDL_NET_MAJOR_VERSION = 2;
24 enum ubyte SDL_NET_MINOR_VERSION = 0;
25 
26 version(SDL_Net_201) {
27     enum sdlNetSupport = SDLNetSupport.sdlNet201;
28     enum SDL_NET_PATCHLEVEL = 1;
29 }
30 else {
31     enum sdlNetSupport = SDLNetSupport.sdlNet200;
32     enum SDL_NET_PATCHLEVEL = 0;
33 }
34 
35 alias SDLNet_Version = SDL_version;
36 
37 @nogc nothrow void SDL_NET_VERSION(SDL_version* X) {
38     X.major = SDL_NET_MAJOR_VERSION;
39     X.minor = SDL_NET_MINOR_VERSION;
40     X.patch = SDL_NET_PATCHLEVEL;
41 }
42 
43 struct IPaddress {
44     Uint32 host;
45     Uint16 port;
46 }
47 
48 enum {
49     INADDR_ANY = 0x00000000,
50     INADDR_NONE = 0xFFFFFFFF,
51     INADDR_LOOPBACK = 0x7f000001,
52     INADDR_BROADCAST = 0xFFFFFFFF,
53 }
54 
55 alias TCPsocket = void*;
56 
57 enum SDLNET_MAX_UDPCHANNELS = 32;
58 enum SDLNET_MAX_UDPADRESSES = 4;
59 
60 alias UDPsocket = void*;
61 
62 struct UDPpacket {
63     int channel;
64     Uint8* data;
65     int len;
66     int maxlen;
67     int status;
68     IPaddress address;
69 }
70 
71 struct _SDLNet_SocketSet;
72 alias _SDLNet_SocketSet* SDLNet_SocketSet;
73 
74 struct _SDLNet_GenericSocket {
75     int ready;
76 }
77 alias SDLNet_GenericSocket = _SDLNet_GenericSocket*;
78 
79 @nogc nothrow {
80     int SDLNet_TCP_AddSocket(SDLNet_SocketSet set,void* sock) {
81         return SDLNet_AddSocket(set,cast(SDLNet_GenericSocket)sock);
82     }
83     alias SDLNet_UDP_AddSocket = SDLNet_TCP_AddSocket;
84 
85     int SDLNet_TCP_DelSocket(SDLNet_SocketSet set,void* sock) {
86         return SDLNet_DelSocket(set,cast(SDLNet_GenericSocket)sock);
87     }
88     alias SDLNet_UDP_DelSocket = SDLNet_TCP_DelSocket;
89 
90     bool SDLNet_SocketReady(void* sock) {
91         return sock && (cast(SDLNet_GenericSocket)sock).ready != 0;
92     }
93 }
94 
95 static if(staticBinding) {
96     extern(C) @nogc nothrow {
97         const(SDLNet_Version)* SDLNet_Linked_Version();
98         int SDLNet_Init();
99         void SDLNet_Quit();
100         int SDLNet_ResolveHost(IPaddress*,const(char)*,Uint16);
101         const(char)* SDLNet_ResolveIP(const(IPaddress)*);
102         int SDLNet_GetLocalAddresses(IPaddress*,int);
103         TCPsocket SDLNet_TCP_Open(IPaddress*);
104         TCPsocket SDLNet_TCP_Accept(TCPsocket);
105         IPaddress* SDLNet_TCP_GetPeerAddress(TCPsocket);
106         int SDLNet_TCP_Send(TCPsocket,const(void)*,int);
107         int SDLNet_TCP_Recv(TCPsocket,void*,int);
108         void SDLNet_TCP_Close(TCPsocket);
109         UDPpacket* SDLNet_AllocPacket(int);
110         int SDLNet_ResizePacket(UDPpacket*,int);
111         void SDLNet_FreePacket(UDPpacket*);
112         UDPpacket** SDLNet_AllocPacketV(int,int);
113         void SDLNet_FreePacketV(UDPpacket**);
114         UDPsocket SDLNet_UDP_Open(Uint16);
115         void SDLNet_UDP_SetPacketLoss(UDPsocket,int);
116         int SDLNet_UDP_Bind(UDPsocket,int,const(IPaddress)*);
117         void SDLNet_UDP_Unbind(UDPsocket,int);
118         IPaddress* SDLNet_UDP_GetPeerAddress(UDPsocket,int);
119         int SDLNet_UDP_SendV(UDPsocket,UDPpacket**,int);
120         int SDLNet_UDP_Send(UDPsocket,int,UDPpacket*);
121         int SDLNet_UDP_RecvV(UDPsocket,UDPpacket**);
122         int SDLNet_UDP_Recv(UDPsocket,UDPpacket*);
123         void SDLNet_UDP_Close(UDPsocket);
124         SDLNet_SocketSet SDLNet_AllocSocketSet(int);
125         int SDLNet_AddSocket(SDLNet_SocketSet,SDLNet_GenericSocket);
126         int SDLNet_DelSocket(SDLNet_SocketSet,SDLNet_GenericSocket);
127         int SDLNet_CheckSockets(SDLNet_SocketSet,Uint32);
128         void SDLNet_FreeSocketSet(SDLNet_SocketSet);
129         void SDLNet_SetError(const(char)* fmt,...);
130         const(char)* SDLNet_GetError();
131     }
132 }
133 else {
134     import bindbc.loader;
135 
136     extern(C) @nogc nothrow {
137         alias pSDLNet_Linked_Version = const(SDLNet_Version)* function();
138         alias pSDLNet_Init = int function();
139         alias pSDLNet_Quit = void function();
140         alias pSDLNet_ResolveHost = int function(IPaddress*,const(char)*,Uint16);
141         alias pSDLNet_ResolveIP = const(char)* function(const(IPaddress)*);
142         alias pSDLNet_GetLocalAddresses = int function(IPaddress*,int);
143         alias pSDLNet_TCP_Open = TCPsocket function(IPaddress*);
144         alias pSDLNet_TCP_Accept = TCPsocket function(TCPsocket);
145         alias pSDLNet_TCP_GetPeerAddress = IPaddress* function(TCPsocket);
146         alias pSDLNet_TCP_Send = int function(TCPsocket,const(void)*,int);
147         alias pSDLNet_TCP_Recv = int function(TCPsocket,void*,int);
148         alias pSDLNet_TCP_Close = void function(TCPsocket);
149         alias pSDLNet_AllocPacket = UDPpacket* function(int);
150         alias pSDLNet_ResizePacket = int function(UDPpacket*,int);
151         alias pSDLNet_FreePacket = void function(UDPpacket*);
152         alias pSDLNet_AllocPacketV = UDPpacket** function(int,int);
153         alias pSDLNet_FreePacketV = void function(UDPpacket**);
154         alias pSDLNet_UDP_Open = UDPsocket function(Uint16);
155         alias pSDLNet_UDP_SetPacketLoss = void function(UDPsocket,int);
156         alias pSDLNet_UDP_Bind = int function(UDPsocket,int,const(IPaddress)*);
157         alias pSDLNet_UDP_Unbind = void function(UDPsocket,int);
158         alias pSDLNet_UDP_GetPeerAddress = IPaddress* function(UDPsocket,int);
159         alias pSDLNet_UDP_SendV = int function(UDPsocket,UDPpacket**,int);
160         alias pSDLNet_UDP_Send = int function(UDPsocket,int,UDPpacket*);
161         alias pSDLNet_UDP_RecvV = int function(UDPsocket,UDPpacket**);
162         alias pSDLNet_UDP_Recv = int function(UDPsocket,UDPpacket*);
163         alias pSDLNet_UDP_Close = void function(UDPsocket);
164         alias pSDLNet_AllocSocketSet = SDLNet_SocketSet function(int);
165         alias pSDLNet_AddSocket = int function(SDLNet_SocketSet,SDLNet_GenericSocket);
166         alias pSDLNet_DelSocket = int function(SDLNet_SocketSet,SDLNet_GenericSocket);
167         alias pSDLNet_CheckSockets = int function(SDLNet_SocketSet,Uint32);
168         alias pSDLNet_FreeSocketSet = void function(SDLNet_SocketSet);
169         alias pSDLNet_SetError = void function(const(char)* fmt,...);
170         alias pSDLNet_GetError = const(char)* function();
171     }
172 
173     __gshared {
174         pSDLNet_Linked_Version SDLNet_Linked_Version;
175         pSDLNet_Init SDLNet_Init;
176         pSDLNet_Quit SDLNet_Quit;
177         pSDLNet_ResolveHost SDLNet_ResolveHost;
178         pSDLNet_ResolveIP SDLNet_ResolveIP;
179         pSDLNet_GetLocalAddresses SDLNet_GetLocalAddresses;
180         pSDLNet_TCP_Open SDLNet_TCP_Open;
181         pSDLNet_TCP_Accept SDLNet_TCP_Accept;
182         pSDLNet_TCP_GetPeerAddress SDLNet_TCP_GetPeerAddress;
183         pSDLNet_TCP_Send SDLNet_TCP_Send;
184         pSDLNet_TCP_Recv SDLNet_TCP_Recv;
185         pSDLNet_TCP_Close SDLNet_TCP_Close;
186         pSDLNet_AllocPacket SDLNet_AllocPacket;
187         pSDLNet_ResizePacket SDLNet_ResizePacket;
188         pSDLNet_FreePacket SDLNet_FreePacket;
189         pSDLNet_AllocPacketV SDLNet_AllocPacketV;
190         pSDLNet_FreePacketV SDLNet_FreePacketV;
191         pSDLNet_UDP_Open SDLNet_UDP_Open;
192         pSDLNet_UDP_SetPacketLoss SDLNet_UDP_SetPacketLoss;
193         pSDLNet_UDP_Bind SDLNet_UDP_Bind;
194         pSDLNet_UDP_Unbind SDLNet_UDP_Unbind;
195         pSDLNet_UDP_GetPeerAddress SDLNet_UDP_GetPeerAddress;
196         pSDLNet_UDP_SendV SDLNet_UDP_SendV;
197         pSDLNet_UDP_Send SDLNet_UDP_Send;
198         pSDLNet_UDP_RecvV SDLNet_UDP_RecvV;
199         pSDLNet_UDP_Recv SDLNet_UDP_Recv;
200         pSDLNet_UDP_Close SDLNet_UDP_Close;
201         pSDLNet_AllocSocketSet SDLNet_AllocSocketSet;
202         pSDLNet_AddSocket SDLNet_AddSocket;
203         pSDLNet_DelSocket SDLNet_DelSocket;
204         pSDLNet_CheckSockets SDLNet_CheckSockets;
205         pSDLNet_FreeSocketSet SDLNet_FreeSocketSet;
206         pSDLNet_SetError SDLNet_SetError;
207         pSDLNet_GetError SDLNet_GetError;
208     }
209 
210     private {
211         SharedLib lib;
212         SDLNetSupport loadedVersion;
213     }
214 
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 }