project_files/Android-build/SDL-android-project/jni/sdl_net/SDLnetTCP.c
branchhedgeroid
changeset 5317 86984c1034a5
equal deleted inserted replaced
5314:09bcdcd78379 5317:86984c1034a5
       
     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: SDLnetTCP.c 3280 2007-07-15 05:55:42Z slouken $ */
       
    24 
       
    25 #include "SDLnetsys.h"
       
    26 #include "SDL_net.h"
       
    27 
       
    28 /* The network API for TCP sockets */
       
    29 
       
    30 /* Since the UNIX/Win32/BeOS code is so different from MacOS,
       
    31    we'll just have two completely different sections here.
       
    32 */
       
    33 
       
    34 #ifdef MACOS_OPENTRANSPORT
       
    35 
       
    36 #include <Events.h>
       
    37 #include <Threads.h>
       
    38 #include <OpenTransport.h>
       
    39 #include <OpenTptInternet.h>
       
    40 #include <OTDebug.h>
       
    41 
       
    42 struct _TCPsocket {
       
    43 	int ready;
       
    44 	SOCKET channel;
       
    45 	
       
    46 	// These are taken from GUSI interface.
       
    47 	// I'm not sure if it's really necessary here yet
       
    48 	// ( masahiro minami<elsur@aaa.letter.co.jp> )
       
    49 	// ( 01/02/19 )
       
    50 	OTEventCode curEvent;
       
    51 	OTEventCode newEvent;
       
    52 	OTEventCode event;
       
    53 	OTEventCode curCompletion;
       
    54 	OTEventCode newCompletion;
       
    55 	OTEventCode completion;
       
    56 	OSStatus	error;
       
    57 	TEndpointInfo info;
       
    58 	Boolean		readShutdown;
       
    59 	Boolean		writeShutdown;
       
    60 	Boolean		connected;
       
    61 	OTConfigurationRef	config;		// Master configuration. you can clone this.
       
    62 	TCPsocket	nextListener;
       
    63 	// ( end of new members --- masahiro minami<elsur@aaa.letter.co.jp>
       
    64 	
       
    65 	IPaddress remoteAddress;
       
    66 	IPaddress localAddress;
       
    67 	int sflag;
       
    68 	
       
    69 	// Maybe we don't need this---- it's from original SDL_net
       
    70 	// (masahiro minami<elsur@aaa.letter.co.jp>)
       
    71 	// ( 01/02/20 )
       
    72 	int rcvdPassConn;
       
    73 };
       
    74 
       
    75 // To be used in WaitNextEvent() here and there....
       
    76 // (010311 masahiro minami<elsur@aaa.letter.co.jp>)
       
    77 EventRecord macEvent;
       
    78 
       
    79 #if TARGET_API_MAC_CARBON
       
    80 /* for Carbon */
       
    81 OTNotifyUPP notifier;
       
    82 #endif
       
    83 
       
    84 /* Input: ep - endpointref on which to negotiate the option
       
    85 			enableReuseIPMode - desired option setting - true/false
       
    86    Return: kOTNoError indicates that the option was successfully negotiated
       
    87    			OSStatus is an error if < 0, otherwise, the status field is
       
    88    			returned and is > 0.
       
    89    	
       
    90    	IMPORTANT NOTE: The endpoint is assumed to be in synchronous more, otherwise
       
    91    			this code will not function as desired
       
    92 */
       
    93 
       
    94 /*
       
    95 NOTE: As this version is written async way, we don't use this function...
       
    96 (010526) masahiro minami<elsur@aaa.letter.co.jp>
       
    97 */
       
    98 /*
       
    99 OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode)
       
   100 
       
   101 {
       
   102 	UInt8		buf[kOTFourByteOptionSize];	// define buffer for fourByte Option size
       
   103 	TOption*	opt;						// option ptr to make items easier to access
       
   104 	TOptMgmt	req;
       
   105 	TOptMgmt	ret;
       
   106 	OSStatus	err;
       
   107 	
       
   108 	if (!OTIsSynchronous(ep))
       
   109 	{
       
   110 		return (-1);
       
   111 	}
       
   112 	opt = (TOption*)buf;					// set option ptr to buffer
       
   113 	req.opt.buf	= buf;
       
   114 	req.opt.len	= sizeof(buf);
       
   115 	req.flags	= T_NEGOTIATE;				// negotiate for option
       
   116 
       
   117 	ret.opt.buf = buf;
       
   118 	ret.opt.maxlen = kOTFourByteOptionSize;
       
   119 
       
   120 	opt->level	= INET_IP;					// dealing with an IP Level function
       
   121 	opt->name	= IP_REUSEADDR;
       
   122 	opt->len	= kOTFourByteOptionSize;
       
   123 	opt->status = 0;
       
   124 	*(UInt32*)opt->value = enableReuseIPMode;		// set the desired option level, true or false
       
   125 
       
   126 	err = OTOptionManagement(ep, &req, &ret);
       
   127 	
       
   128 		// if no error then return the option status value
       
   129 	if (err == kOTNoError)
       
   130 	{
       
   131 		if (opt->status != T_SUCCESS)
       
   132 			err = opt->status;
       
   133 		else
       
   134 			err = kOTNoError;
       
   135 	}
       
   136 				
       
   137 	return err;
       
   138 }
       
   139 */
       
   140 
       
   141 /* A helper function for Mac OpenTransport support*/
       
   142 // This function is a complete copy from GUSI
       
   143 // ( masahiro minami<elsur@aaa.letter.co.jp> )
       
   144 // ( 01/02/19 )
       
   145 static __inline__ Uint32 CompleteMask(OTEventCode code)	
       
   146 { 	
       
   147 	return 1 << (code & 0x1F);
       
   148 }
       
   149 
       
   150 /* Notifier for async OT calls */
       
   151 static pascal void AsyncTCPNotifier( TCPsocket sock, OTEventCode code,
       
   152 					OTResult result, void* cookie )
       
   153 {
       
   154 
       
   155 #ifdef DEBUG_NET
       
   156 	printf("AsyncTCPNotifier got an event : 0x%8.8x\n", code );
       
   157 #endif
       
   158 	
       
   159 	switch( code & 0x7f000000L)
       
   160 	{
       
   161 		case 0:
       
   162 			sock->newEvent |= code;
       
   163 			result = 0;
       
   164 			break;
       
   165 		case kCOMPLETEEVENT:
       
   166 			if(!(code & 0x00FFFFE0 ))
       
   167 				sock->newCompletion |= CompleteMask( code );
       
   168 			if( code == T_OPENCOMPLETE )
       
   169 				sock->channel = (SOCKET)(cookie);
       
   170 			break;
       
   171 		default:
       
   172 			if( code != kOTProviderWillClose )
       
   173 				result = 0;
       
   174 	}
       
   175 	// Do we need these ???? TODO
       
   176 	// sock->SetAsyncMacError( result );
       
   177 	// sock->Wakeup();
       
   178 }
       
   179 
       
   180 /* Retrieve OT event */
       
   181 // This function is taken from GUSI interface.
       
   182 // ( 01/02/19 masahiro minami<elsur@aaa.letter.co.jp> )
       
   183 static void AsyncTCPPopEvent( TCPsocket sock )
       
   184 {
       
   185 	// Make sure OT calls are not interrupted
       
   186 	// Not sure if we really need this.
       
   187 	OTEnterNotifier( sock->channel );
       
   188 	
       
   189 	sock->event |= (sock->curEvent = sock->newEvent );
       
   190 	sock->completion |= ( sock->curCompletion = sock->newCompletion );
       
   191 	sock->newEvent = sock->newCompletion = 0;
       
   192 	
       
   193 	OTLeaveNotifier( sock->channel );
       
   194 	
       
   195 	if( sock->curEvent & T_UDERR)
       
   196 	{
       
   197 		// We just clear the error.
       
   198 		// Should we feed this back to users ?
       
   199 		// (TODO )
       
   200 		OTRcvUDErr( sock->channel, NULL );
       
   201 		
       
   202 #ifdef DEBUG_NET
       
   203 		printf("AsyncTCPPopEvent  T_UDERR recognized");
       
   204 #endif
       
   205 	}
       
   206 	
       
   207 	// Remote is disconnecting...
       
   208 	if( sock->curEvent & ( T_DISCONNECT | T_ORDREL ))
       
   209 	{
       
   210 		sock->readShutdown = true;
       
   211 	}
       
   212 	
       
   213 	if( sock->curEvent &T_CONNECT )
       
   214 	{
       
   215 		// Ignore the info of remote (second parameter).
       
   216 		// Shoule we care ?
       
   217 		// (TODO)
       
   218 		OTRcvConnect( sock->channel, NULL );
       
   219 		sock->connected = 1;
       
   220 	}
       
   221 	
       
   222 	if( sock->curEvent & T_ORDREL )
       
   223 	{
       
   224 		OTRcvOrderlyDisconnect( sock->channel );
       
   225 	}
       
   226 	
       
   227 	if( sock->curEvent & T_DISCONNECT )
       
   228 	{
       
   229 		OTRcvDisconnect( sock->channel, NULL );
       
   230 	}
       
   231 	
       
   232 	// Do we need to ?
       
   233 	// (masahiro minami<elsur@aaa.letter.co.jp>)
       
   234 	//YieldToAnyThread();
       
   235 }
       
   236 
       
   237 /* Create a new TCPsocket */
       
   238 // Because TCPsocket structure gets bigger and bigger,
       
   239 // I think we'd better have a constructor function and delete function.
       
   240 // ( 01/02/25 masahiro minami<elsur@aaa.letter.co.jp> )
       
   241 static TCPsocket AsyncTCPNewSocket()
       
   242 {
       
   243 	TCPsocket sock;
       
   244 	
       
   245 	sock = (TCPsocket)malloc(sizeof(*sock));
       
   246 	if ( sock == NULL ) {
       
   247 		SDLNet_SetError("Out of memory");
       
   248 		return NULL;
       
   249 	}
       
   250 	
       
   251 	sock->newEvent = 0;
       
   252 	sock->event = 0;
       
   253 	sock->curEvent = 0;
       
   254 	sock->newCompletion = 0;
       
   255 	sock->completion = 0;
       
   256 	sock->curCompletion = 0;
       
   257 	//sock->info = NULL;
       
   258 	sock->readShutdown = sock->writeShutdown = sock->connected = false;
       
   259 	sock->error = 0;
       
   260 	sock->config = NULL;
       
   261 	sock->nextListener = NULL;
       
   262 	sock->sflag = 0;
       
   263 	return sock;	
       
   264 }
       
   265 
       
   266 // hmmm.... do we need this ???
       
   267 // ( 01/02/25 masahiro minami<elsur@aaa.letter.co.jp>)
       
   268 static void AsycnTCPDeleteSocket( TCPsocket sock )
       
   269 {
       
   270 	SDLNet_TCP_Close( sock );
       
   271 }
       
   272 /* Open a TCP network socket
       
   273    If 'remote' is NULL, this creates a local server socket on the given port,
       
   274    otherwise a TCP connection to the remote host and port is attempted.
       
   275    The newly created socket is returned, or NULL if there was an error.
       
   276 
       
   277    ( re-written by masahiro minami<elsur@aaa.letter.co.jp>
       
   278      Now endpoint is created in Async mode.
       
   279      01/02/20 )
       
   280 */
       
   281 TCPsocket SDLNet_TCP_Open(IPaddress *ip)
       
   282 {
       
   283 	EndpointRef dummy = NULL;
       
   284 
       
   285 	TCPsocket sock = AsyncTCPNewSocket();
       
   286 	if( ! sock)
       
   287 		return NULL;
       
   288 
       
   289 	// Determin whether bind locally, or connect to remote
       
   290 	if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) )
       
   291 	{
       
   292 		// ######## Connect to remote
       
   293 		OTResult stat;
       
   294 		InetAddress inAddr;
       
   295 		TBind bindReq;
       
   296 
       
   297 		// Open endpoint
       
   298 		sock->error = OTAsyncOpenEndpoint(
       
   299 			OTCreateConfiguration(kTCPName), NULL, &(sock->info),
       
   300 			(OTNotifyProcPtr)(AsyncTCPNotifier),
       
   301 			sock );
       
   302 
       
   303 		AsyncTCPPopEvent( sock );
       
   304 		while( !sock->error && !( sock->completion & CompleteMask(T_OPENCOMPLETE)))
       
   305 		{
       
   306 			//SetThreadState( kCurrentThreadID, kReadyThreadState, kNoThreadID );
       
   307 			//YieldToAnyThread();
       
   308 			//WaitNextEvent(everyEvent, &macEvent, 1, NULL);
       
   309 			AsyncTCPPopEvent( sock );
       
   310 		}
       
   311 
       
   312 		if( !sock->channel )
       
   313 		{
       
   314 			SDLNet_SetError("OTAsyncOpenEndpoint failed --- client socket could not be opened");
       
   315 			goto error_return;
       
   316 		}
       
   317 
       
   318 		// Set blocking mode
       
   319 		// I'm not sure if this is a good solution....
       
   320 		// Check out Apple's sample code, OT Virtual Server
       
   321 		// ( 010314 masahiro minami<elsur@aaa.letter.co.jp>)
       
   322 
       
   323 		sock->error = OTSetBlocking( sock->channel );
       
   324 		if( sock->error != kOTNoError )
       
   325 		{
       
   326 			SDLNet_SetError("OTSetBlocking() returned an error");
       
   327 			goto error_return;
       
   328 		}
       
   329 
       
   330 		// Bind the socket
       
   331 		OTInitInetAddress(&inAddr, 0, 0 );
       
   332 		bindReq.addr.len = sizeof( InetAddress );
       
   333 		bindReq.addr.buf = (unsigned char*)&inAddr;
       
   334 		bindReq.qlen = 0;
       
   335 
       
   336 		sock->error = OTBind( sock->channel, &bindReq, NULL );
       
   337 		AsyncTCPPopEvent(sock);
       
   338 		while( !sock->error && !( sock->completion & CompleteMask(T_BINDCOMPLETE)))
       
   339 		{
       
   340 			//YieldToAnyThread();
       
   341 			//WaitNextEvent(everyEvent, &macEvent, 1, NULL);
       
   342 			AsyncTCPPopEvent(sock);
       
   343 		}
       
   344 
       
   345 
       
   346 		switch( stat = OTGetEndpointState( sock->channel ))
       
   347 		{
       
   348 			InetAddress inAddr;
       
   349 			TCall sndCall;
       
   350 			OTResult res;
       
   351 
       
   352 			case T_OUTCON:
       
   353 				SDLNet_SetError("SDLNet_Open() failed -- T_OUTCON");
       
   354 				goto error_return;
       
   355 				break;
       
   356 			case T_IDLE:
       
   357 				sock->readShutdown = false;
       
   358 				sock->writeShutdown = false;
       
   359 				sock->event &=~T_CONNECT;
       
   360 
       
   361 				OTMemzero(&sndCall, sizeof(TCall));
       
   362 				OTInitInetAddress(&inAddr, ip->port, ip->host );
       
   363 				sndCall.addr.len = sizeof(InetAddress);
       
   364 				sndCall.addr.buf = (unsigned char*)&inAddr;
       
   365 				sock->connected = 0;
       
   366 				res = OTConnect( sock->channel, &sndCall, NULL );
       
   367 				AsyncTCPPopEvent(sock);
       
   368 				while( sock->error == kOTNoDataErr || !sock->connected )
       
   369 					AsyncTCPPopEvent(sock);
       
   370 				break;
       
   371 			default:
       
   372 				// What's to be done ? (TODO)
       
   373 				SDLNet_SetError("SDLNet_TCP_Open() failed -- EndpointState not good");
       
   374 				goto error_return;
       
   375 
       
   376 		}
       
   377 		if( !(sock->event & (T_CONNECT|T_DISCONNECT)))
       
   378 			goto error_return;
       
   379 
       
   380 		AsyncTCPPopEvent( sock );
       
   381 		while( !(sock->event & (T_CONNECT|T_DISCONNECT)))
       
   382 		{
       
   383 			AsyncTCPPopEvent( sock );
       
   384 		}
       
   385 		// OTConnect successfull
       
   386 		if( sock->event & T_CONNECT)
       
   387 		{
       
   388 			sock->remoteAddress.host = inAddr.fHost;
       
   389 			sock->remoteAddress.port = inAddr.fPort;
       
   390 			sock->sflag = false;
       
   391 		}
       
   392 		else
       
   393 		{
       
   394 			// OTConnect failed
       
   395 			sock->event &= ~T_DISCONNECT;
       
   396 			goto error_return;
       
   397 		}
       
   398 	}
       
   399 	else
       
   400 	{
       
   401 		// ######## Bind locally
       
   402 		TBind bindReq;
       
   403 		InetAddress	inAddr;
       
   404 
       
   405 	// First, get InetInterfaceInfo.
       
   406 	// I don't search for all of them.
       
   407 	// Does that matter ?
       
   408 
       
   409 		sock->error = OTAsyncOpenEndpoint(
       
   410 			OTCreateConfiguration("tilisten, tcp"), NULL, &(sock->info),
       
   411 			(OTNotifyProcPtr)(AsyncTCPNotifier),
       
   412 			sock);
       
   413 		AsyncTCPPopEvent( sock );
       
   414 		while( !sock->error && !( sock->completion & CompleteMask( T_OPENCOMPLETE)))
       
   415 		{
       
   416 			AsyncTCPPopEvent( sock );
       
   417 		}
       
   418 
       
   419 		if( ! sock->channel )
       
   420 		{
       
   421 			SDLNet_SetError("OTAsyncOpenEndpoint failed --- server socket could not be opened");
       
   422 			goto error_return;
       
   423 		}
       
   424 
       
   425 		// Create a master OTConfiguration
       
   426 		sock->config = OTCreateConfiguration(kTCPName);
       
   427 		if( ! sock->config )
       
   428 		{
       
   429 			SDLNet_SetError("Could not create master OTConfiguration");
       
   430 			goto error_return;
       
   431 		}
       
   432 
       
   433 		// Bind the socket
       
   434 		OTInitInetAddress(&inAddr, ip->port, 0 );
       
   435 		inAddr.fAddressType = AF_INET;
       
   436 		bindReq.addr.len = sizeof( InetAddress );
       
   437 		bindReq.addr.buf = (unsigned char*)&inAddr;
       
   438 		bindReq.qlen = 35;	// This number is NOT well considered. (TODO)
       
   439 		sock->localAddress.host = inAddr.fHost;
       
   440 		sock->localAddress.port = inAddr.fPort;
       
   441 		sock->sflag = true;
       
   442 		
       
   443 		sock->error = OTBind( sock->channel, &bindReq, NULL );
       
   444 		AsyncTCPPopEvent(sock);
       
   445 		while( !sock->error && !( sock->completion & CompleteMask(T_BINDCOMPLETE)))
       
   446 		{
       
   447 			AsyncTCPPopEvent(sock);
       
   448 		}
       
   449 		if( sock->error != kOTNoError )
       
   450 		{
       
   451 			SDLNet_SetError("Could not bind server socket");
       
   452 			goto error_return;
       
   453 		}
       
   454 		
       
   455 		if( dummy )
       
   456 			OTCloseProvider( dummy );
       
   457 
       
   458 	}
       
   459 	
       
   460 	sock->ready = 0;
       
   461 	return sock;
       
   462 	
       
   463 	error_return:
       
   464 	if( dummy )
       
   465 		OTCloseProvider( dummy );
       
   466 	SDLNet_TCP_Close( sock );
       
   467 	return NULL;	
       
   468 }
       
   469 
       
   470 /* Accept an incoming connection on the given server socket.
       
   471    The newly created socket is returned, or NULL if there was an error.
       
   472 */
       
   473 TCPsocket SDLNet_TCP_Accept(TCPsocket server)
       
   474 {
       
   475 	
       
   476 	/* Only server sockets can accept */
       
   477 	if ( ! server->sflag ) {
       
   478 		SDLNet_SetError("Only server sockets can accept()");
       
   479 		return(NULL);
       
   480 	}
       
   481 	server->ready = 0;
       
   482 
       
   483 	/* Accept a new TCP connection on a server socket */
       
   484 	{
       
   485 		InetAddress peer;
       
   486 		TCall peerinfo;
       
   487 		TCPsocket sock = NULL;
       
   488 		Boolean mustListen = false;
       
   489 		OTResult err;
       
   490 		
       
   491 		memset(&peerinfo, 0, (sizeof peerinfo ));
       
   492 		peerinfo.addr.buf = (Uint8 *) &peer;
       
   493 		peerinfo.addr.maxlen = sizeof(peer);
       
   494 		
       
   495 		while( mustListen || !sock )
       
   496 		{
       
   497 			// OTListen
       
   498 			// We do NOT block ---- right thing ? (TODO)
       
   499 			err = OTListen( server->channel, &peerinfo );
       
   500 
       
   501 			if( err )
       
   502 				goto error_return;
       
   503 			else
       
   504 			{
       
   505 				mustListen = false;
       
   506 				sock = AsyncTCPNewSocket();
       
   507 				if( ! sock )
       
   508 					goto error_return;
       
   509 			}
       
   510 		}
       
   511 		if( sock )
       
   512 		{
       
   513 			// OTAsyncOpenEndpoint
       
   514 			server->error = OTAsyncOpenEndpoint( OTCloneConfiguration( server->config ),
       
   515 				NULL, &(sock->info), (OTNotifyProcPtr)AsyncTCPNotifier, sock );
       
   516 			AsyncTCPPopEvent( sock );
       
   517 			while( !sock->error && !( sock->completion & CompleteMask( T_OPENCOMPLETE)))
       
   518 			{
       
   519 				AsyncTCPPopEvent( sock );
       
   520 			}
       
   521 			if( ! sock->channel )
       
   522 			{
       
   523 				mustListen = false;
       
   524 				goto error_return;
       
   525 			}
       
   526 			
       
   527 			// OTAccept
       
   528 			server->completion &= ~(CompleteMask(T_ACCEPTCOMPLETE));
       
   529 			server->error = OTAccept( server->channel, sock->channel, &peerinfo );
       
   530 			AsyncTCPPopEvent( server );
       
   531 			while( !(server->completion & CompleteMask(T_ACCEPTCOMPLETE)))
       
   532 			{
       
   533 				AsyncTCPPopEvent( server );
       
   534 			}
       
   535 			
       
   536 			switch( server->error )
       
   537 			{
       
   538 				case kOTLookErr:
       
   539 					switch( OTLook(server->channel ))
       
   540 					{
       
   541 						case T_LISTEN:
       
   542 							mustListen = true;
       
   543 							break;
       
   544 						case T_DISCONNECT:
       
   545 							goto error_return;
       
   546 					}
       
   547 					break;
       
   548 				case 0:
       
   549 					sock->nextListener = server->nextListener;
       
   550 					server->nextListener = sock;
       
   551 					sock->remoteAddress.host = peer.fHost;
       
   552 					sock->remoteAddress.port = peer.fPort;
       
   553 					return sock;
       
   554 					// accept successful
       
   555 					break;
       
   556 				default:
       
   557 					free( sock );
       
   558 			}
       
   559 		}
       
   560 		sock->remoteAddress.host = peer.fHost;
       
   561 		sock->remoteAddress.port = peer.fPort;
       
   562 		sock->sflag = 0;
       
   563 		sock->ready = 0;
       
   564 
       
   565 		/* The socket is ready */
       
   566 		return(sock);
       
   567 	
       
   568 	// Error; close the socket and return	
       
   569 	error_return:
       
   570 		SDLNet_TCP_Close(sock);
       
   571 		return(NULL);
       
   572 	}
       
   573 }
       
   574 
       
   575 /* Get the IP address of the remote system associated with the socket.
       
   576    If the socket is a server socket, this function returns NULL.
       
   577 */
       
   578 IPaddress *SDLNet_TCP_GetPeerAddress(TCPsocket sock)
       
   579 {
       
   580 	if ( sock->sflag ) {
       
   581 		return(NULL);
       
   582 	}
       
   583 	return(&sock->remoteAddress);
       
   584 }
       
   585 
       
   586 /* Send 'len' bytes of 'data' over the non-server socket 'sock'
       
   587    This function returns the actual amount of data sent.  If the return value
       
   588    is less than the amount of data sent, then either the remote connection was
       
   589    closed, or an unknown socket error occurred.
       
   590 */
       
   591 int SDLNet_TCP_Send(TCPsocket sock, const void *datap, int len)
       
   592 {
       
   593 	const Uint8 *data = (const Uint8 *)datap;	/* For pointer arithmetic */
       
   594 	int sent, left;
       
   595 
       
   596 	/* Server sockets are for accepting connections only */
       
   597 	if ( sock->sflag ) {
       
   598 		SDLNet_SetError("Server sockets cannot send");
       
   599 		return(-1);
       
   600 	}
       
   601 
       
   602 	/* Keep sending data until it's sent or an error occurs */
       
   603 	left = len;
       
   604 	sent = 0;
       
   605 	errno = 0;
       
   606 	do {
       
   607 		len = OTSnd(sock->channel, (void *)data, left, 0);
       
   608 		if (len == kOTFlowErr)
       
   609 			len = 0;
       
   610 		if ( len > 0 ) {
       
   611 			sent += len;
       
   612 			left -= len;
       
   613 			data += len;
       
   614 		}
       
   615 		// Do we need to ?
       
   616 		// ( masahiro minami<elsur@aaa.letter.co.jp> )
       
   617 		// (TODO)
       
   618 		//WaitNextEvent(everyEvent, &macEvent, 1, NULL);
       
   619 		//AsyncTCPPopEvent(sock);
       
   620 	} while ( (left > 0) && (len > 0) );
       
   621 
       
   622 	return(sent);
       
   623 }
       
   624 
       
   625 /* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
       
   626    and store them in the buffer pointed to by 'data'.
       
   627    This function returns the actual amount of data received.  If the return
       
   628    value is less than or equal to zero, then either the remote connection was
       
   629    closed, or an unknown socket error occurred.
       
   630 */
       
   631 int SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
       
   632 {
       
   633 	int len = 0;
       
   634 	OSStatus res;
       
   635 	/* Server sockets are for accepting connections only */
       
   636 	if ( sock->sflag ) {
       
   637 		SDLNet_SetError("Server sockets cannot receive");
       
   638 		return(-1);
       
   639 	}
       
   640 
       
   641 	do
       
   642 	{
       
   643 		res = OTRcv(sock->channel, data, maxlen-len, 0);
       
   644 		if (res > 0) {
       
   645 			len = res;
       
   646 		}
       
   647 
       
   648 #ifdef DEBUG_NET
       
   649 		if ( res != kOTNoDataErr )
       
   650 			printf("SDLNet_TCP_Recv received ; %d\n", res );
       
   651 #endif
       
   652 		
       
   653 		AsyncTCPPopEvent(sock);
       
   654 		if( res == kOTLookErr )
       
   655 		{
       
   656 			res = OTLook(sock->channel );
       
   657 			continue;
       
   658 		}
       
   659 	} while ( (len == 0) && (res == kOTNoDataErr) );
       
   660 
       
   661 	sock->ready = 0;
       
   662 	if ( len == 0 ) { /* Open Transport error */
       
   663 #ifdef DEBUG_NET
       
   664 		printf("Open Transport error: %d\n", res);
       
   665 #endif
       
   666 		return(-1);
       
   667 	}
       
   668 	return(len);
       
   669 }
       
   670 
       
   671 /* Close a TCP network socket */
       
   672 void SDLNet_TCP_Close(TCPsocket sock)
       
   673 {
       
   674 	if ( sock != NULL ) {
       
   675 		if ( sock->channel != INVALID_SOCKET ) {
       
   676 			//closesocket(sock->channel);
       
   677 			OTSndOrderlyDisconnect( sock->channel );
       
   678 		}
       
   679 		free(sock);
       
   680 	}
       
   681 }
       
   682 
       
   683 #else /* !MACOS_OPENTRANSPORT */
       
   684 
       
   685 struct _TCPsocket {
       
   686 	int ready;
       
   687 	SOCKET channel;
       
   688 	IPaddress remoteAddress;
       
   689 	IPaddress localAddress;
       
   690 	int sflag;
       
   691 };
       
   692 
       
   693 /* Open a TCP network socket
       
   694    If 'remote' is NULL, this creates a local server socket on the given port,
       
   695    otherwise a TCP connection to the remote host and port is attempted.
       
   696    The newly created socket is returned, or NULL if there was an error.
       
   697 */
       
   698 TCPsocket SDLNet_TCP_Open(IPaddress *ip)
       
   699 {
       
   700 	TCPsocket sock;
       
   701 	struct sockaddr_in sock_addr;
       
   702 
       
   703 	/* Allocate a TCP socket structure */
       
   704 	sock = (TCPsocket)malloc(sizeof(*sock));
       
   705 	if ( sock == NULL ) {
       
   706 		SDLNet_SetError("Out of memory");
       
   707 		goto error_return;
       
   708 	}
       
   709 
       
   710 	/* Open the socket */
       
   711 	sock->channel = socket(AF_INET, SOCK_STREAM, 0);
       
   712 	if ( sock->channel == INVALID_SOCKET ) {
       
   713 		SDLNet_SetError("Couldn't create socket");
       
   714 		goto error_return;
       
   715 	}
       
   716 
       
   717 	/* Connect to remote, or bind locally, as appropriate */
       
   718 	if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) ) {
       
   719 
       
   720 	// #########  Connecting to remote
       
   721 	
       
   722 		memset(&sock_addr, 0, sizeof(sock_addr));
       
   723 		sock_addr.sin_family = AF_INET;
       
   724 		sock_addr.sin_addr.s_addr = ip->host;
       
   725 		sock_addr.sin_port = ip->port;
       
   726 
       
   727 		/* Connect to the remote host */
       
   728 		if ( connect(sock->channel, (struct sockaddr *)&sock_addr,
       
   729 				sizeof(sock_addr)) == SOCKET_ERROR ) {
       
   730 			SDLNet_SetError("Couldn't connect to remote host");
       
   731 			goto error_return;
       
   732 		}
       
   733 		sock->sflag = 0;
       
   734 	} else {
       
   735 
       
   736 	// ##########  Binding locally
       
   737 
       
   738 		memset(&sock_addr, 0, sizeof(sock_addr));
       
   739 		sock_addr.sin_family = AF_INET;
       
   740 		sock_addr.sin_addr.s_addr = INADDR_ANY;
       
   741 		sock_addr.sin_port = ip->port;
       
   742 
       
   743 /*
       
   744  * Windows gets bad mojo with SO_REUSEADDR:
       
   745  * http://www.devolution.com/pipermail/sdl/2005-September/070491.html
       
   746  *   --ryan.
       
   747  */
       
   748 #ifndef WIN32
       
   749 		/* allow local address reuse */
       
   750 		{ int yes = 1;
       
   751 			setsockopt(sock->channel, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes));
       
   752 		}
       
   753 #endif
       
   754 
       
   755 		/* Bind the socket for listening */
       
   756 		if ( bind(sock->channel, (struct sockaddr *)&sock_addr,
       
   757 				sizeof(sock_addr)) == SOCKET_ERROR ) {
       
   758 			SDLNet_SetError("Couldn't bind to local port");
       
   759 			goto error_return;
       
   760 		}
       
   761 		if ( listen(sock->channel, 5) == SOCKET_ERROR ) {
       
   762 			SDLNet_SetError("Couldn't listen to local port");
       
   763 			goto error_return;
       
   764 		}
       
   765 
       
   766 		/* Set the socket to non-blocking mode for accept() */
       
   767 #if defined(__BEOS__) && defined(SO_NONBLOCK)
       
   768 		/* On BeOS r5 there is O_NONBLOCK but it's for files only */
       
   769 		{
       
   770 			long b = 1;
       
   771 			setsockopt(sock->channel, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
       
   772 		}
       
   773 #elif defined(O_NONBLOCK)
       
   774 		{
       
   775 			fcntl(sock->channel, F_SETFL, O_NONBLOCK);
       
   776 		}
       
   777 #elif defined(WIN32)
       
   778 		{
       
   779 			unsigned long mode = 1;
       
   780 			ioctlsocket (sock->channel, FIONBIO, &mode);
       
   781 		}
       
   782 #elif defined(__OS2__)
       
   783 		{
       
   784 			int dontblock = 1;
       
   785 			ioctl(sock->channel, FIONBIO, &dontblock);
       
   786 		}
       
   787 #else
       
   788 #warning How do we set non-blocking mode on other operating systems?
       
   789 #endif
       
   790 		sock->sflag = 1;
       
   791 	}
       
   792 	sock->ready = 0;
       
   793 
       
   794 #ifdef TCP_NODELAY
       
   795 	/* Set the nodelay TCP option for real-time games */
       
   796 	{ int yes = 1;
       
   797 	setsockopt(sock->channel, IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(yes));
       
   798 	}
       
   799 #endif /* TCP_NODELAY */
       
   800 
       
   801 	/* Fill in the channel host address */
       
   802 	sock->remoteAddress.host = sock_addr.sin_addr.s_addr;
       
   803 	sock->remoteAddress.port = sock_addr.sin_port;
       
   804 
       
   805 	/* The socket is ready */
       
   806 	return(sock);
       
   807 
       
   808 error_return:
       
   809 	SDLNet_TCP_Close(sock);
       
   810 	return(NULL);
       
   811 }
       
   812 
       
   813 /* Accept an incoming connection on the given server socket.
       
   814    The newly created socket is returned, or NULL if there was an error.
       
   815 */
       
   816 TCPsocket SDLNet_TCP_Accept(TCPsocket server)
       
   817 {
       
   818 	TCPsocket sock;
       
   819 	struct sockaddr_in sock_addr;
       
   820 	int sock_alen;
       
   821 
       
   822 	/* Only server sockets can accept */
       
   823 	if ( ! server->sflag ) {
       
   824 		SDLNet_SetError("Only server sockets can accept()");
       
   825 		return(NULL);
       
   826 	}
       
   827 	server->ready = 0;
       
   828 
       
   829 	/* Allocate a TCP socket structure */
       
   830 	sock = (TCPsocket)malloc(sizeof(*sock));
       
   831 	if ( sock == NULL ) {
       
   832 		SDLNet_SetError("Out of memory");
       
   833 		goto error_return;
       
   834 	}
       
   835 
       
   836 	/* Accept a new TCP connection on a server socket */
       
   837 	sock_alen = sizeof(sock_addr);
       
   838 	sock->channel = accept(server->channel, (struct sockaddr *)&sock_addr,
       
   839 #ifdef USE_GUSI_SOCKETS
       
   840 						(unsigned int *)&sock_alen);
       
   841 #else
       
   842 								&sock_alen);
       
   843 #endif
       
   844 	if ( sock->channel == SOCKET_ERROR ) {
       
   845 		SDLNet_SetError("accept() failed");
       
   846 		goto error_return;
       
   847 	}
       
   848 #ifdef WIN32
       
   849 	{
       
   850 		/* passing a zero value, socket mode set to block on */
       
   851 		unsigned long mode = 0;
       
   852 		ioctlsocket (sock->channel, FIONBIO, &mode);
       
   853 	}
       
   854 #elif defined(O_NONBLOCK)
       
   855 	{
       
   856 		int flags = fcntl(sock->channel, F_GETFL, 0);
       
   857 		fcntl(sock->channel, F_SETFL, flags & ~O_NONBLOCK);
       
   858 	}
       
   859 #endif /* WIN32 */
       
   860 	sock->remoteAddress.host = sock_addr.sin_addr.s_addr;
       
   861 	sock->remoteAddress.port = sock_addr.sin_port;
       
   862 
       
   863 	sock->sflag = 0;
       
   864 	sock->ready = 0;
       
   865 
       
   866 	/* The socket is ready */
       
   867 	return(sock);
       
   868 
       
   869 error_return:
       
   870 	SDLNet_TCP_Close(sock);
       
   871 	return(NULL);
       
   872 }
       
   873 
       
   874 /* Get the IP address of the remote system associated with the socket.
       
   875    If the socket is a server socket, this function returns NULL.
       
   876 */
       
   877 IPaddress *SDLNet_TCP_GetPeerAddress(TCPsocket sock)
       
   878 {
       
   879 	if ( sock->sflag ) {
       
   880 		return(NULL);
       
   881 	}
       
   882 	return(&sock->remoteAddress);
       
   883 }
       
   884 
       
   885 /* Send 'len' bytes of 'data' over the non-server socket 'sock'
       
   886    This function returns the actual amount of data sent.  If the return value
       
   887    is less than the amount of data sent, then either the remote connection was
       
   888    closed, or an unknown socket error occurred.
       
   889 */
       
   890 int SDLNet_TCP_Send(TCPsocket sock, const void *datap, int len)
       
   891 {
       
   892 	const Uint8 *data = (const Uint8 *)datap;	/* For pointer arithmetic */
       
   893 	int sent, left;
       
   894 
       
   895 	/* Server sockets are for accepting connections only */
       
   896 	if ( sock->sflag ) {
       
   897 		SDLNet_SetError("Server sockets cannot send");
       
   898 		return(-1);
       
   899 	}
       
   900 
       
   901 	/* Keep sending data until it's sent or an error occurs */
       
   902 	left = len;
       
   903 	sent = 0;
       
   904 	errno = 0;
       
   905 	do {
       
   906 		len = send(sock->channel, (const char *) data, left, 0);
       
   907 		if ( len > 0 ) {
       
   908 			sent += len;
       
   909 			left -= len;
       
   910 			data += len;
       
   911 		}
       
   912 	} while ( (left > 0) && ((len > 0) || (errno == EINTR)) );
       
   913 
       
   914 	return(sent);
       
   915 }
       
   916 
       
   917 /* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
       
   918    and store them in the buffer pointed to by 'data'.
       
   919    This function returns the actual amount of data received.  If the return
       
   920    value is less than or equal to zero, then either the remote connection was
       
   921    closed, or an unknown socket error occurred.
       
   922 */
       
   923 int SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
       
   924 {
       
   925 	int len;
       
   926 
       
   927 	/* Server sockets are for accepting connections only */
       
   928 	if ( sock->sflag ) {
       
   929 		SDLNet_SetError("Server sockets cannot receive");
       
   930 		return(-1);
       
   931 	}
       
   932 
       
   933 	errno = 0;
       
   934 	do {
       
   935 		len = recv(sock->channel, (char *) data, maxlen, 0);
       
   936 	} while ( errno == EINTR );
       
   937 
       
   938 	sock->ready = 0;
       
   939 	return(len);
       
   940 }
       
   941 
       
   942 /* Close a TCP network socket */
       
   943 void SDLNet_TCP_Close(TCPsocket sock)
       
   944 {
       
   945 	if ( sock != NULL ) {
       
   946 		if ( sock->channel != INVALID_SOCKET ) {
       
   947 			closesocket(sock->channel);
       
   948 		}
       
   949 		free(sock);
       
   950 	}
       
   951 }
       
   952 
       
   953 #endif /* MACOS_OPENTRANSPORT */