diff options
Diffstat (limited to 'packaging/nacl/ports/sdl-net/nacl.patch')
-rw-r--r-- | packaging/nacl/ports/sdl-net/nacl.patch | 1813 |
1 files changed, 1576 insertions, 237 deletions
diff --git a/packaging/nacl/ports/sdl-net/nacl.patch b/packaging/nacl/ports/sdl-net/nacl.patch index 8d7fd7e52..f07fdcffd 100644 --- a/packaging/nacl/ports/sdl-net/nacl.patch +++ b/packaging/nacl/ports/sdl-net/nacl.patch @@ -1,251 +1,1590 @@ -diff -urN SDL_net-1.2.7/SDL_net.h SDL_net-1.2.7-nacl/SDL_net.h ---- SDL_net-1.2.7/SDL_net.h 2007-07-15 09:59:03.000000000 +0400 -+++ SDL_net-1.2.7-nacl/SDL_net.h 2013-11-03 00:01:10.871933000 +0400 -@@ -30,7 +30,7 @@ - #include "SDL_version.h" - #include "begin_code.h" +diff -Naur a/Makefile.am b/Makefile.am +--- a/Makefile.am 2007-07-21 09:26:47.000000000 +0400 ++++ b/Makefile.am 2015-11-28 01:09:05.901015000 +0300 +@@ -8,7 +8,7 @@ + libSDL_net_la_SOURCES = \ + SDLnet.c \ +- SDLnetTCP.c \ ++ SDLnetTCP.cpp \ + SDLnetUDP.c \ + SDLnetselect.c \ + SDLnetsys.h +diff -Naur a/Makefile.in b/Makefile.in +--- a/Makefile.in 2007-07-21 11:55:27.000000000 +0400 ++++ b/Makefile.in 2015-11-28 01:09:18.049151000 +0300 +@@ -244,7 +244,7 @@ + + libSDL_net_la_SOURCES = \ + SDLnet.c \ +- SDLnetTCP.c \ ++ SDLnetTCP.cpp \ + SDLnetUDP.c \ + SDLnetselect.c \ + SDLnetsys.h +diff -Naur a/SDLnetselect.c b/SDLnetselect.c +--- a/SDLnetselect.c 2007-07-02 06:04:03.000000000 +0400 ++++ b/SDLnetselect.c 2015-11-30 00:33:29.895731000 +0300 +@@ -111,109 +111,24 @@ + first. This function returns the number of sockets ready for reading, + or -1 if there was an error with the select() system call. + */ +-#ifdef MACOS_OPENTRANSPORT +-int SDLNet_CheckSockets(SDLNet_SocketSet set, Uint32 timeout) +-{ +-Uint32 stop; +-int numReady; +- +- /* Loop, polling the network devices */ +- +- stop = SDL_GetTicks() + timeout; +- +- do +- { +- OTResult status; +- size_t numBytes; +- int i; +- +- numReady = 0; +- +- for (i = set->numsockets-1;i >= 0;--i) +- { +- status = OTLook( set->sockets[i]->channel ); +- if( status > 0 ) +- { +- switch( status ) +- { +- case T_UDERR: +- OTRcvUDErr( set->sockets[i]->channel , nil); +- break; +- case T_DISCONNECT: +- OTRcvDisconnect( set->sockets[i]->channel, nil ); +- break; +- case T_ORDREL: +- OTRcvOrderlyDisconnect(set->sockets[i]->channel ); +- break; +- case T_CONNECT: +- OTRcvConnect( set->sockets[i]->channel, nil ); +- break; +- +- +- default: +- set->sockets[i]->ready = 1; +- ++numReady; +- } +- } +- else if( OTCountDataBytes(set->sockets[i]->channel, &numBytes ) != kOTNoDataErr ) +- { +- set->sockets[i]->ready = 1; +- ++numReady; +- } +- else +- set->sockets[i]->ready = 0; +- } +- +- } while (!numReady && (SDL_GetTicks() < stop)); + +- return(numReady); +-} +-#else + int SDLNet_CheckSockets(SDLNet_SocketSet set, Uint32 timeout) + { + int i; +- SOCKET maxfd; + int retval; +- struct timeval tv; +- fd_set mask; - -+#define u_int32_t uint32_t +- /* Find the largest file descriptor */ +- maxfd = 0; +- for ( i=set->numsockets-1; i>=0; --i ) { +- if ( set->sockets[i]->channel > maxfd ) { +- maxfd = set->sockets[i]->channel; +- } +- } +- +- /* Check the file descriptors for available data */ +- do { +- errno = 0; +- +- /* Set up the mask of file descriptors */ +- FD_ZERO(&mask); +- for ( i=set->numsockets-1; i>=0; --i ) { +- FD_SET(set->sockets[i]->channel, &mask); +- } + +- /* Set up the timeout */ +- tv.tv_sec = timeout/1000; +- tv.tv_usec = (timeout%1000)*1000; ++ retval = 0; - /* Set up for C function definitions, even when using C++ */ - #ifdef __cplusplus - -diff -urN /dev/null SDL_net-1.2.7-nacl/inet_addr.c ---- /dev/null 2013-11-02 22:47:51.150226312 +0400 -+++ SDL_net-1.2.7-nacl/inet_addr.c 2013-11-02 23:59:09.523930000 +0400 -@@ -0,0 +1,201 @@ -+/* $KAME: inet_addr.c,v 1.5 2001/08/20 02:32:40 itojun Exp $ */ +- /* Look! */ +- retval = select(maxfd+1, &mask, NULL, NULL, &tv); +- } while ( errno == EINTR ); +- +- /* Mark all file descriptors ready that have data available */ +- if ( retval > 0 ) { +- for ( i=set->numsockets-1; i>=0; --i ) { +- if ( FD_ISSET(set->sockets[i]->channel, &mask) ) { +- set->sockets[i]->ready = 1; +- } +- } ++ for (i = 0; i < set->numsockets; ++i) { ++ if (set->sockets[i]->ready) ++ retval++; ++ else ++#warning SDLNet_CheckSockets can work only with TCPsockets! ++ SDLNet_TCP_Recv (set->sockets[i], NULL, 0); + } +- return(retval); + ++ return retval; + } +-#endif /* MACOS_OPENTRANSPORT */ + + /* Free a set of sockets allocated by SDL_NetAllocSocketSet() */ + extern void SDLNet_FreeSocketSet(SDLNet_SocketSet set) +diff -Naur a/SDLnetTCP.c b/SDLnetTCP.c +--- a/SDLnetTCP.c 2007-07-15 09:55:42.000000000 +0400 ++++ b/SDLnetTCP.c 1970-01-01 03:00:00.000000000 +0300 +@@ -1,953 +0,0 @@ +-/* +- SDL_net: An example cross-platform network library for use with SDL +- Copyright (C) 1997-2004 Sam Lantinga +- +- 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 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. +- +- 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 +-*/ +- +-/* $Id: SDLnetTCP.c 3280 2007-07-15 05:55:42Z slouken $ */ +- +-#include "SDLnetsys.h" +-#include "SDL_net.h" +- +-/* The network API for TCP sockets */ +- +-/* Since the UNIX/Win32/BeOS code is so different from MacOS, +- 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; +- IPaddress remoteAddress; +- IPaddress localAddress; +- int sflag; +-}; +- +-/* 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. +-*/ +-TCPsocket SDLNet_TCP_Open(IPaddress *ip) +-{ +- TCPsocket sock; +- struct sockaddr_in sock_addr; +- +- /* Allocate a TCP socket structure */ +- sock = (TCPsocket)malloc(sizeof(*sock)); +- if ( sock == NULL ) { +- SDLNet_SetError("Out of memory"); +- goto error_return; +- } +- +- /* Open the socket */ +- sock->channel = socket(AF_INET, SOCK_STREAM, 0); +- if ( sock->channel == INVALID_SOCKET ) { +- SDLNet_SetError("Couldn't create socket"); +- goto error_return; +- } +- +- /* Connect to remote, or bind locally, as appropriate */ +- if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) ) { +- +- // ######### Connecting to remote +- +- memset(&sock_addr, 0, sizeof(sock_addr)); +- sock_addr.sin_family = AF_INET; +- sock_addr.sin_addr.s_addr = ip->host; +- sock_addr.sin_port = ip->port; +- +- /* Connect to the remote host */ +- if ( connect(sock->channel, (struct sockaddr *)&sock_addr, +- sizeof(sock_addr)) == SOCKET_ERROR ) { +- SDLNet_SetError("Couldn't connect to remote host"); +- goto error_return; +- } +- sock->sflag = 0; +- } else { +- +- // ########## Binding locally +- +- memset(&sock_addr, 0, sizeof(sock_addr)); +- sock_addr.sin_family = AF_INET; +- sock_addr.sin_addr.s_addr = INADDR_ANY; +- sock_addr.sin_port = ip->port; +- +-/* +- * Windows gets bad mojo with SO_REUSEADDR: +- * http://www.devolution.com/pipermail/sdl/2005-September/070491.html +- * --ryan. +- */ +-#ifndef WIN32 +- /* allow local address reuse */ +- { int yes = 1; +- setsockopt(sock->channel, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)); +- } +-#endif +- +- /* Bind the socket for listening */ +- if ( bind(sock->channel, (struct sockaddr *)&sock_addr, +- sizeof(sock_addr)) == SOCKET_ERROR ) { +- SDLNet_SetError("Couldn't bind to local port"); +- goto error_return; +- } +- if ( listen(sock->channel, 5) == SOCKET_ERROR ) { +- SDLNet_SetError("Couldn't listen to local port"); +- goto error_return; +- } +- +- /* Set the socket to non-blocking mode for accept() */ +-#if defined(__BEOS__) && defined(SO_NONBLOCK) +- /* On BeOS r5 there is O_NONBLOCK but it's for files only */ +- { +- long b = 1; +- setsockopt(sock->channel, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); +- } +-#elif defined(O_NONBLOCK) +- { +- fcntl(sock->channel, F_SETFL, O_NONBLOCK); +- } +-#elif defined(WIN32) +- { +- unsigned long mode = 1; +- ioctlsocket (sock->channel, FIONBIO, &mode); +- } +-#elif defined(__OS2__) +- { +- int dontblock = 1; +- ioctl(sock->channel, FIONBIO, &dontblock); +- } +-#else +-#warning How do we set non-blocking mode on other operating systems? +-#endif +- sock->sflag = 1; +- } +- sock->ready = 0; +- +-#ifdef TCP_NODELAY +- /* Set the nodelay TCP option for real-time games */ +- { int yes = 1; +- setsockopt(sock->channel, IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(yes)); +- } +-#endif /* TCP_NODELAY */ +- +- /* Fill in the channel host address */ +- sock->remoteAddress.host = sock_addr.sin_addr.s_addr; +- sock->remoteAddress.port = sock_addr.sin_port; +- +- /* The socket is ready */ +- return(sock); +- +-error_return: +- 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) +-{ +- TCPsocket sock; +- struct sockaddr_in sock_addr; +- int sock_alen; +- +- /* Only server sockets can accept */ +- if ( ! server->sflag ) { +- SDLNet_SetError("Only server sockets can accept()"); +- return(NULL); +- } +- server->ready = 0; +- +- /* Allocate a TCP socket structure */ +- sock = (TCPsocket)malloc(sizeof(*sock)); +- if ( sock == NULL ) { +- SDLNet_SetError("Out of memory"); +- goto error_return; +- } +- +- /* 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 ) { +- SDLNet_SetError("accept() failed"); +- goto error_return; +- } +-#ifdef WIN32 +- { +- /* passing a zero value, socket mode set to block on */ +- unsigned long mode = 0; +- ioctlsocket (sock->channel, FIONBIO, &mode); +- } +-#elif defined(O_NONBLOCK) +- { +- int flags = fcntl(sock->channel, F_GETFL, 0); +- fcntl(sock->channel, F_SETFL, flags & ~O_NONBLOCK); +- } +-#endif /* WIN32 */ +- sock->remoteAddress.host = sock_addr.sin_addr.s_addr; +- sock->remoteAddress.port = sock_addr.sin_port; +- +- sock->sflag = 0; +- sock->ready = 0; +- +- /* The socket is ready */ +- return(sock); +- +-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 = send(sock->channel, (const char *) data, left, 0); +- if ( len > 0 ) { +- sent += len; +- left -= len; +- data += len; +- } +- } while ( (left > 0) && ((len > 0) || (errno == EINTR)) ); +- +- 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; +- +- /* Server sockets are for accepting connections only */ +- if ( sock->sflag ) { +- SDLNet_SetError("Server sockets cannot receive"); +- return(-1); +- } +- +- errno = 0; +- do { +- len = recv(sock->channel, (char *) data, maxlen, 0); +- } while ( errno == EINTR ); +- +- sock->ready = 0; +- return(len); +-} +- +-/* Close a TCP network socket */ +-void SDLNet_TCP_Close(TCPsocket sock) +-{ +- if ( sock != NULL ) { +- if ( sock->channel != INVALID_SOCKET ) { +- closesocket(sock->channel); +- } +- free(sock); +- } +-} +- +-#endif /* MACOS_OPENTRANSPORT */ +diff -Naur a/SDLnetTCP.cpp b/SDLnetTCP.cpp +--- a/SDLnetTCP.cpp 1970-01-01 03:00:00.000000000 +0300 ++++ b/SDLnetTCP.cpp 2015-11-30 00:34:59.378830000 +0300 +@@ -0,0 +1,483 @@ +/* -+ * ++Copyright++ 1983, 1990, 1993 -+ * - -+ * Copyright (c) 1983, 1990, 1993 -+ * The Regents of the University of California. All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. All advertising materials mentioning features or use of this software -+ * must display the following acknowledgement: -+ * This product includes software developed by the University of -+ * California, Berkeley and its contributors. -+ * 4. Neither the name of the University nor the names of its contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -+ * SUCH DAMAGE. -+ * - -+ * Portions Copyright (c) 1993 by Digital Equipment Corporation. -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies, and that -+ * the name of Digital Equipment Corporation not be used in advertising or -+ * publicity pertaining to distribution of the document or software without -+ * specific, written prior permission. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL -+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES -+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT -+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -+ * SOFTWARE. -+ * - -+ * --Copyright-- -+ */ -+ -+#if defined(LIBC_SCCS) && !defined(lint) -+static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; -+#endif /* LIBC_SCCS and not lint */ -+#include <sys/cdefs.h> -+#include <sys/types.h> -+#include <machine/endian.h> -+ -+#include <sys/param.h> -+ -+#include <netinet/in.h> -+#include <arpa/inet.h> -+ -+#include <ctype.h> -+#include <errno.h> -+#include <string.h> -+#include <stdlib.h> ++ SDL_net: An example cross-platform network library for use with SDL ++ Copyright (C) 1997-2004 Sam Lantinga + -+/* -+ * ASCII internet address interpretation routine. -+ * The value returned is in network order. -+ */ -+in_addr_t /* XXX should be struct in_addr :( */ -+inet_addr(cp) -+ const char *cp; ++ 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 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. ++ ++ 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 ++*/ ++ ++/* $Id: SDLnetTCP.c 3280 2007-07-15 05:55:42Z slouken $ */ ++ ++#include "SDLnetsys.h" ++#include "SDL_net.h" ++ ++#include "ppapi_simple/ps.h" ++#include "ppapi/cpp/tcp_socket.h" ++#include "ppapi/cpp/instance_handle.h" ++#include "ppapi/cpp/message_loop.h" ++#include "ppapi/cpp/instance.h" ++#include "ppapi/c/ppb_net_address.h" ++#include "ppapi/cpp/var.h" ++#include "ppapi/utility/completion_callback_factory.h" ++ ++#include "pthread.h" ++#include <condition_variable> ++#include <mutex> ++ ++/* The network API for TCP sockets */ ++ ++#define BUFFER_SIZE 2000 ++ ++struct _TCPsocket { ++ int ready; ++ pp::TCPSocket channel; ++ IPaddress remoteAddress; ++ IPaddress localAddress; ++ int sflag; ++ ++ bool readInProgress; ++ int bufferAmount; ++ int bufferOffset; ++ char buffer [BUFFER_SIZE]; ++}; ++ ++class SDLNetSynchronizer { ++ public: ++ pp::CompletionCallbackFactory <SDLNetSynchronizer> factory; ++ pp::InstanceHandle handle; ++ pp::Instance instance; ++ ++ static pp::MessageLoop loop; ++ ++ pp::TCPSocket sock_result; ++ int32_t result; ++ bool ready; ++ std::condition_variable cv; ++ std::mutex mtx; ++ ++ SDLNetSynchronizer () : factory (this), handle (PSGetInstanceId ()), instance (PSGetInstanceId ()) { ++ ready = false; ++ if (loop.is_null ()) ++ loop = pp::MessageLoop::GetForMainThread (); ++ } ++ ++ int32_t Connect (pp::TCPSocket &sock, IPaddress *ip_addr) { ++ int32_t code; ++ PP_NetAddress_IPv4 ipv4_addr; ++ IpToIpv4 (ip_addr, &ipv4_addr); ++ ++ pp::CompletionCallback cb = factory.NewCallback ( ++ &SDLNetSynchronizer::ConnectWork, ++ sock, ++ pp::NetAddress (handle, ipv4_addr) ++ ); ++ ++ loop.PostWork (cb, 0); ++ wait (); ++ ++ return result; ++ } ++ ++ int32_t Bind (pp::TCPSocket &sock, IPaddress *ip_addr) { ++ PP_NetAddress_IPv4 ipv4_addr; ++ IpToIpv4 (ip_addr, &ipv4_addr); ++ ++ ++ pp::CompletionCallback cb = factory.NewCallback ( ++ &SDLNetSynchronizer::BindWork, ++ sock, ++ pp::NetAddress (handle, ipv4_addr) ++ ); ++ ++ loop.PostWork (cb, 0); ++ ++ wait (); ++ return result; ++ } ++ ++ int32_t Listen (pp::TCPSocket &sock, int32_t backlog) { ++ ++ pp::CompletionCallback cb = factory.NewCallback ( ++ &SDLNetSynchronizer::ListenWork, ++ sock, backlog ++ ); ++ ++ loop.PostWork (cb, 0); ++ ++ wait (); ++ return result; ++ } ++ ++ void WriteWork (int32_t result, pp::TCPSocket &sock, const char *data, size_t size) { ++ sock.Write ( ++ data, size, ++ factory.NewCallback (&SDLNetSynchronizer::resultCallback) ++ ); ++ } ++ ++ int32_t Write (pp::TCPSocket &sock, const char *data, size_t size) { ++ pp::CompletionCallback cb = factory.NewCallback ( ++ &SDLNetSynchronizer::WriteWork, ++ sock, data, size ++ ); ++ ++ loop.PostWork (cb, 0); ++ ++ wait (); ++ return result; ++ } ++ ++ void ReadAsyncCallback (int32_t result, TCPsocket sock) { ++ if (result <= 0) ++ return; ++ ++ sock->bufferOffset = 0; ++ sock->bufferAmount = result; ++ sock->ready = 1; ++ sock->readInProgress = false; ++ } ++ ++ void ReadAsyncWork (int32_t result, TCPsocket sock) { ++ sock->channel.Read ( ++ sock->buffer, BUFFER_SIZE, ++ factory.NewCallback (&SDLNetSynchronizer::ReadAsyncCallback, sock) ++ ); ++ } ++ ++ void ReadAsync (TCPsocket sock) { ++ pp::CompletionCallback cb = factory.NewCallback ( ++ &SDLNetSynchronizer::ReadAsyncWork, ++ sock ++ ); ++ ++ sock->readInProgress = true; ++ loop.PostWork (cb, 0); ++ } ++ ++ void AcceptWork (int32_t result, pp::TCPSocket &sock) { ++ sock.Accept ( ++ factory.NewCallbackWithOutput (&SDLNetSynchronizer::acceptCallback) ++ ); ++ } ++ ++ pp::TCPSocket Accept (pp::TCPSocket &sock, int32_t &out) { ++ pp::CompletionCallback cb = factory.NewCallback ( ++ &SDLNetSynchronizer::AcceptWork, ++ sock ++ ); ++ ++ loop.PostWork (cb, 0); ++ ++ wait (); ++ out = result; ++ return sock_result; ++ } ++ ++ void IpToIpv4 (IPaddress *ip_addr, PP_NetAddress_IPv4 *ipv4_addr) { ++ ipv4_addr->port = ip_addr->port; ++ for (int i = 0; i < 4; ++i) ++ ipv4_addr->addr[i] = (ip_addr->host >> (8 * i)) & 0xFF; ++ } ++ ++ void NetToIp (pp::NetAddress net_addr, IPaddress *ip_addr) { ++ PP_NetAddress_IPv4 ipv4_addr; ++ net_addr.DescribeAsIPv4Address (&ipv4_addr); ++ Ipv4ToIp (&ipv4_addr, ip_addr); ++ } ++ ++ void Ipv4ToIp (PP_NetAddress_IPv4 *ipv4_addr, IPaddress *ip_addr) { ++ ip_addr->port = ipv4_addr->port; ++ ip_addr->host = 0; ++ for (int i = 0; i < 4; ++i) ++ ip_addr->host ^= (((uint32_t) ipv4_addr->addr[i]) << (8 * i)); ++ } ++ ++ void postMessage (std::string msg) { ++ instance.PostMessage (pp::Var (msg)); ++ } ++ ++ void postMessage (int32_t msg) { ++ instance.PostMessage (pp::Var (msg)); ++ } ++ ++ private: ++ void ConnectWork (int32_t result, pp::TCPSocket &sock, pp::NetAddress &addr) { ++ sock.Connect ( ++ addr, ++ factory.NewCallback (&SDLNetSynchronizer::resultCallback) ++ ); ++ } ++ ++ void BindWork (int32_t result, pp::TCPSocket &sock, pp::NetAddress &addr) { ++ sock.Bind ( ++ addr, ++ factory.NewCallback (&SDLNetSynchronizer::resultCallback) ++ ); ++ } ++ ++ void ListenWork (int32_t result, pp::TCPSocket &sock, int32_t backlog) { ++ sock.Listen ( ++ backlog, ++ factory.NewCallback (&SDLNetSynchronizer::resultCallback) ++ ); ++ } ++ ++ void resultCallback (int32_t res) { ++ result = res; ++ unlock (); ++ } ++ ++ void acceptCallback (int32_t res, pp::TCPSocket sock) { ++ result = res; ++ sock_result = sock; ++ ++ unlock(); ++ } ++ ++ void wait () { ++ std::unique_lock <std::mutex> lck (mtx); ++ while (!ready) ++ cv.wait (lck); ++ ready = false; ++ } ++ ++ void unlock () { ++ std::unique_lock <std::mutex> lck (mtx); ++ ready = true; ++ cv.notify_all (); ++ } ++}; ++ ++pp::MessageLoop SDLNetSynchronizer::loop = pp::MessageLoop (); ++ ++SDLNetSynchronizer *__read_syncer = NULL; ++ ++/* 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. ++*/ ++TCPsocket SDLNet_TCP_Open (IPaddress *ip) +{ -+ struct in_addr val; ++ TCPsocket sock; ++ SDLNetSynchronizer syncer; ++ ++ /* Allocate a TCP socket structure */ ++ sock = (TCPsocket)malloc (sizeof (*sock)); ++ if ( sock == NULL ) { ++ SDLNet_SetError ("Out of memory"); ++ goto error_return; ++ } ++ ++ sock->channel = pp::TCPSocket (syncer.handle); ++ ++ /* Connect to remote, or bind locally, as appropriate */ ++ if ( (ip->host != INADDR_NONE) && (ip->host != INADDR_ANY) ) { ++ ++ // ######### Connecting to remote ++ ++ /* Connect to the remote host */ ++ if ( syncer.Connect (sock->channel, ip) != PP_OK ) { ++ SDLNet_SetError("Couldn't connect to remote host"); ++ goto error_return; ++ } ++ sock->sflag = 0; ++ ++ } else { ++ ++ // ########## Binding locally ++ ++ /* Bind the socket for listening */ ++ if ( syncer.Bind (sock->channel, ip) != PP_OK ) { ++ SDLNet_SetError("Couldn't bind to local port"); ++ goto error_return; ++ } ++ ++ if ( syncer.Listen (sock->channel, 5) != PP_OK ) { ++ SDLNet_SetError("Couldn't listen to local port"); ++ goto error_return; ++ } ++ ++ /* Set the socket to non-blocking mode for accept() */ ++ ++ { ++ /* In nacl O_NONBLOCK is defined */ ++ // fcntl(sock->channel, F_SETFL, O_NONBLOCK); ++ } ++ ++ sock->sflag = 1; ++ } + -+ if (inet_aton(cp, &val)) -+ return (val.s_addr); -+ return (INADDR_NONE); ++ sock->readInProgress = 0; ++ sock->ready = 0; ++ sock->bufferOffset = sock->bufferAmount = 0; ++ ++#ifdef TCP_NODELAY ++ /* Set the nodelay TCP option for real-time games */ ++ { int yes = 1; ++ setsockopt(sock->channel, IPPROTO_TCP, TCP_NODELAY, (char*)&yes, sizeof(yes)); ++ } ++#endif /* TCP_NODELAY */ ++ ++ /* Fill in the channel host address */ ++ sock->remoteAddress = *ip; ++ ++ /* The socket is ready */ ++ return(sock); ++ ++error_return: ++ SDLNet_TCP_Close(sock); ++ return(NULL); +} + -+/* -+ * Check whether "cp" is a valid ASCII representation -+ * of an Internet address and convert to a binary address. -+ * Returns 1 if the address is valid, 0 if not. -+ * This replaces inet_addr, the return value from which -+ * cannot distinguish between failure and a local broadcast address. -+ */ -+int -+inet_aton(cp, addr) -+ const char *cp; -+ struct in_addr *addr; ++/* 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) +{ -+ u_long parts[4]; -+ in_addr_t val; -+ char *c; -+ char *endptr; -+ int gotend, n; -+ -+ c = (char *)cp; -+ n = 0; -+ /* -+ * Run through the string, grabbing numbers until -+ * the end of the string, or some error -+ */ -+ gotend = 0; -+ while (!gotend) { -+ errno = 0; -+ val = strtoul(c, &endptr, 0); -+ -+ if (errno == ERANGE) /* Fail completely if it overflowed. */ -+ return (0); -+ -+ /* -+ * If the whole string is invalid, endptr will equal -+ * c.. this way we can make sure someone hasn't -+ * gone '.12' or something which would get past -+ * the next check. -+ */ -+ if (endptr == c) -+ return (0); -+ parts[n] = val; -+ c = endptr; -+ -+ /* Check the next character past the previous number's end */ -+ switch (*c) { -+ case '.' : -+ /* Make sure we only do 3 dots .. */ -+ if (n == 3) /* Whoops. Quit. */ -+ return (0); -+ n++; -+ c++; -+ break; -+ -+ case '\0': -+ gotend = 1; -+ break; -+ -+ default: -+ if (isspace((unsigned char)*c)) { -+ gotend = 1; -+ break; -+ } else -+ return (0); /* Invalid character, so fail */ -+ } -+ -+ } -+ -+ /* -+ * Concoct the address according to -+ * the number of parts specified. -+ */ -+ -+ switch (n) { -+ case 0: /* a -- 32 bits */ -+ /* -+ * Nothing is necessary here. Overflow checking was -+ * already done in strtoul(). -+ */ -+ break; -+ case 1: /* a.b -- 8.24 bits */ -+ if (val > 0xffffff || parts[0] > 0xff) -+ return (0); -+ val |= parts[0] << 24; -+ break; -+ -+ case 2: /* a.b.c -- 8.8.16 bits */ -+ if (val > 0xffff || parts[0] > 0xff || parts[1] > 0xff) -+ return (0); -+ val |= (parts[0] << 24) | (parts[1] << 16); -+ break; -+ -+ case 3: /* a.b.c.d -- 8.8.8.8 bits */ -+ if (val > 0xff || parts[0] > 0xff || parts[1] > 0xff || -+ parts[2] > 0xff) -+ return (0); -+ val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); -+ break; -+ } -+ -+ if (addr != NULL) -+ addr->s_addr = htonl(val); -+ return (1); ++ TCPsocket sock; ++ SDLNetSynchronizer syncer; ++ int acc_res; ++ ++ /* Only server sockets can accept */ ++ if ( ! server->sflag ) { ++ SDLNet_SetError("Only server sockets can accept()"); ++ return(NULL); ++ } ++ server->ready = 0; ++ ++ /* Allocate a TCP socket structure */ ++ sock = (TCPsocket)malloc (sizeof (*sock)); ++ if ( sock == NULL ) { ++ SDLNet_SetError("Out of memory"); ++ goto error_return; ++ } ++ ++ /* Accept a new TCP connection on a server socket */ ++ sock->channel = syncer.Accept (server->channel, acc_res); ++ ++ if ( acc_res != PP_OK ) { ++ SDLNet_SetError("accept() failed"); ++ goto error_return; ++ } ++ ++ ++ { ++ /* int flags = fcntl(sock->channel, F_GETFL, 0); ++ fcntl(sock->channel, F_SETFL, flags & ~O_NONBLOCK); */ ++ } ++ ++ syncer.NetToIp ((sock->channel).GetRemoteAddress (), &sock->remoteAddress); ++ ++ sock->sflag = 0; ++ sock->ready = 0; ++ ++ /* The socket is ready */ ++ return(sock); ++ ++error_return: ++ SDLNet_TCP_Close(sock); ++ return(NULL); +} + -+/* -+ * Weak aliases for applications that use certain private entry points, -+ * and fail to include <arpa/inet.h>. -+ */ -+#undef inet_addr -+__weak_reference(__inet_addr, inet_addr); -+#undef inet_aton -+__weak_reference(__inet_aton, inet_aton); - -diff -urN SDL_net-1.2.7/SDLnet.c SDL_net-1.2.7-nacl/SDLnet.c ---- SDL_net-1.2.7/SDLnet.c 2007-07-02 06:04:03.000000000 +0400 -+++ SDL_net-1.2.7-nacl/SDLnet.c 2013-11-03 00:43:36.859998000 +0400 -@@ -29,6 +29,8 @@ - #include "SDLnetsys.h" - #include "SDL_net.h" - -+#include "inet_addr.c" ++/* 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); ++} + - - const SDL_version *SDLNet_Linked_Version(void) - { -@@ -344,7 +346,7 @@ - - hp = gethostbyname(host); - if ( hp ) { -- memcpy(&address->host,hp->h_addr,hp->h_length); -+ memcpy(&address->host,hp->h_addr_list[0],hp->h_length); - } else { - retval = -1; - } -@@ -368,8 +370,7 @@ - const char *SDLNet_ResolveIP(IPaddress *ip) - { - struct hostent *hp; -- -- hp = gethostbyaddr((char *)&ip->host, 4, AF_INET); -+ hp = NULL; - if ( hp != NULL ) { - return hp->h_name; - } - ++/* 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) ++{ ++ SDLNetSynchronizer syncer; ++ Uint8 *data = (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 = syncer.Write (sock->channel, (const char *) data, left); ++ if ( len > 0 ) { ++ sent += len; ++ left -= len; ++ data += len; ++ } ++ } while ( (left > 0) && (len >= 0 || errno == EINTR) ); ++ ++ 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) ++{ ++ SDLNetSynchronizer syncer; ++ int len = 0; ++ ++ /* Server sockets are for accepting connections only */ ++ if ( sock->sflag ) { ++ SDLNet_SetError("Server sockets cannot receive"); ++ return(-1); ++ } ++ ++ if ( sock->ready && maxlen > 0 ) { ++ len = std::min (sock->bufferAmount - sock->bufferOffset, maxlen); ++ memcpy (data, sock->buffer + sock->bufferOffset, len); ++ sock->bufferOffset += len; ++ if ( sock->bufferOffset == sock->bufferAmount ) ++ sock->ready = 0; ++ } ++ ++ if ( sock->ready == 0 && sock->readInProgress == 0) { ++ if (__read_syncer == NULL) ++ __read_syncer = new SDLNetSynchronizer (); ++ __read_syncer->ReadAsync (sock); ++ } ++ ++ return(len); ++} ++ ++/* Close a TCP network socket */ ++void SDLNet_TCP_Close(TCPsocket sock) ++{ ++ SDLNetSynchronizer syncer; ++ if ( sock != NULL ) { ++ sock->channel.Close (); ++ free (sock); ++ } ++} |