mirror of
https://github.com/DrBeef/DVR.git
synced 2024-12-21 01:51:11 +00:00
797 lines
20 KiB
C
797 lines
20 KiB
C
/*
|
|
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);
|
|
}
|
|
}
|
|
|