|
1 /* |
|
2 SDL_net: An example cross-platform network library for use with SDL |
|
3 Copyright (C) 1997-2004 Sam Lantinga |
|
4 |
|
5 This library is free software; you can redistribute it and/or |
|
6 modify it under the terms of the GNU Library General Public |
|
7 License as published by the Free Software Foundation; either |
|
8 version 2 of the License, or (at your option) any later version. |
|
9 |
|
10 This library is distributed in the hope that it will be useful, |
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 Library General Public License for more details. |
|
14 |
|
15 You should have received a copy of the GNU Library General Public |
|
16 License along with this library; if not, write to the Free |
|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
18 |
|
19 Sam Lantinga |
|
20 slouken@libsdl.org |
|
21 */ |
|
22 |
|
23 /* $Id: SDLnet.c 2207 2006-04-20 16:48:25Z slouken $ */ |
|
24 |
|
25 #include <string.h> |
|
26 |
|
27 #include "SDL_endian.h" |
|
28 |
|
29 #include "SDLnetsys.h" |
|
30 #include "SDL_net.h" |
|
31 |
|
32 |
|
33 const SDL_version *SDLNet_Linked_Version(void) |
|
34 { |
|
35 static SDL_version linked_version; |
|
36 SDL_NET_VERSION(&linked_version); |
|
37 return(&linked_version); |
|
38 } |
|
39 |
|
40 /* Since the UNIX/Win32/BeOS code is so different from MacOS, |
|
41 we'll just have two completely different sections here. |
|
42 */ |
|
43 static int SDLNet_started = 0; |
|
44 |
|
45 #ifdef MACOS_OPENTRANSPORT |
|
46 |
|
47 #include <Events.h> |
|
48 |
|
49 typedef struct |
|
50 { |
|
51 Uint8 stat; |
|
52 InetSvcRef dns; |
|
53 }DNSStatus, *DNSStatusRef; |
|
54 |
|
55 enum |
|
56 { |
|
57 dnsNotReady = 0, |
|
58 dnsReady = 1, |
|
59 dnsResolved = 2, |
|
60 dnsError = 255 |
|
61 }; |
|
62 |
|
63 //static InetSvcRef dns = 0; |
|
64 static DNSStatus dnsStatus; |
|
65 Uint32 OTlocalhost = 0; |
|
66 |
|
67 /* We need a notifier for opening DNS.*/ |
|
68 /* ( 010311 masahiro minami<elsur@aaa.letter.co.jp>) */ |
|
69 static pascal void OpenDNSNotifier( |
|
70 void* context, OTEventCode code, OTResult result, void* cookie ) |
|
71 { |
|
72 switch( code ) |
|
73 { |
|
74 case T_OPENCOMPLETE: |
|
75 // DNS is ready now. |
|
76 if( result == kOTNoError ) |
|
77 { |
|
78 dnsStatus.dns = (InetSvcRef)cookie; |
|
79 dnsStatus.stat = dnsReady; |
|
80 } |
|
81 else |
|
82 { |
|
83 SDLNet_SetError("T_DNRSTRINGTOADDRCOMPLETE event returned an error"); |
|
84 dnsStatus.dns = NULL; |
|
85 dnsStatus.stat = dnsError; |
|
86 } |
|
87 break; |
|
88 case T_DNRSTRINGTOADDRCOMPLETE: |
|
89 // DNR resolved the name to address |
|
90 // WORK IN PROGRESS (TODO ) |
|
91 dnsStatus.stat = dnsResolved; |
|
92 break; |
|
93 default: |
|
94 if( result != kOTNoError ) |
|
95 dnsStatus.stat = dnsError; |
|
96 } |
|
97 // Is there anything else to be done here ??? |
|
98 // ( 010311 masahiro minami<elsur@aaa.letter.co.jp> ) |
|
99 // (TODO) |
|
100 } |
|
101 |
|
102 /* Local functions for initializing and cleaning up the DNS resolver */ |
|
103 static int OpenDNS(void) |
|
104 { |
|
105 int retval; |
|
106 OSStatus status; |
|
107 |
|
108 retval = 0; |
|
109 status = OTAsyncOpenInternetServices( |
|
110 kDefaultInternetServicesPath, 0, OpenDNSNotifier, NULL); |
|
111 if ( status == noErr ) { |
|
112 InetInterfaceInfo info; |
|
113 |
|
114 dnsStatus.stat = dnsNotReady; |
|
115 |
|
116 while( dnsStatus.stat != dnsError && dnsStatus.dns == NULL) |
|
117 { |
|
118 // what's to be done ? Yield ? WaitNextEvent ? or what ? |
|
119 // ( 010311 masahiro minami<elsur@aaa.letter.co.jp> ) |
|
120 //YieldToAnyThread(); |
|
121 } |
|
122 /* Get the address of the local system - |
|
123 What should it be if ethernet is off? |
|
124 */ |
|
125 OTInetGetInterfaceInfo(&info, kDefaultInetInterface); |
|
126 OTlocalhost = info.fAddress; |
|
127 } else { |
|
128 SDLNet_SetError("Unable to open DNS handle"); |
|
129 retval = status; |
|
130 } |
|
131 |
|
132 return(retval); |
|
133 } |
|
134 |
|
135 static void CloseDNS(void) |
|
136 { |
|
137 if ( dnsStatus.dns ) { |
|
138 OTCloseProvider(dnsStatus.dns); |
|
139 dnsStatus.dns = 0; |
|
140 dnsStatus.stat = dnsNotReady; |
|
141 } |
|
142 |
|
143 OTlocalhost = 0; |
|
144 } |
|
145 |
|
146 /* Initialize/Cleanup the network API */ |
|
147 int SDLNet_Init(void) |
|
148 { |
|
149 OSStatus status; |
|
150 int retval; |
|
151 |
|
152 dnsStatus.stat = dnsNotReady; |
|
153 dnsStatus.dns = 0; |
|
154 |
|
155 |
|
156 retval = 0; |
|
157 if ( ! SDLNet_started ) { |
|
158 status = InitOpenTransport(); |
|
159 if ( status == noErr ) { |
|
160 retval = OpenDNS(); |
|
161 if ( retval < 0 ) { |
|
162 SDLNet_Quit(); |
|
163 } |
|
164 } else { |
|
165 SDLNet_SetError("Unable to initialize Open Transport"); |
|
166 retval = status; |
|
167 } |
|
168 } |
|
169 if ( retval == 0 ) { |
|
170 ++SDLNet_started; |
|
171 } |
|
172 return(retval); |
|
173 } |
|
174 |
|
175 void SDLNet_Quit(void) |
|
176 { |
|
177 if ( SDLNet_started == 0 ) { |
|
178 return; |
|
179 } |
|
180 if ( --SDLNet_started == 0 ) { |
|
181 CloseDNS(); |
|
182 CloseOpenTransport(); |
|
183 } |
|
184 } |
|
185 |
|
186 /* Resolve a host name and port to an IP address in network form */ |
|
187 int SDLNet_ResolveHost(IPaddress *address, const char *host, Uint16 port) |
|
188 { |
|
189 int retval = 0; |
|
190 |
|
191 /* Perform the actual host resolution */ |
|
192 if ( host == NULL ) { |
|
193 address->host = INADDR_ANY; |
|
194 } else { |
|
195 /* int a[4]; |
|
196 |
|
197 address->host = INADDR_NONE; |
|
198 |
|
199 if ( sscanf(host, "%d.%d.%d.%d", a, a+1, a+2, a+3) == 4 ) { |
|
200 if ( !(a[0] & 0xFFFFFF00) && !(a[1] & 0xFFFFFF00) && |
|
201 !(a[2] & 0xFFFFFF00) && !(a[3] & 0xFFFFFF00) ) { |
|
202 address->host = ((a[0] << 24) | |
|
203 (a[1] << 16) | |
|
204 (a[2] << 8) | a[3]); |
|
205 if ( address->host == 0x7F000001 ) { |
|
206 address->host = OTlocalhost; |
|
207 } |
|
208 } |
|
209 } |
|
210 |
|
211 if ( address->host == INADDR_NONE ) {*/ |
|
212 InetHostInfo hinfo; |
|
213 |
|
214 /* Check for special case - localhost */ |
|
215 if ( strcmp(host, "localhost") == 0 ) |
|
216 return(SDLNet_ResolveHost(address, "127.0.0.1", port)); |
|
217 |
|
218 /* Have OpenTransport resolve the hostname for us */ |
|
219 retval = OTInetStringToAddress(dnsStatus.dns, (char *)host, &hinfo); |
|
220 if (retval == noErr) { |
|
221 while( dnsStatus.stat != dnsResolved ) |
|
222 {WaitNextEvent(everyEvent, 0, 1, NULL );} |
|
223 address->host = hinfo.addrs[0]; |
|
224 } |
|
225 //} |
|
226 } |
|
227 |
|
228 address->port = SDL_SwapBE16(port); |
|
229 |
|
230 /* Return the status */ |
|
231 return(retval); |
|
232 } |
|
233 |
|
234 /* Resolve an ip address to a host name in canonical form. |
|
235 If the ip couldn't be resolved, this function returns NULL, |
|
236 otherwise a pointer to a static buffer containing the hostname |
|
237 is returned. Note that this function is not thread-safe. |
|
238 */ |
|
239 /* MacOS implementation by Roy Wood |
|
240 */ |
|
241 const char *SDLNet_ResolveIP(IPaddress *ip) |
|
242 { |
|
243 if (ip != nil) |
|
244 { |
|
245 InetHost theIP; |
|
246 static InetDomainName theInetDomainName; |
|
247 OSStatus theOSStatus; |
|
248 |
|
249 |
|
250 /* Default result will be null string */ |
|
251 |
|
252 theInetDomainName[0] = '\0'; |
|
253 |
|
254 |
|
255 /* Do a reverse DNS lookup */ |
|
256 |
|
257 theIP = ip->host; |
|
258 |
|
259 theOSStatus = OTInetAddressToName(dnsStatus.dns,theIP,theInetDomainName); |
|
260 |
|
261 /* If successful, return the result */ |
|
262 |
|
263 if (theOSStatus == kOTNoError) |
|
264 { |
|
265 while( dnsStatus.stat != dnsResolved ) |
|
266 { /*should we yield or what ? */ } |
|
267 return(theInetDomainName); |
|
268 } |
|
269 } |
|
270 |
|
271 SDLNet_SetError("Can't perform reverse DNS lookup"); |
|
272 |
|
273 return(NULL); |
|
274 } |
|
275 |
|
276 #else /* !MACOS_OPENTRANSPORT */ |
|
277 |
|
278 #ifndef __USE_W32_SOCKETS |
|
279 #include <signal.h> |
|
280 #endif |
|
281 |
|
282 /* Initialize/Cleanup the network API */ |
|
283 int SDLNet_Init(void) |
|
284 { |
|
285 if ( !SDLNet_started ) { |
|
286 #ifdef __USE_W32_SOCKETS |
|
287 /* Start up the windows networking */ |
|
288 WORD version_wanted = MAKEWORD(1,1); |
|
289 WSADATA wsaData; |
|
290 |
|
291 if ( WSAStartup(version_wanted, &wsaData) != 0 ) { |
|
292 SDLNet_SetError("Couldn't initialize Winsock 1.1\n"); |
|
293 return(-1); |
|
294 } |
|
295 #else |
|
296 /* SIGPIPE is generated when a remote socket is closed */ |
|
297 void (*handler)(int); |
|
298 handler = signal(SIGPIPE, SIG_IGN); |
|
299 if ( handler != SIG_DFL ) { |
|
300 signal(SIGPIPE, handler); |
|
301 } |
|
302 #endif |
|
303 } |
|
304 ++SDLNet_started; |
|
305 return(0); |
|
306 } |
|
307 void SDLNet_Quit(void) |
|
308 { |
|
309 if ( SDLNet_started == 0 ) { |
|
310 return; |
|
311 } |
|
312 if ( --SDLNet_started == 0 ) { |
|
313 #ifdef __USE_W32_SOCKETS |
|
314 /* Clean up windows networking */ |
|
315 if ( WSACleanup() == SOCKET_ERROR ) { |
|
316 if ( WSAGetLastError() == WSAEINPROGRESS ) { |
|
317 WSACancelBlockingCall(); |
|
318 WSACleanup(); |
|
319 } |
|
320 } |
|
321 #else |
|
322 /* Restore the SIGPIPE handler */ |
|
323 void (*handler)(int); |
|
324 handler = signal(SIGPIPE, SIG_DFL); |
|
325 if ( handler != SIG_IGN ) { |
|
326 signal(SIGPIPE, handler); |
|
327 } |
|
328 #endif |
|
329 } |
|
330 } |
|
331 |
|
332 /* Resolve a host name and port to an IP address in network form */ |
|
333 int SDLNet_ResolveHost(IPaddress *address, const char *host, Uint16 port) |
|
334 { |
|
335 int retval = 0; |
|
336 |
|
337 /* Perform the actual host resolution */ |
|
338 if ( host == NULL ) { |
|
339 address->host = INADDR_ANY; |
|
340 } else { |
|
341 address->host = inet_addr(host); |
|
342 if ( address->host == INADDR_NONE ) { |
|
343 struct hostent *hp; |
|
344 |
|
345 hp = gethostbyname(host); |
|
346 if ( hp ) { |
|
347 memcpy(&address->host,hp->h_addr,hp->h_length); |
|
348 } else { |
|
349 retval = -1; |
|
350 } |
|
351 } |
|
352 } |
|
353 address->port = SDL_SwapBE16(port); |
|
354 |
|
355 /* Return the status */ |
|
356 return(retval); |
|
357 } |
|
358 |
|
359 /* Resolve an ip address to a host name in canonical form. |
|
360 If the ip couldn't be resolved, this function returns NULL, |
|
361 otherwise a pointer to a static buffer containing the hostname |
|
362 is returned. Note that this function is not thread-safe. |
|
363 */ |
|
364 /* Written by Miguel Angel Blanch. |
|
365 * Main Programmer of Arianne RPG. |
|
366 * http://come.to/arianne_rpg |
|
367 */ |
|
368 const char *SDLNet_ResolveIP(IPaddress *ip) |
|
369 { |
|
370 struct hostent *hp; |
|
371 |
|
372 hp = gethostbyaddr((char *)&ip->host, 4, AF_INET); |
|
373 if ( hp != NULL ) { |
|
374 return hp->h_name; |
|
375 } |
|
376 return NULL; |
|
377 } |
|
378 |
|
379 #endif /* MACOS_OPENTRANSPORT */ |
|
380 |
|
381 #if !SDL_DATA_ALIGNED /* function versions for binary compatibility */ |
|
382 |
|
383 /* Write a 16 bit value to network packet buffer */ |
|
384 #undef SDLNet_Write16 |
|
385 void SDLNet_Write16(Uint16 value, void *areap) |
|
386 { |
|
387 (*(Uint16 *)(areap) = SDL_SwapBE16(value)); |
|
388 } |
|
389 |
|
390 /* Write a 32 bit value to network packet buffer */ |
|
391 #undef SDLNet_Write32 |
|
392 void SDLNet_Write32(Uint32 value, void *areap) |
|
393 { |
|
394 *(Uint32 *)(areap) = SDL_SwapBE32(value); |
|
395 } |
|
396 |
|
397 /* Read a 16 bit value from network packet buffer */ |
|
398 #undef SDLNet_Read16 |
|
399 Uint16 SDLNet_Read16(void *areap) |
|
400 { |
|
401 return (SDL_SwapBE16(*(Uint16 *)(areap))); |
|
402 } |
|
403 |
|
404 /* Read a 32 bit value from network packet buffer */ |
|
405 #undef SDLNet_Read32 |
|
406 Uint32 SDLNet_Read32(void *areap) |
|
407 { |
|
408 return (SDL_SwapBE32(*(Uint32 *)(areap))); |
|
409 } |
|
410 |
|
411 #endif /* !SDL_DATA_ALIGNED */ |
|
412 |
|
413 |
|
414 #ifdef USE_GUSI_SOCKETS |
|
415 |
|
416 /* Configure Socket Factories */ |
|
417 |
|
418 void GUSISetupFactories() |
|
419 { |
|
420 GUSIwithInetSockets(); |
|
421 } |
|
422 |
|
423 /* Configure File Devices */ |
|
424 |
|
425 void GUSISetupDevices() |
|
426 { |
|
427 return; |
|
428 } |
|
429 |
|
430 #endif /* USE_GUSI_SOCKETS */ |