1 /+
2 +            Copyright 2022 – 2024 Aya Partridge
3 +          Copyright 2018 - 2022 Michael D. Parker
4 + Distributed under the Boost Software License, Version 1.0.
5 +     (See accompanying file LICENSE_1_0.txt or copy at
6 +           http://www.boost.org/LICENSE_1_0.txt)
7 +/
8 module sdl_net;
9 
10 import bindbc.sdl.config;
11 static if(bindSDLNet):
12 import bindbc.sdl.codegen;
13 
14 alias SDLNet_version = SDL_version;
15 
16 enum SDLNetSupport: SDLNet_version{
17 	noLibrary   = SDLNet_version(0,0,0),
18 	badLibrary  = SDLNet_version(0,0,255),
19 	v2_0_0      = SDLNet_version(2,0,0),
20 	v2_0_1      = SDLNet_version(2,0,1),
21 	v2_2        = SDLNet_version(2,2,0),
22 	
23 	deprecated("Please use `v2_0_0` instead") sdlNet200 = SDLNet_version(2,0,0),
24 	deprecated("Please use `v2_0_1` instead") sdlNet201 = SDLNet_version(2,0,1),
25 }
26 
27 enum sdlNetSupport = (){
28 	version(SDL_Net_2_2)      return SDLNetSupport.v2_2;
29 	else version(SDL_Net_201) return SDLNetSupport.v2_0_1;
30 	else                      return SDLNetSupport.v2_0_0;
31 }();
32 
33 enum SDL_NET_MAJOR_VERSION = sdlNetSupport.major;
34 enum SDL_NET_MINOR_VERSION = sdlNetSupport.minor;
35 enum SDL_NET_PATCHLEVEL    = sdlNetSupport.patch;
36 
37 pragma(inline, true) void SDL_NET_VERSION(SDLNet_version* x) nothrow @nogc pure @safe{
38 	x.major = SDL_NET_MAJOR_VERSION;
39 	x.minor = SDL_NET_MINOR_VERSION;
40 	x.patch = SDL_NET_PATCHLEVEL;
41 }
42 
43 bool SDL_NET_VERSION_ATLEAST(ubyte x, ubyte y, ubyte z){ return SDLNet_version(SDL_NET_MAJOR_VERSION, SDL_NET_MINOR_VERSION, SDL_NET_PATCHLEVEL) >= SDLNet_version(x, y, z); }
44 
45 struct IPaddress{
46 	uint host;
47 	ushort port;
48 }
49 
50 enum: uint{
51 	INADDR_ANY        = 0x0000_0000,
52 	INADDR_NONE       = 0xFFFF_FFFF,
53 	INADDR_LOOPBACK   = 0x7F00_0001,
54 	INADDR_BROADCAST  = 0xFFFF_FFFF,
55 }
56 
57 struct _TCPsocket;
58 alias TCPsocket = _TCPsocket*;
59 
60 enum SDLNET_MAX_UDPCHANNELS = 32;
61 
62 enum SDLNET_MAX_UDPADRESSES = 4;
63 
64 struct _UDPsocket;
65 alias UDPsocket = _UDPsocket*;
66 
67 struct UDPpacket{
68 	int channel;
69 	ubyte* data;
70 	int len;
71 	int maxlen;
72 	int status;
73 	IPaddress address;
74 }
75 
76 struct _SDLNet_SocketSet;
77 alias SDLNet_SocketSet = _SDLNet_SocketSet*;
78 
79 struct _SDLNet_GenericSocket{
80 	int ready;
81 }
82 alias SDLNet_GenericSocket = _SDLNet_GenericSocket*;
83 
84 pragma(inline, true) nothrow @nogc{
85 	int SDLNet_TCP_AddSocket(SDLNet_SocketSet set, TCPsocket sock){
86 		return SDLNet_AddSocket(set, cast(SDLNet_GenericSocket)sock);
87 	}
88 	
89 	int SDLNet_UDP_AddSocket(SDLNet_SocketSet set, UDPsocket sock){
90 		return SDLNet_AddSocket(set, cast(SDLNet_GenericSocket)sock);
91 	}
92 	
93 	int SDLNet_TCP_DelSocket(SDLNet_SocketSet set, TCPsocket sock){
94 		return SDLNet_DelSocket(set, cast(SDLNet_GenericSocket)sock);
95 	}
96 	
97 	int SDLNet_UDP_DelSocket(SDLNet_SocketSet set, UDPsocket sock){
98 		return SDLNet_DelSocket(set, cast(SDLNet_GenericSocket)sock);
99 	}
100 	
101 	bool SDLNet_SocketReady(TCPsocket sock){
102 		return (sock !is null) && (cast(SDLNet_GenericSocket)sock).ready;
103 	}
104 	
105 	bool SDLNet_SocketReady(UDPsocket sock){
106 		return (sock !is null) && (cast(SDLNet_GenericSocket)sock).ready;
107 	}
108 	
109 	pure{
110 		import sdl.endian: SDL_SwapBE16, SDL_SwapBE32;
111 		
112 		void SDLNet_Write16(ushort value, void* areaP){
113 			*cast(ushort*)areaP = SDL_SwapBE16(value);
114 		}
115 		
116 		void SDLNet_Write32(uint value, void* areaP){
117 			*cast(uint*)areaP = SDL_SwapBE32(value);
118 		}
119 		
120 		ushort SDLNet_Read16(const(void)* areaP){
121 			return SDL_SwapBE16(*cast(const(ushort)*)areaP);
122 		}
123 		
124 		uint SDLNet_Read32(const(void)* areaP){
125 			return SDL_SwapBE32(*cast(const(uint)*)areaP);
126 		}
127 	}
128 }
129 
130 mixin(joinFnBinds((){
131 	FnBind[] ret = [
132 		{q{const(SDLNet_version)*}, q{SDLNet_Linked_Version}, q{}},
133 		{q{int}, q{SDLNet_Init}, q{}},
134 		{q{void}, q{SDLNet_Quit}, q{}},
135 		{q{int}, q{SDLNet_ResolveHost}, q{IPaddress* address, const(char)* host, ushort port}},
136 		{q{const(char)*}, q{SDLNet_ResolveIP}, q{const(IPaddress)* ip}},
137 		{q{int}, q{SDLNet_GetLocalAddresses}, q{IPaddress* addresses, int maxCount}},
138 		{q{TCPsocket}, q{SDLNet_TCP_Open}, q{IPaddress* ip}},
139 		{q{TCPsocket}, q{SDLNet_TCP_Accept}, q{TCPsocket server}},
140 		{q{IPaddress*}, q{SDLNet_TCP_GetPeerAddress}, q{TCPsocket sock}},
141 		{q{int}, q{SDLNet_TCP_Send}, q{TCPsocket sock, const(void)* data, int len}},
142 		{q{int}, q{SDLNet_TCP_Recv}, q{TCPsocket sock, void* data, int len}},
143 		{q{void}, q{SDLNet_TCP_Close}, q{TCPsocket sock}},
144 		{q{UDPpacket*}, q{SDLNet_AllocPacket}, q{int size}},
145 		{q{int}, q{SDLNet_ResizePacket}, q{UDPpacket* packet, int newSize}},
146 		{q{void}, q{SDLNet_FreePacket}, q{UDPpacket* packet}},
147 		{q{UDPpacket**}, q{SDLNet_AllocPacketV}, q{int howMany, int size}},
148 		{q{void}, q{SDLNet_FreePacketV}, q{UDPpacket** packetV}},
149 		{q{UDPsocket}, q{SDLNet_UDP_Open}, q{ushort port}},
150 		{q{void}, q{SDLNet_UDP_SetPacketLoss}, q{UDPsocket sock, int percent}},
151 		{q{int}, q{SDLNet_UDP_Bind}, q{UDPsocket sock, int channel, const(IPaddress)* address}},
152 		{q{void}, q{SDLNet_UDP_Unbind}, q{UDPsocket sock, int channel}},
153 		{q{IPaddress*}, q{SDLNet_UDP_GetPeerAddress}, q{UDPsocket sock, int channel}},
154 		{q{int}, q{SDLNet_UDP_SendV}, q{UDPsocket sock, UDPpacket** packets, int nPackets}},
155 		{q{int}, q{SDLNet_UDP_Send}, q{UDPsocket sock, int channel, UDPpacket* packet}},
156 		{q{int}, q{SDLNet_UDP_RecvV}, q{UDPsocket sock, UDPpacket** packets}},
157 		{q{int}, q{SDLNet_UDP_Recv}, q{UDPsocket sock, UDPpacket* packet}},
158 		{q{void}, q{SDLNet_UDP_Close}, q{UDPsocket sock}},
159 		{q{SDLNet_SocketSet}, q{SDLNet_AllocSocketSet}, q{int maxSockets}},
160 		{q{int}, q{SDLNet_AddSocket}, q{SDLNet_SocketSet set, SDLNet_GenericSocket sock}},
161 		{q{int}, q{SDLNet_DelSocket}, q{SDLNet_SocketSet set, SDLNet_GenericSocket sock}},
162 		{q{int}, q{SDLNet_CheckSockets}, q{SDLNet_SocketSet set, uint timeout}},
163 		{q{void}, q{SDLNet_FreeSocketSet}, q{SDLNet_SocketSet set}},
164 		{q{void}, q{SDLNet_SetError}, q{const(char)* fmt, ...}},
165 		{q{const(char)*}, q{SDLNet_GetError}, q{}},
166 	];
167 	return ret;
168 }()));
169 
170 static if(!staticBinding):
171 import bindbc.loader;
172 
173 private{
174 	SharedLib lib;
175 	SDLNetSupport loadedVersion;
176 	enum libNamesCT = (){
177 		version(Windows){
178 			return [
179 				`SDL2_net.dll`,
180 			];
181 		}else version(OSX){
182 			return [
183 				`libSDL2_net.dylib`,
184 				`/opt/homebrew/lib/libSDL2_net.dylib`,
185 				`SDL2_net`,
186 				`/Library/Frameworks/SDL2_net.framework/SDL2_net`,
187 				`/System/Library/Frameworks/SDL2_net.framework/SDL2_net`,
188 			];
189 		}else version(Posix){
190 			return [
191 				`libSDL2_net.so`,
192 				`libSDL2_net-2.0.so`,
193 				`libSDL2_net-2.0.so.0`,
194 			];
195 		}else static assert(0, "BindBC-SDL_net does not have library search paths set up for this platform");
196 	}();
197 }
198 
199 nothrow @nogc:
200 deprecated("Please use `SDLNet_Linked_Version` instead")
201 	SDLNetSupport loadedSDLNetVersion(){ return loadedVersion; }
202 
203 mixin(bindbc.sdl.codegen.makeDynloadFns("Net", [__MODULE__]));