diff -r 09bcdcd78379 -r 86984c1034a5 project_files/Android-build/SDL-android-project/jni/sdl_net/SDLnetUDP.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/Android-build/SDL-android-project/jni/sdl_net/SDLnetUDP.c Thu Jun 23 14:30:04 2011 +0200 @@ -0,0 +1,797 @@ +/* + 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: SDLnetUDP.c 1192 2004-01-04 17:41:55Z slouken $ */ + +#include "SDLnetsys.h" +#include "SDL_net.h" +#ifdef MACOS_OPENTRANSPORT +#include +#endif + +struct _UDPsocket { + int ready; + SOCKET channel; + IPaddress address; + +#ifdef MACOS_OPENTRANSPORT + OTEventCode newEvent; + OTEventCode event; + OTEventCode curEvent; + OTEventCode newCompletion; + OTEventCode completion; + OTEventCode curCompletion; + TEndpointInfo info; + Boolean readShutdown; + Boolean writeShutdown; + OSStatus error; + OTConfigurationRef config; // Master configuration. you can clone this. +#endif /* MACOS_OPENTRANSPORT */ + + struct UDP_channel { + int numbound; + IPaddress address[SDLNET_MAX_UDPADDRESSES]; + } binding[SDLNET_MAX_UDPCHANNELS]; +}; + +#ifdef MACOS_OPENTRANSPORT + +/* A helper function for Mac OpenTransport support*/ +// This function is a complete copy from GUSI +// ( masahiro minami ) +// ( 01/02/19 ) +// +// I guess this function should be put in SDLnet.c +// ( 010315 masahiro minami) +// (TODO) +static __inline__ Uint32 CompleteMask(OTEventCode code) +{ + return 1 << (code & 0x1F); +} + +/* Notifier for async OT calls */ +// This function is completely same as AsyncTCPNotifier, +// except for the argument, UDPsocket / TCPsocket +// ( 010315 masahiro minami) +static pascal void AsyncUDPNotifier( UDPsocket sock, OTEventCode code, + OTResult result, void* cookie ) +{ + 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(); + + // Do we need to ? + //YieldToAnyThread(); +} + +/* Retrieve OT event */ +// This function is completely same as AsyncTCPPopEvent, +// except for the argument, UDPsocket / TCPsocket +// ( 010315 masahiro minami) +static void AsyncUDPPopEvent( UDPsocket 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 ); + } + + // 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 ); + } + + if( sock->curEvent & T_ORDREL ) + { + OTRcvOrderlyDisconnect( sock->channel ); + } + + if( sock->curEvent & T_DISCONNECT ) + { + OTRcvDisconnect( sock->channel, NULL ); + } + + // Should we ?? + // (010318 masahiro minami + //YieldToAnyThread(); +} + +/* Create a new UDPsocket */ +// Because TCPsocket structure gets bigger and bigger, +// I think we'd better have a constructor function and delete function. +// ( 01/02/25 masahiro minami ) +/*static*/ UDPsocket AsyncUDPNewSocket() +{ + UDPsocket sock; + + sock = (UDPsocket)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 = false; + sock->error = 0; + sock->config = NULL; + + return sock; +} + +#endif /* MACOS_OPENTRANSPORT */ + +/* Allocate/free a single UDP packet 'size' bytes long. + The new packet is returned, or NULL if the function ran out of memory. + */ +extern UDPpacket *SDLNet_AllocPacket(int size) +{ + UDPpacket *packet; + int error; + + + error = 1; + packet = (UDPpacket *)malloc(sizeof(*packet)); + if ( packet != NULL ) { + packet->maxlen = size; + packet->data = (Uint8 *)malloc(size); + if ( packet->data != NULL ) { + error = 0; + } + } + if ( error ) { + SDLNet_FreePacket(packet); + packet = NULL; + } + return(packet); +} +int SDLNet_ResizePacket(UDPpacket *packet, int newsize) +{ + Uint8 *newdata; + + newdata = (Uint8 *)malloc(newsize); + if ( newdata != NULL ) { + free(packet->data); + packet->data = newdata; + packet->maxlen = newsize; + } + return(packet->maxlen); +} +extern void SDLNet_FreePacket(UDPpacket *packet) +{ + if ( packet ) { + if ( packet->data ) + free(packet->data); + free(packet); + } +} + +/* Allocate/Free a UDP packet vector (array of packets) of 'howmany' packets, + each 'size' bytes long. + A pointer to the packet array is returned, or NULL if the function ran out + of memory. + */ +UDPpacket **SDLNet_AllocPacketV(int howmany, int size) +{ + UDPpacket **packetV; + + packetV = (UDPpacket **)malloc((howmany+1)*sizeof(*packetV)); + if ( packetV != NULL ) { + int i; + for ( i=0; ierror = OTAsyncOpenEndpoint( + OTCreateConfiguration(kUDPName),0, &(sock->info), + (OTNotifyProcPtr)AsyncUDPNotifier, sock ); + AsyncUDPPopEvent( sock ); + while( !sock->error && !( sock->completion & CompleteMask(T_OPENCOMPLETE))) + { + AsyncUDPPopEvent( sock ); + } + if( sock->error ) + { + SDLNet_SetError("Could not open UDP socket"); + goto error_return; + } + // Should we ?? + // (01/05/03 minami + OTSetBlocking( sock->channel ); + } +#else + sock->channel = socket(AF_INET, SOCK_DGRAM, 0); +#endif /* MACOS_OPENTRANSPORT */ + + if ( sock->channel == INVALID_SOCKET ) + { + SDLNet_SetError("Couldn't create socket"); + goto error_return; + } + +#ifdef MACOS_OPENTRANSPORT + { + InetAddress required, assigned; + TBind req_addr, assigned_addr; + OSStatus status; + InetInterfaceInfo info; + + memset(&assigned_addr, 0, sizeof(assigned_addr)); + assigned_addr.addr.maxlen = sizeof(assigned); + assigned_addr.addr.len = sizeof(assigned); + assigned_addr.addr.buf = (UInt8 *) &assigned; + + if ( port ) { + status = OTInetGetInterfaceInfo( &info, kDefaultInetInterface ); + if( status != kOTNoError ) + goto error_return; + OTInitInetAddress(&required, port, info.fAddress ); + req_addr.addr.maxlen = sizeof( required ); + req_addr.addr.len = sizeof( required ); + req_addr.addr.buf = (UInt8 *) &required; + + sock->error = OTBind(sock->channel, &req_addr, &assigned_addr); + } else { + sock->error = OTBind(sock->channel, nil, &assigned_addr ); + } + AsyncUDPPopEvent(sock); + + while( !sock->error && !(sock->completion & CompleteMask(T_BINDCOMPLETE))) + { + AsyncUDPPopEvent(sock); + } + if (sock->error != noErr) + { + SDLNet_SetError("Couldn't bind to local port, OTBind() = %d",(int) status); + goto error_return; + } + + sock->address.host = assigned.fHost; + sock->address.port = assigned.fPort; + +#ifdef DEBUG_NET + printf("UDP open host = %d, port = %d\n", assigned.fHost, assigned.fPort ); +#endif + } +#else + /* Bind locally, if appropriate */ + if ( port ) + { + struct sockaddr_in sock_addr; + 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 = SDL_SwapBE16(port); + + /* 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; + } + /* Fill in the channel host address */ + sock->address.host = sock_addr.sin_addr.s_addr; + sock->address.port = sock_addr.sin_port; + } + +#ifdef SO_BROADCAST + /* Allow LAN broadcasts with the socket */ + { int yes = 1; + setsockopt(sock->channel, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(yes)); + } +#endif +#endif /* MACOS_OPENTRANSPORT */ + + /* The socket is ready */ + + return(sock); + +error_return: +#ifdef MACOS_OPENTRANSPORT + if( dummy ) + OTCloseProvider( dummy ); +#endif + SDLNet_UDP_Close(sock); + + return(NULL); +} + +/* Verify that the channel is in the valid range */ +static int ValidChannel(int channel) +{ + if ( (channel < 0) || (channel >= SDLNET_MAX_UDPCHANNELS) ) { + SDLNet_SetError("Invalid channel"); + return(0); + } + return(1); +} + +/* Bind the address 'address' to the requested channel on the UDP socket. + If the channel is -1, then the first unbound channel will be bound with + the given address as it's primary address. + If the channel is already bound, this new address will be added to the + list of valid source addresses for packets arriving on the channel. + If the channel is not already bound, then the address becomes the primary + address, to which all outbound packets on the channel are sent. + This function returns the channel which was bound, or -1 on error. +*/ +int SDLNet_UDP_Bind(UDPsocket sock, int channel, IPaddress *address) +{ + struct UDP_channel *binding; + + if ( channel == -1 ) { + for ( channel=0; channel < SDLNET_MAX_UDPCHANNELS; ++channel ) { + binding = &sock->binding[channel]; + if ( binding->numbound < SDLNET_MAX_UDPADDRESSES ) { + break; + } + } + } else { + if ( ! ValidChannel(channel) ) { + return(-1); + } + binding = &sock->binding[channel]; + } + if ( binding->numbound == SDLNET_MAX_UDPADDRESSES ) { + SDLNet_SetError("No room for new addresses"); + return(-1); + } + binding->address[binding->numbound++] = *address; + return(channel); +} + +/* Unbind all addresses from the given channel */ +void SDLNet_UDP_Unbind(UDPsocket sock, int channel) +{ + if ( (channel >= 0) && (channel < SDLNET_MAX_UDPCHANNELS) ) { + sock->binding[channel].numbound = 0; + } +} + +/* Get the primary IP address of the remote system associated with the + socket and channel. + If the channel is not bound, this function returns NULL. + */ +IPaddress *SDLNet_UDP_GetPeerAddress(UDPsocket sock, int channel) +{ + IPaddress *address; + + address = NULL; + switch (channel) { + case -1: + /* Return the actual address of the socket */ + address = &sock->address; + break; + default: + /* Return the address of the bound channel */ + if ( ValidChannel(channel) && + (sock->binding[channel].numbound > 0) ) { + address = &sock->binding[channel].address[0]; + } + break; + } + return(address); +} + +/* Send a vector of packets to the the channels specified within the packet. + If the channel specified in the packet is -1, the packet will be sent to + the address in the 'src' member of the packet. + Each packet will be updated with the status of the packet after it has + been sent, -1 if the packet send failed. + This function returns the number of packets sent. +*/ +int SDLNet_UDP_SendV(UDPsocket sock, UDPpacket **packets, int npackets) +{ + int numsent, i, j; + struct UDP_channel *binding; + int status; +#ifndef MACOS_OPENTRANSPORT + int sock_len; + struct sockaddr_in sock_addr; + + /* Set up the variables to send packets */ + sock_len = sizeof(sock_addr); +#endif + + numsent = 0; + for ( i=0; ichannel < 0 ) + { +#ifdef MACOS_OPENTRANSPORT + TUnitData OTpacket; + InetAddress address; + + memset(&OTpacket, 0, sizeof(OTpacket)); + OTpacket.addr.buf = (Uint8 *)&address; + OTpacket.addr.len = (sizeof address); + OTpacket.udata.buf = packets[i]->data; + OTpacket.udata.len = packets[i]->len; + OTInitInetAddress(&address, packets[i]->address.port, packets[i]->address.host); +#ifdef DEBUG_NET + printf("Packet send address: 0x%8.8x:%d, length = %d\n", packets[i]->address.host, packets[i]->address.port, packets[i]->len); +#endif + + status = OTSndUData(sock->channel, &OTpacket); +#ifdef DEBUG_NET + printf("SDLNet_UDP_SendV OTSndUData return value is ;%d\n", status ); +#endif + + AsyncUDPPopEvent( sock ); + packets[i]->status = status; + + if (status == noErr) + { + ++numsent; + } +#else + sock_addr.sin_addr.s_addr = packets[i]->address.host; + sock_addr.sin_port = packets[i]->address.port; + sock_addr.sin_family = AF_INET; + status = sendto(sock->channel, + packets[i]->data, packets[i]->len, 0, + (struct sockaddr *)&sock_addr,sock_len); + if ( status >= 0 ) + { + packets[i]->status = status; + ++numsent; + } +#endif /* MACOS_OPENTRANSPORT */ + } + else + { + /* Send to each of the bound addresses on the channel */ +#ifdef DEBUG_NET + printf("SDLNet_UDP_SendV sending packet to channel = %d\n", packets[i]->channel ); +#endif + + binding = &sock->binding[packets[i]->channel]; + + for ( j=binding->numbound-1; j>=0; --j ) + { +#ifdef MACOS_OPENTRANSPORT + TUnitData OTpacket; + InetAddress address; + + OTInitInetAddress(&address, binding->address[j].port,binding->address[j].host); +#ifdef DEBUG_NET + printf("Packet send address: 0x%8.8x:%d, length = %d\n", binding->address[j].host, binding->address[j].port, packets[i]->len); +#endif + memset(&OTpacket, 0, sizeof(OTpacket)); + OTpacket.addr.buf = (Uint8 *)&address; + OTpacket.addr.len = (sizeof address); + OTpacket.udata.buf = packets[i]->data; + OTpacket.udata.len = packets[i]->len; + + status = OTSndUData(sock->channel, &OTpacket); +#ifdef DEBUG_NET + printf("SDLNet_UDP_SendV OTSndUData returne value is;%d\n", status ); +#endif + AsyncUDPPopEvent(sock); + packets[i]->status = status; + + if (status == noErr) + { + ++numsent; + } + +#else + sock_addr.sin_addr.s_addr = binding->address[j].host; + sock_addr.sin_port = binding->address[j].port; + sock_addr.sin_family = AF_INET; + status = sendto(sock->channel, + packets[i]->data, packets[i]->len, 0, + (struct sockaddr *)&sock_addr,sock_len); + if ( status >= 0 ) + { + packets[i]->status = status; + ++numsent; + } +#endif /* MACOS_OPENTRANSPORT */ + } + } + } + + return(numsent); +} + +int SDLNet_UDP_Send(UDPsocket sock, int channel, UDPpacket *packet) +{ + /* This is silly, but... */ + packet->channel = channel; + return(SDLNet_UDP_SendV(sock, &packet, 1)); +} + +/* Returns true if a socket is has data available for reading right now */ +static int SocketReady(SOCKET sock) +{ + int retval = 0; +#ifdef MACOS_OPENTRANSPORT + OTResult status; +#else + struct timeval tv; + fd_set mask; +#endif + +#ifdef MACOS_OPENTRANSPORT + //status = OTGetEndpointState(sock); + status = OTLook(sock); + if( status > 0 ) + retval = 1; + +/* switch( status ) + { +// case T_IDLE: + case T_DATAXFER: +// case T_INREL: + retval = 1; + break; + default: + OTCountDataBytes( sock, &numBytes ); + if( numBytes ) + retval = 1; + }*/ +#else + /* Check the file descriptors for available data */ + do { + errno = 0; + + /* Set up the mask of file descriptors */ + FD_ZERO(&mask); + FD_SET(sock, &mask); + + /* Set up the timeout */ + tv.tv_sec = 0; + tv.tv_usec = 0; + + /* Look! */ + retval = select(sock+1, &mask, NULL, NULL, &tv); + } while ( errno == EINTR ); +#endif /* MACOS_OPENTRANSPORT */ + + return(retval == 1); +} + +/* Receive a vector of pending packets from the UDP socket. + The returned packets contain the source address and the channel they arrived + on. If they did not arrive on a bound channel, the the channel will be set + to -1. + This function returns the number of packets read from the network, or -1 + on error. This function does not block, so can return 0 packets pending. +*/ +extern int SDLNet_UDP_RecvV(UDPsocket sock, UDPpacket **packets) +{ + int numrecv, i, j; + struct UDP_channel *binding; +#ifdef MACOS_OPENTRANSPORT + TUnitData OTpacket; + OTFlags flags; + InetAddress address; +#else + int sock_len; + struct sockaddr_in sock_addr; +#endif + + numrecv = 0; + while ( packets[numrecv] && SocketReady(sock->channel) ) + { + UDPpacket *packet; + + packet = packets[numrecv]; + +#ifdef MACOS_OPENTRANSPORT + memset(&OTpacket, 0, sizeof(OTpacket)); + OTpacket.addr.buf = (Uint8 *)&address; + OTpacket.addr.maxlen = (sizeof address); + OTpacket.udata.buf = packet->data; + OTpacket.udata.maxlen = packet->maxlen; + + packet->status = OTRcvUData(sock->channel, &OTpacket, &flags); +#ifdef DEBUG_NET + printf("Packet status: %d\n", packet->status); +#endif + AsyncUDPPopEvent(sock); + if (packet->status == noErr) + { + packet->len = OTpacket.udata.len; + packet->address.host = address.fHost; + packet->address.port = address.fPort; +#ifdef DEBUG_NET + printf("Packet address: 0x%8.8x:%d, length = %d\n", packet->address.host, packet->address.port, packet->len); +#endif + } +#else + sock_len = sizeof(sock_addr); + packet->status = recvfrom(sock->channel, + packet->data, packet->maxlen, 0, + (struct sockaddr *)&sock_addr, +#ifdef USE_GUSI_SOCKETS + (unsigned int *)&sock_len); +#else + &sock_len); +#endif + if ( packet->status >= 0 ) { + packet->len = packet->status; + packet->address.host = sock_addr.sin_addr.s_addr; + packet->address.port = sock_addr.sin_port; + } +#endif + if (packet->status >= 0) + { + packet->channel = -1; + + for (i=(SDLNET_MAX_UDPCHANNELS-1); i>=0; --i ) + { + binding = &sock->binding[i]; + + for ( j=binding->numbound-1; j>=0; --j ) + { + if ( (packet->address.host == binding->address[j].host) && + (packet->address.port == binding->address[j].port) ) + { + packet->channel = i; + goto foundit; /* break twice */ + } + } + } +foundit: + ++numrecv; + } + + else + { + packet->len = 0; + } + } + + sock->ready = 0; + + return(numrecv); +} + +/* Receive a single packet from the UDP socket. + The returned packet contains the source address and the channel it arrived + on. If it did not arrive on a bound channel, the the channel will be set + to -1. + This function returns the number of packets read from the network, or -1 + on error. This function does not block, so can return 0 packets pending. +*/ +int SDLNet_UDP_Recv(UDPsocket sock, UDPpacket *packet) +{ + UDPpacket *packets[2]; + + /* Receive a packet array of 1 */ + packets[0] = packet; + packets[1] = NULL; + return(SDLNet_UDP_RecvV(sock, packets)); +} + +/* Close a UDP network socket */ +extern void SDLNet_UDP_Close(UDPsocket sock) +{ + if ( sock != NULL ) + { + if ( sock->channel != INVALID_SOCKET ) + { +#ifdef MACOS_OPENTRANSPORT + OTUnbind(sock->channel); + OTCloseProvider(sock->channel); +#else + closesocket(sock->channel); +#endif /* MACOS_OPENTRANSPORT */ + } + + free(sock); + } +} +