project_files/Android-build/SDL-android-project/jni/sdl_net/SDLnetUDP.c
branchhedgeroid
changeset 5317 86984c1034a5
--- /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 <Events.h>
+#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<elsur@aaa.letter.co.jp> )
+// ( 01/02/19 )
+//
+// I guess this function should be put in SDLnet.c
+// ( 010315 masahiro minami<elsur@aaa.letter.co.jp>)
+// (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<elsur@aaa.letter.co.jp>)
+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<elsur@aaa.letter.co.jp>)
+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<elsur@aaa.letter.co.jp>
+	//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<elsur@aaa.letter.co.jp> )
+/*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; i<howmany; ++i ) {
+			packetV[i] = SDLNet_AllocPacket(size);
+			if ( packetV[i] == NULL ) {
+				break;
+			}
+		}
+		packetV[i] = NULL;
+
+		if ( i != howmany ) {
+			SDLNet_FreePacketV(packetV);
+			packetV = NULL;
+		}
+	}
+	return(packetV);
+}
+void SDLNet_FreePacketV(UDPpacket **packetV)
+{
+	if ( packetV ) {
+		int i;
+		for ( i=0; packetV[i]; ++i ) {
+			SDLNet_FreePacket(packetV[i]);
+		}
+		free(packetV);
+	}
+}
+
+/* Since the UNIX/Win32/BeOS code is so different from MacOS,
+   we'll just have two completely different sections here.
+*/
+
+/* Open a UDP network socket
+   If 'port' is non-zero, the UDP socket is bound to a fixed local port.
+*/
+extern UDPsocket SDLNet_UDP_Open(Uint16 port)
+{
+	UDPsocket sock;
+#ifdef MACOS_OPENTRANSPORT
+	EndpointRef dummy = NULL;
+#endif
+
+	/* Allocate a UDP socket structure */
+	sock = (UDPsocket)malloc(sizeof(*sock));
+	if ( sock == NULL ) {
+		SDLNet_SetError("Out of memory");
+		goto error_return;
+	}
+	memset(sock, 0, sizeof(*sock));
+	
+	/* Open the socket */
+#ifdef MACOS_OPENTRANSPORT
+	{
+		sock->error = 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<elsur@aaa.letter.co.jp>
+		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; i<npackets; ++i ) 
+	{
+		/* if channel is < 0, then use channel specified in sock */
+		
+		if ( packets[i]->channel < 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);
+	}
+}
+