Updated SDL_net
This commit is contained in:
@@ -1,26 +1,25 @@
|
||||
/*
|
||||
SDL_net: An example cross-platform network library for use with SDL
|
||||
Copyright (C) 1997-2004 Sam Lantinga
|
||||
SDL_net: An example cross-platform network library for use with SDL
|
||||
Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* $Id: SDLnetTCP.c 3280 2007-07-15 05:55:42Z slouken $ */
|
||||
/* $Id$ */
|
||||
|
||||
#include "SDLnetsys.h"
|
||||
#include "SDL_net.h"
|
||||
@@ -31,657 +30,6 @@
|
||||
we'll just have two completely different sections here.
|
||||
*/
|
||||
|
||||
#ifdef MACOS_OPENTRANSPORT
|
||||
|
||||
#include <Events.h>
|
||||
#include <Threads.h>
|
||||
#include <OpenTransport.h>
|
||||
#include <OpenTptInternet.h>
|
||||
#include <OTDebug.h>
|
||||
|
||||
struct _TCPsocket {
|
||||
int ready;
|
||||
SOCKET channel;
|
||||
|
||||
// These are taken from GUSI interface.
|
||||
// I'm not sure if it's really necessary here yet
|
||||
// ( masahiro minami<elsur@aaa.letter.co.jp> )
|
||||
// ( 01/02/19 )
|
||||
OTEventCode curEvent;
|
||||
OTEventCode newEvent;
|
||||
OTEventCode event;
|
||||
OTEventCode curCompletion;
|
||||
OTEventCode newCompletion;
|
||||
OTEventCode completion;
|
||||
OSStatus error;
|
||||
TEndpointInfo info;
|
||||
Boolean readShutdown;
|
||||
Boolean writeShutdown;
|
||||
Boolean connected;
|
||||
OTConfigurationRef config; // Master configuration. you can clone this.
|
||||
TCPsocket nextListener;
|
||||
// ( end of new members --- masahiro minami<elsur@aaa.letter.co.jp>
|
||||
|
||||
IPaddress remoteAddress;
|
||||
IPaddress localAddress;
|
||||
int sflag;
|
||||
|
||||
// Maybe we don't need this---- it's from original SDL_net
|
||||
// (masahiro minami<elsur@aaa.letter.co.jp>)
|
||||
// ( 01/02/20 )
|
||||
int rcvdPassConn;
|
||||
};
|
||||
|
||||
// To be used in WaitNextEvent() here and there....
|
||||
// (010311 masahiro minami<elsur@aaa.letter.co.jp>)
|
||||
EventRecord macEvent;
|
||||
|
||||
#if TARGET_API_MAC_CARBON
|
||||
/* for Carbon */
|
||||
OTNotifyUPP notifier;
|
||||
#endif
|
||||
|
||||
/* Input: ep - endpointref on which to negotiate the option
|
||||
enableReuseIPMode - desired option setting - true/false
|
||||
Return: kOTNoError indicates that the option was successfully negotiated
|
||||
OSStatus is an error if < 0, otherwise, the status field is
|
||||
returned and is > 0.
|
||||
|
||||
IMPORTANT NOTE: The endpoint is assumed to be in synchronous more, otherwise
|
||||
this code will not function as desired
|
||||
*/
|
||||
|
||||
/*
|
||||
NOTE: As this version is written async way, we don't use this function...
|
||||
(010526) masahiro minami<elsur@aaa.letter.co.jp>
|
||||
*/
|
||||
/*
|
||||
OSStatus DoNegotiateIPReuseAddrOption(EndpointRef ep, Boolean enableReuseIPMode)
|
||||
|
||||
{
|
||||
UInt8 buf[kOTFourByteOptionSize]; // define buffer for fourByte Option size
|
||||
TOption* opt; // option ptr to make items easier to access
|
||||
TOptMgmt req;
|
||||
TOptMgmt ret;
|
||||
OSStatus err;
|
||||
|
||||
if (!OTIsSynchronous(ep))
|
||||
{
|
||||
return (-1);
|
||||
}
|
||||
opt = (TOption*)buf; // set option ptr to buffer
|
||||
req.opt.buf = buf;
|
||||
req.opt.len = sizeof(buf);
|
||||
req.flags = T_NEGOTIATE; // negotiate for option
|
||||
|
||||
ret.opt.buf = buf;
|
||||
ret.opt.maxlen = kOTFourByteOptionSize;
|
||||
|
||||
opt->level = INET_IP; // dealing with an IP Level function
|
||||
opt->name = IP_REUSEADDR;
|
||||
opt->len = kOTFourByteOptionSize;
|
||||
opt->status = 0;
|
||||
*(UInt32*)opt->value = enableReuseIPMode; // set the desired option level, true or false
|
||||
|
||||
err = OTOptionManagement(ep, &req, &ret);
|
||||
|
||||
// if no error then return the option status value
|
||||
if (err == kOTNoError)
|
||||
{
|
||||
if (opt->status != T_SUCCESS)
|
||||
err = opt->status;
|
||||
else
|
||||
err = kOTNoError;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
*/
|
||||
|
||||
/* A helper function for Mac OpenTransport support*/
|
||||
// This function is a complete copy from GUSI
|
||||
// ( masahiro minami<elsur@aaa.letter.co.jp> )
|
||||
// ( 01/02/19 )
|
||||
static __inline__ Uint32 CompleteMask(OTEventCode code)
|
||||
{
|
||||
return 1 << (code & 0x1F);
|
||||
}
|
||||
|
||||
/* Notifier for async OT calls */
|
||||
static pascal void AsyncTCPNotifier( TCPsocket sock, OTEventCode code,
|
||||
OTResult result, void* cookie )
|
||||
{
|
||||
|
||||
#ifdef DEBUG_NET
|
||||
printf("AsyncTCPNotifier got an event : 0x%8.8x\n", code );
|
||||
#endif
|
||||
|
||||
switch( code & 0x7f000000L)
|
||||
{
|
||||
case 0:
|
||||
sock->newEvent |= code;
|
||||
result = 0;
|
||||
break;
|
||||
case kCOMPLETEEVENT:
|
||||
if(!(code & 0x00FFFFE0 ))
|
||||
sock->newCompletion |= CompleteMask( code );
|
||||
if( code == T_OPENCOMPLETE )
|
||||
sock->channel = (SOCKET)(cookie);
|
||||
break;
|
||||
default:
|
||||
if( code != kOTProviderWillClose )
|
||||
result = 0;
|
||||
}
|
||||
// Do we need these ???? TODO
|
||||
// sock->SetAsyncMacError( result );
|
||||
// sock->Wakeup();
|
||||
}
|
||||
|
||||
/* Retrieve OT event */
|
||||
// This function is taken from GUSI interface.
|
||||
// ( 01/02/19 masahiro minami<elsur@aaa.letter.co.jp> )
|
||||
static void AsyncTCPPopEvent( TCPsocket sock )
|
||||
{
|
||||
// Make sure OT calls are not interrupted
|
||||
// Not sure if we really need this.
|
||||
OTEnterNotifier( sock->channel );
|
||||
|
||||
sock->event |= (sock->curEvent = sock->newEvent );
|
||||
sock->completion |= ( sock->curCompletion = sock->newCompletion );
|
||||
sock->newEvent = sock->newCompletion = 0;
|
||||
|
||||
OTLeaveNotifier( sock->channel );
|
||||
|
||||
if( sock->curEvent & T_UDERR)
|
||||
{
|
||||
// We just clear the error.
|
||||
// Should we feed this back to users ?
|
||||
// (TODO )
|
||||
OTRcvUDErr( sock->channel, NULL );
|
||||
|
||||
#ifdef DEBUG_NET
|
||||
printf("AsyncTCPPopEvent T_UDERR recognized");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Remote is disconnecting...
|
||||
if( sock->curEvent & ( T_DISCONNECT | T_ORDREL ))
|
||||
{
|
||||
sock->readShutdown = true;
|
||||
}
|
||||
|
||||
if( sock->curEvent &T_CONNECT )
|
||||
{
|
||||
// Ignore the info of remote (second parameter).
|
||||
// Shoule we care ?
|
||||
// (TODO)
|
||||
OTRcvConnect( sock->channel, NULL );
|
||||
sock->connected = 1;
|
||||
}
|
||||
|
||||
if( sock->curEvent & T_ORDREL )
|
||||
{
|
||||
OTRcvOrderlyDisconnect( sock->channel );
|
||||
}
|
||||
|
||||
if( sock->curEvent & T_DISCONNECT )
|
||||
{
|
||||
OTRcvDisconnect( sock->channel, NULL );
|
||||
}
|
||||
|
||||
// Do we need to ?
|
||||
// (masahiro minami<elsur@aaa.letter.co.jp>)
|
||||
//YieldToAnyThread();
|
||||
}
|
||||
|
||||
/* Create a new TCPsocket */
|
||||
// Because TCPsocket structure gets bigger and bigger,
|
||||
// I think we'd better have a constructor function and delete function.
|
||||
// ( 01/02/25 masahiro minami<elsur@aaa.letter.co.jp> )
|
||||
static TCPsocket AsyncTCPNewSocket()
|
||||
{
|
||||
TCPsocket sock;
|
||||
|
||||
sock = (TCPsocket)malloc(sizeof(*sock));
|
||||
if ( sock == NULL ) {
|
||||
SDLNet_SetError("Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sock->newEvent = 0;
|
||||
sock->event = 0;
|
||||
sock->curEvent = 0;
|
||||
sock->newCompletion = 0;
|
||||
sock->completion = 0;
|
||||
sock->curCompletion = 0;
|
||||
//sock->info = NULL;
|
||||
sock->readShutdown = sock->writeShutdown = sock->connected = false;
|
||||
sock->error = 0;
|
||||
sock->config = NULL;
|
||||
sock->nextListener = NULL;
|
||||
sock->sflag = 0;
|
||||
return sock;
|
||||
}
|
||||
|
||||
// hmmm.... do we need this ???
|
||||
// ( 01/02/25 masahiro minami<elsur@aaa.letter.co.jp>)
|
||||
static void AsycnTCPDeleteSocket( TCPsocket sock )
|
||||
{
|
||||
SDLNet_TCP_Close( sock );
|
||||
}
|
||||
/* Open a TCP network socket
|
||||
If 'remote' is NULL, this creates a local server socket on the given port,
|
||||
otherwise a TCP connection to the remote host and port is attempted.
|
||||
The newly created socket is returned, or NULL if there was an error.
|
||||
|
||||
( re-written by masahiro minami<elsur@aaa.letter.co.jp>
|
||||
Now endpoint is created in Async mode.
|
||||
01/02/20 )
|
||||
*/
|
||||
TCPsocket SDLNet_TCP_Open(IPaddress *ip)
|
||||
{
|
||||
EndpointRef dummy = NULL;
|
||||
|
||||
TCPsocket sock = AsyncTCPNewSocket();
|
||||
if( ! sock)
|
||||
return NULL;
|
||||
|
||||
// Determin whether bind locally, or connect to remote
|
||||
if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) )
|
||||
{
|
||||
// ######## Connect to remote
|
||||
OTResult stat;
|
||||
InetAddress inAddr;
|
||||
TBind bindReq;
|
||||
|
||||
// Open endpoint
|
||||
sock->error = OTAsyncOpenEndpoint(
|
||||
OTCreateConfiguration(kTCPName), NULL, &(sock->info),
|
||||
(OTNotifyProcPtr)(AsyncTCPNotifier),
|
||||
sock );
|
||||
|
||||
AsyncTCPPopEvent( sock );
|
||||
while( !sock->error && !( sock->completion & CompleteMask(T_OPENCOMPLETE)))
|
||||
{
|
||||
//SetThreadState( kCurrentThreadID, kReadyThreadState, kNoThreadID );
|
||||
//YieldToAnyThread();
|
||||
//WaitNextEvent(everyEvent, &macEvent, 1, NULL);
|
||||
AsyncTCPPopEvent( sock );
|
||||
}
|
||||
|
||||
if( !sock->channel )
|
||||
{
|
||||
SDLNet_SetError("OTAsyncOpenEndpoint failed --- client socket could not be opened");
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
// Set blocking mode
|
||||
// I'm not sure if this is a good solution....
|
||||
// Check out Apple's sample code, OT Virtual Server
|
||||
// ( 010314 masahiro minami<elsur@aaa.letter.co.jp>)
|
||||
|
||||
sock->error = OTSetBlocking( sock->channel );
|
||||
if( sock->error != kOTNoError )
|
||||
{
|
||||
SDLNet_SetError("OTSetBlocking() returned an error");
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
// Bind the socket
|
||||
OTInitInetAddress(&inAddr, 0, 0 );
|
||||
bindReq.addr.len = sizeof( InetAddress );
|
||||
bindReq.addr.buf = (unsigned char*)&inAddr;
|
||||
bindReq.qlen = 0;
|
||||
|
||||
sock->error = OTBind( sock->channel, &bindReq, NULL );
|
||||
AsyncTCPPopEvent(sock);
|
||||
while( !sock->error && !( sock->completion & CompleteMask(T_BINDCOMPLETE)))
|
||||
{
|
||||
//YieldToAnyThread();
|
||||
//WaitNextEvent(everyEvent, &macEvent, 1, NULL);
|
||||
AsyncTCPPopEvent(sock);
|
||||
}
|
||||
|
||||
|
||||
switch( stat = OTGetEndpointState( sock->channel ))
|
||||
{
|
||||
InetAddress inAddr;
|
||||
TCall sndCall;
|
||||
OTResult res;
|
||||
|
||||
case T_OUTCON:
|
||||
SDLNet_SetError("SDLNet_Open() failed -- T_OUTCON");
|
||||
goto error_return;
|
||||
break;
|
||||
case T_IDLE:
|
||||
sock->readShutdown = false;
|
||||
sock->writeShutdown = false;
|
||||
sock->event &=~T_CONNECT;
|
||||
|
||||
OTMemzero(&sndCall, sizeof(TCall));
|
||||
OTInitInetAddress(&inAddr, ip->port, ip->host );
|
||||
sndCall.addr.len = sizeof(InetAddress);
|
||||
sndCall.addr.buf = (unsigned char*)&inAddr;
|
||||
sock->connected = 0;
|
||||
res = OTConnect( sock->channel, &sndCall, NULL );
|
||||
AsyncTCPPopEvent(sock);
|
||||
while( sock->error == kOTNoDataErr || !sock->connected )
|
||||
AsyncTCPPopEvent(sock);
|
||||
break;
|
||||
default:
|
||||
// What's to be done ? (TODO)
|
||||
SDLNet_SetError("SDLNet_TCP_Open() failed -- EndpointState not good");
|
||||
goto error_return;
|
||||
|
||||
}
|
||||
if( !(sock->event & (T_CONNECT|T_DISCONNECT)))
|
||||
goto error_return;
|
||||
|
||||
AsyncTCPPopEvent( sock );
|
||||
while( !(sock->event & (T_CONNECT|T_DISCONNECT)))
|
||||
{
|
||||
AsyncTCPPopEvent( sock );
|
||||
}
|
||||
// OTConnect successfull
|
||||
if( sock->event & T_CONNECT)
|
||||
{
|
||||
sock->remoteAddress.host = inAddr.fHost;
|
||||
sock->remoteAddress.port = inAddr.fPort;
|
||||
sock->sflag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// OTConnect failed
|
||||
sock->event &= ~T_DISCONNECT;
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ######## Bind locally
|
||||
TBind bindReq;
|
||||
InetAddress inAddr;
|
||||
|
||||
// First, get InetInterfaceInfo.
|
||||
// I don't search for all of them.
|
||||
// Does that matter ?
|
||||
|
||||
sock->error = OTAsyncOpenEndpoint(
|
||||
OTCreateConfiguration("tilisten, tcp"), NULL, &(sock->info),
|
||||
(OTNotifyProcPtr)(AsyncTCPNotifier),
|
||||
sock);
|
||||
AsyncTCPPopEvent( sock );
|
||||
while( !sock->error && !( sock->completion & CompleteMask( T_OPENCOMPLETE)))
|
||||
{
|
||||
AsyncTCPPopEvent( sock );
|
||||
}
|
||||
|
||||
if( ! sock->channel )
|
||||
{
|
||||
SDLNet_SetError("OTAsyncOpenEndpoint failed --- server socket could not be opened");
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
// Create a master OTConfiguration
|
||||
sock->config = OTCreateConfiguration(kTCPName);
|
||||
if( ! sock->config )
|
||||
{
|
||||
SDLNet_SetError("Could not create master OTConfiguration");
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
// Bind the socket
|
||||
OTInitInetAddress(&inAddr, ip->port, 0 );
|
||||
inAddr.fAddressType = AF_INET;
|
||||
bindReq.addr.len = sizeof( InetAddress );
|
||||
bindReq.addr.buf = (unsigned char*)&inAddr;
|
||||
bindReq.qlen = 35; // This number is NOT well considered. (TODO)
|
||||
sock->localAddress.host = inAddr.fHost;
|
||||
sock->localAddress.port = inAddr.fPort;
|
||||
sock->sflag = true;
|
||||
|
||||
sock->error = OTBind( sock->channel, &bindReq, NULL );
|
||||
AsyncTCPPopEvent(sock);
|
||||
while( !sock->error && !( sock->completion & CompleteMask(T_BINDCOMPLETE)))
|
||||
{
|
||||
AsyncTCPPopEvent(sock);
|
||||
}
|
||||
if( sock->error != kOTNoError )
|
||||
{
|
||||
SDLNet_SetError("Could not bind server socket");
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if( dummy )
|
||||
OTCloseProvider( dummy );
|
||||
|
||||
}
|
||||
|
||||
sock->ready = 0;
|
||||
return sock;
|
||||
|
||||
error_return:
|
||||
if( dummy )
|
||||
OTCloseProvider( dummy );
|
||||
SDLNet_TCP_Close( sock );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Accept an incoming connection on the given server socket.
|
||||
The newly created socket is returned, or NULL if there was an error.
|
||||
*/
|
||||
TCPsocket SDLNet_TCP_Accept(TCPsocket server)
|
||||
{
|
||||
|
||||
/* Only server sockets can accept */
|
||||
if ( ! server->sflag ) {
|
||||
SDLNet_SetError("Only server sockets can accept()");
|
||||
return(NULL);
|
||||
}
|
||||
server->ready = 0;
|
||||
|
||||
/* Accept a new TCP connection on a server socket */
|
||||
{
|
||||
InetAddress peer;
|
||||
TCall peerinfo;
|
||||
TCPsocket sock = NULL;
|
||||
Boolean mustListen = false;
|
||||
OTResult err;
|
||||
|
||||
memset(&peerinfo, 0, (sizeof peerinfo ));
|
||||
peerinfo.addr.buf = (Uint8 *) &peer;
|
||||
peerinfo.addr.maxlen = sizeof(peer);
|
||||
|
||||
while( mustListen || !sock )
|
||||
{
|
||||
// OTListen
|
||||
// We do NOT block ---- right thing ? (TODO)
|
||||
err = OTListen( server->channel, &peerinfo );
|
||||
|
||||
if( err )
|
||||
goto error_return;
|
||||
else
|
||||
{
|
||||
mustListen = false;
|
||||
sock = AsyncTCPNewSocket();
|
||||
if( ! sock )
|
||||
goto error_return;
|
||||
}
|
||||
}
|
||||
if( sock )
|
||||
{
|
||||
// OTAsyncOpenEndpoint
|
||||
server->error = OTAsyncOpenEndpoint( OTCloneConfiguration( server->config ),
|
||||
NULL, &(sock->info), (OTNotifyProcPtr)AsyncTCPNotifier, sock );
|
||||
AsyncTCPPopEvent( sock );
|
||||
while( !sock->error && !( sock->completion & CompleteMask( T_OPENCOMPLETE)))
|
||||
{
|
||||
AsyncTCPPopEvent( sock );
|
||||
}
|
||||
if( ! sock->channel )
|
||||
{
|
||||
mustListen = false;
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
// OTAccept
|
||||
server->completion &= ~(CompleteMask(T_ACCEPTCOMPLETE));
|
||||
server->error = OTAccept( server->channel, sock->channel, &peerinfo );
|
||||
AsyncTCPPopEvent( server );
|
||||
while( !(server->completion & CompleteMask(T_ACCEPTCOMPLETE)))
|
||||
{
|
||||
AsyncTCPPopEvent( server );
|
||||
}
|
||||
|
||||
switch( server->error )
|
||||
{
|
||||
case kOTLookErr:
|
||||
switch( OTLook(server->channel ))
|
||||
{
|
||||
case T_LISTEN:
|
||||
mustListen = true;
|
||||
break;
|
||||
case T_DISCONNECT:
|
||||
goto error_return;
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
sock->nextListener = server->nextListener;
|
||||
server->nextListener = sock;
|
||||
sock->remoteAddress.host = peer.fHost;
|
||||
sock->remoteAddress.port = peer.fPort;
|
||||
return sock;
|
||||
// accept successful
|
||||
break;
|
||||
default:
|
||||
free( sock );
|
||||
}
|
||||
}
|
||||
sock->remoteAddress.host = peer.fHost;
|
||||
sock->remoteAddress.port = peer.fPort;
|
||||
sock->sflag = 0;
|
||||
sock->ready = 0;
|
||||
|
||||
/* The socket is ready */
|
||||
return(sock);
|
||||
|
||||
// Error; close the socket and return
|
||||
error_return:
|
||||
SDLNet_TCP_Close(sock);
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the IP address of the remote system associated with the socket.
|
||||
If the socket is a server socket, this function returns NULL.
|
||||
*/
|
||||
IPaddress *SDLNet_TCP_GetPeerAddress(TCPsocket sock)
|
||||
{
|
||||
if ( sock->sflag ) {
|
||||
return(NULL);
|
||||
}
|
||||
return(&sock->remoteAddress);
|
||||
}
|
||||
|
||||
/* Send 'len' bytes of 'data' over the non-server socket 'sock'
|
||||
This function returns the actual amount of data sent. If the return value
|
||||
is less than the amount of data sent, then either the remote connection was
|
||||
closed, or an unknown socket error occurred.
|
||||
*/
|
||||
int SDLNet_TCP_Send(TCPsocket sock, const void *datap, int len)
|
||||
{
|
||||
const Uint8 *data = (const Uint8 *)datap; /* For pointer arithmetic */
|
||||
int sent, left;
|
||||
|
||||
/* Server sockets are for accepting connections only */
|
||||
if ( sock->sflag ) {
|
||||
SDLNet_SetError("Server sockets cannot send");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Keep sending data until it's sent or an error occurs */
|
||||
left = len;
|
||||
sent = 0;
|
||||
errno = 0;
|
||||
do {
|
||||
len = OTSnd(sock->channel, (void *)data, left, 0);
|
||||
if (len == kOTFlowErr)
|
||||
len = 0;
|
||||
if ( len > 0 ) {
|
||||
sent += len;
|
||||
left -= len;
|
||||
data += len;
|
||||
}
|
||||
// Do we need to ?
|
||||
// ( masahiro minami<elsur@aaa.letter.co.jp> )
|
||||
// (TODO)
|
||||
//WaitNextEvent(everyEvent, &macEvent, 1, NULL);
|
||||
//AsyncTCPPopEvent(sock);
|
||||
} while ( (left > 0) && (len > 0) );
|
||||
|
||||
return(sent);
|
||||
}
|
||||
|
||||
/* Receive up to 'maxlen' bytes of data over the non-server socket 'sock',
|
||||
and store them in the buffer pointed to by 'data'.
|
||||
This function returns the actual amount of data received. If the return
|
||||
value is less than or equal to zero, then either the remote connection was
|
||||
closed, or an unknown socket error occurred.
|
||||
*/
|
||||
int SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
|
||||
{
|
||||
int len = 0;
|
||||
OSStatus res;
|
||||
/* Server sockets are for accepting connections only */
|
||||
if ( sock->sflag ) {
|
||||
SDLNet_SetError("Server sockets cannot receive");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
res = OTRcv(sock->channel, data, maxlen-len, 0);
|
||||
if (res > 0) {
|
||||
len = res;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_NET
|
||||
if ( res != kOTNoDataErr )
|
||||
printf("SDLNet_TCP_Recv received ; %d\n", res );
|
||||
#endif
|
||||
|
||||
AsyncTCPPopEvent(sock);
|
||||
if( res == kOTLookErr )
|
||||
{
|
||||
res = OTLook(sock->channel );
|
||||
continue;
|
||||
}
|
||||
} while ( (len == 0) && (res == kOTNoDataErr) );
|
||||
|
||||
sock->ready = 0;
|
||||
if ( len == 0 ) { /* Open Transport error */
|
||||
#ifdef DEBUG_NET
|
||||
printf("Open Transport error: %d\n", res);
|
||||
#endif
|
||||
return(-1);
|
||||
}
|
||||
return(len);
|
||||
}
|
||||
|
||||
/* Close a TCP network socket */
|
||||
void SDLNet_TCP_Close(TCPsocket sock)
|
||||
{
|
||||
if ( sock != NULL ) {
|
||||
if ( sock->channel != INVALID_SOCKET ) {
|
||||
//closesocket(sock->channel);
|
||||
OTSndOrderlyDisconnect( sock->channel );
|
||||
}
|
||||
free(sock);
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !MACOS_OPENTRANSPORT */
|
||||
|
||||
struct _TCPsocket {
|
||||
int ready;
|
||||
SOCKET channel;
|
||||
@@ -817,7 +165,7 @@ TCPsocket SDLNet_TCP_Accept(TCPsocket server)
|
||||
{
|
||||
TCPsocket sock;
|
||||
struct sockaddr_in sock_addr;
|
||||
int sock_alen;
|
||||
socklen_t sock_alen;
|
||||
|
||||
/* Only server sockets can accept */
|
||||
if ( ! server->sflag ) {
|
||||
@@ -836,12 +184,8 @@ TCPsocket SDLNet_TCP_Accept(TCPsocket server)
|
||||
/* Accept a new TCP connection on a server socket */
|
||||
sock_alen = sizeof(sock_addr);
|
||||
sock->channel = accept(server->channel, (struct sockaddr *)&sock_addr,
|
||||
#ifdef USE_GUSI_SOCKETS
|
||||
(unsigned int *)&sock_alen);
|
||||
#else
|
||||
&sock_alen);
|
||||
#endif
|
||||
if ( sock->channel == SOCKET_ERROR ) {
|
||||
if ( sock->channel == INVALID_SOCKET ) {
|
||||
SDLNet_SetError("accept() failed");
|
||||
goto error_return;
|
||||
}
|
||||
@@ -901,7 +245,7 @@ int SDLNet_TCP_Send(TCPsocket sock, const void *datap, int len)
|
||||
/* Keep sending data until it's sent or an error occurs */
|
||||
left = len;
|
||||
sent = 0;
|
||||
errno = 0;
|
||||
SDLNet_SetLastError(0);
|
||||
do {
|
||||
len = send(sock->channel, (const char *) data, left, 0);
|
||||
if ( len > 0 ) {
|
||||
@@ -909,7 +253,7 @@ int SDLNet_TCP_Send(TCPsocket sock, const void *datap, int len)
|
||||
left -= len;
|
||||
data += len;
|
||||
}
|
||||
} while ( (left > 0) && ((len > 0) || (errno == EINTR)) );
|
||||
} while ( (left > 0) && ((len > 0) || (SDLNet_GetLastError() == EINTR)) );
|
||||
|
||||
return(sent);
|
||||
}
|
||||
@@ -930,10 +274,10 @@ int SDLNet_TCP_Recv(TCPsocket sock, void *data, int maxlen)
|
||||
return(-1);
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
SDLNet_SetLastError(0);
|
||||
do {
|
||||
len = recv(sock->channel, (char *) data, maxlen, 0);
|
||||
} while ( errno == EINTR );
|
||||
} while ( SDLNet_GetLastError() == EINTR );
|
||||
|
||||
sock->ready = 0;
|
||||
return(len);
|
||||
@@ -949,5 +293,3 @@ void SDLNet_TCP_Close(TCPsocket sock)
|
||||
free(sock);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MACOS_OPENTRANSPORT */
|
||||
|
||||
Reference in New Issue
Block a user